BF2.5: First commit of smoke code.
authorDaniel Genrich <daniel.genrich@gmx.net>
Thu, 30 Jul 2009 15:00:26 +0000 (15:00 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Thu, 30 Jul 2009 15:00:26 +0000 (15:00 +0000)
Not working:
a) rendering (since volumterics branch is not merged yet)
b) moving collision objects of any kind
c) saving of collision objects (because that's what I am working on)
d) pointcache
e) A bunch of other things I already know of

So please do not report any bugs on this one yet :-)

72 files changed:
intern/CMakeLists.txt
intern/SConscript
intern/smoke/SConscript [new file with mode: 0644]
intern/smoke/extern/smoke_API.h [new file with mode: 0644]
intern/smoke/intern/EIGENVALUE_HELPER.h [new file with mode: 0644]
intern/smoke/intern/FFT_NOISE.h [new file with mode: 0644]
intern/smoke/intern/FLUID_3D.cpp [new file with mode: 0644]
intern/smoke/intern/FLUID_3D.h [new file with mode: 0644]
intern/smoke/intern/FLUID_3D_SOLVERS.cpp [new file with mode: 0644]
intern/smoke/intern/FLUID_3D_STATIC.cpp [new file with mode: 0644]
intern/smoke/intern/IMAGE.h [new file with mode: 0644]
intern/smoke/intern/INTERPOLATE.h [new file with mode: 0644]
intern/smoke/intern/LICENSE.txt [new file with mode: 0644]
intern/smoke/intern/LU_HELPER.h [new file with mode: 0644]
intern/smoke/intern/MERSENNETWISTER.h [new file with mode: 0644]
intern/smoke/intern/Makefile.FFT [new file with mode: 0644]
intern/smoke/intern/Makefile.cygwin [new file with mode: 0644]
intern/smoke/intern/Makefile.linux [new file with mode: 0644]
intern/smoke/intern/Makefile.mac [new file with mode: 0644]
intern/smoke/intern/OBSTACLE.h [new file with mode: 0644]
intern/smoke/intern/SPHERE.cpp [new file with mode: 0644]
intern/smoke/intern/SPHERE.h [new file with mode: 0644]
intern/smoke/intern/VEC3.h [new file with mode: 0644]
intern/smoke/intern/WAVELET_NOISE.h [new file with mode: 0644]
intern/smoke/intern/WTURBULENCE.cpp [new file with mode: 0644]
intern/smoke/intern/WTURBULENCE.h [new file with mode: 0644]
intern/smoke/intern/smoke_API.cpp [new file with mode: 0644]
intern/smoke/intern/tnt/jama_eig.h [new file with mode: 0644]
intern/smoke/intern/tnt/jama_lu.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_array1d.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_array1d_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_array2d.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_array2d_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_array3d.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_array3d_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_cmat.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_fortran_array1d.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_fortran_array2d.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_fortran_array3d.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_i_refvec.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_math_utils.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_stopwatch.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_subscript.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_vec.h [new file with mode: 0644]
intern/smoke/intern/tnt/tnt_version.h [new file with mode: 0644]
release/ui/buttons_data_modifier.py
source/blender/blenkernel/BKE_smoke.h [new file with mode: 0644]
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/SConscript
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/smoke.c [new file with mode: 0644]
source/blender/blenlib/BLI_kdopbvh.h
source/blender/blenlib/intern/BLI_kdopbvh.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/CMakeLists.txt
source/blender/editors/space_view3d/SConscript
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_smoke_types.h [new file with mode: 0644]
source/blender/makesdna/intern/makesdna.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_smoke.c [new file with mode: 0644]
source/creator/CMakeLists.txt

index 697d0b6..71bd00f 100644 (file)
@@ -35,6 +35,7 @@ ADD_SUBDIRECTORY(decimation)
 ADD_SUBDIRECTORY(iksolver)
 ADD_SUBDIRECTORY(boolop)
 ADD_SUBDIRECTORY(opennl)
+ADD_SUBDIRECTORY(smoke)
 
 IF(WITH_ELBEEM)
   ADD_SUBDIRECTORY(elbeem)
index bb8525d..bdbdc7f 100644 (file)
@@ -11,7 +11,8 @@ SConscript(['SoundSystem/SConscript',
             'decimation/SConscript',
             'iksolver/SConscript',
             'boolop/SConscript',
-            'opennl/SConscript'])
+            'opennl/SConscript',
+            'smoke/SConscript'])
 
 # NEW_CSG was intended for intern/csg, but
 # getting it to compile is difficult
