Google Summer of Code project: "Smoke Simulator Improvements & Fire".
authorDaniel Genrich <daniel.genrich@gmx.net>
Wed, 10 Oct 2012 13:18:07 +0000 (13:18 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Wed, 10 Oct 2012 13:18:07 +0000 (13:18 +0000)
Documentation & Test blend files:
------------------
http://wiki.blender.org/index.php/User:MiikaH/GSoC-2012-Smoke-Simulator-Improvements

Credits:
------------------
Miika Hamalainen (MiikaH): Student / Main programmer

Daniel Genrich (Genscher): Mentor / Programmer of merged patches from Smoke2 branch
Google: For Google Summer of Code 2012

50 files changed:
intern/smoke/CMakeLists.txt
intern/smoke/extern/smoke_API.h
intern/smoke/intern/FLUID_3D.cpp
intern/smoke/intern/FLUID_3D.h
intern/smoke/intern/FLUID_3D_SOLVERS.cpp
intern/smoke/intern/FLUID_3D_STATIC.cpp
intern/smoke/intern/WTURBULENCE.cpp
intern/smoke/intern/WTURBULENCE.h
intern/smoke/intern/smoke_API.cpp
intern/smoke/intern/spectrum.cpp [new file with mode: 0644]
intern/smoke/intern/spectrum.h [new file with mode: 0644]
release/datafiles/blender_icons.png
release/scripts/startup/bl_operators/object_quick_effects.py
release/scripts/startup/bl_ui/properties_particle.py
release/scripts/startup/bl_ui/properties_physics_cloth.py
release/scripts/startup/bl_ui/properties_physics_common.py
release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
release/scripts/startup/bl_ui/properties_physics_field.py
release/scripts/startup/bl_ui/properties_physics_smoke.py
release/scripts/startup/bl_ui/properties_physics_softbody.py
release/scripts/startup/bl_ui/properties_texture.py
source/blender/blenkernel/BKE_smoke.h
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/effect.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/BLI_utildefines.h
source/blender/blenlib/intern/math_vector_inline.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/include/UI_icons.h
source/blender/editors/object/object_add.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/drawvolume.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/gpu/GPU_extensions.h
source/blender/gpu/intern/gpu_draw.c
source/blender/gpu/intern/gpu_extensions.c
source/blender/makesdna/DNA_object_force.h
source/blender/makesdna/DNA_smoke_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/makesrna/intern/rna_material.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object_force.c
source/blender/makesrna/intern/rna_smoke.c
source/blender/makesrna/intern/rna_texture.c
source/blender/modifiers/intern/MOD_smoke.c
source/blender/render/intern/source/render_texture.c
source/blender/render/intern/source/voxeldata.c

index 9524f7b29358e355a70231a1e54e450467dc888e..11f173a6835806e4625196f2bb2267c5a7b5084b 100644 (file)
@@ -40,6 +40,7 @@ set(SRC
        intern/FLUID_3D_SOLVERS.cpp
        intern/FLUID_3D_STATIC.cpp
        intern/LU_HELPER.cpp
+       intern/spectrum.cpp
        intern/SPHERE.cpp
        intern/WTURBULENCE.cpp
        intern/smoke_API.cpp
@@ -53,6 +54,7 @@ set(SRC
        intern/LU_HELPER.h
        intern/MERSENNETWISTER.h
        intern/OBSTACLE.h
+       intern/spectrum.h
        intern/SPHERE.h
        intern/VEC3.h
        intern/WAVELET_NOISE.h
index a0eb1bf38e0c92825a94d41615a45d3f2317d34d..98c63f08fbda79a0b1f76eb98b976f77c7589cbe 100644 (file)
@@ -37,17 +37,23 @@ extern "C" {
 
 struct FLUID_3D;
 
-// export
-void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles);
-
 // low res
-struct FLUID_3D *smoke_init(int *res, float *p0, float dtdef);
+struct FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors);
 void smoke_free(struct FLUID_3D *fluid);
 
-void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli);
-void smoke_step(struct FLUID_3D *fluid, float dtSubdiv);
+void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
+                                                 float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp);
+void smoke_step(struct FLUID_3D *fluid, float gravity[3], float dtSubdiv);
 
 float *smoke_get_density(struct FLUID_3D *fluid);
+float *smoke_get_flame(struct FLUID_3D *fluid);
+float *smoke_get_fuel(struct FLUID_3D *fluid);
+float *smoke_get_react(struct FLUID_3D *fluid);
+float *smoke_get_color_r(struct FLUID_3D *fluid);
+float *smoke_get_color_g(struct FLUID_3D *fluid);
+float *smoke_get_color_b(struct FLUID_3D *fluid);
+void smoke_get_rgba(struct FLUID_3D *fluid, float *data, int sequential);
+void smoke_get_rgba_from_density(struct FLUID_3D *fluid, float color[3], float *data, int sequential);
 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);
@@ -68,19 +74,44 @@ size_t smoke_get_index2d(int x, int max_x, int y);
 void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
 
 // wavelet turbulence functions
-struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype);
+struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, int use_fire, int use_colors);
 void smoke_turbulence_free(struct WTURBULENCE *wt);
 void smoke_turbulence_step(struct WTURBULENCE *wt, struct FLUID_3D *fluid);
 
 float *smoke_turbulence_get_density(struct WTURBULENCE *wt);
+float *smoke_turbulence_get_color_r(struct WTURBULENCE *wt);
+float *smoke_turbulence_get_color_g(struct WTURBULENCE *wt);
+float *smoke_turbulence_get_color_b(struct WTURBULENCE *wt);
+void smoke_turbulence_get_rgba(struct WTURBULENCE *wt, float *data, int sequential);
+void smoke_turbulence_get_rgba_from_density(struct WTURBULENCE *wt, float color[3], float *data, int sequential);
+float *smoke_turbulence_get_flame(struct WTURBULENCE *wt);
+float *smoke_turbulence_get_fuel(struct WTURBULENCE *wt);
+float *smoke_turbulence_get_react(struct WTURBULENCE *wt);
 void smoke_turbulence_get_res(struct WTURBULENCE *wt, int *res);
+int smoke_turbulence_get_cells(struct WTURBULENCE *wt);
 void smoke_turbulence_set_noise(struct WTURBULENCE *wt, int type);
 void smoke_initWaveletBlenderRNA(struct WTURBULENCE *wt, float *strength);
-
 void smoke_dissolve_wavelet(struct WTURBULENCE *wt, int speed, int log);
 
-// export
-void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **densold, float **tcu, float **tcv, float **tcw);
+/* export */
+void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat, float **heatold,
+                                 float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles);
+void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
+                                                        float **r, float **g, float **b, float **tcu, float **tcv, float **tcw);
+
+/* flame spectrum */
+void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2);
+
+/* data fields */
+int smoke_has_heat(struct FLUID_3D *fluid);
+int smoke_has_fuel(struct FLUID_3D *fluid);
+int smoke_has_colors(struct FLUID_3D *fluid);
+int smoke_turbulence_has_fuel(struct WTURBULENCE *wt);
+int smoke_turbulence_has_colors(struct WTURBULENCE *wt);
+
+void smoke_ensure_heat(struct FLUID_3D *fluid);
+void smoke_ensure_fire(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
+void smoke_ensure_colors(struct FLUID_3D *fluid, struct WTURBULENCE *wt, float init_r, float init_g, float init_b);
 
 #ifdef __cplusplus
 }
index e006132ea8fe3dd4201a7c43d9aeaa69cc73d4e7..b7b353352e21d0270008aa18ab85c76fdf4b49b2 100644 (file)
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
+FLUID_3D::FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors) :
        _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f)
 {
        // set simulation consts
        _dt = dtdef;    // just in case. set in step from a RNA factor
-       
-       // start point of array
-       _p0[0] = p0[0];
-       _p0[1] = p0[1];
-       _p0[2] = p0[2];
 
        _iterations = 100;
        _tempAmb = 0; 
@@ -72,7 +67,10 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
        */
        
        // scale the constants according to the refinement of the grid
-       _dx = 1.0f / (float)_maxRes;
+       if (!dx)
+               _dx = 1.0f / (float)_maxRes;
+       else
+               _dx = dx;
        _constantScaling = 64.0f / _maxRes;
        _constantScaling = (_constantScaling < 1.0f) ? 1.0f : _constantScaling;
        _vorticityEps = 2.0f / _constantScaling; // Just in case set a default value
@@ -94,8 +92,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
        _zForce       = new float[_totalCells];
        _density      = new float[_totalCells];
        _densityOld   = new float[_totalCells];
-       _heat         = new float[_totalCells];
-       _heatOld      = new float[_totalCells];
        _obstacles    = new unsigned char[_totalCells]; // set 0 at end of step
 
        // For threaded version:
@@ -103,7 +99,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
        _yVelocityTemp = new float[_totalCells];
        _zVelocityTemp = new float[_totalCells];
        _densityTemp   = new float[_totalCells];
-       _heatTemp      = new float[_totalCells];
 
        // DG TODO: check if alloc went fine
 
@@ -111,8 +106,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
        {
                _density[x]      = 0.0f;
                _densityOld[x]   = 0.0f;
-               _heat[x]         = 0.0f;
-               _heatOld[x]      = 0.0f;
                _xVelocity[x]    = 0.0f;
                _yVelocity[x]    = 0.0f;
                _zVelocity[x]    = 0.0f;
@@ -128,6 +121,25 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
                _obstacles[x]    = false;
        }
 
+       /* heat */
+       _heat = _heatOld = _heatTemp = NULL;
+       if (init_heat) {
+               initHeat();
+       }
+       // Fire simulation
+       _flame = _fuel = _fuelTemp = _fuelOld = NULL;
+       _react = _reactTemp = _reactOld = NULL;
+       if (init_fire) {
+               initFire();
+       }
+       // Smoke color
+       _color_r = _color_rOld = _color_rTemp = NULL;
+       _color_g = _color_gOld = _color_gTemp = NULL;
+       _color_b = _color_bOld = _color_bTemp = NULL;
+       if (init_colors) {
+               initColors(0.0f, 0.0f, 0.0f);
+       }
+
        // boundary conditions of the fluid domain
        // set default values -> vertically non-colliding
        _domainBcFront = true;
@@ -138,9 +150,70 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
        _domainBcRight  = _domainBcLeft;
 
        _colloPrev = 1; // default value
+}
 
-       setBorderObstacles(); // walls
+void FLUID_3D::initHeat()
+{
+       if (!_heat) {
+               _heat         = new float[_totalCells];
+               _heatOld      = new float[_totalCells];
+               _heatTemp      = new float[_totalCells];
 
+               for (int x = 0; x < _totalCells; x++)
+               {
+                       _heat[x]         = 0.0f;
+                       _heatOld[x]      = 0.0f;
+               }
+       }
+}
+
+void FLUID_3D::initFire()
+{
+       if (!_flame) {
+               _flame          = new float[_totalCells];
+               _fuel           = new float[_totalCells];
+               _fuelTemp       = new float[_totalCells];
+               _fuelOld        = new float[_totalCells];
+               _react          = new float[_totalCells];
+               _reactTemp      = new float[_totalCells];
+               _reactOld       = new float[_totalCells];
+
+               for (int x = 0; x < _totalCells; x++)
+               {
+                       _flame[x]               = 0.0f;
+                       _fuel[x]                = 0.0f;
+                       _fuelTemp[x]    = 0.0f;
+                       _fuelOld[x]             = 0.0f;
+                       _react[x]               = 0.0f;
+                       _reactTemp[x]   = 0.0f;
+                       _reactOld[x]    = 0.0f;
+               }
+       }
+}
+
+void FLUID_3D::initColors(float init_r, float init_g, float init_b)
+{
+       if (!_color_r) {
+               _color_r                = new float[_totalCells];
+               _color_rOld             = new float[_totalCells];
+               _color_rTemp    = new float[_totalCells];
+               _color_g                = new float[_totalCells];
+               _color_gOld             = new float[_totalCells];
+               _color_gTemp    = new float[_totalCells];
+               _color_b                = new float[_totalCells];
+               _color_bOld             = new float[_totalCells];
+               _color_bTemp    = new float[_totalCells];
+
+               for (int x = 0; x < _totalCells; x++)
+               {
+                       _color_r[x]             = _density[x] * init_r;
+                       _color_rOld[x]  = 0.0f;
+                       _color_g[x]             = _density[x] * init_g;
+                       _color_gOld[x]  = 0.0f;
+                       _color_b[x]             = _density[x] * init_b;
+                       _color_bOld[x]  = 0.0f;
+               }
+       }
 }
 
 void FLUID_3D::setBorderObstacles()
@@ -204,7 +277,6 @@ FLUID_3D::~FLUID_3D()
        if (_heat) delete[] _heat;
        if (_heatOld) delete[] _heatOld;
        if (_obstacles) delete[] _obstacles;
-    // if (_wTurbulence) delete _wTurbulence;
 
        if (_xVelocityTemp) delete[] _xVelocityTemp;
        if (_yVelocityTemp) delete[] _yVelocityTemp;
@@ -212,23 +284,48 @@ FLUID_3D::~FLUID_3D()
        if (_densityTemp) delete[] _densityTemp;
        if (_heatTemp) delete[] _heatTemp;
 
+       if (_flame) delete[] _flame;
+       if (_fuel) delete[] _fuel;
+       if (_fuelTemp) delete[] _fuelTemp;
+       if (_fuelOld) delete[] _fuelOld;
+       if (_react) delete[] _react;
+       if (_reactTemp) delete[] _reactTemp;
+       if (_reactOld) delete[] _reactOld;
+
+       if (_color_r) delete[] _color_r;
+       if (_color_rOld) delete[] _color_rOld;
+       if (_color_rTemp) delete[] _color_rTemp;
+       if (_color_g) delete[] _color_g;
+       if (_color_gOld) delete[] _color_gOld;
+       if (_color_gTemp) delete[] _color_gTemp;
+       if (_color_b) delete[] _color_b;
+       if (_color_bOld) delete[] _color_bOld;
+       if (_color_bTemp) delete[] _color_bTemp;
+
     // printf("deleted fluid\n");
 }
 
 // init direct access functions from blender
-void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision)
+void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision, float *burning_rate,
+                                                         float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
 {
        _alpha = alpha;
        _beta = beta;
        _dtFactor = dt_factor;
        _vorticityRNA = vorticity;
        _borderColli = borderCollision;
+       _burning_rate = burning_rate;
+       _flame_smoke = flame_smoke;
+       _flame_smoke_color = flame_smoke_color;
+       _flame_vorticity = flame_vorticity;
+       _ignition_temp = flame_ignition_temp;
+       _max_temp = flame_max_temp;
 }
 
 //////////////////////////////////////////////////////////////////////
 // step simulation once
 //////////////////////////////////////////////////////////////////////
-void FLUID_3D::step(float dt)
+void FLUID_3D::step(float dt, float gravity[3])
 {
 #if 0
        // If border rules have been changed
@@ -281,7 +378,7 @@ void FLUID_3D::step(float dt)
 
                wipeBoundariesSL(zBegin, zEnd);
                addVorticity(zBegin, zEnd);
-               addBuoyancy(_heat, _density, zBegin, zEnd);
+               addBuoyancy(_heat, _density, gravity, zBegin, zEnd);
                addForce(zBegin, zEnd);
 
 #if PARALLEL==1
@@ -312,13 +409,15 @@ void FLUID_3D::step(float dt)
                if (i==0)
                {
 #endif
-               project();
+                       project();
 #if PARALLEL==1
                }
-               else
+               else if (i==1)
                {
 #endif
-               diffuseHeat();
+                       if (_heat) {
+                               diffuseHeat();
+                       }
 #if PARALLEL==1
                }
        }
@@ -338,6 +437,13 @@ void FLUID_3D::step(float dt)
        SWAP_POINTERS(_density, _densityOld);
        SWAP_POINTERS(_heat, _heatOld);
 
+       SWAP_POINTERS(_fuel, _fuelOld);
+       SWAP_POINTERS(_react, _reactOld);
+
+       SWAP_POINTERS(_color_r, _color_rOld);
+       SWAP_POINTERS(_color_g, _color_gOld);
+       SWAP_POINTERS(_color_b, _color_bOld);
+
        advectMacCormackBegin(0, _zRes);
 
 #if PARALLEL==1
@@ -398,11 +504,8 @@ void FLUID_3D::step(float dt)
        SWAP_POINTERS(_yVelocity, _yForce);
        SWAP_POINTERS(_zVelocity, _zForce);
 
-
-
-
        _totalTime += _dt;
-       _totalSteps++;          
+       _totalSteps++;
 
        for (int i = 0; i < _totalCells; i++)
        {
@@ -643,6 +746,15 @@ void FLUID_3D::wipeBoundaries(int zBegin, int zEnd)
        setZeroBorder(_yVelocity, _res, zBegin, zEnd);
        setZeroBorder(_zVelocity, _res, zBegin, zEnd);
        setZeroBorder(_density, _res, zBegin, zEnd);
+       if (_fuel) {
+               setZeroBorder(_fuel, _res, zBegin, zEnd);
+               setZeroBorder(_react, _res, zBegin, zEnd);
+       }
+       if (_color_r) {
+               setZeroBorder(_color_r, _res, zBegin, zEnd);
+               setZeroBorder(_color_g, _res, zBegin, zEnd);
+               setZeroBorder(_color_b, _res, zBegin, zEnd);
+       }
 }
 
 void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
@@ -668,6 +780,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
                        _yVelocity[index] = 0.0f;
                        _zVelocity[index] = 0.0f;
                        _density[index] = 0.0f;
+                       if (_fuel) {
+                               _fuel[index] = 0.0f;
+                               _react[index] = 0.0f;
+                       }
+                       if (_color_r) {
+                               _color_r[index] = 0.0f;
+                               _color_g[index] = 0.0f;
+                               _color_b[index] = 0.0f;
+                       }
 
                        // right slab
                        index += _xRes - 1;
@@ -675,6 +796,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
                        _yVelocity[index] = 0.0f;
                        _zVelocity[index] = 0.0f;
                        _density[index] = 0.0f;
+                       if (_fuel) {
+                               _fuel[index] = 0.0f;
+                               _react[index] = 0.0f;
+                       }
+                       if (_color_r) {
+                               _color_r[index] = 0.0f;
+                               _color_g[index] = 0.0f;
+                               _color_b[index] = 0.0f;
+                       }
                }
 
        /////////////////////////////////////
@@ -690,6 +820,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
                        _yVelocity[index] = 0.0f;
                        _zVelocity[index] = 0.0f;
                        _density[index] = 0.0f;
+                       if (_fuel) {
+                               _fuel[index] = 0.0f;
+                               _react[index] = 0.0f;
+                       }
+                       if (_color_r) {
+                               _color_r[index] = 0.0f;
+                               _color_g[index] = 0.0f;
+                               _color_b[index] = 0.0f;
+                       }
 
                        // top slab
                        index += slabSize - _xRes;
@@ -697,6 +836,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
                        _yVelocity[index] = 0.0f;
                        _zVelocity[index] = 0.0f;
                        _density[index] = 0.0f;
+                       if (_fuel) {
+                               _fuel[index] = 0.0f;
+                               _react[index] = 0.0f;
+                       }
+                       if (_color_r) {
+                               _color_r[index] = 0.0f;
+                               _color_g[index] = 0.0f;
+                               _color_b[index] = 0.0f;
+                       }
 
                }
 
@@ -717,6 +865,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
                        _yVelocity[index] = 0.0f;
                        _zVelocity[index] = 0.0f;
                        _density[index] = 0.0f;
+                       if (_fuel) {
+                               _fuel[index] = 0.0f;
+                               _react[index] = 0.0f;
+                       }
+                       if (_color_r) {
+                               _color_r[index] = 0.0f;
+                               _color_g[index] = 0.0f;
+                               _color_b[index] = 0.0f;
+                       }
     }
 
        if (zEnd == _zRes)
@@ -735,6 +892,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
                                _yVelocity[indexx] = 0.0f;
                                _zVelocity[indexx] = 0.0f;
                                _density[indexx] = 0.0f;
+                               if (_fuel) {
+                                       _fuel[index] = 0.0f;
+                                       _react[index] = 0.0f;
+                               }
+                               if (_color_r) {
+                                       _color_r[index] = 0.0f;
+                                       _color_g[index] = 0.0f;
+                                       _color_b[index] = 0.0f;
+                               }
                        }
        }
 
@@ -781,35 +947,6 @@ void FLUID_3D::project()
        if(!_domainBcTop) setNeumannZ(_zVelocity, _res, 0, _zRes);
        else setZeroZ(_zVelocity, _res, 0, _zRes);
 
-       /*
-       {
-               float maxx = 0, maxy = 0, maxz = 0;
-               for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++)
-               {
-                       if(_xVelocity[i] > maxx)
-                               maxx = _xVelocity[i];
-                       if(_yVelocity[i] > maxy)
-                               maxy = _yVelocity[i];
-                       if(_zVelocity[i] > maxz)
-                               maxz = _zVelocity[i];
-               }
-               printf("Max velx: %f, vely: %f, velz: %f\n", maxx, maxy, maxz);
-       }
-       */
-
-       /*
-       {
-               float maxvalue = 0;
-               for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++)
-               {
-                       if(_heat[i] > maxvalue)
-                               maxvalue = _heat[i];
-
-               }
-               printf("Max heat: %f\n", maxvalue);
-       }
-       */
-
        // calculate divergence
        index = _slabSize + _xRes + 1;
        for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
@@ -1007,7 +1144,6 @@ void FLUID_3D::diffuseHeat()
        for (int x = 0; x < _totalCells; x++)
                if (_obstacles[x])
                        _heat[x] = 0.0f;
-
 }
 
 //////////////////////////////////////////////////////////////////////
@@ -1175,7 +1311,7 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
 //////////////////////////////////////////////////////////////////////
 // add buoyancy forces
 //////////////////////////////////////////////////////////////////////
-void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd)
+void FLUID_3D::addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd)
 {
        int index = zBegin*_slabSize;
 
@@ -1183,7 +1319,10 @@ void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd)
                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
+                               float buoyancy = *_alpha * density[index] + (*_beta * (((heat) ? heat[index] : 0.0f) - _tempAmb));
+                               _xForce[index] -= gravity[0] * buoyancy;
+                               _yForce[index] -= gravity[1] * buoyancy;
+                               _zForce[index] -= gravity[2] * buoyancy;
                        }
 }
 
@@ -1192,8 +1331,10 @@ void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd)
 //////////////////////////////////////////////////////////////////////
 void FLUID_3D::addVorticity(int zBegin, int zEnd)
 {
+       // set flame vorticity from RNA value
+       float flame_vorticity = (*_flame_vorticity)/_constantScaling;
        //int x,y,z,index;
-       if(_vorticityEps<=0.) return;
+       if(_vorticityEps+flame_vorticity<=0.) return;
 
        int _blockSize=zEnd-zBegin;
        int _blockTotalCells = _slabSize * (_blockSize+2);
@@ -1300,14 +1441,15 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
                                        float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
                                        if (magnitude > FLT_EPSILON)
                                        {
+                                               float flame_vort = (_fuel) ? _fuel[index]*flame_vorticity : 0.0f;
                                                magnitude = 1.0f / magnitude;
                                                N[0] *= magnitude;
                                                N[1] *= magnitude;
                                                N[2] *= magnitude;
 
-                                               _xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * eps;
-                                               _yForce[index] += (N[2] * _xVorticity[vIndex] - N[0] * _zVorticity[vIndex]) * _dx * eps;
-                                               _zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * eps;
+                                               _xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * (eps + flame_vort);
+                                               _yForce[index] += (N[2] * _xVorticity[vIndex] - N[0] * _zVorticity[vIndex]) * _dx * (eps + flame_vort);
+                                               _zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * (eps + flame_vort);
                                        }
                                        }       // if
                                        vIndex++;
@@ -1328,14 +1470,9 @@ void FLUID_3D::advectMacCormackBegin(int zBegin, int zEnd)
 {
        Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
 
-       if(!_domainBcLeft) copyBorderX(_xVelocityOld, res, zBegin, zEnd);
-       else setZeroX(_xVelocityOld, res, zBegin, zEnd);
-
-       if(!_domainBcFront) copyBorderY(_yVelocityOld, res, zBegin, zEnd);
-       else setZeroY(_yVelocityOld, res, zBegin, zEnd); 
-
-       if(!_domainBcTop) copyBorderZ(_zVelocityOld, res, zBegin, zEnd);
-       else setZeroZ(_zVelocityOld, res, zBegin, zEnd);
+       setZeroX(_xVelocityOld, res, zBegin, zEnd);
+       setZeroY(_yVelocityOld, res, zBegin, zEnd);
+       setZeroZ(_zVelocityOld, res, zBegin, zEnd);
 }
 
 //////////////////////////////////////////////////////////////////////
@@ -1355,7 +1492,18 @@ void FLUID_3D::advectMacCormackEnd1(int zBegin, int zEnd)
        // advectFieldMacCormack1(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res)
 
        advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _densityTemp, res, zBegin, zEnd);
