doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / space_view3d / drawvolume.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Daniel Genrich
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28
29 #include <string.h>
30 #include <math.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_scene_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_view3d_types.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_editVert.h"
41 #include "BLI_edgehash.h"
42 #include "BLI_rand.h"
43 #include "BLI_utildefines.h"
44
45 #include "BKE_curve.h"
46 #include "BKE_constraint.h" // for the get_constraint_target function
47 #include "BKE_DerivedMesh.h"
48 #include "BKE_deform.h"
49 #include "BKE_displist.h"
50 #include "BKE_effect.h"
51 #include "BKE_font.h"
52 #include "BKE_global.h"
53 #include "BKE_image.h"
54 #include "BKE_key.h"
55 #include "BKE_lattice.h"
56 #include "BKE_mesh.h"
57 #include "BKE_material.h"
58 #include "BKE_mball.h"
59 #include "BKE_modifier.h"
60 #include "BKE_object.h"
61 #include "BKE_paint.h"
62 #include "BKE_particle.h"
63 #include "BKE_property.h"
64 #include "BKE_smoke.h"
65
66 #include "smoke_API.h"
67
68 #include "BIF_gl.h"
69
70 #include "GPU_extensions.h"
71
72 #include "ED_mesh.h"
73
74
75 #include "BLF_api.h"
76
77
78 #include "view3d_intern.h"      // own include
79
80
81 #ifdef _WIN32
82 #include <time.h>
83 #include <stdio.h>
84 #include <conio.h>
85 #include <windows.h>
86
87 static LARGE_INTEGER liFrequency;
88 static LARGE_INTEGER liStartTime;
89 static LARGE_INTEGER liCurrentTime;
90
91 static void tstart ( void )
92 {
93         QueryPerformanceFrequency ( &liFrequency );
94         QueryPerformanceCounter ( &liStartTime );
95 }
96 static void tend ( void )
97 {
98         QueryPerformanceCounter ( &liCurrentTime );
99 }
100 static double tval( void )
101 {
102         return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
103 }
104 #else
105 #include <sys/time.h>
106 static struct timeval _tstart, _tend;
107 static struct timezone tz;
108 static void tstart ( void )
109 {
110         gettimeofday ( &_tstart, &tz );
111 }
112 static void tend ( void )
113 {
114         gettimeofday ( &_tend,&tz );
115 }
116   #if 0
117 static double tval()
118 {
119         double t1, t2;
120         t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
121         t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
122         return t2-t1;
123 }
124   #endif
125 #endif
126
127 struct GPUTexture;
128
129 static int intersect_edges(float *points, float a, float b, float c, float d, float edges[12][2][3])
130 {
131         int i;
132         float t;
133         int numpoints = 0;
134         
135         for (i=0; i<12; i++) {
136                 t = -(a*edges[i][0][0] + b*edges[i][0][1] + c*edges[i][0][2] + d)
137                         / (a*edges[i][1][0] + b*edges[i][1][1] + c*edges[i][1][2]);
138                 if ((t>0)&&(t<1)) {
139                         points[numpoints * 3 + 0] = edges[i][0][0] + edges[i][1][0]*t;
140                         points[numpoints * 3 + 1] = edges[i][0][1] + edges[i][1][1]*t;
141                         points[numpoints * 3 + 2] = edges[i][0][2] + edges[i][1][2]*t;
142                         numpoints++;
143                 }
144         }
145         return numpoints;
146 }
147
148 static int convex(float *p0, float *up, float *a, float *b)
149 {
150         // Vec3 va = a-p0, vb = b-p0;
151         float va[3], vb[3], tmp[3];
152         VECSUB(va, a, p0);
153         VECSUB(vb, b, p0);
154         cross_v3_v3v3(tmp, va, vb);
155         return INPR(up, tmp) >= 0;
156 }
157
158 // copied from gpu_extension.c
159 static int is_pow2(int n)
160 {
161         return ((n)&(n-1))==0;
162 }
163
164 static int larger_pow2(int n)
165 {
166         if (is_pow2(n))
167                 return n;
168
169         while(!is_pow2(n))
170                 n= n&(n-1);
171
172         return n*2;
173 }
174
175 void draw_volume(ARegion *ar, GPUTexture *tex, float *min, float *max, int res[3], float dx, GPUTexture *tex_shadow)
176 {
177         RegionView3D *rv3d= ar->regiondata;
178
179         float viewnormal[3];
180         int i, j, n, good_index;
181         float d, d0, dd, ds;
182         float *points = NULL;
183         int numpoints = 0;
184         float cor[3] = {1.,1.,1.};
185         int gl_depth = 0, gl_blend = 0;
186
187         /* draw slices of smoke is adapted from c++ code authored by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
188         float cv[][3] = {
189                 {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
190                 {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
191         };
192
193         // edges have the form edges[n][0][xyz] + t*edges[n][1][xyz]
194         float edges[12][2][3] = {
195                 {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
196                 {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
197                 {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
198                 {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
199
200                 {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
201                 {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
202                 {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
203                 {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
204
205                 {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
206                 {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
207                 {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
208                 {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
209         };
210
211         /* Fragment program to calculate the view3d of smoke */
212         /* using 2 textures, density and shadow */
213         const char *text = "!!ARBfp1.0\n"
214                                         "PARAM dx = program.local[0];\n"
215                                         "PARAM darkness = program.local[1];\n"
216                                         "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
217                                         "TEMP temp, shadow, value;\n"
218                                         "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
219                                         "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
220                                         "MUL value, temp, darkness;\n"
221                                         "MUL value, value, dx;\n"
222                                         "MUL value, value, f;\n"
223                                         "EX2 temp, -value.r;\n"
224                                         "SUB temp.a, 1.0, temp.r;\n"
225                                         "MUL temp.r, temp.r, shadow.r;\n"
226                                         "MUL temp.g, temp.g, shadow.r;\n"
227                                         "MUL temp.b, temp.b, shadow.r;\n"
228                                         "MOV result.color, temp;\n"
229                                         "END\n";
230         GLuint prog;
231
232         
233         float size[3];
234
235         if(!tex) {
236                 printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
237                 return;
238         }
239
240         tstart();
241
242         VECSUB(size, max, min);
243
244         // maxx, maxy, maxz
245         cv[0][0] = max[0];
246         cv[0][1] = max[1];
247         cv[0][2] = max[2];
248         // minx, maxy, maxz
249         cv[1][0] = min[0];
250         cv[1][1] = max[1];
251         cv[1][2] = max[2];
252         // minx, miny, maxz
253         cv[2][0] = min[0];
254         cv[2][1] = min[1];
255         cv[2][2] = max[2];
256         // maxx, miny, maxz
257         cv[3][0] = max[0];
258         cv[3][1] = min[1];
259         cv[3][2] = max[2];
260
261         // maxx, maxy, minz
262         cv[4][0] = max[0];
263         cv[4][1] = max[1];
264         cv[4][2] = min[2];
265         // minx, maxy, minz
266         cv[5][0] = min[0];
267         cv[5][1] = max[1];
268         cv[5][2] = min[2];
269         // minx, miny, minz
270         cv[6][0] = min[0];
271         cv[6][1] = min[1];
272         cv[6][2] = min[2];
273         // maxx, miny, minz
274         cv[7][0] = max[0];
275         cv[7][1] = min[1];
276         cv[7][2] = min[2];
277
278         VECCOPY(edges[0][0], cv[4]); // maxx, maxy, minz
279         VECCOPY(edges[1][0], cv[5]); // minx, maxy, minz
280         VECCOPY(edges[2][0], cv[6]); // minx, miny, minz
281         VECCOPY(edges[3][0], cv[7]); // maxx, miny, minz
282
283         VECCOPY(edges[4][0], cv[3]); // maxx, miny, maxz
284         VECCOPY(edges[5][0], cv[2]); // minx, miny, maxz
285         VECCOPY(edges[6][0], cv[6]); // minx, miny, minz
286         VECCOPY(edges[7][0], cv[7]); // maxx, miny, minz
287
288         VECCOPY(edges[8][0], cv[1]); // minx, maxy, maxz
289         VECCOPY(edges[9][0], cv[2]); // minx, miny, maxz
290         VECCOPY(edges[10][0], cv[6]); // minx, miny, minz
291         VECCOPY(edges[11][0], cv[5]); // minx, maxy, minz
292
293         // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
294         // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);
295
296         edges[0][1][2] = size[2];
297         edges[1][1][2] = size[2];
298         edges[2][1][2] = size[2];
299         edges[3][1][2] = size[2];
300
301         edges[4][1][1] = size[1];
302         edges[5][1][1] = size[1];
303         edges[6][1][1] = size[1];
304         edges[7][1][1] = size[1];
305
306         edges[8][1][0] = size[0];
307         edges[9][1][0] = size[0];
308         edges[10][1][0] = size[0];
309         edges[11][1][0] = size[0];
310
311         glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
312         glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
313
314         glLoadMatrixf(rv3d->viewmat);
315         // glMultMatrixf(ob->obmat);    
316
317         glDepthMask(GL_FALSE);
318         glDisable(GL_DEPTH_TEST);
319         glEnable(GL_BLEND);
320         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
321
322         /*
323         printf("Viewinv:\n");
324         printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]);
325         printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]);
326         printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]);
327         */
328
329         // get view vector
330         VECCOPY(viewnormal, rv3d->viewinv[2]);
331         normalize_v3(viewnormal);
332
333         // find cube vertex that is closest to the viewer
334         for (i=0; i<8; i++) {
335                 float x,y,z;
336
337                 x = cv[i][0] - viewnormal[0];
338                 y = cv[i][1] - viewnormal[1];
339                 z = cv[i][2] - viewnormal[2];
340
341                 if ((x>=min[0])&&(x<=max[0])
342                         &&(y>=min[1])&&(y<=max[1])
343                         &&(z>=min[2])&&(z<=max[2])) {
344                         break;
345                 }
346         }
347
348         if(i >= 8) {
349                 /* fallback, avoid using buffer over-run */
350                 i= 0;
351         }
352
353         // printf("i: %d\n", i);
354         // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
355
356         if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program"))
357         {
358                 glEnable(GL_FRAGMENT_PROGRAM_ARB);
359                 glGenProgramsARB(1, &prog);
360
361                 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
362                 glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text);
363
364                 // cell spacing
365                 glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
366                 // custom parameter for smoke style (higher = thicker)
367                 glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0);
368         }
369         else
370                 printf("Your gfx card does not support 3D View smoke drawing.\n");
371
372         GPU_texture_bind(tex, 0);
373         if(tex_shadow)
374                 GPU_texture_bind(tex_shadow, 1);
375         else
376                 printf("No volume shadow\n");
377
378         if (!GPU_non_power_of_two_support()) {
379                 cor[0] = (float)res[0]/(float)larger_pow2(res[0]);
380                 cor[1] = (float)res[1]/(float)larger_pow2(res[1]);
381                 cor[2] = (float)res[2]/(float)larger_pow2(res[2]);
382         }
383
384         // our slices are defined by the plane equation a*x + b*y +c*z + d = 0
385         // (a,b,c), the plane normal, are given by viewdir
386         // d is the parameter along the view direction. the first d is given by
387         // inserting previously found vertex into the plane equation
388         d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]);
389         ds = (ABS(viewnormal[0])*size[0] + ABS(viewnormal[1])*size[1] + ABS(viewnormal[2])*size[2]);
390         dd = 0.05; // ds/512.0f;
391         n = 0;
392         good_index = i;
393
394         // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);
395
396         points = MEM_callocN(sizeof(float)*12*3, "smoke_points_preview");
397
398         while(1) {
399                 float p0[3];
400                 float tmp_point[3], tmp_point2[3];
401
402                 if(dd*(float)n > ds)
403                         break;
404
405                 VECCOPY(tmp_point, viewnormal);
406                 mul_v3_fl(tmp_point, -dd*((ds/dd)-(float)n));
407                 VECADD(tmp_point2, cv[good_index], tmp_point);
408                 d = INPR(tmp_point2, viewnormal);
409
410                 // printf("my d: %f\n", d);
411
412                 // intersect_edges returns the intersection points of all cube edges with
413                 // the given plane that lie within the cube
414                 numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);
415
416                 // printf("points: %d\n", numpoints);
417
418                 if (numpoints > 2) {
419                         VECCOPY(p0, points);
420
421                         // sort points to get a convex polygon
422                         for(i = 1; i < numpoints - 1; i++)
423                         {
424                                 for(j = i + 1; j < numpoints; j++)
425                                 {
426                                         if(!convex(p0, viewnormal, &points[j * 3], &points[i * 3]))
427                                         {
428                                                 float tmp2[3];
429                                                 VECCOPY(tmp2, &points[j * 3]);
430                                                 VECCOPY(&points[j * 3], &points[i * 3]);
431                                                 VECCOPY(&points[i * 3], tmp2);
432                                         }
433                                 }
434                         }
435
436                         // printf("numpoints: %d\n", numpoints);
437                         glBegin(GL_POLYGON);
438                         glColor3f(1.0, 1.0, 1.0);
439                         for (i = 0; i < numpoints; i++) {
440                                 glTexCoord3d((points[i * 3 + 0] - min[0] )*cor[0]/size[0], (points[i * 3 + 1] - min[1])*cor[1]/size[1], (points[i * 3 + 2] - min[2])*cor[2]/size[2]);
441                                 glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]);
442                         }
443                         glEnd();
444                 }
445                 n++;
446         }
447
448         tend();
449         // printf ( "Draw Time: %f\n",( float ) tval() );
450
451         if(tex_shadow)
452                 GPU_texture_unbind(tex_shadow);
453         GPU_texture_unbind(tex);
454
455         if(GLEW_ARB_fragment_program)
456         {
457                 glDisable(GL_FRAGMENT_PROGRAM_ARB);
458                 glDeleteProgramsARB(1, &prog);
459         }
460
461
462         MEM_freeN(points);
463
464         if(!gl_blend)
465                 glDisable(GL_BLEND);
466         if(gl_depth)
467         {
468                 glEnable(GL_DEPTH_TEST);
469                 glDepthMask(GL_TRUE);   
470         }
471 }
472