diff --git a/intern/smoke/SConscript b/intern/smoke/SConscript
new file mode 100644 (file)
index 0000000..fe592b8
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.cpp')
+
+defs = ''
+
+if env['WITH_BF_OPENMP']:
+    defs += ' PARALLEL=1'
+
+incs = env['BF_PNG_INC'] + ' ' + env['BF_ZLIB_INC'] 
+incs += ' intern ../../extern/bullet2/src ../memutil ../guardealloc '
+incs += env['BF_FFTW3_INC'] 
+
+env.BlenderLib ('bf_smoke', sources, Split(incs), Split(defs), libtype=['intern'], priority=[40] )
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
new file mode 100644 (file)
index 0000000..491e065
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 by Daniel Genrich
+ * All rights reserved.
+ *
+ * Contributor(s): None
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef SMOKE_API_H_
+#define SMOKE_API_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct FLUID_3D *smoke_init(int *res, int amplify, float *p0, float *p1, float dt);
+void smoke_free(struct FLUID_3D *fluid);
+
+void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta);
+
+void smoke_step(struct FLUID_3D *fluid);
+
+float *smoke_get_density(struct FLUID_3D *fluid);
+float *smoke_get_bigdensity(struct FLUID_3D *fluid);
+float *smoke_get_heat(struct FLUID_3D *fluid);
+float *smoke_get_velocity_x(struct FLUID_3D *fluid);
+float *smoke_get_velocity_y(struct FLUID_3D *fluid);
+float *smoke_get_velocity_z(struct FLUID_3D *fluid);
+
+unsigned char *smoke_get_obstacle(struct FLUID_3D *fluid);
+
+size_t smoke_get_index(int x, int max_x, int y, int max_y, int z, int max_z);
+size_t smoke_get_index2d(int x, int max_x, int y, int max_y, int z, int max_z);
+
+void smoke_set_noise(struct FLUID_3D *fluid, int type);
+
+void smoke_get_bigres(struct FLUID_3D *fluid, int *res);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SMOKE_API_H_ */
diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.h b/intern/smoke/intern/EIGENVALUE_HELPER.h
new file mode 100644 (file)
index 0000000..6ff61c5
--- /dev/null
@@ -0,0 +1,47 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+//////////////////////////////////////////////////////////////////////
+// Helper function, compute eigenvalues of 3x3 matrix
+//////////////////////////////////////////////////////////////////////
+
+#include "tnt/jama_eig.h"
+
+//////////////////////////////////////////////////////////////////////
+// eigenvalues of 3x3 non-symmetric matrix
+//////////////////////////////////////////////////////////////////////
+int inline computeEigenvalues3x3(
+               float dout[3], 
+               float a[3][3])
+{
+  TNT::Array2D<float> A = TNT::Array2D<float>(3,3, &a[0][0]);
+  TNT::Array1D<float> eig = TNT::Array1D<float>(3);
+  TNT::Array1D<float> eigImag = TNT::Array1D<float>(3);
+  JAMA::Eigenvalue<float> jeig = JAMA::Eigenvalue<float>(A);
+  jeig.getRealEigenvalues(eig);
+
+  // complex ones
+  jeig.getImagEigenvalues(eigImag);
+  dout[0]  = sqrt(eig[0]*eig[0] + eigImag[0]*eigImag[0]);
+  dout[1]  = sqrt(eig[1]*eig[1] + eigImag[1]*eigImag[1]);
+  dout[2]  = sqrt(eig[2]*eig[2] + eigImag[2]*eigImag[2]);
+  return 0;
+}
+
+#undef rfabs 
+#undef ROT
diff --git a/intern/smoke/intern/FFT_NOISE.h b/intern/smoke/intern/FFT_NOISE.h
new file mode 100644 (file)
index 0000000..9ae9682
--- /dev/null
@@ -0,0 +1,178 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+/////////////////////////////////////////////////////////////////////////
+//
+
+#ifndef FFT_NOISE_H_
+#define FFT_NOISE_H_
+
+#if 0
+#include <iostream>
+#include <fftw3.h>
+#include <MERSENNETWISTER.h>
+
+#include "WAVELET_NOISE.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+/////////////////////////////////////////////////////////////////////////
+// shift spectrum to the format that FFTW expects
+/////////////////////////////////////////////////////////////////////////
+static void shift3D(float*& field, int xRes, int yRes, int zRes)
+{
+  int xHalf = xRes / 2;
+  int yHalf = yRes / 2;
+  int zHalf = zRes / 2;
+  int slabSize = xRes * yRes;
+  for (int z = 0; z < zHalf; z++)
+    for (int y = 0; y < yHalf; y++)
+      for (int x = 0; x < xHalf; x++)
+      {
+        int index = x + y * xRes + z * xRes * yRes;
+        float temp;
+        int xSwap = xHalf;
+        int ySwap = yHalf * xRes;
+        int zSwap = zHalf * xRes * yRes;
+        
+        // [0,0,0] to [1,1,1]
+        temp = field[index];
+        field[index] = field[index + xSwap + ySwap + zSwap];
+        field[index + xSwap + ySwap + zSwap] = temp;
+
+        // [1,0,0] to [0,1,1]
+        temp = field[index + xSwap];
+        field[index + xSwap] = field[index + ySwap + zSwap];
+        field[index + ySwap + zSwap] = temp;
+
+        // [0,1,0] to [1,0,1]
+        temp = field[index + ySwap];
+        field[index + ySwap] = field[index + xSwap + zSwap];
+        field[index + xSwap + zSwap] = temp;
+        
+        // [0,0,1] to [1,1,0]
+        temp = field[index + zSwap];
+        field[index + zSwap] = field[index + xSwap + ySwap];
+        field[index + xSwap + ySwap] = temp;
+      }
+}
+
+static void generatTile_FFT(float* const noiseTileData, std::string filename)
+{
+       if (loadTile(noiseTileData, filename)) return;
+       
+       int res = NOISE_TILE_SIZE;
+       int xRes = res;
+       int yRes = res;
+       int zRes = res;
+       int totalCells = xRes * yRes * zRes;
+       
+       // create and shift the filter
+       float* filter = new float[totalCells];
+       for (int z = 0; z < zRes; z++)
+               for (int y = 0; y < yRes; y++)
+                       for (int x = 0; x < xRes; x++)
+                       {
+                               int index = x + y * xRes + z * xRes * yRes;
+                               float diff[] = {abs(x - xRes/2), 
+                               abs(y - yRes/2), 
+                               abs(z - zRes/2)};
+                               float radius = sqrtf(diff[0] * diff[0] + 
+                               diff[1] * diff[1] + 
+                               diff[2] * diff[2]) / (xRes / 2);
+                               radius *= M_PI;
+                               float H = cos((M_PI / 2.0f) * log(4.0f * radius / M_PI) / log(2.0f));
+                               H = H * H;
+                               float filtered = H;
+                               
+                               // clamp everything outside the wanted band
+                               if (radius >= M_PI / 2.0f)
+                                       filtered = 0.0f;
+                               
+                               // make sure to capture all low frequencies
+                               if (radius <= M_PI / 4.0f)
+                                       filtered = 1.0f;
+                               
+                               filter[index] = filtered;
+                       }
+       shift3D(filter, xRes, yRes, zRes);
+       
+       // create the noise
+       float* noise = new float[totalCells];
+       int index = 0;
+       MTRand twister;
+       for (int z = 0; z < zRes; z++)
+       for (int y = 0; y < yRes; y++)
+         for (int x = 0; x < xRes; x++, index++)
+               noise[index] = twister.randNorm();
+       
+       // create padded field
+       fftw_complex* forward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells);
+       
+       // init padded field
+       index = 0;
+       for (int z = 0; z < zRes; z++)
+       for (int y = 0; y < yRes; y++)
+         for (int x = 0; x < xRes; x++, index++)
+         {
+               forward[index][0] = noise[index];
+               forward[index][1] = 0.0f;
+         }
+       
+       // forward FFT 
+       fftw_complex* backward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells);
+       fftw_plan forwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, forward, backward, FFTW_FORWARD, FFTW_ESTIMATE);  
+       fftw_execute(forwardPlan);
+       fftw_destroy_plan(forwardPlan);
+       
+       // apply filter
+       index = 0;
+       for (int z = 0; z < zRes; z++)
+               for (int y = 0; y < yRes; y++)
+                       for (int x = 0; x < xRes; x++, index++)
+                       {
+                               backward[index][0] *= filter[index];
+                               backward[index][1] *= filter[index];
+                       }
+       
+       // backward FFT
+       fftw_plan backwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, backward, forward, FFTW_BACKWARD, FFTW_ESTIMATE);  
+       fftw_execute(backwardPlan);
+       fftw_destroy_plan(backwardPlan);
+       
+       // subtract out the low frequency components
+       index = 0;
+       for (int z = 0; z < zRes; z++)
+               for (int y = 0; y < yRes; y++)
+                       for (int x = 0; x < xRes; x++, index++)
+                               noise[index] -= forward[index][0] / totalCells;
+
+       // save out the noise tile
+       saveTile(noise, filename);
+       
+       fftw_free(forward);
+       fftw_free(backward);
+       delete[] filter;
+       delete[] noise;
+}
+
+#endif
+
+#endif /* FFT_NOISE_H_ */
diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
new file mode 100644 (file)
index 0000000..3427b32
--- /dev/null
@@ -0,0 +1,670 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+//
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright 2008 Theodore Kim and Nils Thuerey
+//
+// FLUID_3D.cpp: implementation of the FLUID_3D class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "FLUID_3D.h"
+#include "IMAGE.h"
+#include <INTERPOLATE.h>
+#include "SPHERE.h"
+#include <zlib.h>
+
+// boundary conditions of the fluid domain
+#define DOMAIN_BC_FRONT  1
+#define DOMAIN_BC_TOP    0
+#define DOMAIN_BC_LEFT   1
+#define DOMAIN_BC_BACK   DOMAIN_BC_FRONT
+#define DOMAIN_BC_BOTTOM DOMAIN_BC_TOP
+#define DOMAIN_BC_RIGHT  DOMAIN_BC_LEFT
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+FLUID_3D::FLUID_3D(int *res, int amplify, float *p0, float *p1, float dt) :
+       _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.), _dt(dt)
+{
+       // set simulation consts
+       // _dt = dt; // 0.10
+       
+       // start point of array
+       _p0[0] = p0[0];
+       _p0[1] = p0[1];
+       _p0[2] = p0[2];
+
+       _iterations = 100;
+       _tempAmb = 0; 
+       _heatDiffusion = 1e-3;
+       _vorticityEps = 2.0;
+       _totalTime = 0.0f;
+       _totalSteps = 0;
+       _res = Vec3Int(_xRes,_yRes,_zRes);
+       _maxRes = MAX3(_xRes, _yRes, _zRes);
+       
+       // initialize wavelet turbulence
+       _wTurbulence = new WTURBULENCE(_res[0],_res[1],_res[2], amplify);
+       
+       // scale the constants according to the refinement of the grid
+       _dx = 1.0f / (float)_maxRes;
+       float scaling = 64.0f / _maxRes;
+       scaling = (scaling < 1.0f) ? 1.0f : scaling;
+       _vorticityEps /= scaling;
+
+       // allocate arrays
+       _totalCells   = _xRes * _yRes * _zRes;
+       _slabSize = _xRes * _yRes;
+       _divergence   = new float[_totalCells];
+       _pressure     = new float[_totalCells];
+       _xVelocity    = new float[_totalCells];
+       _yVelocity    = new float[_totalCells];
+       _zVelocity    = new float[_totalCells];
+       _xVelocityOld = new float[_totalCells];
+       _yVelocityOld = new float[_totalCells];
+       _zVelocityOld = new float[_totalCells];
+       _xForce       = new float[_totalCells];
+       _yForce       = new float[_totalCells];
+       _zForce       = new float[_totalCells];
+       _vorticity    = new float[_totalCells];
+       _density      = new float[_totalCells];
+       _densityOld   = new float[_totalCells];
+       _heat         = new float[_totalCells];
+       _heatOld      = new float[_totalCells];
+       _residual     = new float[_totalCells];
+       _direction    = new float[_totalCells];
+       _q            = new float[_totalCells];
+       _obstacles    = new unsigned char[_totalCells];
+       _xVorticity   = new float[_totalCells];
+       _yVorticity   = new float[_totalCells];
+       _zVorticity   = new float[_totalCells];
+
+       for (int x = 0; x < _totalCells; x++)
+       {
+               _density[x]      = 0.0f;
+               _densityOld[x]   = 0.0f;
+               _heat[x]         = 0.0f;
+               _heatOld[x]      = 0.0f;
+               _divergence[x]   = 0.0f;
+               _pressure[x]     = 0.0f;
+               _xVelocity[x]    = 0.0f;
+               _yVelocity[x]    = 0.0f;
+               _zVelocity[x]    = 0.0f;
+               _xVelocityOld[x] = 0.0f;
+               _yVelocityOld[x] = 0.0f;
+               _zVelocityOld[x] = 0.0f;
+               _xForce[x]       = 0.0f;
+               _yForce[x]       = 0.0f;
+               _zForce[x]       = 0.0f;
+               _xVorticity[x]   = 0.0f;
+               _yVorticity[x]   = 0.0f;
+               _zVorticity[x]   = 0.0f;
+               _residual[x]     = 0.0f;
+               _obstacles[x]    = false;
+       }
+
+       // set side obstacles
+  int index;
+  for (int y = 0; y < _yRes; y++)
+    for (int x = 0; x < _xRes; x++)
+    {
+      // front slab
+      index = x + y * _xRes;
+      if(DOMAIN_BC_FRONT==1) _obstacles[index] = 1;
+
+      // back slab
+      index += _totalCells - _slabSize;
+      if(DOMAIN_BC_BACK==1) _obstacles[index] = 1;
+    }
+  for (int z = 0; z < _zRes; z++)
+    for (int x = 0; x < _xRes; x++)
+    {
+      // bottom slab
+      index = x + z * _slabSize;
+      if(DOMAIN_BC_BOTTOM==1) _obstacles[index] = 1;
+
+      // top slab
+      index += _slabSize - _xRes;
+      if(DOMAIN_BC_TOP==1) _obstacles[index] = 1;
+    }
+  for (int z = 0; z < _zRes; z++)
+    for (int y = 0; y < _yRes; y++)
+    {
+      // left slab
+      index = y * _xRes + z * _slabSize;
+      if(DOMAIN_BC_LEFT==1) _obstacles[index] = 1;
+
+      // right slab
+      index += _xRes - 1;
+      if(DOMAIN_BC_RIGHT==1) _obstacles[index] = 1;
+    }
+
+       /*
+       SPHERE *obsSphere = NULL;
+       obsSphere = new SPHERE(0.375,0.5,0.375, 0.1); // for 4 to 3 domain
+       addObstacle(obsSphere);
+       delete obsSphere;
+       */
+}
+
+FLUID_3D::~FLUID_3D()
+{
+       if (_divergence) delete[] _divergence;
+       if (_pressure) delete[] _pressure;
+       if (_xVelocity) delete[] _xVelocity;
+       if (_yVelocity) delete[] _yVelocity;
+       if (_zVelocity) delete[] _zVelocity;
+       if (_xVelocityOld) delete[] _xVelocityOld;
+       if (_yVelocityOld) delete[] _yVelocityOld;
+       if (_zVelocityOld) delete[] _zVelocityOld;
+       if (_xForce) delete[] _xForce;
+       if (_yForce) delete[] _yForce;
+       if (_zForce) delete[] _zForce;
+       if (_residual) delete[] _residual;
+       if (_direction) delete[] _direction;
+       if (_q)       delete[] _q;
+       if (_density) delete[] _density;
+       if (_densityOld) delete[] _densityOld;
+       if (_heat) delete[] _heat;
+       if (_heatOld) delete[] _heatOld;
+       if (_xVorticity) delete[] _xVorticity;
+       if (_yVorticity) delete[] _yVorticity;
+       if (_zVorticity) delete[] _zVorticity;
+       if (_vorticity) delete[] _vorticity;
+       if (_obstacles) delete[] _obstacles;
+    if (_wTurbulence) delete _wTurbulence;
+
+    printf("deleted fluid\n");
+}
+
+// init direct access functions from blender
+void FLUID_3D::initBlenderRNA(float *alpha, float *beta)
+{
+       _alpha = alpha;
+       _beta = beta;
+       
+       // XXX TODO DEBUG
+       // *_alpha = 0;
+       // *_beta = 0;
+}
+
+//////////////////////////////////////////////////////////////////////
+// step simulation once
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::step()
+{
+       // wipe forces
+       for (int i = 0; i < _totalCells; i++)
+               _xForce[i] = _yForce[i] = _zForce[i] = 0.0f;
+
+       wipeBoundaries();
+
+       // run the solvers
+  addVorticity();
+  addBuoyancy(_heat, _density);
+       addForce();
+       project();
+  diffuseHeat();
+
+       // advect everything
+       advectMacCormack();
+
+       if(_wTurbulence) {
+               _wTurbulence->stepTurbulenceFull(_dt/_dx,
+                               _xVelocity, _yVelocity, _zVelocity, _obstacles);
+               // _wTurbulence->stepTurbulenceReadable(_dt/_dx,
+               //  _xVelocity, _yVelocity, _zVelocity, _obstacles);
+       }
+/*
+ // no file output
+  float *src = _density;
+       string prefix = string("./original.preview/density_fullxy_");
+       writeImageSliceXY(src,_res, _res[2]/2, prefix, _totalSteps);
+*/
+       // artificial damping -- this is necessary because we use a
+  // collated grid, and at very coarse grid resolutions, banding
+  // artifacts can occur
+       artificialDamping(_xVelocity);
+       artificialDamping(_yVelocity);
+       artificialDamping(_zVelocity);
+/*
+// no file output
+  string pbrtPrefix = string("./pbrt/density_small_");
+  IMAGE::dumpPBRT(_totalSteps, pbrtPrefix, _density, _res[0],_res[1],_res[2]);
+  */
+       _totalTime += _dt;
+       _totalSteps++;
+}
+
+//////////////////////////////////////////////////////////////////////
+// helper function to dampen co-located grid artifacts of given arrays in intervals
+// (only needed for velocity, strength (w) depends on testcase...
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::artificialDamping(float* field) {
+       const float w = 0.9;
+       if(_totalSteps % 4 == 1) {
+               for (int z = 1; z < _res[2]-1; z++)
+                       for (int y = 1; y < _res[1]-1; y++)
+                               for (int x = 1+(y+z)%2; x < _res[0]-1; x+=2) {
+                                       const int index = x + y*_res[0] + z * _slabSize;
+                                       field[index] = (1-w)*field[index] + 1./6. * w*(
+                                                       field[index+1] + field[index-1] +
+                                                       field[index+_res[0]] + field[index-_res[0]] +
+                                                       field[index+_slabSize] + field[index-_slabSize] );
+                               }
+       }
+       if(_totalSteps % 4 == 3) {
+               for (int z = 1; z < _res[2]-1; z++)
+                       for (int y = 1; y < _res[1]-1; y++)
+                               for (int x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) {
+                                       const int index = x + y*_res[0] + z * _slabSize;
+                                       field[index] = (1-w)*field[index] + 1./6. * w*(
+                                                       field[index+1] + field[index-1] +
+                                                       field[index+_res[0]] + field[index-_res[0]] +
+                                                       field[index+_slabSize] + field[index-_slabSize] );
+                               }
+       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// copy out the boundary in all directions
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::copyBorderAll(float* field)
+{
+       int index;
+       for (int y = 0; y < _yRes; y++)
+               for (int x = 0; x < _xRes; x++)
+               {
+                       // front slab
+                       index = x + y * _xRes;
+                       field[index] = field[index + _slabSize];
+
+                       // back slab
+                       index += _totalCells - _slabSize;
+                       field[index] = field[index - _slabSize];
+    }
+
+       for (int z = 0; z < _zRes; z++)
+               for (int x = 0; x < _xRes; x++)
+    {
+                       // bottom slab
+                       index = x + z * _slabSize;
+                       field[index] = field[index + _xRes];
+
+                       // top slab
+                       index += _slabSize - _xRes;
+                       field[index] = field[index - _xRes];
+    }
+
+       for (int z = 0; z < _zRes; z++)
+               for (int y = 0; y < _yRes; y++)
+    {
+                       // left slab
+                       index = y * _xRes + z * _slabSize;
+                       field[index] = field[index + 1];
+
+                       // right slab
+                       index += _xRes - 1;
+                       field[index] = field[index - 1];
+               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// wipe boundaries of velocity and density
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::wipeBoundaries()
+{
+       setZeroBorder(_xVelocity, _res);
+       setZeroBorder(_yVelocity, _res);
+       setZeroBorder(_zVelocity, _res);
+       setZeroBorder(_density, _res);
+}
+
+//////////////////////////////////////////////////////////////////////
+// add forces to velocity field
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::addForce()
+{
+       for (int i = 0; i < _totalCells; i++)
+       {
+               _xVelocity[i] += _dt * _xForce[i];
+               _yVelocity[i] += _dt * _yForce[i];
+               _zVelocity[i] += _dt * _zForce[i];
+       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// project into divergence free field
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::project()
+{
+       int index, x, y, z;
+       setObstacleBoundaries();
+
+       // copy out the boundaries
+       if(DOMAIN_BC_LEFT == 0)  setNeumannX(_xVelocity, _res);
+       else setZeroX(_xVelocity, _res);
+
+       if(DOMAIN_BC_TOP == 0)   setNeumannY(_yVelocity, _res);
+       else setZeroY(_yVelocity, _res);
+
+       if(DOMAIN_BC_FRONT == 0) setNeumannZ(_zVelocity, _res);
+       else setZeroZ(_zVelocity, _res);
+
+       // calculate divergence
+       index = _slabSize + _xRes + 1;
+       for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+               for (y = 1; y < _yRes - 1; y++, index += 2)
+                       for (x = 1; x < _xRes - 1; x++, index++)
+                       {
+                               float xright = _xVelocity[index + 1];
+                               float xleft  = _xVelocity[index - 1];
+                               float yup    = _yVelocity[index + _xRes];
+                               float ydown  = _yVelocity[index - _xRes];
+                               float ztop   = _zVelocity[index + _slabSize];
+                               float zbottom = _zVelocity[index - _slabSize];
+
+                               if(_obstacles[index+1]) xright = - _xVelocity[index];
+                               if(_obstacles[index-1]) xleft  = - _xVelocity[index];
+                               if(_obstacles[index+_xRes]) yup    = - _yVelocity[index];
+                               if(_obstacles[index-_xRes]) ydown  = - _yVelocity[index];
+                               if(_obstacles[index+_slabSize]) ztop    = - _zVelocity[index];
+                               if(_obstacles[index-_slabSize]) zbottom = - _zVelocity[index];
+
+                               _divergence[index] = -_dx * 0.5f * (
+                                               xright - xleft +
+                                               yup - ydown +
+                                               ztop - zbottom );
+                               _pressure[index] = 0.0f;
+                       }
+       copyBorderAll(_pressure);
+
+       // solve Poisson equation
+       solvePressure(_pressure, _divergence, _obstacles);
+
+       // project out solution
+       float invDx = 1.0f / _dx;
+       index = _slabSize + _xRes + 1;
+       for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+               for (y = 1; y < _yRes - 1; y++, index += 2)
+                       for (x = 1; x < _xRes - 1; x++, index++)
+                       {
+                               _xVelocity[index] -= 0.5f * (_pressure[index + 1]     - _pressure[index - 1])     * invDx;
+                               _yVelocity[index] -= 0.5f * (_pressure[index + _xRes]  - _pressure[index - _xRes]) * invDx;
+                               _zVelocity[index] -= 0.5f * (_pressure[index + _slabSize] - _pressure[index - _slabSize]) * invDx;
+                       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// diffuse heat
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::diffuseHeat()
+{
+       SWAP_POINTERS(_heat, _heatOld);
+
+       copyBorderAll(_heatOld);
+       solveHeat(_heat, _heatOld, _obstacles);
+
+       // zero out inside obstacles
+       for (int x = 0; x < _totalCells; x++)
+               if (_obstacles[x])
+                       _heat[x] = 0.0f;
+}
+
+//////////////////////////////////////////////////////////////////////
+// stamp an obstacle in the _obstacles field
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::addObstacle(OBSTACLE* obstacle)
+{
+       int index = 0;
+       for (int z = 0; z < _zRes; z++)
+               for (int y = 0; y < _yRes; y++)
+                       for (int x = 0; x < _xRes; x++, index++)
+                               if (obstacle->inside(x * _dx, y * _dx, z * _dx)) {
+                                       _obstacles[index] = true;
+        }
+}
+
+//////////////////////////////////////////////////////////////////////
+// calculate the obstacle directional types
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setObstacleBoundaries()
+{
+       // cull degenerate obstacles , move to addObstacle?
+       for (int z = 1, index = _slabSize + _xRes + 1;
+                       z < _zRes - 1; z++, index += 2 * _xRes)
+               for (int y = 1; y < _yRes - 1; y++, index += 2)
+                       for (int x = 1; x < _xRes - 1; x++, index++)
+                               if (_obstacles[index] != EMPTY)
+                               {
+                                       const int top   = _obstacles[index + _slabSize];
+                                       const int bottom= _obstacles[index - _slabSize];
+                                       const int up    = _obstacles[index + _xRes];
+                                       const int down  = _obstacles[index - _xRes];
+                                       const int left  = _obstacles[index - 1];
+                                       const int right = _obstacles[index + 1];
+
+                                       int counter = 0;
+                                       if (up)    counter++;
+                                       if (down)  counter++;
+                                       if (left)  counter++;
+                                       if (right) counter++;
+                                       if (top)  counter++;
+                                       if (bottom) counter++;
+
+                                       if (counter < 3)
+                                               _obstacles[index] = EMPTY;
+                               }
+
+       // tag remaining obstacle blocks
+       for (int z = 1, index = _slabSize + _xRes + 1;
+                       z < _zRes - 1; z++, index += 2 * _xRes)
+               for (int y = 1; y < _yRes - 1; y++, index += 2)
+                       for (int x = 1; x < _xRes - 1; x++, index++)
+               {
+                       // could do cascade of ifs, but they are a pain
+                       if (_obstacles[index] != EMPTY)
+                       {
+                               const int top   = _obstacles[index + _slabSize];
+                               const int bottom= _obstacles[index - _slabSize];
+                               const int up    = _obstacles[index + _xRes];
+                               const int down  = _obstacles[index - _xRes];
+                               const int left  = _obstacles[index - 1];
+                               const int right = _obstacles[index + 1];
+                               const bool fullz = (top && bottom);
+                               const bool fully = (up && down);
+                               const bool fullx = (left && right);
+
+                               _xVelocity[index] =
+                               _yVelocity[index] =
+                               _zVelocity[index] = 0.0f;
+                               _pressure[index] = 0.0f;
+
+                               // average pressure neighbors
+                               float pcnt = 0.;
+                               if (left && !right) {
+                                       _pressure[index] += _pressure[index + 1];
+                                       pcnt += 1.;
+                               }
+                               if (!left && right) {
+                                       _pressure[index] += _pressure[index - 1];
+                                       pcnt += 1.;
+                               }
+                               if (up && !down) {
+                                       _pressure[index] += _pressure[index - _xRes];
+                                       pcnt += 1.;
+                               }
+                               if (!up && down) {
+                                       _pressure[index] += _pressure[index + _xRes];
+                                       pcnt += 1.;
+                               }
+                               if (top && !bottom) {
+                                       _pressure[index] += _pressure[index - _xRes];
+                                       pcnt += 1.;
+                               }
+                               if (!top && bottom) {
+                                       _pressure[index] += _pressure[index + _xRes];
+                                       pcnt += 1.;
+                               }
+                               _pressure[index] /= pcnt;
+
+                               // TODO? set correct velocity bc's
+                               // velocities are only set to zero right now
+                               // this means it's not a full no-slip boundary condition
+                               // but a "half-slip" - still looks ok right now
+                       }
+               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// add buoyancy forces
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::addBuoyancy(float *heat, float *density)
+{
+       int index = 0;
+
+       for (int z = 0; z < _zRes; z++)
+               for (int y = 0; y < _yRes; y++)
+                       for (int x = 0; x < _xRes; x++, index++)
+                       {
+                               _zForce[index] += *_alpha * density[index] + (*_beta * (heat[index] - _tempAmb)); // DG: was _yForce, changed for Blender
+                       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// add vorticity to the force field
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::addVorticity()
+{
+       int x,y,z,index;
+       if(_vorticityEps<=0.) return;
+
+       // calculate vorticity
+       float gridSize = 0.5f / _dx;
+       index = _slabSize + _xRes + 1;
+       for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+               for (y = 1; y < _yRes - 1; y++, index += 2)
+                       for (x = 1; x < _xRes - 1; x++, index++)
+                       {
+                               int up    = _obstacles[index + _xRes] ? index : index + _xRes;
+                               int down  = _obstacles[index - _xRes] ? index : index - _xRes;
+                               float dy  = (up == index || down == index) ? 1.0f / _dx : gridSize;
+                               int out   = _obstacles[index + _slabSize] ? index : index + _slabSize;
+                               int in    = _obstacles[index - _slabSize] ? index : index - _slabSize;
+                               float dz  = (out == index || in == index) ? 1.0f / _dx : gridSize;
+                               int right = _obstacles[index + 1] ? index : index + 1;
+                               int left  = _obstacles[index - 1] ? index : index - 1;
+                               float dx  = (right == index || right == index) ? 1.0f / _dx : gridSize;
+
+                               _xVorticity[index] = (_zVelocity[up] - _zVelocity[down]) * dy + (-_yVelocity[out] + _yVelocity[in]) * dz;
+                               _yVorticity[index] = (_xVelocity[out] - _xVelocity[in]) * dz + (-_zVelocity[right] + _zVelocity[left]) * dx;
+                               _zVorticity[index] = (_yVelocity[right] - _yVelocity[left]) * dx + (-_xVelocity[up] + _xVelocity[down])* dy;
+
+                               _vorticity[index] = sqrtf(_xVorticity[index] * _xVorticity[index] +
+                                               _yVorticity[index] * _yVorticity[index] +
+                                               _zVorticity[index] * _zVorticity[index]);
+                       }
+
+       // calculate normalized vorticity vectors
+       float eps = _vorticityEps;
+       index = _slabSize + _xRes + 1;
+       for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+               for (y = 1; y < _yRes - 1; y++, index += 2)
+                       for (x = 1; x < _xRes - 1; x++, index++)
+                               if (!_obstacles[index])
+                               {
+                                       float N[3];
+
+                                       int up    = _obstacles[index + _xRes] ? index : index + _xRes;
+                                       int down  = _obstacles[index - _xRes] ? index : index - _xRes;
+                                       float dy  = (up == index || down == index) ? 1.0f / _dx : gridSize;
+                                       int out   = _obstacles[index + _slabSize] ? index : index + _slabSize;
+                                       int in    = _obstacles[index - _slabSize] ? index : index - _slabSize;
+                                       float dz  = (out == index || in == index) ? 1.0f / _dx : gridSize;
+                                       int right = _obstacles[index + 1] ? index : index + 1;
+                                       int left  = _obstacles[index - 1] ? index : index - 1;
+                                       float dx  = (right == index || right == index) ? 1.0f / _dx : gridSize;
+                                       N[0] = (_vorticity[right] - _vorticity[left]) * dx;
+                                       N[1] = (_vorticity[up] - _vorticity[down]) * dy;
+                                       N[2] = (_vorticity[out] - _vorticity[in]) * dz;
+
+                                       float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
+                                       if (magnitude > 0.0f)
+                                       {
+                                               magnitude = 1.0f / magnitude;
+                                               N[0] *= magnitude;
+                                               N[1] *= magnitude;
+                                               N[2] *= magnitude;
+
+                                               _xForce[index] += (N[1] * _zVorticity[index] - N[2] * _yVorticity[index]) * _dx * eps;
+                                               _yForce[index] -= (N[0] * _zVorticity[index] - N[2] * _xVorticity[index]) * _dx * eps;
+                                               _zForce[index] += (N[0] * _yVorticity[index] - N[1] * _xVorticity[index]) * _dx * eps;
+                                       }
+                               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Advect using the MacCormack method from the Selle paper
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::advectMacCormack()
+{
+       Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
+
+       if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res);
+       else setZeroX(_xVelocity, res);
+
+       if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocity, res);
+       else setZeroY(_yVelocity, res);
+
+       if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocity, res);
+       else setZeroZ(_zVelocity, res);
+
+       SWAP_POINTERS(_xVelocity, _xVelocityOld);
+       SWAP_POINTERS(_yVelocity, _yVelocityOld);
+       SWAP_POINTERS(_zVelocity, _zVelocityOld);
+       SWAP_POINTERS(_density, _densityOld);
+       SWAP_POINTERS(_heat, _heatOld);
+
+       const float dt0 = _dt / _dx;
+       // use force arrays as temp arrays
+  for (int x = 0; x < _totalCells; x++)
+    _xForce[x] = _yForce[x] = 0.0;
+       float* t1 = _xForce;
+       float* t2 = _yForce;
+
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, t1,t2, res, NULL);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, t1,t2, res, NULL);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, t1,t2, res, NULL);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, t1,t2, res, NULL);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, t1,t2, res, NULL);
+
+       if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res);
+       else setZeroX(_xVelocity, res);
+
+       if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocity, res);
+       else setZeroY(_yVelocity, res);
+
+       if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocity, res);
+       else setZeroZ(_zVelocity, res);
+
+       setZeroBorder(_density, res);
+       setZeroBorder(_heat, res);
+
+  for (int x = 0; x < _totalCells; x++)
+    t1[x] = t2[x] = 0.0;
+}
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
new file mode 100644 (file)
index 0000000..c26ed14
--- /dev/null
@@ -0,0 +1,176 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// FLUID_3D.h: interface for the FLUID_3D class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef FLUID_3D_H
+#define FLUID_3D_H
+
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+#include "OBSTACLE.h"
+#include "WTURBULENCE.h"
+#include "VEC3.h"
+
+using namespace std;
+using namespace BasicVector;
+class WTURBULENCE;
+
+class FLUID_3D  
+{
+       public:
+               FLUID_3D(int *res, int amplify, float *p0, float *p1, float dt);
+               FLUID_3D() {};
+               virtual ~FLUID_3D();
+
+               void initBlenderRNA(float *alpha, float *beta);
+               
+               // create & allocate vector noise advection 
+               void initVectorNoise(int amplify);
+
+               void addSmokeColumn();
+               static void addSmokeTestCase(float* field, Vec3Int res, float value);
+
+               void step();
+               void addObstacle(OBSTACLE* obstacle);
+
+               const float* xVelocity() { return _xVelocity; }; 
+               const float* yVelocity() { return _yVelocity; }; 
+               const float* zVelocity() { return _zVelocity; }; 
+
+               int xRes() const { return _xRes; };
+               int yRes() const { return _yRes; };
+               int zRes() const { return _zRes; };
+
+       public:  
+               // dimensions
+               int _xRes, _yRes, _zRes, _maxRes;
+               Vec3Int _res;
+               int _totalCells;
+               int _slabSize;
+               float _dx;
+               float _p0[3];
+               float _p1[3];
+               float _totalTime;
+               int _totalSteps;
+               int _totalImgDumps;
+               int _totalVelDumps;
+
+    void artificialDamping(float* field);
+
+               // fields
+               float* _density;
+               float* _densityOld;
+               float* _heat;
+               float* _heatOld;
+               float* _pressure;
+               float* _xVelocity;
+               float* _yVelocity;
+               float* _zVelocity;
+               float* _xVelocityOld;
+               float* _yVelocityOld;
+               float* _zVelocityOld;
+               float* _xForce;
+               float* _yForce;
+               float* _zForce;
+               float* _divergence;
+               float* _xVorticity;
+               float* _yVorticity;
+               float* _zVorticity;
+               float* _vorticity;
+               unsigned char*  _obstacles;
+
+               // CG fields
+               float* _residual;
+               float* _direction;
+               float* _q;
+               int _iterations;
+
+               // simulation constants
+               float _dt;
+               float _vorticityEps;
+               float _heatDiffusion;
+               float *_alpha; // for the buoyancy density term <-- as pointer to get blender RNA in here
+               float *_beta; // was _buoyancy <-- as pointer to get blender RNA in here
+               float _tempAmb; /* ambient temperature */
+
+               // WTURBULENCE object, if active
+               WTURBULENCE* _wTurbulence;
+
+               // boundary setting functions
+               void copyBorderAll(float* field);
+
+               // timestepping functions
+               void wipeBoundaries();
+               void addForce();
+               void addVorticity();
+               void addBuoyancy(float *heat, float *density);
+
+               // solver stuff
+               void project();
+               void diffuseHeat();
+               void solvePressure(float* field, float* b, unsigned char* skip);
+               void solveHeat(float* field, float* b, unsigned char* skip);
+
+               // handle obstacle boundaries
+               void setObstacleBoundaries();
+
+       public:
+               // advection, accessed e.g. by WTURBULENCE class
+               void advectMacCormack();
+
+               // boundary setting functions
+               static void copyBorderX(float* field, Vec3Int res);
+               static void copyBorderY(float* field, Vec3Int res);
+               static void copyBorderZ(float* field, Vec3Int res);
+               static void setNeumannX(float* field, Vec3Int res);
+               static void setNeumannY(float* field, Vec3Int res);
+               static void setNeumannZ(float* field, Vec3Int res);
+               static void setZeroX(float* field, Vec3Int res);
+               static void setZeroY(float* field, Vec3Int res);
+               static void setZeroZ(float* field, Vec3Int res);
+               static void setZeroBorder(float* field, Vec3Int res) {
+                       setZeroX(field, res);
+                       setZeroY(field, res);
+                       setZeroZ(field, res);
+               };
+
+               // static advection functions, also used by WTURBULENCE
+               static void advectFieldSemiLagrange(const float dt, const float* velx, const float* vely,  const float* velz,
+                               float* oldField, float* newField, Vec3Int res);
+               static void advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, 
+                               float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const float* obstacles);
+
+               // maccormack helper functions
+               static void clampExtrema(const float dt, const float* xVelocity, const float* yVelocity,  const float* zVelocity,
+                               float* oldField, float* newField, Vec3Int res);
+               static void clampOutsideRays(const float dt, const float* xVelocity, const float* yVelocity,  const float* zVelocity,
+                               float* oldField, float* newField, Vec3Int res, const float* obstacles, const float *oldAdvection);
+
+               // output helper functions
+               static void writeImageSliceXY(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
+               static void writeImageSliceYZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
+               static void writeImageSliceXZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
+               static void writeProjectedIntern(const float *field, Vec3Int res, int dir1, int dir2, string prefix, int picCnt, float scale=1.); 
+};
+
+#endif
+
diff --git a/intern/smoke/intern/FLUID_3D_SOLVERS.cpp b/intern/smoke/intern/FLUID_3D_SOLVERS.cpp
new file mode 100644 (file)
index 0000000..b628d48
--- /dev/null
@@ -0,0 +1,318 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// FLUID_3D.cpp: implementation of the FLUID_3D class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "FLUID_3D.h"
+#define SOLVER_ACCURACY 1e-06
+
+//////////////////////////////////////////////////////////////////////
+// solve the poisson equation with CG
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::solvePressure(float* field, float* b, unsigned char* skip)
+{
+  int x, y, z, index;
+
+  // i = 0
+  int i = 0;
+
+  // r = b - Ax
+  index = _slabSize + _xRes + 1;
+  for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+    for (y = 1; y < _yRes - 1; y++, index += 2)
+      for (x = 1; x < _xRes - 1; x++, index++)
+      {
+        // if the cell is a variable
+        float Acenter = 0.0f;
+        if (!skip[index])
+        {
+          // set the matrix to the Poisson stencil in order
+          if (!skip[index + 1]) Acenter += 1.;
+          if (!skip[index - 1]) Acenter += 1.;
+          if (!skip[index + _xRes]) Acenter += 1.;
+          if (!skip[index - _xRes]) Acenter += 1.;
+          if (!skip[index + _slabSize]) Acenter += 1.;
+          if (!skip[index - _slabSize]) Acenter += 1.;
+        }
+        
+        _residual[index] = b[index] - (Acenter * field[index] +  
+          field[index - 1] * (skip[index - 1] ? 0.0 : -1.0f)+ 
+          field[index + 1] * (skip[index + 1] ? 0.0 : -1.0f)+
+          field[index - _xRes] * (skip[index - _xRes] ? 0.0 : -1.0f)+ 
+          field[index + _xRes] * (skip[index + _xRes] ? 0.0 : -1.0f)+
+          field[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -1.0f)+ 
+          field[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -1.0f) );
+        _residual[index] = (skip[index]) ? 0.0f : _residual[index];
+      }
+
+  // d = r
+  index = _slabSize + _xRes + 1;
+  for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+    for (y = 1; y < _yRes - 1; y++, index += 2)
+      for (x = 1; x < _xRes - 1; x++, index++)
+        _direction[index] = _residual[index];
+
+  // deltaNew = transpose(r) * r
+  float deltaNew = 0.0f;
+  index = _slabSize + _xRes + 1;
+  for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+    for (y = 1; y < _yRes - 1; y++, index += 2)
+      for (x = 1; x < _xRes - 1; x++, index++)
+        deltaNew += _residual[index] * _residual[index];
+
+  // delta0 = deltaNew
+  float delta0 = deltaNew;
+
+  // While deltaNew > (eps^2) * delta0
+  const float eps  = SOLVER_ACCURACY;
+  float maxR = 2.0f * eps;
+  while ((i < _iterations) && (maxR > eps))
+  {
+    // q = Ad
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+        {
+          // if the cell is a variable
+          float Acenter = 0.0f;
+          if (!skip[index])
+          {
+            // set the matrix to the Poisson stencil in order
+            if (!skip[index + 1]) Acenter += 1.;
+            if (!skip[index - 1]) Acenter += 1.;
+            if (!skip[index + _xRes]) Acenter += 1.;
+            if (!skip[index - _xRes]) Acenter += 1.;
+            if (!skip[index + _slabSize]) Acenter += 1.;
+            if (!skip[index - _slabSize]) Acenter += 1.;
+          }
+          
+          _q[index] = Acenter * _direction[index] +  
+            _direction[index - 1] * (skip[index - 1] ? 0.0 : -1.0f) + 
+            _direction[index + 1] * (skip[index + 1] ? 0.0 : -1.0f) +
+            _direction[index - _xRes] * (skip[index - _xRes] ? 0.0 : -1.0f) + 
+            _direction[index + _xRes] * (skip[index + _xRes] ? 0.0 : -1.0f)+
+            _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -1.0f) + 
+            _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -1.0f);
+          _q[index] = (skip[index]) ? 0.0f : _q[index];
+        }
+
+    // alpha = deltaNew / (transpose(d) * q)
+    float alpha = 0.0f;
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          alpha += _direction[index] * _q[index];
+    if (fabs(alpha) > 0.0f)
+      alpha = deltaNew / alpha;
+
+    // x = x + alpha * d
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          field[index] += alpha * _direction[index];
+
+    // r = r - alpha * q
+    maxR = 0.0f;
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+        {
+          _residual[index] -= alpha * _q[index];
+          maxR = (_residual[index] > maxR) ? _residual[index] : maxR;
+        }
+
+    // deltaOld = deltaNew
+    float deltaOld = deltaNew;
+
+    // deltaNew = transpose(r) * r
+    deltaNew = 0.0f;
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          deltaNew += _residual[index] * _residual[index];
+
+    // beta = deltaNew / deltaOld
+    float beta = deltaNew / deltaOld;
+
+    // d = r + beta * d
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          _direction[index] = _residual[index] + beta * _direction[index];
+
+    // i = i + 1
+    i++;
+  }
+  cout << i << " iterations converged to " << maxR << endl;
+}
+
+//////////////////////////////////////////////////////////////////////
+// solve the heat equation with CG
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::solveHeat(float* field, float* b, unsigned char* skip)
+{
+  int x, y, z, index;
+  const float heatConst = _dt * _heatDiffusion / (_dx * _dx);
+
+  // i = 0
+  int i = 0;
+
+  // r = b - Ax
+  index = _slabSize + _xRes + 1;
+  for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+    for (y = 1; y < _yRes - 1; y++, index += 2)
+      for (x = 1; x < _xRes - 1; x++, index++)
+      {
+        // if the cell is a variable
+        float Acenter = 1.0f;
+        if (!skip[index])
+        {
+          // set the matrix to the Poisson stencil in order
+          if (!skip[index + 1]) Acenter += heatConst;
+          if (!skip[index - 1]) Acenter += heatConst;
+          if (!skip[index + _xRes]) Acenter += heatConst;
+          if (!skip[index - _xRes]) Acenter += heatConst;
+          if (!skip[index + _slabSize]) Acenter += heatConst;
+          if (!skip[index - _slabSize]) Acenter += heatConst;
+        }
+        
+        _residual[index] = b[index] - (Acenter * field[index] + 
+          field[index - 1] * (skip[index - 1] ? 0.0 : -heatConst) + 
+          field[index + 1] * (skip[index + 1] ? 0.0 : -heatConst) +
+          field[index - _xRes] * (skip[index - _xRes] ? 0.0 : -heatConst) + 
+          field[index + _xRes] * (skip[index + _xRes] ? 0.0 : -heatConst) +
+          field[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -heatConst) + 
+          field[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -heatConst));
+        _residual[index] = (skip[index]) ? 0.0f : _residual[index];
+      }
+
+  // d = r
+  index = _slabSize + _xRes + 1;
+  for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+    for (y = 1; y < _yRes - 1; y++, index += 2)
+      for (x = 1; x < _xRes - 1; x++, index++)
+        _direction[index] = _residual[index];
+
+  // deltaNew = transpose(r) * r
+  float deltaNew = 0.0f;
+  index = _slabSize + _xRes + 1;
+  for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+    for (y = 1; y < _yRes - 1; y++, index += 2)
+      for (x = 1; x < _xRes - 1; x++, index++)
+        deltaNew += _residual[index] * _residual[index];
+
+  // delta0 = deltaNew
+  float delta0 = deltaNew;
+
+  // While deltaNew > (eps^2) * delta0
+  const float eps  = SOLVER_ACCURACY;
+  float maxR = 2.0f * eps;
+  while ((i < _iterations) && (maxR > eps))
+  {
+    // q = Ad
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+        {
+          // if the cell is a variable
+          float Acenter = 1.0f;
+          if (!skip[index])
+          {
+            // set the matrix to the Poisson stencil in order
+            if (!skip[index + 1]) Acenter += heatConst;
+            if (!skip[index - 1]) Acenter += heatConst;
+            if (!skip[index + _xRes]) Acenter += heatConst;
+            if (!skip[index - _xRes]) Acenter += heatConst;
+            if (!skip[index + _slabSize]) Acenter += heatConst;
+            if (!skip[index - _slabSize]) Acenter += heatConst;
+          }
+
+          _q[index] = (Acenter * _direction[index] + 
+            _direction[index - 1] * (skip[index - 1] ? 0.0 : -heatConst) + 
+            _direction[index + 1] * (skip[index + 1] ? 0.0 : -heatConst) +
+            _direction[index - _xRes] * (skip[index - _xRes] ? 0.0 : -heatConst) + 
+            _direction[index + _xRes] * (skip[index + _xRes] ? 0.0 : -heatConst) +
+            _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -heatConst) + 
+            _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -heatConst));
+         
+          _q[index] = (skip[index]) ? 0.0f : _q[index];
+        }
+
+    // alpha = deltaNew / (transpose(d) * q)
+    float alpha = 0.0f;
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          alpha += _direction[index] * _q[index];
+    if (fabs(alpha) > 0.0f)
+      alpha = deltaNew / alpha;
+
+    // x = x + alpha * d
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          field[index] += alpha * _direction[index];
+
+    // r = r - alpha * q
+    maxR = 0.0f;
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+        {
+          _residual[index] -= alpha * _q[index];
+          maxR = (_residual[index] > maxR) ? _residual[index] : maxR;
+        }
+
+    // deltaOld = deltaNew
+    float deltaOld = deltaNew;
+
+    // deltaNew = transpose(r) * r
+    deltaNew = 0.0f;
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          deltaNew += _residual[index] * _residual[index];
+
+    // beta = deltaNew / deltaOld
+    float beta = deltaNew / deltaOld;
+
+    // d = r + beta * d
+    index = _slabSize + _xRes + 1;
+    for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
+      for (y = 1; y < _yRes - 1; y++, index += 2)
+        for (x = 1; x < _xRes - 1; x++, index++)
+          _direction[index] = _residual[index] + beta * _direction[index];
+
+    // i = i + 1
+    i++;
+  }
+  cout << i << " iterations converged to " << maxR << endl;
+}
diff --git a/intern/smoke/intern/FLUID_3D_STATIC.cpp b/intern/smoke/intern/FLUID_3D_STATIC.cpp
new file mode 100644 (file)
index 0000000..7ebe987
--- /dev/null
@@ -0,0 +1,650 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+//
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright 2008 Theodore Kim and Nils Thuerey
+//
+// FLUID_3D.cpp: implementation of the static functions of the FLUID_3D class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include <zlib.h>
+#include "FLUID_3D.h"
+#include "IMAGE.h"
+#include "WTURBULENCE.h"
+#include "INTERPOLATE.h"
+
+//////////////////////////////////////////////////////////////////////
+// add a test cube of density to the center
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::addSmokeColumn() {
+       addSmokeTestCase(_density, _res, 1.0);
+       // addSmokeTestCase(_zVelocity, _res, 1.0);
+       addSmokeTestCase(_heat, _res, 1.0);
+       if (_wTurbulence) {
+               addSmokeTestCase(_wTurbulence->getDensityBig(), _wTurbulence->getResBig(), 1.0);
+       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// generic static version, so that it can be applied to the
+// WTURBULENCE grid as well
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::addSmokeTestCase(float* field, Vec3Int res, float value)
+{
+       const int slabSize = res[0]*res[1]; int maxRes = (int)MAX3V(res);
+       float dx = 1.0f / (float)maxRes;
+
+       float xTotal = dx * res[0];
+       float yTotal = dx * res[1];
+       float zTotal = dx * res[2];
+
+  float heighMin = 0.05;
+  float heighMax = 0.10;
+
+  for (int y = 0; y < res[1]; y++)
+    for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[1]); z++)
+      for (int x = 0; x < res[0]; x++)
+      {
+        float xLength = x * dx - xTotal * 0.4f;
+        float yLength = y * dx - zTotal * 0.5f;
+        float radius = sqrtf(xLength * xLength + yLength * yLength);
+
+        if (radius < 0.075f * xTotal)
+        {
+          int index = x + y * res[0] + z * slabSize;
+          field[index] = value;
+        }
+      }
+}
+
+//////////////////////////////////////////////////////////////////////
+// set x direction to Neumann boundary conditions
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setNeumannX(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       int index;
+       for (int z = 0; z < res[2]; z++)
+               for (int y = 0; y < res[1]; y++)
+               {
+                       // left slab
+                       index = y * res[0] + z * slabSize;
+                       field[index] = field[index + 2];
+
+                       // right slab
+                       index += res[0] - 1;
+                       field[index] = field[index - 2];
+               }
+ }
+
+//////////////////////////////////////////////////////////////////////
+// set y direction to Neumann boundary conditions
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setNeumannY(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       int index;
+       for (int z = 0; z < res[2]; z++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // bottom slab
+                       index = x + z * slabSize;
+                       field[index] = field[index + 2 * res[0]];
+
+                       // top slab
+                       index += slabSize - res[0];
+                       field[index] = field[index - 2 * res[0]];
+               }
+
+       // fix, force top slab to only allow outwards flux
+       for (int z = 0; z < res[2]; z++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // top slab
+                       int index = x + z * slabSize;
+                       index += slabSize - res[0];
+                       if(field[index]<0.) field[index] = 0.;
+                       index -= res[0];
+                       if(field[index]<0.) field[index] = 0.;
+               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// set z direction to Neumann boundary conditions
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setNeumannZ(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       const int totalCells = res[0] * res[1] * res[2];
+       int index;
+       for (int y = 0; y < res[1]; y++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // front slab
+                       index = x + y * res[0];
+                       field[index] = field[index + 2 * slabSize];
+
+                       // back slab
+                       index += totalCells - slabSize;
+                       field[index] = field[index - 2 * slabSize];
+               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// set x direction to zero
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setZeroX(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       int index;
+       for (int z = 0; z < res[2]; z++)
+               for (int y = 0; y < res[1]; y++)
+               {
+                       // left slab
+                       index = y * res[0] + z * slabSize;
+                       field[index] = 0.0f;
+
+                       // right slab
+                       index += res[0] - 1;
+                       field[index] = 0.0f;
+               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// set y direction to zero
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setZeroY(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       int index;
+       for (int z = 0; z < res[2]; z++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // bottom slab
+                       index = x + z * slabSize;
+                       field[index] = 0.0f;
+
+                       // top slab
+                       index += slabSize - res[0];
+                       field[index] = 0.0f;
+               }
+}
+
+//////////////////////////////////////////////////////////////////////
+// set z direction to zero
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::setZeroZ(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       const int totalCells = res[0] * res[1] * res[2];
+       int index;
+       for (int y = 0; y < res[1]; y++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // front slab
+                       index = x + y * res[0];
+                       field[index] = 0.0f;
+
+                       // back slab
+                       index += totalCells - slabSize;
+                       field[index] = 0.0f;
+               }
+ }
+
+//////////////////////////////////////////////////////////////////////
+// copy grid boundary
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::copyBorderX(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       int index;
+       for (int z = 0; z < res[2]; z++)
+               for (int y = 0; y < res[1]; y++)
+               {
+                       // left slab
+                       index = y * res[0] + z * slabSize;
+                       field[index] = field[index + 1];
+
+                       // right slab
+                       index += res[0] - 1;
+                       field[index] = field[index - 1];
+               }
+}
+void FLUID_3D::copyBorderY(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       const int totalCells = res[0] * res[1] * res[2];
+       int index;
+       for (int z = 0; z < res[2]; z++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // bottom slab
+                       index = x + z * slabSize;
+                       field[index] = field[index + res[0]];
+                       // top slab
+                       index += slabSize - res[0];
+                       field[index] = field[index - res[0]];
+               }
+}
+void FLUID_3D::copyBorderZ(float* field, Vec3Int res)
+{
+       const int slabSize = res[0] * res[1];
+       const int totalCells = res[0] * res[1] * res[2];
+       int index;
+       for (int y = 0; y < res[1]; y++)
+               for (int x = 0; x < res[0]; x++)
+               {
+                       // front slab
+                       index = x + y * res[0];
+                       field[index] = field[index + slabSize];
+                       // back slab
+                       index += totalCells - slabSize;
+                       field[index] = field[index - slabSize];
+               }
+}
+
+/////////////////////////////////////////////////////////////////////
+// advect field with the semi lagrangian method
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::advectFieldSemiLagrange(const float dt, const float* velx, const float* vely,  const float* velz,
+               float* oldField, float* newField, Vec3Int res)
+{
+       const int xres = res[0];
+       const int yres = res[1];
+       const int zres = res[2];
+       static int hits = 0;
+       static int total = 0;
+       const int slabSize = res[0] * res[1];
+
+       // scale dt up to grid resolution
+#if PARALLEL==1
+#pragma omp parallel for schedule(static)
+#endif
+       for (int z = 0; z < zres; z++)
+               for (int y = 0; y < yres; y++)
+                       for (int x = 0; x < xres; x++)
+                       {
+                               const int index = x + y * xres + z * xres*yres;
+
+        // backtrace
+                               float xTrace = x - dt * velx[index];
+                               float yTrace = y - dt * vely[index];
+                               float zTrace = z - dt * velz[index];
+
+                               // clamp backtrace to grid boundaries
+                               if (xTrace < 0.5) xTrace = 0.5;
+                               if (xTrace > xres - 1.5) xTrace = xres - 1.5;
+                               if (yTrace < 0.5) yTrace = 0.5;
+                               if (yTrace > yres - 1.5) yTrace = yres - 1.5;
+                               if (zTrace < 0.5) zTrace = 0.5;
+                               if (zTrace > zres - 1.5) zTrace = zres - 1.5;
+
+                               // locate neighbors to interpolate
+                               const int x0 = (int)xTrace;
+                               const int x1 = x0 + 1;
+                               const int y0 = (int)yTrace;
+                               const int y1 = y0 + 1;
+                               const int z0 = (int)zTrace;
+                               const int z1 = z0 + 1;
+
+                               // get interpolation weights
+                               const float s1 = xTrace - x0;
+                               const float s0 = 1.0f - s1;
+                               const float t1 = yTrace - y0;
+                               const float t0 = 1.0f - t1;
+                               const float u1 = zTrace - z0;
+                               const float u0 = 1.0f - u1;
+
+                               const int i000 = x0 + y0 * xres + z0 * slabSize;
+                               const int i010 = x0 + y1 * xres + z0 * slabSize;
+                               const int i100 = x1 + y0 * xres + z0 * slabSize;
+                               const int i110 = x1 + y1 * xres + z0 * slabSize;
+                               const int i001 = x0 + y0 * xres + z1 * slabSize;
+                               const int i011 = x0 + y1 * xres + z1 * slabSize;
+                               const int i101 = x1 + y0 * xres + z1 * slabSize;
+                               const int i111 = x1 + y1 * xres + z1 * slabSize;
+
+                               // interpolate
+                               // (indices could be computed once)
+                               newField[index] = u0 * (s0 * (t0 * oldField[i000] +
+                                                       t1 * oldField[i010]) +
+                                               s1 * (t0 * oldField[i100] +
+                                                       t1 * oldField[i110])) +
+                                       u1 * (s0 * (t0 * oldField[i001] +
+                                                               t1 * oldField[i011]) +
+                                                       s1 * (t0 * oldField[i101] +
+                                                               t1 * oldField[i111]));
+                       }
+}
+
+/////////////////////////////////////////////////////////////////////
+// advect field with the maccormack method
+//
+// comments are the pseudocode from selle's paper
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
+               float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const float* obstacles)
+{
+       float* phiHatN  = temp1;
+       float* phiHatN1 = temp2;
+       const int sx= res[0];
+       const int sy= res[1];
+       const int sz= res[2];
+
+       for (int x = 0; x < sx * sy * sz; x++)
+               phiHatN[x] = phiHatN1[x] = oldField[x];
+
+       float*& phiN    = oldField;
+       float*& phiN1   = newField;
+
+       // phiHatN1 = A(phiN)
+       advectFieldSemiLagrange(  dt, xVelocity, yVelocity, zVelocity, phiN, phiHatN1, res);
+
+       // phiHatN = A^R(phiHatN1)
+       advectFieldSemiLagrange( -1.0*dt, xVelocity, yVelocity, zVelocity, phiHatN1, phiHatN, res);
+
+       // phiN1 = phiHatN1 + (phiN - phiHatN) / 2
+       const int border = 0;
+       for (int z = border; z < sz-border; z++)
+               for (int y = border; y < sy-border; y++)
+                       for (int x = border; x < sx-border; x++) {
+                               int index = x + y * sx + z * sx*sy;
+                               phiN1[index] = phiHatN1[index] + (phiN[index] - phiHatN[index]) * 0.50f;
+                               //phiN1[index] = phiHatN1[index]; // debug, correction off
+                       }
+       copyBorderX(phiN1, res);
+       copyBorderY(phiN1, res);
+       copyBorderZ(phiN1, res);
+
+       // clamp any newly created extrema
+       clampExtrema(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res);
+
+       // if the error estimate was bad, revert to first order
+       clampOutsideRays(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, obstacles, phiHatN1);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// Clamp the extrema generated by the BFECC error correction
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::clampExtrema(const float dt, const float* velx, const float* vely,  const float* velz,
+               float* oldField, float* newField, Vec3Int res)
+{
+       const int xres= res[0];
+       const int yres= res[1];
+       const int zres= res[2];
+       const int slabSize = res[0] * res[1];
+       for (int z = 1; z < zres-1; z++)
+               for (int y = 1; y < yres-1; y++)
+                       for (int x = 1; x < xres-1; x++)
+                       {
+                               const int index = x + y * xres+ z * xres*yres;
+                               // backtrace
+                               float xTrace = x - dt * velx[index];
+                               float yTrace = y - dt * vely[index];
+                               float zTrace = z - dt * velz[index];
+
+                               // clamp backtrace to grid boundaries
+                               if (xTrace < 0.5) xTrace = 0.5;
+                               if (xTrace > xres - 1.5) xTrace = xres - 1.5;
+                               if (yTrace < 0.5) yTrace = 0.5;
+                               if (yTrace > yres - 1.5) yTrace = yres - 1.5;
+                               if (zTrace < 0.5) zTrace = 0.5;
+                               if (zTrace > zres - 1.5) zTrace = zres - 1.5;
+
+                               // locate neighbors to interpolate
+                               const int x0 = (int)xTrace;
+                               const int x1 = x0 + 1;
+                               const int y0 = (int)yTrace;
+                               const int y1 = y0 + 1;
+                               const int z0 = (int)zTrace;
+                               const int z1 = z0 + 1;
+
+                               const int i000 = x0 + y0 * xres + z0 * slabSize;
+                               const int i010 = x0 + y1 * xres + z0 * slabSize;
+                               const int i100 = x1 + y0 * xres + z0 * slabSize;
+                               const int i110 = x1 + y1 * xres + z0 * slabSize;
+                               const int i001 = x0 + y0 * xres + z1 * slabSize;
+                               const int i011 = x0 + y1 * xres + z1 * slabSize;
+                               const int i101 = x1 + y0 * xres + z1 * slabSize;
+                               const int i111 = x1 + y1 * xres + z1 * slabSize;
+
+                               float minField = oldField[i000];
+                               float maxField = oldField[i000];
+
+                               minField = (oldField[i010] < minField) ? oldField[i010] : minField;
+                               maxField = (oldField[i010] > maxField) ? oldField[i010] : maxField;
+
+                               minField = (oldField[i100] < minField) ? oldField[i100] : minField;
+                               maxField = (oldField[i100] > maxField) ? oldField[i100] : maxField;
+
+                               minField = (oldField[i110] < minField) ? oldField[i110] : minField;
+                               maxField = (oldField[i110] > maxField) ? oldField[i110] : maxField;
+
+                               minField = (oldField[i001] < minField) ? oldField[i001] : minField;
+                               maxField = (oldField[i001] > maxField) ? oldField[i001] : maxField;
+
+                               minField = (oldField[i011] < minField) ? oldField[i011] : minField;
+                               maxField = (oldField[i011] > maxField) ? oldField[i011] : maxField;
+
+                               minField = (oldField[i101] < minField) ? oldField[i101] : minField;
+                               maxField = (oldField[i101] > maxField) ? oldField[i101] : maxField;
+
+                               minField = (oldField[i111] < minField) ? oldField[i111] : minField;
+                               maxField = (oldField[i111] > maxField) ? oldField[i111] : maxField;
+
+                               newField[index] = (newField[index] > maxField) ? maxField : newField[index];
+                               newField[index] = (newField[index] < minField) ? minField : newField[index];
+                       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Reverts any backtraces that go into boundaries back to first
+// order -- in this case the error correction term was totally
+// incorrect
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::clampOutsideRays(const float dt, const float* velx, const float* vely, const float* velz,
+               float* oldField, float* newField, Vec3Int res, const float* obstacles, const float *oldAdvection)
+{
+       const int sx= res[0];
+       const int sy= res[1];
+       const int sz= res[2];
+       const int slabSize = res[0] * res[1];
+       for (int z = 1; z < sz-1; z++)
+               for (int y = 1; y < sy-1; y++)
+                       for (int x = 1; x < sx-1; x++)
+                       {
+                               const int index = x + y * sx+ z * slabSize;
+                               // backtrace
+                               float xBackward = x + dt * velx[index];
+                               float yBackward = y + dt * vely[index];
+                               float zBackward = z + dt * velz[index];
+                               float xTrace    = x - dt * velx[index];
+                               float yTrace    = y - dt * vely[index];
+                               float zTrace    = z - dt * velz[index];
+
+                               // see if it goes outside the boundaries
+                               bool hasObstacle =
+                                       (zTrace < 1.0f)    || (zTrace > sz - 2.0f) ||
+                                       (yTrace < 1.0f)    || (yTrace > sy - 2.0f) ||
+                                       (xTrace < 1.0f)    || (xTrace > sx - 2.0f) ||
+                                       (zBackward < 1.0f) || (zBackward > sz - 2.0f) ||
+                                       (yBackward < 1.0f) || (yBackward > sy - 2.0f) ||
+                                       (xBackward < 1.0f) || (xBackward > sx - 2.0f);
+                               // reuse old advection instead of doing another one...
+                               if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
+
+                               // clamp to prevent an out of bounds access when looking into
+                               // the _obstacles array
+                               zTrace = (zTrace < 0.5f) ? 0.5f : zTrace;
+                               zTrace = (zTrace > sz - 1.5f) ? sz - 1.5f : zTrace;
+                               yTrace = (yTrace < 0.5f) ? 0.5f : yTrace;
+                               yTrace = (yTrace > sy - 1.5f) ? sy - 1.5f : yTrace;
+                               xTrace = (xTrace < 0.5f) ? 0.5f : xTrace;
+                               xTrace = (xTrace > sx - 1.5f) ? sx - 1.5f : xTrace;
+
+                               // locate neighbors to interpolate,
+                               // do backward first since we will use the forward indices if a
+                               // reversion is actually necessary
+                               zBackward = (zBackward < 0.5f) ? 0.5f : zBackward;
+                               zBackward = (zBackward > sz - 1.5f) ? sz - 1.5f : zBackward;
+                               yBackward = (yBackward < 0.5f) ? 0.5f : yBackward;
+                               yBackward = (yBackward > sy - 1.5f) ? sy - 1.5f : yBackward;
+                               xBackward = (xBackward < 0.5f) ? 0.5f : xBackward;
+                               xBackward = (xBackward > sx - 1.5f) ? sx - 1.5f : xBackward;
+
+                               int x0 = (int)xBackward;
+                               int x1 = x0 + 1;
+                               int y0 = (int)yBackward;
+                               int y1 = y0 + 1;
+                               int z0 = (int)zBackward;
+                               int z1 = z0 + 1;
+                               if(obstacles && !hasObstacle) {
+                                       hasObstacle = hasObstacle ||
+                                               obstacles[x0 + y0 * sx + z0*slabSize] ||
+                                               obstacles[x0 + y1 * sx + z0*slabSize] ||
+                                               obstacles[x1 + y0 * sx + z0*slabSize] ||
+                                               obstacles[x1 + y1 * sx + z0*slabSize] ||
+                                               obstacles[x0 + y0 * sx + z1*slabSize] ||
+                                               obstacles[x0 + y1 * sx + z1*slabSize] ||
+                                               obstacles[x1 + y0 * sx + z1*slabSize] ||
+                                               obstacles[x1 + y1 * sx + z1*slabSize] ;
+                               }
+                               // reuse old advection instead of doing another one...
+                               if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
+
+                               x0 = (int)xTrace;
+                               x1 = x0 + 1;
+                               y0 = (int)yTrace;
+                               y1 = y0 + 1;
+                               z0 = (int)zTrace;
+                               z1 = z0 + 1;
+                               if(obstacles && !hasObstacle) {
+                                       hasObstacle = hasObstacle ||
+                                               obstacles[x0 + y0 * sx + z0*slabSize] ||
+                                               obstacles[x0 + y1 * sx + z0*slabSize] ||
+                                               obstacles[x1 + y0 * sx + z0*slabSize] ||
+                                               obstacles[x1 + y1 * sx + z0*slabSize] ||
+                                               obstacles[x0 + y0 * sx + z1*slabSize] ||
+                                               obstacles[x0 + y1 * sx + z1*slabSize] ||
+                                               obstacles[x1 + y0 * sx + z1*slabSize] ||
+                                               obstacles[x1 + y1 * sx + z1*slabSize] ;
+                               } // obstacle array
+                               // reuse old advection instead of doing another one...
+                               if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
+
+                               // see if either the forward or backward ray went into
+                               // a boundary
+                               if (hasObstacle) {
+                                       // get interpolation weights
+                                       float s1 = xTrace - x0;
+                                       float s0 = 1.0f - s1;
+                                       float t1 = yTrace - y0;
+                                       float t0 = 1.0f - t1;
+                                       float u1 = zTrace - z0;
+                                       float u0 = 1.0f - u1;
+
+                                       const int i000 = x0 + y0 * sx + z0 * slabSize;
+                                       const int i010 = x0 + y1 * sx + z0 * slabSize;
+                                       const int i100 = x1 + y0 * sx + z0 * slabSize;
+                                       const int i110 = x1 + y1 * sx + z0 * slabSize;
+                                       const int i001 = x0 + y0 * sx + z1 * slabSize;
+                                       const int i011 = x0 + y1 * sx + z1 * slabSize;
+                                       const int i101 = x1 + y0 * sx + z1 * slabSize;
+                                       const int i111 = x1 + y1 * sx + z1 * slabSize;
+
+                                       // interpolate, (indices could be computed once)
+                                       newField[index] = u0 * (s0 * (
+                                                               t0 * oldField[i000] +
+                                                               t1 * oldField[i010]) +
+                                                       s1 * (t0 * oldField[i100] +
+                                                               t1 * oldField[i110])) +
+                                               u1 * (s0 * (t0 * oldField[i001] +
+                                                                       t1 * oldField[i011]) +
+                                                               s1 * (t0 * oldField[i101] +
+                                                                       t1 * oldField[i111]));
+                               }
+                       } // xyz
+}
+
+//////////////////////////////////////////////////////////////////////
+// image output
+//////////////////////////////////////////////////////////////////////
+/*
+void FLUID_3D::writeImageSliceXY(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale) {
+  writeProjectedIntern(field, res, 0,1, prefix, picCnt, scale);
+}
+void FLUID_3D::writeImageSliceYZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale) {
+  writeProjectedIntern(field, res, 1,2, prefix, picCnt, scale);
+}
+void FLUID_3D::writeImageSliceXZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale) {
+  writeProjectedIntern(field, res, 0,2, prefix, picCnt, scale);
+}
+*/
+
+//////////////////////////////////////////////////////////////////////
+// Helper function for projecting densities along a dimension
+//////////////////////////////////////////////////////////////////////
+static int getOtherDir(int dir1, int dir2) {
+       switch(dir1) {
+               case 0:
+                       switch(dir2) {
+                               case 1: return 2;
+                               case 2: return 1; }
+                       break;
+               case 1:
+                       switch(dir2) {
+                               case 0: return 2;
+                               case 2: return 0; }
+                       break;
+               case 2:
+                       switch(dir2) {
+                               case 0: return 1;
+                               case 1: return 0; }
+                       break;
+       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// average densities along third spatial direction
+//////////////////////////////////////////////////////////////////////
+void FLUID_3D::writeProjectedIntern(const float *field, Vec3Int res,
+               int dir1, int dir2, string prefix, int picCnt, float scale) {
+       const int nitems = res[dir1]*res[dir2];
+       const int otherDir = getOtherDir(dir1,dir2);
+       float *buf = new float[nitems];
+       Vec3Int min = Vec3Int(0);
+       Vec3Int max = res;
+
+       min[otherDir] = 0;
+       max[otherDir] = res[otherDir];
+       float div = 1./(float)MIN3V(res); // normalize for shorter sides, old: res[otherDir];
+       div *= 4.; //slightly increase contrast
+       for(int i=0; i<nitems; i++) buf[i] = 0.;
+
+       Vec3Int cnt = 0;
+       for (cnt[2] = min[2]; cnt[2] < max[2]; cnt[2]++) {
+               for (cnt[1] = min[1]; cnt[1] < max[1]; cnt[1]++)
+                       for (cnt[0] = min[0]; cnt[0] < max[0]; cnt[0]++)
+                       {
+                               const int index = cnt[0] + cnt[1] * res[0] + cnt[2] * res[0]*res[1];
+                               const int bufindex = cnt[dir1] + cnt[dir2] * res[dir1];
+                               buf[bufindex] += field[index] * scale *div;
+                       }
+       }
+       IMAGE::dumpNumberedPNG(picCnt, prefix, buf, res[dir1], res[dir2]);
+       delete[] buf;
+}
diff --git a/intern/smoke/intern/IMAGE.h b/intern/smoke/intern/IMAGE.h
new file mode 100644 (file)
index 0000000..772c016
--- /dev/null
@@ -0,0 +1,270 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+//
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright 2008 Theodore Kim and Nils Thuerey
+//
+//////////////////////////////////////////////////////////////////////
+//
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <zlib.h>
+
+//////////////////////////////////////////////////////////////////////
+// NT helper functions
+//////////////////////////////////////////////////////////////////////
+template < class T > inline T ABS( T a ) {
+       return (0 < a) ? a : -a ;
+}
+
+template < class T > inline void SWAP_POINTERS( T &a, T &b ) {
+       T temp = a;
+       a = b;
+       b = temp;
+}
+
+template < class T > inline void CLAMP( T &a, T b=0., T c=1.) {
+       if(a<b) { a=b; return; }
+       if(a>c) { a=c; return; }
+}
+
+template < class T > inline T MIN( T a, T b) {
+       return (a < b) ? a : b;
+}
+
+template < class T > inline T MAX( T a, T b) {
+       return (a > b) ? a : b;
+}
+
+template < class T > inline T MAX3( T a, T b, T c) {
+       T max = (a > b) ? a : b;
+       max = (max > c) ? max : c;
+       return max;
+}
+
+template < class T > inline float MAX3V( T vec) {
+       float max = (vec[0] > vec[1]) ? vec[0] : vec[1];
+       max = (max > vec[2]) ? max : vec[2];
+       return max;
+}
+
+template < class T > inline float MIN3V( T vec) {
+       float min = (vec[0] < vec[1]) ? vec[0] : vec[1];
+       min = (min < vec[2]) ? min : vec[2];
+       return min;
+}
+
+//////////////////////////////////////////////////////////////////////
+// PNG, POV-Ray, and PBRT output functions
+//////////////////////////////////////////////////////////////////////
+#include <png.h>
+
+namespace IMAGE {
+  static int writePng(const char *fileName, unsigned char **rowsp, int w, int h, bool normalize)
+  {
+    // defaults
+    const int colortype = PNG_COLOR_TYPE_RGBA;
+    const int bitdepth = 8;
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+    png_bytep *rows = rowsp;
+
+    FILE *fp = NULL;
+    std::string doing = "open for writing";
+    if (!(fp = fopen(fileName, "wb"))) goto fail;
+
+    if(!png_ptr) {
+      doing = "create png write struct";
+      if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
+    }
+    if(!info_ptr) {
+      doing = "create png info struct";
+      if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) goto fail;
+    doing = "init IO";
+    png_init_io(png_ptr, fp);
+    doing = "write header";
+    png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
+        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+    doing = "write info";
+    png_write_info(png_ptr, info_ptr);
+    doing = "write image";
+    png_write_image(png_ptr, rows);
+    doing = "write end";
+    png_write_end(png_ptr, NULL);
+    doing = "write destroy structs";
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    fclose( fp );
+    return 0;
+
+  fail:
+    std::cerr << "writePng: could not "<<doing<<" !\n";
+    if(fp) fclose( fp );
+    if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
+    return -1;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////
+  // write a numbered PNG file out, padded with zeros up to three zeros
+  /////////////////////////////////////////////////////////////////////////////////
+  static void dumpNumberedPNG(int counter, std::string prefix, float* field, int xRes, int yRes)
+  {
+    /*
+       char buffer[256];
+    sprintf(buffer,"%04i", counter);
+    std::string number = std::string(buffer);
+
+    unsigned char pngbuf[xRes*yRes*4];
+    unsigned char *rows[yRes];
+    float *pfield = field;
+    for (int j=0; j<yRes; j++) {
+      for (int i=0; i<xRes; i++) {
+        float val = *pfield;
+        if(val>1.) val=1.;
+        if(val<0.) val=0.;
+        pngbuf[(j*xRes+i)*4+0] = (unsigned char)(val*255.);
+        pngbuf[(j*xRes+i)*4+1] = (unsigned char)(val*255.);
+        pngbuf[(j*xRes+i)*4+2] = (unsigned char)(val*255.);
+        pfield++;
+        pngbuf[(j*xRes+i)*4+3] = 255;
+      }
+      rows[j] = &pngbuf[(yRes-j-1)*xRes*4];
+    }
+    std::string filenamePNG = prefix + number + std::string(".png");
+    writePng(filenamePNG.c_str(), rows, xRes, yRes, false);
+    printf("Writing %s\n", filenamePNG.c_str());
+    */
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////
+  // export pbrt volumegrid geometry object
+  /////////////////////////////////////////////////////////////////////////////////
+  static void dumpPBRT(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes)
+  {
+    char buffer[256];
+    sprintf(buffer,"%04i", counter);
+    std::string number = std::string(buffer);
+
+    std::string filenamePbrt = prefix + number + std::string(".pbrt.gz");
+    printf("Writing PBRT %s\n", filenamePbrt.c_str());
+
+    float *field = new float[xRes*yRes*zRes];
+    // normalize values
+    float maxDensVal = ABS(fieldOrg[0]);
+    float targetNorm = 0.5;
+    for (int i = 0; i < xRes * yRes * zRes; i++) {
+      if(ABS(fieldOrg[i])>maxDensVal) maxDensVal = ABS(fieldOrg[i]);
+      field[i] = 0.;
+    }
+    if(maxDensVal>0.) {
+      for (int i = 0; i < xRes * yRes * zRes; i++) {
+        field[i] = ABS(fieldOrg[i]) / maxDensVal * targetNorm;
+      }
+    }
+
+    std::fstream fout;
+    fout.open(filenamePbrt.c_str(), std::ios::out);
+
+    int maxRes = (xRes > yRes) ? xRes : yRes;
+    maxRes = (maxRes > zRes) ? maxRes : zRes;
+
+    const float xSize = 1.0 / (float)maxRes * (float)xRes;
+    const float ySize = 1.0 / (float)maxRes * (float)yRes;
+    const float zSize = 1.0 / (float)maxRes * (float)zRes;
+
+    gzFile file;
+    file = gzopen(filenamePbrt.c_str(), "wb1");
+    if (file == NULL) {
+      std::cerr << " Couldn't write file " << filenamePbrt << "!!!" << std::endl;
+      return;
+    }
+
+    // dimensions
+    gzprintf(file, "Volume \"volumegrid\" \n");
+    gzprintf(file, " \"integer nx\" %i\n", xRes);
+    gzprintf(file, " \"integer ny\" %i\n", yRes);
+    gzprintf(file, " \"integer nz\" %i\n", zRes);
+    gzprintf(file, " \"point p0\" [ 0.0 0.0 0.0 ] \"point p1\" [%f %f %f ] \n", xSize, ySize, zSize);
+    gzprintf(file, " \"float density\" [ \n");
+    for (int i = 0; i < xRes * yRes * zRes; i++)
+      gzprintf(file, "%f ", field[i]);
+    gzprintf(file, "] \n \n");
+
+    gzclose(file);
+    delete[] field;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////
+  // 3D df3 export
+  /////////////////////////////////////////////////////////////////////////////////
+  static void dumpDF3(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes)
+  {
+    char buffer[256];
+
+    // do deferred copying to final directory, better for network directories
+    sprintf(buffer,"%04i", counter);
+    std::string number = std::string(buffer);
+    std::string filenameDf3 = prefix + number + std::string(".df3.gz");
+    printf("Writing DF3 %s\n", filenameDf3.c_str());
+
+    gzFile file;
+    file = gzopen(filenameDf3.c_str(), "wb1");
+    if (file == NULL) {
+      std::cerr << " Couldn't write file " << filenameDf3 << "!!!" << std::endl;
+      return;
+    }
+
+    // dimensions
+    const int byteSize = 2;
+    const unsigned short int onx=xRes,ony=yRes,onz=zRes;
+    unsigned short int nx,ny,nz;
+    nx = onx >> 8;
+    ny = ony >> 8;
+    nz = onz >> 8;
+    nx += (onx << 8);
+    ny += (ony << 8);
+    nz += (onz << 8);
+    gzwrite(file, (void*)&nx, sizeof(short));
+    gzwrite(file, (void*)&ny, sizeof(short));
+    gzwrite(file, (void*)&nz, sizeof(short));
+    const int nitems = onx*ony*onz;
+    const float mul = (float)( (1<<(8*byteSize))-1);
+
+    unsigned short int *buf = new unsigned short int[nitems];
+    for (int k = 0; k < onz; k++)
+      for (int j = 0; j < ony; j++)
+        for (int i = 0; i < onx; i++) {
+          float val = fieldOrg[k*(onx*ony)+j*onx+i] ;
+          CLAMP(val);
+          buf[k*(onx*ony)+j*onx+i] = (short int)(val*mul);
+        }
+    gzwrite(file, (void*)buf, sizeof(unsigned short int)* nitems);
+
+    gzclose(file);
+    delete[] buf;
+  }
+
+};
+
+
+#endif
diff --git a/intern/smoke/intern/INTERPOLATE.h b/intern/smoke/intern/INTERPOLATE.h
new file mode 100644 (file)
index 0000000..6800c3b
--- /dev/null
@@ -0,0 +1,227 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+//////////////////////////////////////////////////////////////////////
+#ifndef INTERPOLATE_H
+#define INTERPOLATE_H
+
+#include <iostream>
+#include <VEC3.h>
+
+namespace INTERPOLATE {
+
+//////////////////////////////////////////////////////////////////////
+// linear interpolators
+//////////////////////////////////////////////////////////////////////
+static inline float lerp(float t, float a, float b) {
+       return ( a + t * (b - a) );
+}
+
+static inline float lerp(float* field, float x, float y, int res) {
+       // clamp backtrace to grid boundaries
+       if (x < 0.5f) x = 0.5f;
+       if (x > res - 1.5f) x = res - 1.5f;
+       if (y < 0.5f) y = 0.5f;
+       if (y > res - 1.5f) y = res - 1.5f;
+
+       const int x0 = (int)x;
+       const int y0 = (int)y;
+       x -= x0;
+       y -= y0;
+       float d00, d10, d01, d11;
+
+       // lerp the velocities
+       d00 = field[x0 + y0 * res];
+       d10 = field[(x0 + 1) + y0 * res];
+       d01 = field[x0 + (y0 + 1) * res];
+       d11 = field[(x0 + 1) + (y0 + 1) * res];
+       return lerp(y, lerp(x, d00, d10),
+                       lerp(x, d01, d11));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// 3d linear interpolation
+////////////////////////////////////////////////////////////////////////////////////////// 
+static inline float lerp3d(float* field, float x, float y, float z,  int xres, int yres, int zres) {
+       // clamp pos to grid boundaries
+       if (x < 0.5) x = 0.5;
+       if (x > xres - 1.5) x = xres - 1.5;
+       if (y < 0.5) y = 0.5;
+       if (y > yres - 1.5) y = yres - 1.5;
+       if (z < 0.5) z = 0.5;
+       if (z > zres - 1.5) z = zres - 1.5;
+
+       // locate neighbors to interpolate
+       const int x0 = (int)x;
+       const int x1 = x0 + 1;
+       const int y0 = (int)y;
+       const int y1 = y0 + 1;
+       const int z0 = (int)z;
+       const int z1 = z0 + 1;
+
+       // get interpolation weights
+       const float s1 = x - (float)x0;
+       const float s0 = 1.0f - s1;
+       const float t1 = y - (float)y0;
+       const float t0 = 1.0f - t1;
+       const float u1 = z - (float)z0;
+       const float u0 = 1.0f - u1;
+
+       const int slabSize = xres*yres;
+       const int i000 = x0 + y0 * xres + z0 * slabSize;
+       const int i010 = x0 + y1 * xres + z0 * slabSize;
+       const int i100 = x1 + y0 * xres + z0 * slabSize;
+       const int i110 = x1 + y1 * xres + z0 * slabSize;
+       const int i001 = x0 + y0 * xres + z1 * slabSize;
+       const int i011 = x0 + y1 * xres + z1 * slabSize;
+       const int i101 = x1 + y0 * xres + z1 * slabSize;
+       const int i111 = x1 + y1 * xres + z1 * slabSize;
+
+       // interpolate (indices could be computed once)
+       return ( u0 * (s0 * (t0 * field[i000] +
+               t1 * field[i010]) +
+               s1 * (t0 * field[i100] +
+               t1 * field[i110])) +
+               u1 * (s0 * (t0 * field[i001] +
+               t1 * field[i011]) +
+               s1 * (t0 * field[i101] +
+               t1 * field[i111])) );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// convert field entries of type T to floats, then interpolate
+//////////////////////////////////////////////////////////////////////////////////////////
+template <class T> 
+static inline float lerp3dToFloat(T* field1,
+               float x, float y, float z,  int xres, int yres, int zres) {
+       // clamp pos to grid boundaries
+       if (x < 0.5) x = 0.5;
+       if (x > xres - 1.5) x = xres - 1.5;
+       if (y < 0.5) y = 0.5;
+       if (y > yres - 1.5) y = yres - 1.5;
+       if (z < 0.5) z = 0.5;
+       if (z > zres - 1.5) z = zres - 1.5;
+
+       // locate neighbors to interpolate
+       const int x0 = (int)x;
+       const int x1 = x0 + 1;
+       const int y0 = (int)y;
+       const int y1 = y0 + 1;
+       const int z0 = (int)z;
+       const int z1 = z0 + 1;
+
+       // get interpolation weights
+       const float s1 = x - (float)x0;
+       const float s0 = 1.0f - s1;
+       const float t1 = y - (float)y0;
+       const float t0 = 1.0f - t1;
+       const float u1 = z - (float)z0;
+       const float u0 = 1.0f - u1;
+
+       const int slabSize = xres*yres;
+       const int i000 = x0 + y0 * xres + z0 * slabSize;
+       const int i010 = x0 + y1 * xres + z0 * slabSize;
+       const int i100 = x1 + y0 * xres + z0 * slabSize;
+       const int i110 = x1 + y1 * xres + z0 * slabSize;
+       const int i001 = x0 + y0 * xres + z1 * slabSize;
+       const int i011 = x0 + y1 * xres + z1 * slabSize;
+       const int i101 = x1 + y0 * xres + z1 * slabSize;
+       const int i111 = x1 + y1 * xres + z1 * slabSize;
+
+       // interpolate (indices could be computed once)
+       return (float)(
+                       ( u0 * (s0 * (t0 * (float)field1[i000] +
+                               t1 * (float)field1[i010]) +
+                               s1 * (t0 * (float)field1[i100] +
+                               t1 * (float)field1[i110])) +
+                               u1 * (s0 * (t0 * (float)field1[i001] +
+                               t1 * (float)field1[i011]) +
+                               s1 * (t0 * (float)field1[i101] +
+                               t1 * (float)field1[i111])) ) );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// interpolate a vector from 3 fields
+//////////////////////////////////////////////////////////////////////////////////////////
+static inline Vec3 lerp3dVec(float* field1, float* field2, float* field3, 
+               float x, float y, float z,  int xres, int yres, int zres) {
+       // clamp pos to grid boundaries
+       if (x < 0.5) x = 0.5;
+       if (x > xres - 1.5) x = xres - 1.5;
+       if (y < 0.5) y = 0.5;
+       if (y > yres - 1.5) y = yres - 1.5;
+       if (z < 0.5) z = 0.5;
+       if (z > zres - 1.5) z = zres - 1.5;
+
+       // locate neighbors to interpolate
+       const int x0 = (int)x;
+       const int x1 = x0 + 1;
+       const int y0 = (int)y;
+       const int y1 = y0 + 1;
+       const int z0 = (int)z;
+       const int z1 = z0 + 1;
+
+       // get interpolation weights
+       const float s1 = x - (float)x0;
+       const float s0 = 1.0f - s1;
+       const float t1 = y - (float)y0;
+       const float t0 = 1.0f - t1;
+       const float u1 = z - (float)z0;
+       const float u0 = 1.0f - u1;
+
+       const int slabSize = xres*yres;
+       const int i000 = x0 + y0 * xres + z0 * slabSize;
+       const int i010 = x0 + y1 * xres + z0 * slabSize;
+       const int i100 = x1 + y0 * xres + z0 * slabSize;
+       const int i110 = x1 + y1 * xres + z0 * slabSize;
+       const int i001 = x0 + y0 * xres + z1 * slabSize;
+       const int i011 = x0 + y1 * xres + z1 * slabSize;
+       const int i101 = x1 + y0 * xres + z1 * slabSize;
+       const int i111 = x1 + y1 * xres + z1 * slabSize;
+
+       // interpolate (indices could be computed once)
+       return Vec3(
+                       ( u0 * (s0 * (t0 * field1[i000] +
+                               t1 * field1[i010]) +
+                               s1 * (t0 * field1[i100] +
+                               t1 * field1[i110])) +
+                               u1 * (s0 * (t0 * field1[i001] +
+                               t1 * field1[i011]) +
+                               s1 * (t0 * field1[i101] +
+                               t1 * field1[i111])) ) , 
+                       ( u0 * (s0 * (t0 * field2[i000] +
+                               t1 * field2[i010]) +
+                               s1 * (t0 * field2[i100] +
+                               t1 * field2[i110])) +
+                               u1 * (s0 * (t0 * field2[i001] +
+                               t1 * field2[i011]) +
+                               s1 * (t0 * field2[i101] +
+                               t1 * field2[i111])) ) , 
+                       ( u0 * (s0 * (t0 * field3[i000] +
+                               t1 * field3[i010]) +
+                               s1 * (t0 * field3[i100] +
+                               t1 * field3[i110])) +
+                               u1 * (s0 * (t0 * field3[i001] +
+                               t1 * field3[i011]) +
+                               s1 * (t0 * field3[i101] +
+                               t1 * field3[i111])) ) 
+                       );
+}
+
+};
+#endif
diff --git a/intern/smoke/intern/LICENSE.txt b/intern/smoke/intern/LICENSE.txt
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/intern/smoke/intern/LU_HELPER.h b/intern/smoke/intern/LU_HELPER.h
new file mode 100644 (file)
index 0000000..b3f3c5a
--- /dev/null
@@ -0,0 +1,56 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+//////////////////////////////////////////////////////////////////////
+
+#ifndef LU_HELPER_H
+#define LU_HELPER_H
+
+//////////////////////////////////////////////////////////////////////
+// Helper function, compute eigenvalues of 3x3 matrix
+//////////////////////////////////////////////////////////////////////
+
+#include "tnt/jama_lu.h"
+
+//////////////////////////////////////////////////////////////////////
+// LU decomposition of 3x3 non-symmetric matrix
+//////////////////////////////////////////////////////////////////////
+JAMA::LU<float> inline computeLU3x3(
+               float a[3][3])
+{
+               TNT::Array2D<float> A = TNT::Array2D<float>(3,3, &a[0][0]);
+               JAMA::LU<float> jLU= JAMA::LU<float>(A);
+               return jLU;
+}
+
+//////////////////////////////////////////////////////////////////////
+// LU decomposition of 3x3 non-symmetric matrix
+//////////////////////////////////////////////////////////////////////
+void inline solveLU3x3(
+    JAMA::LU<float>& A,
+    float x[3],
+    float b[3])
+{
+  TNT::Array1D<float> jamaB = TNT::Array1D<float>(3, &b[0]);
+  TNT::Array1D<float> jamaX = A.solve(jamaB);
+
+  x[0] = jamaX[0];
+  x[1] = jamaX[1];
+  x[2] = jamaX[2];
+}
+#endif
diff --git a/intern/smoke/intern/MERSENNETWISTER.h b/intern/smoke/intern/MERSENNETWISTER.h
new file mode 100644 (file)
index 0000000..8ad00d8
--- /dev/null
@@ -0,0 +1,429 @@
+// MersenneTwister.h
+// Mersenne Twister random number generator -- a C++ class MTRand
+// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
+// Richard J. Wagner  v1.0  15 May 2003  rjwagner@writeme.com
+
+// The Mersenne Twister is an algorithm for generating random numbers.  It
+// was designed with consideration of the flaws in various other generators.
+// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
+// are far greater.  The generator is also fast; it avoids multiplication and
+// division, and it benefits from caches and pipelines.  For more information
+// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
+
+// Reference
+// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
+// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
+// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
+
+// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+// Copyright (C) 2000 - 2003, Richard J. Wagner
+// All rights reserved.                          
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//   1. Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//
+//   3. The names of its contributors may not be used to endorse or promote 
+//      products derived from this software without specific prior written 
+//      permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original code included the following notice:
+//
+//     When you use this, send an email to: matumoto@math.keio.ac.jp
+//     with an appropriate reference to your work.
+//
+// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
+// when you write.
+
+#ifndef MERSENNETWISTER_H
+#define MERSENNETWISTER_H
+
+// Not thread safe (unless auto-initialization is avoided and each thread has
+// its own MTRand object)
+
+#include <iostream>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+#include <math.h>
+
+class MTRand {
+// Data
+public:
+       typedef unsigned long uint32;  // unsigned integer type, at least 32 bits
+       
+       enum { N = 624 };       // length of state vector
+       enum { SAVE = N + 1 };  // length of array for save()
+
+protected:
+       enum { M = 397 };  // period parameter
+       
+       uint32 state[N];   // internal state
+       uint32 *pNext;     // next value to get from state
+       int left;          // number of values left before reload needed
+
+
+//Methods
+public:
+       MTRand( const uint32& oneSeed );  // initialize with a simple uint32
+       MTRand( uint32 *const bigSeed, uint32 const seedLength = N );  // or an array
+       MTRand();  // auto-initialize with /dev/urandom or time() and clock()
+       
+       // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
+       // values together, otherwise the generator state can be learned after
+       // reading 624 consecutive values.
+       
+       // Access to 32-bit random numbers
+       double rand();                          // real number in [0,1]
+       double rand( const double& n );         // real number in [0,n]
+       double randExc();                       // real number in [0,1)
+       double randExc( const double& n );      // real number in [0,n)
+       double randDblExc();                    // real number in (0,1)
+       double randDblExc( const double& n );   // real number in (0,n)
+       uint32 randInt();                       // integer in [0,2^32-1]
+       uint32 randInt( const uint32& n );      // integer in [0,n] for n < 2^32
+       double operator()() { return rand(); }  // same as rand()
+       
+       // Access to 53-bit random numbers (capacity of IEEE double precision)
+       double rand53();  // real number in [0,1)
+       
+       // Access to nonuniform random number distributions
+       double randNorm( const double& mean = 0.0, const double& variance = 1.0 );
+       
+       // Re-seeding functions with same behavior as initializers
+       void seed( const uint32 oneSeed );
+       void seed( uint32 *const bigSeed, const uint32 seedLength = N );
+       void seed();
+       
+       // Saving and loading generator state
+       void save( uint32* saveArray ) const;  // to array of size SAVE
+       void load( uint32 *const loadArray );  // from such array
+       friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
+       friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
+
+protected:
+       void initialize( const uint32 oneSeed );
+       void reload();
+       uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
+       uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
+       uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
+       uint32 mixBits( const uint32& u, const uint32& v ) const
+               { return hiBit(u) | loBits(v); }
+       uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
+               { return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); }
+       static uint32 hash( time_t t, clock_t c );
+};
+
+
+inline MTRand::MTRand( const uint32& oneSeed )
+       { seed(oneSeed); }
+
+inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
+       { seed(bigSeed,seedLength); }
+
+inline MTRand::MTRand()
+       { seed(); }
+
+inline double MTRand::rand()
+       { return double(randInt()) * (1.0/4294967295.0); }
+
+inline double MTRand::rand( const double& n )
+       { return rand() * n; }
+
+inline double MTRand::randExc()
+       { return double(randInt()) * (1.0/4294967296.0); }
+
+inline double MTRand::randExc( const double& n )
+       { return randExc() * n; }
+
+inline double MTRand::randDblExc()
+       { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
+
+inline double MTRand::randDblExc( const double& n )
+       { return randDblExc() * n; }
+
+inline double MTRand::rand53()
+{
+       uint32 a = randInt() >> 5, b = randInt() >> 6;
+       return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0);  // by Isaku Wada
+}
+
+inline double MTRand::randNorm( const double& mean, const double& variance )
+{
+       // Return a real number from a normal (Gaussian) distribution with given
+       // mean and variance by Box-Muller method
+       double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
+       double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
+       return mean + r * cos(phi);
+}
+
+inline MTRand::uint32 MTRand::randInt()
+{
+       // Pull a 32-bit integer from the generator state
+       // Every other access function simply transforms the numbers extracted here
+       
+       if( left == 0 ) reload();
+       --left;
+               
+       register uint32 s1;
+       s1 = *pNext++;
+       s1 ^= (s1 >> 11);
+       s1 ^= (s1 <<  7) & 0x9d2c5680UL;
+       s1 ^= (s1 << 15) & 0xefc60000UL;
+       return ( s1 ^ (s1 >> 18) );
+}
+
+inline MTRand::uint32 MTRand::randInt( const uint32& n )
+{
+       // Find which bits are used in n
+       // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
+       uint32 used = n;
+       used |= used >> 1;
+       used |= used >> 2;
+       used |= used >> 4;
+       used |= used >> 8;
+       used |= used >> 16;
+       
+       // Draw numbers until one is found in [0,n]
+       uint32 i;
+       do
+               i = randInt() & used;  // toss unused bits to shorten search
+       while( i > n );
+       return i;
+}
+
+
+inline void MTRand::seed( const uint32 oneSeed )
+{
+       // Seed the generator with a simple uint32
+       initialize(oneSeed);
+       reload();
+}
+
+
+inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
+{
+       // Seed the generator with an array of uint32's
+       // There are 2^19937-1 possible initial states.  This function allows
+       // all of those to be accessed by providing at least 19937 bits (with a
+       // default seed length of N = 624 uint32's).  Any bits above the lower 32
+       // in each element are discarded.
+       // Just call seed() if you want to get array from /dev/urandom
+       initialize(19650218UL);
+       register int i = 1;
+       register uint32 j = 0;
+       register int k = ( N > seedLength ? N : seedLength );
+       for( ; k; --k )
+       {
+               state[i] =
+                       state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
+               state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
+               state[i] &= 0xffffffffUL;
+               ++i;  ++j;
+               if( i >= N ) { state[0] = state[N-1];  i = 1; }
+               if( j >= seedLength ) j = 0;
+       }
+       for( k = N - 1; k; --k )
+       {
+               state[i] =
+                       state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
+               state[i] -= i;
+               state[i] &= 0xffffffffUL;
+               ++i;
+               if( i >= N ) { state[0] = state[N-1];  i = 1; }
+       }
+       state[0] = 0x80000000UL;  // MSB is 1, assuring non-zero initial array
+       reload();
+}
+
+
+inline void MTRand::seed()
+{
+  // seed deterministically to produce reproducible runs
+  seed(123456);
+  
+  /*
+       // Seed the generator with an array from /dev/urandom if available
+       // Otherwise use a hash of time() and clock() values
+       
+       // First try getting an array from /dev/urandom
+       FILE* urandom = fopen( "/dev/urandom", "rb" );
+       if( urandom )
+       {
+               uint32 bigSeed[N];
+               register uint32 *s = bigSeed;
+               register int i = N;
+               register bool success = true;
+               while( success && i-- )
+                       success = fread( s++, sizeof(uint32), 1, urandom );
+               fclose(urandom);
+               if( success ) { seed( bigSeed, N );  return; }
+       }
+       
+       // Was not successful, so use time() and clock() instead
+       seed( hash( time(NULL), clock() ) );
+  */
+}
+
+
+inline void MTRand::initialize( const uint32 seed )
+{
+       // Initialize generator state with seed
+       // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
+       // In previous versions, most significant bits (MSBs) of the seed affect
+       // only MSBs of the state array.  Modified 9 Jan 2002 by Makoto Matsumoto.
+       register uint32 *s = state;
+       register uint32 *r = state;
+       register int i = 1;
+       *s++ = seed & 0xffffffffUL;
+       for( ; i < N; ++i )
+       {
+               *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
+               r++;
+       }
+}
+
+
+inline void MTRand::reload()
+{
+       // Generate N new values in state
+       // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
+       register uint32 *p = state;
+       register int i;
+       for( i = N - M; i--; ++p )
+               *p = twist( p[M], p[0], p[1] );
+       for( i = M; --i; ++p )
+               *p = twist( p[M-N], p[0], p[1] );
+       *p = twist( p[M-N], p[0], state[0] );
+
+       left = N, pNext = state;
+}
+
+
+inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
+{
+       // Get a uint32 from t and c
+       // Better than uint32(x) in case x is floating point in [0,1]
+       // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
+
+       static uint32 differ = 0;  // guarantee time-based seeds will change
+
+       uint32 h1 = 0;
+       unsigned char *p = (unsigned char *) &t;
+       for( size_t i = 0; i < sizeof(t); ++i )
+       {
+               h1 *= UCHAR_MAX + 2U;
+               h1 += p[i];
+       }
+       uint32 h2 = 0;
+       p = (unsigned char *) &c;
+       for( size_t j = 0; j < sizeof(c); ++j )
+       {
+               h2 *= UCHAR_MAX + 2U;
+               h2 += p[j];
+       }
+       return ( h1 + differ++ ) ^ h2;
+}
+
+
+inline void MTRand::save( uint32* saveArray ) const
+{
+       register uint32 *sa = saveArray;
+       register const uint32 *s = state;
+       register int i = N;
+       for( ; i--; *sa++ = *s++ ) {}
+       *sa = left;
+}
+
+
+inline void MTRand::load( uint32 *const loadArray )
+{
+       register uint32 *s = state;
+       register uint32 *la = loadArray;
+       register int i = N;
+       for( ; i--; *s++ = *la++ ) {}
+       left = *la;
+       pNext = &state[N-left];
+}
+
+
+inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
+{
+       register const MTRand::uint32 *s = mtrand.state;
+       register int i = mtrand.N;
+       for( ; i--; os << *s++ << "\t" ) {}
+       return os << mtrand.left;
+}
+
+
+inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
+{
+       register MTRand::uint32 *s = mtrand.state;
+       register int i = mtrand.N;
+       for( ; i--; is >> *s++ ) {}
+       is >> mtrand.left;
+       mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
+       return is;
+}
+
+#endif  // MERSENNETWISTER_H
+
+// Change log:
+//
+// v0.1 - First release on 15 May 2000
+//      - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
+//      - Translated from C to C++
+//      - Made completely ANSI compliant
+//      - Designed convenient interface for initialization, seeding, and
+//        obtaining numbers in default or user-defined ranges
+//      - Added automatic seeding from /dev/urandom or time() and clock()
+//      - Provided functions for saving and loading generator state
+//
+// v0.2 - Fixed bug which reloaded generator one step too late
+//
+// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
+//
+// v0.4 - Removed trailing newline in saved generator format to be consistent
+//        with output format of built-in types
+//
+// v0.5 - Improved portability by replacing static const int's with enum's and
+//        clarifying return values in seed(); suggested by Eric Heimburg
+//      - Removed MAXINT constant; use 0xffffffffUL instead
+//
+// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
+//      - Changed integer [0,n] generator to give better uniformity
+//
+// v0.7 - Fixed operator precedence ambiguity in reload()
+//      - Added access for real numbers in (0,1) and (0,n)
+//
+// v0.8 - Included time.h header to properly support time_t and clock_t
+//
+// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
+//      - Allowed for seeding with arrays of any length
+//      - Added access for real numbers in [0,1) with 53-bit resolution
+//      - Added access for real numbers from normal (Gaussian) distributions
+//      - Increased overall speed by optimizing twist()
+//      - Doubled speed of integer [0,n] generation
+//      - Fixed out-of-range number generation on 64-bit machines
+//      - Improved portability by substituting literal constants for long enum's
+//      - Changed license from GNU LGPL to BSD
+
diff --git a/intern/smoke/intern/Makefile.FFT b/intern/smoke/intern/Makefile.FFT
new file mode 100644 (file)
index 0000000..e45af1d
--- /dev/null
@@ -0,0 +1,22 @@
+# common stuff\r
+LDFLAGS_COMMON = -lfftw3 #-lglut -lglu32 -lopengl32 -lz -lpng\r
+CFLAGS_COMMON =  -c -Wall -I./ #-I/cygdrive/c/lib/glvu/include -D_WIN32\r
+\r
+CC         = g++\r
+CFLAGS     = ${CFLAGS_COMMON} -O3 -Wno-unused\r
+LDFLAGS    = ${LDFLAGS_COMMON}\r
+EXECUTABLE = noiseFFT\r
+\r
+SOURCES    = noiseFFT.cpp\r
+OBJECTS    = $(SOURCES:.cpp=.o)\r
+\r
+all: $(SOURCES) $(EXECUTABLE)\r
+       \r
+$(EXECUTABLE): $(OBJECTS) \r
+       $(CC) $(OBJECTS) $(LDFLAGS) -o $@\r
+\r
+.cpp.o:\r
+       $(CC) $(CFLAGS) $< -o $@\r
+\r
+clean:\r
+       rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)\r
diff --git a/intern/smoke/intern/Makefile.cygwin b/intern/smoke/intern/Makefile.cygwin
new file mode 100644 (file)
index 0000000..c93753a
--- /dev/null
@@ -0,0 +1,23 @@
+CC         = g++\r
+LDFLAGS    = -lz -lpng\r
+CFLAGS     =  -O3 -Wno-unused -c -Wall -I./ -D_WIN32\r
+EXECUTABLE = FLUID_3D\r
+\r
+SOURCES    = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp\r
+OBJECTS    = $(SOURCES:.cpp=.o)\r
+\r
+all: $(SOURCES) $(EXECUTABLE)\r
+       \r
+$(EXECUTABLE): $(OBJECTS) \r
+       $(CC) $(OBJECTS) $(LDFLAGS) -o $@\r
+\r
+.cpp.o:\r
+       $(CC) $(CFLAGS) $< -o $@\r
+\r
+SPHERE.o: SPHERE.h\r
+FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp\r
+FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp\r
+main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp\r
+\r
+clean:\r
+       rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)\r
diff --git a/intern/smoke/intern/Makefile.linux b/intern/smoke/intern/Makefile.linux
new file mode 100644 (file)
index 0000000..8e71af4
--- /dev/null
@@ -0,0 +1,23 @@
+CC         = g++\r
+LDFLAGS    = -lz -lpng -fopenmp -lgomp\r
+CFLAGS     =  -c -Wall -I./ -fopenmp -DPARALLEL=1 -O3 -Wno-unused\r
+EXECUTABLE = FLUID_3D\r
+\r
+SOURCES    = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp\r
+OBJECTS    = $(SOURCES:.cpp=.o)\r
+\r
+all: $(SOURCES) $(EXECUTABLE)\r
+       \r
+$(EXECUTABLE): $(OBJECTS) \r
+       $(CC) $(OBJECTS) $(LDFLAGS) -o $@\r
+\r
+.cpp.o:\r
+       $(CC) $(CFLAGS) $< -o $@\r
+\r
+SPHERE.o: SPHERE.h\r
+FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp\r
+FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp\r
+main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp\r
+\r
+clean:\r
+       rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)\r
diff --git a/intern/smoke/intern/Makefile.mac b/intern/smoke/intern/Makefile.mac
new file mode 100644 (file)
index 0000000..227aaa1
--- /dev/null
@@ -0,0 +1,35 @@
+CC         = g++\r
+\r
+# uncomment the other two OPENMP_... lines, if your gcc supports OpenMP\r
+#OPENMP_FLAGS = -fopenmp   -DPARALLEL=1 -I/opt/gcc-4.3/usr/local/include\r
+#OPENMPLD_FLAGS = -fopenmp  -lgomp -I/opt/gcc-4.3/usr/local/lib\r
+OPENMP_FLAGS = \r
+OPENMPLD_FLAGS = \r
+\r
+# assumes MacPorts libpng installation\r
+PNG_INCLUDE =  -I/opt/local/include  \r
+PNG_LIBS =  -I/opt/local/lib  \r
+\r
+LDFLAGS    =  $(PNG_LIBS)-lz -lpng $(OPENMPLD_FLAGS)\r
+CFLAGS     =  -c -Wall -I./ $(PNG_INCLUDE) $(OPENMP_FLAGS) -O3 -Wno-unused\r
+EXECUTABLE = FLUID_3D\r
+\r
+SOURCES    = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp\r
+OBJECTS    = $(SOURCES:.cpp=.o)\r
+\r
+all: $(SOURCES) $(EXECUTABLE)\r
+       \r
+$(EXECUTABLE): $(OBJECTS) \r
+       $(CC) $(OBJECTS) $(LDFLAGS) -o $@\r
+\r
+.cpp.o:\r
+       $(CC) $(CFLAGS) $< -o $@\r
+\r
+SPHERE.o: SPHERE.h\r
+FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp\r
+FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp\r
+main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp\r
+\r
+clean:\r
+       rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)\r
+\r
diff --git a/intern/smoke/intern/OBSTACLE.h b/intern/smoke/intern/OBSTACLE.h
new file mode 100644 (file)
index 0000000..54e824d
--- /dev/null
@@ -0,0 +1,41 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// OBSTACLE.h: interface for the OBSTACLE class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef OBSTACLE_H
+#define OBSTACLE_H
+
+enum OBSTACLE_FLAGS {
+       EMPTY = 0, 
+       MARCHED = 2, 
+       RETIRED = 4 
+};  
+
+class OBSTACLE  
+{
+public:
+       OBSTACLE() {};
+       virtual ~OBSTACLE() {};
+
+  virtual bool inside(float x, float y, float z) = 0;
+};
+
+#endif
diff --git a/intern/smoke/intern/SPHERE.cpp b/intern/smoke/intern/SPHERE.cpp
new file mode 100644 (file)
index 0000000..4bb18fb
--- /dev/null
@@ -0,0 +1,50 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// SPHERE.cpp: implementation of the SPHERE class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "SPHERE.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+SPHERE::SPHERE(float x, float y, float z, float radius) :
+  _radius(radius)
+{
+  _center[0] = x;
+  _center[1] = y;
+  _center[2] = z;
+}
+
+SPHERE::~SPHERE()
+{
+
+}
+
+bool SPHERE::inside(float x, float y, float z)
+{
+  float translate[] = {x - _center[0], y - _center[1], z - _center[2]};
+  float magnitude = translate[0] * translate[0] + 
+                    translate[1] * translate[1] + 
+                    translate[2] * translate[2];
+
+  return (magnitude < _radius * _radius) ? true : false;
+}
diff --git a/intern/smoke/intern/SPHERE.h b/intern/smoke/intern/SPHERE.h
new file mode 100644 (file)
index 0000000..13bd6e9
--- /dev/null
@@ -0,0 +1,41 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// SPHERE.h: interface for the SPHERE class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef SPHERE_H
+#define SPHERE_H
+
+#include "OBSTACLE.h"
+
+class SPHERE : public OBSTACLE  
+{
+public:
+       SPHERE(float x, float y, float z, float radius);
+       virtual ~SPHERE();
+
+  bool inside(float x, float y, float z);
+
+private:
+  float _center[3];
+  float _radius;
+};
+
+#endif
diff --git a/intern/smoke/intern/VEC3.h b/intern/smoke/intern/VEC3.h
new file mode 100644 (file)
index 0000000..ae159e1
--- /dev/null
@@ -0,0 +1,981 @@
+/******************************************************************************
+ * Copyright 2007 Nils Thuerey
+ * Basic vector class 
+ *****************************************************************************/
+#ifndef BASICVECTOR_H
+#define BASICVECTOR_H
+
+#include <math.h>
+#include <stdlib.h>
+#include <iostream>
+#include <sstream>
+
+// use which fp-precision? 1=float, 2=double
+#ifndef FLOATINGPOINT_PRECISION
+#if DDF_DEBUG==1
+#define FLOATINGPOINT_PRECISION 2
+#else // DDF_DEBUG==1
+#define FLOATINGPOINT_PRECISION 1
+#endif // DDF_DEBUG==1
+#endif
+
+// VECTOR_EPSILON is the minimal vector length
+// In order to be able to discriminate floating point values near zero, and
+// to be sure not to fail a comparison because of roundoff errors, use this
+// value as a threshold.  
+
+#if FLOATINGPOINT_PRECISION==1
+typedef float Real;
+#define FP_REAL_MAX __FLT_MAX__
+#define VECTOR_EPSILON (1e-5f)
+#else
+typedef double Real;
+#define FP_REAL_MAX __DBL_MAX__
+#define VECTOR_EPSILON (1e-10)
+#endif
+
+
+// hardcoded limits for now...
+// for e.g. MSVC compiler...
+// some of these defines can be needed
+// for linux systems as well (e.g. FLT_MAX)
+#ifndef __FLT_MAX__
+#      ifdef FLT_MAX  // try to use it instead
+#              define __FLT_MAX__ FLT_MAX
+#      else // FLT_MAX
+#              define __FLT_MAX__ 3.402823466e+38f
+#      endif // FLT_MAX
+#endif // __FLT_MAX__
+#ifndef __DBL_MAX__
+#      ifdef DBL_MAX // try to use it instead
+#              define __DBL_MAX__ DBL_MAX
+#      else // DBL_MAX
+#              define __DBL_MAX__ 1.7976931348623158e+308
+#      endif // DBL_MAX
+#endif // __DBL_MAX__
+
+#ifndef FLT_MAX
+#define FLT_MAX __FLT_MAX__
+#endif
+
+#ifndef DBL_MAX
+#define DBL_MAX __DBL_MAX__
+#endif
+
+#ifndef M_PI
+#      define M_PI 3.1415926536
+#      define M_E  2.7182818284
+#endif
+
+
+
+namespace BasicVector {
+
+
+// basic inlined vector class
+template<class Scalar>
+class Vector3Dim
+{
+public:
+  // Constructor
+  inline Vector3Dim();
+  // Copy-Constructor
+  inline Vector3Dim(const Vector3Dim<Scalar> &v );
+  inline Vector3Dim(const float *);
+  inline Vector3Dim(const double *);
+  // construct a vector from one Scalar
+  inline Vector3Dim(Scalar);
+  // construct a vector from three Scalars
+  inline Vector3Dim(Scalar, Scalar, Scalar);
+
+       // get address of array for OpenGL
+       Scalar *getAddress() { return value; }
+
+  // Assignment operator
+  inline const Vector3Dim<Scalar>& operator=  (const Vector3Dim<Scalar>& v);
+  // Assignment operator
+  inline const Vector3Dim<Scalar>& operator=  (Scalar s);
+  // Assign and add operator
+  inline const Vector3Dim<Scalar>& operator+= (const Vector3Dim<Scalar>& v);
+  // Assign and add operator
+  inline const Vector3Dim<Scalar>& operator+= (Scalar s);
+  // Assign and sub operator
+  inline const Vector3Dim<Scalar>& operator-= (const Vector3Dim<Scalar>& v);
+  // Assign and sub operator
+  inline const Vector3Dim<Scalar>& operator-= (Scalar s);
+  // Assign and mult operator
+  inline const Vector3Dim<Scalar>& operator*= (const Vector3Dim<Scalar>& v);
+  // Assign and mult operator
+  inline const Vector3Dim<Scalar>& operator*= (Scalar s);
+  // Assign and div operator
+  inline const Vector3Dim<Scalar>& operator/= (const Vector3Dim<Scalar>& v);
+  // Assign and div operator
+  inline const Vector3Dim<Scalar>& operator/= (Scalar s);
+
+
+  // unary operator
+  inline Vector3Dim<Scalar> operator- () const;
+
+  // binary operator add
+  inline Vector3Dim<Scalar> operator+ (const Vector3Dim<Scalar>&) const;
+  // binary operator add
+  inline Vector3Dim<Scalar> operator+ (Scalar) const;
+  // binary operator sub
+  inline Vector3Dim<Scalar> operator- (const Vector3Dim<Scalar>&) const;
+  // binary operator sub
+  inline Vector3Dim<Scalar> operator- (Scalar) const;
+  // binary operator mult
+  inline Vector3Dim<Scalar> operator* (const Vector3Dim<Scalar>&) const;
+  // binary operator mult
+  inline Vector3Dim<Scalar> operator* (Scalar) const;
+  // binary operator div
+  inline Vector3Dim<Scalar> operator/ (const Vector3Dim<Scalar>&) const;
+  // binary operator div
+  inline Vector3Dim<Scalar> operator/ (Scalar) const;
+
+  // Projection normal to a vector
+  inline Vector3Dim<Scalar>      getOrthogonalntlVector3Dim() const;
+  // Project into a plane
+  inline const Vector3Dim<Scalar>& projectNormalTo(const Vector3Dim<Scalar> &v);
+  
+  // minimize
+  inline const Vector3Dim<Scalar> &minimize(const Vector3Dim<Scalar> &);
+  // maximize
+  inline const Vector3Dim<Scalar> &maximize(const Vector3Dim<Scalar> &);
+  
+  // access operator
+  inline Scalar& operator[](unsigned int i);
+  // access operator
+  inline const Scalar& operator[](unsigned int i) const;
+
+       //! actual values
+       union {
+               struct {
+               Scalar value[3];  
+               };
+               struct {
+               Scalar x;
+               Scalar y;
+               Scalar z;
+               };
+               struct {
+               Scalar X;
+               Scalar Y;
+               Scalar Z;
+               };
+       };
+protected:
+  
+};
+
+
+
+
+
+//------------------------------------------------------------------------------
+// VECTOR inline FUNCTIONS
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+  Constructor.
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>::Vector3Dim( void )
+{
+  value[0] = value[1] = value[2] = 0;
+}
+
+
+
+/*************************************************************************
+  Copy-Constructor.
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>::Vector3Dim( const Vector3Dim<Scalar> &v )
+{
+  value[0] = v.value[0];
+  value[1] = v.value[1];
+  value[2] = v.value[2];
+}
+template<class Scalar>
+inline Vector3Dim<Scalar>::Vector3Dim( const float *fvalue)
+{
+  value[0] = (Scalar)fvalue[0];
+  value[1] = (Scalar)fvalue[1];
+  value[2] = (Scalar)fvalue[2];
+}
+template<class Scalar>
+inline Vector3Dim<Scalar>::Vector3Dim( const double *fvalue)
+{
+  value[0] = (Scalar)fvalue[0];
+  value[1] = (Scalar)fvalue[1];
+  value[2] = (Scalar)fvalue[2];
+}
+
+
+
+/*************************************************************************
+  Constructor for a vector from a single Scalar. All components of
+  the vector get the same value.
+  \param s The value to set
+  \return The new vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>::Vector3Dim(Scalar s )
+{
+  value[0]= s;
+  value[1]= s;
+  value[2]= s;
+}
+
+
+/*************************************************************************
+  Constructor for a vector from three Scalars.
+  \param s1 The value for the first vector component
+  \param s2 The value for the second vector component
+  \param s3 The value for the third vector component
+  \return The new vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>::Vector3Dim(Scalar s1, Scalar s2, Scalar s3)
+{
+  value[0]= s1;
+  value[1]= s2;
+  value[2]= s3;
+}
+
+
+
+/*************************************************************************
+  Copy a Vector3Dim componentwise.
+  \param v vector with values to be copied
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator=( const Vector3Dim<Scalar> &v )
+{
+  value[0] = v.value[0];
+  value[1] = v.value[1];
+  value[2] = v.value[2];  
+  return *this;
+}
+
+
+/*************************************************************************
+  Copy a Scalar to each component.
+  \param s The value to copy
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator=(Scalar s)
+{
+  value[0] = s;
+  value[1] = s;
+  value[2] = s;  
+  return *this;
+}
+
+
+/*************************************************************************
+  Add another Vector3Dim componentwise.
+  \param v vector with values to be added
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator+=( const Vector3Dim<Scalar> &v )
+{
+  value[0] += v.value[0];
+  value[1] += v.value[1];
+  value[2] += v.value[2];  
+  return *this;
+}
+
+
+/*************************************************************************
+  Add a Scalar value to each component.
+  \param s Value to add
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator+=(Scalar s)
+{
+  value[0] += s;
+  value[1] += s;
+  value[2] += s;  
+  return *this;
+}
+
+
+/*************************************************************************
+  Subtract another vector componentwise.
+  \param v vector of values to subtract
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator-=( const Vector3Dim<Scalar> &v )
+{
+  value[0] -= v.value[0];
+  value[1] -= v.value[1];
+  value[2] -= v.value[2];  
+  return *this;
+}
+
+
+/*************************************************************************
+  Subtract a Scalar value from each component.
+  \param s Value to subtract
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator-=(Scalar s)
+{
+  value[0]-= s;
+  value[1]-= s;
+  value[2]-= s;  
+  return *this;
+}
+
+
+/*************************************************************************
+  Multiply with another vector componentwise.
+  \param v vector of values to multiply with
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator*=( const Vector3Dim<Scalar> &v )
+{
+  value[0] *= v.value[0];
+  value[1] *= v.value[1];
+  value[2] *= v.value[2];  
+  return *this;
+}
+
+
+/*************************************************************************
+  Multiply each component with a Scalar value.
+  \param s Value to multiply with
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator*=(Scalar s)
+{
+  value[0] *= s;
+  value[1] *= s;
+  value[2] *= s;  
+  return *this;
+}
+
+
+/*************************************************************************
+  Divide by another Vector3Dim componentwise.
+  \param v vector of values to divide by
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator/=( const Vector3Dim<Scalar> &v )
+{
+  value[0] /= v.value[0];
+  value[1] /= v.value[1];
+  value[2] /= v.value[2];  
+  return *this;
+}
+
+
+/*************************************************************************
+  Divide each component by a Scalar value.
+  \param s Value to divide by
+  \return Reference to self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::operator/=(Scalar s)
+{
+  value[0] /= s;
+  value[1] /= s;
+  value[2] /= s;
+  return *this;
+}
+
+
+//------------------------------------------------------------------------------
+// unary operators
+//------------------------------------------------------------------------------
+
+
+/*************************************************************************
+  Build componentwise the negative this vector.
+  \return The new (negative) vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator-() const
+{
+  return Vector3Dim<Scalar>(-value[0], -value[1], -value[2]);
+}
+
+
+
+//------------------------------------------------------------------------------
+// binary operators
+//------------------------------------------------------------------------------
+
+
+/*************************************************************************
+  Build a vector with another vector added componentwise.
+  \param v The second vector to add
+  \return The sum vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator+( const Vector3Dim<Scalar> &v ) const
+{
+  return Vector3Dim<Scalar>(value[0]+v.value[0],
+                       value[1]+v.value[1],
+                       value[2]+v.value[2]);
+}
+
+
+/*************************************************************************
+  Build a vector with a Scalar value added to each component.
+  \param s The Scalar value to add
+  \return The sum vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator+(Scalar s) const
+{
+  return Vector3Dim<Scalar>(value[0]+s,
+                       value[1]+s,
+                       value[2]+s);
+}
+
+
+/*************************************************************************
+  Build a vector with another vector subtracted componentwise.
+  \param v The second vector to subtract
+  \return The difference vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator-( const Vector3Dim<Scalar> &v ) const
+{
+  return Vector3Dim<Scalar>(value[0]-v.value[0],
+                       value[1]-v.value[1],
+                       value[2]-v.value[2]);
+}
+
+
+/*************************************************************************
+  Build a vector with a Scalar value subtracted componentwise.
+  \param s The Scalar value to subtract
+  \return The difference vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator-(Scalar s ) const
+{
+  return Vector3Dim<Scalar>(value[0]-s,
+                       value[1]-s,
+                       value[2]-s);
+}
+
+
+
+/*************************************************************************
+  Build a vector with another vector multiplied by componentwise.
+  \param v The second vector to muliply with
+  \return The product vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator*( const Vector3Dim<Scalar>& v) const
+{
+  return Vector3Dim<Scalar>(value[0]*v.value[0],
+                       value[1]*v.value[1],
+                       value[2]*v.value[2]);
+}
+
+
+/*************************************************************************
+  Build a Vector3Dim with a Scalar value multiplied to each component.
+  \param s The Scalar value to multiply with
+  \return The product vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator*(Scalar s) const
+{
+  return Vector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s);
+}
+
+
+/*************************************************************************
+  Build a vector divided componentwise by another vector.
+  \param v The second vector to divide by
+  \return The ratio vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator/(const Vector3Dim<Scalar>& v) const
+{
+  return Vector3Dim<Scalar>(value[0]/v.value[0],
+                       value[1]/v.value[1],
+                       value[2]/v.value[2]);
+}
+
+
+
+/*************************************************************************
+  Build a vector divided componentwise by a Scalar value.
+  \param s The Scalar value to divide by
+  \return The ratio vector
+  */
+template<class Scalar>
+inline Vector3Dim<Scalar>
+Vector3Dim<Scalar>::operator/(Scalar s) const
+{
+  return Vector3Dim<Scalar>(value[0]/s,
+                       value[1]/s,
+                       value[2]/s);
+}
+
+
+
+
+
+/*************************************************************************
+  Get a particular component of the vector.
+  \param i Number of Scalar to get
+  \return Reference to the component
+  */
+template<class Scalar>
+inline Scalar&
+Vector3Dim<Scalar>::operator[]( unsigned int i )
+{
+  return value[i];
+}
+
+
+/*************************************************************************
+  Get a particular component of a constant vector.
+  \param i Number of Scalar to get
+  \return Reference to the component
+  */
+template<class Scalar>
+inline const Scalar&
+Vector3Dim<Scalar>::operator[]( unsigned int i ) const
+{
+  return value[i];
+}
+
+
+
+//------------------------------------------------------------------------------
+// BLITZ compatibility functions
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+  Compute the scalar product with another vector.
+  \param v The second vector to work with
+  \return The value of the scalar product
+  */
+template<class Scalar>
+inline Scalar dot(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v )
+{
+  //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2];
+  return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2]));
+}
+
+
+/*************************************************************************
+  Calculate the cross product of this and another vector
+ */
+template<class Scalar>
+inline Vector3Dim<Scalar> cross(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v)
+{
+  Vector3Dim<Scalar> cp( 
+                       ((t[1]*v[2]) - (t[2]*v[1])),
+                 ((t[2]*v[0]) - (t[0]*v[2])),
+                 ((t[0]*v[1]) - (t[1]*v[0])) );
+  return cp;
+}
+
+
+
+
+/*************************************************************************
+  Compute a vector that is orthonormal to self. Nothing else can be assumed
+  for the direction of the new vector.
+  \return The orthonormal vector
+  */
+template<class Scalar>
+Vector3Dim<Scalar>
+Vector3Dim<Scalar>::getOrthogonalntlVector3Dim() const
+{
+  // Determine the  component with max. absolute value
+  int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1;
+  max= (fabs(value[max]) > fabs(value[2])) ? max : 2;
+
+  /*************************************************************************
+    Choose another axis than the one with max. component and project
+    orthogonal to self
+    */
+  Vector3Dim<Scalar> vec(0.0);
+  vec[(max+1)%3]= 1;
+  vec.normalize();
+  vec.projectNormalTo(this->getNormalized());
+  return vec;
+}
+
+
+/*************************************************************************
+  Projects the vector into a plane normal to the given vector, which must
+  have unit length. Self is modified.
+  \param v The plane normal
+  \return The projected vector
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar>&
+Vector3Dim<Scalar>::projectNormalTo(const Vector3Dim<Scalar> &v)
+{
+  Scalar sprod = dot(*this,v);
+  value[0]= value[0] - v.value[0] * sprod;
+  value[1]= value[1] - v.value[1] * sprod;
+  value[2]= value[2] - v.value[2] * sprod;  
+  return *this;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Other helper functions
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+  Minimize the vector, i.e. set each entry of the vector to the minimum
+  of both values.
+  \param pnt The second vector to compare with
+  \return Reference to the modified self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar> &
+Vector3Dim<Scalar>::minimize(const Vector3Dim<Scalar> &pnt)
+{
+  for (unsigned int i = 0; i < 3; i++)
+    value[i] = MIN(value[i],pnt[i]);
+  return *this;
+}
+
+
+
+/*************************************************************************
+  Maximize the vector, i.e. set each entry of the vector to the maximum
+  of both values.
+  \param pnt The second vector to compare with
+  \return Reference to the modified self
+  */
+template<class Scalar>
+inline const Vector3Dim<Scalar> &
+Vector3Dim<Scalar>::maximize(const Vector3Dim<Scalar> &pnt)
+{
+  for (unsigned int i = 0; i < 3; i++)
+    value[i] = MAX(value[i],pnt[i]);
+  return *this;
+}
+
+
+
+
+
+
+/************************************************************************/
+// HELPER FUNCTIONS, independent of implementation
+/************************************************************************/
+
+#define VECTOR_TYPE Vector3Dim<Scalar>
+
+
+/*************************************************************************
+  Compute the length (norm) of the vector.
+  \return The value of the norm
+  */
+template<class Scalar>
+inline Scalar norm( const VECTOR_TYPE &v)
+{
+  Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+  return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l);
+}
+
+// for e.g. min max operator
+inline Real normHelper(const Vector3Dim<Real> &v) {
+       return norm(v);
+}      
+inline Real normHelper(const Real &v) {
+       return (0. < v) ? v : -v ; 
+}      
+inline Real normHelper(const int &v) {
+       return (0 < v) ? (Real)(v) : (Real)(-v) ; 
+}      
+
+
+/*************************************************************************
+  Same as getNorm but doesnt sqrt  
+  */
+template<class Scalar>
+inline Scalar normNoSqrt( const VECTOR_TYPE &v)
+{
+  return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+}
+
+
+/*************************************************************************
+  Compute a normalized vector based on this vector.
+  \return The new normalized vector
+  */
+template<class Scalar>
+inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v)
+{
+  Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+  if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON)
+    return v; /* normalized "enough"... */
+  else if (l > VECTOR_EPSILON*VECTOR_EPSILON)
+  {
+    Scalar fac = 1./sqrt(l);
+    return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac);
+  }
+  else
+    return VECTOR_TYPE((Scalar)0);
+}
+
+
+/*************************************************************************
+  Compute the norm of the vector and normalize it.
+  \return The value of the norm
+  */
+template<class Scalar>
+inline Scalar normalize( VECTOR_TYPE &v) 
+{
+  Scalar norm;
+  Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];  
+  if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) {
+    norm = 1.;
+       } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) {
+    norm = sqrt(l);
+    Scalar fac = 1./norm;
+    v[0] *= fac;
+    v[1] *= fac;
+    v[2] *= fac; 
+       } else {
+    v[0]= v[1]= v[2]= 0;
+    norm = 0.;
+  }
+  return (Scalar)norm;
+}
+
+
+/*************************************************************************
+  Compute a vector, that is self (as an incoming
+  vector) reflected at a surface with a distinct normal vector. Note
+  that the normal is reversed, if the scalar product with it is positive.
+  \param n The surface normal
+  \return The new reflected vector
+  */
+template<class Scalar>
+inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n) 
+{
+  VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n;
+  return ( t - nn * (2.0 * dot(nn, t)) );
+}
+
+
+
+/*************************************************************************
+ * My own refraction calculation
+ * Taken from Glassner's book, section 5.2 (Heckberts method)
+ */
+template<class Scalar>
+inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl) 
+{
+       Scalar eta = nair / nt;
+       Scalar n = -dot(t, normal);
+       Scalar tt = 1.0 + eta*eta* (n*n-1.0);
+       if(tt<0.0) {
+               // we have total reflection!
+               refRefl = 1;
+       } else {
+               // normal reflection
+               tt = eta*n - sqrt(tt);
+               return( t*eta + normal*tt );
+       }
+       return t;
+}
+
+
+/*************************************************************************
+  Test two ntlVector3Dims for equality based on the equality of their
+  values within a small threshold.
+  \param c The second vector to compare
+  \return TRUE if both are equal
+  \sa getEpsilon()
+  */
+template<class Scalar>
+inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c)
+{
+  return (ABS(v[0]-c[0]) + 
+         ABS(v[1]-c[1]) + 
+         ABS(v[2]-c[2]) < VECTOR_EPSILON);
+}
+
+
+/*************************************************************************
+ * Assume this vector is an RGB color, and convert it to HSV
+ */
+template<class Scalar>
+inline void rgbToHsv( VECTOR_TYPE &V )
+{
+       Scalar h=0,s=0,v=0;
+       Scalar maxrgb, minrgb, delta;
+       // convert to hsv...
+       maxrgb = V[0];
+       int maxindex = 1;
+       if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; }
+       if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; }
+       minrgb = V[0];
+       if(V[2] < minrgb) minrgb = V[2];
+       if(V[1] < minrgb) minrgb = V[1];
+
+       v = maxrgb;
+       delta = maxrgb-minrgb;
+
+       if(maxrgb > 0) s = delta/maxrgb;
+       else s = 0;
+
+       h = 0;
+       if(s > 0) {
+               if(maxindex == 1) {
+                       h = ((V[1]-V[2])/delta)  + 0.0; }
+               if(maxindex == 2) {
+                       h = ((V[2]-V[0])/delta)  + 2.0; }
+               if(maxindex == 3) {
+                       h = ((V[0]-V[1])/delta)  + 4.0; }
+               h *= 60.0;
+               if(h < 0.0) h += 360.0;
+       }
+
+       V[0] = h;
+       V[1] = s;
+       V[2] = v;
+}
+
+/*************************************************************************
+ * Assume this vector is HSV and convert to RGB
+ */
+template<class Scalar>
+inline void hsvToRgb( VECTOR_TYPE &V )
+{
+       Scalar h = V[0], s = V[1], v = V[2];
+       Scalar r=0,g=0,b=0;
+       Scalar p,q,t, fracth;
+       int floorh;
+       // ...and back to rgb
+       if(s == 0) {
+               r = g = b = v; }
+       else {
+               h /= 60.0;
+               floorh = (int)h;
+               fracth = h - floorh;
+               p = v * (1.0 - s);
+               q = v * (1.0 - (s * fracth));
+               t = v * (1.0 - (s * (1.0 - fracth)));
+               switch (floorh) {
+               case 0: r = v; g = t; b = p; break;
+               case 1: r = q; g = v; b = p; break;
+               case 2: r = p; g = v; b = t; break;
+               case 3: r = p; g = q; b = v; break;
+               case 4: r = t; g = p; b = v; break;
+               case 5: r = v; g = p; b = q; break;
+               }
+       }
+
+       V[0] = r;
+       V[1] = g;
+       V[2] = b;
+}
+
+//------------------------------------------------------------------------------
+// STREAM FUNCTIONS
+//------------------------------------------------------------------------------
+
+
+
+//! global string for formatting vector output in utilities.cpp
+//extern const char *globVecFormatStr;
+static const char *globVecFormatStr = "[%6.4f,%6.4f,%6.4f]";
+
+/*************************************************************************
+  Outputs the object in human readable form using the format
+  [x,y,z]
+  */
+template<class Scalar>
+std::ostream&
+operator<<( std::ostream& os, const BasicVector::Vector3Dim<Scalar>& i )
+{
+       char buf[256];
+#if _WIN32
+  sprintf(buf,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]);
+#else
+  snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]);
+#endif
+       os << std::string(buf); 
+  return os;
+}
+
+
+/*************************************************************************
+  Reads the contents of the object from a stream using the same format
+  as the output operator.
+  */
+template<class Scalar>
+std::istream&
+operator>>( std::istream& is, BasicVector::Vector3Dim<Scalar>& i )
+{
+  char c;
+  char dummy[3];
+  is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
+  return is;
+}
+
+
+/**************************************************************************/
+// typedefs!
+/**************************************************************************/
+
+/* get minimal vector length value that can be discriminated.  */
+inline Real getVecEpsilon() { return (Real)VECTOR_EPSILON; }
+
+// a 3D integer vector
+typedef Vector3Dim<int> Vec3Int; 
+
+// a 3D vector 
+typedef Vector3Dim<Real> Vec3; 
+
+
+}; // namespace 
+
+
+#endif /* BASICVECTOR_H */
diff --git a/intern/smoke/intern/WAVELET_NOISE.h b/intern/smoke/intern/WAVELET_NOISE.h
new file mode 100644 (file)
index 0000000..72469c2
--- /dev/null
@@ -0,0 +1,456 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+//////////////////////////////////////////////////////////////////////////////////////////
+// Wavelet noise functions
+//
+// This code is based on the C code provided in the appendices of:
+//
+// @article{1073264,
+//  author = {Robert L. Cook and Tony DeRose},
+//  title = {Wavelet noise},
+//  journal = {ACM Trans. Graph.},
+//  volume = {24},
+//  number = {3},
+//  year = {2005},
+//  issn = {0730-0301},
+//  pages = {803--811},
+//  doi = {http://doi.acm.org/10.1145/1073204.1073264},
+//  publisher = {ACM},
+//  address = {New York, NY, USA},
+//  }
+//
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef WAVELET_NOISE_H
+#define WAVELET_NOISE_H
+
+#include <MERSENNETWISTER.h>
+
+#define NOISE_TILE_SIZE 128
+static const int noiseTileSize = NOISE_TILE_SIZE;
+
+// warning - noiseTileSize has to be 128^3!
+#define modFast128(x) ((x) & 127)
+#define modFast64(x)  ((x) & 63)
+#define DOWNCOEFFS 0.000334f,-0.001528f, 0.000410f, 0.003545f,-0.000938f,-0.008233f, 0.002172f, 0.019120f, \
+                  -0.005040f,-0.044412f, 0.011655f, 0.103311f,-0.025936f,-0.243780f, 0.033979f, 0.655340f, \
+                   0.655340f, 0.033979f,-0.243780f,-0.025936f, 0.103311f, 0.011655f,-0.044412f,-0.005040f, \
+                   0.019120f, 0.002172f,-0.008233f,-0.000938f, 0.003546f, 0.000410f,-0.001528f, 0.000334f
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Wavelet downsampling -- periodic boundary conditions
+//////////////////////////////////////////////////////////////////////////////////////////
+static void downsampleX(float *from, float *to, int n){
+  // if these values are not local incorrect results are generated
+  float downCoeffs[32] = { DOWNCOEFFS };
+       const float *a = &downCoeffs[16];
+       for (int i = 0; i < n / 2; i++) {
+               to[i] = 0;
+               for (int k = 2 * i - 16; k <= 2 * i + 16; k++)
+                       to[i] += a[k - 2 * i] * from[modFast128(k)];
+       }
+}
+static void downsampleY(float *from, float *to, int n){
+  // if these values are not local incorrect results are generated
+  float downCoeffs[32] = { DOWNCOEFFS };
+       const float *a = &downCoeffs[16];
+       for (int i = 0; i < n / 2; i++) {
+               to[i * n] = 0;
+               for (int k = 2 * i - 16; k <= 2 * i + 16; k++)
+                       to[i * n] += a[k - 2 * i] * from[modFast128(k) * n];
+       }
+}
+static void downsampleZ(float *from, float *to, int n){
+  // if these values are not local incorrect results are generated
+  float downCoeffs[32] = { DOWNCOEFFS };
+       const float *a = &downCoeffs[16];
+       for (int i = 0; i < n / 2; i++) {
+               to[i * n * n] = 0;
+               for (int k = 2 * i - 16; k <= 2 * i + 16; k++)
+                       to[i * n * n] += a[k - 2 * i] * from[modFast128(k) * n * n];
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Wavelet downsampling -- Neumann boundary conditions
+//////////////////////////////////////////////////////////////////////////////////////////
+static void downsampleNeumann(const float *from, float *to, int n, int stride)
+{
+  // if these values are not local incorrect results are generated
+  float downCoeffs[32] = { DOWNCOEFFS };
+  static const float *const aCoCenter= &downCoeffs[16];
+       for (int i = 0; i < n / 2; i++) {
+               to[i * stride] = 0;
+               for (int k = 2 * i - 16; k < 2 * i + 16; k++) { 
+                       // handle boundary
+                       float fromval; 
+                       if (k < 0) {
+                               fromval = from[0];
+                       } else if(k > n - 1) {
+                               fromval = from[(n - 1) * stride];
+                       } else {
+                               fromval = from[k * stride]; 
+                       } 
+                       to[i * stride] += aCoCenter[k - 2 * i] * fromval; 
+               }
+       }
+}
+static void downsampleXNeumann(float* to, const float* from, int sx,int sy, int sz) {
+       for (int iy = 0; iy < sy; iy++) 
+               for (int iz = 0; iz < sz; iz++) {
+                       const int i = iy * sx + iz*sx*sy;
+                       downsampleNeumann(&from[i], &to[i], sx, 1);
+               }
+}
+static void downsampleYNeumann(float* to, const float* from, int sx,int sy, int sz) {
+       for (int ix = 0; ix < sx; ix++) 
+               for (int iz = 0; iz < sz; iz++) {
+                       const int i = ix + iz*sx*sy;
+                       downsampleNeumann(&from[i], &to[i], sy, sx);
+    }
+}
+static void downsampleZNeumann(float* to, const float* from, int sx,int sy, int sz) {
+       for (int ix = 0; ix < sx; ix++) 
+               for (int iy = 0; iy < sy; iy++) {
+                       const int i = ix + iy*sx;
+                       downsampleNeumann(&from[i], &to[i], sz, sx*sy);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Wavelet upsampling - periodic boundary conditions
+//////////////////////////////////////////////////////////////////////////////////////////
+static float _upCoeffs[4] = {0.25f, 0.75f, 0.75f, 0.25f};
+static void upsampleX(float *from, float *to, int n) {
+       const float *p = &_upCoeffs[2];
+
+       for (int i = 0; i < n; i++) {
+               to[i] = 0;
+               for (int k = i / 2; k <= i / 2 + 1; k++)
+                       to[i] += p[i - 2 * k] * from[modFast64(k)];
+       }
+}
+static void upsampleY(float *from, float *to, int n) {
+       const float *p = &_upCoeffs[2];
+
+       for (int i = 0; i < n; i++) {
+               to[i * n] = 0;
+               for (int k = i / 2; k <= i / 2 + 1; k++)
+                       to[i * n] += p[i - 2 * k] * from[modFast64(k) * n];
+       }
+}
+static void upsampleZ(float *from, float *to, int n) {
+       const float *p = &_upCoeffs[2];
+
+       for (int i = 0; i < n; i++) {
+               to[i * n * n] = 0;
+               for (int k = i / 2; k <= i / 2 + 1; k++)
+                       to[i * n * n] += p[i - 2 * k] * from[modFast64(k) * n * n];
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Wavelet upsampling - Neumann boundary conditions
+//////////////////////////////////////////////////////////////////////////////////////////
+static void upsampleNeumann(const float *from, float *to, int n, int stride) {
+  static const float *const pCoCenter = &_upCoeffs[2];
+       for (int i = 0; i < n; i++) {
+               to[i * stride] = 0;
+               for (int k = i / 2; k <= i / 2 + 1; k++) {
+                       float fromval;
+                       if(k>n/2) {
+                               fromval = from[(n/2) * stride];
+                       } else {
+                               fromval = from[k * stride]; 
+                       }  
+                       to[i * stride] += pCoCenter[i - 2 * k] * fromval; 
+               }
+       }
+}
+static void upsampleXNeumann(float* to, const float* from, int sx, int sy, int sz) {
+       for (int iy = 0; iy < sy; iy++) 
+               for (int iz = 0; iz < sz; iz++) {
+                       const int i = iy * sx + iz*sx*sy;
+                       upsampleNeumann(&from[i], &to[i], sx, 1);
+               }
+}
+static void upsampleYNeumann(float* to, const float* from, int sx, int sy, int sz) {
+       for (int ix = 0; ix < sx; ix++) 
+               for (int iz = 0; iz < sz; iz++) {
+                       const int i = ix + iz*sx*sy;
+                       upsampleNeumann(&from[i], &to[i], sy, sx);
+               }
+}
+static void upsampleZNeumann(float* to, const float* from, int sx, int sy, int sz) {
+       for (int ix = 0; ix < sx; ix++) 
+               for (int iy = 0; iy < sy; iy++) {
+                       const int i = ix + iy*sx;
+                       upsampleNeumann(&from[i], &to[i], sz, sx*sy);
+               }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// load in an existing noise tile
+//////////////////////////////////////////////////////////////////////////////////////////
+static bool loadTile(float* const noiseTileData, std::string filename)
+{
+       FILE* file;
+       file = fopen(filename.c_str(), "rb");
+
+       if (file == NULL) {
+               printf("loadTile: No noise tile '%s' found.\n", filename.c_str());
+               return false;
+       }
+
+       // dimensions
+       int gridSize = noiseTileSize * noiseTileSize * noiseTileSize;
+
+       // noiseTileData memory is managed by caller
+       int bread = fread((void*)noiseTileData, sizeof(float), gridSize, file);
+       fclose(file);
+       printf("Noise tile file '%s' loaded.\n", filename.c_str());
+
+       if (bread != gridSize) {
+               printf("loadTile: Noise tile '%s' is wrong size %d.\n", filename.c_str(), bread);
+               return false;
+       } 
+       return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// write out an existing noise tile
+//////////////////////////////////////////////////////////////////////////////////////////
+static void saveTile(float* const noiseTileData, std::string filename)
+{
+       FILE* file;
+       file = fopen(filename.c_str(), "wb");
+
+       if (file == NULL) {
+               printf("saveTile: Noise tile '%s' could not be saved.\n", filename.c_str());
+               return;
+       } 
+
+       fwrite((void*)noiseTileData, sizeof(float), noiseTileSize * noiseTileSize * noiseTileSize, file);
+       fclose(file);
+
+       printf("saveTile: Noise tile file '%s' saved.\n", filename.c_str());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// create a new noise tile if necessary
+//////////////////////////////////////////////////////////////////////////////////////////
+static void generateTile_WAVELET(float* const noiseTileData, std::string filename) {
+       // if a tile already exists, just use that
+       if (loadTile(noiseTileData, filename)) return;
+
+       const int n = noiseTileSize;
+       const int n3 = n*n*n;
+       std::cout <<"Generating new 3d noise tile size="<<n<<"^3 \n";
+       MTRand twister;
+
+       float *temp13 = new float[n3];
+       float *temp23 = new float[n3];
+       float *noise3 = new float[n3];
+
+       // initialize
+       for (int i = 0; i < n3; i++) {
+               temp13[i] = temp23[i] = noise3[i] = 0.;
+       }
+
+       // Step 1. Fill the tile with random numbers in the range -1 to 1.
+       for (int i = 0; i < n3; i++) 
+               noise3[i] = twister.randNorm();
+
+       // Steps 2 and 3. Downsample and upsample the tile
+       for (int iy = 0; iy < n; iy++) 
+               for (int iz = 0; iz < n; iz++) {
+                       const int i = iy * n + iz*n*n;
+                       downsampleX(&noise3[i], &temp13[i], n);
+                       upsampleX  (&temp13[i], &temp23[i], n);
+               }
+       for (int ix = 0; ix < n; ix++) 
+               for (int iz = 0; iz < n; iz++) {
+                       const int i = ix + iz*n*n;
+                       downsampleY(&temp23[i], &temp13[i], n);
+                       upsampleY  (&temp13[i], &temp23[i], n);
+               }
+       for (int ix = 0; ix < n; ix++) 
+               for (int iy = 0; iy < n; iy++) {
+                       const int i = ix + iy*n;
+                       downsampleZ(&temp23[i], &temp13[i], n);
+                       upsampleZ  (&temp13[i], &temp23[i], n);
+               }
+
+       // Step 4. Subtract out the coarse-scale contribution
+       for (int i = 0; i < n3; i++) 
+               noise3[i] -= temp23[i];
+
+       // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
+       int offset = n / 2;
+       if (offset % 2 == 0) offset++;
+
+       int icnt=0;
+       for (int ix = 0; ix < n; ix++)
+               for (int iy = 0; iy < n; iy++)
+                       for (int iz = 0; iz < n; iz++) { 
+                               temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n];
+                               icnt++;
+                       }
+
+       for (int i = 0; i < n3; i++) 
+               noise3[i] += temp13[i];
+
+       for (int i = 0; i < n3; i++) 
+               noiseTileData[i] = noise3[i];
+
+       saveTile(noise3, filename); 
+       delete[] temp13;
+       delete[] temp23;
+       std::cout <<"Generating new 3d noise done\n";
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// x derivative of noise
+//////////////////////////////////////////////////////////////////////////////////////////
+static inline float WNoiseDx(Vec3 p, float* data) { 
+  int i, f[3], c[3], mid[3], n = noiseTileSize;
+  float w[3][3], t, result = 0;
+  
+  mid[0] = ceil(p[0] - 0.5); 
+  t = mid[0] - (p[0] - 0.5);
+       w[0][0] = -t;
+       w[0][2] = (1.f - t);
+       w[0][1] = 2.0f * t - 1.0f;
+  
+  mid[1] = ceil(p[1] - 0.5); 
+  t = mid[1] - (p[1] - 0.5);
+  w[1][0] = t * t / 2; 
+  w[1][2] = (1 - t) * (1 - t) / 2;
+  w[1][1] = 1 - w[1][0] - w[1][2];
+
+  mid[2] = ceil(p[2] - 0.5); 
+  t = mid[2] - (p[2] - 0.5);
+  w[2][0] = t * t / 2; 
+  w[2][2] = (1 - t) * (1 - t)/2; 
+  w[2][1] = 1 - w[2][0] - w[2][2];
+  // to optimize, explicitly unroll this loop
+  for (int z = -1; z <=1; z++)
+    for (int y = -1; y <=1; y++)
+      for (int x = -1; x <=1; x++)
+      {
+        float weight = 1.0f;
+        c[0] = modFast128(mid[0] + x);
+        weight *= w[0][x+1];
+        c[1] = modFast128(mid[1] + y);
+        weight *= w[1][y+1];
+        c[2] = modFast128(mid[2] + z);
+        weight *= w[2][z+1];
+        result += weight * data[c[2]*n*n+c[1]*n+c[0]];
+      }
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// y derivative of noise
+//////////////////////////////////////////////////////////////////////////////////////////
+static inline float WNoiseDy(Vec3 p, float* data) { 
+  int i, f[3], c[3], mid[3], n=noiseTileSize; 
+  float w[3][3], t, result =0;
+  
+  mid[0] = ceil(p[0] - 0.5); 
+  t = mid[0]-(p[0] - 0.5);
+  w[0][0] = t * t / 2; 
+  w[0][2] = (1 - t) * (1 - t) / 2;
+  w[0][1] = 1 - w[0][0] - w[0][2];
+  
+  mid[1] = ceil(p[1] - 0.5); 
+  t = mid[1]-(p[1] - 0.5);
+       w[1][0] = -t;
+       w[1][2] = (1.f - t);
+       w[1][1] = 2.0f * t - 1.0f;
+
+  mid[2] = ceil(p[2] - 0.5); 
+  t = mid[2] - (p[2] - 0.5);
+  w[2][0] = t * t / 2; 
+  w[2][2] = (1 - t) * (1 - t)/2; 
+  w[2][1] = 1 - w[2][0] - w[2][2];
+  
+  // to optimize, explicitly unroll this loop
+  for (int z = -1; z <=1; z++)
+    for (int y = -1; y <=1; y++)
+      for (int x = -1; x <=1; x++)
+      {
+        float weight = 1.0f;
+        c[0] = modFast128(mid[0] + x);
+        weight *= w[0][x+1];
+        c[1] = modFast128(mid[1] + y);
+        weight *= w[1][y+1];
+        c[2] = modFast128(mid[2] + z);
+        weight *= w[2][z+1];
+        result += weight * data[c[2]*n*n+c[1]*n+c[0]];
+      }
+
+  return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// z derivative of noise
+//////////////////////////////////////////////////////////////////////////////////////////
+static inline float WNoiseDz(Vec3 p, float* data) { 
+  int i, f[3], c[3], mid[3], n=noiseTileSize; 
+  float w[3][3], t, result =0;
+
+  mid[0] = ceil(p[0] - 0.5); 
+  t = mid[0]-(p[0] - 0.5);
+  w[0][0] = t * t / 2; 
+  w[0][2] = (1 - t) * (1 - t) / 2;
+  w[0][1] = 1 - w[0][0] - w[0][2];
+  
+  mid[1] = ceil(p[1] - 0.5); 
+  t = mid[1]-(p[1] - 0.5);
+  w[1][0] = t * t / 2; 
+  w[1][2] = (1 - t) * (1 - t) / 2;
+  w[1][1] = 1 - w[1][0] - w[1][2];
+
+  mid[2] = ceil(p[2] - 0.5); 
+  t = mid[2] - (p[2] - 0.5);
+       w[2][0] = -t;
+       w[2][2] = (1.f - t);
+       w[2][1] = 2.0f * t - 1.0f;
+
+  // to optimize, explicitly unroll this loop
+  for (int z = -1; z <=1; z++)
+    for (int y = -1; y <=1; y++)
+      for (int x = -1; x <=1; x++)
+      {
+        float weight = 1.0f;
+        c[0] = modFast128(mid[0] + x);
+        weight *= w[0][x+1];
+        c[1] = modFast128(mid[1] + y);
+        weight *= w[1][y+1];
+        c[2] = modFast128(mid[2] + z);
+        weight *= w[2][z+1];
+        result += weight * data[c[2]*n*n+c[1]*n+c[0]];
+      }
+  return result;
+}
+
+#endif
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp
new file mode 100644 (file)
index 0000000..64cce9e
--- /dev/null
@@ -0,0 +1,962 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// WTURBULENCE handling
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "WTURBULENCE.h"
+#include "INTERPOLATE.h"
+#include "IMAGE.h"
+#include <MERSENNETWISTER.h>
+#include "WAVELET_NOISE.h"
+#include "FFT_NOISE.h"
+#include "EIGENVALUE_HELPER.h"
+#include "LU_HELPER.h"
+#include "SPHERE.h"
+#include <zlib.h>
+
+// needed to access static advection functions
+#include "FLUID_3D.h"
+
+#if PARALLEL==1
+#include <omp.h>
+#endif // PARALLEL 
+
+// 2^ {-5/6}
+static const float persistence = 0.56123f;
+
+//////////////////////////////////////////////////////////////////////
+// constructor
+//////////////////////////////////////////////////////////////////////
+WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify)
+{
+       // if noise magnitude is below this threshold, its contribution
+       // is negilgible, so stop evaluating new octaves
+       _cullingThreshold = 1e-3;
+       
+       // factor by which to increase the simulation resolution
+       _amplify = amplify;
+       
+       // manually adjust the overall amount of turbulence
+       _strength = 2.;
+       
+       // add the corresponding octaves of noise
+       _octaves = log((float)_amplify) / log(2.0f);
+       
+       // noise resolution
+       _xResBig = _amplify * xResSm;
+       _yResBig = _amplify * yResSm;
+       _zResBig = _amplify * zResSm;
+       _resBig = Vec3Int(_xResBig, _yResBig, _zResBig);
+       _invResBig = Vec3(1./(float)_resBig[0], 1./(float)_resBig[1], 1./(float)_resBig[2]);
+       _slabSizeBig = _xResBig*_yResBig;
+       _totalCellsBig = _slabSizeBig * _zResBig;
+       
+       // original / small resolution
+       _xResSm = xResSm;
+       _yResSm = yResSm;
+       _zResSm = zResSm;
+       _resSm = Vec3Int(xResSm, yResSm, zResSm);
+       _invResSm = Vec3(1./(float)_resSm[0], 1./(float)_resSm[1], 1./(float)_resSm[2] );
+       _slabSizeSm = _xResSm*_yResSm;
+       _totalCellsSm = _slabSizeSm * _zResSm;
+       
+       // allocate high resolution density field
+       _totalStepsBig = 0;
+       _densityBig = new float[_totalCellsBig];
+       _densityBigOld = new float[_totalCellsBig]; 
+       
+       // allocate high resolution velocity field. Note that this is only
+       // necessary because we use MacCormack advection. For semi-Lagrangian
+       // advection, these arrays are not necessary.
+       _tempBig1 = _tempBig2 = 
+       _bigUx = _bigUy = _bigUz = NULL;
+       _tempBig1 = new float[_totalCellsBig];
+       _tempBig2 = new float[_totalCellsBig];
+       _bigUx = new float[_totalCellsBig];
+       _bigUy = new float[_totalCellsBig];
+       _bigUz = new float[_totalCellsBig]; 
+       
+       for(int i = 0; i < _totalCellsBig; i++) {
+               _densityBig[i] = 
+               _densityBigOld[i] = 
+               _bigUx[i] =  
+               _bigUy[i] =  
+               _bigUz[i] =  
+               _tempBig1[i] =  
+               _tempBig2[i] = 0.;
+       }
+       
+       // allocate & init texture coordinates
+       _tcU = new float[_totalCellsSm];
+       _tcV = new float[_totalCellsSm];
+       _tcW = new float[_totalCellsSm];
+       _tcTemp = new float[_totalCellsSm];
+       
+       // allocate & init energy terms
+       _energy = new float[_totalCellsSm];
+       _highFreqEnergy = new float[_totalCellsSm];
+       
+       // map all 
+       const float dx = 1./(float)(_resSm[0]);
+       const float dy = 1./(float)(_resSm[1]);
+       const float dz = 1./(float)(_resSm[2]);
+       int index = 0;
+       for (int z = 0; z < _zResSm; z++) 
+       for (int y = 0; y < _yResSm; y++) 
+               for (int x = 0; x < _xResSm; x++, index++)
+               {
+               _tcU[index] = x*dx;
+               _tcV[index] = y*dy;
+               _tcW[index] = z*dz;
+               _tcTemp[index] = 0.;
+               _energy[index] = 0.;
+               }
+       
+       // allocate eigenvalue arrays
+       _eigMin = new float[_totalCellsSm];
+       _eigMax = new float[_totalCellsSm];
+       for(int i=0; i < _totalCellsSm; i++) 
+               _eigMin[i] = _eigMax[i] =  0.;
+       
+       // noise tiles
+       _noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize];
+       std::string noiseTileFilename = std::string("noise.wavelets");
+       generateTile_WAVELET(_noiseTile, noiseTileFilename);
+       /*
+       std::string noiseTileFilename = std::string("noise.fft");
+       generatTile_FFT(_noiseTile, noiseTileFilename);
+       */
+}
+
+//////////////////////////////////////////////////////////////////////
+// destructor
+//////////////////////////////////////////////////////////////////////
+WTURBULENCE::~WTURBULENCE() {
+  delete[] _densityBig;
+  delete[] _densityBigOld;
+
+  delete[] _bigUx;
+  delete[] _bigUy;
+  delete[] _bigUz;
+  delete[] _tempBig1;
+  delete[] _tempBig2;
+
+  delete[] _tcU;
+  delete[] _tcV;
+  delete[] _tcW;
+  delete[] _tcTemp;
+
+  delete[] _eigMin;
+  delete[] _eigMax;
+  delete[] _noiseTile;
+
+  delete[] _energy;
+  delete[] _highFreqEnergy;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Change noise type
+//
+// type (1<<1) = wavelet / 2
+// type (1<<2) = FFT / 4
+// type (1<<3) = curl / 8
+//////////////////////////////////////////////////////////////////////
+void WTURBULENCE::setNoise(int type)
+{
+       if(type == 4) // FFT
+       {
+               std::string noiseTileFilename = std::string("noise.fft");
+               generatTile_FFT(_noiseTile, noiseTileFilename);
+       }
+       else if(type == 8) // curl
+       {
+               // TODO: not supported yet
+       }
+       else // standard - wavelet
+       {
+               std::string noiseTileFilename = std::string("noise.wavelets");
+               generateTile_WAVELET(_noiseTile, noiseTileFilename);
+       }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Get the smallest valid x derivative
+//
+// Takes the one-sided finite difference in both directions and
+// selects the smaller of the two
+//////////////////////////////////////////////////////////////////////
+static float minDx(int x, int y, int z, float* input, Vec3Int res)
+{
+  const int index = x + y * res[0] + z * res[0] * res[1];
+  const int maxx = res[0]-2;
+
+  // get grid values
+  float center = input[index];
+  float left  = (x <= 1)    ? FLT_MAX : input[index - 1];
+  float right = (x >= maxx) ? FLT_MAX : input[index + 1];
+
+  const float dx = res[0];
+
+  // get all the derivative estimates
+  float dLeft   = (x <= 1)     ? FLT_MAX : (center - left) * dx;
+  float dRight  = (x >= maxx)  ? FLT_MAX : (right - center) * dx;
+  float dCenter = (x <= 1 || x >= maxx) ? FLT_MAX : (right - left) * dx * 0.5f;
+
+  // if it's on a boundary, only one estimate is valid
+  if (x <= 1) return dRight;
+  if (x >= maxx) return dLeft;
+
+  // if it's not on a boundary, get the smallest one
+  float finalD;
+  finalD = (fabs(dCenter) < fabs(dRight)) ? dCenter : dRight;
+  finalD = (fabs(finalD)  < fabs(dLeft))  ? finalD  : dLeft;
+
+  return finalD;
+}
+
+//////////////////////////////////////////////////////////////////////
+// get the smallest valid y derivative
+//
+// Takes the one-sided finite difference in both directions and
+// selects the smaller of the two
+//////////////////////////////////////////////////////////////////////
+static float minDy(int x, int y, int z, float* input, Vec3Int res)
+{
+  const int index = x + y * res[0] + z * res[0] * res[1];
+  const int maxy = res[1]-2;
+
+  // get grid values
+  float center = input[index];
+  float down  = (y <= 1) ? FLT_MAX : input[index - res[0]];
+  float up = (y >= maxy) ? FLT_MAX : input[index + res[0]];
+
+  const float dx = res[1]; // only for square domains
+
+  // get all the derivative estimates
+  float dDown   = (y <= 1)  ? FLT_MAX : (center - down) * dx;
+  float dUp  = (y >= maxy)  ? FLT_MAX : (up - center) * dx;
+  float dCenter = (y <= 1 || y >= maxy) ? FLT_MAX : (up - down) * dx * 0.5f;
+
+  // if it's on a boundary, only one estimate is valid
+  if (y <= 1) return dUp;
+  if (y >= maxy) return dDown;
+
+  // if it's not on a boundary, get the smallest one
+  float finalD = (fabs(dCenter) < fabs(dUp)) ? dCenter : dUp;
+  finalD = (fabs(finalD) < fabs(dDown)) ? finalD : dDown;
+
+  return finalD;
+}
+
+//////////////////////////////////////////////////////////////////////
+// get the smallest valid z derivative
+//
+// Takes the one-sided finite difference in both directions and
+// selects the smaller of the two
+//////////////////////////////////////////////////////////////////////
+static float minDz(int x, int y, int z, float* input, Vec3Int res)
+{
+  const int slab = res[0]*res[1];
+  const int index = x + y * res[0] + z * slab;
+  const int maxz = res[2]-2;
+
+  // get grid values
+  float center = input[index];
+  float front  = (z <= 1) ? FLT_MAX : input[index - slab];
+  float back = (z >= maxz) ? FLT_MAX : input[index + slab];
+
+  const float dx = res[2]; // only for square domains
+
+  // get all the derivative estimates
+  float dfront   = (z <= 1)  ? FLT_MAX : (center - front) * dx;
+  float dback  = (z >= maxz)  ? FLT_MAX : (back - center) * dx;
+  float dCenter = (z <= 1 || z >= maxz) ? FLT_MAX : (back - front) * dx * 0.5f;
+
+  // if it's on a boundary, only one estimate is valid
+  if (z <= 1) return dback;
+  if (z >= maxz) return dfront;
+
+  // if it's not on a boundary, get the smallest one
+  float finalD = (fabs(dCenter) < fabs(dback)) ? dCenter : dback;
+  finalD = (fabs(finalD) < fabs(dfront)) ? finalD : dfront;
+
+  return finalD;
+}
+
+//////////////////////////////////////////////////////////////////////
+// handle texture coordinates (advection, reset, eigenvalues), 
+// Beware -- uses big density maccormack as temporary arrays
+////////////////////////////////////////////////////////////////////// 
+void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel) {
+  // advection
+  SWAP_POINTERS(_tcTemp, _tcU);
+  FLUID_3D::copyBorderX(_tcTemp, _resSm);
+  FLUID_3D::copyBorderY(_tcTemp, _resSm);
+  FLUID_3D::copyBorderZ(_tcTemp, _resSm);
+  FLUID_3D::advectFieldMacCormack(dtOrg, xvel, yvel, zvel, 
+      _tcTemp, _tcU, _tempBig1, _tempBig2, _resSm, NULL);
+
+  SWAP_POINTERS(_tcTemp, _tcV);
+  FLUID_3D::copyBorderX(_tcTemp, _resSm);
+  FLUID_3D::copyBorderY(_tcTemp, _resSm);
+  FLUID_3D::copyBorderZ(_tcTemp, _resSm);
+  FLUID_3D::advectFieldMacCormack(dtOrg, xvel, yvel, zvel, 
+      _tcTemp, _tcV, _tempBig1, _tempBig2, _resSm, NULL);
+
+  SWAP_POINTERS(_tcTemp, _tcW);
+  FLUID_3D::copyBorderX(_tcTemp, _resSm);
+  FLUID_3D::copyBorderY(_tcTemp, _resSm);
+  FLUID_3D::copyBorderZ(_tcTemp, _resSm);
+  FLUID_3D::advectFieldMacCormack(dtOrg, xvel, yvel, zvel, 
+      _tcTemp, _tcW, _tempBig1, _tempBig2, _resSm, NULL);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Compute the eigenvalues of the advected texture
+////////////////////////////////////////////////////////////////////// 
+void WTURBULENCE::computeEigenvalues() {
+  // stats
+  float maxeig = -1.;
+  float mineig = 10.;
+
+  // texture coordinate eigenvalues
+  for (int z = 1; z < _zResSm-1; z++) {
+    for (int y = 1; y < _yResSm-1; y++) 
+      for (int x = 1; x < _xResSm-1; x++)
+      {
+        const int index = x+ y *_resSm[0] + z*_slabSizeSm;
+
+        // compute jacobian
+        float jacobian[3][3] = {
+          { minDx(x, y, z, _tcU, _resSm), minDx(x, y, z, _tcV, _resSm), minDx(x, y, z, _tcW, _resSm) } ,
+          { minDy(x, y, z, _tcU, _resSm), minDy(x, y, z, _tcV, _resSm), minDy(x, y, z, _tcW, _resSm) } ,
+          { minDz(x, y, z, _tcU, _resSm), minDz(x, y, z, _tcV, _resSm), minDz(x, y, z, _tcW, _resSm) }
+        };
+
+        // ONLY compute the eigenvalues after checking that the matrix
+        // is nonsingular
+        JAMA::LU<float> LU = computeLU3x3(jacobian);
+
+        if (LU.isNonsingular())
+        {
+          // get the analytic eigenvalues, quite slow right now...
+          Vec3 eigenvalues = Vec3(1.);
+          computeEigenvalues3x3( &eigenvalues[0], jacobian);
+          _eigMax[index] = MAX3V(eigenvalues);
+          _eigMin[index] = MIN3V(eigenvalues);
+          maxeig = MAX(_eigMax[index],maxeig);
+          mineig = MIN(_eigMin[index],mineig);
+        }
+        else
+        {
+          _eigMax[index] = 10.0f;
+          _eigMin[index] = 0.1;
+        }
+      }
+  }
+}
+
+//////////////////////////////////////////////////////////////////////
+// advect & reset texture coordinates based on eigenvalues
+////////////////////////////////////////////////////////////////////// 
+void WTURBULENCE::resetTextureCoordinates() 
+{
+  // allowed deformation of the textures
+  const float limit = 2.f;
+  const float limitInv = 1./limit;
+
+  // standard reset
+  int resets = 0;
+  const float dx = 1./(float)(_resSm[0]);
+  const float dy = 1./(float)(_resSm[1]);
+  const float dz = 1./(float)(_resSm[2]);
+
+  for (int z = 1; z < _zResSm-1; z++)
+    for (int y = 1; y < _yResSm-1; y++)
+      for (int x = 1; x < _xResSm-1; x++)
+      {
+        const int index = x+ y *_resSm[0] + z*_slabSizeSm;
+        if (_eigMax[index] > limit || _eigMin[index] < limitInv)
+        {
+          _tcU[index] = (float)x * dx;
+          _tcV[index] = (float)y * dy;
+          _tcW[index] = (float)z * dz;
+          resets++;
+        }
+      }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Compute the highest frequency component of the wavelet
+// decomposition
+//////////////////////////////////////////////////////////////////////
+void WTURBULENCE::decomposeEnergy()
+{
+  // do the decomposition -- the goal here is to have
+  // the energy with the high frequency component stomped out
+  // stored in _tcTemp when it is done. _highFreqEnergy is only used
+  // as an additional temp array
+  
+  // downsample input
+  downsampleXNeumann(_highFreqEnergy, _energy, _xResSm, _yResSm, _zResSm);
+  downsampleYNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
+  downsampleZNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm);
+
+  // upsample input
+  upsampleZNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
+  upsampleYNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm);
+  upsampleXNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
+
+  // subtract the down and upsampled field from the original field -- 
+  // what should be left over is solely the high frequency component
+       int index = 0;
+  for (int z = 0; z < _zResSm; z++) 
+    for (int y = 0; y < _yResSm; y++) {
+      for (int x = 0; x < _xResSm; x++, index++) {
+        // brute force reset of boundaries
+        if(z >= _zResSm - 1 || x >= _xResSm - 1 || y >= _yResSm - 1 || z <= 0 || y <= 0 || x <= 0) 
+          _highFreqEnergy[index] = 0.; 
+        else 
+          _highFreqEnergy[index] = _energy[index] - _tcTemp[index];
+    }
+  }
+}
+
+//////////////////////////////////////////////////////////////////////
+// compute velocity from energies and march into obstacles
+// for wavelet decomposition
+////////////////////////////////////////////////////////////////////// 
+void WTURBULENCE::computeEnergy(float* xvel, float* yvel, float* zvel, unsigned char *obstacles) 
+{
+  // compute everywhere
+  for (int x = 0; x < _totalCellsSm; x++) 
+    _energy[x] = 0.5f * (xvel[x] * xvel[x] + yvel[x] * yvel[x] + zvel[x] * zvel[x]);
+
+  FLUID_3D::copyBorderX(_energy, _resSm);
+  FLUID_3D::copyBorderY(_energy, _resSm);
+  FLUID_3D::copyBorderZ(_energy, _resSm);
+
+  // pseudo-march the values into the obstacles
+  // the wavelet upsampler only uses a 3x3 support neighborhood, so
+  // propagating the values in by 4 should be sufficient
+  int index;
+
+  // iterate
+  for (int iter = 0; iter < 4; iter++)
+  {
+    index = _slabSizeSm + _xResSm + 1;
+    for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
+      for (int y = 1; y < _yResSm - 1; y++, index += 2)
+        for (int x = 1; x < _xResSm - 1; x++, index++)
+          if (obstacles[index] && obstacles[index] != RETIRED)
+          {
+            float sum = 0.0f;
+            int valid = 0;
+
+            if (!obstacles[index + 1] || obstacles[index + 1] == RETIRED)
+            {
+              sum += _energy[index + 1];
+              valid++;
+            }
+            if (!obstacles[index - 1] || obstacles[index - 1] == RETIRED)
+            {
+              sum += _energy[index - 1];
+              valid++;
+            }
+            if (!obstacles[index + _xResSm] || obstacles[index + _xResSm] == RETIRED)
+            {
+              sum += _energy[index + _xResSm];
+              valid++;
+            }
+            if (!obstacles[index - _xResSm] || obstacles[index - _xResSm] == RETIRED)
+            {
+              sum += _energy[index - _xResSm];
+              valid++;
+            }
+            if (!obstacles[index + _slabSizeSm] || obstacles[index + _slabSizeSm] == RETIRED)
+            {
+              sum += _energy[index + _slabSizeSm];
+              valid++;
+            }
+            if (!obstacles[index - _slabSizeSm] || obstacles[index - _slabSizeSm] == RETIRED)
+            {
+              sum += _energy[index - _slabSizeSm];
+              valid++;
+            }
+            if (valid > 0)
+            {
+              _energy[index] = sum / valid;
+              obstacles[index] = MARCHED;
+            }
+          }
+    index = _slabSizeSm + _xResSm + 1;
+    for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
+      for (int y = 1; y < _yResSm - 1; y++, index += 2)
+        for (int x = 1; x < _xResSm - 1; x++, index++)
+          if (obstacles[index] == MARCHED)
+            obstacles[index] = RETIRED;
+  }
+  index = _slabSizeSm + _xResSm + 1;
+  for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
+    for (int y = 1; y < _yResSm - 1; y++, index += 2)
+      for (int x = 1; x < _xResSm - 1; x++, index++)
+        if (obstacles[index])
+          obstacles[index] = 1;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Evaluate derivatives
+//////////////////////////////////////////////////////////////////////////////////////////
+Vec3 WTURBULENCE::WVelocity(Vec3 orgPos)
+{
+  // arbitrarily offset evaluation points
+  const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2,0,0);
+  const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2,0);
+  const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2);
+
+  const float f1y = WNoiseDy(p1, _noiseTile);
+  const float f1z = WNoiseDz(p1, _noiseTile);
+
+  const float f2x = WNoiseDx(p2, _noiseTile);
+  const float f2z = WNoiseDz(p2, _noiseTile);
+
+  const float f3x = WNoiseDx(p3, _noiseTile);
+  const float f3y = WNoiseDy(p3, _noiseTile);
+
+  Vec3 ret = Vec3( 
+      f3y - f2z,
+      f1z - f3x,
+      f2x - f1y ); 
+  return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Evaluate derivatives with Jacobian
+//////////////////////////////////////////////////////////////////////////////////////////
+Vec3 WTURBULENCE::WVelocityWithJacobian(Vec3 orgPos, float* xUnwarped, float* yUnwarped, float* zUnwarped)
+{
+  // arbitrarily offset evaluation points
+  const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2,0,0);
+  const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2,0);
+  const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2);
+
+  Vec3 final;
+  final[0] = WNoiseDx(p1, _noiseTile);
+  final[1] = WNoiseDy(p1, _noiseTile);
+  final[2] = WNoiseDz(p1, _noiseTile);
+  const float f1x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
+  const float f1y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
+  const float f1z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
+
+  final[0] = WNoiseDx(p2, _noiseTile);
+  final[1] = WNoiseDy(p2, _noiseTile);
+  final[2] = WNoiseDz(p2, _noiseTile);
+  const float f2x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
+  const float f2y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
+  const float f2z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
+
+  final[0] = WNoiseDx(p3, _noiseTile);
+  final[1] = WNoiseDy(p3, _noiseTile);
+  final[2] = WNoiseDz(p3, _noiseTile);
+  const float f3x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
+  const float f3y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
+  const float f3z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
+
+  Vec3 ret = Vec3( 
+      f3y - f2z,
+      f1z - f3x,
+      f2x - f1y ); 
+  return ret;
+}
+
+//////////////////////////////////////////////////////////////////////
+// perform an actual noise advection step
+//////////////////////////////////////////////////////////////////////
+void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) 
+{
+  // enlarge timestep to match grid
+  const float dt = dtOrg * _amplify;
+  const float invAmp = 1.0f / _amplify;
+
+  // prepare textures
+  advectTextureCoordinates(dtOrg, xvel,yvel,zvel);
+
+  // compute eigenvalues of the texture coordinates
+  computeEigenvalues();
+
+  // do wavelet decomposition of energy
+  computeEnergy(xvel, yvel, zvel, obstacles);
+  decomposeEnergy();
+
+  // zero out coefficients inside of the obstacle
+  for (int x = 0; x < _totalCellsSm; x++)
+    if (obstacles[x]) _energy[x] = 0.f;
+
+  float maxVelocity = 0.;
+  for (int z = 1; z < _zResBig - 1; z++) 
+    for (int y = 1; y < _yResBig - 1; y++) 
+      for (int x = 1; x < _xResBig - 1; x++)
+      {
+        // get unit position for both fine and coarse grid
+        const Vec3 pos = Vec3(x,y,z);
+        const Vec3 posSm = pos * invAmp;
+        
+        // get grid index for both fine and coarse grid
+        const int index = x + y *_xResBig + z *_slabSizeBig;
+        const int indexSmall = (int)posSm[0] + (int)posSm[1] * _xResSm + (int)posSm[2] * _slabSizeSm;
+        
+        // get a linearly interpolated velocity and texcoords
+        // from the coarse grid
+        Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel, 
+            posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
+        Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW, 
+            posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
+
+        // multiply the texture coordinate by _resSm so that turbulence
+        // synthesis begins at the first octave that the coarse grid 
+        // cannot capture
+        Vec3 texCoord = Vec3(uvw[0] * _resSm[0], 
+                             uvw[1] * _resSm[1],
+                             uvw[2] * _resSm[2]); 
+
+        // retrieve wavelet energy at highest frequency
+        float energy = INTERPOLATE::lerp3d(
+            _highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm);
+
+        // base amplitude for octave 0
+        float coefficient = sqrtf(2.0f * fabs(energy));
+        const float amplitude = _strength * fabs(0.5 * coefficient) * persistence;
+
+        // add noise to velocity, but only if the turbulence is
+        // sufficiently undeformed, and the energy is large enough
+        // to make a difference
+        const bool addNoise = _eigMax[indexSmall] < 2. && 
+                              _eigMin[indexSmall] > 0.5;
+        if (addNoise && amplitude > _cullingThreshold) {
+          // base amplitude for octave 0
+          float amplitudeScaled = amplitude;
+
+          for (int octave = 0; octave < _octaves; octave++)
+          {
+            // multiply the vector noise times the maximum allowed
+            // noise amplitude at this octave, and add it to the total
+            vel += WVelocity(texCoord) * amplitudeScaled;
+
+            // scale coefficient for next octave
+            amplitudeScaled *= persistence;
+            texCoord *= 2.0f;
+          }
+        }
+
+        // Store velocity + turbulence in big grid for maccormack step
+        //
+        // If you wanted to save memory, you would instead perform a 
+        // semi-Lagrangian backtrace for the current grid cell here. Then
+        // you could just throw the velocity away.
+        _bigUx[index] = vel[0];
+        _bigUy[index] = vel[1];
+        _bigUz[index] = vel[2];
+
+        // compute the velocity magnitude for substepping later
+        const float velMag = _bigUx[index] * _bigUx[index] + 
+                             _bigUy[index] * _bigUy[index] + 
+                             _bigUz[index] * _bigUz[index];
+        if (velMag > maxVelocity) maxVelocity = velMag;
+
+        // zero out velocity inside obstacles
+        float obsCheck = INTERPOLATE::lerp3dToFloat(
+            obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); 
+        if (obsCheck > 0.95) 
+          _bigUx[index] = _bigUy[index] = _bigUz[index] = 0.;
+      }
+
+  // prepare density for an advection
+  SWAP_POINTERS(_densityBig, _densityBigOld);
+
+  // based on the maximum velocity present, see if we need to substep,
+  // but cap the maximum number of substeps to 5
+  const int maxSubSteps = 25;
+  const int maxVel = 5;
+  maxVelocity = sqrt(maxVelocity) * dt;
+  int totalSubsteps = (int)(maxVelocity / (float)maxVel);
+  totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
+  totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
+  const float dtSubdiv = dt / (float)totalSubsteps;
+
+  // set boundaries of big velocity grid
+  FLUID_3D::setZeroX(_bigUx, _resBig); 
+  FLUID_3D::setZeroY(_bigUy, _resBig); 
+  FLUID_3D::setZeroZ(_bigUz, _resBig);
+
+  // do the MacCormack advection, with substepping if necessary
+  for(int substep = 0; substep < totalSubsteps; substep++)
+  {
+    FLUID_3D::advectFieldMacCormack(dtSubdiv, _bigUx, _bigUy, _bigUz, 
+        _densityBigOld, _densityBig, _tempBig1, _tempBig2, _resBig, NULL);
+
+    if (substep < totalSubsteps - 1) 
+      SWAP_POINTERS(_densityBig, _densityBigOld);
+  } // substep
+  
+  // wipe the density borders
+  FLUID_3D::setZeroBorder(_densityBig, _resBig);
+    
+  // reset texture coordinates now in preparation for next timestep
+  // Shouldn't do this before generating the noise because then the 
+  // eigenvalues stored do not reflect the underlying texture coordinates
+  resetTextureCoordinates();
+  
+  // output files
+  /*
+  string prefix = string("./amplified.preview/density_bigxy_");
+  FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f);
+  //string df3Prefix = string("./df3/density_big_");
+  //IMAGE::dumpDF3(_totalStepsBig, df3Prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
+  string pbrtPrefix = string("./pbrt/density_big_");
+  IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
+       */
+  _totalStepsBig++;
+}
+
+//////////////////////////////////////////////////////////////////////
+// perform the full turbulence algorithm, including OpenMP 
+// if available
+//////////////////////////////////////////////////////////////////////
+void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles)
+{
+  // enlarge timestep to match grid
+  const float dt = dtOrg * _amplify;
+  const float invAmp = 1.0f / _amplify;
+
+  // prepare textures
+  advectTextureCoordinates(dtOrg, xvel,yvel,zvel);
+
+  // do wavelet decomposition of energy
+  computeEnergy(xvel, yvel, zvel, obstacles);
+  decomposeEnergy();
+
+  // zero out coefficients inside of the obstacle
+  for (int x = 0; x < _totalCellsSm; x++)
+    if (obstacles[x]) _energy[x] = 0.f;
+
+  // parallel region setup
+  float maxVelMagThreads[8] = { -1., -1., -1., -1., -1., -1., -1., -1. };
+#if PARALLEL==1
+#pragma omp parallel
+#endif
+  { float maxVelMag1 = 0.;
+#if PARALLEL==1
+    const int id  = omp_get_thread_num(), num = omp_get_num_threads();
+#else
+    const int id  = 0; 
+#endif
+
+  // vector noise main loop
+#if PARALLEL==1
+#pragma omp for  schedule(static)
+#endif
+  for (int zSmall = 0; zSmall < _zResSm; zSmall++) 
+  for (int ySmall = 0; ySmall < _yResSm; ySmall++) 
+  for (int xSmall = 0; xSmall < _xResSm; xSmall++)
+  {
+    const int indexSmall = xSmall + ySmall * _xResSm + zSmall * _slabSizeSm;
+
+    // compute jacobian
+    float jacobian[3][3] = {
+      { minDx(xSmall, ySmall, zSmall, _tcU, _resSm), minDx(xSmall, ySmall, zSmall, _tcV, _resSm), minDx(xSmall, ySmall, zSmall, _tcW, _resSm) } ,
+      { minDy(xSmall, ySmall, zSmall, _tcU, _resSm), minDy(xSmall, ySmall, zSmall, _tcV, _resSm), minDy(xSmall, ySmall, zSmall, _tcW, _resSm) } ,
+      { minDz(xSmall, ySmall, zSmall, _tcU, _resSm), minDz(xSmall, ySmall, zSmall, _tcV, _resSm), minDz(xSmall, ySmall, zSmall, _tcW, _resSm) }
+    };
+
+    // get LU factorization of texture jacobian and apply 
+    // it to unit vectors
+    JAMA::LU<float> LU = computeLU3x3(jacobian);
+    float xUnwarped[] = {1.0f, 0.0f, 0.0f};
+    float yUnwarped[] = {0.0f, 1.0f, 0.0f};
+    float zUnwarped[] = {0.0f, 0.0f, 1.0f};
+    float xWarped[] = {1.0f, 0.0f, 0.0f};
+    float yWarped[] = {0.0f, 1.0f, 0.0f};
+    float zWarped[] = {0.0f, 0.0f, 1.0f};
+    bool nonSingular = LU.isNonsingular();
+    float eigMax = 10.0f;
+    float eigMin = 0.1f;
+    if (nonSingular)
+    {
+      solveLU3x3(LU, xUnwarped, xWarped);
+      solveLU3x3(LU, yUnwarped, yWarped);
+      solveLU3x3(LU, zUnwarped, zWarped);
+
+      // compute the eigenvalues while we have the Jacobian available
+      Vec3 eigenvalues = Vec3(1.);
+      computeEigenvalues3x3( &eigenvalues[0], jacobian);
+      _eigMax[indexSmall] = MAX3V(eigenvalues);
+      _eigMin[indexSmall] = MIN3V(eigenvalues);
+    }
+    
+    // make sure to skip one on the beginning and end
+    int xStart = (xSmall == 0) ? 1 : 0;
+    int xEnd   = (xSmall == _xResSm - 1) ? _amplify - 1 : _amplify;
+    int yStart = (ySmall == 0) ? 1 : 0;
+    int yEnd   = (ySmall == _yResSm - 1) ? _amplify - 1 : _amplify;
+    int zStart = (zSmall == 0) ? 1 : 0;
+    int zEnd   = (zSmall == _zResSm - 1) ? _amplify - 1 : _amplify;
+      
+    for (int zBig = zStart; zBig < zEnd; zBig++) 
+    for (int yBig = yStart; yBig < yEnd; yBig++) 
+    for (int xBig = xStart; xBig < xEnd; xBig++)
+    {
+      const int x = xSmall * _amplify + xBig;
+      const int y = ySmall * _amplify + yBig;
+      const int z = zSmall * _amplify + zBig;
+      
+      // get unit position for both fine and coarse grid
+      const Vec3 pos = Vec3(x,y,z);
+      const Vec3 posSm = pos * invAmp;
+      
+      // get grid index for both fine and coarse grid
+      const int index = x + y *_xResBig + z *_slabSizeBig;
+      
+      // get a linearly interpolated velocity and texcoords
+      // from the coarse grid
+      Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel, 
+          posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
+      Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW, 
+          posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
+
+      // multiply the texture coordinate by _resSm so that turbulence
+      // synthesis begins at the first octave that the coarse grid 
+      // cannot capture
+      Vec3 texCoord = Vec3(uvw[0] * _resSm[0], 
+                           uvw[1] * _resSm[1],
+                           uvw[2] * _resSm[2]); 
+
+      // retrieve wavelet energy at highest frequency
+      float energy = INTERPOLATE::lerp3d(
+          _highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm);
+
+      // base amplitude for octave 0
+      float coefficient = sqrtf(2.0f * fabs(energy));
+      const float amplitude = _strength * fabs(0.5 * coefficient) * persistence;
+
+      // add noise to velocity, but only if the turbulence is
+      // sufficiently undeformed, and the energy is large enough
+      // to make a difference
+      const bool addNoise = _eigMax[indexSmall] < 2. && 
+                            _eigMin[indexSmall] > 0.5;
+      if (addNoise && amplitude > _cullingThreshold) {
+        // base amplitude for octave 0
+        float amplitudeScaled = amplitude;
+
+        for (int octave = 0; octave < _octaves; octave++)
+        {
+          // multiply the vector noise times the maximum allowed
+          // noise amplitude at this octave, and add it to the total
+          vel += WVelocityWithJacobian(texCoord, &xUnwarped[0], &yUnwarped[0], &zUnwarped[0]) * amplitudeScaled;
+
+          // scale coefficient for next octave
+          amplitudeScaled *= persistence;
+          texCoord *= 2.0f;
+        }
+      }
+
+      // Store velocity + turbulence in big grid for maccormack step
+      //
+      // If you wanted to save memory, you would instead perform a 
+      // semi-Lagrangian backtrace for the current grid cell here. Then
+      // you could just throw the velocity away.
+      _bigUx[index] = vel[0];
+      _bigUy[index] = vel[1];
+      _bigUz[index] = vel[2];
+
+      // compute the velocity magnitude for substepping later
+      const float velMag = _bigUx[index] * _bigUx[index] + 
+                           _bigUy[index] * _bigUy[index] + 
+                           _bigUz[index] * _bigUz[index];
+      if (velMag > maxVelMag1) maxVelMag1 = velMag;
+
+      // zero out velocity inside obstacles
+      float obsCheck = INTERPOLATE::lerp3dToFloat(
+          obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); 
+      if (obsCheck > 0.95) 
+        _bigUx[index] = _bigUy[index] = _bigUz[index] = 0.;
+    } // xyz
+
+#if PARALLEL==1
+    maxVelMagThreads[id] = maxVelMag1;
+#else
+    maxVelMagThreads[0] = maxVelMag1;
+#endif
+  }
+  } // omp
+  
+  // compute maximum over threads
+  float maxVelMag = maxVelMagThreads[0];
+#if PARALLEL==1
+  for (int i = 1; i < 8; i++) 
+    if (maxVelMag < maxVelMagThreads[i]) 
+      maxVelMag = maxVelMagThreads[i];
+#endif
+
+  // prepare density for an advection
+  SWAP_POINTERS(_densityBig, _densityBigOld);
+
+  // based on the maximum velocity present, see if we need to substep,
+  // but cap the maximum number of substeps to 5
+  const int maxSubSteps = 25;
+  const int maxVel = 5;
+  maxVelMag = sqrt(maxVelMag) * dt;
+  int totalSubsteps = (int)(maxVelMag / (float)maxVel);
+  totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
+  
+  totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
+  const float dtSubdiv = dt / (float)totalSubsteps;
+
+  // set boundaries of big velocity grid
+  FLUID_3D::setZeroX(_bigUx, _resBig); 
+  FLUID_3D::setZeroY(_bigUy, _resBig); 
+  FLUID_3D::setZeroZ(_bigUz, _resBig);
+
+  // do the MacCormack advection, with substepping if necessary
+  for(int substep = 0; substep < totalSubsteps; substep++)
+  {
+    FLUID_3D::advectFieldMacCormack(dtSubdiv, _bigUx, _bigUy, _bigUz, 
+        _densityBigOld, _densityBig, _tempBig1, _tempBig2, _resBig, NULL);
+
+    if (substep < totalSubsteps - 1) 
+      SWAP_POINTERS(_densityBig, _densityBigOld);
+  } // substep
+  
+  // wipe the density borders
+  FLUID_3D::setZeroBorder(_densityBig, _resBig);
+    
+  // reset texture coordinates now in preparation for next timestep
+  // Shouldn't do this before generating the noise because then the 
+  // eigenvalues stored do not reflect the underlying texture coordinates
+  resetTextureCoordinates();
+  
+  // output files
+  // string prefix = string("./amplified.preview/density_bigxy_");
+  // FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f);
+  //string df3prefix = string("./df3/density_big_");
+  //IMAGE::dumpDF3(_totalStepsBig, df3prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
+  // string pbrtPrefix = string("./pbrt/density_big_");
+  // IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
+  
+  _totalStepsBig++;
+}
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
new file mode 100644 (file)
index 0000000..858a47b
--- /dev/null
@@ -0,0 +1,147 @@
+//////////////////////////////////////////////////////////////////////
+// This file is part of Wavelet Turbulence.
+// 
+// Wavelet Turbulence is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// Wavelet Turbulence is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with Wavelet Turbulence.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// Copyright 2008 Theodore Kim and Nils Thuerey
+// 
+// WTURBULENCE handling
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef WTURBULENCE_H
+#define WTURBULENCE_H
+
+#include "VEC3.h"
+using namespace BasicVector;
+class SIMPLE_PARSER;
+
+///////////////////////////////////////////////////////////////////////////////
+/// Main WTURBULENCE class, stores large density array etc.
+///////////////////////////////////////////////////////////////////////////////
+class WTURBULENCE  
+{
+       public:
+               // both config files can be NULL, altCfg might override values from noiseCfg
+               WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify);
+
+               /// destructor
+               virtual ~WTURBULENCE();
+               
+               void setNoise(int type);
+
+               // step more readable version -- no rotation correction
+               void stepTurbulenceReadable(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
+
+               // step more complete version -- include rotation correction
+               // and use OpenMP if available
+               void stepTurbulenceFull(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
+       
+               // texcoord functions
+               void advectTextureCoordinates(float dtOrg, float* xvel, float* yvel, float* zvel);
+               void resetTextureCoordinates();
+
+               void computeEnergy(float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
+
+               // evaluate wavelet noise function
+               Vec3 WVelocity(Vec3 p);
+               Vec3 WVelocityWithJacobian(Vec3 p, float* xUnwarped, float* yUnwarped, float* zUnwarped);
+
+               // access functions
+               inline float* getDensityBig() { return _densityBig; }
+               inline float* getArrayTcU() { return _tcU; }
+               inline float* getArrayTcV() { return _tcV; }
+               inline float* getArrayTcW() { return _tcW; }
+               inline float* getArrayEigMin() { return _eigMin; }
+               inline float* getArrayEigMax() { return _eigMax; }
+
+               inline Vec3Int getResSm() { return _resSm; } // small resolution
+               inline Vec3Int getResBig() { return _resBig; }
+               inline int getOctaves() { return _octaves; }
+
+       protected:
+               // enlargement factor from original velocity field / simulation
+               // _Big = _amplify * _Sm
+               int _amplify;
+               int _octaves;
+               float _strength;
+
+               // noise settings
+               float _cullingThreshold;
+               float _noiseStrength;
+               float _noiseSizeScale;
+               bool _uvwAdvection;
+               bool _uvwReset;
+               float _noiseTimeanimSpeed;
+               int _dumpInterval;
+               int _noiseControlType;
+               // debug, scale density for projections output images
+               float _outputScale;
+
+               // noise resolution
+               int _xResBig;
+               int _yResBig;
+               int _zResBig;
+               Vec3Int _resBig;
+               Vec3 _invResBig;
+               int _totalCellsBig;
+               int _slabSizeBig;
+               // original / small resolution
+               int _xResSm;
+               int _yResSm;
+               int _zResSm;
+               Vec3Int _resSm;
+               Vec3 _invResSm;
+               int _totalCellsSm;
+               int _slabSizeSm;
+
+               float* _densityBig;
+               float* _densityBigOld;
+
+               // big velocity macCormack fields
+               float* _bigUx;
+               float* _bigUy;
+               float* _bigUz;
+               // temp arrays for BFECC and MacCormack - they have more convenient
+               // names in the actual implementations
+               float* _tempBig1;
+               float* _tempBig2;
+
+               // texture coordinates for noise
+               float* _tcU;
+               float* _tcV;
+               float* _tcW;
+               float* _tcTemp;
+
+               float* _eigMin;
+               float* _eigMax;
+
+               // wavelet decomposition of velocity energies
+               float* _energy;
+
+               // noise data
+               float* _noiseTile;
+               //float* _noiseTileExt;
+
+               // step counter
+               int _totalStepsBig;
+
+               // highest frequency component of wavelet decomposition
+               float* _highFreqEnergy;
+               
+               void computeEigenvalues();
+               void decomposeEnergy();
+};
+
+#endif // WTURBULENCE_H
+
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
new file mode 100644 (file)
index 0000000..c81d6fb
--- /dev/null
@@ -0,0 +1,125 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 by Daniel Genrich
+ * All rights reserved.
+ *
+ * Contributor(s): None
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "FLUID_3D.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// y in smoke is z in blender
+extern "C" FLUID_3D *smoke_init(int *res, int amplify, float *p0, float *p1, float dt)
+{
+       // smoke lib uses y as top-bottom/vertical axis where blender uses z
+       FLUID_3D *fluid = new FLUID_3D(res, amplify, p0, p1, dt);
+
+       // printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]);
+
+       return fluid;
+}
+
+extern "C" void smoke_free(FLUID_3D *fluid)
+{
+       delete fluid;
+       fluid = NULL;
+}
+
+extern "C" void smoke_step(FLUID_3D *fluid, float dx)
+{
+       // fluid->addSmokeColumn();
+       fluid->step();
+}
+
+extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta)
+{
+       fluid->initBlenderRNA(alpha, beta);
+}
+
+template < class T > inline T ABS( T a ) {
+       return (0 < a) ? a : -a ;
+}
+
+extern "C" float *smoke_get_density(FLUID_3D *fluid)
+{
+       return fluid->_density;
+}
+
+extern "C" float *smoke_get_heat(FLUID_3D *fluid)
+{
+       return fluid->_heat;
+}
+
+extern "C" float *smoke_get_velocity_x(FLUID_3D *fluid)
+{
+       return fluid->_xVorticity;
+}
+
+extern "C" float *smoke_get_velocity_y(FLUID_3D *fluid)
+{
+       return fluid->_yVorticity;
+}
+
+extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid)
+{
+       return fluid->_zVorticity;
+}
+
+extern "C" float *smoke_get_bigdensity(FLUID_3D *fluid)
+{
+       return fluid->_wTurbulence->getDensityBig();
+}
+
+extern "C" void smoke_get_bigres(FLUID_3D *fluid, int *res)
+{
+       Vec3Int r = fluid->_wTurbulence->getResBig();
+       res[0] = r[0];
+       res[1] = r[1];
+       res[2] = r[2];
+}
+
+extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
+{
+       return fluid->_obstacles;
+}
+
+extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z, int max_z)
+{
+       // // const int index = x + y * smd->res[0] + z * smd->res[0]*smd->res[1];
+       return x + y * max_x + z * max_x*max_y;
+}
+
+extern "C" size_t smoke_get_index2d(int x, int max_x, int y, int max_y, int z, int max_z)
+{
+       return x + y * max_x;
+}
+
+extern "C" void smoke_set_noise(FLUID_3D *fluid, int type)
+{
+       fluid->_wTurbulence->setNoise(type);
+}
+
+
+
diff --git a/intern/smoke/intern/tnt/jama_eig.h b/intern/smoke/intern/tnt/jama_eig.h
new file mode 100644 (file)
index 0000000..0d833be
--- /dev/null
@@ -0,0 +1,1050 @@
+#ifndef JAMA_EIG_H
+#define JAMA_EIG_H
+
+
+#include "tnt_array1d.h"
+#include "tnt_array2d.h"
+#include "tnt_math_utils.h"
+
+#include <algorithm>
+// for min(), max() below
+
+#include <cmath>
+// for fabs() below
+
+using namespace TNT;
+using namespace std;
+
+// NT debugging
+//static int gEigenDebug=0;
+//if(gEigenDebug) std::cerr<<"n="<<n<<" m="<<m<<" l="<<l<<"\n"; 
+// m has to be smaller l! in line 262
+// gcc can get confused with abs calls, replaced by fabs
+
+namespace JAMA
+{
+
+/** 
+
+    Computes eigenvalues and eigenvectors of a real (non-complex)
+    matrix. 
+<P>
+    If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
+    diagonal and the eigenvector matrix V is orthogonal. That is,
+       the diagonal values of D are the eigenvalues, and
+    V*V' = I, where I is the identity matrix.  The columns of V 
+    represent the eigenvectors in the sense that A*V = V*D.
+    
+<P>
+    If A is not symmetric, then the eigenvalue matrix D is block diagonal
+    with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
+    a + i*b, in 2-by-2 blocks, [a, b; -b, a].  That is, if the complex
+    eigenvalues look like
+<pre>
+
+          u + iv     .        .          .      .    .
+            .      u - iv     .          .      .    .
+            .        .      a + ib       .      .    .
+            .        .        .        a - ib   .    .
+            .        .        .          .      x    .
+            .        .        .          .      .    y
+</pre>
+        then D looks like
+<pre>
+
+            u        v        .          .      .    .
+           -v        u        .          .      .    . 
+            .        .        a          b      .    .
+            .        .       -b          a      .    .
+            .        .        .          .      x    .
+            .        .        .          .      .    y
+</pre>
+    This keeps V a real matrix in both symmetric and non-symmetric
+    cases, and A*V = V*D.
+    
+    
+    
+    <p>
+    The matrix V may be badly
+    conditioned, or even singular, so the validity of the equation
+    A = V*D*inverse(V) depends upon the condition number of V.
+
+   <p>
+       (Adapted from JAMA, a Java Matrix Library, developed by jointly 
+       by the Mathworks and NIST; see  http://math.nist.gov/javanumerics/jama).
+**/
+
+template <class Real>
+class Eigenvalue
+{
+
+
+   /** Row and column dimension (square matrix).  */
+    int n;
+
+   int issymmetric; /* boolean*/
+
+   /** Arrays for internal storage of eigenvalues. */
+
+   TNT::Array1D<Real> d;         /* real part */
+   TNT::Array1D<Real> e;         /* img part */
+
+   /** Array for internal storage of eigenvectors. */
+    TNT::Array2D<Real> V;
+
+   /** Array for internal storage of nonsymmetric Hessenberg form.
+   @serial internal storage of nonsymmetric Hessenberg form.
+   */
+   TNT::Array2D<Real> H;
+   
+
+   /** Working storage for nonsymmetric algorithm.
+   @serial working storage for nonsymmetric algorithm.
+   */
+   TNT::Array1D<Real> ort;
+
+
+   // Symmetric Householder reduction to tridiagonal form.
+
+   void tred2() {
+
+   //  This is derived from the Algol procedures tred2 by
+   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+   //  Fortran subroutine in EISPACK.
+
+      for (int j = 0; j < n; j++) {
+         d[j] = V[n-1][j];
+      }
+
+      // Householder reduction to tridiagonal form.
+   
+      for (int i = n-1; i > 0; i--) {
+   
+         // Scale to avoid under/overflow.
+   
+         Real scale = 0.0;
+         Real h = 0.0;
+         for (int k = 0; k < i; k++) {
+            scale = scale + fabs(d[k]);
+         }
+         if (scale == 0.0) {
+            e[i] = d[i-1];
+            for (int j = 0; j < i; j++) {
+               d[j] = V[i-1][j];
+               V[i][j] = 0.0;
+               V[j][i] = 0.0;
+            }
+         } else {
+   
+            // Generate Householder vector.
+   
+            for (int k = 0; k < i; k++) {
+               d[k] /= scale;
+               h += d[k] * d[k];
+            }
+            Real f = d[i-1];
+            Real g = sqrt(h);
+            if (f > 0) {
+               g = -g;
+            }
+            e[i] = scale * g;
+            h = h - f * g;
+            d[i-1] = f - g;
+            for (int j = 0; j < i; j++) {
+               e[j] = 0.0;
+            }
+   
+            // Apply similarity transformation to remaining columns.
+   
+            for (int j = 0; j < i; j++) {
+               f = d[j];
+               V[j][i] = f;
+               g = e[j] + V[j][j] * f;
+               for (int k = j+1; k <= i-1; k++) {
+                  g += V[k][j] * d[k];
+                  e[k] += V[k][j] * f;
+               }
+               e[j] = g;
+            }
+            f = 0.0;
+            for (int j = 0; j < i; j++) {
+               e[j] /= h;
+               f += e[j] * d[j];
+            }
+            Real hh = f / (h + h);
+            for (int j = 0; j < i; j++) {
+               e[j] -= hh * d[j];
+            }
+            for (int j = 0; j < i; j++) {
+               f = d[j];
+               g = e[j];
+               for (int k = j; k <= i-1; k++) {
+                  V[k][j] -= (f * e[k] + g * d[k]);
+               }
+               d[j] = V[i-1][j];
+               V[i][j] = 0.0;
+            }
+         }
+         d[i] = h;
+      }
+   
+      // Accumulate transformations.
+   
+      for (int i = 0; i < n-1; i++) {
+         V[n-1][i] = V[i][i];
+         V[i][i] = 1.0;
+         Real h = d[i+1];
+         if (h != 0.0) {
+            for (int k = 0; k <= i; k++) {
+               d[k] = V[k][i+1] / h;
+            }
+            for (int j = 0; j <= i; j++) {
+               Real g = 0.0;
+               for (int k = 0; k <= i; k++) {
+                  g += V[k][i+1] * V[k][j];
+               }
+               for (int k = 0; k <= i; k++) {
+                  V[k][j] -= g * d[k];
+               }
+            }
+         }
+         for (int k = 0; k <= i; k++) {
+            V[k][i+1] = 0.0;
+         }
+      }
+      for (int j = 0; j < n; j++) {
+         d[j] = V[n-1][j];
+         V[n-1][j] = 0.0;
+      }
+      V[n-1][n-1] = 1.0;
+      e[0] = 0.0;
+   } 
+
+   // Symmetric tridiagonal QL algorithm.
+   
+   void tql2 () {
+
+   //  This is derived from the Algol procedures tql2, by
+   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+   //  Fortran subroutine in EISPACK.
+   
+      for (int i = 1; i < n; i++) {
+         e[i-1] = e[i];
+      }
+      e[n-1] = 0.0;
+   
+      Real f = 0.0;
+      Real tst1 = 0.0;
+      Real eps = pow(2.0,-52.0);
+      for (int l = 0; l < n; l++) {
+
+         // Find small subdiagonal element
+   
+         tst1 = max(tst1,fabs(d[l]) + fabs(e[l]));
+         int m = l;
+
+        // Original while-loop from Java code
+         while (m < n) {
+            if (fabs(e[m]) <= eps*tst1) {
+               break;
+            }
+            m++;
+         }
+
+   
+         // If m == l, d[l] is an eigenvalue,
+         // otherwise, iterate.
+   
+         if (m > l) {
+            int iter = 0;
+            do {
+               iter = iter + 1;  // (Could check iteration count here.)
+   
+               // Compute implicit shift
+
+               Real g = d[l];
+               Real p = (d[l+1] - g) / (2.0 * e[l]);
+               Real r = hypot(p,1.0);
+               if (p < 0) {
+                  r = -r;
+               }
+               d[l] = e[l] / (p + r);
+               d[l+1] = e[l] * (p + r);
+               Real dl1 = d[l+1];
+               Real h = g - d[l];
+               for (int i = l+2; i < n; i++) {
+                  d[i] -= h;
+               }
+               f = f + h;
+   
+               // Implicit QL transformation.
+   
+               p = d[m];
+               Real c = 1.0;
+               Real c2 = c;
+               Real c3 = c;
+               Real el1 = e[l+1];
+               Real s = 0.0;
+               Real s2 = 0.0;
+               for (int i = m-1; i >= l; i--) {
+                  c3 = c2;
+                  c2 = c;
+                  s2 = s;
+                  g = c * e[i];
+                  h = c * p;
+                  r = hypot(p,e[i]);
+                  e[i+1] = s * r;
+                  s = e[i] / r;
+                  c = p / r;
+                  p = c * d[i] - s * g;
+                  d[i+1] = h + s * (c * g + s * d[i]);
+   
+                  // Accumulate transformation.
+   
+                  for (int k = 0; k < n; k++) {
+                     h = V[k][i+1];
+                     V[k][i+1] = s * V[k][i] + c * h;
+                     V[k][i] = c * V[k][i] - s * h;
+                  }
+               }
+               p = -s * s2 * c3 * el1 * e[l] / dl1;
+               e[l] = s * p;
+               d[l] = c * p;
+   
+               // Check for convergence.
+   
+            } while (fabs(e[l]) > eps*tst1);
+         }
+         d[l] = d[l] + f;
+         e[l] = 0.0;
+      }
+     
+      // Sort eigenvalues and corresponding vectors.
+   
+      for (int i = 0; i < n-1; i++) {
+         int k = i;
+         Real p = d[i];
+         for (int j = i+1; j < n; j++) {
+            if (d[j] < p) {
+               k = j;
+               p = d[j];
+            }
+         }
+         if (k != i) {
+            d[k] = d[i];
+            d[i] = p;
+            for (int j = 0; j < n; j++) {
+               p = V[j][i];
+               V[j][i] = V[j][k];
+               V[j][k] = p;
+            }
+         }
+      }
+   }
+
+   // Nonsymmetric reduction to Hessenberg form.
+
+   void orthes () {
+   
+      //  This is derived from the Algol procedures orthes and ortran,
+      //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+      //  Vol.ii-Linear Algebra, and the corresponding
+      //  Fortran subroutines in EISPACK.
+   
+      int low = 0;
+      int high = n-1;
+   
+      for (int m = low+1; m <= high-1; m++) {
+   
+         // Scale column.
+   
+         Real scale = 0.0;
+         for (int i = m; i <= high; i++) {
+            scale = scale + fabs(H[i][m-1]);
+         }
+         if (scale != 0.0) {
+   
+            // Compute Householder transformation.
+   
+            Real h = 0.0;
+            for (int i = high; i >= m; i--) {
+               ort[i] = H[i][m-1]/scale;
+               h += ort[i] * ort[i];
+            }
+            Real g = sqrt(h);
+            if (ort[m] > 0) {
+               g = -g;
+            }
+            h = h - ort[m] * g;
+            ort[m] = ort[m] - g;
+   
+            // Apply Householder similarity transformation
+            // H = (I-u*u'/h)*H*(I-u*u')/h)
+   
+            for (int j = m; j < n; j++) {
+               Real f = 0.0;
+               for (int i = high; i >= m; i--) {
+                  f += ort[i]*H[i][j];
+               }
+               f = f/h;
+               for (int i = m; i <= high; i++) {
+                  H[i][j] -= f*ort[i];
+               }
+           }
+   
+           for (int i = 0; i <= high; i++) {
+               Real f = 0.0;
+               for (int j = high; j >= m; j--) {
+                  f += ort[j]*H[i][j];
+               }
+               f = f/h;
+               for (int j = m; j <= high; j++) {
+                  H[i][j] -= f*ort[j];
+               }
+            }
+            ort[m] = scale*ort[m];
+            H[m][m-1] = scale*g;
+         }
+      }
+   
+      // Accumulate transformations (Algol's ortran).
+
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            V[i][j] = (i == j ? 1.0 : 0.0);
+         }
+      }
+
+      for (int m = high-1; m >= low+1; m--) {
+         if (H[m][m-1] != 0.0) {
+            for (int i = m+1; i <= high; i++) {
+               ort[i] = H[i][m-1];
+            }
+            for (int j = m; j <= high; j++) {
+               Real g = 0.0;
+               for (int i = m; i <= high; i++) {
+                  g += ort[i] * V[i][j];
+               }
+               // Double division avoids possible underflow
+               g = (g / ort[m]) / H[m][m-1];
+               for (int i = m; i <= high; i++) {
+                  V[i][j] += g * ort[i];
+               }
+            }
+         }
+      }
+   }
+
+
+   // Complex scalar division.
+
+   Real cdivr, cdivi;
+   void cdiv(Real xr, Real xi, Real yr, Real yi) {
+      Real r,d;
+      if (fabs(yr) > fabs(yi)) {
+         r = yi/yr;
+         d = yr + r*yi;
+         cdivr = (xr + r*xi)/d;
+         cdivi = (xi - r*xr)/d;
+      } else {
+         r = yr/yi;
+         d = yi + r*yr;
+         cdivr = (r*xr + xi)/d;
+         cdivi = (r*xi - xr)/d;
+      }
+   }
+
+
+   // Nonsymmetric reduction from Hessenberg to real Schur form.
+
+   void hqr2 () {
+   
+      //  This is derived from the Algol procedure hqr2,
+      //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+      //  Vol.ii-Linear Algebra, and the corresponding
+      //  Fortran subroutine in EISPACK.
+   
+      // Initialize
+   
+      int nn = this->n;
+      int n = nn-1;
+      int low = 0;
+      int high = nn-1;
+      Real eps = pow(2.0,-52.0);
+      Real exshift = 0.0;
+      Real p=0,q=0,r=0,s=0,z=0,t,w,x,y;
+   
+      // Store roots isolated by balanc and compute matrix norm
+   
+      Real norm = 0.0;
+      for (int i = 0; i < nn; i++) {
+         if ((i < low) || (i > high)) {
+            d[i] = H[i][i];
+            e[i] = 0.0;
+         }
+         for (int j = max(i-1,0); j < nn; j++) {
+            norm = norm + fabs(H[i][j]);
+         }
+      }
+   
+      // Outer loop over eigenvalue index
+   
+      int iter = 0;
+               int totIter = 0;
+      while (n >= low) {
+
+                       // NT limit no. of iterations
+                       totIter++;
+                       if(totIter>100) {
+                               //if(totIter>15) std::cout<<"!!!!iter ABORT !!!!!!! "<<totIter<<"\n"; 
+                               // NT hack/fix, return large eigenvalues
+                               for (int i = 0; i < nn; i++) {
+                                       d[i] = 10000.;
+                                       e[i] = 10000.;
+                               }
+                               return;
+                       }
+   
+         // Look for single small sub-diagonal element
+   
+         int l = n;
+         while (l > low) {
+            s = fabs(H[l-1][l-1]) + fabs(H[l][l]);
+            if (s == 0.0) {
+               s = norm;
+            }
+            if (fabs(H[l][l-1]) < eps * s) {
+               break;
+            }
+            l--;
+         }
+       
+         // Check for convergence
+         // One root found
+   
+         if (l == n) {
+            H[n][n] = H[n][n] + exshift;
+            d[n] = H[n][n];
+            e[n] = 0.0;
+            n--;
+            iter = 0;
+   
+         // Two roots found
+   
+         } else if (l == n-1) {
+            w = H[n][n-1] * H[n-1][n];
+            p = (H[n-1][n-1] - H[n][n]) / 2.0;
+            q = p * p + w;
+            z = sqrt(fabs(q));
+            H[n][n] = H[n][n] + exshift;
+            H[n-1][n-1] = H[n-1][n-1] + exshift;
+            x = H[n][n];
+   
+            // Real pair
+   
+            if (q >= 0) {
+               if (p >= 0) {
+                  z = p + z;
+               } else {
+                  z = p - z;
+               }
+               d[n-1] = x + z;
+               d[n] = d[n-1];
+               if (z != 0.0) {
+                  d[n] = x - w / z;
+               }
+               e[n-1] = 0.0;
+               e[n] = 0.0;
+               x = H[n][n-1];
+               s = fabs(x) + fabs(z);
+               p = x / s;
+               q = z / s;
+               r = sqrt(p * p+q * q);
+               p = p / r;
+               q = q / r;
+   
+               // Row modification
+   
+               for (int j = n-1; j < nn; j++) {
+                  z = H[n-1][j];
+                  H[n-1][j] = q * z + p * H[n][j];
+                  H[n][j] = q * H[n][j] - p * z;
+               }
+   
+               // Column modification
+   
+               for (int i = 0; i <= n; i++) {
+                  z = H[i][n-1];
+                  H[i][n-1] = q * z + p * H[i][n];
+                  H[i][n] = q * H[i][n] - p * z;
+               }
+   
+               // Accumulate transformations
+   
+               for (int i = low; i <= high; i++) {
+                  z = V[i][n-1];
+                  V[i][n-1] = q * z + p * V[i][n];
+                  V[i][n] = q * V[i][n] - p * z;
+               }
+   
+            // Complex pair
+   
+            } else {
+               d[n-1] = x + p;
+               d[n] = x + p;
+               e[n-1] = z;
+               e[n] = -z;
+            }
+            n = n - 2;
+            iter = 0;
+   
+         // No convergence yet
+   
+         } else {
+   
+            // Form shift
+   
+            x = H[n][n];
+            y = 0.0;
+            w = 0.0;
+            if (l < n) {
+               y = H[n-1][n-1];
+               w = H[n][n-1] * H[n-1][n];
+            }
+   
+            // Wilkinson's original ad hoc shift
+   
+            if (iter == 10) {
+               exshift += x;
+               for (int i = low; i <= n; i++) {
+                  H[i][i] -= x;
+               }
+               s = fabs(H[n][n-1]) + fabs(H[n-1][n-2]);
+               x = y = 0.75 * s;
+               w = -0.4375 * s * s;
+            }
+
+            // MATLAB's new ad hoc shift
+
+            if (iter == 30) {
+                s = (y - x) / 2.0;
+                s = s * s + w;
+                if (s > 0) {
+                    s = sqrt(s);
+                    if (y < x) {
+                       s = -s;
+                    }
+                    s = x - w / ((y - x) / 2.0 + s);
+                    for (int i = low; i <= n; i++) {
+                       H[i][i] -= s;
+                    }
+                    exshift += s;
+                    x = y = w = 0.964;
+                }
+            }
+   
+            iter = iter + 1;   // (Could check iteration count here.)
+   
+            // Look for two consecutive small sub-diagonal elements
+   
+            int m = n-2;
+            while (m >= l) {
+               z = H[m][m];
+               r = x - z;
+               s = y - z;
+               p = (r * s - w) / H[m+1][m] + H[m][m+1];
+               q = H[m+1][m+1] - z - r - s;
+               r = H[m+2][m+1];
+               s = fabs(p) + fabs(q) + fabs(r);
+               p = p / s;
+               q = q / s;
+               r = r / s;
+               if (m == l) {
+                  break;
+               }
+               if (fabs(H[m][m-1]) * (fabs(q) + fabs(r)) <
+                  eps * (fabs(p) * (fabs(H[m-1][m-1]) + fabs(z) +
+                  fabs(H[m+1][m+1])))) {
+                     break;
+               }
+               m--;
+            }
+   
+            for (int i = m+2; i <= n; i++) {
+               H[i][i-2] = 0.0;
+               if (i > m+2) {
+                  H[i][i-3] = 0.0;
+               }
+            }
+   
+            // Double QR step involving rows l:n and columns m:n
+   
+            for (int k = m; k <= n-1; k++) {
+               int notlast = (k != n-1);
+               if (k != m) {
+                  p = H[k][k-1];
+                  q = H[k+1][k-1];
+                  r = (notlast ? H[k+2][k-1] : 0.0);
+                  x = fabs(p) + fabs(q) + fabs(r);
+                  if (x != 0.0) {
+                     p = p / x;
+                     q = q / x;
+                     r = r / x;
+                  }
+               }
+               if (x == 0.0) {
+                  break;
+               }
+               s = sqrt(p * p + q * q + r * r);
+               if (p < 0) {
+                  s = -s;
+               }
+               if (s != 0) {
+                  if (k != m) {
+                     H[k][k-1] = -s * x;
+                  } else if (l != m) {
+                     H[k][k-1] = -H[k][k-1];
+                  }
+                  p = p + s;
+                  x = p / s;
+                  y = q / s;
+                  z = r / s;
+                  q = q / p;
+                  r = r / p;
+   
+                  // Row modification
+   
+                  for (int j = k; j < nn; j++) {
+                     p = H[k][j] + q * H[k+1][j];
+                     if (notlast) {
+                        p = p + r * H[k+2][j];
+                        H[k+2][j] = H[k+2][j] - p * z;
+                     }
+                     H[k][j] = H[k][j] - p * x;
+                     H[k+1][j] = H[k+1][j] - p * y;
+                  }
+   
+                  // Column modification
+   
+                  for (int i = 0; i <= min(n,k+3); i++) {
+                     p = x * H[i][k] + y * H[i][k+1];
+                     if (notlast) {
+                        p = p + z * H[i][k+2];
+                        H[i][k+2] = H[i][k+2] - p * r;
+                     }
+                     H[i][k] = H[i][k] - p;
+                     H[i][k+1] = H[i][k+1] - p * q;
+                  }
+   
+                  // Accumulate transformations
+   
+                  for (int i = low; i <= high; i++) {
+                     p = x * V[i][k] + y * V[i][k+1];
+                     if (notlast) {
+                        p = p + z * V[i][k+2];
+                        V[i][k+2] = V[i][k+2] - p * r;
+                     }
+                     V[i][k] = V[i][k] - p;
+                     V[i][k+1] = V[i][k+1] - p * q;
+                  }
+               }  // (s != 0)
+            }  // k loop
+         }  // check convergence
+      }  // while (n >= low)
+               //if(totIter>15) std::cout<<"!!!!iter "<<totIter<<"\n";
+      
+      // Backsubstitute to find vectors of upper triangular form
+
+      if (norm == 0.0) {
+         return;
+      }
+   
+      for (n = nn-1; n >= 0; n--) {
+         p = d[n];
+         q = e[n];
+   
+         // Real vector
+   
+         if (q == 0) {
+            int l = n;
+            H[n][n] = 1.0;
+            for (int i = n-1; i >= 0; i--) {
+               w = H[i][i] - p;
+               r = 0.0;
+               for (int j = l; j <= n; j++) {
+                  r = r + H[i][j] * H[j][n];
+               }
+               if (e[i] < 0.0) {
+                  z = w;
+                  s = r;
+               } else {
+                  l = i;
+                  if (e[i] == 0.0) {
+                     if (w != 0.0) {
+                        H[i][n] = -r / w;
+                     } else {
+                        H[i][n] = -r / (eps * norm);
+                     }
+   
+                  // Solve real equations
+   
+                  } else {
+                     x = H[i][i+1];
+                     y = H[i+1][i];
+                     q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
+                     t = (x * s - z * r) / q;
+                     H[i][n] = t;
+                     if (fabs(x) > fabs(z)) {
+                        H[i+1][n] = (-r - w * t) / x;
+                     } else {
+                        H[i+1][n] = (-s - y * t) / z;
+                     }
+                  }
+   
+                  // Overflow control
+   
+                  t = fabs(H[i][n]);
+                  if ((eps * t) * t > 1) {
+                     for (int j = i; j <= n; j++) {
+                        H[j][n] = H[j][n] / t;
+                     }
+                  }
+               }
+            }
+   
+         // Complex vector
+   
+         } else if (q < 0) {
+            int l = n-1;
+
+            // Last vector component imaginary so matrix is triangular
+   
+            if (fabs(H[n][n-1]) > fabs(H[n-1][n])) {
+               H[n-1][n-1] = q / H[n][n-1];
+               H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
+            } else {
+               cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
+               H[n-1][n-1] = cdivr;
+               H[n-1][n] = cdivi;
+            }
+            H[n][n-1] = 0.0;
+            H[n][n] = 1.0;
+            for (int i = n-2; i >= 0; i--) {
+               Real ra,sa,vr,vi;
+               ra = 0.0;
+               sa = 0.0;
+               for (int j = l; j <= n; j++) {
+                  ra = ra + H[i][j] * H[j][n-1];
+                  sa = sa + H[i][j] * H[j][n];
+               }
+               w = H[i][i] - p;
+   
+               if (e[i] < 0.0) {
+                  z = w;
+                  r = ra;
+                  s = sa;
+               } else {
+                  l = i;
+                  if (e[i] == 0) {
+                     cdiv(-ra,-sa,w,q);
+                     H[i][n-1] = cdivr;
+                     H[i][n] = cdivi;
+                  } else {
+   
+                     // Solve complex equations
+   
+                     x = H[i][i+1];
+                     y = H[i+1][i];
+                     vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
+                     vi = (d[i] - p) * 2.0 * q;
+                     if ((vr == 0.0) && (vi == 0.0)) {
+                        vr = eps * norm * (fabs(w) + fabs(q) +
+                        fabs(x) + fabs(y) + fabs(z));
+                     }
+                     cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
+                     H[i][n-1] = cdivr;
+                     H[i][n] = cdivi;
+                     if (fabs(x) > (fabs(z) + fabs(q))) {
+                        H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
+                        H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
+                     } else {
+                        cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
+                        H[i+1][n-1] = cdivr;
+                        H[i+1][n] = cdivi;
+                     }
+                  }
+   
+                  // Overflow control
+
+                  t = max(fabs(H[i][n-1]),fabs(H[i][n]));
+                  if ((eps * t) * t > 1) {
+                     for (int j = i; j <= n; j++) {
+                        H[j][n-1] = H[j][n-1] / t;
+                        H[j][n] = H[j][n] / t;
+                     }
+                  }
+               }
+            }
+         }
+      }
+   
+      // Vectors of isolated roots
+   
+      for (int i = 0; i < nn; i++) {
+         if (i < low || i > high) {
+            for (int j = i; j < nn; j++) {
+               V[i][j] = H[i][j];
+            }
+         }
+      }
+   
+      // Back transformation to get eigenvectors of original matrix
+   
+      for (int j = nn-1; j >= low; j--) {
+         for (int i = low; i <= high; i++) {
+            z = 0.0;
+            for (int k = low; k <= min(j,high); k++) {
+               z = z + V[i][k] * H[k][j];
+            }
+            V[i][j] = z;
+         }
+      }
+   }
+
+public:
+
+
+   /** Check for symmetry, then construct the eigenvalue decomposition
+   @param A    Square real (non-complex) matrix
+   */
+
+   Eigenvalue(const TNT::Array2D<Real> &A) {
+      n = A.dim2();
+      V = Array2D<Real>(n,n);
+      d = Array1D<Real>(n);
+      e = Array1D<Real>(n);
+
+      issymmetric = 1;
+      for (int j = 0; (j < n) && issymmetric; j++) {
+         for (int i = 0; (i < n) && issymmetric; i++) {
+            issymmetric = (A[i][j] == A[j][i]);
+         }
+      }
+
+      if (issymmetric) {
+         for (int i = 0; i < n; i++) {
+            for (int j = 0; j < n; j++) {
+               V[i][j] = A[i][j];
+            }
+         }
+   
+         // Tridiagonalize.
+         tred2();
+   
+         // Diagonalize.
+         tql2();
+
+      } else {
+         H = TNT::Array2D<Real>(n,n);
+         ort = TNT::Array1D<Real>(n);
+         
+         for (int j = 0; j < n; j++) {
+            for (int i = 0; i < n; i++) {
+               H[i][j] = A[i][j];
+            }
+         }
+   
+         // Reduce to Hessenberg form.
+         orthes();
+   
+         // Reduce Hessenberg to real Schur form.
+         hqr2();
+      }
+   }
+
+
+   /** Return the eigenvector matrix
+   @return     V
+   */
+
+   void getV (TNT::Array2D<Real> &V_) {
+      V_ = V;
+      return;
+   }
+
+   /** Return the real parts of the eigenvalues
+   @return     real(diag(D))
+   */
+
+   void getRealEigenvalues (TNT::Array1D<Real> &d_) {
+      d_ = d;
+      return ;
+   }
+
+   /** Return the imaginary parts of the eigenvalues
+   in parameter e_.
+
+   @pararm e_: new matrix with imaginary parts of the eigenvalues.
+   */
+   void getImagEigenvalues (TNT::Array1D<Real> &e_) {
+      e_ = e;
+      return;
+   }
+
+   
+/** 
+       Computes the block diagonal eigenvalue matrix.
+    If the original matrix A is not symmetric, then the eigenvalue 
+       matrix D is block diagonal with the real eigenvalues in 1-by-1 
+       blocks and any complex eigenvalues,
+    a + i*b, in 2-by-2 blocks, [a, b; -b, a].  That is, if the complex
+    eigenvalues look like
+<pre>
+
+          u + iv     .        .          .      .    .
+            .      u - iv     .          .      .    .
+            .        .      a + ib       .      .    .
+            .        .        .        a - ib   .    .
+            .        .        .          .      x    .
+            .        .        .          .      .    y
+</pre>
+        then D looks like
+<pre>
+
+            u        v        .          .      .    .
+           -v        u        .          .      .    . 
+            .        .        a          b      .    .
+            .        .       -b          a      .    .
+            .        .        .          .      x    .
+            .        .        .          .      .    y
+</pre>
+    This keeps V a real matrix in both symmetric and non-symmetric
+    cases, and A*V = V*D.
+
+       @param D: upon return, the matrix is filled with the block diagonal 
+       eigenvalue matrix.
+       
+*/
+   void getD (TNT::Array2D<Real> &D) {
+      D = Array2D<Real>(n,n);
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            D[i][j] = 0.0;
+         }
+         D[i][i] = d[i];
+         if (e[i] > 0) {
+            D[i][i+1] = e[i];
+         } else if (e[i] < 0) {
+            D[i][i-1] = e[i];
+         }
+      }
+   }
+};
+
+} //namespace JAMA
+
+
+#endif
+// JAMA_EIG_H
diff --git a/intern/smoke/intern/tnt/jama_lu.h b/intern/smoke/intern/tnt/jama_lu.h
new file mode 100644 (file)
index 0000000..a4f96b1
--- /dev/null
@@ -0,0 +1,319 @@
+#ifndef JAMA_LU_H
+#define JAMA_LU_H
+
+#include "tnt.h"
+#include <algorithm>
+//for min(), max() below
+
+using namespace TNT;
+using namespace std;
+
+namespace JAMA
+{
+
+   /** LU Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
+   unit lower triangular matrix L, an n-by-n upper triangular matrix U,
+   and a permutation vector piv of length m so that A(piv,:) = L*U.
+   If m < n, then L is m-by-m and U is m-by-n.
+   <P>
+   The LU decompostion with pivoting always exists, even if the matrix is
+   singular, so the constructor will never fail.  The primary use of the
+   LU decomposition is in the solution of square systems of simultaneous
+   linear equations.  This will fail if isNonsingular() returns false.
+   */
+template <class Real>
+class LU
+{
+
+
+
+   /* Array for internal storage of decomposition.  */
+   Array2D<Real>  LU_;
+   int m, n, pivsign; 
+   Array1D<int> piv;
+
+
+   Array2D<Real> permute_copy(const Array2D<Real> &A, 
+                       const Array1D<int> &piv, int j0, int j1)
+       {
+               int piv_length = piv.dim();
+
+               Array2D<Real> X(piv_length, j1-j0+1);
+
+
+         for (int i = 0; i < piv_length; i++) 
+            for (int j = j0; j <= j1; j++) 
+               X[i][j-j0] = A[piv[i]][j];
+
+               return X;
+       }
+
+   Array1D<Real> permute_copy(const Array1D<Real> &A, 
+               const Array1D<int> &piv)
+       {
+               int piv_length = piv.dim();
+               if (piv_length != A.dim())
+                       return Array1D<Real>();
+
+               Array1D<Real> x(piv_length);
+
+
+         for (int i = 0; i < piv_length; i++) 
+               x[i] = A[piv[i]];
+
+               return x;
+       }
+
+
+       public :
+
+   /** LU Decomposition
+   @param  A   Rectangular matrix
+   @return     LU Decomposition object to access L, U and piv.
+   */
+
+    LU (const Array2D<Real> &A) : LU_(A.copy()), m(A.dim1()), n(A.dim2()), 
+               piv(A.dim1())
+       
+       {
+
+   // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+
+
+      for (int i = 0; i < m; i++) {
+         piv[i] = i;
+      }
+      pivsign = 1;
+      Real *LUrowi = 0;;
+      Array1D<Real> LUcolj(m);
+
+      // Outer loop.
+
+      for (int j = 0; j < n; j++) {
+
+         // Make a copy of the j-th column to localize references.
+
+         for (int i = 0; i < m; i++) {
+            LUcolj[i] = LU_[i][j];
+         }
+
+         // Apply previous transformations.
+
+         for (int i = 0; i < m; i++) {
+            LUrowi = LU_[i];
+
+            // Most of the time is spent in the following dot product.
+
+            int kmax = min(i,j);
+            double s = 0.0;
+            for (int k = 0; k < kmax; k++) {
+               s += LUrowi[k]*LUcolj[k];
+            }
+
+            LUrowi[j] = LUcolj[i] -= s;
+         }
+   
+         // Find pivot and exchange if necessary.
+
+         int p = j;
+         for (int i = j+1; i < m; i++) {
+            if (abs(LUcolj[i]) > abs(LUcolj[p])) {
+               p = i;
+            }
+         }
+         if (p != j) {
+                   int k=0;
+            for (k = 0; k < n; k++) {
+               double t = LU_[p][k]; 
+                          LU_[p][k] = LU_[j][k]; 
+                          LU_[j][k] = t;
+            }
+            k = piv[p]; 
+                       piv[p] = piv[j]; 
+                       piv[j] = k;
+            pivsign = -pivsign;
+         }
+
+         // Compute multipliers.
+         
+         if ((j < m) && (LU_[j][j] != 0.0)) {
+            for (int i = j+1; i < m; i++) {
+               LU_[i][j] /= LU_[j][j];
+            }
+         }
+      }
+   }
+
+
+   /** Is the matrix nonsingular?
+   @return     1 (true)  if upper triangular factor U (and hence A) 
+                               is nonsingular, 0 otherwise.
+   */
+
+   int isNonsingular () {
+      for (int j = 0; j < n; j++) {
+         if (LU_[j][j] == 0)
+            return 0;
+      }
+      return 1;
+   }
+
+   /** Return lower triangular factor
+   @return     L
+   */
+
+   Array2D<Real> getL () {
+      Array2D<Real> L_(m,n);
+      for (int i = 0; i < m; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i > j) {
+               L_[i][j] = LU_[i][j];
+            } else if (i == j) {
+               L_[i][j] = 1.0;
+            } else {
+               L_[i][j] = 0.0;
+            }
+         }
+      }
+      return L_;
+   }
+
+   /** Return upper triangular factor
+   @return     U portion of LU factorization.
+   */
+
+   Array2D<Real> getU () {
+         Array2D<Real> U_(n,n);
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i <= j) {
+               U_[i][j] = LU_[i][j];
+            } else {
+               U_[i][j] = 0.0;
+            }
+         }
+      }
+      return U_;
+   }
+
+   /** Return pivot permutation vector
+   @return     piv
+   */
+
+   Array1D<int> getPivot () {
+      return piv;
+   }
+
+
+   /** Compute determinant using LU factors.
+   @return     determinant of A, or 0 if A is not square.
+   */
+
+   Real det () {
+      if (m != n) {
+         return Real(0);
+      }
+      Real d = Real(pivsign);
+      for (int j = 0; j < n; j++) {
+         d *= LU_[j][j];
+      }
+      return d;
+   }
+
+   /** Solve A*X = B
+   @param  B   A Matrix with as many rows as A and any number of columns.
+   @return     X so that L*U*X = B(piv,:), if B is nonconformant, returns
+                                       0x0 (null) array.
+   */
+
+   Array2D<Real> solve (const Array2D<Real> &B) 
+   {
+
+         /* Dimensions: A is mxn, X is nxk, B is mxk */
+      
+      if (B.dim1() != m) {
+               return Array2D<Real>(0,0);
+      }
+      if (!isNonsingular()) {
+        return Array2D<Real>(0,0);
+      }
+
+      // Copy right hand side with pivoting
+      int nx = B.dim2();
+
+
+         Array2D<Real> X = permute_copy(B, piv, 0, nx-1);
+
+      // Solve L*Y = B(piv,:)
+      for (int k = 0; k < n; k++) {
+         for (int i = k+1; i < n; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*LU_[i][k];
+            }
+         }
+      }
+      // Solve U*X = Y;
+      for (int k = n-1; k >= 0; k--) {
+         for (int j = 0; j < nx; j++) {
+            X[k][j] /= LU_[k][k];
+         }