-       advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heatTemp, res, zBegin, zEnd);
+       if (_heat) {
+               advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heatTemp, res, zBegin, zEnd);
+       }
+       if (_fuel) {
+               advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuelTemp, res, zBegin, zEnd);
+               advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _reactTemp, res, zBegin, zEnd);
+       }
+       if (_color_r) {
+               advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_rTemp, res, zBegin, zEnd);
+               advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_gTemp, res, zBegin, zEnd);
+               advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_bTemp, res, zBegin, zEnd);
+       }
        advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, res, zBegin, zEnd);
        advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, res, zBegin, zEnd);
        advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, res, zBegin, zEnd);
@@ -1371,17 +1519,30 @@ void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd)
        const float dt0 = _dt / _dx;
        Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
 
-       // use force array as temp arrays
+       // use force array as temp array
        float* t1 = _xForce;
 
        // advectFieldMacCormack2(dt, xVelocity, yVelocity, zVelocity, oldField, newField, tempfield, temp, res, obstacles)
 
+       /* finish advection */
        advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, _densityTemp, t1, res, _obstacles, zBegin, zEnd);
-       advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, _heatTemp, t1, res, _obstacles, zBegin, zEnd);
+       if (_heat) {
+               advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, _heatTemp, t1, res, _obstacles, zBegin, zEnd);
+       }
+       if (_fuel) {
+               advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuel, _fuelTemp, t1, res, _obstacles, zBegin, zEnd);
+               advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _react, _reactTemp, t1, res, _obstacles, zBegin, zEnd);
+       }
+       if (_color_r) {
+               advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_r, _color_rTemp, t1, res, _obstacles, zBegin, zEnd);
+               advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_g, _color_gTemp, t1, res, _obstacles, zBegin, zEnd);
+               advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_b, _color_bTemp, t1, res, _obstacles, zBegin, zEnd);
+       }
        advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocityTemp, _xVelocity, t1, res, _obstacles, zBegin, zEnd);
        advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocityTemp, _yVelocity, t1, res, _obstacles, zBegin, zEnd);
        advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocityTemp, _zVelocity, t1, res, _obstacles, zBegin, zEnd);
 
+       /* set boundary conditions for velocity */
        if(!_domainBcLeft) copyBorderX(_xVelocityTemp, res, zBegin, zEnd);
        else setZeroX(_xVelocityTemp, res, zBegin, zEnd);                               
 
@@ -1391,40 +1552,71 @@ void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd)
        if(!_domainBcTop) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd);
        else setZeroZ(_zVelocityTemp, res, zBegin, zEnd);
 
+       /* clear data boundaries */
        setZeroBorder(_density, res, zBegin, zEnd);
-       setZeroBorder(_heat, res, zBegin, zEnd);
-#if 0
-       {
-       const size_t index_ = _slabSize + _xRes + 1;
-       int bb=0;
-       int bt=0;
+       if (_fuel) {
+               setZeroBorder(_fuel, res, zBegin, zEnd);
+               setZeroBorder(_react, res, zBegin, zEnd);
+       }
+       if (_color_r) {
+               setZeroBorder(_color_r, res, zBegin, zEnd);
+               setZeroBorder(_color_g, res, zBegin, zEnd);
+               setZeroBorder(_color_b, res, zBegin, zEnd);
+       }
+}
 
-       if (zBegin == 0) {bb = 1;}
-       if (zEnd == _zRes) {bt = 1;}
-       
-       for (int z = zBegin + bb; z < zEnd - bt; z++)
+
+void FLUID_3D::processBurn(float *fuel, float *smoke, float *react, float *flame, float *heat,
+                                                  float *r, float *g, float *b, int total_cells, float dt)
+{
+       float burning_rate = *_burning_rate;
+       float flame_smoke = *_flame_smoke;
+       float ignition_point = *_ignition_temp;
+       float temp_max = *_max_temp;
+
+       for (int index = 0; index < total_cells; index++)
        {
-               size_t index = index_ +(z-1)*_slabSize;
+               float orig_fuel = fuel[index];
+               float orig_smoke = smoke[index];
+               float smoke_emit = 0.0f;
+               float react_coord = 0.0f;
+
+               /* process fuel */
+               fuel[index] -= burning_rate * dt;
+               if (fuel[index] < 0.0f) fuel[index] = 0.0f;
+               /* process reaction coordinate */
+               if (orig_fuel) {
+                       react[index] *= fuel[index]/orig_fuel;
+                       react_coord = react[index];
+               }
+               else {
+                       react[index] = 0.0f;
+               }
 
-               for (int y = 1; y < _yRes - 1; y++, index += 2)
-               {
-                       for (int x = 1; x < _xRes - 1; x++, index++)
-                       {
-                               // clean custom velocities from moving obstacles again
-                               if (_obstacles[index])
-                               {
-                                       _xVelocity[index] =
-                                       _yVelocity[index] =
-                                       _zVelocity[index] = 0.0f;
-                               }
-                       }
+               /* emit smoke based on fuel burn rate and "flame_smoke" factor */
+               smoke_emit = (orig_fuel < 1.0f) ? (1.0f - orig_fuel)*0.5f : 0.0f;
+               smoke_emit = (smoke_emit + 0.5f) * (orig_fuel-fuel[index]) * 0.1f * flame_smoke;
+               smoke[index] += smoke_emit;
+               CLAMP(smoke[index], 0.0f, 1.0f);
+
+               /* model flame temperature curve from the reaction coordinate (fuel) */
+               if (react_coord>0.0f) {
+                       /* do a smooth falloff for rest of the values */
+                       flame[index] = pow(react_coord, 0.5f);
+               }
+               else
+                       flame[index] = 0.0f;
+
+               /* set fluid temperature from the flame temperature profile */
+               if (heat && flame[index])
+                       heat[index] = (1.0f-flame[index])*ignition_point + flame[index]*temp_max;
+
+               /* mix new color */
+               if (r && smoke_emit) {
+                       float smoke_factor = smoke[index]/(orig_smoke+smoke_emit);
+                       r[index] = (r[index] + _flame_smoke_color[0] * smoke_emit) * smoke_factor;
+                       g[index] = (g[index] + _flame_smoke_color[1] * smoke_emit) * smoke_factor;
+                       b[index] = (b[index] + _flame_smoke_color[2] * smoke_emit) * smoke_factor;
                }
        }
-       }
-#endif
-
-       /*int begin=zBegin * _slabSize;
-       int end=begin + (zEnd - zBegin) * _slabSize;
-  for (int x = begin; x < end; x++)
-    _xForce[x] = _yForce[x] = 0.0f;*/
 }
index ac77148ce84f08916d6e658b9966579ffb9145f7..8cadf3bc9895135456946b15c81e73cc7f9104b4 100644 (file)
@@ -46,11 +46,16 @@ class WTURBULENCE;
 class FLUID_3D  
 {
        public:
-               FLUID_3D(int *res, /* int amplify, */ float *p0, float dtdef);
+               FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors);
                FLUID_3D() {};
                virtual ~FLUID_3D();
 
-               void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli);
+               void initHeat();
+               void initFire();
+               void initColors(float init_r, float init_g, float init_b);
+
+               void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
+                                                       float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *ignition_temp, float *max_temp);
                
                // create & allocate vector noise advection 
                void initVectorNoise(int amplify);
@@ -58,7 +63,7 @@ class FLUID_3D
                void addSmokeColumn();
                static void addSmokeTestCase(float* field, Vec3Int res);
 
-               void step(float dt);
+               void step(float dt, float gravity[3]);
                void addObstacle(OBSTACLE* obstacle);
 
                const float* xVelocity() { return _xVelocity; }; 
@@ -115,6 +120,27 @@ class FLUID_3D
                float* _heatTemp;
                float* _densityTemp;
 
+               // fire simulation
+               float *_flame;
+               float *_fuel;
+               float *_fuelTemp;
+               float *_fuelOld;
+               float *_react;
+               float *_reactTemp;
+               float *_reactOld;
+
+               // smoke color
+               float *_color_r;
+               float *_color_rOld;
+               float *_color_rTemp;
+               float *_color_g;
+               float *_color_gOld;
+               float *_color_gTemp;
+               float *_color_b;
+               float *_color_bOld;
+               float *_color_bTemp;
+
+
                // CG fields
                int _iterations;
 
@@ -153,14 +179,16 @@ class FLUID_3D
                void wipeBoundariesSL(int zBegin, int zEnd);
                void addForce(int zBegin, int zEnd);
                void addVorticity(int zBegin, int zEnd);
-               void addBuoyancy(float *heat, float *density, int zBegin, int zEnd);
+               void addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd);
 
                // solver stuff
                void project();
                void diffuseHeat();
+               void diffuseColor();
                void solvePressure(float* field, float* b, unsigned char* skip);
                void solvePressurePre(float* field, float* b, unsigned char* skip);
                void solveHeat(float* field, float* b, unsigned char* skip);
+               void solveDiffusion(float* field, float* b, float* factor);
 
 
                // handle obstacle boundaries
@@ -174,6 +202,16 @@ class FLUID_3D
                void advectMacCormackEnd1(int zBegin, int zEnd);
                void advectMacCormackEnd2(int zBegin, int zEnd);
 
+               /* burning */
+               float *_burning_rate; // RNA pointer
+               float *_flame_smoke; // RNA pointer
+               float *_flame_smoke_color; // RNA pointer
+               float *_flame_vorticity; // RNA pointer
+               float *_ignition_temp; // RNA pointer
+               float *_max_temp; // RNA pointer
+               void processBurn(float *fuel, float *smoke, float *react, float *flame, float *heat,
+                                                float *r, float *g, float *b, int total_cells, float dt);
+
                // boundary setting functions
                static void copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd);
                static void copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd);
index 3cf94eb00a918f157d4045f89322f977a3b51270..42a8b2d6923cf001b417aeaf3c82604eee09ff6b 100644 (file)
@@ -165,7 +165,6 @@ void FLUID_3D::solveHeat(float* field, float* b, unsigned char* skip)
        if (_Acenter)  delete[] _Acenter;
 }
 
-
 void FLUID_3D::solvePressurePre(float* field, float* b, unsigned char* skip)
 {
        int x, y, z;
index c7a0ddcd04c8811316fbdd35a713ddd962eff87b..ac485ad983a005d92748d9c5e94d7a28e6a87721 100644 (file)
@@ -92,18 +92,10 @@ void FLUID_3D::setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd)
                        // left slab
                        index = y * res[0] + z * slabSize;
                        field[index] = field[index + 2];
-                       /* only allow outwards flux */
-                       if(field[index]>0.) field[index] = 0.;
-                       index += 1;
-                       if(field[index]>0.) field[index] = 0.;
 
                        // right slab
                        index = y * res[0] + z * slabSize + res[0] - 1;
                        field[index] = field[index - 2];
-                       /* only allow outwards flux */
-                       if(field[index]<0.) field[index] = 0.;
-                       index -= 1;
-                       if(field[index]<0.) field[index] = 0.;
                }
  }
 
@@ -120,18 +112,10 @@ void FLUID_3D::setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd)
                        // front slab
                        index = x + z * slabSize;
                        field[index] = field[index + 2 * res[0]];
-                       /* only allow outwards flux */
-                       if(field[index]>0.) field[index] = 0.;
-                       index += res[0];
-                       if(field[index]>0.) field[index] = 0.;
 
                        // back slab
                        index = x + z * slabSize + slabSize - res[0];
                        field[index] = field[index - 2 * res[0]];
-                       /* only allow outwards flux */
-                       if(field[index]<0.) field[index] = 0.;
-                       index -= res[0];
-                       if(field[index]<0.) field[index] = 0.;
                }
 }
 
@@ -152,14 +136,6 @@ void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
                                // front slab
                                index = x + y * res[0];
                                field[index] = field[index + 2 * slabSize];
-                               /* only allow outwards flux */
-
-                               // DG: Disable this for z-axis.
-                               // The problem is that smoke somehow gets sucked in again
-                               // from the TOP slab when this is enabled
-                               // if(field[index]>0.) field[index] = 0.;
-                               // index += slabSize;
-                               // if(field[index]>0.) field[index] = 0.;
                        }
        }
 
@@ -170,10 +146,6 @@ void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
                                // back slab
                                index = x + y * res[0] + cellsslab;
                                field[index] = field[index - 2 * slabSize];
-                               /* only allow outwards flux */
-                               if(field[index]<0.) field[index] = 0.;
-                               index -= slabSize;
-                               if(field[index]<0.) field[index] = 0.;
                        }
        }
                
index 671198065e8af0bb389dc1b6294ed36c9d56a1fb..1c89f5d681bcaeb0fef1d895753d2f9f8c710276 100644 (file)
@@ -51,7 +51,7 @@ static const float persistence = 0.56123f;
 //////////////////////////////////////////////////////////////////////
 // constructor
 //////////////////////////////////////////////////////////////////////
-WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype)
+WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, int init_fire, int init_colors)
 {
        // if noise magnitude is below this threshold, its contribution
        // is negilgible, so stop evaluating new octaves
@@ -87,12 +87,26 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
        // allocate high resolution density field
        _totalStepsBig = 0;
        _densityBig = new float[_totalCellsBig];
-       _densityBigOld = new float[_totalCellsBig]; 
+       _densityBigOld = new float[_totalCellsBig];
        
        for(int i = 0; i < _totalCellsBig; i++) {
                _densityBig[i] = 
                _densityBigOld[i] = 0.;
        }
+
+       /* fire */
+       _flameBig = _fuelBig = _fuelBigOld = NULL;
+       _reactBig = _reactBigOld = NULL;
+       if (init_fire) {
+               initFire();
+       }
+       /* colors */
+       _color_rBig = _color_rBigOld = NULL;
+       _color_gBig = _color_gBigOld = NULL;
+       _color_bBig = _color_bBigOld = NULL;
+       if (init_colors) {
+               initColors(0.0f, 0.0f, 0.0f);
+       }
        
        // allocate & init texture coordinates
        _tcU = new float[_totalCellsSm];
@@ -128,12 +142,64 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
        */
 }
 
+void WTURBULENCE::initFire()
+{
+       if (!_fuelBig) {
+               _flameBig = new float[_totalCellsBig];
+               _fuelBig = new float[_totalCellsBig];
+               _fuelBigOld = new float[_totalCellsBig];
+               _reactBig = new float[_totalCellsBig];
+               _reactBigOld = new float[_totalCellsBig];
+
+               for(int i = 0; i < _totalCellsBig; i++) {
+                       _flameBig[i] = 
+                       _fuelBig[i] = 
+                       _fuelBigOld[i] = 0.;
+                       _reactBig[i] = 
+                       _reactBigOld[i] = 0.;
+               }
+       }
+}
+
+void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
+{
+       if (!_color_rBig) {
+               _color_rBig = new float[_totalCellsBig];
+               _color_rBigOld = new float[_totalCellsBig];
+               _color_gBig = new float[_totalCellsBig];
+               _color_gBigOld = new float[_totalCellsBig];
+               _color_bBig = new float[_totalCellsBig];
+               _color_bBigOld = new float[_totalCellsBig];
+
+               for(int i = 0; i < _totalCellsBig; i++) {
+                       _color_rBig[i] = _densityBig[i] * init_r;
+                       _color_rBigOld[i] = 0.0f;
+                       _color_gBig[i] = _densityBig[i] * init_g;
+                       _color_gBigOld[i] = 0.0f;
+                       _color_bBig[i] = _densityBig[i] * init_b;
+                       _color_bBigOld[i] = 0.0f;
+               }
+       }
+}
+
 //////////////////////////////////////////////////////////////////////
 // destructor
 //////////////////////////////////////////////////////////////////////
 WTURBULENCE::~WTURBULENCE() {
   delete[] _densityBig;
   delete[] _densityBigOld;
+  if (_flameBig) delete[] _flameBig;
+  if (_fuelBig) delete[] _fuelBig;
+  if (_fuelBigOld) delete[] _fuelBigOld;
+  if (_reactBig) delete[] _reactBig;
+  if (_reactBigOld) delete[] _reactBigOld;
+
+  if (_color_rBig) delete[] _color_rBig;
+  if (_color_rBigOld) delete[] _color_rBigOld;
+  if (_color_gBig) delete[] _color_gBig;
+  if (_color_gBigOld) delete[] _color_gBigOld;
+  if (_color_bBig) delete[] _color_bBig;
+  if (_color_bBigOld) delete[] _color_bBigOld;
 
   delete[] _tcU;
   delete[] _tcV;
@@ -757,8 +823,10 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
        // enlarge timestep to match grid
        const float dt = dtOrg * _amplify;
        const float invAmp = 1.0f / _amplify;
-       float *tempBig1 = (float *)calloc(_totalCellsBig, sizeof(float));
-       float *tempBig2 = (float *)calloc(_totalCellsBig, sizeof(float));
+       float *tempFuelBig = NULL, *tempReactBig = NULL;
+       float *tempColor_rBig = NULL, *tempColor_gBig = NULL, *tempColor_bBig = NULL;
+       float *tempDensityBig = (float *)calloc(_totalCellsBig, sizeof(float));
+       float *tempBig = (float *)calloc(_totalCellsBig, sizeof(float));
        float *bigUx = (float *)calloc(_totalCellsBig, sizeof(float));
        float *bigUy = (float *)calloc(_totalCellsBig, sizeof(float));
        float *bigUz = (float *)calloc(_totalCellsBig, sizeof(float)); 
@@ -767,11 +835,21 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
        float *eigMin  = (float *)calloc(_totalCellsSm, sizeof(float));
        float *eigMax  = (float *)calloc(_totalCellsSm, sizeof(float));
 
+       if (_fuelBig) {
+               tempFuelBig = (float *)calloc(_totalCellsBig, sizeof(float));
+               tempReactBig = (float *)calloc(_totalCellsBig, sizeof(float));
+       }
+       if (_color_rBig) {
+               tempColor_rBig = (float *)calloc(_totalCellsBig, sizeof(float));
+               tempColor_gBig = (float *)calloc(_totalCellsBig, sizeof(float));
+               tempColor_bBig = (float *)calloc(_totalCellsBig, sizeof(float));
+       }
+
        memset(_tcTemp, 0, sizeof(float)*_totalCellsSm);
 
 
        // prepare textures
-       advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2);
+       advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempDensityBig, tempBig);
 
        // do wavelet decomposition of energy
        computeEnergy(_energy, xvel, yvel, zvel, obstacles);
@@ -972,6 +1050,11 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
 
   // prepare density for an advection
   SWAP_POINTERS(_densityBig, _densityBigOld);
+  SWAP_POINTERS(_fuelBig, _fuelBigOld);
+  SWAP_POINTERS(_reactBig, _reactBigOld);
+  SWAP_POINTERS(_color_rBig, _color_rBigOld);
+  SWAP_POINTERS(_color_gBig, _color_gBigOld);
+  SWAP_POINTERS(_color_bBig, _color_bBigOld);
 
   // based on the maximum velocity present, see if we need to substep,
   // but cap the maximum number of substeps to 5
@@ -1017,7 +1100,21 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
                int zEnd = (int)((float)(i+1)*partSize + 0.5f);
 #endif
                FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 
-                   _densityBigOld, tempBig1, _resBig, zBegin, zEnd);
+                   _densityBigOld, tempDensityBig, _resBig, zBegin, zEnd);
+               if (_fuelBig) {
+                       FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _fuelBigOld, tempFuelBig, _resBig, zBegin, zEnd);
+                       FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _reactBigOld, tempReactBig, _resBig, zBegin, zEnd);
+               }
+               if (_color_rBig) {
+                       FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _color_rBigOld, tempColor_rBig, _resBig, zBegin, zEnd);
+                       FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _color_gBigOld, tempColor_gBig, _resBig, zBegin, zEnd);
+                       FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _color_bBigOld, tempColor_bBig, _resBig, zBegin, zEnd);
+               }
 #if PARALLEL==1
        }
 
@@ -1030,18 +1127,43 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
                int zEnd = (int)((float)(i+1)*partSize + 0.5f);
 #endif
                FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 
-                   _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL, zBegin, zEnd);
+                   _densityBigOld, _densityBig, tempDensityBig, tempBig, _resBig, NULL, zBegin, zEnd);
+               if (_fuelBig) {
+                       FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _fuelBigOld, _fuelBig, tempFuelBig, tempBig, _resBig, NULL, zBegin, zEnd);
+                       FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _reactBigOld, _reactBig, tempReactBig, tempBig, _resBig, NULL, zBegin, zEnd);
+               }
+               if (_color_rBig) {
+                       FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _color_rBigOld, _color_rBig, tempColor_rBig, tempBig, _resBig, NULL, zBegin, zEnd);
+                       FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _color_gBigOld, _color_gBig, tempColor_gBig, tempBig, _resBig, NULL, zBegin, zEnd);
+                       FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 
+                               _color_bBigOld, _color_bBig, tempColor_bBig, tempBig, _resBig, NULL, zBegin, zEnd);
+               }
 #if PARALLEL==1
        }
        }
 #endif
 
-    if (substep < totalSubsteps - 1) 
+       if (substep < totalSubsteps - 1) {
       SWAP_POINTERS(_densityBig, _densityBigOld);
+         SWAP_POINTERS(_fuelBig, _fuelBigOld);
+         SWAP_POINTERS(_reactBig, _reactBigOld);
+         SWAP_POINTERS(_color_rBig, _color_rBigOld);
+         SWAP_POINTERS(_color_gBig, _color_gBigOld);
+         SWAP_POINTERS(_color_bBig, _color_bBigOld);
+       }
   } // substep
 
-  free(tempBig1);
-  free(tempBig2);
+  free(tempDensityBig);
+  if (tempFuelBig) free(tempFuelBig);
+  if (tempReactBig) free(tempReactBig);
+  if (tempColor_rBig) free(tempColor_rBig);
+  if (tempColor_gBig) free(tempColor_gBig);
+  if (tempColor_bBig) free(tempColor_bBig);
+  free(tempBig);
   free(bigUx);
   free(bigUy);
   free(bigUz);
@@ -1050,6 +1172,15 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
   
   // wipe the density borders
   FLUID_3D::setZeroBorder(_densityBig, _resBig, 0 , _resBig[2]);
+  if (_fuelBig) {
+       FLUID_3D::setZeroBorder(_fuelBig, _resBig, 0 , _resBig[2]);
+       FLUID_3D::setZeroBorder(_reactBig, _resBig, 0 , _resBig[2]);
+  }
+  if (_color_rBig) {
+         FLUID_3D::setZeroBorder(_color_rBig, _resBig, 0 , _resBig[2]);
+         FLUID_3D::setZeroBorder(_color_gBig, _resBig, 0 , _resBig[2]);
+         FLUID_3D::setZeroBorder(_color_bBig, _resBig, 0 , _resBig[2]);
+  }
     
   // reset texture coordinates now in preparation for next timestep
   // Shouldn't do this before generating the noise because then the 
index f31ca100fdff3c345fa6293c04e2cb2faac6f1b0..1655bd95d3279827c73dcc492e6fb25952bfcd4f 100644 (file)
@@ -36,10 +36,13 @@ class WTURBULENCE
 {
        public:
                // both config files can be NULL, altCfg might override values from noiseCfg
-               WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype);
+               WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, int init_fire, int init_colors);
 
                /// destructor
                virtual ~WTURBULENCE();
+
+               void initFire();
+               void initColors(float init_r, float init_g, float init_b);
                
                void setNoise(int type);
                void initBlenderRNA(float *strength);
@@ -63,6 +66,8 @@ class WTURBULENCE
 
                // access functions
                inline float* getDensityBig() { return _densityBig; }
+               inline float* getFlameBig() { return _flameBig; }
+               inline float* getFuelBig() { return _fuelBig; }
                inline float* getArrayTcU() { return _tcU; }
                inline float* getArrayTcV() { return _tcV; }
                inline float* getArrayTcW() { return _tcW; }
@@ -111,6 +116,18 @@ class WTURBULENCE
 
                float* _densityBig;
                float* _densityBigOld;
+               float* _flameBig;
+               float* _fuelBig;
+               float* _fuelBigOld;
+               float* _reactBig;
+               float* _reactBigOld;
+
+               float* _color_rBig;
+               float* _color_rBigOld;
+               float* _color_gBig;
+               float* _color_gBigOld;
+               float* _color_bBig;
+               float* _color_bBigOld;
 
                // texture coordinates for noise
                float* _tcU;
index 4bbf8e0a82b67eea03ade9101cac187d9b2cef33..e51c317669954ba0d6a7aee7d2c8ad091d0c2e1d 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "FLUID_3D.h"
 #include "WTURBULENCE.h"
+#include "spectrum.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "../extern/smoke_API.h"  /* to ensure valid prototypes */
 
-// y in smoke is z in blender
-extern "C" FLUID_3D *smoke_init(int *res, float *p0, float dtdef)
+extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors)
 {
-       // smoke lib uses y as top-bottom/vertical axis where blender uses z
-       FLUID_3D *fluid = new FLUID_3D(res, p0, dtdef);
-
-       // printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]);
-
+       FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors);
        return fluid;
 }
 
-extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype)
+extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, int use_fire, int use_colors)
 {
-       // initialize wavelet turbulence
        if(amplify)
-               return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype);
+               return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, use_fire, use_colors);
        else 
                return NULL;
 }
@@ -71,7 +66,6 @@ extern "C" void smoke_turbulence_free(WTURBULENCE *wt)
 
 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;
 }
 
