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