From 8bf8a128c2f1df5c85ee0005d1821316d3e88261 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Sat, 28 Apr 2012 21:46:43 +0000 Subject: Smoke: Support for moving obstacles. (Merge from Smoke2 branch) Sponsored by the Blender Development Fund. http://www.blender.org/blenderorg/blender-foundation/development-fund/ Remarks: The original code was not designed to support moving obstacles so I had to introduce some velocity constraints into the code to prevent smoke from exploding. If this causes problems with "fire" emulation, please let me know. --- source/blender/blenkernel/intern/smoke.c | 1536 +++++++++++++++++----------- source/blender/makesdna/DNA_smoke_types.h | 12 +- source/blender/makesrna/intern/rna_smoke.c | 14 + 3 files changed, 977 insertions(+), 585 deletions(-) (limited to 'source') 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) + + if(!smd->coll) + { smokeModifier_createType(smd); + } - if (!smd->coll->points) + 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) - { - MEM_freeN(smd->coll->points); - smd->coll->points = NULL; - } + SmokeCollSettings *scs = smd->coll; - if (smd->coll->bvhtree) + if(scs->numpoints && scs->points) { - BLI_bvhtree_free(smd->coll->bvhtree); - smd->coll->bvhtree = 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; + } } - -#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? + + // TODO: only something to do for ANIMATED obstacles: need to update positions + + } + } + + if(collobjs) + MEM_freeN(collobjs); + } + +#endif +} - if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points) +/* 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++) - { - int badcell = 0; - size_t index = 0; - int cell[3]; + /* x_current = x_old + (x_new - x_old) * step_current / steps_total */ + float mulStep = (float)(((float)substep) / ((float)totalsteps)); - // 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; - */ + 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)) + { + 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; - - /* - * 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 = otherobj; - sim.psys = psys; - - // initialize temp emission map - if (!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) + totchild = psys->totchildcache; + } + else + */ + + // TODO: PART_HAIR not supported whatsoever + totchild=0; + } + else + totchild=psys->totchild*psys->part->disp/100; + + for(p=0; pparticles[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; - } - } - - // mostly copied from particle code - if (psys->part->type==PART_HAIR) + 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) { - /* - if (psys->childcache) - { - totchild = psys->totchildcache; - } - else - */ - - // TODO: PART_HAIR not supported whatsoever - totchild=0; + // 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 - totchild=psys->totchild*psys->part->disp/100; - - for (p=0; ptype & 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 - if (p < totpart) + // 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++) { - 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; - } + // neighbor cell emission densities (for high resolution smoke smooth interpolation) + float c000, c001, c010, c011, c100, c101, c110, c111; - 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; - - // 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) + 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) { - // 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; + /* 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++) + { - smoke_turbulence_get_res(smd->domain->wt, bigres); - block_size = smd->domain->amplify + 1; // high res block size + float fx,fy,fz, interpolated_value; + int shift_x, shift_y, shift_z; - // 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++) - { + /* + * 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; + + // 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; + + + // add some contrast / sharpness + // depending on hi-res block size + + 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; + } - // neighbor cell emission densities (for high resolution smoke smooth interpolation) - float c000, c001, c010, c011, c100, c101, c110, c111; + // 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); - 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; + // 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; - 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 + if (bigdensity[index_big]>1) + bigdensity[index_big]=1.0f; + } + } // end of hires loop + } // end of low res loop + // free temporary emission map + if (temp_emission_map) + MEM_freeN(temp_emission_map); - // get cell index - index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); + } // end emission + } + } + } - // 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; - } + if(flowobjs) + MEM_freeN(flowobjs); +} - smoke_turbulence_get_res(smd->domain->wt, bigres); +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); +} - /* - 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++) - { - - float fx,fy,fz, interpolated_value; - int shift_x, shift_y, shift_z; - - - /* - * 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; - - // 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; - - - // add some contrast / sharpness - // depending on hi-res block size - - 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; - } - - // 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; - } +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) - } // end of hires loop + float dt = DT_DEFAULT; + float maxVelMag = 0.0f; + int totalSubsteps; + int substep = 0; + float dtSubdiv; - } // end of low res loop + SmokeDomainSettings *sds = smd->domain; - // free temporary emission map - if (temp_emission_map) MEM_freeN(temp_emission_map); + /* 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]; - } // end emission + 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); - - } - else { - /* - for () - { - // no psys - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist = FLT_MAX; + // printf("test maxVel: %f\n", (sds->dx * 1.5) / dt); // gives 0.9 + maxVel = (sds->dx * 1.5); - 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; - } + 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; } - // do effectors + 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++) { - ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); + // 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 - 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); - } - } + smoke_step(sds->fluid, dtSubdiv); - pdEndEffectors(&effectors); - } + // 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); + // rigid movement support + copy_m4_m4(scs->mat_old, scs->mat); + copy_m4_m4(scs->mat, ob->obmat); - smd->coll->dm = CDDM_copy_from_tessface(dm); -#endif + 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 - // rigid movement support - copy_m4_m4(smd->coll->mat_old, smd->coll->mat); - copy_m4_m4(smd->coll->mat, ob->obmat); + 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) -- cgit v1.2.3