@@ -80,137 +74,134 @@ extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z
        return x + y * max_x;
 }
 
-extern "C" void smoke_step(FLUID_3D *fluid, float dtSubdiv)
+extern "C" void smoke_step(FLUID_3D *fluid, float gravity[3], float dtSubdiv)
 {
-       fluid->step(dtSubdiv);
+       if (fluid->_fuel) {
+               fluid->processBurn(fluid->_fuel, fluid->_density, fluid->_react, fluid->_flame, fluid->_heat,
+                                                  fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, (*fluid->_dtFactor)*dtSubdiv);
+       }
+       fluid->step(dtSubdiv, gravity);
 }
 
 extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid)
 {
+       if (wt->_fuelBig) {
+               fluid->processBurn(wt->_fuelBig, wt->_densityBig, wt->_reactBig, wt->_flameBig, 0,
+                                                  wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, fluid->_dt);
+       }
        wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles); 
 }
 
-extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli)
+extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
+                                                                        float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
 {
-       fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli);
+       fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli, burning_rate, flame_smoke, flame_smoke_color, flame_vorticity, flame_ignition_temp, flame_max_temp);
 }
 
-extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
+extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
 {
-       float *density = fluid->_density;
-       //float *densityOld = fluid->_densityOld;
-       float *heat = fluid->_heat;
+       wt->initBlenderRNA(strength);
+}
 
+static void data_dissolve(float *density, float *heat, float *r, float *g, float *b, int total_cells, int speed, int log)
+{
        if(log)
        {
                /* max density/speed = dydx */
-               float dydx = 1.0 / (float)speed;
-               size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
+               float fac = 1.0f - (1.0f / (float)speed);
 
-               for(size_t i = 0; i < size; i++)
+               for(size_t i = 0; i < total_cells; i++)
                {
-                       density[i] *= (1.0 - dydx);
-
-                       if(density[i] < 0.0f)
-                               density[i] = 0.0f;
-
-                       heat[i] *= (1.0 - dydx);
-
-                       /*if(heat[i] < 0.0f)
-                               heat[i] = 0.0f;*/
+                       /* density */
+                       density[i] *= fac;
+
+                       /* heat */
+                       if (heat) {
+                               heat[i] *= fac;
+                       }
+
+                       /* color */
+                       if (r) {
+                               r[i] *= fac;
+                               g[i] *= fac;
+                               b[i] *= fac;
+                       }
                }
        }
        else // linear falloff
        {
                /* max density/speed = dydx */
-               float dydx = 1.0 / (float)speed;
-               size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
+               float dydx = 1.0f / (float)speed;
 
-               for(size_t i = 0; i < size; i++)
+               for(size_t i = 0; i < total_cells; i++)
                {
+                       float d = density[i];
+                       /* density */
                        density[i] -= dydx;
-
                        if(density[i] < 0.0f)
                                density[i] = 0.0f;
 
-                       if(abs(heat[i]) < dydx) heat[i] = 0.0f;
-                       else if (heat[i]>0.0f) heat[i] -= dydx;
-                       else if (heat[i]<0.0f) heat[i] += dydx;
+                       /* heat */
+                       if (heat) {
+                               if(abs(heat[i]) < dydx) heat[i] = 0.0f;
+                               else if (heat[i]>0.0f) heat[i] -= dydx;
+                               else if (heat[i]<0.0f) heat[i] += dydx;
+                       }
+
+                       /* color */
+                       if (r && d) {
+                               r[i] *= (density[i]/d);
+                               g[i] *= (density[i]/d);
+                               b[i] *= (density[i]/d);
+                       }
                                
                }
        }
 }
 
-extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
-{
-       float *density = wt->getDensityBig();
-       Vec3Int r = wt->getResBig();
-
-       if(log)
-       {
-               /* max density/speed = dydx */
-               float dydx = 1.0 / (float)speed;
-               size_t size= r[0] * r[1] * r[2];
-
-               for(size_t i = 0; i < size; i++)
-               {
-                       density[i] *= (1.0 - dydx);
-
-                       if(density[i] < 0.0f)
-                               density[i] = 0.0f;
-               }
-       }
-       else // linear falloff
-       {
-               /* max density/speed = dydx */
-               float dydx = 1.0 / (float)speed;
-               size_t size= r[0] * r[1] * r[2];
-
-               for(size_t i = 0; i < size; i++)
-               {
-                       density[i] -= dydx;
-
-                       if(density[i] < 0.0f)
-                               density[i] = 0.0f;                              
-               }
-       }
-}
-
-extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
+extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
 {
-       wt->initBlenderRNA(strength);
+       data_dissolve(fluid->_density, fluid->_heat, fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, speed, log);
 }
 
-template < class T > inline T ABS( T a )
+extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
 {
-       return (0 < a) ? a : -a ;
+       data_dissolve(wt->_densityBig, 0, wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, speed, log);
 }
 
-extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles)
+extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat, 
+                                                        float **heatold, float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles)
 {
        *dens = fluid->_density;
-       *densold = fluid->_densityOld;
+       *fuel = fluid->_fuel;
+       *react = fluid->_react;
+       *flame = fluid->_flame;
        *heat = fluid->_heat;
        *heatold = fluid->_heatOld;
        *vx = fluid->_xVelocity;
        *vy = fluid->_yVelocity;
        *vz = fluid->_zVelocity;
-       *vxold = fluid->_xVelocityOld;
-       *vyold = fluid->_yVelocityOld;
-       *vzold = fluid->_zVelocityOld;
+       *r = fluid->_color_r;
+       *g = fluid->_color_g;
+       *b = fluid->_color_b;
        *obstacles = fluid->_obstacles;
        *dt = fluid->_dt;
        *dx = fluid->_dx;
-
 }
 
-extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **densold, float **tcu, float **tcv, float **tcw)
+extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
+                                                                               float **r, float **g, float **b , float **tcu, float **tcv, float **tcw)
 {
        if(!wt)
                return;
 
        *dens = wt->_densityBig;
-       *densold = wt->_densityBigOld;
+       *fuel = wt->_fuelBig;
+       *react = wt->_reactBig;
+       *flame = wt->_flameBig;
+       *r = wt->_color_rBig;
+       *g = wt->_color_gBig;
+       *b = wt->_color_bBig;
        *tcu = wt->_tcU;
        *tcv = wt->_tcV;
        *tcw = wt->_tcW;
@@ -221,6 +212,16 @@ extern "C" float *smoke_get_density(FLUID_3D *fluid)
        return fluid->_density;
 }
 
+extern "C" float *smoke_get_fuel(FLUID_3D *fluid)
+{
+       return fluid->_fuel;
+}
+
+extern "C" float *smoke_get_react(FLUID_3D *fluid)
+{
+       return fluid->_react;
+}
+
 extern "C" float *smoke_get_heat(FLUID_3D *fluid)
 {
        return fluid->_heat;
@@ -256,15 +257,137 @@ extern "C" float *smoke_get_force_z(FLUID_3D *fluid)
        return fluid->_zForce;
 }
 
+extern "C" float *smoke_get_flame(FLUID_3D *fluid)
+{
+       return fluid->_flame;
+}
+
+extern "C" float *smoke_get_color_r(FLUID_3D *fluid)
+{
+       return fluid->_color_r;
+}
+
+extern "C" float *smoke_get_color_g(FLUID_3D *fluid)
+{
+       return fluid->_color_g;
+}
+
+extern "C" float *smoke_get_color_b(FLUID_3D *fluid)
+{
+       return fluid->_color_b;
+}
+
+static void get_rgba(float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
+{
+       int i;
+       int m = 4, i_g = 1, i_b = 2, i_a = 3;
+       /* sequential data */
+       if (sequential) {
+               m = 1;
+               i_g *= total_cells;
+               i_b *= total_cells;
+               i_a *= total_cells;
+       }
+
+       for (i=0; i<total_cells; i++) {
+               float alpha = a[i];
+               if (alpha) {
+                       data[i*m  ] = r[i];
+                       data[i*m+i_g] = g[i];
+                       data[i*m+i_b] = b[i];
+               }
+               else {
+                       data[i*m  ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
+               }
+               data[i*m+i_a] = alpha;
+       }
+}
+
+extern "C" void smoke_get_rgba(FLUID_3D *fluid, float *data, int sequential)
+{
+       get_rgba(fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_density, fluid->_totalCells, data, sequential);
+}
+
+extern "C" void smoke_turbulence_get_rgba(WTURBULENCE *wt, float *data, int sequential)
+{
+       get_rgba(wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_densityBig, wt->_totalCellsBig, data, sequential);
+}
+
+/* get a single color premultiplied voxel grid */
+static void get_rgba_from_density(float color[3], float *a, int total_cells, float *data, int sequential)
+{
+       int i;
+       int m = 4, i_g = 1, i_b = 2, i_a = 3;
+       /* sequential data */
+       if (sequential) {
+               m = 1;
+               i_g *= total_cells;
+               i_b *= total_cells;
+               i_a *= total_cells;
+       }
+
+       for (i=0; i<total_cells; i++) {
+               float alpha = a[i];
+               if (alpha) {
+                       data[i*m  ] = color[0] * alpha;
+                       data[i*m+i_g] = color[1] * alpha;
+                       data[i*m+i_b] = color[2] * alpha;
+               }
+               else {
+                       data[i*m  ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
+               }
+               data[i*m+i_a] = alpha;
+       }
+}
+
+extern "C" void smoke_get_rgba_from_density(FLUID_3D *fluid, float color[3], float *data, int sequential)
+{
+       get_rgba_from_density(color, fluid->_density, fluid->_totalCells, data, sequential);
+}
+
+extern "C" void smoke_turbulence_get_rgba_from_density(WTURBULENCE *wt, float color[3], float *data, int sequential)
+{
+       get_rgba_from_density(color, wt->_densityBig, wt->_totalCellsBig, data, sequential);
+}
+
 extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt)
 {
        return wt ? wt->getDensityBig() : NULL;
 }
 
+extern "C" float *smoke_turbulence_get_fuel(WTURBULENCE *wt)
+{
+       return wt ? wt->getFuelBig() : NULL;
+}
+
+extern "C" float *smoke_turbulence_get_react(WTURBULENCE *wt)
+{
+       return wt ? wt->_reactBig : NULL;
+}
+
+extern "C" float *smoke_turbulence_get_color_r(WTURBULENCE *wt)
+{
+       return wt ? wt->_color_rBig : NULL;
+}
+
+extern "C" float *smoke_turbulence_get_color_g(WTURBULENCE *wt)
+{
+       return wt ? wt->_color_gBig : NULL;
+}
+
+extern "C" float *smoke_turbulence_get_color_b(WTURBULENCE *wt)
+{
+       return wt ? wt->_color_bBig : NULL;
+}
+
+extern "C" float *smoke_turbulence_get_flame(WTURBULENCE *wt)
+{
+       return wt ? wt->getFlameBig() : NULL;
+}
+
 extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
 {
-       if(wt)
-       {
+       if(wt) {
                Vec3Int r = wt->getResBig();
                res[0] = r[0];
                res[1] = r[1];
@@ -272,6 +395,15 @@ extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
        }
 }
 
+extern "C" int smoke_turbulence_get_cells(WTURBULENCE *wt)
+{
+       if(wt) {
+               Vec3Int r = wt->getResBig();
+               return r[0]*r[1]*r[2];
+       }
+       return 0;
+}
+
 extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
 {
        return fluid->_obstacles;
@@ -295,3 +427,61 @@ extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type)
 {
        wt->setNoise(type);
 }
+
+extern "C" void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2)
+{
+       spectrum(t1, t2, width, spec);
+}
+
+extern "C" int smoke_has_heat(FLUID_3D *fluid)
+{
+       return (fluid->_heat) ? 1 : 0;
+}
+
+extern "C" int smoke_has_fuel(FLUID_3D *fluid)
+{
+       return (fluid->_fuel) ? 1 : 0;
+}
+
+extern "C" int smoke_has_colors(FLUID_3D *fluid)
+{
+       return (fluid->_color_r && fluid->_color_g && fluid->_color_b) ? 1 : 0;
+}
+
+extern "C" int smoke_turbulence_has_fuel(WTURBULENCE *wt)
+{
+       return (wt->_fuelBig) ? 1 : 0;
+}
+
+extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
+{
+       return (wt->_color_rBig && wt->_color_gBig && wt->_color_bBig) ? 1 : 0;
+}
+
+/* additional field initialization */
+extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
+{
+       if (fluid) {
+               fluid->initHeat();
+       }
+}
+
+extern "C" void smoke_ensure_fire(FLUID_3D *fluid, WTURBULENCE *wt)
+{
+       if (fluid) {
+               fluid->initFire();
+       }
+       if (wt) {
+               wt->initFire();
+       }
+}
+
+extern "C" void smoke_ensure_colors(FLUID_3D *fluid, WTURBULENCE *wt, float init_r, float init_g, float init_b)
+{
+       if (fluid) {
+               fluid->initColors(init_r, init_g, init_b);
+       }
+       if (wt) {
+               wt->initColors(init_r, init_g, init_b);
+       }
+}
\ No newline at end of file
diff --git a/intern/smoke/intern/spectrum.cpp b/intern/smoke/intern/spectrum.cpp
new file mode 100644 (file)
index 0000000..34725c1
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+                Colour Rendering of Spectra
+
+                       by John Walker
+                  http://www.fourmilab.ch/
+                 
+                Last updated: March 9, 2003
+
+           This program is in the public domain.
+
+    For complete information about the techniques employed in
+    this program, see the World-Wide Web document:
+
+             http://www.fourmilab.ch/documents/specrend/
+            
+    The xyz_to_rgb() function, which was wrong in the original
+    version of this program, was corrected by:
+    
+           Andrew J. S. Hamilton 21 May 1999
+           Andrew.Hamilton@Colorado.EDU
+           http://casa.colorado.edu/~ajsh/
+
+    who also added the gamma correction facilities and
+    modified constrain_rgb() to work by desaturating the
+    colour by adding white.
+    
+    A program which uses these functions to plot CIE
+    "tongue" diagrams called "ppmcie" is included in
+    the Netpbm graphics toolkit:
+       http://netpbm.sourceforge.net/
+    (The program was called cietoppm in earlier
+    versions of Netpbm.)
+
+*/
+
+#include <stdio.h>
+#include <math.h>
+
+/* A colour system is defined by the CIE x and y coordinates of
+   its three primary illuminants and the x and y coordinates of
+   the white point. */
+
+struct colourSystem {
+    char *name;                    /* Colour system name */
+    double xRed, yRed,             /* Red x, y */
+           xGreen, yGreen,         /* Green x, y */
+           xBlue, yBlue,           /* Blue x, y */
+           xWhite, yWhite,         /* White point x, y */
+          gamma;                   /* Gamma correction for system */
+};
+
+/* White point chromaticities. */
+
+#define IlluminantC     0.3101, 0.3162         /* For NTSC television */
+#define IlluminantD65   0.3127, 0.3291         /* For EBU and SMPTE */
+#define IlluminantE    0.33333333, 0.33333333  /* CIE equal-energy illuminant */
+
+/*  Gamma of nonlinear correction.
+
+    See Charles Poynton's ColorFAQ Item 45 and GammaFAQ Item 6 at:
+    
+       http://www.poynton.com/ColorFAQ.html
+       http://www.poynton.com/GammaFAQ.html
+*/
+
+#define GAMMA_REC709   0               /* Rec. 709 */
+
+static struct colourSystem
+                  /* Name                  xRed    yRed    xGreen  yGreen  xBlue  yBlue    White point        Gamma   */
+    NTSCsystem  =  { "NTSC",               0.67,   0.33,   0.21,   0.71,   0.14,   0.08,   IlluminantC,    GAMMA_REC709 },
+    EBUsystem   =  { "EBU (PAL/SECAM)",    0.64,   0.33,   0.29,   0.60,   0.15,   0.06,   IlluminantD65,  GAMMA_REC709 },
+    SMPTEsystem =  { "SMPTE",              0.630,  0.340,  0.310,  0.595,  0.155,  0.070,  IlluminantD65,  GAMMA_REC709 },
+    HDTVsystem  =  { "HDTV",               0.670,  0.330,  0.210,  0.710,  0.150,  0.060,  IlluminantD65,  GAMMA_REC709 },
+    CIEsystem   =  { "CIE",                0.7355, 0.2645, 0.2658, 0.7243, 0.1669, 0.0085, IlluminantE,    GAMMA_REC709 },
+    Rec709system = { "CIE REC 709",        0.64,   0.33,   0.30,   0.60,   0.15,   0.06,   IlluminantD65,  GAMMA_REC709 };
+
+/*                         UPVP_TO_XY
+
+    Given 1976 coordinates u', v', determine 1931 chromaticities x, y
+    
+*/
+
+void upvp_to_xy(double up, double vp, double *xc, double *yc)
+{
+    *xc = (9 * up) / ((6 * up) - (16 * vp) + 12);
+    *yc = (4 * vp) / ((6 * up) - (16 * vp) + 12);
+}
+
+/*                         XY_TO_UPVP
+
+    Given 1931 chromaticities x, y, determine 1976 coordinates u', v'
+    
+*/
+
+void xy_to_upvp(double xc, double yc, double *up, double *vp)
+{
+    *up = (4 * xc) / ((-2 * xc) + (12 * yc) + 3);
+    *vp = (9 * yc) / ((-2 * xc) + (12 * yc) + 3);
+}
+
+/*                             XYZ_TO_RGB
+
+    Given an additive tricolour system CS, defined by the CIE x
+    and y chromaticities of its three primaries (z is derived
+    trivially as 1-(x+y)), and a desired chromaticity (XC, YC,
+    ZC) in CIE space, determine the contribution of each
+    primary in a linear combination which sums to the desired
+    chromaticity.  If the  requested chromaticity falls outside
+    the Maxwell  triangle (colour gamut) formed by the three
+    primaries, one of the r, g, or b weights will be negative. 
+
+    Caller can use constrain_rgb() to desaturate an
+    outside-gamut colour to the closest representation within
+    the available gamut and/or norm_rgb to normalise the RGB
+    components so the largest nonzero component has value 1.
+    
+*/
+
+void xyz_to_rgb(struct colourSystem *cs,
+                double xc, double yc, double zc,
+                double *r, double *g, double *b)
+{
+    double xr, yr, zr, xg, yg, zg, xb, yb, zb;
+    double xw, yw, zw;
+    double rx, ry, rz, gx, gy, gz, bx, by, bz;
+    double rw, gw, bw;
+
+    xr = cs->xRed;    yr = cs->yRed;    zr = 1 - (xr + yr);
+    xg = cs->xGreen;  yg = cs->yGreen;  zg = 1 - (xg + yg);
+    xb = cs->xBlue;   yb = cs->yBlue;   zb = 1 - (xb + yb);
+
+    xw = cs->xWhite;  yw = cs->yWhite;  zw = 1 - (xw + yw);
+
+    /* xyz -> rgb matrix, before scaling to white. */
+    
+    rx = (yg * zb) - (yb * zg);  ry = (xb * zg) - (xg * zb);  rz = (xg * yb) - (xb * yg);
+    gx = (yb * zr) - (yr * zb);  gy = (xr * zb) - (xb * zr);  gz = (xb * yr) - (xr * yb);
+    bx = (yr * zg) - (yg * zr);  by = (xg * zr) - (xr * zg);  bz = (xr * yg) - (xg * yr);
+
+    /* White scaling factors.
+       Dividing by yw scales the white luminance to unity, as conventional. */
+       
+    rw = ((rx * xw) + (ry * yw) + (rz * zw)) / yw;
+    gw = ((gx * xw) + (gy * yw) + (gz * zw)) / yw;
+    bw = ((bx * xw) + (by * yw) + (bz * zw)) / yw;
+
+    /* xyz -> rgb matrix, correctly scaled to white. */
+    
+    rx = rx / rw;  ry = ry / rw;  rz = rz / rw;
+    gx = gx / gw;  gy = gy / gw;  gz = gz / gw;
+    bx = bx / bw;  by = by / bw;  bz = bz / bw;
+
+    /* rgb of the desired point */
+
+    *r = (rx * xc) + (ry * yc) + (rz * zc);
+    *g = (gx * xc) + (gy * yc) + (gz * zc);
+    *b = (bx * xc) + (by * yc) + (bz * zc);
+}
+
+/*                            INSIDE_GAMUT
+
+     Test whether a requested colour is within the gamut
+     achievable with the primaries of the current colour
+     system.  This amounts simply to testing whether all the
+     primary weights are non-negative. */
+
+int inside_gamut(double r, double g, double b)
+{
+    return (r >= 0) && (g >= 0) && (b >= 0);
+}
+
+/*                          CONSTRAIN_RGB
+
+    If the requested RGB shade contains a negative weight for
+    one of the primaries, it lies outside the colour gamut 
+    accessible from the given triple of primaries.  Desaturate
+    it by adding white, equal quantities of R, G, and B, enough
+    to make RGB all positive.  The function returns 1 if the
+    components were modified, zero otherwise.
+    
+*/
+
+int constrain_rgb(double *r, double *g, double *b)
+{
+    double w;
+
+    /* Amount of white needed is w = - min(0, *r, *g, *b) */
+    
+    w = (0 < *r) ? 0 : *r;
+    w = (w < *g) ? w : *g;
+    w = (w < *b) ? w : *b;
+    w = -w;
+
+    /* Add just enough white to make r, g, b all positive. */
+    
+    if (w > 0) {
+        *r += w;  *g += w; *b += w;
+        return 1;                     /* Colour modified to fit RGB gamut */
+    }
+
+    return 0;                         /* Colour within RGB gamut */
+}
+
+/*                          GAMMA_CORRECT_RGB
+
+    Transform linear RGB values to nonlinear RGB values. Rec.
+    709 is ITU-R Recommendation BT. 709 (1990) ``Basic
+    Parameter Values for the HDTV Standard for the Studio and
+    for International Programme Exchange'', formerly CCIR Rec.
+    709. For details see
+    
+       http://www.poynton.com/ColorFAQ.html
+       http://www.poynton.com/GammaFAQ.html
+*/
+
+void gamma_correct(const struct colourSystem *cs, double *c)
+{
+    double gamma;
+
+    gamma = cs->gamma;
+
+    if (gamma == GAMMA_REC709) {
+       /* Rec. 709 gamma correction. */
+       double cc = 0.018;
+       
+       if (*c < cc) {
+           *c *= ((1.099 * pow(cc, 0.45)) - 0.099) / cc;
+       } else {
+           *c = (1.099 * pow(*c, 0.45)) - 0.099;
+       }
+    } else {
+       /* Nonlinear colour = (Linear colour)^(1/gamma) */
+       *c = pow(*c, 1.0 / gamma);
+    }
+}
+
+void gamma_correct_rgb(const struct colourSystem *cs, double *r, double *g, double *b)
+{
+    gamma_correct(cs, r);
+    gamma_correct(cs, g);
+    gamma_correct(cs, b);
+}
+
+/*                         NORM_RGB
+
+    Normalise RGB components so the most intense (unless all
+    are zero) has a value of 1.
+    
+*/
+
+void norm_rgb(double *r, double *g, double *b)
+{
+#define Max(a, b)   (((a) > (b)) ? (a) : (b))
+    double greatest = Max(*r, Max(*g, *b));
+
+    if (greatest > 0) {
+       *r /= greatest;
+       *g /= greatest;
+       *b /= greatest;
+    }
+#undef Max
+}
+
+/*                          SPECTRUM_TO_XYZ
+
+    Calculate the CIE X, Y, and Z coordinates corresponding to
+    a light source with spectral distribution given by  the
+    function SPEC_INTENS, which is called with a series of
+    wavelengths between 380 and 780 nm (the argument is 
+    expressed in meters), which returns emittance at  that
+    wavelength in arbitrary units.  The chromaticity
+    coordinates of the spectrum are returned in the x, y, and z
+    arguments which respect the identity:
+
+            x + y + z = 1.
+*/
+
+void spectrum_to_xyz(double (*spec_intens)(double wavelength),
+                     double *x, double *y, double *z)
+{
+    int i;
+    double lambda, X = 0, Y = 0, Z = 0, XYZ;
+
+    /* CIE colour matching functions xBar, yBar, and zBar for
+       wavelengths from 380 through 780 nanometers, every 5
+       nanometers.  For a wavelength lambda in this range:
+
+            cie_colour_match[(lambda - 380) / 5][0] = xBar
+            cie_colour_match[(lambda - 380) / 5][1] = yBar
+            cie_colour_match[(lambda - 380) / 5][2] = zBar
+
+       To save memory, this table can be declared as floats
+       rather than doubles; (IEEE) float has enough 
+       significant bits to represent the values. It's declared
+       as a double here to avoid warnings about "conversion
+       between floating-point types" from certain persnickety
+       compilers. */
+
+    static double cie_colour_match[81][3] = {
+        {0.0014,0.0000,0.0065}, {0.0022,0.0001,0.0105}, {0.0042,0.0001,0.0201},
+        {0.0076,0.0002,0.0362}, {0.0143,0.0004,0.0679}, {0.0232,0.0006,0.1102},
+        {0.0435,0.0012,0.2074}, {0.0776,0.0022,0.3713}, {0.1344,0.0040,0.6456},
+        {0.2148,0.0073,1.0391}, {0.2839,0.0116,1.3856}, {0.3285,0.0168,1.6230},
+        {0.3483,0.0230,1.7471}, {0.3481,0.0298,1.7826}, {0.3362,0.0380,1.7721},
+        {0.3187,0.0480,1.7441}, {0.2908,0.0600,1.6692}, {0.2511,0.0739,1.5281},
+        {0.1954,0.0910,1.2876}, {0.1421,0.1126,1.0419}, {0.0956,0.1390,0.8130},
+        {0.0580,0.1693,0.6162}, {0.0320,0.2080,0.4652}, {0.0147,0.2586,0.3533},
+        {0.0049,0.3230,0.2720}, {0.0024,0.4073,0.2123}, {0.0093,0.5030,0.1582},
+        {0.0291,0.6082,0.1117}, {0.0633,0.7100,0.0782}, {0.1096,0.7932,0.0573},
+        {0.1655,0.8620,0.0422}, {0.2257,0.9149,0.0298}, {0.2904,0.9540,0.0203},
+        {0.3597,0.9803,0.0134}, {0.4334,0.9950,0.0087}, {0.5121,1.0000,0.0057},
+        {0.5945,0.9950,0.0039}, {0.6784,0.9786,0.0027}, {0.7621,0.9520,0.0021},
+        {0.8425,0.9154,0.0018}, {0.9163,0.8700,0.0017}, {0.9786,0.8163,0.0014},
+        {1.0263,0.7570,0.0011}, {1.0567,0.6949,0.0010}, {1.0622,0.6310,0.0008},
+        {1.0456,0.5668,0.0006}, {1.0026,0.5030,0.0003}, {0.9384,0.4412,0.0002},
+        {0.8544,0.3810,0.0002}, {0.7514,0.3210,0.0001}, {0.6424,0.2650,0.0000},
+        {0.5419,0.2170,0.0000}, {0.4479,0.1750,0.0000}, {0.3608,0.1382,0.0000},
+        {0.2835,0.1070,0.0000}, {0.2187,0.0816,0.0000}, {0.1649,0.0610,0.0000},
+        {0.1212,0.0446,0.0000}, {0.0874,0.0320,0.0000}, {0.0636,0.0232,0.0000},
+        {0.0468,0.0170,0.0000}, {0.0329,0.0119,0.0000}, {0.0227,0.0082,0.0000},
+        {0.0158,0.0057,0.0000}, {0.0114,0.0041,0.0000}, {0.0081,0.0029,0.0000},
+        {0.0058,0.0021,0.0000}, {0.0041,0.0015,0.0000}, {0.0029,0.0010,0.0000},
+        {0.0020,0.0007,0.0000}, {0.0014,0.0005,0.0000}, {0.0010,0.0004,0.0000},
+        {0.0007,0.0002,0.0000}, {0.0005,0.0002,0.0000}, {0.0003,0.0001,0.0000},
+        {0.0002,0.0001,0.0000}, {0.0002,0.0001,0.0000}, {0.0001,0.0000,0.0000},
+        {0.0001,0.0000,0.0000}, {0.0001,0.0000,0.0000}, {0.0000,0.0000,0.0000}
+    };
+
+    for (i = 0, lambda = 380; lambda < 780.1; i++, lambda += 5) {
+        double Me;
+
+        Me = (*spec_intens)(lambda);
+        X += Me * cie_colour_match[i][0];
+        Y += Me * cie_colour_match[i][1];
+        Z += Me * cie_colour_match[i][2];
+    }
+    XYZ = (X + Y + Z);
+    *x = X / XYZ;
+    *y = Y / XYZ;
+    *z = Z / XYZ;
+}
+
+/*                            BB_SPECTRUM
+
+    Calculate, by Planck's radiation law, the emittance of a black body
+    of temperature bbTemp at the given wavelength (in metres).  */
+
+double bbTemp = 5000;                 /* Hidden temperature argument
+                                         to BB_SPECTRUM. */
+double bb_spectrum(double wavelength)
+{
+    double wlm = wavelength * 1e-9;   /* Wavelength in meters */
+
+    return (3.74183e-16 * pow(wlm, -5.0)) /
+           (exp(1.4388e-2 / (wlm * bbTemp)) - 1.0);
+}
+
+void xyz_to_lms(double x, double y, double z, double* l, double* m, double* s)
+{
+       *l =  0.3897*x + 0.6890*y - 0.0787*z;
+       *m = -0.2298*x + 1.1834*y + 0.0464*z;
+       *s = z;
+}
+
+void lms_to_xyz(double l, double m, double s, double* x, double *y, double* z)
+{
+       *x =  1.9102*l - 1.1121*m + 0.2019*s;
+       *y =  0.3709*l + 0.6290*m + 0.0000*s;
+       *z = s;
+}
+
+void spectrum(double t1, double t2, int N, unsigned char* d)
+{
+       int i,j,dj;
+       double X,Y,Z,R,G,B,L,M,S, Lw, Mw, Sw;
+       struct colourSystem *cs = &CIEsystem;
+
+       j = 0; dj = 1;
+       if (t1<t2) {
+               double t = t1;
+               t1 = t2;
+               t2 = t;
+               j = N-1; dj=-1;
+       }
+
+       for (i=0; i<N; i++) {
+               bbTemp = t1 + (t2-t1)/N*i;
+
+                       // integrate blackbody radiation spectrum to XYZ
+               spectrum_to_xyz(bb_spectrum, &X, &Y, &Z);
+
+                       // normalize highest temperature to white (in LMS system)
+               xyz_to_lms(X,Y,Z,&L,&M,&S);
+               if (i==0) {
+                       Lw=1/L; Mw=1/M; Sw=1/S;
+               }
+               L *= Lw; M *= Mw; S *= Sw;
+               lms_to_xyz(L,M,S,&X,&Y,&Z);
+
+                       // convert to RGB
+               xyz_to_rgb(cs, X, Y, Z, &R, &G, &B);
+               constrain_rgb(&R, &G, &B);
+               norm_rgb(&R, &G, &B);
+               d[(j<<2)] = (unsigned char) ((double)R*255);
+               d[(j<<2)+1] = (unsigned char) ((double)G*255);
+               d[(j<<2)+2] = (unsigned char) ((double)B*255);
+               d[(j<<2)+3] = (B>0.1)? B*255 : 0;
+               j += dj;
+       }
+}
diff --git a/intern/smoke/intern/spectrum.h b/intern/smoke/intern/spectrum.h
new file mode 100644 (file)
index 0000000..9edd9ad
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __SPECTRUM_H
+#define __SPECTRUM_H
+
+void spectrum(double t1, double t2, int n, unsigned char* d);
+
+#endif
index a0d460b0153b68d4fff7eaaa3bdcfd3a3f6b62e4..09a63f4c47d68266d158493cad880c7d4abcfaf0 100644 (file)
Binary files a/release/datafiles/blender_icons.png and b/release/datafiles/blender_icons.png differ
index 35b496b6dd0c6adc18ca41fa0c459038bfb7fc62..cd0b63a6b784f3c31eb515e9a645f940aadff862 100644 (file)
@@ -299,7 +299,6 @@ class QuickSmoke(Operator):
     style = EnumProperty(
             name="Smoke Style",
             items=(('STREAM', "Stream", ""),
-                   ('PUFF', "Puff", ""),
                    ('FIRE', "Fire", ""),
                    ),
             default='STREAM',
@@ -328,20 +327,9 @@ class QuickSmoke(Operator):
             bpy.ops.object.modifier_add(fake_context, type='SMOKE')
             obj.modifiers[-1].smoke_type = 'FLOW'
 
-            psys = obj.particle_systems[-1]
-            if self.style == 'PUFF':
-                psys.settings.frame_end = psys.settings.frame_start
-                psys.settings.emit_from = 'VOLUME'
-                psys.settings.distribution = 'RAND'
-            elif self.style == 'FIRE':
-                psys.settings.effector_weights.gravity = -1
-                psys.settings.lifetime = 5
-                psys.settings.count = 100000
-
-                obj.modifiers[-2].flow_settings.initial_velocity = True
-                obj.modifiers[-2].flow_settings.temperature = 2
-
-            psys.settings.use_render_emitter = self.show_flows
+            if self.style == 'FIRE':
+                obj.modifiers[-1].flow_settings.smoke_flow_type = 'FIRE'
+
             if not self.show_flows:
                 obj.draw_type = 'WIRE'
 
@@ -361,8 +349,6 @@ class QuickSmoke(Operator):
         bpy.ops.object.modifier_add(type='SMOKE')
         obj.modifiers[-1].smoke_type = 'DOMAIN'
         if self.style == 'FIRE':
-            obj.modifiers[-1].domain_settings.use_dissolve_smoke = True
-            obj.modifiers[-1].domain_settings.dissolve_speed = 20
             obj.modifiers[-1].domain_settings.use_high_resolution = True
 
         # create a volume material with a voxel data texture for the domain
@@ -373,6 +359,7 @@ class QuickSmoke(Operator):
         mat.type = 'VOLUME'
         mat.volume.density = 0
         mat.volume.density_scale = 5
+        mat.volume.step_size = 0.1
 
         tex = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA')
         tex.voxel_data.domain_object = obj
@@ -381,29 +368,35 @@ class QuickSmoke(Operator):
         tex_slot.texture = tex
         tex_slot.use_map_color_emission = False
         tex_slot.use_map_density = True
+        tex_slot.use_map_color_reflection = True
 
-        # for fire add a second texture for emission and emission color
-        if self.style == 'FIRE':
-            mat.volume.emission = 5
-            tex = bpy.data.textures.new("Smoke Heat", 'VOXEL_DATA')
-            tex.voxel_data.domain_object = obj
-            tex.use_color_ramp = True
-
-            tex_slot = mat.texture_slots.add()
-            tex_slot.texture = tex
-
-            ramp = tex.color_ramp
-
-            elem = ramp.elements.new(0.333)
-            elem.color[0] = elem.color[3] = 1
-            elem.color[1] = elem.color[2] = 0
+        # for fire add a second texture for flame emission
+        mat.volume.emission_color = Vector((0.0, 0.0, 0.0))
+        tex = bpy.data.textures.new("Flame", 'VOXEL_DATA')
+        tex.voxel_data.domain_object = obj
+        tex.voxel_data.smoke_data_type = 'SMOKEFLAME'
+        tex.use_color_ramp = True
 
-            elem = ramp.elements.new(0.666)
-            elem.color[0] = elem.color[1] = elem.color[3] = 1
-            elem.color[2] = 0
+        tex_slot = mat.texture_slots.add()
+        tex_slot.texture = tex
 
-            mat.texture_slots[1].use_map_emission = True
-            mat.texture_slots[1].blend_type = 'MULTIPLY'
+        # add color ramp for flame color
+        ramp = tex.color_ramp
+        # dark orange
+        elem = ramp.elements.new(0.333)
+        elem.color[0] = 0.2
+        elem.color[1] = 0.03
+        elem.color[2] = 0
+        elem.color[3] = 1
+        # yellow glow
+        elem = ramp.elements.new(0.666)
+        elem.color[0] = elem.color[3] = 1
+        elem.color[1] = 0.65
+        elem.color[2] = 0.25
+
+        mat.texture_slots[1].use_map_density = True
+        mat.texture_slots[1].use_map_emission = True
+        mat.texture_slots[1].emission_factor = 5
 
         return {'FINISHED'}
 
index f29589faa2df686062d300955e8a28c501d5aa42..6fcd56fb99ead5de2739796d9b3bbdcb4b4e134a 100644 (file)
@@ -1124,7 +1124,7 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
 
     def draw(self, context):
         part = particle_get_settings(context)
-        effector_weights_ui(self, context, part.effector_weights)
+        effector_weights_ui(self, context, part.effector_weights, 'PSYS')
 
         if part.type == 'HAIR':
             row = self.layout.row()
index e5db1eec37ed8e0bf8669b72c2999b39636fce82..5a44294f0e0289f37f61d28537a4efaf2a627178 100644 (file)
@@ -197,7 +197,7 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel):
 
     def draw(self, context):
         cloth = context.cloth.settings
-        effector_weights_ui(self, context, cloth.effector_weights)
+        effector_weights_ui(self, context, cloth.effector_weights, 'CLOTH')
 
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
index 00a35b233dad575284cf570d56cd7e196c2bc60e..b94df3148a928a1cec4a64c125e7d75c505c6cbb 100644 (file)
@@ -179,7 +179,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
         col.operator("ptcache.bake_all", text="Update All To Frame").bake = False
 
 
-def effector_weights_ui(self, context, weights):
+def effector_weights_ui(self, context, weights, weight_type):
     layout = self.layout
 
     layout.prop(weights, "group")
@@ -200,6 +200,8 @@ def effector_weights_ui(self, context, weights):
     col.prop(weights, "wind", slider=True)
     col.prop(weights, "curve_guide", slider=True)
     col.prop(weights, "texture", slider=True)
+    if weight_type != 'SMOKE':
+        col.prop(weights, "smokeflow", slider=True)
 
     col = split.column()
     col.prop(weights, "harmonic", slider=True)
index fa37e9cd10f7992b0b7609524ca33b0e55f83870..1df2936b2d45bab7d8be8765df6deb37e97f1c54 100644 (file)
@@ -349,7 +349,7 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
 
             col = layout.column()
             col.active = surface.use_drip
-            effector_weights_ui(self, context, surface.effector_weights)
+            effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT')
 
             layout.label(text="Surface Movement:")
             row = layout.row()
index 6b5612d78365664a116717af9e0c94428bdcbe85..933a9aa12a3b8c51a0b85c0cef90ae1a661788a4 100644 (file)
@@ -112,6 +112,14 @@ class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
             col = split.column()
             col.prop(field, "use_object_coords")
             col.prop(field, "use_2d_force")
+        elif field.type == 'SMOKE_FLOW':
+            col = split.column()
+            col.prop(field, "strength")
+            col.prop(field, "flow")
+            col = split.column()
+            col.label(text="Domain Object:")
+            col.prop(field, "source_object", "")
+            col.prop(field, "use_smoke_density")
         else:
             basic_force_field_settings_ui(self, context, field)
 
index acbaad4f9610beb9f55e64f40e7f27e79b30e4ee..ce5053f0ecfde77b27fadcbb0f01cbc809a628f3 100644 (file)
@@ -76,28 +76,40 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
         elif md.smoke_type == 'FLOW':
 
             flow = md.flow_settings
-
-            split = layout.split()
-
-            col = split.column()
-            col.prop(flow, "use_outflow")
-            col.label(text="Particle System:")
-            col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
-
-            sub = col.column()
-            sub.active = not md.flow_settings.use_outflow
-
-            sub.prop(flow, "initial_velocity", text="Initial Velocity")
-            sub = sub.column()
-            sub.active = flow.initial_velocity
-            sub.prop(flow, "velocity_factor", text="Multiplier")
-
-            sub = split.column()
-            sub.active = not md.flow_settings.use_outflow
-            sub.label(text="Initial Values:")
-            sub.prop(flow, "use_absolute")
-            sub.prop(flow, "density")
-            sub.prop(flow, "temperature")
+            
+            layout.prop(flow, "smoke_flow_type", expand=False)
+
+            if flow.smoke_flow_type != "OUTFLOW":
+                split = layout.split()
+                col = split.column()
+                col.label(text="Flow Source:")
+                col.prop(flow, "smoke_flow_source", expand=False, text="")
+                if flow.smoke_flow_source == "PARTICLES":
+                    col.label(text="Particle System:")
+                    col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
+                else:
+                    col.prop(flow, "surface_distance")
+                    col.prop(flow, "volume_density")
+
+                sub = col.column(align=True)
+
+                sub.prop(flow, "initial_velocity")
+                sub = sub.column()
+                sub.active = flow.initial_velocity
+                sub.prop(flow, "velocity_factor")
+                if flow.smoke_flow_source == "MESH":
+                    sub.prop(flow, "velocity_normal")
+                    #sub.prop(flow, "velocity_random")
+
+                sub = split.column()
+                sub.label(text="Initial Values:")
+                sub.prop(flow, "use_absolute")
+                if flow.smoke_flow_type in {'SMOKE', 'BOTH'}:
+                    sub.prop(flow, "density")
+                    sub.prop(flow, "temperature")
+                    sub.prop(flow, "smoke_color")
+                if flow.smoke_flow_type in {'FIRE', 'BOTH'}:
+                    sub.prop(flow, "fuel_amount")
 
         elif md.smoke_type == 'COLLISION':
             coll = md.coll_settings
@@ -106,36 +118,99 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
 
             col = split.column()
             col.prop(coll, "collision_type")
+            
+class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
+    bl_label = "Smoke Flow Advanced"
+    bl_options = {'DEFAULT_CLOSED'}
 
+    @classmethod
+    def poll(cls, context):
+        md = context.smoke
+        return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == "MESH")
 
-class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
-    bl_label = "Smoke Groups"
+    def draw(self, context):
+        layout = self.layout
+        ob = context.object
+        flow = context.smoke.flow_settings
+        
+        split = layout.split()
+        col = split.column()
+
+        col.prop(flow, "use_texture")
+        sub = col.column()
+        sub.active = flow.use_texture
+        sub.prop(flow, "noise_texture", text="")
+        sub.label(text="Mapping:")
+        sub.prop(flow, "texture_map_type", expand=False, text="")
+        if flow.texture_map_type == "UV":
+            sub.prop_search(flow, "uv_layer", ob.data, "uv_textures", text="")
+        if flow.texture_map_type == "AUTO":
+            sub.prop(flow, "texture_size")
+        sub.prop(flow, "texture_offset")
+        
+        col = split.column()
+        col.label(text="Vertex Group:")
+        col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="")
+
+class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
+    bl_label = "Smoke Flames"
     bl_options = {'DEFAULT_CLOSED'}
 
     @classmethod
     def poll(cls, context):
         md = context.smoke
