Smoke: fix crash with collisions + flows
[blender.git] / source / blender / blenkernel / intern / smoke.c
index c619c3e25ab0a0a77df39d3b25113bc624e30123..3f23fbda484beb996bddc98ded51e6bc2501aa08 100644 (file)
@@ -48,6 +48,7 @@
 #include "BLI_kdtree.h"
 #include "BLI_kdopbvh.h"
 
+#include "BKE_bvhutils.h"
 #include "BKE_cdderivedmesh.h"
 #include "BKE_customdata.h"
 #include "BKE_DerivedMesh.h"
@@ -125,6 +126,82 @@ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int n
 
 #define TRI_UVOFFSET (1./4.)
 
+
+BVHTree *bvhtree_build_from_smoke ( float mat[4][4], MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon )
+{
+       BVHTree *tree;
+       float co[12];
+       int i;
+       MFace *tface = mfaces;
+
+       // calc quads 
+       // todo
+
+       tree = BLI_bvhtree_new ( numfaces, epsilon, 2, 6 );
+
+       // fill tree
+       for ( i = 0; i < numfaces; i++, tface++ )
+       {
+               VECCOPY ( &co[0*3], x[tface->v1].co );
+               Mat4MulVecfl (mat, &co[0*3]);
+               VECCOPY ( &co[1*3], x[tface->v2].co );
+               Mat4MulVecfl (mat, &co[1*3]);
+               VECCOPY ( &co[2*3], x[tface->v3].co );
+               Mat4MulVecfl (mat, &co[2*3]);
+
+               if ( tface->v4 )
+               {
+                       VECCOPY ( &co[3*3], x[tface->v4].co );
+                       Mat4MulVecfl (mat, &co[3*3]);
+               }
+
+               BLI_bvhtree_insert ( tree, i, co, ( mfaces->v4 ? 4 : 3 ) );
+       }
+
+       // balance tree
+       BLI_bvhtree_balance ( tree );
+
+       return tree;
+}
+
+void bvhtree_update_from_smoke ( float mat[4][4], BVHTree * bvhtree, MFace *faces, int numfaces, MVert *x, int numverts)
+{
+       int i;
+       MFace *mfaces = faces;
+       float co[12];
+       int ret = 0;
+
+       if ( !bvhtree )
+               return;
+
+       if ( x )
+       {
+               for ( i = 0; i < numfaces; i++, mfaces++ )
+               {
+                       VECCOPY ( &co[0*3], x[mfaces->v1].co );
+                       Mat4MulVecfl (mat, &co[0*3]);
+                       VECCOPY ( &co[1*3], x[mfaces->v2].co );
+                       Mat4MulVecfl (mat, &co[1*3]);
+                       VECCOPY ( &co[2*3], x[mfaces->v3].co );
+                       Mat4MulVecfl (mat, &co[2*3]);
+
+                       if ( mfaces->v4 )
+                       {
+                               VECCOPY ( &co[3*3], x[mfaces->v4].co );
+                               Mat4MulVecfl (mat, &co[3*3]);
+                       }
+
+                       ret = BLI_bvhtree_update_node ( bvhtree, i, co, NULL, ( mfaces->v4 ? 4 : 3 ) );
+
+                       // check if tree is already full
+                       if ( !ret )
+                               break;
+               }
+
+               BLI_bvhtree_update_tree ( bvhtree );
+       }
+}
+
 int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
 {
        if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
@@ -134,7 +211,9 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive
                float size[3];
                MVert *verts = dm->getVertArray(dm);
                float scale = 0.0;
-               int res = smd->domain->maxres;
+               int res;                
+
+               res = smd->domain->maxres;
 
                // get BB of domain
                for(i = 0; i < dm->getNumVerts(dm); i++)
@@ -370,6 +449,11 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive
                        MEM_freeN(tridivs);
                }
 
+               if(!smd->coll->bvhtree)
+               {
+                       smd->coll->bvhtree = bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
+               }
+
        }
 
        return 0;
@@ -522,6 +606,12 @@ void smokeModifier_freeCollision(SmokeModifierData *smd)
                        smd->coll->points = NULL;
                }
 
+               if(smd->coll->bvhtree)
+               {
+                       BLI_bvhtree_free(smd->coll->bvhtree);
+                       smd->coll->bvhtree = NULL;
+               }
+
                MEM_freeN(smd->coll);
                smd->coll = NULL;
        }
