b36ce6656b299c358eb1d28c4736a5c88eece3a6
[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_view3d_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_math.h"
44 #include "BLI_edgehash.h"
45 #include "BLI_rand.h"
46
47 #include "BKE_curve.h"
48 #include "BKE_constraint.h" // for the get_constraint_target function
49 #include "BKE_DerivedMesh.h"
50 #include "BKE_deform.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
77 #include "BLF_api.h"
78
79
80 #include "view3d_intern.h"      // own include
81
82
83 #ifdef _WIN32
84 #include <time.h>
85 #include <stdio.h>
86 #include <conio.h>
87 #include <windows.h>
88
89 static LARGE_INTEGER liFrequency;
90 static LARGE_INTEGER liStartTime;
91 static LARGE_INTEGER liCurrentTime;
92
93 static void tstart ( void )
94 {
95         QueryPerformanceFrequency ( &liFrequency );
96         QueryPerformanceCounter ( &liStartTime );
97 }
98 static void tend ( void )
99 {
100         QueryPerformanceCounter ( &liCurrentTime );
101 }
102 static double tval( void )
103 {
104         return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
105 }
106 #else
107 #include <sys/time.h>
108 static struct timeval _tstart, _tend;
109 static struct timezone tz;
110 static void tstart ( void )
111 {
112         gettimeofday ( &_tstart, &tz );
113 }
114 static void tend ( void )
115 {
116         gettimeofday ( &_tend,&tz );
117 }
118   #if 0
119 static double tval()
120 {
121         double t1, t2;
122         t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
123         t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
124         return t2-t1;
125 }
126   #endif
127 #endif
128
129 struct GPUTexture;
130
131 static int intersect_edges(float *points, float a, float b, float c, float d, float edges[12][2][3])
132 {
133         int i;
134         float t;
135         int numpoints = 0;
136         
137         for (i=0; i<12; i++) {
138                 t = -(a*edges[i][0][0] + b*edges[i][0][1] + c*edges[i][0][2] + d)
139                         / (a*edges[i][1][0] + b*edges[i][1][1] + c*edges[i][1][2]);
140                 if ((t>0)&&(t<1)) {
141                         points[numpoints * 3 + 0] = edges[i][0][0] + edges[i][1][0]*t;
142                         points[numpoints * 3 + 1] = edges[i][0][1] + edges[i][1][1]*t;
143                         points[numpoints * 3 + 2] = edges[i][0][2] + edges[i][1][2]*t;
144                         numpoints++;
145                 }
146         }
147         return numpoints;
148 }
149
150 static int convex(float *p0, float *up, float *a, float *b)
151 {
152         // Vec3 va = a-p0, vb = b-p0;
153         float va[3], vb[3], tmp[3];
154         sub_v3_v3v3(va, a, p0);
155         sub_v3_v3v3(vb, b, p0);
156         cross_v3_v3v3(tmp, va, vb);
157         return dot_v3v3(up, tmp) >= 0;
158 }
159
160 void draw_volume(ARegion *ar, GPUTexture *tex, float *min, float *max, int res[3], float dx, GPUTexture *tex_shadow)
161 {
162         RegionView3D *rv3d= ar->regiondata;
163
164         float viewnormal[3];
165         int i, j, n, good_index;
166         float d /*, d0 */ /* UNUSED */, dd, ds;
167         float *points = NULL;
168         int numpoints = 0;
169         float cor[3] = {1.,1.,1.};
170         int gl_depth = 0, gl_blend = 0;
171
172         /* draw slices of smoke is adapted from c++ code authored
173          * by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
174         float cv[][3] = {
175                 {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
176                 {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
177         };
178
179         // edges have the form edges[n][0][xyz] + t*edges[n][1][xyz]
180         float edges[12][2][3] = {
181                 {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
182                 {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
183                 {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
184                 {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
185
186                 {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
187                 {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
188                 {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
189                 {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
190
191                 {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
192                 {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
193                 {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
194                 {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
195         };
196
197         /* Fragment program to calculate the view3d of smoke */
198         /* using 2 textures, density and shadow */
199         const char *text = "!!ARBfp1.0\n"
200                                         "PARAM dx = program.local[0];\n"
201                                         "PARAM darkness = program.local[1];\n"
202                                         "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
203                                         "TEMP temp, shadow, value;\n"
204                                         "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
205                                         "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
206                                         "MUL value, temp, darkness;\n"
207                                         "MUL value, value, dx;\n"
208                                         "MUL value, value, f;\n"
209                                         "EX2 temp, -value.r;\n"
210                                         "SUB temp.a, 1.0, temp.r;\n"
211                                         "MUL temp.r, temp.r, shadow.r;\n"
212                                         "MUL temp.g, temp.g, shadow.r;\n"
213                                         "MUL temp.b, temp.b, shadow.r;\n"
214                                         "MOV result.color, temp;\n"
215                                         "END\n";
216         GLuint prog;
217
218         
219         float size[3];
220
221         if (!tex) {
222                 printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
223                 return;
224         }
225
226         tstart();
227
228         sub_v3_v3v3(size, max, min);
229
230         // maxx, maxy, maxz
231         cv[0][0] = max[0];
232         cv[0][1] = max[1];
233         cv[0][2] = max[2];
234         // minx, maxy, maxz
235         cv[1][0] = min[0];
236         cv[1][1] = max[1];
237         cv[1][2] = max[2];
238         // minx, miny, maxz
239         cv[2][0] = min[0];
240         cv[2][1] = min[1];
241         cv[2][2] = max[2];
242         // maxx, miny, maxz
243         cv[3][0] = max[0];
244         cv[3][1] = min[1];
245         cv[3][2] = max[2];
246
247         // maxx, maxy, minz
248         cv[4][0] = max[0];
249         cv[4][1] = max[1];
250         cv[4][2] = min[2];
251         // minx, maxy, minz
252         cv[5][0] = min[0];
253         cv[5][1] = max[1];
254         cv[5][2] = min[2];
255         // minx, miny, minz
256         cv[6][0] = min[0];
257         cv[6][1] = min[1];
258         cv[6][2] = min[2];
259         // maxx, miny, minz
260         cv[7][0] = max[0];
261         cv[7][1] = min[1];
262         cv[7][2] = min[2];
263
264         copy_v3_v3(edges[0][0], cv[4]); // maxx, maxy, minz
265         copy_v3_v3(edges[1][0], cv[5]); // minx, maxy, minz
266         copy_v3_v3(edges[2][0], cv[6]); // minx, miny, minz
267         copy_v3_v3(edges[3][0], cv[7]); // maxx, miny, minz
268
269         copy_v3_v3(edges[4][0], cv[3]); // maxx, miny, maxz
270         copy_v3_v3(edges[5][0], cv[2]); // minx, miny, maxz
271         copy_v3_v3(edges[6][0], cv[6]); // minx, miny, minz
272         copy_v3_v3(edges[7][0], cv[7]); // maxx, miny, minz
273
274         copy_v3_v3(edges[8][0], cv[1]); // minx, maxy, maxz
275         copy_v3_v3(edges[9][0], cv[2]); // minx, miny, maxz
276         copy_v3_v3(edges[10][0], cv[6]); // minx, miny, minz
277         copy_v3_v3(edges[11][0], cv[5]); // minx, maxy, minz
278
279         // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
280         // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);
281
282         edges[0][1][2] = size[2];
283         edges[1][1][2] = size[2];
284         edges[2][1][2] = size[2];
285         edges[3][1][2] = size[2];
286
287         edges[4][1][1] = size[1];
288         edges[5][1][1] = size[1];
289         edges[6][1][1] = size[1];
290         edges[7][1][1] = size[1];
291
292         edges[8][1][0] = size[0];
293         edges[9][1][0] = size[0];
294         edges[10][1][0] = size[0];
295         edges[11][1][0] = size[0];
296
297         glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
298         glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
299
300         glLoadMatrixf(rv3d->viewmat);
301         // glMultMatrixf(ob->obmat);    
302
303         glDepthMask(GL_FALSE);
304         glDisable(GL_DEPTH_TEST);
305         glEnable(GL_BLEND);
306         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
307
308 #if 0
309         printf("Viewinv:\n");
310         printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]);
311         printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]);
312         printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]);
313 #endif
314
315         // get view vector
316         copy_v3_v3(viewnormal, rv3d->viewinv[2]);
317         normalize_v3(viewnormal);
318
319         // find cube vertex that is closest to the viewer
320         for (i=0; i<8; i++) {
321                 float x,y,z;
322
323                 x = cv[i][0] - viewnormal[0];
324                 y = cv[i][1] - viewnormal[1];
325                 z = cv[i][2] - viewnormal[2];
326
327                 if ((x>=min[0])&&(x<=max[0])
328                         &&(y>=min[1])&&(y<=max[1])
329                         &&(z>=min[2])&&(z<=max[2])) {
330                         break;
331                 }
332         }
333
334         if (i >= 8) {
335                 /* fallback, avoid using buffer over-run */
336                 i= 0;
337         }
338
339         // printf("i: %d\n", i);
340         // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
341
342         if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program"))
343         {
344                 glEnable(GL_FRAGMENT_PROGRAM_ARB);
345                 glGenProgramsARB(1, &prog);
346
347                 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
348                 glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text);
349
350                 // cell spacing
351                 glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
352                 // custom parameter for smoke style (higher = thicker)
353                 glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0);
354         }
355         else
356                 printf("Your gfx card does not support 3D View smoke drawing.\n");
357
358         GPU_texture_bind(tex, 0);
359         if (tex_shadow)
360                 GPU_texture_bind(tex_shadow, 1);
361         else
362                 printf("No volume shadow\n");
363
364         if (!GPU_non_power_of_two_support()) {
365                 cor[0] = (float)res[0]/(float)power_of_2_max_i(res[0]);
366                 cor[1] = (float)res[1]/(float)power_of_2_max_i(res[1]);
367                 cor[2] = (float)res[2]/(float)power_of_2_max_i(res[2]);
368         }
369
370         // our slices are defined by the plane equation a*x + b*y +c*z + d = 0
371         // (a,b,c), the plane normal, are given by viewdir
372         // d is the parameter along the view direction. the first d is given by
373         // inserting previously found vertex into the plane equation
374
375         /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
376         ds = (ABS(viewnormal[0])*size[0] + ABS(viewnormal[1])*size[1] + ABS(viewnormal[2])*size[2]);
377         dd = 0.05; // ds/512.0f;
378         n = 0;
379         good_index = i;
380
381         // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);
382
383         points = MEM_callocN(sizeof(float)*12*3, "smoke_points_preview");
384
385         while (1) {
386                 float p0[3];
387                 float tmp_point[3], tmp_point2[3];
388
389                 if (dd*(float)n > ds)
390                         break;
391
392                 copy_v3_v3(tmp_point, viewnormal);
393                 mul_v3_fl(tmp_point, -dd*((ds/dd)-(float)n));
394                 add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
395                 d = dot_v3v3(tmp_point2, viewnormal);
396
397                 // printf("my d: %f\n", d);
398
399                 // intersect_edges returns the intersection points of all cube edges with
400                 // the given plane that lie within the cube
401                 numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);
402
403                 // printf("points: %d\n", numpoints);
404
405                 if (numpoints > 2) {
406                         copy_v3_v3(p0, points);
407
408                         // sort points to get a convex polygon
409                         for (i = 1; i < numpoints - 1; i++)
410                         {
411                                 for (j = i + 1; j < numpoints; j++)
412                                 {
413                                         if (!convex(p0, viewnormal, &points[j * 3], &points[i * 3]))
414                                         {
415                                                 float tmp2[3];
416                                                 copy_v3_v3(tmp2, &points[j * 3]);
417                                                 copy_v3_v3(&points[j * 3], &points[i * 3]);
418                                                 copy_v3_v3(&points[i * 3], tmp2);
419                                         }
420                                 }
421                         }
422
423                         // printf("numpoints: %d\n", numpoints);
424                         glBegin(GL_POLYGON);
425                         glColor3f(1.0, 1.0, 1.0);
426                         for (i = 0; i < numpoints; i++) {
427                                 glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
428                                              (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
429                                              (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
430                                 glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]);
431                         }
432                         glEnd();
433                 }
434                 n++;
435         }
436
437         tend();
438         // printf ( "Draw Time: %f\n",( float ) tval() );
439
440         if (tex_shadow)
441                 GPU_texture_unbind(tex_shadow);
442         GPU_texture_unbind(tex);
443
444         if (GLEW_ARB_fragment_program)
445         {
446                 glDisable(GL_FRAGMENT_PROGRAM_ARB);
447                 glDeleteProgramsARB(1, &prog);
448         }
449
450
451         MEM_freeN(points);
452
453         if (!gl_blend)
454                 glDisable(GL_BLEND);
455         if (gl_depth)
456         {
457                 glEnable(GL_DEPTH_TEST);
458                 glDepthMask(GL_TRUE);   
459         }
460 }
461