-        rd = context.scene.render
-        return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+        return md and (md.smoke_type == 'DOMAIN')
 
     def draw(self, context):
         layout = self.layout
-
-        group = context.smoke.domain_settings
+        domain = context.smoke.domain_settings
 
         split = layout.split()
+        split.enabled = not domain.point_cache.is_baked
+
+        col = split.column(align=True)
+        col.label(text="Reaction:")
+        col.prop(domain, "burning_rate")
+        col.prop(domain, "flame_smoke")
+        col.prop(domain, "flame_vorticity")
+
+        col = split.column(align=True)
+        col.label(text="Temperatures:")
+        col.prop(domain, "flame_ignition")
+        col.prop(domain, "flame_max_temp")
+        col.prop(domain, "flame_smoke_color")
+        
+class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
+    bl_label = "Smoke Adaptive Domain"
+    bl_options = {'DEFAULT_CLOSED'}
 
-        col = split.column()
-        col.label(text="Flow Group:")
-        col.prop(group, "fluid_group", text="")
+    @classmethod
+    def poll(cls, context):
+        md = context.smoke
+        return md and (md.smoke_type == 'DOMAIN')
 
-        #col.label(text="Effector Group:")
-        #col.prop(group, "effector_group", text="")
+    def draw_header(self, context):
+        md = context.smoke.domain_settings
 
-        col = split.column()
-        col.label(text="Collision Group:")
-        col.prop(group, "collision_group", text="")
+        self.layout.prop(md, "use_adaptive_domain", text="")
 
+    def draw(self, context):
+        layout = self.layout
+
+        domain = context.smoke.domain_settings
+        layout.active = domain.use_adaptive_domain
+        
+        split = layout.split()
+        split.enabled = not domain.point_cache.is_baked
+        col = split.column(align=True)
+        col.label(text="Resolution:")
+        col.prop(domain, "additional_res")
+        col.prop(domain, "adapt_margin")
+
+        col = split.column(align=True)
+        col.label(text="Advanced:")
+        col.prop(domain, "adapt_threshold")
 
 class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
     bl_label = "Smoke High Resolution"
@@ -174,6 +249,32 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
 
         layout.prop(md, "show_high_resolution")
 
+class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
+    bl_label = "Smoke Groups"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        md = context.smoke
+        rd = context.scene.render
+        return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+
+    def draw(self, context):
+        layout = self.layout
+        domain = context.smoke.domain_settings
+        
+        split = layout.split()
+
+        col = split.column()
+        col.label(text="Flow Group:")
+        col.prop(domain, "fluid_group", text="")
+
+        #col.label(text="Effector Group:")
+        #col.prop(domain, "effector_group", text="")
+
+        col = split.column()
+        col.label(text="Collision Group:")
+        col.prop(domain, "collision_group", text="")
 
 class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
     bl_label = "Smoke Cache"
@@ -209,7 +310,7 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
 
     def draw(self, context):
         domain = context.smoke.domain_settings
-        effector_weights_ui(self, context, domain.effector_weights)
+        effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
 
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
index a69e7955de54ab6c8fde1032a51bf7a30fc8cb1f..79d676533a58c0386073350586c0bfd3ccf8f463 100644 (file)
@@ -231,7 +231,7 @@ class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel):
         md = context.soft_body
         softbody = md.settings
 
-        effector_weights_ui(self, context, softbody.effector_weights)
+        effector_weights_ui(self, context, softbody.effector_weights, 'SOFTBODY')
 
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
index 9e6bfe6889edb883e8c9b3fd9187ecc2dad15571..d4752e4e7b5bf451718b772506999222cfedc8d1 100644 (file)
@@ -887,8 +887,12 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
                 col = split.column()
                 if tex.texture_coords in {'ORCO', 'UV'}:
                     col.prop(tex, "use_from_dupli")
+                    if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'):
+                        col.prop(tex, "use_map_to_bounds")
                 elif tex.texture_coords == 'OBJECT':
                     col.prop(tex, "use_from_original")
+                    if (idblock.type == 'VOLUME'):
+                        col.prop(tex, "use_map_to_bounds")
                 else:
                     col.label()
 
index 1f824ccbafc6f50f010e6fc783b75d199a1edece..3a9d2b86b419fc544e8c6ad9e0d047d8249f3f28 100644 (file)
 
 typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
 
-void smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
 
+void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
+void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
 void smokeModifier_free(struct SmokeModifierData *smd);
 void smokeModifier_reset(struct SmokeModifierData *smd);
 void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
@@ -44,5 +46,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd);
 void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd);
 
 long long smoke_get_mem_req(int xres, int yres, int zres, int amplify);
+float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
+int smoke_get_data_flags(struct SmokeDomainSettings *sds);
 
 #endif /* __BKE_SMOKE_H__ */
index 31a6f768f89baa3dfb654eaf707dc7c55b028ff1..9b52fbae626f6fcb7dc7ab429bfb227973a4e81a 100644 (file)
@@ -400,8 +400,7 @@ static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Mat
        }
 }
 
-static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node)
-{
+static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield){
        Base *base;
        DagNode *node2;
 
@@ -411,6 +410,8 @@ static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Objec
                if ((base->lay & ob->lay) && base->object->pd) {
                        Object *ob1 = base->object;
                        if ((ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) {
+                               if (skip_forcefield && ob1->pd->forcefield == skip_forcefield)
+                                       continue;
                                node2 = dag_get_node(dag, ob1);                                 
                                dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision");
                        }
@@ -570,12 +571,14 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
        /* softbody collision  */
        if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) {
                if (ob->particlesystem.first ||
-                       modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
-                       modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
-                       modifiers_isModifierEnabled(ob, eModifierType_Smoke) ||
-                       modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
+                   modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
+                   modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
+                   modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
                {
-                       dag_add_collision_field_relation(dag, scene, ob, node);  /* TODO: use effectorweight->group */
+                       dag_add_collision_field_relation(dag, scene, ob, node, 0);  /* TODO: use effectorweight->group */
+               }
+               else if (modifiers_isModifierEnabled(ob, eModifierType_Smoke)) {
+                       dag_add_collision_field_relation(dag, scene, ob, node, PFIELD_SMOKEFLOW);
                }
        }
        
index 4f4bafd00b481558202e7d678e5da67a2306a602..495814acbee6f9e6f12e38535ce669ebca78a97b 100644 (file)
@@ -84,6 +84,7 @@
 #include "BKE_object.h"
 #include "BKE_particle.h"
 #include "BKE_scene.h"
+#include "BKE_smoke.h"
 
 
 #include "RE_render_ext.h"
@@ -137,6 +138,9 @@ PartDeflect *object_add_collision_fields(int type)
                case PFIELD_TEXTURE:
                        pd->f_size = 1.0f;
                        break;
+               case PFIELD_SMOKEFLOW:
+                       pd->f_flow = 1.0f;
+                       break;
        }
        pd->flag = PFIELD_DO_LOCATION|PFIELD_DO_ROTATION;
 
@@ -922,12 +926,27 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
 
                        mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
                        break;
+               case PFIELD_SMOKEFLOW:
+                       zero_v3(force);
+                       if (pd->f_source) {
+                               float density;
+                               if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
+                                       float influence = strength * efd->falloff;
+                                       if (pd->flag & PFIELD_SMOKE_DENSITY)
+                                               influence *= density;
+                                       mul_v3_fl(force, influence);
+                                       /* apply flow */
+                                       madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
+                               }
+                       }
+                       break;
+
        }
 
        if (pd->flag & PFIELD_DO_LOCATION) {
                madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec);
 
