diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h index 9d5dfd98823..a0eb1bf38e0 100644 --- a/intern/smoke/extern/smoke_API.h +++ b/intern/smoke/extern/smoke_API.h @@ -41,11 +41,11 @@ struct FLUID_3D; 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); +struct FLUID_3D *smoke_init(int *res, float *p0, float dtdef); 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, size_t framenr, float fps); +void smoke_step(struct FLUID_3D *fluid, float dtSubdiv); float *smoke_get_density(struct FLUID_3D *fluid); float *smoke_get_heat(struct FLUID_3D *fluid); @@ -53,6 +53,9 @@ float *smoke_get_velocity_x(struct FLUID_3D *fluid); float *smoke_get_velocity_y(struct FLUID_3D *fluid); float *smoke_get_velocity_z(struct FLUID_3D *fluid); +/* Moving obstacle velocity provided by blender */ +void smoke_get_ob_velocity(struct FLUID_3D *fluid, float **x, float **y, float **z); + float *smoke_get_force_x(struct FLUID_3D *fluid); float *smoke_get_force_y(struct FLUID_3D *fluid); float *smoke_get_force_z(struct FLUID_3D *fluid); diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp index 9f036cc6d2f..04971f898e9 100644 --- a/intern/smoke/intern/FLUID_3D.cpp +++ b/intern/smoke/intern/FLUID_3D.cpp @@ -34,6 +34,8 @@ #include "SPHERE.h" #include +#include "float.h" + #if PARALLEL==1 #include #endif // PARALLEL @@ -42,11 +44,11 @@ // Construction/Destruction ////////////////////////////////////////////////////////////////////// -FLUID_3D::FLUID_3D(int *res, float *p0) : +FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) : _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f) { // set simulation consts - _dt = DT_DEFAULT; // just in case. set in step from a RNA factor + _dt = dtdef; // just in case. set in step from a RNA factor // start point of array _p0[0] = p0[0]; @@ -81,6 +83,9 @@ FLUID_3D::FLUID_3D(int *res, float *p0) : _xVelocity = new float[_totalCells]; _yVelocity = new float[_totalCells]; _zVelocity = new float[_totalCells]; + _xVelocityOb = new float[_totalCells]; + _yVelocityOb = new float[_totalCells]; + _zVelocityOb = new float[_totalCells]; _xVelocityOld = new float[_totalCells]; _yVelocityOld = new float[_totalCells]; _zVelocityOld = new float[_totalCells]; @@ -111,6 +116,9 @@ FLUID_3D::FLUID_3D(int *res, float *p0) : _xVelocity[x] = 0.0f; _yVelocity[x] = 0.0f; _zVelocity[x] = 0.0f; + _xVelocityOb[x] = 0.0f; + _yVelocityOb[x] = 0.0f; + _zVelocityOb[x] = 0.0f; _xVelocityOld[x] = 0.0f; _yVelocityOld[x] = 0.0f; _zVelocityOld[x] = 0.0f; @@ -131,9 +139,15 @@ FLUID_3D::FLUID_3D(int *res, float *p0) : _colloPrev = 1; // default value + setBorderObstacles(); // walls +} + +void FLUID_3D::setBorderObstacles() +{ + // set side obstacles - int index; + unsigned int index; for (int y = 0; y < _yRes; y++) for (int x = 0; x < _xRes; x++) { @@ -169,7 +183,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0) : index += _xRes - 1; if(_domainBcRight==1) _obstacles[index] = 1; } - } FLUID_3D::~FLUID_3D() @@ -177,6 +190,9 @@ FLUID_3D::~FLUID_3D() if (_xVelocity) delete[] _xVelocity; if (_yVelocity) delete[] _yVelocity; if (_zVelocity) delete[] _zVelocity; + if (_xVelocityOb) delete[] _xVelocityOb; + if (_yVelocityOb) delete[] _yVelocityOb; + if (_zVelocityOb) delete[] _zVelocityOb; if (_xVelocityOld) delete[] _xVelocityOld; if (_yVelocityOld) delete[] _yVelocityOld; if (_zVelocityOld) delete[] _zVelocityOld; @@ -214,10 +230,18 @@ void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float ////////////////////////////////////////////////////////////////////// void FLUID_3D::step(float dt) { +#if 0 // If border rules have been changed if (_colloPrev != *_borderColli) { + printf("Border collisions changed\n"); + + // DG TODO: Need to check that no animated obstacle flags are overwritten setBorderCollisions(); } +#endif + + // DG: TODO for the moment redo border for every timestep since it's been deleted every time by moving obstacles + setBorderCollisions(); // set delta time by dt_factor @@ -786,6 +810,7 @@ void FLUID_3D::project() memset(_pressure, 0, sizeof(float)*_totalCells); memset(_divergence, 0, sizeof(float)*_totalCells); + // set velocity and pressure inside of obstacles to zero setObstacleBoundaries(_pressure, 0, _zRes); // copy out the boundaries @@ -798,12 +823,49 @@ void FLUID_3D::project() if(_domainBcTop == 0) 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) for (y = 1; y < _yRes - 1; y++, index += 2) for (x = 1; x < _xRes - 1; x++, index++) { + + if(_obstacles[index]) + { + _divergence[index] = 0.0f; + continue; + } + + float xright = _xVelocity[index + 1]; float xleft = _xVelocity[index - 1]; float yup = _yVelocity[index + _xRes]; @@ -811,26 +873,82 @@ void FLUID_3D::project() float ztop = _zVelocity[index + _slabSize]; float zbottom = _zVelocity[index - _slabSize]; - if(_obstacles[index+1]) xright = - _xVelocity[index]; + if(_obstacles[index+1]) xright = - _xVelocity[index]; // DG: += if(_obstacles[index-1]) xleft = - _xVelocity[index]; if(_obstacles[index+_xRes]) yup = - _yVelocity[index]; if(_obstacles[index-_xRes]) ydown = - _yVelocity[index]; if(_obstacles[index+_slabSize]) ztop = - _zVelocity[index]; if(_obstacles[index-_slabSize]) zbottom = - _zVelocity[index]; + if(_obstacles[index+1] & 8) xright += _xVelocityOb[index + 1]; + if(_obstacles[index-1] & 8) xleft += _xVelocityOb[index - 1]; + if(_obstacles[index+_xRes] & 8) yup += _yVelocityOb[index + _xRes]; + if(_obstacles[index-_xRes] & 8) ydown += _yVelocityOb[index - _xRes]; + if(_obstacles[index+_slabSize] & 8) ztop += _zVelocityOb[index + _slabSize]; + if(_obstacles[index-_slabSize] & 8) zbottom += _zVelocityOb[index - _slabSize]; + _divergence[index] = -_dx * 0.5f * ( xright - xleft + yup - ydown + ztop - zbottom ); - // DG: commenting this helps CG to get a better start, 10-20% speed improvement - // _pressure[index] = 0.0f; + // Pressure is zero anyway since now a local array is used + _pressure[index] = 0.0f; } + + + /* + { + float maxvalue = 0; + for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++) + { + if(_divergence[i] > maxvalue) + maxvalue = _divergence[i]; + + } + printf("Max divergence: %f\n", maxvalue); + } + */ + copyBorderAll(_pressure, 0, _zRes); + /* + { + float maxvalue = 0; + for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++) + { + if(_pressure[i] > maxvalue) + maxvalue = _pressure[i]; + } + printf("Max pressure BEFORE: %f\n", maxvalue); + } + */ + // solve Poisson equation solvePressurePre(_pressure, _divergence, _obstacles); + { + float maxvalue = 0; + for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++) + { + if(_pressure[i] > maxvalue) + maxvalue = _pressure[i]; + + /* HACK: Animated collision object sometimes result in a non converging solvePressurePre() */ + if(_pressure[i] > _dx * _dt) + _pressure[i] = _dx * _dt; + else if(_pressure[i] < -_dx * _dt) + _pressure[i] = -_dx * _dt; + + // if(_obstacle[i] && _pressure[i] != 0.0) + // printf("BAD PRESSURE i\n"); + + // if(_pressure[i]>1) + // printf("index: %d\n", i); + } + // printf("Max pressure: %f, dx: %f\n", maxvalue, _dx); + } + setObstaclePressure(_pressure, 0, _zRes); // project out solution @@ -848,12 +966,74 @@ void FLUID_3D::project() } } + setObstacleVelocity(0, _zRes); + if (_pressure) delete[] _pressure; if (_divergence) delete[] _divergence; } +////////////////////////////////////////////////////////////////////// +// calculate the obstacle velocity at boundary +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setObstacleVelocity(int zBegin, int zEnd) +{ + + // completely TODO <-- who wrote this and what is here TODO? DG + const size_t index_ = _slabSize + _xRes + 1; + //int vIndex=_slabSize + _xRes + 1; + + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == _zRes) {bt = 1;} + + // tag remaining obstacle blocks + for (int z = zBegin + bb; z < zEnd - bt; z++) + { + size_t index = index_ +(z-1)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + if (!_obstacles[index]) + { + // if(_obstacles[index+1]) xright = - _xVelocityOb[index]; + if((_obstacles[index - 1] & 8) && abs(_xVelocityOb[index - 1]) > FLT_EPSILON ) + { + // printf("velocity x!\n"); + _xVelocity[index] = _xVelocityOb[index - 1]; + _xVelocity[index - 1] = _xVelocityOb[index - 1]; + } + // if(_obstacles[index+_xRes]) yup = - _yVelocityOb[index]; + if((_obstacles[index - _xRes] & 8) && abs(_yVelocityOb[index - _xRes]) > FLT_EPSILON) + { + // printf("velocity y!\n"); + _yVelocity[index] = _yVelocityOb[index - _xRes]; + _yVelocity[index - _xRes] = _yVelocityOb[index - _xRes]; + } + // if(_obstacles[index+_slabSize]) ztop = - _zVelocityOb[index]; + if((_obstacles[index - _slabSize] & 8) && abs(_zVelocityOb[index - _slabSize]) > FLT_EPSILON) + { + // printf("velocity z!\n"); + _zVelocity[index] = _zVelocityOb[index - _slabSize]; + _zVelocity[index - _slabSize] = _zVelocityOb[index - _slabSize]; + } + } + else + { + _density[index] = 0; + } + //vIndex++; + } // x loop + //vIndex += 2; + } // y loop + //vIndex += 2 * _xRes; + } // z loop +} ////////////////////////////////////////////////////////////////////// // diffuse heat @@ -892,7 +1072,7 @@ void FLUID_3D::addObstacle(OBSTACLE* obstacle) void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd) { - // compleately TODO + // completely TODO <-- who wrote this and what is here TODO? DG const size_t index_ = _slabSize + _xRes + 1; @@ -914,7 +1094,7 @@ void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd) for (int x = 1; x < _xRes - 1; x++, index++) { // could do cascade of ifs, but they are a pain - if (_obstacles[index]) + if (_obstacles[index] /* && !(_obstacles[index] & 8) DG TODO TEST THIS CONDITION */) { const int top = _obstacles[index + _slabSize]; const int bottom= _obstacles[index - _slabSize]; @@ -928,9 +1108,11 @@ void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd) // const bool fully = (up && down); //const bool fullx = (left && right); + /* _xVelocity[index] = _yVelocity[index] = _zVelocity[index] = 0.0f; + */ _pressure[index] = 0.0f; // average pressure neighbors @@ -1253,7 +1435,35 @@ void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd) 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 (zBegin == 0) {bb = 1;} + if (zEnd == _zRes) {bt = 1;} + + for (int z = zBegin + bb; z < zEnd - bt; z++) + { + size_t index = index_ +(z-1)*_slabSize; + + 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; + } + } + } + } + } +#endif /*int begin=zBegin * _slabSize; int end=begin + (zEnd - zBegin) * _slabSize; diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h index c9e18926fb2..5704cba3ed4 100644 --- a/intern/smoke/intern/FLUID_3D.h +++ b/intern/smoke/intern/FLUID_3D.h @@ -39,9 +39,6 @@ // #include "WTURBULENCE.h" #include "VEC3.h" -// timestep default value for nice appearance -#define DT_DEFAULT 0.1f; - using namespace std; using namespace BasicVector; class WTURBULENCE; @@ -49,7 +46,7 @@ class WTURBULENCE; class FLUID_3D { public: - FLUID_3D(int *res, /* int amplify, */ float *p0); + FLUID_3D(int *res, /* int amplify, */ float *p0, float dtdef); FLUID_3D() {}; virtual ~FLUID_3D(); @@ -72,7 +69,7 @@ class FLUID_3D int yRes() const { return _yRes; }; int zRes() const { return _zRes; }; - public: + public: // dimensions int _xRes, _yRes, _zRes, _maxRes; Vec3Int _res; @@ -89,6 +86,8 @@ class FLUID_3D void artificialDampingSL(int zBegin, int zEnd); void artificialDampingExactSL(int pos); + void setBorderObstacles(); + // fields float* _density; float* _densityOld; @@ -97,13 +96,17 @@ class FLUID_3D float* _xVelocity; float* _yVelocity; float* _zVelocity; + float* _xVelocityOb; + float* _yVelocityOb; + float* _zVelocityOb; float* _xVelocityOld; float* _yVelocityOld; float* _zVelocityOld; float* _xForce; float* _yForce; float* _zForce; - unsigned char* _obstacles; + unsigned char* _obstacles; /* only used (usefull) for static obstacles like domain boundaries */ + unsigned char* _obstaclesAnim; // Required for proper threading: float* _xVelocityTemp; @@ -137,6 +140,8 @@ class FLUID_3D // have to recalibrate borders if nothing has changed void setBorderCollisions(); + void setObstacleVelocity(int zBegin, int zEnd); + // WTURBULENCE object, if active // WTURBULENCE* _wTurbulence; diff --git a/intern/smoke/intern/OBSTACLE.h b/intern/smoke/intern/OBSTACLE.h index 61d47b727f0..da8ec6be024 100644 --- a/intern/smoke/intern/OBSTACLE.h +++ b/intern/smoke/intern/OBSTACLE.h @@ -27,9 +27,11 @@ #define OBSTACLE_H enum OBSTACLE_FLAGS { - EMPTY = 0, + EMPTY = 0, + /* 1 is used to flag an object cell */ MARCHED = 2, - RETIRED = 4 + RETIRED = 4, + ANIMATED = 8, }; class OBSTACLE diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp index cd18cf7b344..83bec466c9f 100644 --- a/intern/smoke/intern/WTURBULENCE.cpp +++ b/intern/smoke/intern/WTURBULENCE.cpp @@ -431,8 +431,11 @@ void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy) // compute velocity from energies and march into obstacles // for wavelet decomposition ////////////////////////////////////////////////////////////////////// -void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) +void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *origObstacles) { + unsigned char *obstacles = new unsigned char[_totalCellsSm]; + memcpy(obstacles, origObstacles, sizeof(unsigned char) * _totalCellsSm); + // compute everywhere for (int x = 0; x < _totalCellsSm; x++) _energy[x] = 0.5f * (xvel[x] * xvel[x] + yvel[x] * yvel[x] + zvel[x] * zvel[x]); @@ -506,7 +509,9 @@ void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* for (int y = 1; y < _yResSm - 1; y++, index += 2) for (int x = 1; x < _xResSm - 1; x++, index++) if (obstacles[index]) - obstacles[index] = 1; + obstacles[index] = 1; // DG TODO ? animated obstacle flag? + + free(obstacles); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp index a2f3c21bbbf..78f7d35360a 100644 --- a/intern/smoke/intern/smoke_API.cpp +++ b/intern/smoke/intern/smoke_API.cpp @@ -19,6 +19,7 @@ * All rights reserved. * * Contributor(s): Daniel Genrich + * Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ @@ -36,10 +37,10 @@ #include // y in smoke is z in blender -extern "C" FLUID_3D *smoke_init(int *res, float *p0) +extern "C" FLUID_3D *smoke_init(int *res, float *p0, float dtdef) { // smoke lib uses y as top-bottom/vertical axis where blender uses z - FLUID_3D *fluid = new FLUID_3D(res, p0); + FLUID_3D *fluid = new FLUID_3D(res, p0, dtdef); // printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]); @@ -78,41 +79,9 @@ 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, size_t framenr, float fps) +extern "C" void smoke_step(FLUID_3D *fluid, float dtSubdiv) { - /* stability values copied from wturbulence.cpp */ - const int maxSubSteps = 25; - const float maxVel = 0.5f; /* TODO: maybe 0.5 is still too high, please confirm! -dg */ - - float dt = DT_DEFAULT; - float maxVelMag = 0.0f; - int totalSubsteps; - int substep = 0; - float dtSubdiv; - - /* get max velocity and lower the dt value if it is too high */ - size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes; - - for(size_t i = 0; i < size; i++) - { - float vtemp = (fluid->_xVelocity[i]*fluid->_xVelocity[i]+fluid->_yVelocity[i]*fluid->_yVelocity[i]+fluid->_zVelocity[i]*fluid->_zVelocity[i]); - if(vtemp > maxVelMag) - maxVelMag = vtemp; - } - - /* adapt timestep for different framerates, dt = 0.1 is at 25fps */ - dt *= (25.0f / fps); - - maxVelMag = sqrt(maxVelMag) * dt * (*(fluid->_dtFactor)); - totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ - totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; - totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; - dtSubdiv = (float)dt / (float)totalSubsteps; - - // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt); - - for(substep = 0; substep < totalSubsteps; substep++) - fluid->step(dtSubdiv); + fluid->step(dtSubdiv); } extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid) @@ -307,6 +276,18 @@ extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid) return fluid->_obstacles; } +extern "C" void smoke_get_ob_velocity(struct FLUID_3D *fluid, float **x, float **y, float **z) +{ + *x = fluid->_xVelocityOb; + *y = fluid->_yVelocityOb; + *z = fluid->_zVelocityOb; +} + +extern "C" unsigned char *smoke_get_obstacle_anim(FLUID_3D *fluid) +{ + return fluid->_obstaclesAnim; +} + extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type) { wt->setNoise(type); diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index 9f760f2f024..d3ab616a793 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -100,6 +100,15 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): sub.prop(flow, "use_absolute") sub.prop(flow, "density") sub.prop(flow, "temperature") + + elif md.smoke_type == 'COLLISION': + coll = md.coll_settings + + split = layout.split() + + col = split.column() + col.prop(coll, "collision_type") + class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel): diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 9d13397859d..f3939a2ebfc 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -21,6 +21,7 @@ * The Original Code is: all of this file. * * Contributor(s): Daniel Genrich + * Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ @@ -53,6 +54,7 @@ #include "BKE_bvhutils.h" #include "BKE_cdderivedmesh.h" +#include "BKE_collision.h" #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" #include "BKE_effect.h" @@ -118,7 +120,6 @@ static void tend ( void ) gettimeofday ( &_tend,&tz ); } -#if 0 // unused static double tval() { double t1, t2; @@ -127,14 +128,16 @@ static double tval() return t2-t1; } #endif -#endif struct Object; struct Scene; struct DerivedMesh; struct SmokeModifierData; -#define TRI_UVOFFSET (1.0 / 4.0) +#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); @@ -159,7 +162,7 @@ void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Obje static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) { - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) + 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}; @@ -171,7 +174,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, res = smd->domain->maxres; // get BB of domain - for (i = 0; i < dm->getNumVerts(dm); i++) + for(i = 0; i < dm->getNumVerts(dm); i++) { float tmp[3]; @@ -198,32 +201,32 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, // printf("size: %f, %f, %f\n", size[0], size[1], size[2]); // prevent crash when initializing a plane as domain - if ((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON)) + if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON)) return 0; - if (size[0] > size[1]) + if(size[0] > size[1]) { - if (size[0] > size[2]) + if(size[0] > size[2]) { scale = res / size[0]; - smd->domain->dx = size[0] / res; + smd->domain->dx = size[0] / res; // dx is in global coords 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->dx = size[2] / res; + smd->domain->dx = size[2] / res; // dx is in global coords 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); } } else { - if (size[1] > size[2]) + if(size[1] > size[2]) { scale = res / size[1]; - smd->domain->dx = size[1] / res; + smd->domain->dx = size[1] / res; // dx is in global coords 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); @@ -243,10 +246,10 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]); // dt max is 0.1 - smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0); + 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) + 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); @@ -257,19 +260,19 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, // printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n"); } - if (!smd->domain->shadow) + 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) + if(smd->domain->wt) { smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength)); // printf("smoke_initWaveletBlenderRNA\n"); } return 1; } - else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) + else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { // handle flow object here // XXX TODO @@ -288,7 +291,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, } /* - if (!smd->flow->bvh) + if(!smd->flow->bvh) { // smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces"); // bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6); @@ -301,28 +304,33 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, return 1; } - else if ((smd->type & MOD_SMOKE_TYPE_COLL)) + else if((smd->type & MOD_SMOKE_TYPE_COLL)) { - smd->time = scene->r.cfra; - // todo: delete this when loading colls work -dg - if (!smd->coll) - smokeModifier_createType(smd); - if (!smd->coll->points) + 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); + + // DEBUG printf("scs->dx: %f\n", scs->dx); } - if (!smd->coll->bvhtree) + 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 ); } @@ -337,50 +345,52 @@ 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; - int *tridivs = NULL; - float cell_len = 1.0 / 50.0; // for res = 50 + + // 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++) + for(i = 0; i < dm->getNumTessFaces(dm); i++) { - if (mface[i].v4) + if(mface[i].v4) quads++; } - calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumTessFaces(dm), dm->getNumTessFaces(dm) + quads, &tridivs, cell_len); + 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++) + for(i = 0; i < dm->getNumTessFaces(dm) + quads; i++) { - divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1); + divs += (scs->tridivs[3 * i] + 1) * (scs->tridivs[3 * i + 1] + 1) * (scs->tridivs[3 * i + 2] + 1); } - // printf("divs: %d\n", divs); - 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++) + for(i = 0; i < dm->getNumVerts(dm); i++) { float tmpvec[3]; copy_v3_v3(tmpvec, mvert[i].co); - mul_m4_v3(ob->obmat, tmpvec); + // 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++) + for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++) { int again = 0; do { int j, k; - int divs1 = tridivs[3 * facecounter + 0]; - int divs2 = tridivs[3 * facecounter + 1]; - //int divs3 = tridivs[3 * facecounter + 2]; + 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) + 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); @@ -395,23 +405,23 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) copy_v3_v3(trinorm, trinormorg); mul_v3_fl(trinorm, 0.25 * cell_len); - for (j = 0; j <= divs1; j++) + for(j = 0; j <= divs1; j++) { - for (k = 0; k <= divs2; k++) + 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) + 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) + if(again == 1 && mface[i].v4) { copy_v3_v3(p2, mvert[ mface[i].v3 ].co); copy_v3_v3(p3, mvert[ mface[i].v4 ].co); @@ -428,40 +438,211 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) add_v3_v3v3(p, p1, p2); add_v3_v3(p, p3); - if (newdivs > divs) + if(newdivs > divs) printf("mem problem\n"); // mMovPoints.push_back(p + trinorm); add_v3_v3v3(tmpvec, p, trinorm); - mul_m4_v3(ob->obmat, tmpvec); + // 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) + 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); + // 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) + if(again == 0 && mface[i].v4) again++; else again = 0; facecounter++; - } while (again!=0); + } while(again!=0); } + scs->numverts = dm->getNumVerts(dm); + // DG TODO: also save triangle count? + scs->numpoints = dm->getNumVerts(dm) + newdivs; - MEM_freeN(tridivs); + for(i = 0; i < scs->numpoints * 3; i++) + { + scs->points_old[i] = scs->points[i]; + } +} + + +static void fill_scs_points_anim(Object *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 */ @@ -472,22 +653,22 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa // mTriangleDivs3.resize( faces.size() ); size_t i = 0, facecounter = 0; - float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); + 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]); + 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.5 * scaleFac; + fsTri = cell_len * 0.75 * scaleFac; // fsTri = cell_len * 0.9; - if (*tridivs) + if(*tridivs) MEM_freeN(*tridivs); *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); - for (i = 0, facecounter = 0; i < numfaces; i++) + for(i = 0, facecounter = 0; i < numfaces; i++) { float p0[3], p1[3], p2[3]; float side1[3]; @@ -506,21 +687,22 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa sub_v3_v3v3(side2, p2, p0); sub_v3_v3v3(side3, p1, p2); - if (dot_v3v3(side1, side1) > fsTri*fsTri) + if(dot_v3v3(side1, side1) > fsTri*fsTri) { float tmp = normalize_v3(side1); divs1 = (int)ceil(tmp/fsTri); } - if (dot_v3v3(side2, side2) > fsTri*fsTri) + if(dot_v3v3(side2, side2) > fsTri*fsTri) { float tmp = normalize_v3(side2); divs2 = (int)ceil(tmp/fsTri); - /* + /* // debug - if (i==0) + if(i==0) printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); */ + } (*tridivs)[3 * facecounter + 0] = divs1; @@ -528,7 +710,7 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa (*tridivs)[3 * facecounter + 2] = divs3; // TODO quad case - if (faces[i].v4) + if(faces[i].v4) { divs1=0, divs2=0, divs3=0; @@ -545,12 +727,12 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa sub_v3_v3v3(side2, p2, p0); sub_v3_v3v3(side3, p1, p2); - if (dot_v3v3(side1, side1) > fsTri*fsTri) + if(dot_v3v3(side1, side1) > fsTri*fsTri) { float tmp = normalize_v3(side1); divs1 = (int)ceil(tmp/fsTri); } - if (dot_v3v3(side2, side2) > fsTri*fsTri) + if(dot_v3v3(side2, side2) > fsTri*fsTri) { float tmp = normalize_v3(side2); divs2 = (int)ceil(tmp/fsTri); @@ -568,19 +750,19 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa static void smokeModifier_freeDomain(SmokeModifierData *smd) { - if (smd->domain) + if(smd->domain) { - if (smd->domain->shadow) + if(smd->domain->shadow) MEM_freeN(smd->domain->shadow); smd->domain->shadow = NULL; - if (smd->domain->fluid) + if(smd->domain->fluid) smoke_free(smd->domain->fluid); - if (smd->domain->wt) + if(smd->domain->wt) smoke_turbulence_free(smd->domain->wt); - if (smd->domain->effector_weights) + if(smd->domain->effector_weights) MEM_freeN(smd->domain->effector_weights); smd->domain->effector_weights = NULL; @@ -594,10 +776,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd) static void smokeModifier_freeFlow(SmokeModifierData *smd) { - if (smd->flow) + if(smd->flow) { /* - if (smd->flow->bvh) + if(smd->flow->bvh) { free_bvhtree_from_mesh(smd->flow->bvh); MEM_freeN(smd->flow->bvh); @@ -611,22 +793,37 @@ static void smokeModifier_freeFlow(SmokeModifierData *smd) static void smokeModifier_freeCollision(SmokeModifierData *smd) { - if (smd->coll) + if(smd->coll) { - if (smd->coll->points) + SmokeCollSettings *scs = smd->coll; + + if(scs->numpoints) { - MEM_freeN(smd->coll->points); - smd->coll->points = NULL; + if(scs->points) + { + 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; + } } - if (smd->coll->bvhtree) + if(scs->bvhtree) { - BLI_bvhtree_free(smd->coll->bvhtree); - smd->coll->bvhtree = NULL; + BLI_bvhtree_free(scs->bvhtree); + scs->bvhtree = NULL; } #ifdef USE_SMOKE_COLLISION_DM - if (smd->coll->dm) + if(smd->coll->dm) smd->coll->dm->release(smd->coll->dm); smd->coll->dm = NULL; #endif @@ -638,7 +835,7 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd) void smokeModifier_reset_turbulence(struct SmokeModifierData *smd) { - if (smd && smd->domain && smd->domain->wt) + if(smd && smd->domain && smd->domain->wt) { smoke_turbulence_free(smd->domain->wt); smd->domain->wt = NULL; @@ -647,15 +844,15 @@ void smokeModifier_reset_turbulence(struct SmokeModifierData *smd) void smokeModifier_reset(struct SmokeModifierData *smd) { - if (smd) + if(smd) { - if (smd->domain) + if(smd->domain) { - if (smd->domain->shadow) + if(smd->domain->shadow) MEM_freeN(smd->domain->shadow); smd->domain->shadow = NULL; - if (smd->domain->fluid) + if(smd->domain->fluid) { smoke_free(smd->domain->fluid); smd->domain->fluid = NULL; @@ -667,10 +864,10 @@ void smokeModifier_reset(struct SmokeModifierData *smd) // printf("reset domain end\n"); } - else if (smd->flow) + else if(smd->flow) { /* - if (smd->flow->bvh) + if(smd->flow->bvh) { free_bvhtree_from_mesh(smd->flow->bvh); MEM_freeN(smd->flow->bvh); @@ -678,33 +875,33 @@ void smokeModifier_reset(struct SmokeModifierData *smd) smd->flow->bvh = NULL; */ } - else if (smd->coll) + else if(smd->coll) { - if (smd->coll->points) + SmokeCollSettings *scs = smd->coll; + + if(scs->numpoints && scs->points) { - MEM_freeN(smd->coll->points); - smd->coll->points = NULL; + 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; + } } - - if (smd->coll->bvhtree) - { - BLI_bvhtree_free(smd->coll->bvhtree); - smd->coll->bvhtree = NULL; - } - -#ifdef USE_SMOKE_COLLISION_DM - if (smd->coll->dm) - smd->coll->dm->release(smd->coll->dm); - smd->coll->dm = NULL; -#endif - } } } void smokeModifier_free (SmokeModifierData *smd) { - if (smd) + if(smd) { smokeModifier_freeDomain(smd); smokeModifier_freeFlow(smd); @@ -714,11 +911,11 @@ void smokeModifier_free (SmokeModifierData *smd) void smokeModifier_createType(struct SmokeModifierData *smd) { - if (smd) + if(smd) { - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) + if(smd->type & MOD_SMOKE_TYPE_DOMAIN) { - if (smd->domain) + if(smd->domain) smokeModifier_freeDomain(smd); smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); @@ -745,7 +942,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->beta = 0.1; smd->domain->time_scale = 1.0; smd->domain->vorticity = 2.0; - smd->domain->border_collisions = 1; // vertically non-colliding + smd->domain->border_collisions = SM_BORDER_OPEN; // open domain smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG | MOD_SMOKE_HIGH_SMOOTH; smd->domain->strength = 2.0; smd->domain->noise = MOD_SMOKE_NOISEWAVE; @@ -755,9 +952,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG; smd->domain->effector_weights = BKE_add_effector_weights(NULL); } - else if (smd->type & MOD_SMOKE_TYPE_FLOW) + else if(smd->type & MOD_SMOKE_TYPE_FLOW) { - if (smd->flow) + if(smd->flow) smokeModifier_freeFlow(smd); smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); @@ -773,17 +970,23 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->flow->psys = NULL; } - else if (smd->type & MOD_SMOKE_TYPE_COLL) + else if(smd->type & MOD_SMOKE_TYPE_COLL) { - if (smd->coll) + if(smd->coll) smokeModifier_freeCollision(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->type = 0; // static obstacle + smd->coll->dx = 1.0f / 50.0f; #ifdef USE_SMOKE_COLLISION_DM smd->coll->dm = NULL; @@ -818,7 +1021,7 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData MEM_freeN(tsmd->domain->effector_weights); tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights); - } + } else if (tsmd->flow) { tsmd->flow->density = smd->flow->density; tsmd->flow->temp = smd->flow->temp; @@ -845,15 +1048,15 @@ static int get_lamp(Scene *scene, float *light) int found_lamp = 0; // try to find a lamp, preferably local - for (base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next) { - if (base_tmp->object->type == OB_LAMP) { + for(base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next) { + if(base_tmp->object->type == OB_LAMP) { Lamp *la = base_tmp->object->data; - if (la->type == LA_LOCAL) { + if(la->type == LA_LOCAL) { copy_v3_v3(light, base_tmp->object->obmat[3]); return 1; } - else if (!found_lamp) { + else if(!found_lamp) { copy_v3_v3(light, base_tmp->object->obmat[3]); found_lamp = 1; } @@ -865,497 +1068,603 @@ static int get_lamp(Scene *scene, float *light) static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) { +#if 0 SmokeDomainSettings *sds = smd->domain; GroupObject *go = NULL; - Base *base = NULL; + Base *base = NULL; - // do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells - if (1) + /* do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells */ + if(1) { - Object *otherobj = NULL; - ModifierData *md = NULL; + unsigned int i; + Object **collobjs = NULL; + unsigned int numcollobj = 0; + collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj); - if (sds->coll_group) // we use groups since we have 2 domains - go = sds->coll_group->gobject.first; - else - base = scene->base.first; - - while (base || go) + for(i = 0; i < numcollobj; i++) { - otherobj = NULL; - if (sds->coll_group) - { - if (go->ob) - otherobj = go->ob; - } - else - otherobj = base->object; - if (!otherobj) - { - if (sds->coll_group) - go = go->next; - else - base= base->next; - continue; - } - md = modifiers_findByType(otherobj, eModifierType_Smoke); + 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)) + // if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) + // SmokeModifierData *smd2 = (SmokeModifierData *)md; + + if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old) { - SmokeModifierData *smd2 = (SmokeModifierData *)md; + // ??? anything to do here? - if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points) + // TODO: only something to do for ANIMATED obstacles: need to update positions + + } + } + + if(collobjs) + MEM_freeN(collobjs); + } + +#endif +} + +/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */ +static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt, int substep, int totalsteps) +{ + Object **collobjs = NULL; + unsigned int numcollobj = 0; + + unsigned int collIndex; + unsigned char *obstacles = smoke_get_obstacle(sds->fluid); + float *velx = NULL; + float *vely = NULL; + float *velz = NULL; + 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); + unsigned int z; + + 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]) + { + // density[z] = 0; + + velxOrig[z] = 0; + velyOrig[z] = 0; + velzOrig[z] = 0; + } + + 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 && smd2->coll->points && smd2->coll->points_old) + { + SmokeCollSettings *scs = smd2->coll; + unsigned int i; + + /* + // DG TODO: support static cobstacles, but basicly we could even support static + rigid with one set of code + if(scs->type > SM_COLL_STATIC) + */ + + /* 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 */ { - // we got nice collision object - SmokeCollSettings *scs = smd2->coll; - size_t i, j; - unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid); + float tmp[3]; - for (i = 0; i < scs->numpoints; i++) + /* x_current = x_old + (x_new - x_old) * step_current / steps_total */ + float mulStep = (float)(((float)substep) / ((float)totalsteps)); + + sub_v3_v3v3(tmp, cPos, cOldpos); + mul_v3_fl(tmp, mulStep); + add_v3_v3(cOldpos, tmp); + } + + sub_v3_v3v3(vel, pos, oldpos); + /* Scale velocity to incorperate the object movement during this step */ + mul_v3_fl(vel, 1.0 / (totalsteps * dt)); + // mul_v3_fl(vel, 1.0 / dt); + + // DG TODO: cap velocity to maxVelMag (or maxvel) + + // oldpos + velocity * dt = newpos + get_cell(sds->p0, sds->res, sds->dx, 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)) { - int badcell = 0; - size_t index = 0; - int cell[3]; - - // 1. get corresponding cell - get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, &scs->points[3 * i], 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)) - { - 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]); - - // 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; - // for moving gobstacles - /* - const LbmFloat maxVelVal = 0.1666; - const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5; - - LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); - { - const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; - USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); - if (usqr>maxusqr) { - // cutoff at maxVelVal - for (int jj=0; jj<3; jj++) { - if (objvel[jj] > 0.0) objvel[jj] = maxVelVal; - if (objvel[jj] < 0.0) objvel[jj] = -maxVelVal; - } - } - } - const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); - const LbmVec oldov=objvel; // debug - objvel = vec2L((*pNormals)[n]) *dp; - */ + 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]); + + // 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 */; + + if(len_v3(vel) > FLT_EPSILON) + { + // Collision object is moving + + velx[index] = vel[0]; // use "+="? + vely[index] = vel[1]; + velz[index] = vel[2]; } } - - if (sds->coll_group) - go = go->next; - else - base= base->next; } } - // do flows and fluids - if (1) + if(collobjs) + MEM_freeN(collobjs); +} + +static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float time) +{ + Object **flowobjs = NULL; + unsigned int numflowobj = 0; + unsigned int flowIndex; + + flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke); + + // update obstacle tags in cells + for(flowIndex = 0; flowIndex < numflowobj; flowIndex++) { - Object *otherobj = NULL; - ModifierData *md = NULL; - if (sds->fluid_group) // we use groups since we have 2 domains - go = sds->fluid_group->gobject.first; - else - base = scene->base.first; - while (base || go) - { - otherobj = NULL; - if (sds->fluid_group) - { - if (go->ob) - otherobj = go->ob; - } - else - otherobj = base->object; - if (!otherobj) - { - if (sds->fluid_group) - go = go->next; - else - base= base->next; + Object *collob= flowobjs[flowIndex]; + SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke); - continue; - } + // check for initialized smoke object + if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) + { + // we got nice flow object + SmokeFlowSettings *sfs = smd2->flow; - md = modifiers_findByType(otherobj, eModifierType_Smoke); - - // check for active smoke modifier - if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) + if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected { - SmokeModifierData *smd2 = (SmokeModifierData *)md; - - // check for initialized smoke object - if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) + 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)) { - // we got nice flow object - SmokeFlowSettings *sfs = smd2->flow; - - if (sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected + 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; ires[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) { - 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); - int bigres[3]; - short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); - short high_emission_smoothing = bigdensity ? (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) : 0; + totchild = psys->totchildcache; + } + else + */ - /* - * 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; + // TODO: PART_HAIR not supported whatsoever + totchild=0; + } + else + totchild=psys->totchild*psys->part->disp/100; - sim.scene = scene; - sim.ob = otherobj; - sim.psys = psys; + for(p=0; ptype & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) + 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; + + // 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, 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)) { - 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; ires[0]*sds->res[1]*sds->res[2]; i++) { - temp_emission_map[i] = 0.0f; - } + 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; + } } - - // mostly copied from particle code - if (psys->part->type==PART_HAIR) - { - /* - if (psys->childcache) + } + } // 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; + + smoke_turbulence_get_res(sds->wt, bigres); + block_size = sds->amplify + 1; // high res block size + + // 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++) { - totchild = psys->totchildcache; - } - else - */ + // neighbor cell emission densities (for high resolution smoke smooth interpolation) + float c000, c001, c010, c011, c100, c101, c110, c111; - // TODO: PART_HAIR not supported whatsoever - totchild=0; - } - else - totchild=psys->totchild*psys->part->disp/100; - - for (p=0; p0 && 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; - 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; - } + 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 - state.time = smd->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(smd->domain->p0, smd->domain->res, smd->domain->dx, 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; + // get cell index + index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); - // Uses particle velocity as initial velocity for smoke - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) + // add emission to low resolution density + if (absolute_flow) { - 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(smd->domain->wt, bigres); - - for (i = 0; i < smd->domain->amplify + 1; i++) - for (j = 0; j < smd->domain->amplify + 1; j++) - for (k = 0; k < smd->domain->amplify + 1; k++) - { - index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); - bigdensity[index] = 0.f; - } + if (temp_emission_map[index]>0) + density[index] = temp_emission_map[index]; } - } - } // particles loop + else + { + density[index] += temp_emission_map[index]; + if (density[index]>1) + density[index]=1.0f; + } - // apply emission values - if (!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) { + smoke_turbulence_get_res(sds->wt, bigres); - // initialize variables - int ii, jj, kk, x, y, z, block_size; - size_t index, index_big; - - smoke_turbulence_get_res(smd->domain->wt, bigres); - block_size = smd->domain->amplify + 1; // high res block size - - - // 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++) + /* 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++) { - // neighbor cell emission densities (for high resolution smoke smooth interpolation) - float c000, c001, c010, c011, c100, c101, c110, c111; - - 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; - - 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 - - - - // get cell index - index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); - - // add emission to low resolution density - if (absolute_flow) {if (temp_emission_map[index]>0) density[index] = temp_emission_map[index];} - else { - density[index] += temp_emission_map[index]; - if (density[index]>1) density[index]=1.0f; - } - - smoke_turbulence_get_res(smd->domain->wt, bigres); - + float fx,fy,fz, interpolated_value; + int shift_x, shift_y, shift_z; /* - loop through high res blocks if high res enabled + * Do volume interpolation if emitter smoothing + * is enabled */ - if (bigdensity) - for (ii = 0; ii < block_size; ii++) - for (jj = 0; jj < block_size; jj++) - for (kk = 0; kk < block_size; kk++) - { + if (high_emission_smoothing) + { + // convert block position to relative + // for interpolation smoothing + fx = (float)ii/block_size + 0.5f/block_size; + fy = (float)jj/block_size + 0.5f/block_size; + fz = (float)kk/block_size + 0.5f/block_size; - float fx,fy,fz, interpolated_value; - int shift_x, shift_y, shift_z; + // calculate trilinear interpolation + interpolated_value = c000 * (1-fx) * (1-fy) * (1-fz) + + c100 * fx * (1-fy) * (1-fz) + + c010 * (1-fx) * fy * (1-fz) + + c001 * (1-fx) * (1-fy) * fz + + c101 * fx * (1-fy) * fz + + c011 * (1-fx) * fy * fz + + c110 * fx * fy * (1-fz) + + c111 * fx * fy * fz; - /* - * Do volume interpolation if emitter smoothing - * is enabled - */ - if (high_emission_smoothing) { - // convert block position to relative - // for interpolation smoothing - fx = (float)ii/block_size + 0.5f/block_size; - fy = (float)jj/block_size + 0.5f/block_size; - fz = (float)kk/block_size + 0.5f/block_size; + // add some contrast / sharpness + // depending on hi-res block size - // calculate trilinear interpolation - interpolated_value = c000 * (1-fx) * (1-fy) * (1-fz) + - c100 * fx * (1-fy) * (1-fz) + - c010 * (1-fx) * fy * (1-fz) + - c001 * (1-fx) * (1-fy) * fz + - c101 * fx * (1-fy) * fz + - c011 * (1-fx) * fy * fz + - c110 * fx * fy * (1-fz) + - c111 * fx * fy * fz; + interpolated_value = (interpolated_value-0.4f*sfs->density)*(block_size/2) + 0.4f*sfs->density; + if (interpolated_value<0.0f) interpolated_value = 0.0f; + if (interpolated_value>1.0f) interpolated_value = 1.0f; + // shift smoke block index + // (because pixel center is actually + // in halfway of the low res block) + shift_x = (x < 1) ? 0 : block_size/2; + shift_y = (y < 1) ? 0 : block_size/2; + shift_z = (z < 1) ? 0 : block_size/2; + } + else + { + // without interpolation use same low resolution + // block value for all hi-res blocks + interpolated_value = c111; + shift_x = 0; + shift_y = 0; + shift_z = 0; + } - // add some contrast / sharpness - // depending on hi-res block size + // get shifted index for current high resolution block + index_big = smoke_get_index(block_size * x + ii - shift_x, bigres[0], block_size * y + jj - shift_y, bigres[1], block_size * z + kk - shift_z); - interpolated_value = (interpolated_value-0.4f*sfs->density)*(block_size/2) + 0.4f*sfs->density; - if (interpolated_value<0.0f) interpolated_value = 0.0f; - if (interpolated_value>1.0f) interpolated_value = 1.0f; + // add emission data to high resolution density + if (absolute_flow) + { + if (interpolated_value > 0) + bigdensity[index_big] = interpolated_value; + } + else + { + bigdensity[index_big] += interpolated_value; - // shift smoke block index - // (because pixel center is actually - // in halfway of the low res block) - shift_x = (x < 1) ? 0 : block_size/2; - shift_y = (y < 1) ? 0 : block_size/2; - shift_z = (z < 1) ? 0 : block_size/2; - } - else { - // without interpolation use same low resolution - // block value for all hi-res blocks - interpolated_value = c111; - shift_x = 0; - shift_y = 0; - shift_z = 0; - } + if (bigdensity[index_big]>1) + bigdensity[index_big]=1.0f; + } + } // end of hires loop - // get shifted index for current high resolution block - index_big = smoke_get_index(block_size * x + ii - shift_x, bigres[0], block_size * y + jj - shift_y, bigres[1], block_size * z + kk - shift_z); - - // add emission data to high resolution density - if (absolute_flow) {if (interpolated_value > 0) bigdensity[index_big] = interpolated_value;} - else { - bigdensity[index_big] += interpolated_value; - if (bigdensity[index_big]>1) bigdensity[index_big]=1.0f; - } + } // end of low res loop - } // end of hires loop + // free temporary emission map + if (temp_emission_map) + MEM_freeN(temp_emission_map); - } // end of low res loop - - // free temporary emission map - if (temp_emission_map) MEM_freeN(temp_emission_map); - - } // end emission - - - - } - else { - /* - for () - { - // no psys - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist = FLT_MAX; - - BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh); - }*/ - } - } - } - if (sds->fluid_group) - go = go->next; - else - base= base->next; - } - } - - // do effectors - { - ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); - - if (effectors) - { - float *density = smoke_get_density(sds->fluid); - float *force_x = smoke_get_force_x(sds->fluid); - float *force_y = smoke_get_force_y(sds->fluid); - float *force_z = smoke_get_force_z(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); - int x, y, z; - - // precalculate wind forces - for (x = 0; x < sds->res[0]; x++) - for (y = 0; y < sds->res[1]; y++) - for (z = 0; z < sds->res[2]; z++) - { - EffectedPoint epoint; - float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0}; - unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); - - if (density[index] < FLT_EPSILON) - continue; - - vel[0] = velocity_x[index]; - vel[1] = velocity_y[index]; - vel[2] = velocity_z[index]; - - voxelCenter[0] = sds->p0[0] + sds->dx * x + sds->dx * 0.5; - voxelCenter[1] = sds->p0[1] + sds->dx * y + sds->dx * 0.5; - voxelCenter[2] = sds->p0[2] + sds->dx * z + sds->dx * 0.5; - - pd_point_from_loc(scene, voxelCenter, vel, index, &epoint); - pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); - - // TODO dg - do in force! - force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); - force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); - force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0); + } // end emission } } - - pdEndEffectors(&effectors); } + if(flowobjs) + MEM_freeN(flowobjs); } + +static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) +{ + ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); + + if(effectors) + { + float *density = smoke_get_density(sds->fluid); + float *force_x = smoke_get_force_x(sds->fluid); + float *force_y = smoke_get_force_y(sds->fluid); + float *force_z = smoke_get_force_z(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); + int x, y, z; + + // precalculate wind forces + for(x = 0; x < sds->res[0]; x++) + for(y = 0; y < sds->res[1]; y++) + for(z = 0; z < sds->res[2]; z++) + { + EffectedPoint epoint; + float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0}; + unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); + + if((density[index] < FLT_EPSILON) || obstacle[index]) + continue; + + vel[0] = velocity_x[index]; + vel[1] = velocity_y[index]; + vel[2] = velocity_z[index]; + + voxelCenter[0] = sds->p0[0] + sds->dx * x + sds->dx * 0.5; + voxelCenter[1] = sds->p0[1] + sds->dx * y + sds->dx * 0.5; + voxelCenter[2] = sds->p0[2] + sds->dx * z + sds->dx * 0.5; + + pd_point_from_loc(scene, voxelCenter, vel, index, &epoint); + pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); + + // TODO dg - do in force! + force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); + force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); + force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0); + } + } + + pdEndEffectors(&effectors); +} + +static void step(Scene *scene, Object *ob, SmokeModifierData *smd, float fps) +{ + /* stability values copied from wturbulence.cpp */ + const int maxSubSteps = 25; + float maxVel; + // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size) + + float dt = DT_DEFAULT; + float maxVelMag = 0.0f; + int totalSubsteps; + int substep = 0; + float dtSubdiv; + + SmokeDomainSettings *sds = smd->domain; + + /* get max velocity and lower the dt value if it is too high */ + size_t size= sds->res[0] * sds->res[1] * sds->res[2]; + + float *velX = smoke_get_velocity_x(sds->fluid); + float *velY = smoke_get_velocity_y(sds->fluid); + float *velZ = smoke_get_velocity_z(sds->fluid); + size_t i; + + /* adapt timestep for different framerates, dt = 0.1 is at 25fps */ + dt *= (25.0f / fps); + + // printf("test maxVel: %f\n", (sds->dx * 1.5) / dt); // gives 0.9 + maxVel = (sds->dx * 1.5); + + for(i = 0; i < size; i++) + { + float vtemp = (velX[i]*velX[i]+velY[i]*velY[i]+velZ[i]*velZ[i]); + if(vtemp > maxVelMag) + maxVelMag = vtemp; + } + + maxVelMag = sqrt(maxVelMag) * dt * sds->time_scale; + totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ + totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; + totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; + + // totalSubsteps = 2.0f; // DEBUG + + dtSubdiv = (float)dt / (float)totalSubsteps; + + // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt); + + for(substep = 0; substep < totalSubsteps; substep++) + { + // calc animated obstacle velocities + update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps); + update_flowsfluids(scene, ob, sds, smd->time); + update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt + + smoke_step(sds->fluid, dtSubdiv); + + // move animated obstacle: Done in update_obstacles() */ + + // where to delete old obstacles from array? Done in update_obstacles() */ + } +} + void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) { - if ((smd->type & MOD_SMOKE_TYPE_FLOW)) + if((smd->type & MOD_SMOKE_TYPE_FLOW)) { - if (scene->r.cfra >= smd->time) + if(scene->r.cfra >= smd->time) smokeModifier_init(smd, ob, scene, dm); - if (scene->r.cfra > smd->time) + if(scene->r.cfra > smd->time) { // XXX TODO smd->time = scene->r.cfra; @@ -1366,40 +1675,102 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM copy_m4_m4(smd->flow->mat, ob->obmat); */ } - else if (scene->r.cfra < smd->time) + else if(scene->r.cfra < smd->time) { smd->time = scene->r.cfra; smokeModifier_reset(smd); } } - else if (smd->type & MOD_SMOKE_TYPE_COLL) + else if(smd->type & MOD_SMOKE_TYPE_COLL) { - if (scene->r.cfra >= smd->time) + /* Check if domain resolution changed */ + /* DG TODO: can this be solved more elegant using dependancy graph? */ + { + SmokeCollSettings *scs = smd->coll; + Base *base = scene->base.first; + int changed = 0; + float dx = FLT_MAX; + int haveDomain = 0; + + for ( ; base; base = base->next) + { + SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke); + + if (smd2 && (smd2->type & MOD_SMOKE_TYPE_DOMAIN) && smd2->domain) + { + SmokeDomainSettings *sds = smd2->domain; + + if(sds->dx < dx) + { + dx = sds->dx; + changed = 1; + } + + haveDomain = 1; + } + } + + if(!haveDomain) + return; + + if(changed) + { + if(dx != scs->dx) + { + scs->dx = dx; + smokeModifier_reset(smd); + } + } + } + + if(scene->r.cfra >= smd->time) smokeModifier_init(smd, ob, scene, dm); - if (scene->r.cfra > smd->time) + if(scene->r.cfra > smd->time) { - // XXX TODO + unsigned int i; + SmokeCollSettings *scs = smd->coll; + float *points_old = scs->points_old; + float *points = scs->points; + unsigned int numpoints = scs->numpoints; + + // XXX TODO <-- DG: what is TODO here? smd->time = scene->r.cfra; -#ifdef USE_SMOKE_COLLISION_DM - if (smd->coll->dm) - smd->coll->dm->release(smd->coll->dm); - - smd->coll->dm = CDDM_copy_from_tessface(dm); -#endif - // rigid movement support - copy_m4_m4(smd->coll->mat_old, smd->coll->mat); - copy_m4_m4(smd->coll->mat, ob->obmat); + copy_m4_m4(scs->mat_old, scs->mat); + copy_m4_m4(scs->mat, ob->obmat); + + if(scs->type != SM_COLL_ANIMATED) // if(not_animated) + { + // nothing to do, "mat" is already up to date + } + else + { + // XXX TODO: need to update positions + divs + + if(scs->numverts != dm->getNumVerts(dm)) + { + // DG TODO: reset modifier? + return; + } + + for(i = 0; i < numpoints * 3; i++) + { + points_old[i] = points[i]; + } + + DM_ensure_tessface(dm); + fill_scs_points_anim(ob, dm, scs); + } } - else if (scene->r.cfra < smd->time) + else if(scene->r.cfra < smd->time) { smd->time = scene->r.cfra; smokeModifier_reset(smd); } } - else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) + else if(smd->type & MOD_SMOKE_TYPE_DOMAIN) { SmokeDomainSettings *sds = smd->domain; float light[3]; @@ -1416,14 +1787,14 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM BKE_ptcache_id_from_smoke(&pid, ob, smd); BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); - if (!smd->domain->fluid || framenr == startframe) + if(!smd->domain->fluid || framenr == startframe) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); BKE_ptcache_validate(cache, framenr); cache->flag &= ~PTCACHE_REDO_NEEDED; } - if (!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0) + if(!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0) return; smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD; @@ -1436,21 +1807,21 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM // printf("startframe: %d, framenr: %d\n", startframe, framenr); - if (smokeModifier_init(smd, ob, scene, dm)==0) + if(smokeModifier_init(smd, ob, scene, dm)==0) { printf("bad smokeModifier_init\n"); return; } /* try to read from cache */ - if (BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) { + if(BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) { BKE_ptcache_validate(cache, framenr); smd->time = framenr; return; } /* only calculate something when we advanced a single frame */ - if (framenr != (int)smd->time+1) + if(framenr != (int)smd->time+1) return; /* don't simulate if viewing start frame, but scene frame is not real start frame */ @@ -1462,14 +1833,14 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM smoke_calc_domain(scene, ob, smd); /* if on second frame, write cache for first frame */ - if ((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) { + if((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) { // create shadows straight after domain initialization so we get nice shadows for startframe, too - if (get_lamp(scene, light)) + if(get_lamp(scene, light)) smoke_calc_transparency(sds->shadow, smoke_get_density(sds->fluid), sds->p0, sds->p1, sds->res, sds->dx, light, calc_voxel_transp, -7.0*sds->dx); - if (sds->wt) + if(sds->wt) { - if (sds->flags & MOD_SMOKE_DISSOLVE) + if(sds->flags & MOD_SMOKE_DISSOLVE) smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); smoke_turbulence_step(sds->wt, sds->fluid); } @@ -1486,30 +1857,31 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM // simulate the actual smoke (c++ code in intern/smoke) // DG: interesting commenting this line + deactivating loading of noise files - if (framenr!=startframe) + if(framenr!=startframe) { - if (sds->flags & MOD_SMOKE_DISSOLVE) + if(sds->flags & MOD_SMOKE_DISSOLVE) smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); - smoke_step(sds->fluid, smd->time, scene->r.frs_sec / scene->r.frs_sec_base); + + step(scene, ob, smd, scene->r.frs_sec / scene->r.frs_sec_base); } // create shadows before writing cache so they get stored - if (get_lamp(scene, light)) + if(get_lamp(scene, light)) smoke_calc_transparency(sds->shadow, smoke_get_density(sds->fluid), sds->p0, sds->p1, sds->res, sds->dx, light, calc_voxel_transp, -7.0*sds->dx); - if (sds->wt) + if(sds->wt) { - if (sds->flags & MOD_SMOKE_DISSOLVE) + if(sds->flags & MOD_SMOKE_DISSOLVE) smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); smoke_turbulence_step(sds->wt, sds->fluid); } BKE_ptcache_validate(cache, framenr); - if (framenr != startframe) + if(framenr != startframe) BKE_ptcache_write(&pid, framenr); tend(); - //printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() ); + // printf ( "Frame: %d, Time: %f\n\n", (int)smd->time, ( float ) tval() ); } } @@ -1520,7 +1892,7 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix // T_ray *= T_vox *tRay *= exp(input[index]*correct); - if (result[index] < 0.0f) + if(result[index] < 0.0f) { #pragma omp critical result[index] = *tRay; @@ -1574,7 +1946,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f err_1 = dy2 - l; err_2 = dz2 - l; for (i = 0; i < l; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) + if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) break; if (err_1 > 0) { pixel[1] += y_inc; @@ -1588,12 +1960,12 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f err_2 += dz2; pixel[0] += x_inc; } - } + } else if ((m >= l) && (m >= n)) { err_1 = dx2 - m; err_2 = dz2 - m; for (i = 0; i < m; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) + if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) break; if (err_1 > 0) { pixel[0] += x_inc; @@ -1607,12 +1979,12 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f err_2 += dz2; pixel[1] += y_inc; } - } + } else { err_1 = dy2 - n; err_2 = dx2 - n; for (i = 0; i < n; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) + if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) break; if (err_1 > 0) { pixel[1] += y_inc; @@ -1654,7 +2026,7 @@ static void smoke_calc_transparency(float *result, float *input, float *p0, floa float bv[6]; int a, z, slabsize=res[0]*res[1], size= res[0]*res[1]*res[2]; - for (a=0; a= 0.0f) + if(result[index] >= 0.0f) continue; voxelCenter[0] = p0[0] + dx * x + dx * 0.5; voxelCenter[1] = p0[1] + dx * y + dx * 0.5; voxelCenter[2] = p0[2] + dx * z + dx * 0.5; // get starting position (in voxel coords) - if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) + if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) { // we're ouside get_cell(p0, res, dx, pos, cell, 1); diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 26b3a3e6c62..3e20b353856 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -56,6 +56,11 @@ #define SM_BORDER_VERTICAL 1 #define SM_BORDER_CLOSED 2 +/* collision types */ +#define SM_COLL_STATIC 0 +#define SM_COLL_RIGID 1 +#define SM_COLL_ANIMATED 2 + typedef struct SmokeDomainSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct FLUID_3D *fluid; @@ -137,15 +142,16 @@ typedef struct SmokeFlowSettings { typedef struct SmokeCollSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ - -// struct DerivedMesh *dm; // UNUSED, ifdef'd in code for now. float *points; float *points_old; - float *vel; + float *vel; // UNUSED + int *tridivs; float mat[4][4]; float mat_old[4][4]; int numpoints; int numverts; // check if mesh changed + int numtris; + float dx; /* global domain cell length taken from (scale / resolution) */ short type; // static = 0, rigid = 1, dynamic = 2 short pad; int pad2; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 69d76c0e342..b1fed62f87b 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -16,6 +16,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Contributor(s): Daniel Genrich + * Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ @@ -336,12 +337,25 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna) static void rna_def_smoke_coll_settings(BlenderRNA *brna) { + static EnumPropertyItem smoke_coll_type_items[] = { + {SM_COLL_STATIC, "COLLSTATIC", 0, "Static", "Non moving obstacle"}, + {SM_COLL_RIGID, "COLLRIGID", 0, "Rigid", "Rigid obstacle"}, + {SM_COLL_ANIMATED, "COLLANIMATED", 0, "Animated", "Animated obstacle"}, + {0, NULL, 0, NULL, NULL}}; + StructRNA *srna; + PropertyRNA *prop; srna = RNA_def_struct(brna, "SmokeCollSettings", NULL); RNA_def_struct_ui_text(srna, "Collision Settings", "Smoke collision settings"); RNA_def_struct_sdna(srna, "SmokeCollSettings"); RNA_def_struct_path_func(srna, "rna_SmokeCollSettings_path"); + + prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, smoke_coll_type_items); + RNA_def_property_ui_text(prop, "Collision type", "Collision type"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); } void RNA_def_smoke(BlenderRNA *brna)