Smoke:
[blender.git] / source / blender / blenkernel / intern / smoke.c
1 /**
2  * BKE_cloth.h
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) Blender Foundation.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): Daniel Genrich
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 /* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
33
34 #include <GL/glew.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include <float.h>
39 #include <math.h>
40 #include "stdio.h"
41
42 #include "BLI_linklist.h"
43 #include "BLI_rand.h"
44 #include "BLI_jitter.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_arithb.h"
47 #include "BLI_edgehash.h"
48 #include "BLI_kdtree.h"
49 #include "BLI_kdopbvh.h"
50
51 #include "BKE_cdderivedmesh.h"
52 #include "BKE_customdata.h"
53 #include "BKE_DerivedMesh.h"
54 #include "BKE_modifier.h"
55 #include "BKE_particle.h"
56 #include "BKE_utildefines.h"
57
58 #include "DNA_customdata_types.h"
59 #include "DNA_group_types.h"
60 #include "DNA_mesh_types.h"
61 #include "DNA_meshdata_types.h"
62 #include "DNA_modifier_types.h"
63 #include "DNA_object_types.h"
64 #include "DNA_particle_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_smoke_types.h"
67
68 #include "smoke_API.h"
69
70 #include "BKE_smoke.h"
71
72 #ifdef _WIN32
73 #include <time.h>
74 #include <stdio.h>
75 #include <conio.h>
76 #include <windows.h>
77
78 static LARGE_INTEGER liFrequency;
79 static LARGE_INTEGER liStartTime;
80 static LARGE_INTEGER liCurrentTime;
81
82 static void tstart ( void )
83 {
84         QueryPerformanceFrequency ( &liFrequency );
85         QueryPerformanceCounter ( &liStartTime );
86 }
87 static void tend ( void )
88 {
89         QueryPerformanceCounter ( &liCurrentTime );
90 }
91 static double tval()
92 {
93         return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
94 }
95 #else
96 #include <sys/time.h>
97 static struct timeval _tstart, _tend;
98 static struct timezone tz;
99 static void tstart ( void )
100 {
101         gettimeofday ( &_tstart, &tz );
102 }
103 static void tend ( void )
104 {
105         gettimeofday ( &_tend,&tz );
106 }
107 static double tval()
108 {
109         double t1, t2;
110         t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
111         t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
112         return t2-t1;
113 }
114 #endif
115
116 struct Object;
117 struct Scene;
118 struct DerivedMesh;
119 struct SmokeModifierData;
120
121 // forward declerations
122 static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct);
123 static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct);
124 void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
125
126 #define TRI_UVOFFSET (1./4.)
127
128 int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
129 {
130         if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
131         {
132                 size_t i;
133                 float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
134                 float size[3];
135                 MVert *verts = dm->getVertArray(dm);
136                 float scale = 0.0;
137                 int res = smd->domain->maxres;
138
139                 // get BB of domain
140                 for(i = 0; i < dm->getNumVerts(dm); i++)
141                 {
142                         float tmp[3];
143
144                         VECCOPY(tmp, verts[i].co);
145                         Mat4MulVecfl(ob->obmat, tmp);
146
147                         // min BB
148                         min[0] = MIN2(min[0], tmp[0]);
149                         min[1] = MIN2(min[1], tmp[1]);
150                         min[2] = MIN2(min[2], tmp[2]);
151
152                         // max BB
153                         max[0] = MAX2(max[0], tmp[0]);
154                         max[1] = MAX2(max[1], tmp[1]);
155                         max[2] = MAX2(max[2], tmp[2]);
156                 }
157
158                 VECCOPY(smd->domain->p0, min);
159                 VECCOPY(smd->domain->p1, max);
160
161                 // calc other res with max_res provided
162                 VECSUB(size, max, min);
163                 if(size[0] > size[1])
164                 {
165                         if(size[0] > size[1])
166                         {
167                                 scale = res / size[0];
168                                 smd->domain->dx = size[0] / res;
169                                 smd->domain->res[0] = res;
170                                 smd->domain->res[1] = (int)(size[1] * scale + 0.5);
171                                 smd->domain->res[2] = (int)(size[2] * scale + 0.5);
172                         }
173                         else
174                         {
175                                 scale = res / size[1];
176                                 smd->domain->dx = size[1] / res;
177                                 smd->domain->res[1] = res;
178                                 smd->domain->res[0] = (int)(size[0] * scale + 0.5);
179                                 smd->domain->res[2] = (int)(size[2] * scale + 0.5);
180                         }
181                 }
182                 else
183                 {
184                         if(size[1] > size[2])
185                         {
186                                 scale = res / size[1];
187                                 smd->domain->dx = size[1] / res;
188                                 smd->domain->res[1] = res;
189                                 smd->domain->res[0] = (int)(size[0] * scale + 0.5);
190                                 smd->domain->res[2] = (int)(size[2] * scale + 0.5);
191                         }
192                         else
193                         {
194                                 scale = res / size[2];
195                                 smd->domain->dx = size[2] / res;
196                                 smd->domain->res[2] = res;
197                                 smd->domain->res[0] = (int)(size[0] * scale + 0.5);
198                                 smd->domain->res[1] = (int)(size[1] * scale + 0.5);
199                         }
200                 }
201
202                 // TODO: put in failsafe if res<=0 - dg
203
204                 // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
205
206                 // dt max is 0.1
207                 smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->amplify, smd->domain->p0, smd->domain->p1, 2.5 / FPS);
208                 smd->time = scene->r.cfra;
209                 smd->domain->firstframe = smd->time;
210                 
211                 smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta));
212
213                 return 1;
214         }
215         else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
216         {
217                 // handle flow object here
218                 // XXX TODO
219
220                 smd->time = scene->r.cfra;
221
222                 // update particle lifetime to be one frame
223                 // smd->flow->psys->part->lifetime = scene->r.efra + 1;
224
225                 return 1;
226         }
227         else if((smd->type & MOD_SMOKE_TYPE_COLL))
228         {
229                 smd->time = scene->r.cfra;
230
231                 // todo: delete this when loading colls work -dg
232                 if(!smd->coll)
233                         smokeModifier_createType(smd);
234
235                 if(!smd->coll->points)
236                 {
237                         // init collision points
238                         SmokeCollSettings *scs = smd->coll;
239                         MVert *mvert = dm->getVertArray(dm);
240                         MFace *mface = dm->getFaceArray(dm);
241                         size_t i = 0, divs = 0;
242                         int *tridivs = NULL;
243                         float cell_len = 1.0 / 50.0; // for res = 50
244                         size_t newdivs = 0;
245                         size_t max_points = 0;
246                         size_t quads = 0, facecounter = 0;
247
248                         // count quads
249                         for(i = 0; i < dm->getNumFaces(dm); i++)
250                         {
251                                 if(mface[i].v4)
252                                         quads++;
253                         }
254
255                         calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface,  dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
256
257                         // count triangle divisions
258                         for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
259                         {
260                                 divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
261                         }
262
263                         // printf("divs: %d\n", divs);
264
265                         scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
266
267                         for(i = 0; i < dm->getNumVerts(dm); i++)
268                         {
269                                 float tmpvec[3];
270                                 VECCOPY(tmpvec, mvert[i].co);
271                                 Mat4MulVecfl (ob->obmat, tmpvec);
272                                 VECCOPY(&scs->points[i * 3], tmpvec);
273                         }
274                         
275                         for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
276                         {
277                                 int again = 0;
278                                 do
279                                 {
280                                         size_t j, k;
281                                         int divs1 = tridivs[3 * facecounter + 0];
282                                         int divs2 = tridivs[3 * facecounter + 1];
283                                         int divs3 = tridivs[3 * facecounter + 2];
284                                         float side1[3], side2[3], trinormorg[3], trinorm[3];
285                                         
286                                         if(again == 1 && mface[i].v4)
287                                         {
288                                                 VECSUB(side1,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
289                                                 VECSUB(side2,  mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
290                                         }
291                                         else
292                                         {
293                                                 VECSUB(side1,  mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
294                                                 VECSUB(side2,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
295                                         }
296
297                                         Crossf(trinormorg, side1, side2);
298                                         Normalize(trinormorg);
299                                         VECCOPY(trinorm, trinormorg);
300                                         VecMulf(trinorm, 0.25 * cell_len);
301
302                                         for(j = 0; j <= divs1; j++)
303                                         {
304                                                 for(k = 0; k <= divs2; k++)
305                                                 {
306                                                         float p1[3], p2[3], p3[3], p[3]={0,0,0}; 
307                                                         const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
308                                                         const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
309                                                         float tmpvec[3];
310                                                         
311                                                         if(uf+vf > 1.0) 
312                                                         {
313                                                                 // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
314                                                                 continue;
315                                                         }
316
317                                                         VECCOPY(p1, mvert[ mface[i].v1 ].co);
318                                                         if(again == 1 && mface[i].v4)
319                                                         {
320                                                                 VECCOPY(p2, mvert[ mface[i].v3 ].co);
321                                                                 VECCOPY(p3, mvert[ mface[i].v4 ].co);
322                                                         }
323                                                         else
324                                                         {
325                                                                 VECCOPY(p2, mvert[ mface[i].v2 ].co);
326                                                                 VECCOPY(p3, mvert[ mface[i].v3 ].co);
327                                                         }
328
329                                                         VecMulf(p1, (1.0-uf-vf));
330                                                         VecMulf(p2, uf);
331                                                         VecMulf(p3, vf);
332                                                         
333                                                         VECADD(p, p1, p2);
334                                                         VECADD(p, p, p3);
335
336                                                         if(newdivs > divs)
337                                                                 printf("mem problem\n");
338
339                                                         // mMovPoints.push_back(p + trinorm);
340                                                         VECCOPY(tmpvec, p);
341                                                         VECADD(tmpvec, tmpvec, trinorm);
342                                                         Mat4MulVecfl (ob->obmat, tmpvec);
343                                                         VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
344                                                         newdivs++;
345
346                                                         if(newdivs > divs)
347                                                                 printf("mem problem\n");
348
349                                                         // mMovPoints.push_back(p - trinorm);
350                                                         VECCOPY(tmpvec, p);
351                                                         VECSUB(tmpvec, tmpvec, trinorm);
352                                                         Mat4MulVecfl (ob->obmat, tmpvec);
353                                                         VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
354                                                         newdivs++;
355                                                 }
356                                         }
357
358                                         if(again == 0 && mface[i].v4)
359                                                 again++;
360                                         else
361                                                 again = 0;
362
363                                         facecounter++;
364
365                                 } while(again!=0);
366                         }
367
368                         scs->numpoints = dm->getNumVerts(dm) + newdivs;
369
370                         MEM_freeN(tridivs);
371                 }
372
373         }
374
375         return 0;
376 }
377
378 /*! init triangle divisions */
379 void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) 
380 {
381         // mTriangleDivs1.resize( faces.size() );
382         // mTriangleDivs2.resize( faces.size() );
383         // mTriangleDivs3.resize( faces.size() );
384
385         size_t i = 0, facecounter = 0;
386         float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale);
387         float maxpart = ABS(maxscale[0]);
388         float scaleFac = 0;
389         float fsTri = 0;
390         if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
391         if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
392         scaleFac = 1.0 / maxpart;
393         // featureSize = mLevel[mMaxRefine].nodeSize
394         fsTri = cell_len * 0.5 * scaleFac;
395
396         if(*tridivs)
397                 MEM_freeN(*tridivs);
398
399         *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
400
401         for(i = 0, facecounter = 0; i < numfaces; i++) 
402         {
403                 float p0[3], p1[3], p2[3];
404                 float side1[3];
405                 float side2[3];
406                 float side3[3];
407                 int divs1=0, divs2=0, divs3=0;
408
409                 VECCOPY(p0, verts[faces[i].v1].co);
410                 Mat4MulVecfl (ob->obmat, p0);
411                 VECCOPY(p1, verts[faces[i].v2].co);
412                 Mat4MulVecfl (ob->obmat, p1);
413                 VECCOPY(p2, verts[faces[i].v3].co);
414                 Mat4MulVecfl (ob->obmat, p2);
415
416                 VECSUB(side1, p1, p0);
417                 VECSUB(side2, p2, p0);
418                 VECSUB(side3, p1, p2);
419
420                 if(INPR(side1, side1) > fsTri*fsTri) 
421                 { 
422                         float tmp = Normalize(side1);
423                         divs1 = (int)(tmp/fsTri); 
424                 }
425                 if(INPR(side2, side2) > fsTri*fsTri) 
426                 { 
427                         float tmp = Normalize(side2);
428                         divs2 = (int)(tmp/fsTri); 
429                         
430                         /*
431                         // debug
432                         if(i==0)
433                                 printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
434                         */
435                 }
436
437                 (*tridivs)[3 * facecounter + 0] = divs1;
438                 (*tridivs)[3 * facecounter + 1] = divs2;
439                 (*tridivs)[3 * facecounter + 2] = divs3;
440
441                 // TODO quad case
442                 if(faces[i].v4)
443                 {
444                         divs1=0, divs2=0, divs3=0;
445
446                         facecounter++;
447                         
448                         VECCOPY(p1, verts[faces[i].v3].co);
449                         Mat4MulVecfl (ob->obmat, p1);
450                         VECCOPY(p2, verts[faces[i].v4].co);
451                         Mat4MulVecfl (ob->obmat, p2);
452
453                         VECSUB(side1, p1, p0);
454                         VECSUB(side2, p2, p0);
455                         VECSUB(side3, p1, p2);
456
457                         if(INPR(side1, side1) > fsTri*fsTri) 
458                         { 
459                                 float tmp = Normalize(side1);
460                                 divs1 = (int)(tmp/fsTri); 
461                         }
462                         if(INPR(side2, side2) > fsTri*fsTri) 
463                         { 
464                                 float tmp = Normalize(side2);
465                                 divs2 = (int)(tmp/fsTri); 
466                         }
467
468                         (*tridivs)[3 * facecounter + 0] = divs1;
469                         (*tridivs)[3 * facecounter + 1] = divs2;
470                         (*tridivs)[3 * facecounter + 2] = divs3;
471                 }
472                 facecounter++;
473         }
474 }
475
476 void smokeModifier_freeDomain(SmokeModifierData *smd)
477 {
478         if(smd->domain)
479         {
480                 // free visualisation buffers
481                 if(smd->domain->bind)
482                 {
483                         glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
484                         MEM_freeN(smd->domain->bind);
485                 }
486                 smd->domain->max_textures = 0; // unnecessary but let's be sure
487
488                 if(smd->domain->tray)
489                         MEM_freeN(smd->domain->tray);
490                 if(smd->domain->tvox)
491                         MEM_freeN(smd->domain->tvox);
492                 if(smd->domain->traybig)
493                         MEM_freeN(smd->domain->traybig);
494                 if(smd->domain->tvoxbig)
495                         MEM_freeN(smd->domain->tvoxbig);
496
497                 if(smd->domain->fluid)
498                 {
499                         smoke_free(smd->domain->fluid);
500                 }
501                 MEM_freeN(smd->domain);
502                 smd->domain = NULL;
503         }
504 }
505
506 void smokeModifier_freeFlow(SmokeModifierData *smd)
507 {
508         if(smd->flow)
509         {
510                 MEM_freeN(smd->flow);
511                 smd->flow = NULL;
512         }
513 }
514
515 void smokeModifier_freeCollision(SmokeModifierData *smd)
516 {
517         if(smd->coll)
518         {
519                 if(smd->coll->points)
520                 {
521                         MEM_freeN(smd->coll->points);
522                         smd->coll->points = NULL;
523                 }
524
525                 MEM_freeN(smd->coll);
526                 smd->coll = NULL;
527         }
528 }
529
530 void smokeModifier_reset(struct SmokeModifierData *smd)
531 {
532         if(smd)
533         {
534                 if(smd->domain)
535                 {
536                         // free visualisation buffers
537                         if(smd->domain->bind)
538                         {
539                                 glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
540                                 MEM_freeN(smd->domain->bind);
541                                 smd->domain->bind = NULL;
542                         }
543                         smd->domain->max_textures = 0;
544                         smd->domain->viewsettings = 0; // reset view for new frame
545
546                         if(smd->domain->tray)
547                                 MEM_freeN(smd->domain->tray);
548                         if(smd->domain->tvox)
549                                 MEM_freeN(smd->domain->tvox);
550                         if(smd->domain->traybig)
551                                 MEM_freeN(smd->domain->traybig);
552                         if(smd->domain->tvoxbig)
553                                 MEM_freeN(smd->domain->tvoxbig);
554
555                         smd->domain->tvox = NULL;
556                         smd->domain->tray = NULL;
557                         smd->domain->tvoxbig = NULL;
558                         smd->domain->traybig = NULL;
559
560                         if(smd->domain->fluid)
561                         {
562                                 smoke_free(smd->domain->fluid);
563                                 smd->domain->fluid = NULL;
564                         }
565                 }
566                 else if(smd->flow)
567                 {
568                                                 
569                 }
570                 else if(smd->coll)
571                 {
572                         if(smd->coll->points)
573                         {
574                                 MEM_freeN(smd->coll->points);
575                                 smd->coll->points = NULL;
576                         }
577                 }
578         }
579 }
580
581 void smokeModifier_free (SmokeModifierData *smd)
582 {
583         if(smd)
584         {
585                 smokeModifier_freeDomain(smd);
586                 smokeModifier_freeFlow(smd);
587                 smokeModifier_freeCollision(smd);
588         }
589 }
590
591 void smokeModifier_createType(struct SmokeModifierData *smd)
592 {
593         if(smd)
594         {
595                 if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
596                 {
597                         if(smd->domain)
598                                 smokeModifier_freeDomain(smd);
599
600                         smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
601
602                         smd->domain->smd = smd;
603
604                         /* set some standard values */
605                         smd->domain->fluid = NULL;
606                         smd->domain->eff_group = NULL;
607                         smd->domain->fluid_group = NULL;
608                         smd->domain->coll_group = NULL;
609                         smd->domain->maxres = 32;
610                         smd->domain->amplify = 2;
611                         smd->domain->omega = 0.5;
612                         smd->domain->alpha = -0.001;
613                         smd->domain->beta = 0.1;
614                         smd->domain->flags = 0;
615                         smd->domain->noise = MOD_SMOKE_NOISEWAVE;
616                         smd->domain->visibility = 1;
617
618                         // init 3dview buffer
619                         smd->domain->tvox = NULL;
620                         smd->domain->tray = NULL;
621                         smd->domain->tvoxbig = NULL;
622                         smd->domain->traybig = NULL;
623                         smd->domain->viewsettings = 0;
624                         smd->domain->bind = NULL;
625                         smd->domain->max_textures = 0;
626                 }
627                 else if(smd->type & MOD_SMOKE_TYPE_FLOW)
628                 {
629                         if(smd->flow)
630                                 smokeModifier_freeFlow(smd);
631
632                         smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
633
634                         smd->flow->smd = smd;
635
636                         /* set some standard values */
637                         smd->flow->density = 1.0;
638                         smd->flow->temp = 1.0;
639
640                         smd->flow->psys = NULL;
641
642                 }
643                 else if(smd->type & MOD_SMOKE_TYPE_COLL)
644                 {
645                         if(smd->coll)
646                                 smokeModifier_freeCollision(smd);
647
648                         smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
649
650                         smd->coll->smd = smd;
651                         smd->coll->points = NULL;
652                         smd->coll->numpoints = 0;
653                 }
654         }
655 }
656
657 // forward declaration
658 void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big);
659
660 void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
661 {       
662         if(scene->r.cfra >= smd->time)
663                 smokeModifier_init(smd, ob, scene, dm);
664
665         if((smd->type & MOD_SMOKE_TYPE_FLOW))
666         {
667                 if(scene->r.cfra > smd->time)
668                 {
669                         // XXX TODO
670                 }
671                 else if(scene->r.cfra < smd->time)
672                 {
673                         smd->time = scene->r.cfra;
674                         smokeModifier_reset(smd);
675                 }
676         }
677         else if((smd->type & MOD_SMOKE_TYPE_DOMAIN))
678         {
679                 SmokeDomainSettings *sds = smd->domain;
680                 
681                 if(scene->r.cfra > smd->time)
682                 {
683                         GroupObject *go = NULL;
684                         Base *base = NULL;
685                         int cnt_domain = 0;
686                         
687                         tstart();
688
689                         sds->viewsettings = 0; // reset view for new frame
690
691                         // check for 2nd domain, if not there -> no groups are necessary
692                         for(base = scene->base.first; base; base= base->next) 
693                         {
694                                 Object *ob1= base->object;
695                                 
696                                 if(ob1 && ob1 != ob)
697                                 {
698                                         ModifierData *tmd = modifiers_findByType(ob1, eModifierType_Smoke);
699
700                                         if(tmd && tmd->mode & (eModifierMode_Realtime | eModifierMode_Render))
701                                         {
702                                                 SmokeModifierData *tsmd = (SmokeModifierData *)tmd;
703
704                                                 if((tsmd->type & MOD_SMOKE_TYPE_DOMAIN))
705                                                 {
706                                                         cnt_domain++;
707                                                 }
708                                         }
709                                 }
710                         }
711
712                         // do flows and fluids
713                         if(sds->fluid_group || !cnt_domain)
714                         {
715                                 Object *otherobj = NULL;
716                                 ModifierData *md = NULL;
717
718                                 if(cnt_domain && !sds->fluid_group) // we use groups since we have 2 domains
719                                         go = sds->fluid_group->gobject.first;
720                                 else
721                                         base = scene->base.first;
722
723                                 while(base || go)
724                                 {
725                                         otherobj = NULL;
726
727                                         if(cnt_domain && !sds->fluid_group) 
728                                         {
729                                                 if(go->ob)
730                                                         otherobj = go->ob;
731                                         }
732                                         else
733                                                 otherobj = base->object;
734
735                                         if(!otherobj)
736                                         {
737                                                 if(cnt_domain && !sds->fluid_group)
738                                                         go = go->next;
739                                                 else
740                                                         base= base->next;
741
742                                                 continue;
743                                         }
744
745                                         md = modifiers_findByType(otherobj, eModifierType_Smoke);
746                                         
747                                         // check for active smoke modifier
748                                         if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
749                                         {
750                                                 SmokeModifierData *smd2 = (SmokeModifierData *)md;
751                                                 
752                                                 // check for initialized smoke object
753                                                 if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
754                                                 {
755                                                         // we got nice flow object
756                                                         SmokeFlowSettings *sfs = smd2->flow;
757                                                         
758                                                         if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
759                                                         {
760                                                                 ParticleSystem *psys = sfs->psys;
761                                                                 ParticleSettings *part=psys->part;
762                                                                 ParticleData *pa = NULL;
763                                                                 int p = 0;
764                                                                 float *density = smoke_get_density(sds->fluid);
765                                                                 float *bigdensity = smoke_get_bigdensity(sds->fluid);
766                                                                 float *heat = smoke_get_heat(sds->fluid);
767                                                                 float *velocity_x = smoke_get_velocity_x(sds->fluid);
768                                                                 float *velocity_y = smoke_get_velocity_y(sds->fluid);
769                                                                 float *velocity_z = smoke_get_velocity_z(sds->fluid);
770                                                                 int bigres[3];
771
772                                                                 smoke_get_bigres(smd->domain->fluid, bigres);
773                                                                 
774                                                                 // mostly copied from particle code
775                                                                 for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++)
776                                                                 {
777                                                                         int cell[3];
778                                                                         size_t i = 0;
779                                                                         size_t index = 0;
780                                                                         
781                                                                         if(pa->alive == PARS_KILLED) continue;
782                                                                         else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
783                                                                         else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue;
784                                                                         else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
785                                                                         
786                                                                         // VECCOPY(pos, pa->state.co);
787                                                                         // Mat4MulVecfl (ob->imat, pos);
788                                                                         
789                                                                         // 1. get corresponding cell
790                                                                         get_cell(smd, pa->state.co, cell, 0);
791                                                                 
792                                                                         // check if cell is valid (in the domain boundary)
793                                                                         for(i = 0; i < 3; i++)
794                                                                         {
795                                                                                 if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))
796                                                                                         continue;
797                                                                         }
798                                                                         
799                                                                         // 2. set cell values (heat, density and velocity)
800                                                                         index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
801                                                                         
802                                                                         if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) // this is inflow
803                                                                         {
804                                                                                 heat[index] = sfs->temp;
805                                                                                 density[index] = sfs->density;
806                                                                                 velocity_x[index] = pa->state.vel[0];
807                                                                                 velocity_y[index] = pa->state.vel[1];
808                                                                                 velocity_z[index] = pa->state.vel[2];
809
810                                                                                 // we need different handling for the high-res feature
811                                                                                 if(bigdensity)
812                                                                                 {
813                                                                                         // init all surrounding cells according to amplification, too
814                                                                                         int i, j, k;
815                                                                                         for(i = 0; i < smd->domain->amplify; i++)
816                                                                                                 for(j = 0; j < smd->domain->amplify; j++)
817                                                                                                         for(k = 0; k < smd->domain->amplify; k++)
818                                                                                                         {
819                                                                                                                 index = smoke_get_index(smd->domain->amplify * cell[0] + i, bigres[0], smd->domain->amplify * cell[1] + j, bigres[1], smd->domain->amplify * cell[2] + k);
820                                                                                                                 bigdensity[index] = sfs->density;
821                                                                                                         }
822                                                                                 }
823                                                                         }
824                                                                         else // outflow
825                                                                         {
826                                                                                 heat[index] = 0.f;
827                                                                                 density[index] = 0.f;
828                                                                                 velocity_x[index] = 0.f;
829                                                                                 velocity_y[index] = 0.f;
830                                                                                 velocity_z[index] = 0.f;
831
832                                                                                 // we need different handling for the high-res feature
833                                                                                 if(bigdensity)
834                                                                                 {
835                                                                                         // init all surrounding cells according to amplification, too
836                                                                                         int i, j, k;
837                                                                                         for(i = 0; i < smd->domain->amplify; i++)
838                                                                                                 for(j = 0; j < smd->domain->amplify; j++)
839                                                                                                         for(k = 0; k < smd->domain->amplify; k++)
840                                                                                                         {
841                                                                                                                 index = smoke_get_index(smd->domain->amplify * cell[0] + i, bigres[0], smd->domain->amplify * cell[1] + j, bigres[1], smd->domain->amplify * cell[2] + k);
842                                                                                                                 bigdensity[index] = 0.f;
843                                                                                                         }
844                                                                                 }
845                                                                         }
846                                                                 }
847                                                         }       
848                                                 }       
849                                         }
850
851                                         if(cnt_domain && !sds->fluid_group)
852                                                 go = go->next;
853                                         else
854                                                 base= base->next;
855                                 }
856                         }
857
858                         // do effectors
859                         /*
860                         if(sds->eff_group)
861                         {
862                                 for(go = sds->eff_group->gobject.first; go; go = go->next) 
863                                 {
864                                         if(go->ob)
865                                         {
866                                                 if(ob->pd)
867                                                 {
868                                                         
869                                                 }
870                                         }
871                                 }
872                         }
873                         */
874
875                         // do collisions        
876                         if(sds->coll_group || !cnt_domain)
877                         {
878                                 Object *otherobj = NULL;
879                                 ModifierData *md = NULL;
880
881                                 if(cnt_domain && !sds->coll_group) // we use groups since we have 2 domains
882                                         go = sds->coll_group->gobject.first;
883                                 else
884                                         base = scene->base.first;
885
886                                 while(base || go)
887                                 {
888                                         otherobj = NULL;
889
890                                         if(cnt_domain && !sds->coll_group) 
891                                         {
892                                                 if(go->ob)
893                                                         otherobj = go->ob;
894                                         }
895                                         else
896                                                 otherobj = base->object;
897
898                                         if(!otherobj)
899                                         {
900                                                 if(cnt_domain && !sds->coll_group)
901                                                         go = go->next;
902                                                 else
903                                                         base= base->next;
904
905                                                 continue;
906                                         }
907                         
908                                         md = modifiers_findByType(otherobj, eModifierType_Smoke);
909                                         
910                                         // check for active smoke modifier
911                                         if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
912                                         {
913                                                 SmokeModifierData *smd2 = (SmokeModifierData *)md;
914
915                                                 if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
916                                                 {
917                                                         // we got nice collision object
918                                                         SmokeCollSettings *scs = smd2->coll;
919                                                         int cell[3];
920                                                         size_t index = 0;
921                                                         size_t i, j;
922                                                         unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
923
924                                                         for(i = 0; i < scs->numpoints; i++)
925                                                         {
926                                                                 // 1. get corresponding cell
927                                                                 get_cell(smd, &scs->points[3 * i], cell, 0);
928                                                         
929                                                                 // check if cell is valid (in the domain boundary)
930                                                                 for(j = 0; j < 3; j++)
931                                                                         if((cell[j] > sds->res[j] - 1) || (cell[j] < 0))
932                                                                                 continue;
933                                                                 
934                                                                 // 2. set cell values (heat, density and velocity)
935                                                                 index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
936                                                                         
937                                                                 obstacles[index] = 1;
938
939                                                                 // for moving gobstacles
940                                                                 /*
941                                                                 const LbmFloat maxVelVal = 0.1666;
942                                                                 const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
943
944                                                                 LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { 
945                                                                 const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; 
946                                                                 USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); 
947                                                                 if(usqr>maxusqr) { 
948                                                                         // cutoff at maxVelVal 
949                                                                         for(int jj=0; jj<3; jj++) { 
950                                                                                 if(objvel[jj]>0.) objvel[jj] =  maxVelVal;  
951                                                                                 if(objvel[jj]<0.) objvel[jj] = -maxVelVal; 
952                                                                         } 
953                                                                 } } 
954
955                                                                 const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); 
956                                                                 const LbmVec oldov=objvel; // debug
957                                                                 objvel = vec2L((*pNormals)[n]) *dp;
958                                                                 */
959                                                         }
960                                                 }
961                                         }
962
963                                         if(cnt_domain && !sds->coll_group)
964                                                 go = go->next;
965                                         else
966                                                 base= base->next;
967                                 }
968                         }
969                         
970                         // set new time
971                         smd->time = scene->r.cfra;
972
973                         // simulate the actual smoke (c++ code in intern/smoke)
974                         smoke_step(sds->fluid);
975
976                         tend();
977                         printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() );
978                 }
979                 else if(scene->r.cfra < smd->time)
980                 {
981                         // we got back in time, reset smoke in this case (TODO: use cache later)
982                         smd->time = scene->r.cfra;
983                         smokeModifier_reset(smd);
984                 }
985         }
986 }
987
988 // update necessary information for 3dview
989 void smoke_prepare_View(SmokeModifierData *smd, float *light)
990 {
991         float *density = NULL;
992         int x, y, z;
993
994         if(!smd->domain->tray)
995         {
996                 // TRay is for self shadowing
997                 smd->domain->tray = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tRay");
998         }
999         if(!smd->domain->tvox)
1000         {
1001                 // TVox is for tranaparency
1002                 smd->domain->tvox = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tVox");
1003         }
1004
1005         // update 3dview
1006         density = smoke_get_density(smd->domain->fluid);
1007         for(x = 0; x < smd->domain->res[0]; x++)
1008                         for(y = 0; y < smd->domain->res[1]; y++)
1009                                 for(z = 0; z < smd->domain->res[2]; z++)
1010                                 {
1011                                         size_t index;
1012
1013                                         index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z);
1014                                         // Transparency computation
1015                                         // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
1016                                         // T_vox = exp(-C_ext * h)
1017                                         // C_ext/sigma_t = density * C_ext
1018                                         smoke_set_tvox(smd, index, exp(-density[index] * 4.0 * smd->domain->dx));
1019         }
1020         smoke_calc_transparency(smd, light, 0);
1021 }
1022
1023 // update necessary information for 3dview ("high res" option)
1024 void smoke_prepare_bigView(SmokeModifierData *smd, float *light)
1025 {
1026         float *density = NULL;
1027         size_t i = 0;
1028         int bigres[3];
1029
1030         smoke_get_bigres(smd->domain->fluid, bigres);
1031
1032         if(!smd->domain->traybig)
1033         {
1034                 // TRay is for self shadowing
1035                 smd->domain->traybig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tRayBig");
1036         }
1037         if(!smd->domain->tvoxbig)
1038         {
1039                 // TVox is for tranaparency
1040                 smd->domain->tvoxbig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tVoxBig");
1041         }
1042
1043         density = smoke_get_bigdensity(smd->domain->fluid);
1044         for (i = 0; i < bigres[0] * bigres[1] * bigres[2]; i++)
1045         {
1046                 // Transparency computation
1047                 // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
1048                 // T_vox = exp(-C_ext * h)
1049                 // C_ext/sigma_t = density * C_ext
1050                 smoke_set_bigtvox(smd, i, exp(-density[i] * 4.0 * smd->domain->dx / smd->domain->amplify) );
1051         }
1052         smoke_calc_transparency(smd, light, 1);
1053 }
1054
1055
1056 float smoke_get_tvox(SmokeModifierData *smd, size_t index)
1057 {
1058         return smd->domain->tvox[index];
1059 }
1060
1061 void smoke_set_tvox(SmokeModifierData *smd, size_t index, float tvox)
1062 {
1063         smd->domain->tvox[index] = tvox;
1064 }
1065
1066 float smoke_get_tray(SmokeModifierData *smd, size_t index)
1067 {
1068         return smd->domain->tray[index];
1069 }
1070
1071 void smoke_set_tray(SmokeModifierData *smd, size_t index, float transparency)
1072 {
1073         smd->domain->tray[index] = transparency;
1074 }
1075
1076 float smoke_get_bigtvox(SmokeModifierData *smd, size_t index)
1077 {
1078         return smd->domain->tvoxbig[index];
1079 }
1080
1081 void smoke_set_bigtvox(SmokeModifierData *smd, size_t index, float tvox)
1082 {
1083         smd->domain->tvoxbig[index] = tvox;
1084 }
1085
1086 float smoke_get_bigtray(SmokeModifierData *smd, size_t index)
1087 {
1088         return smd->domain->traybig[index];
1089 }
1090
1091 void smoke_set_bigtray(SmokeModifierData *smd, size_t index, float transparency)
1092 {
1093         smd->domain->traybig[index] = transparency;
1094 }
1095
1096 long long smoke_get_mem_req(int xres, int yres, int zres, int amplify)
1097 {
1098           int totalCells = xres * yres * zres;
1099           int amplifiedCells = totalCells * amplify * amplify * amplify;
1100
1101           // print out memory requirements
1102           long long int coarseSize = sizeof(float) * totalCells * 22 +
1103                            sizeof(unsigned char) * totalCells;
1104
1105           long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
1106                          sizeof(float) * totalCells * 8 +     // small grids
1107                          sizeof(float) * 128 * 128 * 128;     // noise tile
1108
1109           long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
1110
1111           return totalMB;
1112 }
1113
1114
1115 static void calc_voxel_transp(SmokeModifierData *smd, int *pixel, float *tRay)
1116 {
1117         // printf("Pixel(%d, %d, %d)\n", pixel[0], pixel[1], pixel[2]);
1118         const size_t index = smoke_get_index(pixel[0], smd->domain->res[0], pixel[1], smd->domain->res[1], pixel[2]);
1119
1120         // T_ray *= T_vox
1121         *tRay *= smoke_get_tvox(smd, index);
1122 }
1123
1124 static void calc_voxel_transp_big(SmokeModifierData *smd, int *pixel, float *tRay)
1125 {
1126         int bigres[3];
1127         size_t index;
1128
1129         smoke_get_bigres(smd->domain->fluid, bigres);
1130         index = smoke_get_index(pixel[0], bigres[0], pixel[1], bigres[1], pixel[2]);
1131
1132         /*
1133         if(index > bigres[0]*bigres[1]*bigres[2])
1134                 printf("pixel[0]: %d, [1]: %d, [2]: %d\n", pixel[0], pixel[1], pixel[2]);
1135         */
1136
1137         // T_ray *= T_vox
1138         *tRay *= smoke_get_bigtvox(smd, index);
1139 }
1140
1141 static void bresenham_linie_3D(SmokeModifierData *smd, int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, int big)
1142 {
1143     int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
1144     int pixel[3];
1145
1146     pixel[0] = x1;
1147     pixel[1] = y1;
1148     pixel[2] = z1;
1149
1150     dx = x2 - x1;
1151     dy = y2 - y1;
1152     dz = z2 - z1;
1153
1154     x_inc = (dx < 0) ? -1 : 1;
1155     l = abs(dx);
1156     y_inc = (dy < 0) ? -1 : 1;
1157     m = abs(dy);
1158     z_inc = (dz < 0) ? -1 : 1;
1159     n = abs(dz);
1160     dx2 = l << 1;
1161     dy2 = m << 1;
1162     dz2 = n << 1;
1163
1164     if ((l >= m) && (l >= n)) {
1165         err_1 = dy2 - l;
1166         err_2 = dz2 - l;
1167         for (i = 0; i < l; i++) {
1168                 if(!big)
1169                                 calc_voxel_transp(smd, pixel, tRay);
1170                         else
1171                                 calc_voxel_transp_big(smd, pixel, tRay);
1172                 if(*tRay < 0.0f)
1173                         return;
1174             if (err_1 > 0) {
1175                 pixel[1] += y_inc;
1176                 err_1 -= dx2;
1177             }
1178             if (err_2 > 0) {
1179                 pixel[2] += z_inc;
1180                 err_2 -= dx2;
1181             }
1182             err_1 += dy2;
1183             err_2 += dz2;
1184             pixel[0] += x_inc;
1185         }
1186     } else if ((m >= l) && (m >= n)) {
1187         err_1 = dx2 - m;
1188         err_2 = dz2 - m;
1189         for (i = 0; i < m; i++) {
1190                 if(!big)
1191                                 calc_voxel_transp(smd, pixel, tRay);
1192                         else
1193                                 calc_voxel_transp_big(smd, pixel, tRay);
1194                 if(*tRay < 0.0f)
1195                         return;
1196             if (err_1 > 0) {
1197                 pixel[0] += x_inc;
1198                 err_1 -= dy2;
1199             }
1200             if (err_2 > 0) {
1201                 pixel[2] += z_inc;
1202                 err_2 -= dy2;
1203             }
1204             err_1 += dx2;
1205             err_2 += dz2;
1206             pixel[1] += y_inc;
1207         }
1208     } else {
1209         err_1 = dy2 - n;
1210         err_2 = dx2 - n;
1211         for (i = 0; i < n; i++) {
1212                 if(!big)
1213                                 calc_voxel_transp(smd, pixel, tRay);
1214                         else
1215                                 calc_voxel_transp_big(smd, pixel, tRay);
1216                 if(*tRay < 0.0f)
1217                         return;
1218             if (err_1 > 0) {
1219                 pixel[1] += y_inc;
1220                 err_1 -= dz2;
1221             }
1222             if (err_2 > 0) {
1223                 pixel[0] += x_inc;
1224                 err_2 -= dz2;
1225             }
1226             err_1 += dy2;
1227             err_2 += dx2;
1228             pixel[2] += z_inc;
1229         }
1230     }
1231     if(!big)
1232         calc_voxel_transp(smd, pixel, tRay);
1233     else
1234         calc_voxel_transp_big(smd, pixel, tRay);
1235 }
1236
1237 static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct)
1238 {
1239         float tmp[3];
1240
1241         VECSUB(tmp, pos, smd->domain->p0);
1242         VecMulf(tmp, 1.0 / smd->domain->dx);
1243
1244         if(correct)
1245         {
1246                 cell[0] = MIN2(smd->domain->res[0] - 1, MAX2(0, (int)floor(tmp[0])));
1247                 cell[1] = MIN2(smd->domain->res[1] - 1, MAX2(0, (int)floor(tmp[1])));
1248                 cell[2] = MIN2(smd->domain->res[2] - 1, MAX2(0, (int)floor(tmp[2])));
1249         }
1250         else
1251         {
1252                 cell[0] = (int)floor(tmp[0]);
1253                 cell[1] = (int)floor(tmp[1]);
1254                 cell[2] = (int)floor(tmp[2]);
1255         }
1256 }
1257 static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct)
1258 {
1259         float tmp[3];
1260         int res[3];
1261         smoke_get_bigres(smd->domain->fluid, res);
1262
1263         VECSUB(tmp, pos, smd->domain->p0);
1264
1265         VecMulf(tmp, smd->domain->amplify / smd->domain->dx );
1266
1267         if(correct)
1268         {
1269                 cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0])));
1270                 cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1])));
1271                 cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2])));
1272         }
1273         else
1274         {
1275                 cell[0] = (int)floor(tmp[0]);
1276                 cell[1] = (int)floor(tmp[1]);
1277                 cell[2] = (int)floor(tmp[2]);
1278         }
1279 }
1280
1281
1282 void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big)
1283 {
1284         int x, y, z;
1285         float bv[6];
1286         int res[3];
1287         float bigfactor = 1.0;
1288
1289         // x
1290         bv[0] = smd->domain->p0[0];
1291         bv[1] = smd->domain->p1[0];
1292         // y
1293         bv[2] = smd->domain->p0[1];
1294         bv[3] = smd->domain->p1[1];
1295         // z
1296         bv[4] = smd->domain->p0[2];
1297         bv[5] = smd->domain->p1[2];
1298 /*
1299         printf("bv[0]: %f, [1]: %f, [2]: %f, [3]: %f, [4]: %f, [5]: %f\n", bv[0], bv[1], bv[2], bv[3], bv[4], bv[5]);
1300
1301         printf("p0[0]: %f, p0[1]: %f, p0[2]: %f\n", smd->domain->p0[0], smd->domain->p0[1], smd->domain->p0[2]);
1302         printf("p1[0]: %f, p1[1]: %f, p1[2]: %f\n", smd->domain->p1[0], smd->domain->p1[1], smd->domain->p1[2]);
1303         printf("dx: %f, amp: %d\n", smd->domain->dx, smd->domain->amplify);
1304 */
1305         if(!big)
1306         {
1307                 res[0] = smd->domain->res[0];
1308                 res[1] = smd->domain->res[1];
1309                 res[2] = smd->domain->res[2];
1310         }
1311         else
1312         {
1313                 smoke_get_bigres(smd->domain->fluid, res);
1314                 bigfactor = 1.0 / smd->domain->amplify;
1315         }
1316
1317 #pragma omp parallel for schedule(static) private(y, z) shared(big, smd, light, res, bigfactor)
1318         for(x = 0; x < res[0]; x++)
1319                 for(y = 0; y < res[1]; y++)
1320                         for(z = 0; z < res[2]; z++)
1321                         {
1322                                 float voxelCenter[3];
1323                                 size_t index;
1324                                 float pos[3];
1325                                 int cell[3];
1326                                 float tRay = 1.0;
1327
1328                                 index = smoke_get_index(x, res[0], y, res[1], z);
1329
1330                                 // voxelCenter = m_voxelarray[i].GetCenter();
1331                                 voxelCenter[0] = smd->domain->p0[0] + smd->domain->dx * bigfactor * x + smd->domain->dx * bigfactor * 0.5;
1332                                 voxelCenter[1] = smd->domain->p0[1] + smd->domain->dx * bigfactor * y + smd->domain->dx * bigfactor * 0.5;
1333                                 voxelCenter[2] = smd->domain->p0[2] + smd->domain->dx * bigfactor * z + smd->domain->dx * bigfactor * 0.5;
1334
1335                                 // printf("vc[0]: %f, vc[1]: %f, vc[2]: %f\n", voxelCenter[0], voxelCenter[1], voxelCenter[2]);
1336                                 // printf("light[0]: %f, light[1]: %f, light[2]: %f\n", light[0], light[1], light[2]);
1337
1338                                 // get starting position (in voxel coords)
1339                                 if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
1340                                 {
1341                                         // we're ouside
1342                                         // printf("out: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", pos[0], pos[1], pos[2]);
1343                                         if(!big)
1344                                                 get_cell(smd, pos, cell, 1);
1345                                         else
1346                                                 get_bigcell(smd, pos, cell, 1);
1347                                 }
1348                                 else
1349                                 {
1350                                         // printf("in: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", light[0], light[1], light[2]);
1351                                         // we're inside
1352                                         if(!big)
1353                                                 get_cell(smd, light, cell, 1);
1354                                         else
1355                                                 get_bigcell(smd, light, cell, 1);
1356                                 }
1357
1358                                 // printf("cell - [0]: %d, [1]: %d, [2]: %d\n", cell[0], cell[1], cell[2]);
1359                                 bresenham_linie_3D(smd, cell[0], cell[1], cell[2], x, y, z, &tRay, big);
1360
1361                                 if(!big)
1362                                         smoke_set_tray(smd, index, tRay);
1363                                 else
1364                                         smoke_set_bigtray(smd, index, tRay);
1365                         }
1366 }
1367