-               if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)==0 && pd->f_flow != 0.0f) {
+               if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) {
                        madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
                }
        }
index 8c0d19ba1fde51d25a747acfbe1cad4a886947d6..6b90ec88362559372af9216864ab318fee34e054 100644 (file)
@@ -532,20 +532,31 @@ static int  ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
        SmokeDomainSettings *sds = smd->domain;
        
        if (sds->fluid) {
-               return sds->res[0]*sds->res[1]*sds->res[2];
+               return sds->base_res[0]*sds->base_res[1]*sds->base_res[2];
        }
        else
                return 0;
 }
+
+#define SMOKE_CACHE_VERSION "1.04"
+
 static int  ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
 {      
        SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
        SmokeDomainSettings *sds = smd->domain;
        int ret = 0;
+       int fluid_fields = smoke_get_data_flags(sds);
+
+       /* version header */
+       ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
+       ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
+       ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
+       ptcache_file_write(pf, &sds->res, 3, sizeof(int));
+       ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
        
        if (sds->fluid) {
                size_t res = sds->res[0]*sds->res[1]*sds->res[2];
-               float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
+               float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
                unsigned char *obstacles;
                unsigned int in_len = sizeof(float)*(unsigned int)res;
                unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer");
@@ -553,22 +564,40 @@ static int  ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
                int mode=1;             // light
                if (sds->cache_comp == SM_CACHE_HEAVY) mode=2;  // heavy
 
-               smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
+               smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
 
                ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
                ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
-               ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len, out, mode); 
-               ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
-               ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
+               if (fluid_fields & SM_ACTIVE_HEAT) {
+                       ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
+               }
+               if (fluid_fields & SM_ACTIVE_FIRE) {
+                       ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
+               }
+               if (fluid_fields & SM_ACTIVE_COLORS) {
+                       ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
+               }
                ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
                ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
                ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
-               ptcache_file_compressed_write(pf, (unsigned char *)vxold, in_len, out, mode);
-               ptcache_file_compressed_write(pf, (unsigned char *)vyold, in_len, out, mode);
-               ptcache_file_compressed_write(pf, (unsigned char *)vzold, in_len, out, mode);
                ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
                ptcache_file_write(pf, &dt, 1, sizeof(float));
                ptcache_file_write(pf, &dx, 1, sizeof(float));
+               ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
+               ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
+               ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
+               ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
+               ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
+               ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
+               ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
+               ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
+               ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
+               ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
 
                MEM_freeN(out);
                
@@ -579,7 +608,7 @@ static int  ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
                int res_big_array[3];
                int res_big;
                int res = sds->res[0]*sds->res[1]*sds->res[2];
-               float *dens, *densold, *tcu, *tcv, *tcw;
+               float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
                unsigned int in_len = sizeof(float)*(unsigned int)res;
                unsigned int in_len_big;
                unsigned char *out;
@@ -593,11 +622,20 @@ static int  ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
 
                in_len_big = sizeof(float) * (unsigned int)res_big;
 
-               smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
+               smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
 
                out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
                ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
-               ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len_big, out, mode);     
+               if (fluid_fields & SM_ACTIVE_FIRE) {
+                       ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
+               }
+               if (fluid_fields & SM_ACTIVE_COLORS) {
+                       ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
+                       ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
+               }
                MEM_freeN(out);
 
                out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
@@ -615,34 +653,95 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
 {
        SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
        SmokeDomainSettings *sds = smd->domain;
+       char version[4];
+       int ch_res[3];
+       float ch_dx;
+       int fluid_fields = smoke_get_data_flags(sds);
+       int cache_fields = 0;
+       int active_fields = 0;
+       int reallocate = 0;
+
+       /* version header */
+       ptcache_file_read(pf, version, 4, sizeof(char));
+       if (strncmp(version, SMOKE_CACHE_VERSION, 4)) return 0;
+       /* fluid info */
+       ptcache_file_read(pf, &cache_fields, 1, sizeof(int));
+       ptcache_file_read(pf, &active_fields, 1, sizeof(int));
+       ptcache_file_read(pf, &ch_res, 3, sizeof(int));
+       ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
+
+       /* check if resolution has changed */
+       if (sds->res[0] != ch_res[0] ||
+               sds->res[1] != ch_res[1] ||
+               sds->res[2] != ch_res[2]) {
+               if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)
+                       reallocate = 1;
+               else
+                       return 0;
+       }
+       /* check if active fields have changed */
+       if (fluid_fields != cache_fields ||
+               active_fields != sds->active_fields)
+               reallocate = 1;
+
+       /* reallocate fluid if needed*/
+       if (reallocate) {
+               sds->active_fields = active_fields;
+               smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
+               sds->dx = ch_dx;
+               VECCOPY(sds->res, ch_res);
+               sds->total_cells = ch_res[0]*ch_res[1]*ch_res[2];
+               if(sds->flags & MOD_SMOKE_HIGHRES) {
+                       smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
+               }
+       }
        
        if (sds->fluid) {
                size_t res = sds->res[0]*sds->res[1]*sds->res[2];
-               float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
+               float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
                unsigned char *obstacles;
                unsigned int out_len = (unsigned int)res * sizeof(float);
                
-               smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
+               smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
 
                ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
                ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len);
-               ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len);
-               ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
-               ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
+               if (cache_fields & SM_ACTIVE_HEAT) {
+                       ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
+                       ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
+               }
+               if (cache_fields & SM_ACTIVE_FIRE) {
+                       ptcache_file_compressed_read(pf, (unsigned char*)flame, out_len);
+                       ptcache_file_compressed_read(pf, (unsigned char*)fuel, out_len);
+                       ptcache_file_compressed_read(pf, (unsigned char*)react, out_len);
+               }
+               if (cache_fields & SM_ACTIVE_COLORS) {
+                       ptcache_file_compressed_read(pf, (unsigned char*)r, out_len);
+                       ptcache_file_compressed_read(pf, (unsigned char*)g, out_len);
+                       ptcache_file_compressed_read(pf, (unsigned char*)b, out_len);
+               }
                ptcache_file_compressed_read(pf, (unsigned char*)vx, out_len);
                ptcache_file_compressed_read(pf, (unsigned char*)vy, out_len);
                ptcache_file_compressed_read(pf, (unsigned char*)vz, out_len);
-               ptcache_file_compressed_read(pf, (unsigned char*)vxold, out_len);
-               ptcache_file_compressed_read(pf, (unsigned char*)vyold, out_len);
-               ptcache_file_compressed_read(pf, (unsigned char*)vzold, out_len);
                ptcache_file_compressed_read(pf, (unsigned char*)obstacles, (unsigned int)res);
                ptcache_file_read(pf, &dt, 1, sizeof(float));
                ptcache_file_read(pf, &dx, 1, sizeof(float));
-
-               if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
+               ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
+               ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
+               ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
+               ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
+               ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
+               ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
+               ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
+               ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
+               ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
+               ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
+       }
+
+       if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
                        int res = sds->res[0]*sds->res[1]*sds->res[2];
                        int res_big, res_big_array[3];
-                       float *dens, *densold, *tcu, *tcv, *tcw;
+                       float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
                        unsigned int out_len = sizeof(float)*(unsigned int)res;
                        unsigned int out_len_big;
 
@@ -650,16 +749,23 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
                        res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
                        out_len_big = sizeof(float) * (unsigned int)res_big;
 
-                       smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
+                       smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
 
                        ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len_big);
-                       ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len_big);
+                       if (cache_fields & SM_ACTIVE_FIRE) {
+                               ptcache_file_compressed_read(pf, (unsigned char*)flame, out_len_big);
+                               ptcache_file_compressed_read(pf, (unsigned char*)fuel, out_len_big);
+                       }
+                       if (cache_fields & SM_ACTIVE_COLORS) {
+                               ptcache_file_compressed_read(pf, (unsigned char*)r, out_len_big);
+                               ptcache_file_compressed_read(pf, (unsigned char*)g, out_len_big);
+                               ptcache_file_compressed_read(pf, (unsigned char*)b, out_len_big);
+                       }
 
                        ptcache_file_compressed_read(pf, (unsigned char*)tcu, out_len);
                        ptcache_file_compressed_read(pf, (unsigned char*)tcv, out_len);
                        ptcache_file_compressed_read(pf, (unsigned char*)tcw, out_len);
                }
-       }
 
        return 1;
 }
@@ -2466,10 +2572,10 @@ int  BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
                        sbFreeSimulation(pid->calldata);
                else if (pid->type == PTCACHE_TYPE_PARTICLES)
                        psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
-               else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
+               /*else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
                        smokeModifier_reset(pid->calldata);
                else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
-                       smokeModifier_reset_turbulence(pid->calldata);
+                       smokeModifier_reset_turbulence(pid->calldata);*/
                else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
                        dynamicPaint_clearSurface((DynamicPaintSurface*)pid->calldata);
        }
index 5e67e094e4366d8be673a536531ae0179be60bfd..a07c58746df6f8fa62cbd2e498b6f6f6b999b315 100644 (file)
 #include "BLI_kdtree.h"
 #include "BLI_kdopbvh.h"
 #include "BLI_utildefines.h"
-
-#include "BKE_bvhutils.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_collision.h"
-#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_effect.h"
-#include "BKE_modifier.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_smoke.h"
-
+#include "BLI_voxel.h"
 
 #include "DNA_customdata_types.h"
 #include "DNA_group_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_smoke_types.h"
 
+#include "BKE_bvhutils.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_collision.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
 #include "BKE_smoke.h"
 
+#include "RE_shader_ext.h"
+
 /* UNUSED so far, may be enabled later */
 /* #define USE_SMOKE_COLLISION_DM */
 
@@ -103,7 +104,7 @@ static void tend ( void )
 {
        QueryPerformanceCounter ( &liCurrentTime );
 }
-static double UNUSED_FUNCTION(tval)( void )
+static double tval( void )
 {
        return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
 }
@@ -134,590 +135,220 @@ struct Scene;
 struct DerivedMesh;
 struct SmokeModifierData;
 
-#define TRI_UVOFFSET (1./4.)
-
 // timestep default value for nice appearance 0.1f
 #define DT_DEFAULT 0.1f
 
-/* forward declerations */
-static void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
-static void get_cell(const float p0[3], const int res[3], float dx, const float pos[3], int cell[3], int correct);
-static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs);
+#define ADD_IF_LOWER_POS(a,b) (MIN2((a)+(b), MAX2((a),(b))))
+#define ADD_IF_LOWER_NEG(a,b) (MAX2((a)+(b), MIN2((a),(b))))
+#define ADD_IF_LOWER(a,b) (((b)>0)?ADD_IF_LOWER_POS((a),(b)):ADD_IF_LOWER_NEG((a),(b)))
 
 #else /* WITH_SMOKE */
 
 /* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; }
-// struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; }
+struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
+//struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
 void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
 float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; }
 void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {}
 void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {}
-void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli)) {}
-long long smoke_get_mem_req(int UNUSED(xres), int UNUSED(yres), int UNUSED(zres), int UNUSED(amplify)) { return 0; }
-void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) {}
+void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
+                                                 int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
+                                                 float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
+float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
+void flame_get_spectrum(unsigned char *UNUSED(spec), int UNUSED(width), float UNUSED(t1), float UNUSED(t2)) {}
 
 #endif /* WITH_SMOKE */
 
 #ifdef WITH_SMOKE
 
-static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+void smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
 {
-       if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
-       {
-               size_t i;
-               float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
-               float size[3];
-               MVert *verts = dm->getVertArray(dm);
-               float scale = 0.0;
-               int res;                
+       int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
+       int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT|SM_ACTIVE_FIRE));
+       int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+
+       if (free_old && sds->fluid)
+               smoke_free(sds->fluid);
+       if (!MIN3(res[0],res[1],res[2])) {
+               sds->fluid = NULL;
+               return;
+       }
+       sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
+       smoke_initBlenderRNA(sds->fluid, &(sds->alpha), &(sds->beta), &(sds->time_scale), &(sds->vorticity), &(sds->border_collisions),
+                                                &(sds->burning_rate), &(sds->flame_smoke), sds->flame_smoke_color, &(sds->flame_vorticity), &(sds->flame_ignition), &(sds->flame_max_temp));
+
+       /* reallocate shadow buffer */
+       if (sds->shadow)
+               MEM_freeN(sds->shadow);
+       sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
+}
 
-               res = smd->domain->maxres;
+void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
+{
+       int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT|SM_ACTIVE_FIRE));
+       int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
 
-               // get BB of domain
-               for(i = 0; i < dm->getNumVerts(dm); i++)
-               {
-                       float tmp[3];
+       if (free_old && sds->wt)
+               smoke_turbulence_free(sds->wt);
+       if (!MIN3(res[0],res[1],res[2])) {
+               sds->wt = NULL;
+               return;
+       }
+       sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, use_fire, use_colors);
+       sds->res_wt[0] = res[0] * (sds->amplify + 1);
+       sds->res_wt[1] = res[1] * (sds->amplify + 1);                   
+       sds->res_wt[2] = res[2] * (sds->amplify + 1);                   
+       sds->dx_wt = dx / (sds->amplify + 1);
+       smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
+}
 
-                       copy_v3_v3(tmp, verts[i].co);
-                       mul_m4_v3(ob->obmat, tmp);
+/* convert global position to domain cell space */
+static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
+{
+       mul_m4_v3(sds->imat, pos);
+       sub_v3_v3(pos, sds->p0);
+       pos[0] *= 1.0f/sds->cell_size[0];
+       pos[1] *= 1.0f/sds->cell_size[1];
+       pos[2] *= 1.0f/sds->cell_size[2];
+}
 
-                       // min BB
-                       min[0] = MIN2(min[0], tmp[0]);
-                       min[1] = MIN2(min[1], tmp[1]);
-                       min[2] = MIN2(min[2], tmp[2]);
+/* set domain resolution and dimensions from object derivedmesh */
+static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *ob, DerivedMesh *dm)
+{
+       size_t i;
+       float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+       float size[3];
+       MVert *verts = dm->getVertArray(dm);
+       float scale = 0.0;
+       int res;
 
-                       // max BB
-                       max[0] = MAX2(max[0], tmp[0]);
-                       max[1] = MAX2(max[1], tmp[1]);
-                       max[2] = MAX2(max[2], tmp[2]);
-               }
+       res = sds->maxres;
 
-               copy_v3_v3(smd->domain->p0, min);
-               copy_v3_v3(smd->domain->p1, max);
+       // get BB of domain
+       for(i = 0; i < dm->getNumVerts(dm); i++)
+       {
+               // min BB
+               min[0] = MIN2(min[0], verts[i].co[0]);
+               min[1] = MIN2(min[1], verts[i].co[1]);
+               min[2] = MIN2(min[2], verts[i].co[2]);
+
+               // max BB
+               max[0] = MAX2(max[0], verts[i].co[0]);
+               max[1] = MAX2(max[1], verts[i].co[1]);
+               max[2] = MAX2(max[2], verts[i].co[2]);
+       }
 
-               // calc other res with max_res provided
-               sub_v3_v3v3(size, max, min);
+       /* set domain bounds */
+       copy_v3_v3(sds->p0, min);
+       copy_v3_v3(sds->p1, max);
+       sds->dx = 1.0f / res;
 
-               // prevent crash when initializing a plane as domain
-               if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
-                       return 0;
+       /* calculate domain dimensions */
+       sub_v3_v3v3(size, max, min);
+       copy_v3_v3(sds->cell_size, size);
+       mul_v3_v3(size, ob->size);
+       copy_v3_v3(sds->global_size, size);
+       copy_v3_v3(sds->dp0, min);
 
-               if(size[0] > size[1])
-               {
-                       if(size[0] > size[2])
-                       {
-                               scale = res / size[0];
-                               smd->domain->scale = size[0];
-                               smd->domain->dx = 1.0f / res; 
-                               smd->domain->res[0] = res;
-                               smd->domain->res[1] = (int)(size[1] * scale + 0.5);
-                               smd->domain->res[2] = (int)(size[2] * scale + 0.5);
-                       }
-                       else {
-                               scale = res / size[2];
-                               smd->domain->scale = size[2];
-                               smd->domain->dx = 1.0f / res;
-                               smd->domain->res[2] = res;
-                               smd->domain->res[0] = (int)(size[0] * scale + 0.5);
-                               smd->domain->res[1] = (int)(size[1] * scale + 0.5);
-                       }
+       invert_m4_m4(sds->imat, ob->obmat);
+
+       // prevent crash when initializing a plane as domain
+       if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
+               return;
+
+       /* define grid resolutions from longest domain side */
+       if (size[0] > MAX2(size[1], size[2])) {
+               scale = res / size[0];
+               sds->scale = size[0] / ob->size[0];
+               sds->base_res[0] = res;
+               sds->base_res[1] = (int)(size[1] * scale + 0.5);
+               sds->base_res[2] = (int)(size[2] * scale + 0.5);
+       }
+       else if (size[1] > MAX2(size[0], size[2])) {
+               scale = res / size[1];
+               sds->scale = size[1] / ob->size[1];
+               sds->base_res[0] = (int)(size[0] * scale + 0.5);
+               sds->base_res[1] = res;
+               sds->base_res[2] = (int)(size[2] * scale + 0.5);
+       }
+       else {
+               scale = res / size[2];
+               sds->scale = size[2] / ob->size[2];
+               sds->base_res[0] = (int)(size[0] * scale + 0.5);
+               sds->base_res[1] = (int)(size[1] * scale + 0.5);
+               sds->base_res[2] = res;
+       }
+
+       /* set cell size */
+       sds->cell_size[0] /= (float)sds->base_res[0];
+       sds->cell_size[1] /= (float)sds->base_res[1];
+       sds->cell_size[2] /= (float)sds->base_res[2];
+}
+
+static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+{
+       if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
+       {
+               SmokeDomainSettings *sds = smd->domain;
+               int res[3];
+               /* set domain dimensions from derivedmesh */
+               smoke_set_domain_from_derivedmesh(sds, ob, dm);
+               /* reset domain values */
+               zero_v3_int(sds->shift);
+               zero_v3(sds->shift_f);
+               add_v3_fl(sds->shift_f, 0.5f);
+               zero_v3(sds->prev_loc);
+               mul_m4_v3(ob->obmat, sds->prev_loc);
+
+               /* set resolutions */
+               if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+                       res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
                }
                else {
-                       if(size[1] > size[2])
-                       {
-                               scale = res / size[1];
-                               smd->domain->scale = size[1];
-                               smd->domain->dx = 1.0f / res; 
-                               smd->domain->res[1] = res;
-                               smd->domain->res[0] = (int)(size[0] * scale + 0.5);
-                               smd->domain->res[2] = (int)(size[2] * scale + 0.5);
-                       }
-                       else {
-                               scale = res / size[2];
-                               smd->domain->scale = size[2];
-                               smd->domain->dx = 1.0f / res;
-                               smd->domain->res[2] = res;
-                               smd->domain->res[0] = (int)(size[0] * scale + 0.5);
-                               smd->domain->res[1] = (int)(size[1] * scale + 0.5);
-                       }
+                       VECCOPY(res, sds->base_res);
                }
+               VECCOPY(sds->res, res);
+               sds->total_cells = sds->res[0]*sds->res[1]*sds->res[2];
+               sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
+               VECCOPY(sds->res_max, res);
 
-               // TODO: put in failsafe if res<=0 - dg
+               /* allocate fluid */
+               smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
 
-               // dt max is 0.1
-               smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, DT_DEFAULT);
                smd->time = scene->r.cfra;
 
-               if(smd->domain->flags & MOD_SMOKE_HIGHRES)
-               {
-                       smd->domain->wt = smoke_turbulence_init(smd->domain->res, smd->domain->amplify + 1, smd->domain->noise);
-                       smd->domain->res_wt[0] = smd->domain->res[0] * (smd->domain->amplify + 1);
-                       smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1);                      
-                       smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1);                      
-                       smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1);              
+               /* allocate highres fluid */
+               if(sds->flags & MOD_SMOKE_HIGHRES) {
+                       smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
                }
+               /* allocate shadow buffer */
+               if(!sds->shadow)
+                       sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], "SmokeDomainShadow");
 
-               if(!smd->domain->shadow)
-                       smd->domain->shadow = MEM_callocN(sizeof(float) * smd->domain->res[0] * smd->domain->res[1] * smd->domain->res[2], "SmokeDomainShadow");
-
-               smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta), &(smd->domain->time_scale), &(smd->domain->vorticity), &(smd->domain->border_collisions));
-
-               if(smd->domain->wt)     
-               {
-                       smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength));
-               }
                return 1;
        }
        else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
        {
-               // handle flow object here
-               // XXX TODO
-
                smd->time = scene->r.cfra;
 
                return 1;
        }
        else if((smd->type & MOD_SMOKE_TYPE_COLL))
        {
-               // todo: delete this when loading colls work -dg
-
                if(!smd->coll)
                {
                        smokeModifier_createType(smd);
                }
 
-               if(!smd->coll->points)
-               {
-                       // init collision points
-                       SmokeCollSettings *scs = smd->coll;
-
-                       smd->time = scene->r.cfra;
-
-                       // copy obmat
-                       copy_m4_m4(scs->mat, ob->obmat);
-                       copy_m4_m4(scs->mat_old, ob->obmat);
-
-                       DM_ensure_tessface(dm);
-                       fill_scs_points(ob, dm, scs);
-               }
+               smd->time = scene->r.cfra;
 
-               if(!smd->coll->bvhtree)
-               {
-                       smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
-               }
                return 1;
        }
 
        return 2;
 }
 
