Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / draw / engines / workbench / workbench_volume.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2018, Blender Foundation.
17  */
18
19 /** \file \ingroup draw_engine
20  */
21
22 #include "workbench_private.h"
23
24 #include "BKE_object.h"
25
26 #include "BLI_rand.h"
27 #include "BLI_dynstr.h"
28
29 #include "DNA_modifier_types.h"
30 #include "DNA_object_force_types.h"
31 #include "DNA_smoke_types.h"
32
33 #include "GPU_draw.h"
34
35 enum {
36         VOLUME_SH_SLICE = 0,
37         VOLUME_SH_COBA,
38         VOLUME_SH_CUBIC,
39 };
40
41 #define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
42
43 static struct {
44         struct GPUShader *volume_sh[VOLUME_SH_MAX];
45         struct GPUShader *volume_coba_sh;
46         struct GPUShader *volume_slice_sh;
47         struct GPUShader *volume_slice_coba_sh;
48         struct GPUTexture *dummy_tex;
49         struct GPUTexture *dummy_coba_tex;
50 } e_data = {{NULL}};
51
52 extern char datatoc_workbench_volume_vert_glsl[];
53 extern char datatoc_workbench_volume_frag_glsl[];
54
55 static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
56 {
57         int id = 0;
58         id += (slice) ? (1 << VOLUME_SH_SLICE) : 0;
59         id += (coba) ? (1 << VOLUME_SH_COBA) : 0;
60         id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0;
61
62         if (!e_data.volume_sh[id]) {
63                 DynStr *ds = BLI_dynstr_new();
64
65                 if (slice) {
66                         BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
67                 }
68                 if (coba) {
69                         BLI_dynstr_append(ds, "#define USE_COBA\n");
70                 }
71                 if (cubic) {
72                         BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
73                 }
74
75                 char *defines = BLI_dynstr_get_cstring(ds);
76                 BLI_dynstr_free(ds);
77
78                 e_data.volume_sh[id] = DRW_shader_create(
79                         datatoc_workbench_volume_vert_glsl, NULL,
80                         datatoc_workbench_volume_frag_glsl,
81                         defines);
82
83                 MEM_freeN(defines);
84         }
85
86         return e_data.volume_sh[id];
87 }
88
89 void workbench_volume_engine_init(void)
90 {
91         if (!e_data.dummy_tex) {
92                 float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f};
93                 e_data.dummy_tex = GPU_texture_create_3D(1, 1, 1, GPU_RGBA8, pixel, NULL);
94                 e_data.dummy_coba_tex = GPU_texture_create_1D(1, GPU_RGBA8, pixel, NULL);
95         }
96 }
97
98 void workbench_volume_engine_free(void)
99 {
100         for (int i = 0; i < VOLUME_SH_MAX; ++i) {
101                 DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
102         }
103         DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
104         DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex);
105 }
106
107 void workbench_volume_cache_init(WORKBENCH_Data *vedata)
108 {
109         vedata->psl->volume_pass = DRW_pass_create("Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL | DRW_STATE_CULL_FRONT);
110 }
111
112 void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Object *ob, ModifierData *md)
113 {
114         SmokeModifierData *smd = (SmokeModifierData *)md;
115         SmokeDomainSettings *sds = smd->domain;
116         WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
117         WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
118         DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
119         DRWShadingGroup *grp = NULL;
120
121         /* Don't show smoke before simulation starts, this could be made an option in the future. */
122         if (!sds->fluid || CFRA < sds->point_cache[0]->startframe) {
123                 return;
124         }
125
126         wpd->volumes_do = true;
127         if (sds->use_coba) {
128                 GPU_create_smoke_coba_field(smd);
129         }
130         else if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
131                 GPU_create_smoke(smd, 0);
132         }
133         else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
134                 GPU_create_smoke(smd, 1);
135         }
136
137         if ((!sds->use_coba && sds->tex == NULL) ||
138             (sds->use_coba && sds->tex_field == NULL))
139         {
140                 return;
141         }
142
143         const bool use_slice = (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
144                                 sds->axis_slice_method == AXIS_SLICE_SINGLE);
145         const bool cubic_interp = (sds->interp_method == VOLUME_INTERP_CUBIC);
146         GPUShader *sh = volume_shader_get(use_slice, sds->use_coba, cubic_interp);
147
148         if (use_slice) {
149                 float invviewmat[4][4];
150                 DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
151
152                 const int axis = (sds->slice_axis == SLICE_AXIS_AUTO)
153                                   ? axis_dominant_v3_single(invviewmat[2])
154                                   : sds->slice_axis - 1;
155                 float dim[3];
156                 BKE_object_dimensions_get(ob, dim);
157                 /* 0.05f to acheive somewhat the same opacity as the full view.  */
158                 float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
159
160                 grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
161                 DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
162                 DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
163                 DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
164                 DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT);
165         }
166         else {
167                 double noise_ofs;
168                 BLI_halton_1D(3, 0.0, effect_info->jitter_index, &noise_ofs);
169                 float dim[3], step_length, max_slice;
170                 float slice_ct[3] = {sds->res[0], sds->res[1], sds->res[2]};
171                 mul_v3_fl(slice_ct, max_ff(0.001f, sds->slice_per_voxel));
172                 max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
173                 BKE_object_dimensions_get(ob, dim);
174                 invert_v3(slice_ct);
175                 mul_v3_v3(dim, slice_ct);
176                 step_length = len_v3(dim);
177
178                 grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
179                 DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
180                 DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
181                 DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
182                 DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
183                 DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
184         }
185
186         if (sds->use_coba) {
187                 DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex_field);
188                 DRW_shgroup_uniform_texture(grp, "transferTexture", sds->tex_coba);
189         }
190         else {
191                 DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex);
192                 DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow);
193                 DRW_shgroup_uniform_texture(grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex);
194                 DRW_shgroup_uniform_texture(grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex);
195         }
196         DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
197         DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness);
198
199         if (use_slice) {
200                 DRW_shgroup_call_object_add(grp, DRW_cache_quad_get(), ob);
201         }
202         else {
203                 DRW_shgroup_call_object_add(grp, DRW_cache_cube_get(), ob);
204         }
205
206         BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd));
207 }
208
209 void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
210 {
211         /* Free Smoke Textures after rendering */
212         /* XXX This is a waste of processing and GPU bandwidth if nothing
213          * is updated. But the problem is since Textures are stored in the
214          * modifier we don't want them to take precious VRAM if the
215          * modifier is not used for display. We should share them for
216          * all viewport in a redraw at least. */
217         for (LinkData *link = wpd->smoke_domains.first; link; link = link->next) {
218                 SmokeModifierData *smd = (SmokeModifierData *)link->data;
219                 GPU_free_smoke(smd);
220         }
221         BLI_freelistN(&wpd->smoke_domains);
222 }