Cleanup: code-style, duplicate header
[blender-staging.git] / source / blender / editors / space_view3d / drawvolume.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Genrich
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_view3d/drawvolume.c
27  *  \ingroup spview3d
28  */
29
30 #include <string.h>
31 #include <math.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_scene_types.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_smoke_types.h"
38 #include "DNA_view3d_types.h"
39
40 #include "BLI_utildefines.h"
41 #include "BLI_math.h"
42
43 #include "BKE_DerivedMesh.h"
44 #include "BKE_texture.h"
45 #include "BKE_particle.h"
46
47 #include "smoke_API.h"
48
49 #include "BIF_gl.h"
50
51 #include "GPU_debug.h"
52 #include "GPU_shader.h"
53 #include "GPU_texture.h"
54
55 #include "view3d_intern.h"  // own include
56
57 struct GPUTexture;
58
59 // #define DEBUG_DRAW_TIME
60
61 #ifdef DEBUG_DRAW_TIME
62 #  include "PIL_time.h"
63 #  include "PIL_time_utildefines.h"
64 #endif
65
66 /* *************************** Transfer functions *************************** */
67
68 enum {
69         TFUNC_FLAME_SPECTRUM = 0,
70         TFUNC_COLOR_RAMP     = 1,
71 };
72
73 #define TFUNC_WIDTH 256
74
75 static void create_flame_spectrum_texture(float *data)
76 {
77 #define FIRE_THRESH 7
78 #define MAX_FIRE_ALPHA 0.06f
79 #define FULL_ON_FIRE 100
80
81         float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
82
83         blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
84
85         for (int i = 0; i < 16; i++) {
86                 for (int j = 0; j < 16; j++) {
87                         for (int k = 0; k < TFUNC_WIDTH; k++) {
88                                 int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
89                                 if (k >= FIRE_THRESH) {
90                                         spec_pixels[index] = (data[k * 4]);
91                                         spec_pixels[index + 1] = (data[k * 4 + 1]);
92                                         spec_pixels[index + 2] = (data[k * 4 + 2]);
93                                         spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
94                                                 (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
95                                 }
96                                 else {
97                                         zero_v4(&spec_pixels[index]);
98                                 }
99                         }
100                 }
101         }
102
103         memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
104
105         MEM_freeN(spec_pixels);
106
107 #undef FIRE_THRESH
108 #undef MAX_FIRE_ALPHA
109 #undef FULL_ON_FIRE
110 }
111
112 static void create_color_ramp(const ColorBand *coba, float *data)
113 {
114         for (int i = 0; i < TFUNC_WIDTH; i++) {
115                 do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
116         }
117 }
118
119 static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
120 {
121         float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
122
123         switch (type) {
124                 case TFUNC_FLAME_SPECTRUM:
125                         create_flame_spectrum_texture(data);
126                         break;
127                 case TFUNC_COLOR_RAMP:
128                         create_color_ramp(coba, data);
129                         break;
130         }
131
132         GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL);
133
134         MEM_freeN(data);
135
136         return tex;
137 }
138
139 static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
140 {
141         float *field = NULL;
142
143         switch (sds->coba_field) {
144 #ifdef WITH_SMOKE
145                 case FLUID_FIELD_DENSITY:    field = smoke_get_density(sds->fluid); break;
146                 case FLUID_FIELD_HEAT:       field = smoke_get_heat(sds->fluid); break;
147                 case FLUID_FIELD_FUEL:       field = smoke_get_fuel(sds->fluid); break;
148                 case FLUID_FIELD_REACT:      field = smoke_get_react(sds->fluid); break;
149                 case FLUID_FIELD_FLAME:      field = smoke_get_flame(sds->fluid); break;
150                 case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break;
151                 case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break;
152                 case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break;
153                 case FLUID_FIELD_COLOR_R:    field = smoke_get_color_r(sds->fluid); break;
154                 case FLUID_FIELD_COLOR_G:    field = smoke_get_color_g(sds->fluid); break;
155                 case FLUID_FIELD_COLOR_B:    field = smoke_get_color_b(sds->fluid); break;
156                 case FLUID_FIELD_FORCE_X:    field = smoke_get_force_x(sds->fluid); break;
157                 case FLUID_FIELD_FORCE_Y:    field = smoke_get_force_y(sds->fluid); break;
158                 case FLUID_FIELD_FORCE_Z:    field = smoke_get_force_z(sds->fluid); break;
159 #endif
160                 default: return NULL;
161         }
162
163         return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field);
164 }
165
166 typedef struct VolumeSlicer {
167         float size[3];
168         float min[3];
169         float max[3];
170         float (*verts)[3];
171 } VolumeSlicer;
172
173 /* *************************** Axis Aligned Slicing ************************** */
174
175 static void create_single_slice(VolumeSlicer *slicer, const float depth,
176                                 const int axis, const int idx)
177 {
178         const float vertices[3][4][3] = {
179             {
180                 { depth, slicer->min[1], slicer->min[2] },
181                 { depth, slicer->max[1], slicer->min[2] },
182                 { depth, slicer->max[1], slicer->max[2] },
183                 { depth, slicer->min[1], slicer->max[2] }
184             },
185             {
186                 { slicer->min[0], depth, slicer->min[2] },
187                 { slicer->min[0], depth, slicer->max[2] },
188                 { slicer->max[0], depth, slicer->max[2] },
189                 { slicer->max[0], depth, slicer->min[2] }
190             },
191             {
192                 { slicer->min[0], slicer->min[1], depth },
193                 { slicer->min[0], slicer->max[1], depth },
194                 { slicer->max[0], slicer->max[1], depth },
195                 { slicer->max[0], slicer->min[1], depth }
196             }
197         };
198
199         copy_v3_v3(slicer->verts[idx + 0], vertices[axis][0]);
200         copy_v3_v3(slicer->verts[idx + 1], vertices[axis][1]);
201         copy_v3_v3(slicer->verts[idx + 2], vertices[axis][2]);
202         copy_v3_v3(slicer->verts[idx + 3], vertices[axis][0]);
203         copy_v3_v3(slicer->verts[idx + 4], vertices[axis][2]);
204         copy_v3_v3(slicer->verts[idx + 5], vertices[axis][3]);
205 }
206
207 static void create_axis_aligned_slices(VolumeSlicer *slicer, const int num_slices,
208                                        const float view_dir[3], const int axis)
209 {
210         float depth, slice_size = slicer->size[axis] / num_slices;
211
212         /* always process slices in back to front order! */
213         if (view_dir[axis] > 0.0f) {
214                 depth = slicer->min[axis];
215         }
216         else {
217                 depth = slicer->max[axis];
218                 slice_size = -slice_size;
219         }
220
221         int count = 0;
222         for (int slice = 0; slice < num_slices; slice++) {
223                 create_single_slice(slicer, depth, axis, count);
224
225                 count += 6;
226                 depth += slice_size;
227         }
228 }
229
230 /* *************************** View Aligned Slicing ************************** */
231
232 /* Code adapted from:
233  * "GPU-based Volume Rendering, Real-time Volume Graphics", AK Peters/CRC Press
234  */
235 static int create_view_aligned_slices(VolumeSlicer *slicer,
236                                       const int num_slices,
237                                       const float view_dir[3])
238 {
239         const int indices[] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 };
240
241         const float vertices[8][3] = {
242             { slicer->min[0], slicer->min[1], slicer->min[2] },
243             { slicer->max[0], slicer->min[1], slicer->min[2] },
244             { slicer->max[0], slicer->max[1], slicer->min[2] },
245             { slicer->min[0], slicer->max[1], slicer->min[2] },
246             { slicer->min[0], slicer->min[1], slicer->max[2] },
247             { slicer->max[0], slicer->min[1], slicer->max[2] },
248             { slicer->max[0], slicer->max[1], slicer->max[2] },
249             { slicer->min[0], slicer->max[1], slicer->max[2] }
250         };
251
252         const int edges[12][2] = {
253             { 0, 1 }, { 1, 2 }, { 2, 3 },
254             { 3, 0 }, { 0, 4 }, { 1, 5 },
255             { 2, 6 }, { 3, 7 }, { 4, 5 },
256             { 5, 6 }, { 6, 7 }, { 7, 4 }
257         };
258
259         const int edge_list[8][12] = {
260             { 0, 1, 5, 6, 4, 8, 11, 9, 3, 7, 2, 10 },
261             { 0, 4, 3, 11, 1, 2, 6, 7, 5, 9, 8, 10 },
262             { 1, 5, 0, 8, 2, 3, 7, 4, 6, 10, 9, 11 },
263             { 7, 11, 10, 8, 2, 6, 1, 9, 3, 0, 4, 5 },
264             { 8, 5, 9, 1, 11, 10, 7, 6, 4, 3, 0, 2 },
265             { 9, 6, 10, 2, 8, 11, 4, 7, 5, 0, 1, 3 },
266             { 9, 8, 5, 4, 6, 1, 2, 0, 10, 7, 11, 3 },
267             { 10, 9, 6, 5, 7, 2, 3, 1, 11, 4, 8, 0 }
268         };
269
270         /* find vertex that is the furthest from the view plane */
271         int max_index = 0;
272         float max_dist, min_dist;
273         min_dist = max_dist = dot_v3v3(view_dir, vertices[0]);
274
275         for (int i = 1; i < 8; i++) {
276                 float dist = dot_v3v3(view_dir, vertices[i]);
277
278                 if (dist > max_dist) {
279                         max_dist = dist;
280                         max_index = i;
281                 }
282
283                 if (dist < min_dist) {
284                         min_dist = dist;
285                 }
286         }
287
288         max_dist -= FLT_EPSILON;
289         min_dist += FLT_EPSILON;
290
291         /* start and direction vectors */
292         float vec_start[12][3], vec_dir[12][3];
293         /* lambda intersection values */
294         float lambda[12], lambda_inc[12];
295         float denom = 0.0f;
296
297         float plane_dist = min_dist;
298         float plane_dist_inc = (max_dist - min_dist) / (float)num_slices;
299
300         /* for all egdes */
301         for (int i = 0; i < 12; i++) {
302                 copy_v3_v3(vec_start[i], vertices[edges[edge_list[max_index][i]][0]]);
303                 copy_v3_v3(vec_dir[i],   vertices[edges[edge_list[max_index][i]][1]]);
304                 sub_v3_v3(vec_dir[i], vec_start[i]);
305
306                 denom = dot_v3v3(vec_dir[i], view_dir);
307
308                 if (1.0f + denom != 1.0f) {
309                         lambda_inc[i] = plane_dist_inc / denom;
310                         lambda[i] = (plane_dist - dot_v3v3(vec_start[i], view_dir)) / denom;
311                 }
312                 else {
313                         lambda[i] = -1.0f;
314                         lambda_inc[i] = 0.0f;
315                 }
316         }
317
318         float intersections[6][3];
319         float dL[12];
320         int num_points = 0;
321         /* find intersections for each slice, process them in back to front order */
322         for (int i = 0; i < num_slices; i++) {
323                 for (int e = 0; e < 12; e++) {
324                         dL[e] = lambda[e] + i * lambda_inc[e];
325                 }
326
327                 if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
328                         madd_v3_v3v3fl(intersections[0], vec_start[0], vec_dir[0], dL[0]);
329                 }
330                 else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
331                         madd_v3_v3v3fl(intersections[0], vec_start[1], vec_dir[1], dL[1]);
332                 }
333                 else if ((dL[3] >= 0.0f) && (dL[3] < 1.0f)) {
334                         madd_v3_v3v3fl(intersections[0], vec_start[3], vec_dir[3], dL[3]);
335                 }
336                 else continue;
337
338                 if ((dL[2] >= 0.0f) && (dL[2] < 1.0f)) {
339                         madd_v3_v3v3fl(intersections[1], vec_start[2], vec_dir[2], dL[2]);
340                 }
341                 else if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
342                         madd_v3_v3v3fl(intersections[1], vec_start[0], vec_dir[0], dL[0]);
343                 }
344                 else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
345                         madd_v3_v3v3fl(intersections[1], vec_start[1], vec_dir[1], dL[1]);
346                 }
347                 else {
348                         madd_v3_v3v3fl(intersections[1], vec_start[3], vec_dir[3], dL[3]);
349                 }
350
351                 if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
352                         madd_v3_v3v3fl(intersections[2], vec_start[4], vec_dir[4], dL[4]);
353                 }
354                 else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
355                         madd_v3_v3v3fl(intersections[2], vec_start[5], vec_dir[5], dL[5]);
356                 }
357                 else {
358                         madd_v3_v3v3fl(intersections[2], vec_start[7], vec_dir[7], dL[7]);
359                 }
360
361                 if ((dL[6] >= 0.0f) && (dL[6] < 1.0f)) {
362                         madd_v3_v3v3fl(intersections[3], vec_start[6], vec_dir[6], dL[6]);
363                 }
364                 else if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
365                         madd_v3_v3v3fl(intersections[3], vec_start[4], vec_dir[4], dL[4]);
366                 }
367                 else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
368                         madd_v3_v3v3fl(intersections[3], vec_start[5], vec_dir[5], dL[5]);
369                 }
370                 else {
371                         madd_v3_v3v3fl(intersections[3], vec_start[7], vec_dir[7], dL[7]);
372                 }
373
374                 if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
375                         madd_v3_v3v3fl(intersections[4], vec_start[8], vec_dir[8], dL[8]);
376                 }
377                 else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
378                         madd_v3_v3v3fl(intersections[4], vec_start[9], vec_dir[9], dL[9]);
379                 }
380                 else {
381                         madd_v3_v3v3fl(intersections[4], vec_start[11], vec_dir[11], dL[11]);
382                 }
383
384                 if ((dL[10] >= 0.0f) && (dL[10] < 1.0f)) {
385                         madd_v3_v3v3fl(intersections[5], vec_start[10], vec_dir[10], dL[10]);
386                 }
387                 else if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
388                         madd_v3_v3v3fl(intersections[5], vec_start[8], vec_dir[8], dL[8]);
389                 }
390                 else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
391                         madd_v3_v3v3fl(intersections[5], vec_start[9], vec_dir[9], dL[9]);
392                 }
393                 else {
394                         madd_v3_v3v3fl(intersections[5], vec_start[11], vec_dir[11], dL[11]);
395                 }
396
397                 for (int e = 0; e < 12; e++) {
398                         copy_v3_v3(slicer->verts[num_points++], intersections[indices[e]]);
399                 }
400         }
401
402         return num_points;
403 }
404
405 static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
406                         GPUTexture *tex_tfunc, GPUTexture *tex_coba,
407                         bool use_fire, const float min[3],
408                         const float ob_sizei[3], const float invsize[3])
409 {
410         int invsize_location = GPU_shader_get_uniform(shader, "invsize");
411         int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
412         int min_location = GPU_shader_get_uniform(shader, "min_location");
413
414         int soot_location;
415         int stepsize_location;
416         int densityscale_location;
417         int spec_location, flame_location;
418         int shadow_location, actcol_location;
419         int tfunc_location = 0;
420         int coba_location = 0;
421
422         if (use_fire) {
423                 spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
424                 flame_location = GPU_shader_get_uniform(shader, "flame_texture");
425         }
426         else {
427                 shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
428                 actcol_location = GPU_shader_get_uniform(shader, "active_color");
429                 soot_location = GPU_shader_get_uniform(shader, "soot_texture");
430                 stepsize_location = GPU_shader_get_uniform(shader, "step_size");
431                 densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
432
433                 if (sds->use_coba) {
434                         tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture");
435                         coba_location = GPU_shader_get_uniform(shader, "color_band_texture");
436                 }
437         }
438
439         GPU_shader_bind(shader);
440
441         if (use_fire) {
442                 GPU_texture_bind(sds->tex_flame, 2);
443                 GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
444
445                 GPU_texture_bind(tex_spec, 3);
446                 GPU_shader_uniform_texture(shader, spec_location, tex_spec);
447         }
448         else {
449                 float density_scale = 10.0f * sds->display_thickness;
450
451                 GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
452                 GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
453
454                 GPU_texture_bind(sds->tex, 0);
455                 GPU_shader_uniform_texture(shader, soot_location, sds->tex);
456
457                 GPU_texture_bind(sds->tex_shadow, 1);
458                 GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
459
460                 float active_color[3] = { 0.9, 0.9, 0.9 };
461                 if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
462                         mul_v3_v3(active_color, sds->active_color);
463                 GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
464
465                 if (sds->use_coba) {
466                         GPU_texture_bind(tex_tfunc, 4);
467                         GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc);
468
469                         GPU_texture_bind(tex_coba, 5);
470                         GPU_shader_uniform_texture(shader, coba_location, tex_coba);
471                 }
472         }
473
474         GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
475         GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
476         GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
477 }
478
479 static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec,
480                           GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire)
481 {
482         GPU_shader_unbind();
483
484         GPU_texture_unbind(sds->tex);
485
486         if (use_fire) {
487                 GPU_texture_unbind(sds->tex_flame);
488                 GPU_texture_unbind(tex_spec);
489                 GPU_texture_free(tex_spec);
490         }
491         else {
492                 GPU_texture_unbind(sds->tex_shadow);
493
494                 if (sds->use_coba) {
495                         GPU_texture_unbind(tex_tfunc);
496                         GPU_texture_free(tex_tfunc);
497
498                         GPU_texture_unbind(tex_coba);
499                         GPU_texture_free(tex_coba);
500                 }
501         }
502 }
503
504 static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer,
505                         const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire)
506 {
507         GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL;
508         GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL;
509         GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : NULL;
510
511         GLuint vertex_buffer;
512         glGenBuffers(1, &vertex_buffer);
513         glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
514         glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW);
515
516         bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize);
517
518         glEnableClientState(GL_VERTEX_ARRAY);
519         glVertexPointer(3, GL_FLOAT, 0, NULL);
520
521         glDrawArrays(GL_TRIANGLES, 0, num_points);
522
523         glDisableClientState(GL_VERTEX_ARRAY);
524
525         unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire);
526
527         /* cleanup */
528
529         glBindBuffer(GL_ARRAY_BUFFER, 0);
530
531         glDeleteBuffers(1, &vertex_buffer);
532 }
533
534 void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
535                        const float min[3], const float max[3],
536                         const float viewnormal[3])
537 {
538         if (!sds->tex || !sds->tex_shadow) {
539                 fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n");
540                 return;
541         }
542
543         const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
544
545         GPUBuiltinShader builtin_shader;
546
547         if (sds->use_coba) {
548                 builtin_shader = GPU_SHADER_SMOKE_COBA;
549         }
550         else {
551                 builtin_shader = GPU_SHADER_SMOKE;
552         }
553
554         GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader);
555
556         if (!shader) {
557                 fprintf(stderr, "Unable to create GLSL smoke shader.\n");
558                 return;
559         }
560
561         GPUShader *fire_shader = NULL;
562         if (use_fire) {
563                 fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE);
564
565                 if (!fire_shader) {
566                         fprintf(stderr, "Unable to create GLSL fire shader.\n");
567                         return;
568                 }
569         }
570
571         const float ob_sizei[3] = {
572             1.0f / fabsf(ob->size[0]),
573             1.0f / fabsf(ob->size[1]),
574             1.0f / fabsf(ob->size[2])
575         };
576
577         const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
578         const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] };
579
580 #ifdef DEBUG_DRAW_TIME
581         TIMEIT_START(draw);
582 #endif
583
584         /* setup slicing information */
585
586         const bool view_aligned = (sds->slice_method == MOD_SMOKE_SLICE_VIEW_ALIGNED);
587         int max_slices, max_points, axis = 0;
588
589         if (view_aligned) {
590                 max_slices = max_iii(sds->res[0], sds->res[1], sds->res[2]) * sds->slice_per_voxel;
591                 max_points = max_slices * 12;
592         }
593         else {
594                 if (sds->axis_slice_method == AXIS_SLICE_FULL) {
595                         axis = axis_dominant_v3_single(viewnormal);
596                         max_slices = sds->res[axis] * sds->slice_per_voxel;
597                 }
598                 else {
599                         axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewnormal) : sds->slice_axis - 1;
600                         max_slices = 1;
601                 }
602
603                 max_points = max_slices * 6;
604         }
605
606         VolumeSlicer slicer;
607         copy_v3_v3(slicer.min, min);
608         copy_v3_v3(slicer.max, max);
609         copy_v3_v3(slicer.size, size);
610         slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");
611
612         int num_points;
613
614         if (view_aligned) {
615                 num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
616         }
617         else {
618                 num_points = max_points;
619
620                 if (sds->axis_slice_method == AXIS_SLICE_FULL) {
621                         create_axis_aligned_slices(&slicer, max_slices, viewnormal, axis);
622                 }
623                 else {
624                         const float depth = (sds->slice_depth - 0.5f) * size[axis];
625                         create_single_slice(&slicer, depth, axis, 0);
626                 }
627         }
628
629         /* setup buffer and draw */
630
631         int gl_depth = 0, gl_blend = 0, gl_depth_write = 0;
632         glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
633         glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
634         glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&gl_depth_write);
635
636         glEnable(GL_DEPTH_TEST);
637         glDepthMask(GL_FALSE);
638         glEnable(GL_BLEND);
639
640         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
641         draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
642
643         /* Draw fire separately (T47639). */
644         if (use_fire && !sds->use_coba) {
645                 glBlendFunc(GL_ONE, GL_ONE);
646                 draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
647         }
648
649 #ifdef DEBUG_DRAW_TIME
650         printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
651         TIMEIT_END(draw);
652 #endif
653
654         MEM_freeN(slicer.verts);
655
656         glDepthMask(gl_depth_write);
657
658         if (!gl_blend) {
659                 glDisable(GL_BLEND);
660         }
661
662         if (gl_depth) {
663                 glEnable(GL_DEPTH_TEST);
664         }
665 }
666
667 #ifdef WITH_SMOKE
668 static void add_tri(float (*verts)[3], float(*colors)[3], int *offset,
669                     float p1[3], float p2[3], float p3[3], float rgb[3])
670 {
671         copy_v3_v3(verts[*offset + 0], p1);
672         copy_v3_v3(verts[*offset + 1], p2);
673         copy_v3_v3(verts[*offset + 2], p3);
674
675         copy_v3_v3(colors[*offset + 0], rgb);
676         copy_v3_v3(colors[*offset + 1], rgb);
677         copy_v3_v3(colors[*offset + 2], rgb);
678
679         *offset += 3;
680 }
681
682 static void add_needle(float (*verts)[3], float (*colors)[3], float center[3],
683                        float dir[3], float scale, float voxel_size, int *offset)
684 {
685         float len = len_v3(dir);
686
687         float rgb[3];
688         weight_to_rgb(rgb, len);
689
690         if (len != 0.0f) {
691                 mul_v3_fl(dir, 1.0f / len);
692                 len *= scale;
693         }
694
695         len *= voxel_size;
696
697         float corners[4][3] = {
698             { 0.0f, 0.2f, -0.5f },
699             { -0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
700             { 0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
701             { 0.0f, 0.0f, 0.5f }
702         };
703
704         const float up[3] = { 0.0f, 0.0f, 1.0f };
705         float rot[3][3];
706
707         rotation_between_vecs_to_mat3(rot, up, dir);
708         transpose_m3(rot);
709
710         for (int i = 0; i < 4; i++) {
711                 mul_m3_v3(rot, corners[i]);
712                 mul_v3_fl(corners[i], len);
713                 add_v3_v3(corners[i], center);
714         }
715
716         add_tri(verts, colors, offset, corners[0], corners[1], corners[2], rgb);
717         add_tri(verts, colors, offset, corners[0], corners[1], corners[3], rgb);
718         add_tri(verts, colors, offset, corners[1], corners[2], corners[3], rgb);
719         add_tri(verts, colors, offset, corners[2], corners[0], corners[3], rgb);
720 }
721
722 static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3],
723                            float dir[3], float scale, float voxel_size, int *offset)
724 {
725         const float len = len_v3(dir);
726
727         float rgb[3];
728         weight_to_rgb(rgb, len);
729
730         copy_v3_v3(colors[(*offset)], rgb);
731         copy_v3_v3(verts[(*offset)++], center);
732
733         mul_v3_fl(dir, scale * voxel_size);
734         add_v3_v3(center, dir);
735
736         copy_v3_v3(colors[(*offset)], rgb);
737         copy_v3_v3(verts[(*offset)++], center);
738 }
739
740 typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float*, float*, float, float, int*);
741 #endif  /* WITH_SMOKE */
742
743 void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
744 {
745 #ifdef WITH_SMOKE
746         const float *vel_x = smoke_get_velocity_x(domain->fluid);
747         const float *vel_y = smoke_get_velocity_y(domain->fluid);
748         const float *vel_z = smoke_get_velocity_z(domain->fluid);
749
750         if (ELEM(NULL, vel_x, vel_y, vel_z)) {
751                 return;
752         }
753
754         const int *base_res = domain->base_res;
755         const int *res = domain->res;
756         const int *res_min = domain->res_min;
757
758         int res_max[3];
759         copy_v3_v3_int(res_max, domain->res_max);
760
761         const float *cell_size = domain->cell_size;
762         const float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.0f;
763
764         /* set first position so that it doesn't jump when domain moves */
765         float xyz[3] = {
766             res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size),
767             res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size),
768             res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size)
769         };
770
771         if (xyz[0] < res_min[0]) xyz[0] += step_size;
772         if (xyz[1] < res_min[1]) xyz[1] += step_size;
773         if (xyz[2] < res_min[2]) xyz[2] += step_size;
774
775         float min[3] = {
776             domain->p0[0] - domain->cell_size[0] * domain->adapt_res,
777             domain->p0[1] - domain->cell_size[1] * domain->adapt_res,
778             domain->p0[2] - domain->cell_size[2] * domain->adapt_res,
779         };
780
781         int num_points_v[3] = {
782             ((float)(res_max[0] - floor(xyz[0])) / step_size) + 0.5f,
783             ((float)(res_max[1] - floor(xyz[1])) / step_size) + 0.5f,
784             ((float)(res_max[2] - floor(xyz[2])) / step_size) + 0.5f
785         };
786
787         if (domain->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
788             domain->axis_slice_method == AXIS_SLICE_SINGLE)
789         {
790                 const int axis = (domain->slice_axis == SLICE_AXIS_AUTO) ?
791                                      axis_dominant_v3_single(viewnormal) : domain->slice_axis - 1;
792
793                 xyz[axis] = (float)base_res[axis] * domain->slice_depth;
794                 num_points_v[axis] = 1;
795                 res_max[axis] = xyz[axis] + 1;
796         }
797
798         vector_draw_func func;
799         int max_points;
800
801         if (domain->vector_draw_type == VECTOR_DRAW_NEEDLE) {
802                 func = add_needle;
803                 max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 4 * 3;
804         }
805         else {
806                 func = add_streamline;
807                 max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 2;
808         }
809
810         float (*verts)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
811         float (*colors)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
812
813         int num_points = 0;
814
815         for (float x = floor(xyz[0]); x < res_max[0]; x += step_size) {
816                 for (float y = floor(xyz[1]); y < res_max[1]; y += step_size) {
817                         for (float z = floor(xyz[2]); z < res_max[2]; z += step_size) {
818                                 int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
819
820                                 float pos[3] = {
821                                     min[0] + ((float)x + 0.5f) * cell_size[0],
822                                     min[1] + ((float)y + 0.5f) * cell_size[1],
823                                     min[2] + ((float)z + 0.5f) * cell_size[2]
824                                 };
825
826                                 float vel[3] = {
827                                     vel_x[index], vel_y[index], vel_z[index]
828                                 };
829
830                                 func(verts, colors, pos, vel, domain->vector_scale, cell_size[0], &num_points);
831                         }
832                 }
833         }
834
835         glLineWidth(1.0f);
836
837         glEnableClientState(GL_VERTEX_ARRAY);
838         glVertexPointer(3, GL_FLOAT, 0, verts);
839
840         glEnableClientState(GL_COLOR_ARRAY);
841         glColorPointer(3, GL_FLOAT, 0, colors);
842
843         glDrawArrays(GL_LINES, 0, num_points);
844
845         glDisableClientState(GL_VERTEX_ARRAY);
846         glDisableClientState(GL_COLOR_ARRAY);
847
848         MEM_freeN(verts);
849         MEM_freeN(colors);
850 #else
851         UNUSED_VARS(domain, viewnormal);
852 #endif
853 }