-static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
-{
-       MVert *mvert = dm->getVertArray(dm);
-       MFace *mface = dm->getTessFaceArray(dm);
-       int i = 0, divs = 0;
-
-       // DG TODO: need to do this dynamically according to the domain object!
-       float cell_len = scs->dx;
-       int newdivs = 0;
-       int quads = 0, facecounter = 0;
-
-       // count quads
-       for(i = 0; i < dm->getNumTessFaces(dm); i++)
-       {
-               if(mface[i].v4)
-                       quads++;
-       }
-
-       scs->numtris = dm->getNumTessFaces(dm) + quads;
-       scs->tridivs = NULL;
-       calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface,  dm->getNumTessFaces(dm), scs->numtris, &(scs->tridivs), cell_len);
-
-       // count triangle divisions
-       for(i = 0; i < dm->getNumTessFaces(dm) + quads; i++)
-       {
-               divs += (scs->tridivs[3 * i] + 1) * (scs->tridivs[3 * i + 1] + 1) * (scs->tridivs[3 * i + 2] + 1);
-       }
-
-       scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
-       scs->points_old = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPointsOld");
-
-       for(i = 0; i < dm->getNumVerts(dm); i++)
-       {
-               float tmpvec[3];
-               copy_v3_v3(tmpvec, mvert[i].co);
-               // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
-               copy_v3_v3(&scs->points[i * 3], tmpvec);
-       }
-       
-       for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
-       {
-               int again = 0;
-               do
-               {
-                       int j, k;
-                       int divs1 = scs->tridivs[3 * facecounter + 0];
-                       int divs2 = scs->tridivs[3 * facecounter + 1];
-                       //int divs3 = scs->tridivs[3 * facecounter + 2];
-                       float side1[3], side2[3], trinormorg[3], trinorm[3];
-                       
-                       if(again == 1 && mface[i].v4)
-                       {
-                               sub_v3_v3v3(side1,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
-                               sub_v3_v3v3(side2,  mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
-                       }
-                       else {
-                               sub_v3_v3v3(side1,  mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
-                               sub_v3_v3v3(side2,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
-                       }
-
-                       cross_v3_v3v3(trinormorg, side1, side2);
-                       normalize_v3(trinormorg);
-                       copy_v3_v3(trinorm, trinormorg);
-                       mul_v3_fl(trinorm, 0.25 * cell_len);
-
-                       for(j = 0; j <= divs1; j++)
-                       {
-                               for(k = 0; k <= divs2; k++)
-                               {
-                                       float p1[3], p2[3], p3[3], p[3]={0,0,0}; 
-                                       const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
-                                       const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
-                                       float tmpvec[3];
-                                       
-                                       if(uf+vf > 1.0) 
-                                       {
-                                               // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
-                                               continue;
-                                       }
-
-                                       copy_v3_v3(p1, mvert[ mface[i].v1 ].co);
-                                       if(again == 1 && mface[i].v4)
-                                       {
-                                               copy_v3_v3(p2, mvert[ mface[i].v3 ].co);
-                                               copy_v3_v3(p3, mvert[ mface[i].v4 ].co);
-                                       }
-                                       else {
-                                               copy_v3_v3(p2, mvert[ mface[i].v2 ].co);
-                                               copy_v3_v3(p3, mvert[ mface[i].v3 ].co);
-                                       }
-
-                                       mul_v3_fl(p1, (1.0-uf-vf));
-                                       mul_v3_fl(p2, uf);
-                                       mul_v3_fl(p3, vf);
-                                       
-                                       add_v3_v3v3(p, p1, p2);
-                                       add_v3_v3(p, p3);
-
-                                       if(newdivs > divs)
-                                               printf("mem problem\n");
-
-                                       // mMovPoints.push_back(p + trinorm);
-                                       add_v3_v3v3(tmpvec, p, trinorm);
-                                       // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
-                                       copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
-                                       newdivs++;
-
-                                       if(newdivs > divs)
-                                               printf("mem problem\n");
-
-                                       // mMovPoints.push_back(p - trinorm);
-                                       copy_v3_v3(tmpvec, p);
-                                       sub_v3_v3(tmpvec, trinorm);
-                                       // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
-                                       copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
-                                       newdivs++;
-                               }
-                       }
-
-                       if(again == 0 && mface[i].v4)
-                               again++;
-                       else
-                               again = 0;
-
-                       facecounter++;
-
-               } while(again!=0);
-       }
-
-       scs->numverts = dm->getNumVerts(dm);
-       // DG TODO: also save triangle count?
-
-       scs->numpoints = dm->getNumVerts(dm) + newdivs;
-
-       for(i = 0; i < scs->numpoints * 3; i++)
-       {
-               scs->points_old[i] = scs->points[i];
-       }
-}
-
-
-static void fill_scs_points_anim(Object *UNUSED(ob), DerivedMesh *dm, SmokeCollSettings *scs)
-{
-       MVert *mvert = dm->getVertArray(dm);
-       MFace *mface = dm->getTessFaceArray(dm);
-       int quads = 0, numtris = 0, facecounter = 0;
-       unsigned int i = 0;
-       int divs = 0, newdivs = 0;
-       
-       // DG TODO: need to do this dynamically according to the domain object!
-       float cell_len = scs->dx;
-
-       // count quads
-       for(i = 0; i < dm->getNumTessFaces(dm); i++)
-       {
-               if(mface[i].v4)
-                       quads++;
-       }
-
-       numtris = dm->getNumTessFaces(dm) + quads;
-
-       // check if mesh changed topology
-       if(scs->numtris != numtris)
-               return;
-       if(scs->numverts != dm->getNumVerts(dm))
-               return;
-
-       // update new positions
-       for(i = 0; i < dm->getNumVerts(dm); i++)
-       {
-               float tmpvec[3];
-               copy_v3_v3(tmpvec, mvert[i].co);
-               copy_v3_v3(&scs->points[i * 3], tmpvec);
-       }
-
-       // for every triangle // update div points
-       for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
-       {
-               int again = 0;
-               do
-               {
-                       int j, k;
-                       int divs1 = scs->tridivs[3 * facecounter + 0];
-                       int divs2 = scs->tridivs[3 * facecounter + 1];
-                       float srcside1[3], srcside2[3], destside1[3], destside2[3], src_trinormorg[3], dest_trinormorg[3], src_trinorm[3], dest_trinorm[3];
-                       
-                       if(again == 1 && mface[i].v4)
-                       {
-                               sub_v3_v3v3(srcside1,  &scs->points_old[mface[i].v3 * 3], &scs->points_old[mface[i].v1 * 3]);
-                               sub_v3_v3v3(destside1,  &scs->points[mface[i].v3 * 3], &scs->points[mface[i].v1 * 3]);
-
-                               sub_v3_v3v3(srcside2,  &scs->points_old[mface[i].v4 * 3], &scs->points_old[mface[i].v1 * 3]);
-                               sub_v3_v3v3(destside2,  &scs->points[mface[i].v4 * 3], &scs->points[mface[i].v1 * 3]);
-                       }
-                       else {
-                               sub_v3_v3v3(srcside1,  &scs->points_old[mface[i].v2 * 3], &scs->points_old[mface[i].v1 * 3]);
-                               sub_v3_v3v3(destside1,  &scs->points[mface[i].v2 * 3], &scs->points[mface[i].v1 * 3]);
-
-                               sub_v3_v3v3(srcside2,  &scs->points_old[mface[i].v3 * 3], &scs->points_old[mface[i].v1 * 3]);
-                               sub_v3_v3v3(destside2,  &scs->points[mface[i].v3 * 3], &scs->points[mface[i].v1 * 3]);
-                       }
-
-                       cross_v3_v3v3(src_trinormorg, srcside1, srcside2);
-                       cross_v3_v3v3(dest_trinormorg, destside1, destside2);
-
-                       normalize_v3(src_trinormorg);
-                       normalize_v3(dest_trinormorg);
-
-                       copy_v3_v3(src_trinorm, src_trinormorg);
-                       copy_v3_v3(dest_trinorm, dest_trinormorg);
-
-                       mul_v3_fl(src_trinorm, 0.25 * cell_len);
-                       mul_v3_fl(dest_trinorm, 0.25 * cell_len);
-
-                       for(j = 0; j <= divs1; j++)
-                       {
-                               for(k = 0; k <= divs2; k++)
-                               {
-                                       float src_p1[3], src_p2[3], src_p3[3], src_p[3]={0,0,0};
-                                       float dest_p1[3], dest_p2[3], dest_p3[3], dest_p[3]={0,0,0};
-                                       const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
-                                       const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
-                                       float src_tmpvec[3], dest_tmpvec[3];
-                                       
-                                       if(uf+vf > 1.0) 
-                                       {
-                                               // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
-                                               continue;
-                                       }
-
-                                       copy_v3_v3(src_p1, &scs->points_old[mface[i].v1 * 3]);
-                                       copy_v3_v3(dest_p1, &scs->points[mface[i].v1 * 3]);
-                                       if(again == 1 && mface[i].v4)
-                                       {
-                                               copy_v3_v3(src_p2, &scs->points_old[mface[i].v3 * 3]);
-                                               copy_v3_v3(dest_p2, &scs->points[mface[i].v3 * 3]);
-
-                                               copy_v3_v3(src_p3,&scs->points_old[mface[i].v4 * 3]);
-                                               copy_v3_v3(dest_p3, &scs->points[mface[i].v4 * 3]);
-                                       }
-                                       else {
-                                               copy_v3_v3(src_p2, &scs->points_old[mface[i].v2 * 3]);
-                                               copy_v3_v3(dest_p2, &scs->points[mface[i].v2 * 3]);
-                                               copy_v3_v3(src_p3, &scs->points_old[mface[i].v3 * 3]);
-                                               copy_v3_v3(dest_p3, &scs->points[mface[i].v3 * 3]);
-                                       }
-
-                                       mul_v3_fl(src_p1, (1.0-uf-vf));
-                                       mul_v3_fl(dest_p1, (1.0-uf-vf));
-
-                                       mul_v3_fl(src_p2, uf);
-                                       mul_v3_fl(dest_p2, uf);
-
-                                       mul_v3_fl(src_p3, vf);
-                                       mul_v3_fl(dest_p3, vf);
-
-                                       add_v3_v3v3(src_p, src_p1, src_p2);
-                                       add_v3_v3v3(dest_p, dest_p1, dest_p2);
-
-                                       add_v3_v3(src_p, src_p3);
-                                       add_v3_v3(dest_p, dest_p3);
-
-                                       if(newdivs > divs)
-                                               printf("mem problem\n");
-
-                                       // mMovPoints.push_back(p + trinorm);
-                                       add_v3_v3v3(src_tmpvec, src_p, src_trinorm);
-                                       add_v3_v3v3(dest_tmpvec, dest_p, dest_trinorm);
-
-                                       // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
-                                       copy_v3_v3(&scs->points_old[3 * (dm->getNumVerts(dm) + newdivs)], src_tmpvec);
-                                       copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], dest_tmpvec);
-                                       newdivs++;
-
-                                       if(newdivs > divs)
-                                               printf("mem problem\n");
-
-                                       // mMovPoints.push_back(p - trinorm);
-                                       copy_v3_v3(src_tmpvec, src_p);
-                                       copy_v3_v3(dest_tmpvec, dest_p);
-
-                                       sub_v3_v3(src_tmpvec, src_trinorm);
-                                       sub_v3_v3(dest_tmpvec, dest_trinorm);
-
-                                       // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
-                                       copy_v3_v3(&scs->points_old[3 * (dm->getNumVerts(dm) + newdivs)], src_tmpvec);
-                                       copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], dest_tmpvec);
-                                       newdivs++;
-                               }
-                       }
-
-                       if(again == 0 && mface[i].v4)
-                               again++;
-                       else
-                               again = 0;
-
-                       facecounter++;
-
-               } while(again!=0);
-       }
-
-       // scs->numpoints = dm->getNumVerts(dm) + newdivs;
-
-}
-
-/*! init triangle divisions */
-static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len)
-{
-       // mTriangleDivs1.resize( faces.size() );
-       // mTriangleDivs2.resize( faces.size() );
-       // mTriangleDivs3.resize( faces.size() );
-
-       size_t i = 0, facecounter = 0;
-       float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); get max scale value
-       float maxpart = ABS(maxscale[0]);
-       float scaleFac = 0;
-       float fsTri = 0;
-       if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
-       if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
-       scaleFac = 1.0 / maxpart;
-       // featureSize = mLevel[mMaxRefine].nodeSize
-       fsTri = cell_len * 0.75 * scaleFac; // fsTri = cell_len * 0.9;
-
-       if(*tridivs)
-               MEM_freeN(*tridivs);
-
-       *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
-
-       for(i = 0, facecounter = 0; i < numfaces; i++) 
-       {
-               float p0[3], p1[3], p2[3];
-               float side1[3];
-               float side2[3];
-               float side3[3];
-               int divs1=0, divs2=0, divs3=0;
-
-               copy_v3_v3(p0, verts[faces[i].v1].co);
-               mul_m4_v3(ob->obmat, p0);
-               copy_v3_v3(p1, verts[faces[i].v2].co);
-               mul_m4_v3(ob->obmat, p1);
-               copy_v3_v3(p2, verts[faces[i].v3].co);
-               mul_m4_v3(ob->obmat, p2);
-
-               sub_v3_v3v3(side1, p1, p0);
-               sub_v3_v3v3(side2, p2, p0);
-               sub_v3_v3v3(side3, p1, p2);
-
-               if(dot_v3v3(side1, side1) > fsTri*fsTri)
-               { 
-                       float tmp = normalize_v3(side1);
-                       divs1 = (int)ceil(tmp/fsTri); 
-               }
-               if(dot_v3v3(side2, side2) > fsTri*fsTri)
-               { 
-                       float tmp = normalize_v3(side2);
-                       divs2 = (int)ceil(tmp/fsTri); 
-                       
-                       /*              
-                       // debug
-                       if(i==0)
-                               printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
-                       */
-                       
-               }
-
-               (*tridivs)[3 * facecounter + 0] = divs1;
-               (*tridivs)[3 * facecounter + 1] = divs2;
-               (*tridivs)[3 * facecounter + 2] = divs3;
-
-               // TODO quad case
-               if(faces[i].v4)
-               {
-                       divs1=0, divs2=0, divs3=0;
-
-                       facecounter++;
-                       
-                       copy_v3_v3(p0, verts[faces[i].v3].co);
-                       mul_m4_v3(ob->obmat, p0);
-                       copy_v3_v3(p1, verts[faces[i].v4].co);
-                       mul_m4_v3(ob->obmat, p1);
-                       copy_v3_v3(p2, verts[faces[i].v1].co);
-                       mul_m4_v3(ob->obmat, p2);
-
-                       sub_v3_v3v3(side1, p1, p0);
-                       sub_v3_v3v3(side2, p2, p0);
-                       sub_v3_v3v3(side3, p1, p2);
-
-                       if(dot_v3v3(side1, side1) > fsTri*fsTri)
-                       { 
-                               float tmp = normalize_v3(side1);
-                               divs1 = (int)ceil(tmp/fsTri); 
-                       }
-                       if(dot_v3v3(side2, side2) > fsTri*fsTri)
-                       { 
-                               float tmp = normalize_v3(side2);
-                               divs2 = (int)ceil(tmp/fsTri); 
-                       }
-
-                       (*tridivs)[3 * facecounter + 0] = divs1;
-                       (*tridivs)[3 * facecounter + 1] = divs2;
-                       (*tridivs)[3 * facecounter + 2] = divs3;
-               }
-               facecounter++;
-       }
-}
-
 #endif /* WITH_SMOKE */
 
 static void smokeModifier_freeDomain(SmokeModifierData *smd)
@@ -750,14 +381,8 @@ static void smokeModifier_freeFlow(SmokeModifierData *smd)
 {
        if(smd->flow)
        {
-/*
-               if(smd->flow->bvh)
-               {
-                       free_bvhtree_from_mesh(smd->flow->bvh);
-                       MEM_freeN(smd->flow->bvh);
-               }
-               smd->flow->bvh = NULL;
-*/
+               if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
+               if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
                MEM_freeN(smd->flow);
                smd->flow = NULL;
        }
@@ -769,36 +394,18 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd)
        {
                SmokeCollSettings *scs = smd->coll;
 
-               if(scs->numpoints)
+               if(scs->numverts)
                {
-                       if(scs->points)
-                       {
-                               MEM_freeN(scs->points);
-                               scs->points = NULL;
-                       }
-                       if(scs->points_old)
+                       if(scs->verts_old)
                        {
-                               MEM_freeN(scs->points_old);
-                               scs->points_old = NULL;
-                       }
-                       if(scs->tridivs)
-                       {
-                               MEM_freeN(scs->tridivs);
-                               scs->tridivs = NULL;
+                               MEM_freeN(scs->verts_old);
+                               scs->verts_old = NULL;
                        }
                }
 
-               if(scs->bvhtree)
-               {
-                       BLI_bvhtree_free(scs->bvhtree);
-                       scs->bvhtree = NULL;
-               }
-
-#ifdef USE_SMOKE_COLLISION_DM
                if(smd->coll->dm)
                        smd->coll->dm->release(smd->coll->dm);
                smd->coll->dm = NULL;
-#endif
 
                MEM_freeN(smd->coll);
                smd->coll = NULL;
@@ -833,39 +440,23 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
                        smokeModifier_reset_turbulence(smd);
 
                        smd->time = -1;
-
-                       // printf("reset domain end\n");
+                       smd->domain->total_cells = 0;
+                       smd->domain->active_fields = 0;
                }
                else if(smd->flow)
                {
-                       /*
-                       if(smd->flow->bvh)
-                       {
-                               free_bvhtree_from_mesh(smd->flow->bvh);
-                               MEM_freeN(smd->flow->bvh);
-                       }
-                       smd->flow->bvh = NULL;
-                       */
+                       if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
+                       smd->flow->verts_old = NULL;
+                       smd->flow->numverts = 0;
                }
                else if(smd->coll)
                {
                        SmokeCollSettings *scs = smd->coll;
 
-                       if(scs->numpoints && scs->points)
+                       if(scs->numverts && scs->verts_old)
                        {
-                               MEM_freeN(scs->points);
-                               scs->points = NULL;
-                       
-                               if(scs->points_old)
-                               {
-                                       MEM_freeN(scs->points_old);
-                                       scs->points_old = NULL;
-                               }
-                               if(scs->tridivs)
-                               {
-                                       MEM_freeN(scs->tridivs);
-                                       scs->tridivs = NULL;
-                               }
+                               MEM_freeN(scs->verts_old);
+                               scs->verts_old = NULL;
                        }
                }
        }
@@ -908,8 +499,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->domain->fluid_group = NULL;
                        smd->domain->coll_group = NULL;
                        smd->domain->maxres = 32;
-                       smd->domain->amplify = 1;                       
-                       smd->domain->omega = 1.0;                       
+                       smd->domain->amplify = 1;                                       
                        smd->domain->alpha = -0.001;
                        smd->domain->beta = 0.1;
                        smd->domain->time_scale = 1.0;
@@ -919,7 +509,21 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->domain->strength = 2.0;
                        smd->domain->noise = MOD_SMOKE_NOISEWAVE;
                        smd->domain->diss_speed = 5;
-                       // init 3dview buffer
+                       smd->domain->active_fields = 0;
+
+                       smd->domain->adapt_margin = 4;
+                       smd->domain->adapt_res = 0;
+                       smd->domain->adapt_threshold = 0.02f;
+
+                       smd->domain->burning_rate = 0.75f;
+                       smd->domain->flame_smoke = 1.0f;
+                       smd->domain->flame_vorticity = 0.5f;
+                       smd->domain->flame_ignition = 1.25f;
+                       smd->domain->flame_max_temp = 1.75f;
+                       /* color */
+                       smd->domain->flame_smoke_color[0] = 0.7f;
+                       smd->domain->flame_smoke_color[1] = 0.7f;
+                       smd->domain->flame_smoke_color[2] = 0.7f;
 
                        smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
                        smd->domain->effector_weights = BKE_add_effector_weights(NULL);
@@ -934,11 +538,20 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->flow->smd = smd;
 
                        /* set some standard values */
-                       smd->flow->density = 1.0;
-                       smd->flow->temp = 1.0;
+                       smd->flow->density = 1.0f;
+                       smd->flow->fuel_amount = 1.0f;
+                       smd->flow->temp = 1.0f;
                        smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE;
-                       smd->flow->vel_multi = 1.0;
+                       smd->flow->vel_multi = 1.0f;
+                       smd->flow->surface_distance = 1.5f;
+                       smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
+                       smd->flow->texture_size = 1.0f;
 
+                       smd->flow->color[0] = 0.7f;
+                       smd->flow->color[1] = 0.7f;
+                       smd->flow->color[2] = 0.7f;
+
+                       smd->flow->dm = NULL;
                        smd->flow->psys = NULL;
 
                }
@@ -950,15 +563,10 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
 
                        smd->coll->smd = smd;
-                       smd->coll->points = NULL;
-                       smd->coll->points_old = NULL;
-                       smd->coll->tridivs = NULL;
-                       smd->coll->vel = NULL;
-                       smd->coll->numpoints = 0;
-                       smd->coll->numtris = 0;
-                       smd->coll->bvhtree = NULL;
+                       smd->coll->verts_old = NULL;
+                       smd->coll->numverts = 0;
                        smd->coll->type = 0; // static obstacle
-                       smd->coll->dx = 1.0f / 50.0f;
+                       smd->coll->dm = NULL;
 
 #ifdef USE_SMOKE_COLLISION_DM
                        smd->coll->dm = NULL;
@@ -975,32 +583,61 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
        smokeModifier_createType(tsmd);
 
        if (tsmd->domain) {
-               tsmd->domain->maxres = smd->domain->maxres;
-               tsmd->domain->amplify = smd->domain->amplify;
-               tsmd->domain->omega = smd->domain->omega;
+               tsmd->domain->fluid_group = smd->domain->fluid_group;
+               tsmd->domain->coll_group = smd->domain->coll_group;
+
+               tsmd->domain->adapt_margin = smd->domain->adapt_margin;
+               tsmd->domain->adapt_res = smd->domain->adapt_res;
+               tsmd->domain->adapt_threshold = smd->domain->adapt_threshold;
+
                tsmd->domain->alpha = smd->domain->alpha;
                tsmd->domain->beta = smd->domain->beta;
+               tsmd->domain->amplify = smd->domain->amplify;
+               tsmd->domain->maxres = smd->domain->maxres;
                tsmd->domain->flags = smd->domain->flags;
-               tsmd->domain->strength = smd->domain->strength;
+               tsmd->domain->viewsettings = smd->domain->viewsettings;
                tsmd->domain->noise = smd->domain->noise;
                tsmd->domain->diss_speed = smd->domain->diss_speed;
-               tsmd->domain->viewsettings = smd->domain->viewsettings;
-               tsmd->domain->fluid_group = smd->domain->fluid_group;
-               tsmd->domain->coll_group = smd->domain->coll_group;
+               tsmd->domain->strength = smd->domain->strength;
+
+               tsmd->domain->border_collisions = smd->domain->border_collisions;
                tsmd->domain->vorticity = smd->domain->vorticity;
                tsmd->domain->time_scale = smd->domain->time_scale;
-               tsmd->domain->border_collisions = smd->domain->border_collisions;
+
+               tsmd->domain->burning_rate = smd->domain->burning_rate;
+               tsmd->domain->flame_smoke = smd->domain->flame_smoke;
+               tsmd->domain->flame_vorticity = smd->domain->flame_vorticity;
+               tsmd->domain->flame_ignition = smd->domain->flame_ignition;
+               tsmd->domain->flame_max_temp = smd->domain->flame_max_temp;
+               copy_v3_v3(tsmd->domain->flame_smoke_color, smd->domain->flame_smoke_color);
                
                MEM_freeN(tsmd->domain->effector_weights);
                tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
        } 
        else if (tsmd->flow) {
+               tsmd->flow->psys = smd->flow->psys;
+               tsmd->flow->noise_texture = smd->flow->noise_texture;
+
+               tsmd->flow->vel_multi = smd->flow->vel_multi;
+               tsmd->flow->vel_normal = smd->flow->vel_normal;
+               tsmd->flow->vel_random = smd->flow->vel_random;
+
                tsmd->flow->density = smd->flow->density;
+               copy_v3_v3(tsmd->flow->color, smd->flow->color);
+               tsmd->flow->fuel_amount = smd->flow->fuel_amount;
                tsmd->flow->temp = smd->flow->temp;
-               tsmd->flow->psys = smd->flow->psys;
+               tsmd->flow->volume_density = smd->flow->volume_density;
+               tsmd->flow->surface_distance = smd->flow->surface_distance;
+
+               tsmd->flow->texture_size = smd->flow->texture_size;
+               tsmd->flow->texture_offset = smd->flow->texture_offset;
+               BLI_strncpy(tsmd->flow->uvlayer_name, tsmd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name));
+               tsmd->flow->vgroup_density = smd->flow->vgroup_density;
+
                tsmd->flow->type = smd->flow->type;
+               tsmd->flow->source = smd->flow->source;
+               tsmd->flow->texture_type = smd->flow->texture_type;
                tsmd->flow->flags = smd->flow->flags;
-               tsmd->flow->vel_multi = smd->flow->vel_multi;
        }
        else if (tsmd->coll) {
                ;
@@ -1011,7 +648,7 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
 #ifdef WITH_SMOKE
 
 // forward decleration
-static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct);
+static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene);
 static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
 
 static int get_lamp(Scene *scene, float *light)
@@ -1038,44 +675,127 @@ static int get_lamp(Scene *scene, float *light)
        return found_lamp;
 }
 
-static void smoke_calc_domain(Scene *UNUSED(scene), Object *UNUSED(ob), SmokeModifierData *UNUSED(smd))
+static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs, unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
 {
-#if 0
-       SmokeDomainSettings *sds = smd->domain;
-       GroupObject *go = NULL;                 
-       Base *base = NULL;
-
-       /* do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells */
-       if(1)
+       if (!scs->dm) return;
        {
-               unsigned int i;
-               Object **collobjs = NULL;
-               unsigned int numcollobj = 0;
-               collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj);
+               DerivedMesh *dm = NULL;
+               MVert *mvert = NULL;
+               MFace *mface = NULL;
+               BVHTreeFromMesh treeData = {0};
+               int numverts, i, z;
+               int *res = sds->res;
+
+               float surface_distance = 0.6;
+
+               float *vert_vel = NULL;
+               int has_velocity = 0;
+
+               tstart();
+
+               dm = CDDM_copy(scs->dm);
+               CDDM_calc_normals(dm);
+               mvert = dm->getVertArray(dm);
+               mface = dm->getTessFaceArray(dm);
+               numverts = dm->getNumVerts(dm);
+
+               // DG TODO
+               // if(scs->type > SM_COLL_STATIC)
+               // if line above is used, the code is in trouble if the object moves but is declared as "does not move"
 
-               for(i = 0; i < numcollobj; i++)
                {
-                       Object *collob= collobjs[i];
-                       SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);                
-                       
-                       // check for active smoke modifier
-                       // if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
-                       // SmokeModifierData *smd2 = (SmokeModifierData *)md;
+                       vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
+
+                       if (scs->numverts != numverts || !scs->verts_old) {
+                               if (scs->verts_old) MEM_freeN(scs->verts_old);
 
-                       if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old)
+                               scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
+                               scs->numverts = numverts;
+                       }
+                       else {
+                               has_velocity = 1;
+                       }
+               }
+
+               /*      Transform collider vertices to
+               *   domain grid space for fast lookups */
+               for (i = 0; i < numverts; i++) {
+                       float n[3];
+                       float co[3];
+
+                       /* vert pos */
+                       mul_m4_v3(coll_ob->obmat, mvert[i].co);
+                       smoke_pos_to_cell(sds, mvert[i].co);
+
+                       /* vert normal */
+                       normal_short_to_float_v3(n, mvert[i].no);
+                       mul_mat3_m4_v3(coll_ob->obmat, n);
+                       mul_mat3_m4_v3(sds->imat, n);
+                       normalize_v3(n);
+                       normal_float_to_short_v3(mvert[i].no, n);
+
+                       /* vert velocity */
+                       VECADD(co, mvert[i].co, sds->shift);
+                       if (has_velocity) 
                        {
-                               // ??? anything to do here?
+                               sub_v3_v3v3(&vert_vel[i*3], co, &scs->verts_old[i*3]);
+                               mul_v3_fl(&vert_vel[i*3], sds->dx/dt);
+                       }
+                       copy_v3_v3(&scs->verts_old[i*3], co);
+               }
+
+               if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6)) {
+                       #pragma omp parallel for schedule(static)
+                       for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
+                               int x,y;
+                               for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
+                               for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
+                                       int index = smoke_get_index(x-sds->res_min[0], sds->res[0], y-sds->res_min[1], sds->res[1], z-sds->res_min[2]);
+
+                                       float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+                                       BVHTreeNearest nearest = {0};
+                                       nearest.index = -1;
+                                       nearest.dist = surface_distance * surface_distance; /* find_nearest uses squared distance */
+
+                                       /* find the nearest point on the mesh */
+                                       if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, treeData.nearest_callback, &treeData) != -1) {
+                                               float weights[4];
+                                               int v1, v2, v3, f_index = nearest.index;
+
+                                               /* calculate barycentric weights for nearest point */
+                                               v1 = mface[f_index].v1;
+                                               v2 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v3 : mface[f_index].v2;
+                                               v3 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v4 : mface[f_index].v3;
+                                               interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+
+                                               // DG TODO
+                                               if(has_velocity)
+                                               {
+                                                       /* apply object velocity */
+                                                       {
+                                                               float hit_vel[3];
+                                                               interp_v3_v3v3v3(hit_vel, &vert_vel[v1*3], &vert_vel[v2*3], &vert_vel[v3*3], weights);
+                                                               velocityX[index] += hit_vel[0];
+                                                               velocityY[index] += hit_vel[1];
+                                                               velocityZ[index] += hit_vel[2];
+                                                       }
+                                               }
 
-                               // TODO: only something to do for ANIMATED obstacles: need to update positions
+                                               /* tag obstacle cells */
+                                               obstacle_map[index] = 1;
 
+                                               if(has_velocity)
+                                                       obstacle_map[index] |= 8;
+                                       }
+                               }
                        }
                }
