bb2227801c78406fc804ee1f65b015c9640cbd5d
[blender-staging.git] / intern / smoke / intern / FLUID_3D.cpp
1 //////////////////////////////////////////////////////////////////////
2 // This file is part of Wavelet Turbulence.
3 //
4 // Wavelet Turbulence is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Wavelet Turbulence is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
16 //
17 // Copyright 2008 Theodore Kim and Nils Thuerey
18 //
19 // FLUID_3D.cpp: implementation of the FLUID_3D class.
20 //
21 //////////////////////////////////////////////////////////////////////
22
23 #include "FLUID_3D.h"
24 #include "IMAGE.h"
25 #include <INTERPOLATE.h>
26 #include "SPHERE.h"
27 #include <zlib.h>
28
29 // boundary conditions of the fluid domain
30 #define DOMAIN_BC_FRONT  0 // z
31 #define DOMAIN_BC_TOP    1 // y
32 #define DOMAIN_BC_LEFT   1 // x
33 #define DOMAIN_BC_BACK   DOMAIN_BC_FRONT
34 #define DOMAIN_BC_BOTTOM DOMAIN_BC_TOP
35 #define DOMAIN_BC_RIGHT  DOMAIN_BC_LEFT
36
37 //////////////////////////////////////////////////////////////////////
38 // Construction/Destruction
39 //////////////////////////////////////////////////////////////////////
40
41 FLUID_3D::FLUID_3D(int *res, float *p0, float dt) :
42         _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f), _dt(dt)
43 {
44         // set simulation consts
45         // _dt = dt; // 0.10
46         
47         // start point of array
48         _p0[0] = p0[0];
49         _p0[1] = p0[1];
50         _p0[2] = p0[2];
51
52         _iterations = 100;
53         _tempAmb = 0; 
54         _heatDiffusion = 1e-3;
55         _vorticityEps = 2.0;
56         _totalTime = 0.0f;
57         _totalSteps = 0;
58         _res = Vec3Int(_xRes,_yRes,_zRes);
59         _maxRes = MAX3(_xRes, _yRes, _zRes);
60         
61         // initialize wavelet turbulence
62         /*
63         if(amplify)
64                 _wTurbulence = new WTURBULENCE(_res[0],_res[1],_res[2], amplify, noisetype);
65         else
66                 _wTurbulence = NULL;
67         */
68         
69         // scale the constants according to the refinement of the grid
70         _dx = 1.0f / (float)_maxRes;
71         float scaling = 64.0f / _maxRes;
72         scaling = (scaling < 1.0f) ? 1.0f : scaling;
73         _vorticityEps /= scaling;
74
75         // allocate arrays
76         _totalCells   = _xRes * _yRes * _zRes;
77         _slabSize = _xRes * _yRes;
78         _xVelocity    = new float[_totalCells];
79         _yVelocity    = new float[_totalCells];
80         _zVelocity    = new float[_totalCells];
81         _xVelocityOld = new float[_totalCells];
82         _yVelocityOld = new float[_totalCells];
83         _zVelocityOld = new float[_totalCells];
84         _xForce       = new float[_totalCells];
85         _yForce       = new float[_totalCells];
86         _zForce       = new float[_totalCells];
87         _density      = new float[_totalCells];
88         _densityOld   = new float[_totalCells];
89         _heat         = new float[_totalCells];
90         _heatOld      = new float[_totalCells];
91         _obstacles    = new unsigned char[_totalCells]; // set 0 at end of step
92
93         // DG TODO: check if alloc went fine
94
95         for (int x = 0; x < _totalCells; x++)
96         {
97                 _density[x]      = 0.0f;
98                 _densityOld[x]   = 0.0f;
99                 _heat[x]         = 0.0f;
100                 _heatOld[x]      = 0.0f;
101                 _xVelocity[x]    = 0.0f;
102                 _yVelocity[x]    = 0.0f;
103                 _zVelocity[x]    = 0.0f;
104                 _xVelocityOld[x] = 0.0f;
105                 _yVelocityOld[x] = 0.0f;
106                 _zVelocityOld[x] = 0.0f;
107                 _xForce[x]       = 0.0f;
108                 _yForce[x]       = 0.0f;
109                 _zForce[x]       = 0.0f;
110                 _obstacles[x]    = false;
111         }
112
113         // set side obstacles
114         int index;
115         for (int y = 0; y < _yRes; y++)
116         for (int x = 0; x < _xRes; x++)
117         {
118                 // front slab
119                 index = x + y * _xRes;
120                 if(DOMAIN_BC_FRONT==1) _obstacles[index] = 1;
121
122                 // back slab
123                 index += _totalCells - _slabSize;
124                 if(DOMAIN_BC_BACK==1) _obstacles[index] = 1;
125         }
126
127         for (int z = 0; z < _zRes; z++)
128         for (int x = 0; x < _xRes; x++)
129         {
130                 // bottom slab
131                 index = x + z * _slabSize;
132                 if(DOMAIN_BC_BOTTOM==1) _obstacles[index] = 1;
133
134                 // top slab
135                 index += _slabSize - _xRes;
136                 if(DOMAIN_BC_TOP==1) _obstacles[index] = 1;
137         }
138
139         for (int z = 0; z < _zRes; z++)
140         for (int y = 0; y < _yRes; y++)
141         {
142                 // left slab
143                 index = y * _xRes + z * _slabSize;
144                 if(DOMAIN_BC_LEFT==1) _obstacles[index] = 1;
145
146                 // right slab
147                 index += _xRes - 1;
148                 if(DOMAIN_BC_RIGHT==1) _obstacles[index] = 1;
149         }
150 }
151
152 FLUID_3D::~FLUID_3D()
153 {
154         if (_xVelocity) delete[] _xVelocity;
155         if (_yVelocity) delete[] _yVelocity;
156         if (_zVelocity) delete[] _zVelocity;
157         if (_xVelocityOld) delete[] _xVelocityOld;
158         if (_yVelocityOld) delete[] _yVelocityOld;
159         if (_zVelocityOld) delete[] _zVelocityOld;
160         if (_xForce) delete[] _xForce;
161         if (_yForce) delete[] _yForce;
162         if (_zForce) delete[] _zForce;
163         if (_density) delete[] _density;
164         if (_densityOld) delete[] _densityOld;
165         if (_heat) delete[] _heat;
166         if (_heatOld) delete[] _heatOld;
167         if (_obstacles) delete[] _obstacles;
168     // if (_wTurbulence) delete _wTurbulence;
169
170     // printf("deleted fluid\n");
171 }
172
173 // init direct access functions from blender
174 void FLUID_3D::initBlenderRNA(float *alpha, float *beta)
175 {
176         _alpha = alpha;
177         _beta = beta;
178 }
179
180 //////////////////////////////////////////////////////////////////////
181 // step simulation once
182 //////////////////////////////////////////////////////////////////////
183 void FLUID_3D::step()
184 {
185         // addSmokeTestCase(_density, _res);
186         // addSmokeTestCase(_heat, _res);
187         
188         // wipe forces
189         for (int i = 0; i < _totalCells; i++)
190         {
191                 _xForce[i] = _yForce[i] = _zForce[i] = 0.0f;
192                 // _obstacles[i] &= ~2;
193         }
194
195         wipeBoundaries();
196
197         // run the solvers
198         addVorticity();
199         addBuoyancy(_heat, _density);
200         addForce();
201         project();
202         diffuseHeat();
203
204         // advect everything
205         advectMacCormack();
206
207         // if(_wTurbulence) {
208         //      _wTurbulence->stepTurbulenceFull(_dt/_dx,
209         //                      _xVelocity, _yVelocity, _zVelocity, _obstacles);
210                 // _wTurbulence->stepTurbulenceReadable(_dt/_dx,
211                 //  _xVelocity, _yVelocity, _zVelocity, _obstacles);
212         // }
213 /*
214  // no file output
215   float *src = _density;
216         string prefix = string("./original.preview/density_fullxy_");
217         writeImageSliceXY(src,_res, _res[2]/2, prefix, _totalSteps);
218 */
219         // artificial damping -- this is necessary because we use a
220   // collated grid, and at very coarse grid resolutions, banding
221   // artifacts can occur
222         artificialDamping(_xVelocity);
223         artificialDamping(_yVelocity);
224         artificialDamping(_zVelocity);
225 /*
226 // no file output
227   string pbrtPrefix = string("./pbrt/density_small_");
228   IMAGE::dumpPBRT(_totalSteps, pbrtPrefix, _density, _res[0],_res[1],_res[2]);
229   */
230         _totalTime += _dt;
231         _totalSteps++;  
232
233         // todo xxx dg: only clear obstacles, not boundaries
234         // memset(_obstacles, 0, sizeof(unsigned char)*_xRes*_yRes*_zRes);
235 }
236
237 //////////////////////////////////////////////////////////////////////
238 // helper function to dampen co-located grid artifacts of given arrays in intervals
239 // (only needed for velocity, strength (w) depends on testcase...
240 //////////////////////////////////////////////////////////////////////
241 void FLUID_3D::artificialDamping(float* field) {
242         const float w = 0.9;
243         if(_totalSteps % 4 == 1) {
244                 for (int z = 1; z < _res[2]-1; z++)
245                         for (int y = 1; y < _res[1]-1; y++)
246                                 for (int x = 1+(y+z)%2; x < _res[0]-1; x+=2) {
247                                         const int index = x + y*_res[0] + z * _slabSize;
248                                         field[index] = (1-w)*field[index] + 1./6. * w*(
249                                                         field[index+1] + field[index-1] +
250                                                         field[index+_res[0]] + field[index-_res[0]] +
251                                                         field[index+_slabSize] + field[index-_slabSize] );
252                                 }
253         }
254         if(_totalSteps % 4 == 3) {
255                 for (int z = 1; z < _res[2]-1; z++)
256                         for (int y = 1; y < _res[1]-1; y++)
257                                 for (int x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) {
258                                         const int index = x + y*_res[0] + z * _slabSize;
259                                         field[index] = (1-w)*field[index] + 1./6. * w*(
260                                                         field[index+1] + field[index-1] +
261                                                         field[index+_res[0]] + field[index-_res[0]] +
262                                                         field[index+_slabSize] + field[index-_slabSize] );
263                                 }
264         }
265 }
266
267 //////////////////////////////////////////////////////////////////////
268 // copy out the boundary in all directions
269 //////////////////////////////////////////////////////////////////////
270 void FLUID_3D::copyBorderAll(float* field)
271 {
272         int index;
273         for (int y = 0; y < _yRes; y++)
274                 for (int x = 0; x < _xRes; x++)
275                 {
276                         // front slab
277                         index = x + y * _xRes;
278                         field[index] = field[index + _slabSize];
279
280                         // back slab
281                         index += _totalCells - _slabSize;
282                         field[index] = field[index - _slabSize];
283     }
284
285         for (int z = 0; z < _zRes; z++)
286                 for (int x = 0; x < _xRes; x++)
287     {
288                         // bottom slab
289                         index = x + z * _slabSize;
290                         field[index] = field[index + _xRes];
291
292                         // top slab
293                         index += _slabSize - _xRes;
294                         field[index] = field[index - _xRes];
295     }
296
297         for (int z = 0; z < _zRes; z++)
298                 for (int y = 0; y < _yRes; y++)
299     {
300                         // left slab
301                         index = y * _xRes + z * _slabSize;
302                         field[index] = field[index + 1];
303
304                         // right slab
305                         index += _xRes - 1;
306                         field[index] = field[index - 1];
307                 }
308 }
309
310 //////////////////////////////////////////////////////////////////////
311 // wipe boundaries of velocity and density
312 //////////////////////////////////////////////////////////////////////
313 void FLUID_3D::wipeBoundaries()
314 {
315         setZeroBorder(_xVelocity, _res);
316         setZeroBorder(_yVelocity, _res);
317         setZeroBorder(_zVelocity, _res);
318         setZeroBorder(_density, _res);
319 }
320
321 //////////////////////////////////////////////////////////////////////
322 // add forces to velocity field
323 //////////////////////////////////////////////////////////////////////
324 void FLUID_3D::addForce()
325 {
326         for (int i = 0; i < _totalCells; i++)
327         {
328                 _xVelocity[i] += _dt * _xForce[i];
329                 _yVelocity[i] += _dt * _yForce[i];
330                 _zVelocity[i] += _dt * _zForce[i];
331         }
332 }
333
334 //////////////////////////////////////////////////////////////////////
335 // project into divergence free field
336 //////////////////////////////////////////////////////////////////////
337 void FLUID_3D::project()
338 {
339         int x, y, z;
340         size_t index;
341
342         float *_pressure = new float[_totalCells];
343         float *_divergence   = new float[_totalCells];
344
345         memset(_pressure, 0, sizeof(float)*_totalCells);
346         memset(_divergence, 0, sizeof(float)*_totalCells);
347
348         setObstacleBoundaries(_pressure);
349
350         // copy out the boundaries
351         if(DOMAIN_BC_LEFT == 0)  setNeumannX(_xVelocity, _res);
352         else setZeroX(_xVelocity, _res); 
353
354         if(DOMAIN_BC_TOP == 0)   setNeumannY(_yVelocity, _res);
355         else setZeroY(_yVelocity, _res); 
356
357         if(DOMAIN_BC_FRONT == 0) setNeumannZ(_zVelocity, _res);
358         else setZeroZ(_zVelocity, _res);
359
360         // calculate divergence
361         index = _slabSize + _xRes + 1;
362         for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
363                 for (y = 1; y < _yRes - 1; y++, index += 2)
364                         for (x = 1; x < _xRes - 1; x++, index++)
365                         {
366                                 float xright = _xVelocity[index + 1];
367                                 float xleft  = _xVelocity[index - 1];
368                                 float yup    = _yVelocity[index + _xRes];
369                                 float ydown  = _yVelocity[index - _xRes];
370                                 float ztop   = _zVelocity[index + _slabSize];
371                                 float zbottom = _zVelocity[index - _slabSize];
372
373                                 if(_obstacles[index+1]) xright = - _xVelocity[index];
374                                 if(_obstacles[index-1]) xleft  = - _xVelocity[index];
375                                 if(_obstacles[index+_xRes]) yup    = - _yVelocity[index];
376                                 if(_obstacles[index-_xRes]) ydown  = - _yVelocity[index];
377                                 if(_obstacles[index+_slabSize]) ztop    = - _zVelocity[index];
378                                 if(_obstacles[index-_slabSize]) zbottom = - _zVelocity[index];
379
380                                 _divergence[index] = -_dx * 0.5f * (
381                                                 xright - xleft +
382                                                 yup - ydown +
383                                                 ztop - zbottom );
384
385                                 // DG: commenting this helps CG to get a better start, 10-20% speed improvement
386                                 // _pressure[index] = 0.0f;
387                         }
388         copyBorderAll(_pressure);
389
390         // solve Poisson equation
391         solvePressurePre(_pressure, _divergence, _obstacles);
392
393         setObstaclePressure(_pressure);
394
395         // project out solution
396         float invDx = 1.0f / _dx;
397         index = _slabSize + _xRes + 1;
398         for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
399                 for (y = 1; y < _yRes - 1; y++, index += 2)
400                         for (x = 1; x < _xRes - 1; x++, index++)
401                         {
402                                 if(!_obstacles[index])
403                                 {
404                                         _xVelocity[index] -= 0.5f * (_pressure[index + 1]     - _pressure[index - 1]) * invDx;
405                                         _yVelocity[index] -= 0.5f * (_pressure[index + _xRes]  - _pressure[index - _xRes]) * invDx;
406                                         _zVelocity[index] -= 0.5f * (_pressure[index + _slabSize] - _pressure[index - _slabSize]) * invDx;
407                                 }
408                         }
409
410         if (_pressure) delete[] _pressure;
411         if (_divergence) delete[] _divergence;
412 }
413
414 //////////////////////////////////////////////////////////////////////
415 // diffuse heat
416 //////////////////////////////////////////////////////////////////////
417 void FLUID_3D::diffuseHeat()
418 {
419         SWAP_POINTERS(_heat, _heatOld);
420
421         copyBorderAll(_heatOld);
422         solveHeat(_heat, _heatOld, _obstacles);
423
424         // zero out inside obstacles
425         for (int x = 0; x < _totalCells; x++)
426                 if (_obstacles[x])
427                         _heat[x] = 0.0f;
428 }
429
430 //////////////////////////////////////////////////////////////////////
431 // stamp an obstacle in the _obstacles field
432 //////////////////////////////////////////////////////////////////////
433 void FLUID_3D::addObstacle(OBSTACLE* obstacle)
434 {
435         int index = 0;
436         for (int z = 0; z < _zRes; z++)
437                 for (int y = 0; y < _yRes; y++)
438                         for (int x = 0; x < _xRes; x++, index++)
439                                 if (obstacle->inside(x * _dx, y * _dx, z * _dx)) {
440                                         _obstacles[index] = true;
441         }
442 }
443
444 //////////////////////////////////////////////////////////////////////
445 // calculate the obstacle directional types
446 //////////////////////////////////////////////////////////////////////
447 void FLUID_3D::setObstaclePressure(float *_pressure)
448 {
449         // tag remaining obstacle blocks
450         for (int z = 1, index = _slabSize + _xRes + 1;
451                         z < _zRes - 1; z++, index += 2 * _xRes)
452                 for (int y = 1; y < _yRes - 1; y++, index += 2)
453                         for (int x = 1; x < _xRes - 1; x++, index++)
454                 {
455                         // could do cascade of ifs, but they are a pain
456                         if (_obstacles[index])
457                         {
458                                 const int top   = _obstacles[index + _slabSize];
459                                 const int bottom= _obstacles[index - _slabSize];
460                                 const int up    = _obstacles[index + _xRes];
461                                 const int down  = _obstacles[index - _xRes];
462                                 const int left  = _obstacles[index - 1];
463                                 const int right = _obstacles[index + 1];
464
465                                 // unused
466                                 // const bool fullz = (top && bottom);
467                                 // const bool fully = (up && down);
468                                 //const bool fullx = (left && right);
469
470                                 _xVelocity[index] =
471                                 _yVelocity[index] =
472                                 _zVelocity[index] = 0.0f;
473                                 _pressure[index] = 0.0f;
474
475                                 // average pressure neighbors
476                                 float pcnt = 0.;
477                                 if (left && !right) {
478                                         _pressure[index] += _pressure[index + 1];
479                                         pcnt += 1.;
480                                 }
481                                 if (!left && right) {
482                                         _pressure[index] += _pressure[index - 1];
483                                         pcnt += 1.;
484                                 }
485                                 if (up && !down) {
486                                         _pressure[index] += _pressure[index - _xRes];
487                                         pcnt += 1.;
488                                 }
489                                 if (!up && down) {
490                                         _pressure[index] += _pressure[index + _xRes];
491                                         pcnt += 1.;
492                                 }
493                                 if (top && !bottom) {
494                                         _pressure[index] += _pressure[index - _slabSize];
495                                         pcnt += 1.;
496                                 }
497                                 if (!top && bottom) {
498                                         _pressure[index] += _pressure[index + _slabSize];
499                                         pcnt += 1.;
500                                 }
501                                 
502                                 if(pcnt > 0.000001f)
503                                         _pressure[index] /= pcnt;
504
505                                 // TODO? set correct velocity bc's
506                                 // velocities are only set to zero right now
507                                 // this means it's not a full no-slip boundary condition
508                                 // but a "half-slip" - still looks ok right now
509                         }
510                 }
511 }
512
513 void FLUID_3D::setObstacleBoundaries(float *_pressure)
514 {
515         // cull degenerate obstacles , move to addObstacle?
516         for (int z = 1, index = _slabSize + _xRes + 1;
517                         z < _zRes - 1; z++, index += 2 * _xRes)
518                 for (int y = 1; y < _yRes - 1; y++, index += 2)
519                         for (int x = 1; x < _xRes - 1; x++, index++)
520                         {
521                                 if (_obstacles[index] != EMPTY)
522                                 {
523                                         const int top   = _obstacles[index + _slabSize];
524                                         const int bottom= _obstacles[index - _slabSize];
525                                         const int up    = _obstacles[index + _xRes];
526                                         const int down  = _obstacles[index - _xRes];
527                                         const int left  = _obstacles[index - 1];
528                                         const int right = _obstacles[index + 1];
529
530                                         int counter = 0;
531                                         if (up)    counter++;
532                                         if (down)  counter++;
533                                         if (left)  counter++;
534                                         if (right) counter++;
535                                         if (top)  counter++;
536                                         if (bottom) counter++;
537
538                                         if (counter < 3)
539                                                 _obstacles[index] = EMPTY;
540                                 }
541                                 if (_obstacles[index])
542                                 {
543                                         _xVelocity[index] =
544                                         _yVelocity[index] =
545                                         _zVelocity[index] = 0.0f;
546                                         _pressure[index] = 0.0f;
547                                 }
548                         }
549 }
550
551 //////////////////////////////////////////////////////////////////////
552 // add buoyancy forces
553 //////////////////////////////////////////////////////////////////////
554 void FLUID_3D::addBuoyancy(float *heat, float *density)
555 {
556         int index = 0;
557
558         for (int z = 0; z < _zRes; z++)
559                 for (int y = 0; y < _yRes; y++)
560                         for (int x = 0; x < _xRes; x++, index++)
561                         {
562                                 _zForce[index] += *_alpha * density[index] + (*_beta * (heat[index] - _tempAmb)); // DG: was _yForce, changed for Blender
563                         }
564 }
565
566 //////////////////////////////////////////////////////////////////////
567 // add vorticity to the force field
568 //////////////////////////////////////////////////////////////////////
569 void FLUID_3D::addVorticity()
570 {
571         int x,y,z,index;
572         if(_vorticityEps<=0.) return;
573
574         float *_xVorticity, *_yVorticity, *_zVorticity, *_vorticity;
575
576         _xVorticity = new float[_totalCells];
577         _yVorticity = new float[_totalCells];
578         _zVorticity = new float[_totalCells];
579         _vorticity = new float[_totalCells];
580
581         memset(_xVorticity, 0, sizeof(float)*_totalCells);
582         memset(_yVorticity, 0, sizeof(float)*_totalCells);
583         memset(_zVorticity, 0, sizeof(float)*_totalCells);
584         memset(_vorticity, 0, sizeof(float)*_totalCells);
585
586         // calculate vorticity
587         float gridSize = 0.5f / _dx;
588         index = _slabSize + _xRes + 1;
589         for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
590                 for (y = 1; y < _yRes - 1; y++, index += 2)
591                         for (x = 1; x < _xRes - 1; x++, index++)
592                         {
593                                 int up    = _obstacles[index + _xRes] ? index : index + _xRes;
594                                 int down  = _obstacles[index - _xRes] ? index : index - _xRes;
595                                 float dy  = (up == index || down == index) ? 1.0f / _dx : gridSize;
596                                 int out   = _obstacles[index + _slabSize] ? index : index + _slabSize;
597                                 int in    = _obstacles[index - _slabSize] ? index : index - _slabSize;
598                                 float dz  = (out == index || in == index) ? 1.0f / _dx : gridSize;
599                                 int right = _obstacles[index + 1] ? index : index + 1;
600                                 int left  = _obstacles[index - 1] ? index : index - 1;
601                                 float dx  = (right == index || right == index) ? 1.0f / _dx : gridSize;
602
603                                 _xVorticity[index] = (_zVelocity[up] - _zVelocity[down]) * dy + (-_yVelocity[out] + _yVelocity[in]) * dz;
604                                 _yVorticity[index] = (_xVelocity[out] - _xVelocity[in]) * dz + (-_zVelocity[right] + _zVelocity[left]) * dx;
605                                 _zVorticity[index] = (_yVelocity[right] - _yVelocity[left]) * dx + (-_xVelocity[up] + _xVelocity[down])* dy;
606
607                                 _vorticity[index] = sqrtf(_xVorticity[index] * _xVorticity[index] +
608                                                 _yVorticity[index] * _yVorticity[index] +
609                                                 _zVorticity[index] * _zVorticity[index]);
610                         }
611
612         // calculate normalized vorticity vectors
613         float eps = _vorticityEps;
614         index = _slabSize + _xRes + 1;
615         for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
616                 for (y = 1; y < _yRes - 1; y++, index += 2)
617                         for (x = 1; x < _xRes - 1; x++, index++)
618                                 if (!_obstacles[index])
619                                 {
620                                         float N[3];
621
622                                         int up    = _obstacles[index + _xRes] ? index : index + _xRes;
623                                         int down  = _obstacles[index - _xRes] ? index : index - _xRes;
624                                         float dy  = (up == index || down == index) ? 1.0f / _dx : gridSize;
625                                         int out   = _obstacles[index + _slabSize] ? index : index + _slabSize;
626                                         int in    = _obstacles[index - _slabSize] ? index : index - _slabSize;
627                                         float dz  = (out == index || in == index) ? 1.0f / _dx : gridSize;
628                                         int right = _obstacles[index + 1] ? index : index + 1;
629                                         int left  = _obstacles[index - 1] ? index : index - 1;
630                                         float dx  = (right == index || right == index) ? 1.0f / _dx : gridSize;
631                                         N[0] = (_vorticity[right] - _vorticity[left]) * dx;
632                                         N[1] = (_vorticity[up] - _vorticity[down]) * dy;
633                                         N[2] = (_vorticity[out] - _vorticity[in]) * dz;
634
635                                         float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
636                                         if (magnitude > 0.0f)
637                                         {
638                                                 magnitude = 1.0f / magnitude;
639                                                 N[0] *= magnitude;
640                                                 N[1] *= magnitude;
641                                                 N[2] *= magnitude;
642
643                                                 _xForce[index] += (N[1] * _zVorticity[index] - N[2] * _yVorticity[index]) * _dx * eps;
644                                                 _yForce[index] -= (N[0] * _zVorticity[index] - N[2] * _xVorticity[index]) * _dx * eps;
645                                                 _zForce[index] += (N[0] * _yVorticity[index] - N[1] * _xVorticity[index]) * _dx * eps;
646                                         }
647                                 }
648                                 
649         if (_xVorticity) delete[] _xVorticity;
650         if (_yVorticity) delete[] _yVorticity;
651         if (_zVorticity) delete[] _zVorticity;
652         if (_vorticity) delete[] _vorticity;
653 }
654
655 //////////////////////////////////////////////////////////////////////
656 // Advect using the MacCormack method from the Selle paper
657 //////////////////////////////////////////////////////////////////////
658 void FLUID_3D::advectMacCormack()
659 {
660         Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
661
662         if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res);
663         else setZeroX(_xVelocity, res); 
664
665         if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocity, res);
666         else setZeroY(_yVelocity, res); 
667
668         if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocity, res);
669         else setZeroZ(_zVelocity, res);
670
671         SWAP_POINTERS(_xVelocity, _xVelocityOld);
672         SWAP_POINTERS(_yVelocity, _yVelocityOld);
673         SWAP_POINTERS(_zVelocity, _zVelocityOld);
674         SWAP_POINTERS(_density, _densityOld);
675         SWAP_POINTERS(_heat, _heatOld);
676
677         const float dt0 = _dt / _dx;
678         // use force arrays as temp arrays
679         for (int x = 0; x < _totalCells; x++)
680                 _xForce[x] = _yForce[x] = 0.0;
681
682         float* t1 = _xForce;
683         float* t2 = _yForce;
684
685         advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, t1,t2, res, _obstacles);
686         advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, t1,t2, res, _obstacles);
687         advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, t1,t2, res, _obstacles);
688         advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, t1,t2, res, _obstacles);
689         advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, t1,t2, res, _obstacles);
690
691         if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res);
692         else setZeroX(_xVelocity, res); 
693
694         if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocity, res);
695         else setZeroY(_yVelocity, res); 
696
697         if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocity, res);
698         else setZeroZ(_zVelocity, res);
699
700         setZeroBorder(_density, res);
701         setZeroBorder(_heat, res);
702
703   for (int x = 0; x < _totalCells; x++)
704     t1[x] = t2[x] = 0.0;
705 }