quiet double-promotion warnings, change octree.cpp to use a float (vector accumulated...
[blender.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
31
32 #include <string.h>
33 #include <math.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_smoke_types.h"
40 #include "DNA_view3d_types.h"
41 #include "DNA_property_types.h"
42
43 #include "BLI_utildefines.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_math.h"
46 #include "BLI_edgehash.h"
47
48 #include "BKE_curve.h"
49 #include "BKE_constraint.h"  /* for the get_constraint_target function */
50 #include "BKE_DerivedMesh.h"
51 #include "BKE_displist.h"
52 #include "BKE_effect.h"
53 #include "BKE_font.h"
54 #include "BKE_global.h"
55 #include "BKE_image.h"
56 #include "BKE_key.h"
57 #include "BKE_lattice.h"
58 #include "BKE_mesh.h"
59 #include "BKE_material.h"
60 #include "BKE_mball.h"
61 #include "BKE_modifier.h"
62 #include "BKE_object.h"
63 #include "BKE_paint.h"
64 #include "BKE_particle.h"
65 #include "BKE_property.h"
66 #include "BKE_smoke.h"
67
68 #include "smoke_API.h"
69
70 #include "BIF_gl.h"
71
72 #include "GPU_extensions.h"
73
74 #include "ED_mesh.h"
75
76 #include "BLF_api.h"
77
78 #include "view3d_intern.h"  // own include
79
80 struct GPUTexture;
81
82 // #define DEBUG_DRAW_TIME
83
84 #ifdef DEBUG_DRAW_TIME
85 #  include "PIL_time.h"
86 #endif
87
88 static int intersect_edges(float *points, float a, float b, float c, float d, float edges[12][2][3])
89 {
90         int i;
91         float t;
92         int numpoints = 0;
93
94         for (i = 0; i < 12; i++) {
95                 t = -(a * edges[i][0][0] + b * edges[i][0][1] + c * edges[i][0][2] + d) /
96                      (a * edges[i][1][0] + b * edges[i][1][1] + c * edges[i][1][2]);
97                 if ((t > 0) && (t < 1)) {
98                         points[numpoints * 3 + 0] = edges[i][0][0] + edges[i][1][0] * t;
99                         points[numpoints * 3 + 1] = edges[i][0][1] + edges[i][1][1] * t;
100                         points[numpoints * 3 + 2] = edges[i][0][2] + edges[i][1][2] * t;
101                         numpoints++;
102                 }
103         }
104         return numpoints;
105 }
106
107 static bool convex(const float p0[3], const float up[3], const float a[3], const float b[3])
108 {
109         /* Vec3 va = a-p0, vb = b-p0; */
110         float va[3], vb[3], tmp[3];
111         sub_v3_v3v3(va, a, p0);
112         sub_v3_v3v3(vb, b, p0);
113         cross_v3_v3v3(tmp, va, vb);
114         return dot_v3v3(up, tmp) >= 0;
115 }
116
117 void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
118                        GPUTexture *tex, float min[3], float max[3],
119                        int res[3], float dx, float UNUSED(base_scale), float viewnormal[3],
120                        GPUTexture *tex_shadow, GPUTexture *tex_flame)
121 {
122         int i, j, k, n, good_index;
123         float d /*, d0 */ /* UNUSED */, dd, ds;
124         float *points = NULL;
125         int numpoints = 0;
126         float cor[3] = {1.0f, 1.0f, 1.0f};
127         int gl_depth = 0, gl_blend = 0;
128
129         /* draw slices of smoke is adapted from c++ code authored
130          * by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
131         float cv[][3] = {
132                 {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
133                 {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
134         };
135
136         /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */
137         float edges[12][2][3] = {
138                 {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
139                 {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
140                 {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
141                 {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
142
143                 {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
144                 {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
145                 {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
146                 {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
147
148                 {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
149                 {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
150                 {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
151                 {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
152         };
153
154         unsigned char *spec_data;
155         float *spec_pixels;
156         GPUTexture *tex_spec;
157
158         /* Fragment program to calculate the view3d of smoke */
159         /* using 4 textures, density, shadow, flame and flame spectrum */
160         const char *shader_basic =
161                 "!!ARBfp1.0\n"
162                 "PARAM dx = program.local[0];\n"
163                 "PARAM darkness = program.local[1];\n"
164                 "PARAM render = program.local[2];\n"
165                 "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
166                 "TEMP temp, shadow, flame, spec, value;\n"
167                 "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
168                 "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
169                 "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
170                 "TEX spec, flame.r, texture[3], 1D;\n"
171                 /* calculate shading factor from density */
172                 "MUL value.r, temp.a, darkness.a;\n"
173                 "MUL value.r, value.r, dx.r;\n"
174                 "MUL value.r, value.r, f.r;\n"
175                 "EX2 temp, -value.r;\n"
176                 /* alpha */
177                 "SUB temp.a, 1.0, temp.r;\n"
178                 /* shade colors */
179                 "MUL temp.r, temp.r, shadow.r;\n"
180                 "MUL temp.g, temp.g, shadow.r;\n"
181                 "MUL temp.b, temp.b, shadow.r;\n"
182                 "MUL temp.r, temp.r, darkness.r;\n"
183                 "MUL temp.g, temp.g, darkness.g;\n"
184                 "MUL temp.b, temp.b, darkness.b;\n"
185                 /* for now this just replace smoke shading if rendering fire */
186                 "CMP result.color, render.r, temp, spec;\n"
187                 "END\n";
188
189         /* color shader */
190         const char *shader_color =
191                 "!!ARBfp1.0\n"
192                 "PARAM dx = program.local[0];\n"
193                 "PARAM darkness = program.local[1];\n"
194                 "PARAM render = program.local[2];\n"
195                 "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
196                 "TEMP temp, shadow, flame, spec, value;\n"
197                 "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
198                 "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
199                 "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
200                 "TEX spec, flame.r, texture[3], 1D;\n"
201                 /* unpremultiply volume texture */
202                 "RCP value.r, temp.a;\n"
203                 "MUL temp.r, temp.r, value.r;\n"
204                 "MUL temp.g, temp.g, value.r;\n"
205                 "MUL temp.b, temp.b, value.r;\n"
206                 /* calculate shading factor from density */
207                 "MUL value.r, temp.a, darkness.a;\n"
208                 "MUL value.r, value.r, dx.r;\n"
209                 "MUL value.r, value.r, f.r;\n"
210                 "EX2 value.r, -value.r;\n"
211                 /* alpha */
212                 "SUB temp.a, 1.0, value.r;\n"
213                 /* shade colors */
214                 "MUL temp.r, temp.r, shadow.r;\n"
215                 "MUL temp.g, temp.g, shadow.r;\n"
216                 "MUL temp.b, temp.b, shadow.r;\n"
217                 "MUL temp.r, temp.r, value.r;\n"
218                 "MUL temp.g, temp.g, value.r;\n"
219                 "MUL temp.b, temp.b, value.r;\n"
220                 /* for now this just replace smoke shading if rendering fire */
221                 "CMP result.color, render.r, temp, spec;\n"
222                 "END\n";
223
224         GLuint prog;
225
226         
227         float size[3];
228
229         if (!tex) {
230                 printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
231                 return;
232         }
233
234 #ifdef DEBUG_DRAW_TIME
235         TIMEIT_START(draw);
236 #endif
237
238         /* generate flame spectrum texture */
239         #define SPEC_WIDTH 256
240         #define FIRE_THRESH 7
241         #define MAX_FIRE_ALPHA 0.06f
242         #define FULL_ON_FIRE 100
243         spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char));
244         flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
245         spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float));
246         for (i = 0; i < 16; i++) {
247                 for (j = 0; j < 16; j++) {
248                         for (k = 0; k < SPEC_WIDTH; k++) {
249                                 int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
250                                 if (k >= FIRE_THRESH) {
251                                         spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f;
252                                         spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f;
253                                         spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f;
254                                         spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
255                                                 (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
256                                 }
257                                 else {
258                                         spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f;
259                                 }
260                         }
261                 }
262         }
263
264         tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
265
266         sub_v3_v3v3(size, max, min);
267
268         /* maxx, maxy, maxz */
269         cv[0][0] = max[0];
270         cv[0][1] = max[1];
271         cv[0][2] = max[2];
272         /* minx, maxy, maxz */
273         cv[1][0] = min[0];
274         cv[1][1] = max[1];
275         cv[1][2] = max[2];
276         /* minx, miny, maxz */
277         cv[2][0] = min[0];
278         cv[2][1] = min[1];
279         cv[2][2] = max[2];
280         /* maxx, miny, maxz */
281         cv[3][0] = max[0];
282         cv[3][1] = min[1];
283         cv[3][2] = max[2];
284
285         /* maxx, maxy, minz */
286         cv[4][0] = max[0];
287         cv[4][1] = max[1];
288         cv[4][2] = min[2];
289         /* minx, maxy, minz */
290         cv[5][0] = min[0];
291         cv[5][1] = max[1];
292         cv[5][2] = min[2];
293         /* minx, miny, minz */
294         cv[6][0] = min[0];
295         cv[6][1] = min[1];
296         cv[6][2] = min[2];
297         /* maxx, miny, minz */
298         cv[7][0] = max[0];
299         cv[7][1] = min[1];
300         cv[7][2] = min[2];
301
302         copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */
303         copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */
304         copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */
305         copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */
306
307         copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */
308         copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */
309         copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */
310         copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */
311
312         copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */
313         copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */
314         copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */
315         copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */
316
317         // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
318         // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);
319
320         edges[0][1][2] = size[2];
321         edges[1][1][2] = size[2];
322         edges[2][1][2] = size[2];
323         edges[3][1][2] = size[2];
324
325         edges[4][1][1] = size[1];
326         edges[5][1][1] = size[1];
327         edges[6][1][1] = size[1];
328         edges[7][1][1] = size[1];
329
330         edges[8][1][0] = size[0];
331         edges[9][1][0] = size[0];
332         edges[10][1][0] = size[0];
333         edges[11][1][0] = size[0];
334
335         glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
336         glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
337
338         glDepthMask(GL_FALSE);
339         glDisable(GL_DEPTH_TEST);
340         glEnable(GL_BLEND);
341
342         /* find cube vertex that is closest to the viewer */
343         for (i = 0; i < 8; i++) {
344                 float x, y, z;
345
346                 x = cv[i][0] - viewnormal[0] * size[0] * 0.5f;
347                 y = cv[i][1] - viewnormal[1] * size[1] * 0.5f;
348                 z = cv[i][2] - viewnormal[2] * size[2] * 0.5f;
349
350                 if ((x >= min[0]) && (x <= max[0]) &&
351                     (y >= min[1]) && (y <= max[1]) &&
352                     (z >= min[2]) && (z <= max[2]))
353                 {
354                         break;
355                 }
356         }
357
358         if (i >= 8) {
359                 /* fallback, avoid using buffer over-run */
360                 i = 0;
361         }
362
363         // printf("i: %d\n", i);
364         // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
365
366         if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) {
367                 glEnable(GL_FRAGMENT_PROGRAM_ARB);
368                 glGenProgramsARB(1, &prog);
369
370                 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
371                 /* set shader */
372                 if (sds->active_fields & SM_ACTIVE_COLORS)
373                         glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
374                 else
375                         glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);
376
377                 /* cell spacing */
378                 glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
379                 /* custom parameter for smoke style (higher = thicker) */
380                 if (sds->active_fields & SM_ACTIVE_COLORS)
381                         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
382                 else
383                         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
384         }
385         else
386                 printf("Your gfx card does not support 3D View smoke drawing.\n");
387
388         GPU_texture_bind(tex, 0);
389         if (tex_shadow)
390                 GPU_texture_bind(tex_shadow, 1);
391         else
392                 printf("No volume shadow\n");
393
394         if (tex_flame) {
395                 GPU_texture_bind(tex_flame, 2);
396                 GPU_texture_bind(tex_spec, 3);
397         }
398
399         if (!GPU_non_power_of_two_support()) {
400                 cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]);
401                 cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]);
402                 cor[2] = (float)res[2] / (float)power_of_2_max_i(res[2]);
403         }
404
405         /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0
406          * (a,b,c), the plane normal, are given by viewdir
407          * d is the parameter along the view direction. the first d is given by
408          * inserting previously found vertex into the plane equation */
409
410         /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
411         ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]);
412         dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f;
413         n = 0;
414         good_index = i;
415
416         // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);
417
418         points = MEM_callocN(sizeof(float) * 12 * 3, "smoke_points_preview");
419
420         while (1) {
421                 float p0[3];
422                 float tmp_point[3], tmp_point2[3];
423
424                 if (dd * (float)n > ds)
425                         break;
426
427                 copy_v3_v3(tmp_point, viewnormal);
428                 mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n));
429                 add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
430                 d = dot_v3v3(tmp_point2, viewnormal);
431
432                 // printf("my d: %f\n", d);
433
434                 /* intersect_edges returns the intersection points of all cube edges with
435                  * the given plane that lie within the cube */
436                 numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);
437
438                 // printf("points: %d\n", numpoints);
439
440                 if (numpoints > 2) {
441                         copy_v3_v3(p0, points);
442
443                         /* sort points to get a convex polygon */
444                         for (i = 1; i < numpoints - 1; i++) {
445                                 for (j = i + 1; j < numpoints; j++) {
446                                         if (!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) {
447                                                 float tmp2[3];
448                                                 copy_v3_v3(tmp2, &points[j * 3]);
449                                                 copy_v3_v3(&points[j * 3], &points[i * 3]);
450                                                 copy_v3_v3(&points[i * 3], tmp2);
451                                         }
452                                 }
453                         }
454
455                         /* render fire slice */
456                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
457                         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
458                         glBegin(GL_POLYGON);
459                         glColor3f(1.0, 1.0, 1.0);
460                         for (i = 0; i < numpoints; i++) {
461                                 glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
462                                              (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
463                                              (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
464                                 glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]),
465                                            points[i * 3 + 1] / fabsf(ob->size[1]),
466                                            points[i * 3 + 2] / fabsf(ob->size[2]));
467                         }
468                         glEnd();
469
470                         /* render smoke slice */
471                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
472                         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
473                         glBegin(GL_POLYGON);
474                         glColor3f(1.0, 1.0, 1.0);
475                         for (i = 0; i < numpoints; i++) {
476                                 glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
477                                              (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
478                                              (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
479                                 glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]),
480                                            points[i * 3 + 1] / fabsf(ob->size[1]),
481                                            points[i * 3 + 2] / fabsf(ob->size[2]));
482                         }
483                         glEnd();
484                 }
485                 n++;
486         }
487
488 #ifdef DEBUG_DRAW_TIME
489         printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
490         TIMEIT_END(draw);
491 #endif
492
493         if (tex_shadow)
494                 GPU_texture_unbind(tex_shadow);
495         GPU_texture_unbind(tex);
496         if (tex_flame) {
497                 GPU_texture_unbind(tex_flame);
498                 GPU_texture_unbind(tex_spec);
499         }
500         GPU_texture_free(tex_spec);
501
502         free(spec_data);
503         free(spec_pixels);
504
505         if (GLEW_ARB_fragment_program) {
506                 glDisable(GL_FRAGMENT_PROGRAM_ARB);
507                 glDeleteProgramsARB(1, &prog);
508         }
509
510
511         MEM_freeN(points);
512
513         if (!gl_blend) {
514                 glDisable(GL_BLEND);
515         }
516
517         if (gl_depth) {
518                 glEnable(GL_DEPTH_TEST);
519                 glDepthMask(GL_TRUE);
520         }
521 }
522
523 #ifdef SMOKE_DEBUG_VELOCITY
524 void draw_smoke_velocity(SmokeDomainSettings *domain, Object *ob)
525 {
526         float x, y, z;
527         float x0, y0, z0;
528         int *base_res = domain->base_res;
529         int *res = domain->res;
530         int *res_min = domain->res_min;
531         int *res_max = domain->res_max;
532         float *vel_x = smoke_get_velocity_x(domain->fluid);
533         float *vel_y = smoke_get_velocity_y(domain->fluid);
534         float *vel_z = smoke_get_velocity_z(domain->fluid);
535
536         float min[3];
537         float *cell_size = domain->cell_size;
538         float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
539         float vf = domain->scale / 16.f * 2.f; /* velocity factor */
540
541         glLineWidth(1.0f);
542
543         /* set first position so that it doesn't jump when domain moves */
544         x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
545         y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
546         z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
547         if (x0 < res_min[0]) x0 += step_size;
548         if (y0 < res_min[1]) y0 += step_size;
549         if (z0 < res_min[2]) z0 += step_size;
550         add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
551
552         for (x = floor(x0); x < res_max[0]; x += step_size)
553                 for (y = floor(y0); y < res_max[1]; y += step_size)
554                         for (z = floor(z0); z < res_max[2]; z += step_size) {
555                                 int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
556
557                                 float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]};
558                                 float vel = sqrtf(vel_x[index] * vel_x[index] + vel_y[index] * vel_y[index] + vel_z[index] * vel_z[index]);
559
560                                 /* draw heat as scaled "arrows" */
561                                 if (vel >= 0.01f) {
562                                         float col_g = 1.0f - vel;
563                                         CLAMP(col_g, 0.0f, 1.0f);
564                                         glColor3f(1.0f, col_g, 0.0f);
565                                         glPointSize(10.0f * vel);
566
567                                         glBegin(GL_LINES);
568                                         glVertex3f(pos[0], pos[1], pos[2]);
569                                         glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
570                                         glEnd();
571                                         glBegin(GL_POINTS);
572                                         glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
573                                         glEnd();
574                                 }
575                         }
576 }
577 #endif
578
579 #ifdef SMOKE_DEBUG_HEAT
580 void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
581 {
582         float x, y, z;
583         float x0, y0, z0;
584         int *base_res = domain->base_res;
585         int *res = domain->res;
586         int *res_min = domain->res_min;
587         int *res_max = domain->res_max;
588         float *heat = smoke_get_heat(domain->fluid);
589
590         float min[3];
591         float *cell_size = domain->cell_size;
592         float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
593         float vf = domain->scale / 16.f * 2.f; /* velocity factor */
594
595         /* set first position so that it doesn't jump when domain moves */
596         x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
597         y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
598         z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
599         if (x0 < res_min[0]) x0 += step_size;
600         if (y0 < res_min[1]) y0 += step_size;
601         if (z0 < res_min[2]) z0 += step_size;
602         add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
603
604         for (x = floor(x0); x < res_max[0]; x += step_size)
605                 for (y = floor(y0); y < res_max[1]; y += step_size)
606                         for (z = floor(z0); z < res_max[2]; z += step_size) {
607                                 int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
608
609                                 float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]};
610
611                                 /* draw heat as different sized points */
612                                 if (heat[index] >= 0.01f) {
613                                         float col_gb = 1.0f - heat[index];
614                                         CLAMP(col_gb, 0.0f, 1.0f);
615                                         glColor3f(1.0f, col_gb, col_gb);
616                                         glPointSize(24.0f * heat[index]);
617
618                                         glBegin(GL_POINTS);
619                                         glVertex3f(pos[0], pos[1], pos[2]);
620                                         glEnd();
621                                 }
622                         }
623 }
624 #endif