+               /* free bvh tree */
+               free_bvhtree_from_mesh(&treeData);
+               dm->release(dm);
 
-               if(collobjs)
-                       MEM_freeN(collobjs);
+               if (vert_vel) MEM_freeN(vert_vel);
        }
-
-#endif
 }
 
 /* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
@@ -1092,142 +812,833 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
        float *velxOrig = smoke_get_velocity_x(sds->fluid);
        float *velyOrig = smoke_get_velocity_y(sds->fluid);
        float *velzOrig = smoke_get_velocity_z(sds->fluid);
-       // float *density = smoke_get_density(sds->fluid);
+       float *density = smoke_get_density(sds->fluid);
+       float *fuel = smoke_get_fuel(sds->fluid);
+       float *flame = smoke_get_flame(sds->fluid);
+       float *r = smoke_get_color_r(sds->fluid);
+       float *g = smoke_get_color_g(sds->fluid);
+       float *b = smoke_get_color_b(sds->fluid);
        unsigned int z;
 
-       smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
+       smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
+
+       // TODO: delete old obstacle flags
+       for(z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
+       {
+               if(obstacles[z] & 8) // Do not delete static obstacles
+               {
+                       obstacles[z] = 0;
+               }
+
+               velx[z] = 0;
+               vely[z] = 0;
+               velz[z] = 0;
+       }
+
+
+       collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+
+       // update obstacle tags in cells
+       for(collIndex = 0; collIndex < numcollobj; collIndex++)
+       {
+               Object *collob= collobjs[collIndex];
+               SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
+
+               // DG TODO: check if modifier is active?
+               
+               if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
+               {
+                       SmokeCollSettings *scs = smd2->coll;
+                       obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, dt);
+               }
+       }
+
+       if(collobjs)
+               MEM_freeN(collobjs);
+
+       /* obstacle cells should not contain any velocity from the smoke simulation */
+       for(z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
+       {
+               if(obstacles[z])
+               {
+                       velxOrig[z] = 0;
+                       velyOrig[z] = 0;
+                       velzOrig[z] = 0;
+                       density[z] = 0;
+                       if (fuel) {
+                               fuel[z] = 0;
+                               flame[z] = 0;
+                       }
+                       if (r) {
+                               r[z] = 0;
+                               g[z] = 0;
+                               b[z] = 0;
+                       }
+               }
+       }
+}
+
+
+typedef struct EmissionMap {
+       float *influence;
+       float *velocity;
+       int min[3], max[3], res[3];
+       int total_cells, valid;
+} EmissionMap;
+
+static void em_boundInsert(EmissionMap *em, float point[3])
+{
+       int i = 0;
+       if (!em->valid) {
+               VECCOPY(em->min, point);
+               VECCOPY(em->max, point);
+               em->valid = 1;
+       }
+       else {
+               for (; i < 3; i++) {
+                       if (point[i] < em->min[i]) em->min[i] = (int)floor(point[i]);
+                       if (point[i] > em->max[i]) em->max[i] = (int)ceil(point[i]);
+               }
+       }
+}
+
+static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3], float *min_vel, float *max_vel, int margin, float dt)
+{
+       int i;
+       for (i=0; i<3; i++) {
+               int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
+               /* add margin */
+               min[i] -= margin;
+               max[i] += margin;
+
+               /* adapt to velocity */
+               if (min_vel && min_vel[i]<0.0f) {
+                       min[i] += (int)ceil(min_vel[i] * dt);
+               }
+               if (max_vel && max_vel[i]>0.0f) {
+                       max[i] += (int)ceil(max_vel[i] * dt);
+               }
+
+               /* clamp within domain max size */
+               CLAMP(min[i], -adapt, sds->base_res[i]+adapt);
+               CLAMP(max[i], -adapt, sds->base_res[i]+adapt);
+       }
+}
+
+static void em_allocateData(EmissionMap *em, int use_velocity) {
+       int i, res[3];
+
+       for (i=0; i<3; i++) {
+               res[i] = em->max[i] - em->min[i];
+               if (res[i] <= 0)
+                       return;
+       }
+       em->total_cells = res[0]*res[1]*res[2];
+       copy_v3_v3_int(em->res, res);
+
+
+       em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
+       if (use_velocity)
+               em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
+}
+
+static void em_freeData(EmissionMap *em) {
+       if (em->influence)
+               MEM_freeN(em->influence);
+       if (em->velocity)
+               MEM_freeN(em->velocity);
+}
+
+
+static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float time, float dt)
+{
+       if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
+       {
+               ParticleSimulationData sim;
+               ParticleSystem *psys = sfs->psys;
+               float *particle_pos;
+               float *particle_vel;
+               int totpart=psys->totpart, totchild;
+               int p = 0;
+               int valid_particles = 0;
+
+               sim.scene = scene;
+               sim.ob = flow_ob;
+               sim.psys = psys;
+
+               if(psys->part->type==PART_HAIR)
+               {
+                       // TODO: PART_HAIR not supported whatsoever
+                       totchild=0;
+               }
+               else
+                       totchild=psys->totchild*psys->part->disp/100;
+
+               particle_pos = MEM_callocN(sizeof(float) * (totpart+totchild) * 3, "smoke_flow_particles");
+               particle_vel = MEM_callocN(sizeof(float) * (totpart+totchild) * 3, "smoke_flow_particles");
+
+               /* calculate local position for each particle */
+               for(p=0; p<totpart+totchild; p++)
+               {
+                       ParticleKey state;
+                       float *pos;
+                       if(p < totpart) {
+                               if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
+                                       continue;
+                       }
+                       else {
+                               /* handle child particle */
+                               ChildParticle *cpa = &psys->child[p - totpart];
+                               if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
+                                       continue;
+                       }
+
+                       state.time = time;
+                       if(psys_get_particle_state(&sim, p, &state, 0) == 0)
+                               continue;
+
+                       /* location */
+                       pos = &particle_pos[valid_particles*3];
+                       copy_v3_v3(pos, state.co);
+                       smoke_pos_to_cell(sds, pos);
+
+                       /* velocity */
+                       copy_v3_v3(&particle_vel[valid_particles*3], state.vel);
+                       mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles*3]);
+
+                       /* calculate emission map bounds */
+                       em_boundInsert(em, pos);
+                       valid_particles++;
+               }
+
+               /* set emission map */
+               clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, 1, dt);
+               em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY);
+
+               for(p=0; p<valid_particles; p++)
+               {
+                       int cell[3];
+                       size_t i = 0;
+                       size_t index = 0;
+                       int badcell = 0;
+
+                       /* 1. get corresponding cell */
+                       cell[0] = floor(particle_pos[p*3]) - em->min[0];
+                       cell[1] = floor(particle_pos[p*3+1]) - em->min[1];
+                       cell[2] = floor(particle_pos[p*3+2]) - em->min[2];
+                       /* check if cell is valid (in the domain boundary) */
+                       for(i = 0; i < 3; i++) {
+                               if((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
+                                       badcell = 1;
+                                       break;
+                               }
+                       }
+                       if(badcell)
+                               continue;
+                       /* get cell index */
+                       index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
+                       /* Add influence to emission map */
+                       em->influence[index] = 1.0f;
+                       /* Uses particle velocity as initial velocity for smoke */
+                       if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
+                       {
+                               VECADDFAC(&em->velocity[index*3], &em->velocity[index*3], &particle_vel[p*3], sfs->vel_multi);
+                       }
+               }       // particles loop
+
+               /* free data */
+               if (particle_pos)
+                       MEM_freeN(particle_pos);
+               if (particle_vel)
+                       MEM_freeN(particle_vel);
+       }
+}
+
+static void get_texture_value(Tex *texture, float *tex_co, TexResult *texres)
+{
+       int result_type;
+
+       /* no node textures for now */
+       result_type = multitex_ext_safe(texture, tex_co, texres);
+
+       /* if the texture gave an RGB value, we assume it didn't give a valid
+        * intensity, since this is in the context of modifiers don't use perceptual color conversion.
+        * if the texture didn't give an RGB value, copy the intensity across
+        */
+       if (result_type & TEX_RGB) {
+               texres->tin = (1.0f / 3.0f) * (texres->tr + texres->tg + texres->tb);
+       }
+       else {
+               copy_v3_fl(&texres->tr, texres->tin);
+       }
+}
+
+static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
+{
+       if (!sfs->dm) return;
+       {
+               DerivedMesh *dm = sfs->dm;
+               int defgrp_index = sfs->vgroup_density-1;
+               MDeformVert *dvert = NULL;
+               MVert *mvert = NULL;
+               MVert *mvert_orig = NULL;
+               MFace *mface = NULL;
+               MTFace *tface = NULL;
+               BVHTreeFromMesh treeData = {0};
+               int numOfVerts, i, z;
+               float flow_center[3] = {0};
+
+               float *vert_vel = NULL;
+               int has_velocity = 0;
+
+               CDDM_calc_normals(dm);
+               mvert = dm->getVertArray(dm);
+               mvert_orig = dm->dupVertArray(dm);      /* copy original mvert and restore when done */
+               mface = dm->getTessFaceArray(dm);
+               numOfVerts = dm->getNumVerts(dm);
+               dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+               tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, sfs->uvlayer_name);
+
+               if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+                       vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
+
+                       if (sfs->numverts != numOfVerts || !sfs->verts_old) {
+                               if (sfs->verts_old) MEM_freeN(sfs->verts_old);
+                               sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
+                               sfs->numverts = numOfVerts;
+                       }
+                       else {
+                               has_velocity = 1;
+                       }
+               }
+
+               /*      Transform dm vertices to
+               *   domain grid space for fast lookups */
+               for (i = 0; i < numOfVerts; i++) {
+                       float n[3];
+                       /* vert pos */
+                       mul_m4_v3(flow_ob->obmat, mvert[i].co);
+                       smoke_pos_to_cell(sds, mvert[i].co);
+                       /* vert normal */
+                       normal_short_to_float_v3(n, mvert[i].no);
+                       mul_mat3_m4_v3(flow_ob->obmat, n);
+                       mul_mat3_m4_v3(sds->imat, n);
+                       normalize_v3(n);
+                       normal_float_to_short_v3(mvert[i].no, n);
+                       /* vert velocity */
+                       if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+                               float co[3];
+                               VECADD(co, mvert[i].co, sds->shift);
+                               if (has_velocity) {
+                                       sub_v3_v3v3(&vert_vel[i*3], co, &sfs->verts_old[i*3]);
+                                       mul_v3_fl(&vert_vel[i*3], sds->dx/dt);
+                               }
+                               copy_v3_v3(&sfs->verts_old[i*3], co);
+                       }
+
+                       /* calculate emission map bounds */
+                       em_boundInsert(em, mvert[i].co);
+               }
+               mul_m4_v3(flow_ob->obmat, flow_center);
+               smoke_pos_to_cell(sds, flow_center);
+
+               /* set emission map */
+               clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, sfs->surface_distance, dt);
+               em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY);
+
+               if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6)) {
+                       #pragma omp parallel for schedule(static)
+                       for (z = em->min[2]; z < em->max[2]; z++) {
+                               int x,y;
+                               for (x = em->min[0]; x < em->max[0]; x++)
+                               for (y = em->min[1]; y < em->max[1]; y++) {
+                                       int index = smoke_get_index(x-em->min[0], em->res[0], y-em->min[1], em->res[1], z-em->min[2]);
+
+                                       float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+                                       float ray_dir[3] = {1.0f, 0.0f, 0.0f};
+
+                                       BVHTreeRayHit hit = {0};
+                                       BVHTreeNearest nearest = {0};
+
+                                       float volume_factor = 0.0f;
+                                       float sample_str = 0.0f;
+
+                                       hit.index = -1;
+                                       hit.dist = 9999;
+                                       nearest.index = -1;
+                                       nearest.dist = sfs->surface_distance * sfs->surface_distance; /* find_nearest uses squared distance */
+
+                                       /* Check volume collision */
+                                       if (sfs->volume_density) {
+                                               if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) {
+                                                       float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
+                                                       /*  If ray and hit face normal are facing same direction
+                                                        *      hit point is inside a closed mesh. */
+                                                       if (dot >= 0) {
+                                                               /* Also cast a ray in opposite direction to make sure
+                                                                * point is at least surrounded by two faces */
+                                                               negate_v3(ray_dir);
+                                                               hit.index = -1;
+                                                               hit.dist = 9999;
+
+                                                               BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, treeData.raycast_callback, &treeData);
+                                                               if (hit.index != -1) {
+                                                                       volume_factor = sfs->volume_density;
+                                                                       nearest.dist = hit.dist*hit.dist;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       /* find the nearest point on the mesh */
+                                       if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, treeData.nearest_callback, &treeData) != -1) {
+                                               float weights[4];
+                                               int v1, v2, v3, f_index = nearest.index;
+                                               float n1[3], n2[3], n3[3], hit_normal[3];
+
+                                               /* emit from surface based on distance */
+                                               if (sfs->surface_distance) {
+                                                       sample_str = sqrtf(nearest.dist) / sfs->surface_distance;
+                                                       CLAMP(sample_str, 0.0f, 1.0f);
+                                                       sample_str = pow(1.0f - sample_str, 0.5f);
+                                               }
+                                               else
+                                                       sample_str = 0.0f;
+
+                                               /* calculate barycentric weights for nearest point */
+                                               v1 = mface[f_index].v1;
+                                               v2 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v3 : mface[f_index].v2;
+                                               v3 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v4 : mface[f_index].v3;
+                                               interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+
+                                               if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+                                                       /* apply normal directional velocity */
+                                                       if (sfs->vel_normal) {
+                                                               /* interpolate vertex normal vectors to get nearest point normal */
+                                                               normal_short_to_float_v3(n1, mvert[v1].no);
+                                                               normal_short_to_float_v3(n2, mvert[v2].no);
+                                                               normal_short_to_float_v3(n3, mvert[v3].no);
+                                                               interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+                                                               normalize_v3(hit_normal);
+                                                               /* apply normal directional and random velocity
+                                                               * - TODO: random disabled for now since it doesnt really work well as pressure calc smoothens it out... */
+                                                               em->velocity[index*3]   += hit_normal[0]*sfs->vel_normal * 0.25f;
+                                                               em->velocity[index*3+1] += hit_normal[1]*sfs->vel_normal * 0.25f;
+                                                               em->velocity[index*3+2] += hit_normal[2]*sfs->vel_normal * 0.25f;
+                                                               /* TODO: for fire emitted from mesh surface we can use
+                                                               *  Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
+                                                       }
+                                                       /* apply object velocity */
+                                                       if (has_velocity && sfs->vel_multi) {
+                                                               float hit_vel[3];
+                                                               interp_v3_v3v3v3(hit_vel, &vert_vel[v1*3], &vert_vel[v2*3], &vert_vel[v3*3], weights);
+                                                               em->velocity[index*3]   += hit_vel[0] * sfs->vel_multi;
+                                                               em->velocity[index*3+1] += hit_vel[1] * sfs->vel_multi;
+                                                               em->velocity[index*3+2] += hit_vel[2] * sfs->vel_multi;
+                                                       }
+                                               }
 
-       // TODO: delete old obstacle flags
-       for(z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
-       {
-               if(obstacles[z])
-               {
-                       // density[z] = 0;
+                                               /* apply vertex group influence if used */
+                                               if (defgrp_index >= 0 && dvert) {
+                                                       float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+                                                                                               defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+                                                                                               defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+                                                       sample_str *= weight_mask;
+                                               }
 
-                       velxOrig[z] = 0;
-                       velyOrig[z] = 0;
-                       velzOrig[z] = 0;
-               }
+                                               /* apply emission texture */
+                                               if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
+                                                       float tex_co[3] = {0};
+                                                       TexResult texres;
+
+                                                       if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
+                                                               tex_co[0] = ((float)(x - flow_center[0]) / sds->base_res[0]) / sfs->texture_size;
+                                                               tex_co[1] = ((float)(y - flow_center[1]) / sds->base_res[1]) / sfs->texture_size;
+                                                               tex_co[2] = ((float)(z - flow_center[2]) / sds->base_res[2] - sfs->texture_offset) / sfs->texture_size;
+                                                       }
+                                                       else if (tface) {
+                                                               interp_v2_v2v2v2(tex_co, tface[f_index].uv[0], tface[f_index].uv[(nearest.flags & BVH_ONQUAD) ? 2 : 1], 
+                                                                                                                                  tface[f_index].uv[(nearest.flags & BVH_ONQUAD) ? 3 : 2], weights);
+                                                               /* map between -1.0f and 1.0f */
+                                                               tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+                                                               tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+                                                               tex_co[2] = sfs->texture_offset;
+                                                       }
+                                                       texres.nor = NULL;
+                                                       get_texture_value(sfs->noise_texture, tex_co, &texres);
+                                                       sample_str *= texres.tin;
+                                               }
+                                       }
 
-               if(obstacles[z] & 8) // Do not delete static obstacles
-               {
-                       obstacles[z] = 0;
-               }
+                                       /* multiply initial velocity by emitter influence */
+                                       if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+                                               mul_v3_fl(&em->velocity[index*3], sample_str);
+                                       }
 
-               velx[z] = 0;
-               vely[z] = 0;
-               velz[z] = 0;
+                                       /* apply final influence based on volume factor */
+                                       em->influence[index] = MAX2(volume_factor, sample_str);
+                               }
+                       }
+               }
+               /* free bvh tree */
+               free_bvhtree_from_mesh(&treeData);
+               /* restore original mverts */
+               CustomData_set_layer(&dm->vertData, CD_MVERT, mvert_orig);
+               if (mvert)
+                       MEM_freeN(mvert);
+
+               if (vert_vel) MEM_freeN(vert_vel);
        }
+}
 
-       collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], EmissionMap *emaps, unsigned int numflowobj, float dt)
+{
+       int min[3]={32767,32767,32767}, max[3]={-32767,-32767,-32767}, res[3];
+       int total_cells = 1, res_changed = 0, shift_changed = 0;
+       float min_vel[3], max_vel[3];
+       int x,y,z, i;
+       float *density = smoke_get_density(sds->fluid);
+       float *fuel = smoke_get_fuel(sds->fluid);
+       float *vx = smoke_get_velocity_x(sds->fluid);
+       float *vy = smoke_get_velocity_y(sds->fluid);
+       float *vz = smoke_get_velocity_z(sds->fluid);
+
+       INIT_MINMAX(min_vel, max_vel);
+
+       /* Calculate bounds for current domain content */
+       for(x = sds->res_min[0]; x <  sds->res_max[0]; x++)
+               for(y =  sds->res_min[1]; y <  sds->res_max[1]; y++)
+                       for(z =  sds->res_min[2]; z <  sds->res_max[2]; z++)
+                       {
+                               int xn = x-new_shift[0];
+                               int yn = y-new_shift[1];
+                               int zn = z-new_shift[2];
+                               int index = smoke_get_index(x-sds->res_min[0], sds->res[0], y-sds->res_min[1], sds->res[1], z-sds->res_min[2]);
+                               float max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
+
+                               /* content bounds (use shifted coordinates) */
+                               if (max_den >= sds->adapt_threshold) {
+                                       if (min[0] > xn) min[0] = xn;
+                                       if (min[1] > yn) min[1] = yn;
+                                       if (min[2] > zn) min[2] = zn;
+                                       if (max[0] < xn) max[0] = xn;
+                                       if (max[1] < yn) max[1] = yn;
+                                       if (max[2] < zn) max[2] = zn;
+                               }
+                               /* velocity bounds */
+                               if (min_vel[0] > vx[index]) min_vel[0] = vx[index];
+                               if (min_vel[1] > vy[index]) min_vel[1] = vy[index];
+                               if (min_vel[2] > vz[index]) min_vel[2] = vz[index];
+                               if (max_vel[0] < vx[index]) max_vel[0] = vx[index];
+                               if (max_vel[1] < vy[index]) max_vel[1] = vy[index];
+                               if (max_vel[2] < vz[index]) max_vel[2] = vz[index];
+                       }
 
-       // update obstacle tags in cells
-       for(collIndex = 0; collIndex < numcollobj; collIndex++)
+       /* also apply emission maps */
+       for(i = 0; i < numflowobj; i++)
        {
-               Object *collob= collobjs[collIndex];
-               SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
+               EmissionMap *em = &emaps[i];
 
-               // DG TODO: check if modifier is active?
-               
-               if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old)
-               {
-                       SmokeCollSettings *scs = smd2->coll;
-                       unsigned int i;
+               for(x = em->min[0]; x < em->max[0]; x++)
+                       for(y = em->min[1]; y < em->max[1]; y++)
+                               for(z = em->min[2]; z < em->max[2]; z++)                                                                                                        
+                               {
+                                       int index = smoke_get_index(x-em->min[0], em->res[0], y-em->min[1], em->res[1], z-em->min[2]);
+                                       float max_den = em->influence[index];
+
+                                       /* density bounds */
+                                       if (max_den >= sds->adapt_threshold) {
+                                               if (min[0] > x) min[0] = x;
+                                               if (min[1] > y) min[1] = y;
+                                               if (min[2] > z) min[2] = z;
+                                               if (max[0] < x) max[0] = x;
+                                               if (max[1] < y) max[1] = y;
+                                               if (max[2] < z) max[2] = z;
+                                       }
+                                       /* velocity bounds */
+                                       if (em->velocity) {
+                                               if (min_vel[0] > em->velocity[index*3]) min_vel[0] = em->velocity[index*3];
+                                               if (min_vel[1] > em->velocity[index*3+1]) min_vel[1] = em->velocity[index*3+1];
+                                               if (min_vel[2] > em->velocity[index*3+2]) min_vel[2] = em->velocity[index*3+2];
+                                               if (max_vel[0] < em->velocity[index*3]) max_vel[0] = em->velocity[index*3];
+                                               if (max_vel[1] < em->velocity[index*3+1]) max_vel[1] = em->velocity[index*3+1];
+                                               if (max_vel[2] < em->velocity[index*3+2]) max_vel[2] = em->velocity[index*3+2];
+                                       }
+                               }
+       }
 
-                       /*
-                       // DG TODO: support static cobstacles, but basicly we could even support static + rigid with one set of code
-                       if(scs->type > SM_COLL_STATIC)
-                       */
+       /* calculate new bounds based on these values */
+       clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin+1, dt);
 
-                       /* Handle collisions */
-                       for(i = 0; i < scs->numpoints; i++)
-                       {
-                               // 1. get corresponding cell
-                               int cell[3];
-                               float pos[3], oldpos[3], vel[3];
-                               float cPos[3], cOldpos[3]; /* current position in substeps */
-                               int badcell = 0;
-                               size_t index;
-                               int j;
-
-                               // translate local points into global positions
-                               copy_v3_v3(cPos, &scs->points[3 * i]);
-                               mul_m4_v3(scs->mat, cPos);
-                               copy_v3_v3(pos, cPos);
-
-                               copy_v3_v3(cOldpos, &scs->points_old[3 * i]);
-                               mul_m4_v3(scs->mat_old, cOldpos);
-                               copy_v3_v3(oldpos, cOldpos);
-
-                               /* support for rigid bodies, armatures etc */
-                               {
-                                       float tmp[3];
+       for (i=0; i<3; i++) {
+               /* calculate new resolution */
+               res[i] = max[i] - min[i];
+               total_cells *= res[i];
 
-                                       /* x_current = x_old + (x_new - x_old) * step_current / steps_total */
-                                       float mulStep = (float)(((float)substep) / ((float)totalsteps));
+               if (new_shift[i])
+                       shift_changed = 1;
 
-                                       sub_v3_v3v3(tmp, cPos, cOldpos);
-                                       mul_v3_fl(tmp, mulStep);
-                                       add_v3_v3(cOldpos, tmp);
-                               }
+               /* if no content set minimum dimensions */
+               if (res[i] <= 0) {
+                       int j;
+                       for (j=0; j<3; j++) {
+                               min[j] = 0;
+                               max[j] = 1;
+                               res[j] = 1;
+                       }
+                       res_changed = 1;
+                       total_cells = 1;
+                       break;
+               }
+               if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i])
+                       res_changed = 1;
+       }
 