@@ -574,6 +664,12 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
                                MEM_freeN(smd->coll->points);
                                smd->coll->points = NULL;
                        }
+
+                       if(smd->coll->bvhtree)
+                       {
+                               BLI_bvhtree_free(smd->coll->bvhtree);
+                               smd->coll->bvhtree = NULL;
+                       }
                }
        }
 }
@@ -608,7 +704,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->domain->coll_group = NULL;
                        smd->domain->maxres = 32;
                        smd->domain->amplify = 2;
-                       smd->domain->omega = 0.5;
+                       smd->domain->omega = 1.0;
                        smd->domain->alpha = -0.001;
                        smd->domain->beta = 0.1;
                        smd->domain->flags = 0;
@@ -650,6 +746,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->coll->smd = smd;
                        smd->coll->points = NULL;
                        smd->coll->numpoints = 0;
+                       smd->coll->bvhtree = NULL;
                }
        }
 }
@@ -657,7 +754,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
 // forward declaration
 void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big);
 
-void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
 {      
        if(scene->r.cfra >= smd->time)
                smokeModifier_init(smd, ob, scene, dm);
@@ -667,6 +764,25 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                if(scene->r.cfra > smd->time)
                {
                        // XXX TODO
+                       smd->time = scene->r.cfra;
+               }
+               else if(scene->r.cfra < smd->time)
+               {
+                       smd->time = scene->r.cfra;
+                       smokeModifier_reset(smd);
+               }
+       }
+       else if(smd->type & MOD_SMOKE_TYPE_COLL)
+       {
+               if(scene->r.cfra > smd->time)
+               {
+                       // XXX TODO
+                       smd->time = scene->r.cfra;
+                       
+                       if(smd->coll->bvhtree)
+                               bvhtree_update_from_smoke ( ob->obmat, smd->coll->bvhtree, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm));
+                       else
+                               printf("smoke coll with no bvh\n");
                }
                else if(scene->r.cfra < smd->time)
                {
@@ -674,7 +790,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                        smokeModifier_reset(smd);
                }
        }
-       else if((smd->type & MOD_SMOKE_TYPE_DOMAIN))
+       else if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
        {
                SmokeDomainSettings *sds = smd->domain;
                
@@ -777,6 +893,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                                        int cell[3];
                                                                        size_t i = 0;
                                                                        size_t index = 0;
+                                                                       int badcell = 0;
                                                                        
                                                                        if(pa->alive == PARS_KILLED) continue;
                                                                        else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
@@ -793,8 +910,14 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                                        for(i = 0; i < 3; i++)
                                                                        {
                                                                                if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))
-                                                                                       continue;
+                                                                               {
+                                                                                       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]);
@@ -921,18 +1044,31 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                        size_t i, j;
                                                        unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
 
+                                                       // int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata);
+
                                                        for(i = 0; i < scs->numpoints; i++)
                                                        {
+                                                               int badcell = 0;
+
                                                                // 1. get corresponding cell
                                                                get_cell(smd, &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))
-                                                                               continue;
-                                                               
+                                                                       {
+                                                                               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;
 
@@ -1015,7 +1151,7 @@ void smoke_prepare_View(SmokeModifierData *smd, float *light)
                                        // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
                                        // T_vox = exp(-C_ext * h)
                                        // C_ext/sigma_t = density * C_ext
-                                       smoke_set_tvox(smd, index, exp(-density[index] * 4.0 * smd->domain->dx));
+                                       smoke_set_tvox(smd, index, exp(-density[index] * 7.0 * smd->domain->dx));
        }
        smoke_calc_transparency(smd, light, 0);
 }
@@ -1047,7 +1183,7 @@ void smoke_prepare_bigView(SmokeModifierData *smd, float *light)
                // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
                // T_vox = exp(-C_ext * h)
                // C_ext/sigma_t = density * C_ext
-               smoke_set_bigtvox(smd, i, exp(-density[i] * 4.0 * smd->domain->dx / smd->domain->amplify) );
+               smoke_set_bigtvox(smd, i, exp(-density[i] * 7.0 * smd->domain->dx / smd->domain->amplify) );
        }
        smoke_calc_transparency(smd, light, 1);
 }