-                               sub_v3_v3v3(vel, pos, oldpos);
-                               /* Scale velocity to incorperate the object movement during this step */
-                               mul_v3_fl(vel, 1.0 / (totalsteps * dt * sds->scale));
-                               // mul_v3_fl(vel, 1.0 / dt);
+       if (res_changed || shift_changed) {
+               struct FLUID_3D *fluid_old = sds->fluid;
+               struct WTURBULENCE *turb_old = sds->wt;
+               /* allocate new fluid data */
+               smoke_reallocate_fluid(sds, sds->dx, res, 0);
+               if(sds->flags & MOD_SMOKE_HIGHRES) {
+                       smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
+               }
 
-                               // DG TODO: cap velocity to maxVelMag (or maxvel)
+               /* copy values from old fluid to new */
+               if (sds->total_cells>1 && total_cells>1) {
+                       /* low res smoke */
+                       float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b;
+                       float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b;
+                       float dummy;
+                       unsigned char *dummy_p;
+                       /* high res smoke */
+                       int wt_res_old[3];
+                       float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, *o_wt_r, *o_wt_g, *o_wt_b;
+                       float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, *n_wt_r, *n_wt_g, *n_wt_b;
+
+                       smoke_export(fluid_old, &dummy, &dummy, &o_dens, &o_react, &o_flame, &o_fuel, &o_heat, &o_heatold, &o_vx, &o_vy, &o_vz, &o_r, &o_g, &o_b, &dummy_p);
+                       smoke_export(sds->fluid, &dummy, &dummy, &n_dens, &n_react, &n_flame, &n_fuel, &n_heat, &n_heatold, &n_vx, &n_vy, &n_vz, &n_r, &n_g, &n_b, &dummy_p);
+
+                       if(sds->flags & MOD_SMOKE_HIGHRES) {
+                               smoke_turbulence_export(turb_old, &o_wt_dens, &o_wt_react, &o_wt_flame, &o_wt_fuel, &o_wt_r, &o_wt_g, &o_wt_b, &o_wt_tcu, &o_wt_tcv, &o_wt_tcw);
+                               smoke_turbulence_get_res(turb_old, wt_res_old);
+                               smoke_turbulence_export(sds->wt, &n_wt_dens, &n_wt_react, &n_wt_flame, &n_wt_fuel, &n_wt_r, &n_wt_g, &n_wt_b, &n_wt_tcu, &n_wt_tcv, &n_wt_tcw);
+                       }
 
-                               // oldpos + velocity * dt = newpos
-                               get_cell(sds->p0, sds->res, sds->dx*sds->scale, cOldpos /* use current position here instead of "pos" */, cell, 0);
 
-                               // check if cell is valid (in the domain boundary)
-                               for(j = 0; j < 3; j++)
-                                       if((cell[j] > sds->res[j] - 1) || (cell[j] < 0))
+                       for(x = sds->res_min[0]; x < sds->res_max[0]; x++)
+                               for(y = sds->res_min[1]; y < sds->res_max[1]; y++)
+                                       for(z = sds->res_min[2]; z < sds->res_max[2]; z++)
                                        {
-                                               badcell = 1;
-                                               break;
+                                               /* old grid index */
+                                               int xo = x-sds->res_min[0];
+                                               int yo = y-sds->res_min[1];
+                                               int zo = z-sds->res_min[2];
+                                               int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
+                                               /* new grid index */
+                                               int xn = x-min[0]-new_shift[0];
+                                               int yn = y-min[1]-new_shift[1];
+                                               int zn = z-min[2]-new_shift[2];
+                                               int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
+
+                                               /* skip if outside new domain */
+                                               if (xn<0 || xn>=res[0] ||
+                                                       yn<0 || yn>=res[1] ||
+                                                       zn<0 || zn>=res[2])
+                                                       continue;
+
+                                               /* copy data */
+                                               n_dens[index_new] = o_dens[index_old];
+                                               /* heat */
+                                               if (n_heat && o_heat) {
+                                                       n_heat[index_new] = o_heat[index_old];
+                                                       n_heatold[index_new] = o_heatold[index_old];
+                                               }
+                                               /* fuel */
+                                               if (n_fuel && o_fuel) {
+                                                       n_flame[index_new] = o_flame[index_old];
+                                                       n_fuel[index_new] = o_fuel[index_old];
+                                                       n_react[index_new] = o_react[index_old];
+                                               }
+                                               /* color */
+                                               if (o_r && n_r) {
+                                                       n_r[index_new] = o_r[index_old];
+                                                       n_g[index_new] = o_g[index_old];
+                                                       n_b[index_new] = o_b[index_old];
+                                               }
+                                               n_vx[index_new] = o_vx[index_old];
+                                               n_vy[index_new] = o_vy[index_old];
+                                               n_vz[index_new] = o_vz[index_old];
+
+                                               if(sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
+                                                       int block_size = sds->amplify + 1;
+                                                       int i,j,k;
+                                                       /* old grid index */
+                                                       int xx_o = xo*block_size;
+                                                       int yy_o = yo*block_size;
+                                                       int zz_o = zo*block_size;
+                                                       /* new grid index */
+                                                       int xx_n = xn*block_size;
+                                                       int yy_n = yn*block_size;
+                                                       int zz_n = zn*block_size;
+
+                                                       n_wt_tcu[index_new] = o_wt_tcu[index_old];
+                                                       n_wt_tcv[index_new] = o_wt_tcv[index_old];
+                                                       n_wt_tcw[index_new] = o_wt_tcw[index_old];
+
+                                                       for(i = 0; i < block_size; i++)
+                                                               for(j = 0; j < block_size; j++)
+                                                                       for(k = 0; k < block_size; k++)                                                                                                 
+                                                                       {
+                                                                               int big_index_old = smoke_get_index(xx_o+i, wt_res_old[0], yy_o+j, wt_res_old[1], zz_o+k);
+                                                                               int big_index_new = smoke_get_index(xx_n+i, sds->res_wt[0], yy_n+j, sds->res_wt[1], zz_n+k);
+                                                                               /* copy data */
+                                                                               n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
+                                                                               if (n_wt_flame && o_wt_flame) {
+                                                                                       n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
+                                                                                       n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
+                                                                                       n_wt_react[big_index_new] = o_wt_react[big_index_old];
+                                                                               }
+                                                                               if (n_wt_r && o_wt_r) {
+                                                                                       n_wt_r[big_index_new] = o_wt_r[big_index_old];
+                                                                                       n_wt_g[big_index_new] = o_wt_g[big_index_old];
+                                                                                       n_wt_b[big_index_new] = o_wt_b[big_index_old];
+                                                                               }
+                                                                       }
+                                               }
                                        }
-                                                                                                               
-                               if(badcell)
-                                       continue;
+               }
+               smoke_free(fluid_old);
+               if (turb_old)
+                       smoke_turbulence_free(turb_old);
+
+               /* set new domain dimensions */
+               VECCOPY(sds->res_min, min);
+               VECCOPY(sds->res_max, max);
+               VECCOPY(sds->res, res);
+               sds->total_cells = total_cells;
+       }
+}
 
-                               // 2. set cell values (heat, density and velocity)
-                               index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
+BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+{
+       density[index] = 0.f;
+       if (heat) {
+               heat[index] = 0.f;
+       }
+       if (fuel) {
+               fuel[index] = 0.f;
+               react[index] = 0.f;
+       }
+       if (color_r) {
+               color_r[index] = 0.f;
+               color_g[index] = 0.f;
+               color_b[index] = 0.f;
+       }
+}
 
-                               // Don't overwrite existing obstacles
-                               if(obstacles[index])
-                                       continue;
-                                                                                               
-                               // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]);                                                                
-                               // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index);                                                                                                                                   
-                               obstacles[index] = 1 | 8 /* ANIMATED */;
+BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+{
+       int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
+       float dens_old = density[index];
+       float fuel_old = (fuel) ? fuel[index] : 0.0f;
+       float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
+       float fuel_flow = emission_value * sfs->fuel_amount;
+       /* add heat */
+       if (heat) {
+               heat[index] = MAX2(emission_value*sfs->temp, heat[index]);
+       }
+       /* absolute */
+       if (absolute_flow) {
+               if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+                       if (dens_flow > density[index])
+                               density[index] = dens_flow;
+               }
+               if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
+                       if (fuel_flow > fuel[index])
+                               fuel[index] = fuel_flow;
+               }
+       }
+       /* additive */
+       else {
+               if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+                       density[index] += dens_flow;
+                       CLAMP(density[index], 0.0f, 1.0f);
+               }
+               if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
+                       fuel[index] += fuel_flow;
+                       CLAMP(fuel[index], 0.0f, 10.0f);
+               }
+       }
 
-                               if(len_v3(vel) > FLT_EPSILON)
-                               {
-                                       // Collision object is moving
+       /* set color */
+       if (color_r && dens_flow) {
+               float total_dens = density[index]/(dens_old+dens_flow);
+               color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
+               color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
+               color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
+       }
 
-                                       velx[index] = vel[0]; // use "+="?
-                                       vely[index] = vel[1];
-                                       velz[index] = vel[2];
-                               }
-                       }
+       /* set fire reaction coordinate */
+       if (fuel && fuel[index]) {
+               /* instead of using 1.0 for all new fuel add slight falloff
+                * to reduce flow blockiness */
+               float value = 1.0f - pow(1.0f - emission_value, 2.0f);
+
+               if (value > react[index]) {
+                       float f = fuel_flow / fuel[index];
+                       react[index] = value*f + (1.0f - f)*react[index];
                }
        }
-
-       if(collobjs)
-               MEM_freeN(collobjs);
 }
 
-static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float time)
+static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float time, float dt)
 {
        Object **flowobjs = NULL;
+       EmissionMap *emaps = NULL;
        unsigned int numflowobj = 0;
        unsigned int flowIndex;
+       int new_shift[3] = {0};
+       int active_fields = sds->active_fields;
+
+       /* calculate domain shift for current frame if using adaptive domain */
+       if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+               int total_shift[3];
+               float frame_shift_f[3];
+               float ob_loc[3] = {0};
+
+               mul_m4_v3(ob->obmat, ob_loc);
+
+               VECSUB(frame_shift_f, ob_loc, sds->prev_loc);
+               copy_v3_v3(sds->prev_loc, ob_loc);
+               /* convert global space shift to local "cell" space */
+               mul_mat3_m4_v3(sds->imat, frame_shift_f);
+               frame_shift_f[0] = frame_shift_f[0]/sds->cell_size[0];
+               frame_shift_f[1] = frame_shift_f[1]/sds->cell_size[1];
+               frame_shift_f[2] = frame_shift_f[2]/sds->cell_size[2];
+               /* add to total shift */
+               VECADD(sds->shift_f, sds->shift_f, frame_shift_f);
+               /* convert to integer */
+               total_shift[0] = floor(sds->shift_f[0]);
+               total_shift[1] = floor(sds->shift_f[1]);
+               total_shift[2] = floor(sds->shift_f[2]);
+               VECSUB(new_shift, total_shift, sds->shift);
+               copy_v3_v3_int(sds->shift, total_shift);
+
+               /* calculate new domain boundary points so that smoke doesnt slide on sub-cell movement */
+               sds->p0[0] = sds->dp0[0] - sds->cell_size[0]*(sds->shift_f[0]-total_shift[0] - 0.5f);
+               sds->p0[1] = sds->dp0[1] - sds->cell_size[1]*(sds->shift_f[1]-total_shift[1] - 0.5f);
+               sds->p0[2] = sds->dp0[2] - sds->cell_size[2]*(sds->shift_f[2]-total_shift[2] - 0.5f);
+               sds->p1[0] = sds->p0[0] + sds->cell_size[0]*sds->base_res[0];
+               sds->p1[1] = sds->p0[1] + sds->cell_size[1]*sds->base_res[1];
+               sds->p1[2] = sds->p0[2] + sds->cell_size[2]*sds->base_res[2];
+       }
 
        flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
 
-       // update obstacle tags in cells
+       /* init emission maps for each flow */
+       emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
+
+       /* Prepare flow emission maps */
        for(flowIndex = 0; flowIndex < numflowobj; flowIndex++)
        {
                Object *collob= flowobjs[flowIndex];
@@ -1238,289 +1649,249 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
                {
                        // we got nice flow object
                        SmokeFlowSettings *sfs = smd2->flow;
+                       EmissionMap *em = &emaps[flowIndex];
 
-                       if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
-                       {
-                               ParticleSimulationData sim;
-                               ParticleSystem *psys = sfs->psys;
-                               int totpart=psys->totpart, totchild;
-                               int p = 0;                                                              
-                               float *density = smoke_get_density(sds->fluid);                                                         
-                               float *bigdensity = smoke_turbulence_get_density(sds->wt);                                                              
-                               float *heat = smoke_get_heat(sds->fluid);                                                               
-                               float *velocity_x = smoke_get_velocity_x(sds->fluid);                                                           
-                               float *velocity_y = smoke_get_velocity_y(sds->fluid);                                                           
-                               float *velocity_z = smoke_get_velocity_z(sds->fluid);                                                           
-                               unsigned char *obstacle = smoke_get_obstacle(sds->fluid);                                                       
-                               // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
-                               int bigres[3];
-                               short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
-                               short high_emission_smoothing = bigdensity ? (sds->flags & MOD_SMOKE_HIGH_SMOOTH) : 0;
-
-                               /*
-                               * A temporary volume map used to store whole emissive
-                               * area to be added to smoke density and interpolated
-                               * for high resolution smoke.
-                               */
-                               float *temp_emission_map = NULL;
-
-                               sim.scene = scene;
-                               sim.ob = collob;
-                               sim.psys = psys;
-
-                               // initialize temp emission map
-                               if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW))
-                               {
-                                       int i;
-                                       temp_emission_map = MEM_callocN(sizeof(float) * sds->res[0]*sds->res[1]*sds->res[2], "SmokeTempEmission");
-                                       // set whole volume to 0.0f
-                                       for (i=0; i<sds->res[0]*sds->res[1]*sds->res[2]; i++) {
-                                               temp_emission_map[i] = 0.0f;
-                                       }
-                               }
-
-                               // mostly copied from particle code                                                             
-                               if(psys->part->type==PART_HAIR)
-                               {
-                                       /*
-                                       if(psys->childcache)
-                                       {
-                                       totchild = psys->totchildcache;
-                                       }
-                                       else
-                                       */
+                       if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
+                               emit_from_particles(collob, sds, sfs, em, scene, time, dt);
+                       }
+                       else {
+                               emit_from_derivedmesh(collob, sds, sfs, em, dt);
+                       }
 
-                                       // TODO: PART_HAIR not supported whatsoever
-                                       totchild=0;
+                       /* update required data fields */
+                       if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
+                               /* activate heat field if flow produces any heat */
+                               if (sfs->temp) {
+                                       active_fields |= SM_ACTIVE_HEAT;
                                }
-                               else
-                                       totchild=psys->totchild*psys->part->disp/100;
-
-                               for(p=0; p<totpart+totchild; p++)                                                               
-                               {
-                                       int cell[3];
-                                       size_t i = 0;
-                                       size_t index = 0;
-                                       int badcell = 0;
-                                       ParticleKey state;
-
-                                       if(p < totpart)
-                                       {
-                                               if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
-                                                       continue;
-                                       }
-                                       else {
-                                               /* handle child particle */
-                                               ChildParticle *cpa = &psys->child[p - totpart];
-
-                                               if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
-                                                       continue;
+                               /* activate fuel field if flow adds any fuel */
+                               if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
+                                       active_fields |= SM_ACTIVE_FIRE;
+                               }
+                               /* activate color field if flows add smoke with varying colors */
+                               if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
+                                       if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+                                               copy_v3_v3(sds->active_color, sfs->color);
+                                               active_fields |= SM_ACTIVE_COLOR_SET;
                                        }
-
-                                       state.time = time;
-                                       if(psys_get_particle_state(&sim, p, &state, 0) == 0)
-                                               continue;
-
-                                       // copy_v3_v3(pos, pa->state.co);
-                                       // mul_m4_v3(ob->imat, pos);
-                                       // 1. get corresponding cell
-                                       get_cell(sds->p0, sds->res, sds->dx*sds->scale, state.co, cell, 0);                                                                                                                                     
-                                       // check if cell is valid (in the domain boundary)                                                                      
-                                       for(i = 0; i < 3; i++)                                                                  
-                                       {                                                                               
-                                               if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))                                                                                
-                                               {                                                                                       
-                                                       badcell = 1;                                                                                    
-                                                       break;                                                                          
-                                               }                                                                       
-                                       }                                                                                                                                                       
-                                       if(badcell)                                                                             
-                                               continue;                                                                                                                                               
-                                       // 2. set cell values (heat, density and velocity)                                                                      
-                                       index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);                                                                                                                                           
-                                       if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index])) // this is inflow
-                                       {                                                                               
-                                               // heat[index] += sfs->temp * 0.1;                                                                              
-                                               // density[index] += sfs->density * 0.1;
-                                               heat[index] = sfs->temp;
-
-                                               // Add emitter density to temp emission map
-                                               temp_emission_map[index] = sfs->density;
-
-                                               // Uses particle velocity as initial velocity for smoke
-                                               if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
-                                               {
-                                                       velocity_x[index] = state.vel[0]*sfs->vel_multi;
-                                                       velocity_y[index] = state.vel[1]*sfs->vel_multi;
-                                                       velocity_z[index] = state.vel[2]*sfs->vel_multi;
-                                               }                                                                               
-                                       }                                                                       
-                                       else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow                                                                     
-                                       {                                                                               
-                                               heat[index] = 0.f;                                                                              
-                                               density[index] = 0.f;                                                                           
-                                               velocity_x[index] = 0.f;                                                                                
-                                               velocity_y[index] = 0.f;                                                                                
-                                               velocity_z[index] = 0.f;
-                                               // we need different handling for the high-res feature
-                                               if(bigdensity)
-                                               {
-                                                       // init all surrounding cells according to amplification, too                                                                                   
-                                                       int i, j, k;
-                                                       smoke_turbulence_get_res(sds->wt, bigres);
-
-                                                       for(i = 0; i < sds->amplify + 1; i++)
-                                                               for(j = 0; j < sds->amplify + 1; j++)
-                                                                       for(k = 0; k < sds->amplify + 1; k++)
-                                                                       {                                                                                                               
-                                                                               index = smoke_get_index((sds->amplify + 1)* cell[0] + i, bigres[0], (sds->amplify + 1)* cell[1] + j, bigres[1], (sds->amplify + 1)* cell[2] + k);                                                                                                               
-                                                                               bigdensity[index] = 0.f;                                                                                                        
-                                                                       }                                                                               
-                                               }
+                                       else if (!equals_v3v3(sds->active_color, sfs->color)) {
+                                               active_fields |= SM_ACTIVE_COLORS;
                                        }
-                               }       // particles loop
+                               }
+                       }
+               }
+       }
 
-                               // apply emission values
-                               if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) 
-                               {
-                                       // initialize variables
-                                       int ii, jj, kk, x, y, z, block_size;
-                                       size_t index, index_big;
+       /* monitor active fields based on domain settings */
+       /* if domain has fire, activate new fields if required */
+       if (active_fields & SM_ACTIVE_FIRE) {
+               /* heat is always needed for fire */
+               active_fields |= SM_ACTIVE_HEAT;
+               /* also activate colors if domain smoke color differs from active color */
+               if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+                       copy_v3_v3(sds->active_color, sds->flame_smoke_color);
+                       active_fields |= SM_ACTIVE_COLOR_SET;
+               }
+               else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
+                       active_fields |= SM_ACTIVE_COLORS;
+               }
+       }
 
-                                       smoke_turbulence_get_res(sds->wt, bigres);
-                                       block_size = sds->amplify + 1;  // high res block size
+       /* Adjust domain size if needed */
+       if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+               adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
+       }
 
-                                       // loop through every low res cell
-                                       for(x = 0; x < sds->res[0]; x++)
-                                               for(y = 0; y < sds->res[1]; y++)
-                                                       for(z = 0; z < sds->res[2]; z++)                                                                                                        
-                                                       {
-                                                               // neighbor cell emission densities (for high resolution smoke smooth interpolation)
-                                                               float c000, c001, c010, c011,  c100, c101, c110, c111;
+       /* Initialize new data fields if any */
+       if (active_fields & SM_ACTIVE_HEAT) {
+               smoke_ensure_heat(sds->fluid);
+       }
+       if (active_fields & SM_ACTIVE_FIRE) {
+               smoke_ensure_fire(sds->fluid, sds->wt);
+       }
+       if (active_fields & SM_ACTIVE_COLORS) {
+               /* initialize all smoke with "active_color" */
+               smoke_ensure_colors(sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
+       }
+       sds->active_fields = active_fields;
 
-                                                               c000 = (x>0 && y>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z-1)] : 0;
-                                                               c001 = (x>0 && y>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z)] : 0;
-                                                               c010 = (x>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z-1)] : 0;
-                                                               c011 = (x>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z)] : 0;
+       /* Apply emission data */
+       if (sds->fluid) {
+               for(flowIndex = 0; flowIndex < numflowobj; flowIndex++)
+               {
+                       Object *collob= flowobjs[flowIndex];
+                       SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
 
-                                                               c100 = (y>0 && z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z-1)] : 0;
-                                                               c101 = (y>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z)] : 0;
-                                                               c110 = (z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z-1)] : 0;
-                                                               c111 = temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z)]; // this cell
+                       // check for initialized smoke object
+                       if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)                                            
+                       {
+                               // we got nice flow object
+                               SmokeFlowSettings *sfs = smd2->flow;
+                               EmissionMap *em = &emaps[flowIndex];
+                                                               
+                               float *density = smoke_get_density(sds->fluid);
+                               float *color_r = smoke_get_color_r(sds->fluid);
+                               float *color_g = smoke_get_color_g(sds->fluid);
+                               float *color_b = smoke_get_color_b(sds->fluid);
+                               float *fuel = smoke_get_fuel(sds->fluid);
+                               float *react = smoke_get_react(sds->fluid);
+                               float *bigdensity = smoke_turbulence_get_density(sds->wt);
+                               float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
+                               float *bigreact = smoke_turbulence_get_react(sds->wt);
+                               float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
+                               float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
+                               float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
+                               float *heat = smoke_get_heat(sds->fluid);
+                               float *velocity_x = smoke_get_velocity_x(sds->fluid);
+                               float *velocity_y = smoke_get_velocity_y(sds->fluid);
+                               float *velocity_z = smoke_get_velocity_z(sds->fluid);
+                               //unsigned char *obstacle = smoke_get_obstacle(sds->fluid);                                                     
+                               // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
+                               int bigres[3];
+                               short high_emission_smoothing = (sds->flags & MOD_SMOKE_HIGH_SMOOTH);
+                               float *velocity_map = em->velocity;
+                               float *emission_map = em->influence;
 
-                                                               // get cell index
-                                                               index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+                               int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
+                               size_t e_index, d_index, index_big;
 
-                                                               // add emission to low resolution density
-                                                               if (absolute_flow) 
-                                                               {
-                                                                       if (temp_emission_map[index]>0) 
-                                                                               density[index] = temp_emission_map[index];
+                               // loop through every emission map cell
+                               for(gx = em->min[0]; gx < em->max[0]; gx++)
+                                       for(gy = em->min[1]; gy < em->max[1]; gy++)
+                                               for(gz = em->min[2]; gz < em->max[2]; gz++)                                                                                                     
+                                               {
+                                                       /* get emission map index */
+                                                       ex = gx-em->min[0];
+                                                       ey = gy-em->min[1];
+                                                       ez = gz-em->min[2];
+                                                       e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
+                                                       if (!emission_map[e_index]) continue;
+                                                       /* get domain index */
+                                                       dx = gx-sds->res_min[0];
+                                                       dy = gy-sds->res_min[1];
+                                                       dz = gz-sds->res_min[2];
+                                                       d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
+
+                                                       if(sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+                                                               apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b);
+                                                       }
+                                                       else { // inflow
+                                                               apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b);
+
+                                                               /* initial velocity */
+                                                               if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+                                                                       velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], velocity_map[e_index*3]);
+                                                                       velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], velocity_map[e_index*3+1]);
+                                                                       velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], velocity_map[e_index*3+2]);
                                                                }
-                                                               else 
-                                                               {
-                                                                       density[index] += temp_emission_map[index];
+                                                       }
 
-                                                                       if (density[index]>1) 
-                                                                               density[index]=1.0f;
-                                                               }
+                                                       /* loop through high res blocks if high res enabled */
+                                                       if (bigdensity) {
+                                                               // neighbor cell emission densities (for high resolution smoke smooth interpolation)
+                                                               float c000, c001, c010, c011,  c100, c101, c110, c111;
 
                                                                smoke_turbulence_get_res(sds->wt, bigres);
+                                                               block_size = sds->amplify + 1;  // high res block size
 
-                                                               /* loop through high res blocks if high res enabled */
-                                                               if (bigdensity)
-                                                                       for(ii = 0; ii < block_size; ii++)
-                                                                               for(jj = 0; jj < block_size; jj++)
-                                                                                       for(kk = 0; kk < block_size; kk++)                                                                                                      
-                                                                                       {
-
-                         &