Blender V2.61 - r43446

smoke.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Daniel Genrich
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
00034 
00035 #include <GL/glew.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include <float.h>
00040 #include <math.h>
00041 #include <stdio.h>
00042 #include <string.h> /* memset */
00043 
00044 #include "BLI_linklist.h"
00045 #include "BLI_rand.h"
00046 #include "BLI_jitter.h"
00047 #include "BLI_blenlib.h"
00048 #include "BLI_math.h"
00049 #include "BLI_edgehash.h"
00050 #include "BLI_kdtree.h"
00051 #include "BLI_kdopbvh.h"
00052 #include "BLI_utildefines.h"
00053 
00054 #include "BKE_bvhutils.h"
00055 #include "BKE_cdderivedmesh.h"
00056 #include "BKE_customdata.h"
00057 #include "BKE_DerivedMesh.h"
00058 #include "BKE_effect.h"
00059 #include "BKE_modifier.h"
00060 #include "BKE_particle.h"
00061 #include "BKE_pointcache.h"
00062 #include "BKE_smoke.h"
00063 
00064 
00065 #include "DNA_customdata_types.h"
00066 #include "DNA_group_types.h"
00067 #include "DNA_lamp_types.h"
00068 #include "DNA_mesh_types.h"
00069 #include "DNA_meshdata_types.h"
00070 #include "DNA_modifier_types.h"
00071 #include "DNA_object_types.h"
00072 #include "DNA_particle_types.h"
00073 #include "DNA_scene_types.h"
00074 #include "DNA_smoke_types.h"
00075 
00076 #include "smoke_API.h"
00077 
00078 #include "BKE_smoke.h"
00079 
00080 #ifdef WITH_SMOKE
00081 
00082 #ifdef _WIN32
00083 #include <time.h>
00084 #include <stdio.h>
00085 #include <conio.h>
00086 #include <windows.h>
00087 
00088 static LARGE_INTEGER liFrequency;
00089 static LARGE_INTEGER liStartTime;
00090 static LARGE_INTEGER liCurrentTime;
00091 
00092 static void tstart ( void )
00093 {
00094     QueryPerformanceFrequency ( &liFrequency );
00095     QueryPerformanceCounter ( &liStartTime );
00096 }
00097 static void tend ( void )
00098 {
00099     QueryPerformanceCounter ( &liCurrentTime );
00100 }
00101 static double tval( void )
00102 {
00103     return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
00104 }
00105 #else
00106 #include <sys/time.h>
00107 static struct timeval _tstart, _tend;
00108 static struct timezone tz;
00109 static void tstart ( void )
00110 {
00111     gettimeofday ( &_tstart, &tz );
00112 }
00113 static void tend ( void )
00114 {
00115     gettimeofday ( &_tend,&tz );
00116 }
00117 
00118 #if 0 // unused
00119 static double tval()
00120 {
00121     double t1, t2;
00122     t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
00123     t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
00124     return t2-t1;
00125 }
00126 #endif
00127 #endif
00128 
00129 struct Object;
00130 struct Scene;
00131 struct DerivedMesh;
00132 struct SmokeModifierData;
00133 
00134 #define TRI_UVOFFSET (1./4.)
00135 
00136 /* forward declerations */
00137 static void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
00138 static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct);
00139 static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs);
00140 
00141 #else /* WITH_SMOKE */
00142 
00143 /* Stubs to use when smoke is disabled */
00144 struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; }
00145 struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; }
00146 void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
00147 void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {}
00148 void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {}
00149 void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli)) {}
00150 long long smoke_get_mem_req(int UNUSED(xres), int UNUSED(yres), int UNUSED(zres), int UNUSED(amplify)) { return 0; }
00151 void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) {}
00152 
00153 #endif /* WITH_SMOKE */
00154 
00155 #ifdef WITH_SMOKE
00156 
00157 static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
00158 {
00159     if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
00160     {
00161         size_t i;
00162         float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
00163         float size[3];
00164         MVert *verts = dm->getVertArray(dm);
00165         float scale = 0.0;
00166         int res;        
00167 
00168         res = smd->domain->maxres;
00169 
00170         // get BB of domain
00171         for(i = 0; i < dm->getNumVerts(dm); i++)
00172         {
00173             float tmp[3];
00174 
00175             copy_v3_v3(tmp, verts[i].co);
00176             mul_m4_v3(ob->obmat, tmp);
00177 
00178             // min BB
00179             min[0] = MIN2(min[0], tmp[0]);
00180             min[1] = MIN2(min[1], tmp[1]);
00181             min[2] = MIN2(min[2], tmp[2]);
00182 
00183             // max BB
00184             max[0] = MAX2(max[0], tmp[0]);
00185             max[1] = MAX2(max[1], tmp[1]);
00186             max[2] = MAX2(max[2], tmp[2]);
00187         }
00188 
00189         copy_v3_v3(smd->domain->p0, min);
00190         copy_v3_v3(smd->domain->p1, max);
00191 
00192         // calc other res with max_res provided
00193         sub_v3_v3v3(size, max, min);
00194 
00195         // printf("size: %f, %f, %f\n", size[0], size[1], size[2]);
00196 
00197         // prevent crash when initializing a plane as domain
00198         if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
00199             return 0;
00200 
00201         if(size[0] > size[1])
00202         {
00203             if(size[0] > size[2])
00204             {
00205                 scale = res / size[0];
00206                 smd->domain->dx = size[0] / res;
00207                 smd->domain->res[0] = res;
00208                 smd->domain->res[1] = (int)(size[1] * scale + 0.5);
00209                 smd->domain->res[2] = (int)(size[2] * scale + 0.5);
00210             }
00211             else
00212             {
00213                 scale = res / size[2];
00214                 smd->domain->dx = size[2] / res;
00215                 smd->domain->res[2] = res;
00216                 smd->domain->res[0] = (int)(size[0] * scale + 0.5);
00217                 smd->domain->res[1] = (int)(size[1] * scale + 0.5);
00218             }
00219         }
00220         else
00221         {
00222             if(size[1] > size[2])
00223             {
00224                 scale = res / size[1];
00225                 smd->domain->dx = size[1] / res;
00226                 smd->domain->res[1] = res;
00227                 smd->domain->res[0] = (int)(size[0] * scale + 0.5);
00228                 smd->domain->res[2] = (int)(size[2] * scale + 0.5);
00229             }
00230             else
00231             {
00232                 scale = res / size[2];
00233                 smd->domain->dx = size[2] / res;
00234                 smd->domain->res[2] = res;
00235                 smd->domain->res[0] = (int)(size[0] * scale + 0.5);
00236                 smd->domain->res[1] = (int)(size[1] * scale + 0.5);
00237             }
00238         }
00239 
00240         // printf("smd->domain->dx: %f\n", smd->domain->dx);
00241 
00242         // TODO: put in failsafe if res<=0 - dg
00243 
00244         // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
00245         // dt max is 0.1
00246         smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0);
00247         smd->time = scene->r.cfra;
00248 
00249         if(smd->domain->flags & MOD_SMOKE_HIGHRES)
00250         {
00251             smd->domain->wt = smoke_turbulence_init(smd->domain->res, smd->domain->amplify + 1, smd->domain->noise);
00252             smd->domain->res_wt[0] = smd->domain->res[0] * (smd->domain->amplify + 1);
00253             smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1);          
00254             smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1);          
00255             smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1);      
00256             // printf("smd->domain->amplify: %d\n",  smd->domain->amplify);
00257             // printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n");
00258         }
00259 
00260         if(!smd->domain->shadow)
00261             smd->domain->shadow = MEM_callocN(sizeof(float) * smd->domain->res[0] * smd->domain->res[1] * smd->domain->res[2], "SmokeDomainShadow");
00262 
00263         smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta), &(smd->domain->time_scale), &(smd->domain->vorticity), &(smd->domain->border_collisions));
00264 
00265         if(smd->domain->wt) 
00266         {
00267             smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength));
00268             // printf("smoke_initWaveletBlenderRNA\n");
00269         }
00270         return 1;
00271     }
00272     else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
00273     {
00274         // handle flow object here
00275         // XXX TODO
00276 
00277         smd->time = scene->r.cfra;
00278 
00279         // update particle lifetime to be one frame
00280         // smd->flow->psys->part->lifetime = scene->r.efra + 1;
00281 /*
00282         if(!smd->flow->bvh)
00283         {
00284             // smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces");
00285             // bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6);
00286 
00287             // copy obmat
00288             // copy_m4_m4(smd->flow->mat, ob->obmat);
00289             // copy_m4_m4(smd->flow->mat_old, ob->obmat);
00290         }
00291 */
00292 
00293         return 1;
00294     }
00295     else if((smd->type & MOD_SMOKE_TYPE_COLL))
00296     {
00297         smd->time = scene->r.cfra;
00298 
00299         // todo: delete this when loading colls work -dg
00300         if(!smd->coll)
00301             smokeModifier_createType(smd);
00302 
00303         if(!smd->coll->points)
00304         {
00305             // init collision points
00306             SmokeCollSettings *scs = smd->coll;
00307 
00308             // copy obmat
00309             copy_m4_m4(scs->mat, ob->obmat);
00310             copy_m4_m4(scs->mat_old, ob->obmat);
00311 
00312             fill_scs_points(ob, dm, scs);
00313         }
00314 
00315         if(!smd->coll->bvhtree)
00316         {
00317             smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
00318         }
00319         return 1;
00320     }
00321 
00322     return 2;
00323 }
00324 
00325 static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
00326 {
00327     MVert *mvert = dm->getVertArray(dm);
00328     MFace *mface = dm->getFaceArray(dm);
00329     int i = 0, divs = 0;
00330     int *tridivs = NULL;
00331     float cell_len = 1.0 / 50.0; // for res = 50
00332     int newdivs = 0;
00333     int quads = 0, facecounter = 0;
00334 
00335     // count quads
00336     for(i = 0; i < dm->getNumFaces(dm); i++)
00337     {
00338         if(mface[i].v4)
00339             quads++;
00340     }
00341 
00342     calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface,  dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
00343 
00344     // count triangle divisions
00345     for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
00346     {
00347         divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
00348     }
00349 
00350     // printf("divs: %d\n", divs);
00351 
00352     scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
00353 
00354     for(i = 0; i < dm->getNumVerts(dm); i++)
00355     {
00356         float tmpvec[3];
00357         copy_v3_v3(tmpvec, mvert[i].co);
00358         mul_m4_v3(ob->obmat, tmpvec);
00359         copy_v3_v3(&scs->points[i * 3], tmpvec);
00360     }
00361     
00362     for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
00363     {
00364         int again = 0;
00365         do
00366         {
00367             int j, k;
00368             int divs1 = tridivs[3 * facecounter + 0];
00369             int divs2 = tridivs[3 * facecounter + 1];
00370             //int divs3 = tridivs[3 * facecounter + 2];
00371             float side1[3], side2[3], trinormorg[3], trinorm[3];
00372             
00373             if(again == 1 && mface[i].v4)
00374             {
00375                 sub_v3_v3v3(side1,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
00376                 sub_v3_v3v3(side2,  mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
00377             }
00378             else
00379             {
00380                 sub_v3_v3v3(side1,  mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
00381                 sub_v3_v3v3(side2,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
00382             }
00383 
00384             cross_v3_v3v3(trinormorg, side1, side2);
00385             normalize_v3(trinormorg);
00386             copy_v3_v3(trinorm, trinormorg);
00387             mul_v3_fl(trinorm, 0.25 * cell_len);
00388 
00389             for(j = 0; j <= divs1; j++)
00390             {
00391                 for(k = 0; k <= divs2; k++)
00392                 {
00393                     float p1[3], p2[3], p3[3], p[3]={0,0,0}; 
00394                     const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
00395                     const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
00396                     float tmpvec[3];
00397                     
00398                     if(uf+vf > 1.0) 
00399                     {
00400                         // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
00401                         continue;
00402                     }
00403 
00404                     copy_v3_v3(p1, mvert[ mface[i].v1 ].co);
00405                     if(again == 1 && mface[i].v4)
00406                     {
00407                         copy_v3_v3(p2, mvert[ mface[i].v3 ].co);
00408                         copy_v3_v3(p3, mvert[ mface[i].v4 ].co);
00409                     }
00410                     else
00411                     {
00412                         copy_v3_v3(p2, mvert[ mface[i].v2 ].co);
00413                         copy_v3_v3(p3, mvert[ mface[i].v3 ].co);
00414                     }
00415 
00416                     mul_v3_fl(p1, (1.0-uf-vf));
00417                     mul_v3_fl(p2, uf);
00418                     mul_v3_fl(p3, vf);
00419                     
00420                     add_v3_v3v3(p, p1, p2);
00421                     add_v3_v3(p, p3);
00422 
00423                     if(newdivs > divs)
00424                         printf("mem problem\n");
00425 
00426                     // mMovPoints.push_back(p + trinorm);
00427                     add_v3_v3v3(tmpvec, p, trinorm);
00428                     mul_m4_v3(ob->obmat, tmpvec);
00429                     copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
00430                     newdivs++;
00431 
00432                     if(newdivs > divs)
00433                         printf("mem problem\n");
00434 
00435                     // mMovPoints.push_back(p - trinorm);
00436                     copy_v3_v3(tmpvec, p);
00437                     sub_v3_v3(tmpvec, trinorm);
00438                     mul_m4_v3(ob->obmat, tmpvec);
00439                     copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
00440                     newdivs++;
00441                 }
00442             }
00443 
00444             if(again == 0 && mface[i].v4)
00445                 again++;
00446             else
00447                 again = 0;
00448 
00449             facecounter++;
00450 
00451         } while(again!=0);
00452     }
00453 
00454     scs->numpoints = dm->getNumVerts(dm) + newdivs;
00455 
00456     MEM_freeN(tridivs);
00457 }
00458 
00460 static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len)
00461 {
00462     // mTriangleDivs1.resize( faces.size() );
00463     // mTriangleDivs2.resize( faces.size() );
00464     // mTriangleDivs3.resize( faces.size() );
00465 
00466     size_t i = 0, facecounter = 0;
00467     float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale);
00468     float maxpart = ABS(maxscale[0]);
00469     float scaleFac = 0;
00470     float fsTri = 0;
00471     if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
00472     if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
00473     scaleFac = 1.0 / maxpart;
00474     // featureSize = mLevel[mMaxRefine].nodeSize
00475     fsTri = cell_len * 0.5 * scaleFac;
00476 
00477     if(*tridivs)
00478         MEM_freeN(*tridivs);
00479 
00480     *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
00481 
00482     for(i = 0, facecounter = 0; i < numfaces; i++) 
00483     {
00484         float p0[3], p1[3], p2[3];
00485         float side1[3];
00486         float side2[3];
00487         float side3[3];
00488         int divs1=0, divs2=0, divs3=0;
00489 
00490         copy_v3_v3(p0, verts[faces[i].v1].co);
00491         mul_m4_v3(ob->obmat, p0);
00492         copy_v3_v3(p1, verts[faces[i].v2].co);
00493         mul_m4_v3(ob->obmat, p1);
00494         copy_v3_v3(p2, verts[faces[i].v3].co);
00495         mul_m4_v3(ob->obmat, p2);
00496 
00497         sub_v3_v3v3(side1, p1, p0);
00498         sub_v3_v3v3(side2, p2, p0);
00499         sub_v3_v3v3(side3, p1, p2);
00500 
00501         if(dot_v3v3(side1, side1) > fsTri*fsTri)
00502         { 
00503             float tmp = normalize_v3(side1);
00504             divs1 = (int)ceil(tmp/fsTri); 
00505         }
00506         if(dot_v3v3(side2, side2) > fsTri*fsTri)
00507         { 
00508             float tmp = normalize_v3(side2);
00509             divs2 = (int)ceil(tmp/fsTri); 
00510             
00511             /*
00512             // debug
00513             if(i==0)
00514                 printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
00515             */
00516         }
00517 
00518         (*tridivs)[3 * facecounter + 0] = divs1;
00519         (*tridivs)[3 * facecounter + 1] = divs2;
00520         (*tridivs)[3 * facecounter + 2] = divs3;
00521 
00522         // TODO quad case
00523         if(faces[i].v4)
00524         {
00525             divs1=0, divs2=0, divs3=0;
00526 
00527             facecounter++;
00528             
00529             copy_v3_v3(p0, verts[faces[i].v3].co);
00530             mul_m4_v3(ob->obmat, p0);
00531             copy_v3_v3(p1, verts[faces[i].v4].co);
00532             mul_m4_v3(ob->obmat, p1);
00533             copy_v3_v3(p2, verts[faces[i].v1].co);
00534             mul_m4_v3(ob->obmat, p2);
00535 
00536             sub_v3_v3v3(side1, p1, p0);
00537             sub_v3_v3v3(side2, p2, p0);
00538             sub_v3_v3v3(side3, p1, p2);
00539 
00540             if(dot_v3v3(side1, side1) > fsTri*fsTri)
00541             { 
00542                 float tmp = normalize_v3(side1);
00543                 divs1 = (int)ceil(tmp/fsTri); 
00544             }
00545             if(dot_v3v3(side2, side2) > fsTri*fsTri)
00546             { 
00547                 float tmp = normalize_v3(side2);
00548                 divs2 = (int)ceil(tmp/fsTri); 
00549             }
00550 
00551             (*tridivs)[3 * facecounter + 0] = divs1;
00552             (*tridivs)[3 * facecounter + 1] = divs2;
00553             (*tridivs)[3 * facecounter + 2] = divs3;
00554         }
00555         facecounter++;
00556     }
00557 }
00558 
00559 #endif /* WITH_SMOKE */
00560 
00561 static void smokeModifier_freeDomain(SmokeModifierData *smd)
00562 {
00563     if(smd->domain)
00564     {
00565         if(smd->domain->shadow)
00566                 MEM_freeN(smd->domain->shadow);
00567             smd->domain->shadow = NULL;
00568 
00569         if(smd->domain->fluid)
00570             smoke_free(smd->domain->fluid);
00571 
00572         if(smd->domain->wt)
00573             smoke_turbulence_free(smd->domain->wt);
00574 
00575         if(smd->domain->effector_weights)
00576                 MEM_freeN(smd->domain->effector_weights);
00577         smd->domain->effector_weights = NULL;
00578 
00579         BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
00580         smd->domain->point_cache[0] = NULL;
00581 
00582         MEM_freeN(smd->domain);
00583         smd->domain = NULL;
00584     }
00585 }
00586 
00587 static void smokeModifier_freeFlow(SmokeModifierData *smd)
00588 {
00589     if(smd->flow)
00590     {
00591 /*
00592         if(smd->flow->bvh)
00593         {
00594             free_bvhtree_from_mesh(smd->flow->bvh);
00595             MEM_freeN(smd->flow->bvh);
00596         }
00597         smd->flow->bvh = NULL;
00598 */
00599         MEM_freeN(smd->flow);
00600         smd->flow = NULL;
00601     }
00602 }
00603 
00604 static void smokeModifier_freeCollision(SmokeModifierData *smd)
00605 {
00606     if(smd->coll)
00607     {
00608         if(smd->coll->points)
00609         {
00610             MEM_freeN(smd->coll->points);
00611             smd->coll->points = NULL;
00612         }
00613 
00614         if(smd->coll->bvhtree)
00615         {
00616             BLI_bvhtree_free(smd->coll->bvhtree);
00617             smd->coll->bvhtree = NULL;
00618         }
00619 
00620         if(smd->coll->dm)
00621             smd->coll->dm->release(smd->coll->dm);
00622         smd->coll->dm = NULL;
00623 
00624         MEM_freeN(smd->coll);
00625         smd->coll = NULL;
00626     }
00627 }
00628 
00629 void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
00630 {
00631     if(smd && smd->domain && smd->domain->wt)
00632     {
00633         smoke_turbulence_free(smd->domain->wt);
00634         smd->domain->wt = NULL;
00635     }
00636 }
00637 
00638 void smokeModifier_reset(struct SmokeModifierData *smd)
00639 {
00640     if(smd)
00641     {
00642         if(smd->domain)
00643         {
00644             if(smd->domain->shadow)
00645                 MEM_freeN(smd->domain->shadow);
00646             smd->domain->shadow = NULL;
00647 
00648             if(smd->domain->fluid)
00649             {
00650                 smoke_free(smd->domain->fluid);
00651                 smd->domain->fluid = NULL;
00652             }
00653 
00654             smokeModifier_reset_turbulence(smd);
00655 
00656             smd->time = -1;
00657 
00658             // printf("reset domain end\n");
00659         }
00660         else if(smd->flow)
00661         {
00662             /*
00663             if(smd->flow->bvh)
00664             {
00665                 free_bvhtree_from_mesh(smd->flow->bvh);
00666                 MEM_freeN(smd->flow->bvh);
00667             }
00668             smd->flow->bvh = NULL;
00669             */
00670         }
00671         else if(smd->coll)
00672         {
00673             if(smd->coll->points)
00674             {
00675                 MEM_freeN(smd->coll->points);
00676                 smd->coll->points = NULL;
00677             }
00678 
00679             if(smd->coll->bvhtree)
00680             {
00681                 BLI_bvhtree_free(smd->coll->bvhtree);
00682                 smd->coll->bvhtree = NULL;
00683             }
00684 
00685             if(smd->coll->dm)
00686                 smd->coll->dm->release(smd->coll->dm);
00687             smd->coll->dm = NULL;
00688 
00689         }
00690     }
00691 }
00692 
00693 void smokeModifier_free (SmokeModifierData *smd)
00694 {
00695     if(smd)
00696     {
00697         smokeModifier_freeDomain(smd);
00698         smokeModifier_freeFlow(smd);
00699         smokeModifier_freeCollision(smd);
00700     }
00701 }
00702 
00703 void smokeModifier_createType(struct SmokeModifierData *smd)
00704 {
00705     if(smd)
00706     {
00707         if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
00708         {
00709             if(smd->domain)
00710                 smokeModifier_freeDomain(smd);
00711 
00712             smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
00713 
00714             smd->domain->smd = smd;
00715 
00716             smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
00717             smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
00718             smd->domain->point_cache[0]->step = 1;
00719 
00720             /* Deprecated */
00721             smd->domain->point_cache[1] = NULL;
00722             smd->domain->ptcaches[1].first = smd->domain->ptcaches[1].last = NULL;
00723             /* set some standard values */
00724             smd->domain->fluid = NULL;
00725             smd->domain->wt = NULL;         
00726             smd->domain->eff_group = NULL;
00727             smd->domain->fluid_group = NULL;
00728             smd->domain->coll_group = NULL;
00729             smd->domain->maxres = 32;
00730             smd->domain->amplify = 1;           
00731             smd->domain->omega = 1.0;           
00732             smd->domain->alpha = -0.001;
00733             smd->domain->beta = 0.1;
00734             smd->domain->time_scale = 1.0;
00735             smd->domain->vorticity = 2.0;
00736             smd->domain->border_collisions = 1;     // vertically non-colliding
00737             smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG | MOD_SMOKE_HIGH_SMOOTH;
00738             smd->domain->strength = 2.0;
00739             smd->domain->noise = MOD_SMOKE_NOISEWAVE;
00740             smd->domain->diss_speed = 5;
00741             // init 3dview buffer
00742 
00743             smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
00744             smd->domain->effector_weights = BKE_add_effector_weights(NULL);
00745         }
00746         else if(smd->type & MOD_SMOKE_TYPE_FLOW)
00747         {
00748             if(smd->flow)
00749                 smokeModifier_freeFlow(smd);
00750 
00751             smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
00752 
00753             smd->flow->smd = smd;
00754 
00755             /* set some standard values */
00756             smd->flow->density = 1.0;
00757             smd->flow->temp = 1.0;
00758             smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE;
00759             smd->flow->vel_multi = 1.0;
00760 
00761             smd->flow->psys = NULL;
00762 
00763         }
00764         else if(smd->type & MOD_SMOKE_TYPE_COLL)
00765         {
00766             if(smd->coll)
00767                 smokeModifier_freeCollision(smd);
00768 
00769             smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
00770 
00771             smd->coll->smd = smd;
00772             smd->coll->points = NULL;
00773             smd->coll->numpoints = 0;
00774             smd->coll->bvhtree = NULL;
00775             smd->coll->dm = NULL;
00776         }
00777     }
00778 }
00779 
00780 void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd)
00781 {
00782     tsmd->type = smd->type;
00783     tsmd->time = smd->time;
00784     
00785     smokeModifier_createType(tsmd);
00786 
00787     if (tsmd->domain) {
00788         tsmd->domain->maxres = smd->domain->maxres;
00789         tsmd->domain->amplify = smd->domain->amplify;
00790         tsmd->domain->omega = smd->domain->omega;
00791         tsmd->domain->alpha = smd->domain->alpha;
00792         tsmd->domain->beta = smd->domain->beta;
00793         tsmd->domain->flags = smd->domain->flags;
00794         tsmd->domain->strength = smd->domain->strength;
00795         tsmd->domain->noise = smd->domain->noise;
00796         tsmd->domain->diss_speed = smd->domain->diss_speed;
00797         tsmd->domain->viewsettings = smd->domain->viewsettings;
00798         tsmd->domain->fluid_group = smd->domain->fluid_group;
00799         tsmd->domain->coll_group = smd->domain->coll_group;
00800         tsmd->domain->vorticity = smd->domain->vorticity;
00801         tsmd->domain->time_scale = smd->domain->time_scale;
00802         tsmd->domain->border_collisions = smd->domain->border_collisions;
00803         
00804         MEM_freeN(tsmd->domain->effector_weights);
00805         tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
00806     } else if (tsmd->flow) {
00807         tsmd->flow->density = smd->flow->density;
00808         tsmd->flow->temp = smd->flow->temp;
00809         tsmd->flow->psys = smd->flow->psys;
00810         tsmd->flow->type = smd->flow->type;
00811         tsmd->flow->flags = smd->flow->flags;
00812         tsmd->flow->vel_multi = smd->flow->vel_multi;
00813     } else if (tsmd->coll) {
00814         ;
00815         /* leave it as initialised, collision settings is mostly caches */
00816     }
00817 }
00818 
00819 #ifdef WITH_SMOKE
00820 
00821 // forward decleration
00822 static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct);
00823 static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
00824 
00825 static int get_lamp(Scene *scene, float *light)
00826 {   
00827     Base *base_tmp = NULL;  
00828     int found_lamp = 0;
00829 
00830     // try to find a lamp, preferably local
00831     for(base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next) {
00832         if(base_tmp->object->type == OB_LAMP) {
00833             Lamp *la = base_tmp->object->data;
00834 
00835             if(la->type == LA_LOCAL) {
00836                 copy_v3_v3(light, base_tmp->object->obmat[3]);
00837                 return 1;
00838             }
00839             else if(!found_lamp) {
00840                 copy_v3_v3(light, base_tmp->object->obmat[3]);
00841                 found_lamp = 1;
00842             }
00843         }
00844     }
00845 
00846     return found_lamp;
00847 }
00848 
00849 static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
00850 {
00851     SmokeDomainSettings *sds = smd->domain;
00852     GroupObject *go = NULL;         
00853     Base *base = NULL;  
00854 
00855     // do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells
00856     if(1)
00857     {
00858         Object *otherobj = NULL;
00859         ModifierData *md = NULL;
00860 
00861         if(sds->coll_group) // we use groups since we have 2 domains
00862             go = sds->coll_group->gobject.first;
00863         else
00864             base = scene->base.first;
00865 
00866         while(base || go)
00867         {
00868             otherobj = NULL;
00869             if(sds->coll_group) 
00870             {                       
00871                 if(go->ob)                          
00872                     otherobj = go->ob;                  
00873             }                   
00874             else                        
00875                 otherobj = base->object;                    
00876             if(!otherobj)                   
00877             {                       
00878                 if(sds->coll_group)                         
00879                     go = go->next;                      
00880                 else                            
00881                     base= base->next;                       
00882                 continue;                   
00883             }           
00884             md = modifiers_findByType(otherobj, eModifierType_Smoke);
00885             
00886             // check for active smoke modifier
00887             if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))                    
00888             {
00889                 SmokeModifierData *smd2 = (SmokeModifierData *)md;
00890 
00891                 if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points)
00892                 {
00893                     // we got nice collision object
00894                     SmokeCollSettings *scs = smd2->coll;
00895                     size_t i, j;
00896                     unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
00897 
00898                     for(i = 0; i < scs->numpoints; i++)
00899                     {
00900                         int badcell = 0;
00901                         size_t index = 0;
00902                         int cell[3];
00903 
00904                         // 1. get corresponding cell
00905                         get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, &scs->points[3 * i], cell, 0);
00906                     
00907                         // check if cell is valid (in the domain boundary)
00908                         for(j = 0; j < 3; j++)
00909                             if((cell[j] > sds->res[j] - 1) || (cell[j] < 0))
00910                             {
00911                                 badcell = 1;
00912                                 break;
00913                             }
00914                                                                 
00915                             if(badcell)                                 
00916                                 continue;
00917                         // 2. set cell values (heat, density and velocity)
00918                         index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
00919                                                         
00920                         // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]);                                
00921                         // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index);                                                                   
00922                         obstacles[index] = 1;
00923                         // for moving gobstacles                                
00924                         /*
00925                         const LbmFloat maxVelVal = 0.1666;
00926                         const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
00927 
00928                         LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); 
00929                         {                               
00930                         const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5;                                
00931                         USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz);                                 
00932                         if(usqr>maxusqr) {                                  
00933                         // cutoff at maxVelVal                                  
00934                         for(int jj=0; jj<3; jj++) {                                         
00935                         if(objvel[jj]>0.) objvel[jj] =  maxVelVal;                                          
00936                         if(objvel[jj]<0.) objvel[jj] = -maxVelVal;                                  
00937                         }                               
00938                         } 
00939                         }                               
00940                         const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) );                              
00941                         const LbmVec oldov=objvel; // debug                             
00942                         objvel = vec2L((*pNormals)[n]) *dp;                             
00943                         */
00944                     }
00945                 }
00946             }
00947 
00948             if(sds->coll_group)
00949                 go = go->next;
00950             else
00951                 base= base->next;
00952         }
00953     }
00954 
00955     // do flows and fluids
00956     if(1)           
00957     {
00958         Object *otherobj = NULL;                
00959         ModifierData *md = NULL;
00960         if(sds->fluid_group) // we use groups since we have 2 domains
00961             go = sds->fluid_group->gobject.first;               
00962         else                    
00963             base = scene->base.first;
00964         while(base || go)
00965         {                   
00966             otherobj = NULL;
00967             if(sds->fluid_group) 
00968             {
00969                 if(go->ob)                          
00970                     otherobj = go->ob;                  
00971             }                   
00972             else                        
00973                 otherobj = base->object;
00974             if(!otherobj)
00975             {
00976                 if(sds->fluid_group)
00977                     go = go->next;
00978                 else
00979                     base= base->next;
00980 
00981                 continue;
00982             }
00983 
00984             md = modifiers_findByType(otherobj, eModifierType_Smoke);
00985             
00986             // check for active smoke modifier
00987             if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
00988             {
00989                 SmokeModifierData *smd2 = (SmokeModifierData *)md;
00990                 
00991                 // check for initialized smoke object
00992                 if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)                        
00993                 {
00994                     // we got nice flow object
00995                     SmokeFlowSettings *sfs = smd2->flow;
00996                     
00997                     if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
00998                     {
00999                         ParticleSimulationData sim;
01000                         ParticleSystem *psys = sfs->psys;
01001                         int p = 0;                              
01002                         float *density = smoke_get_density(sds->fluid);                             
01003                         float *bigdensity = smoke_turbulence_get_density(sds->wt);                              
01004                         float *heat = smoke_get_heat(sds->fluid);                               
01005                         float *velocity_x = smoke_get_velocity_x(sds->fluid);                               
01006                         float *velocity_y = smoke_get_velocity_y(sds->fluid);                               
01007                         float *velocity_z = smoke_get_velocity_z(sds->fluid);                               
01008                         unsigned char *obstacle = smoke_get_obstacle(sds->fluid);                               
01009                         int bigres[3];
01010                         short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
01011                         short high_emission_smoothing = bigdensity ? (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) : 0;
01012 
01013                         /*
01014                         * A temporary volume map used to store whole emissive
01015                         * area to be added to smoke density and interpolated
01016                         * for high resolution smoke.
01017                         */
01018                         float *temp_emission_map = NULL;
01019 
01020                         sim.scene = scene;
01021                         sim.ob = otherobj;
01022                         sim.psys = psys;
01023 
01024                         // initialize temp emission map
01025                         if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW))
01026                         {
01027                             int i;
01028                             temp_emission_map = MEM_callocN(sizeof(float) * sds->res[0]*sds->res[1]*sds->res[2], "SmokeTempEmission");
01029                             // set whole volume to 0.0f
01030                             for (i=0; i<sds->res[0]*sds->res[1]*sds->res[2]; i++) {
01031                                 temp_emission_map[i] = 0.0f;
01032                             }
01033                         }
01034                                                         
01035                         // mostly copied from particle code                             
01036                         for(p=0; p<psys->totpart; p++)                              
01037                         {
01038                             int cell[3];
01039                             size_t i = 0;
01040                             size_t index = 0;
01041                             int badcell = 0;
01042                             ParticleKey state;
01043 
01044                             if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
01045                                 continue;
01046 
01047                             state.time = smd->time;
01048 
01049                             if(psys_get_particle_state(&sim, p, &state, 0) == 0)
01050                                 continue;
01051                             
01052                             // copy_v3_v3(pos, pa->state.co);
01053                             // mul_m4_v3(ob->imat, pos);                                                                        
01054                             // 1. get corresponding cell    
01055                             get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, state.co, cell, 0);                                                                    
01056                             // check if cell is valid (in the domain boundary)                                  
01057                             for(i = 0; i < 3; i++)                                  
01058                             {                                       
01059                                 if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))                                        
01060                                 {                                           
01061                                     badcell = 1;                                            
01062                                     break;                                      
01063                                 }                                   
01064                             }                                                                           
01065                             if(badcell)                                     
01066                                 continue;                                                                       
01067                             // 2. set cell values (heat, density and velocity)                                  
01068                             index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);                                                                       
01069                             if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index])) // this is inflow
01070                             {                                       
01071                                 // heat[index] += sfs->temp * 0.1;                                      
01072                                 // density[index] += sfs->density * 0.1;
01073                                 heat[index] = sfs->temp;
01074                                 
01075                                 // Add emitter density to temp emission map
01076                                 temp_emission_map[index] = sfs->density;
01077 
01078                                 // Uses particle velocity as initial velocity for smoke
01079                                 if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
01080                                 {
01081                                     velocity_x[index] = state.vel[0]*sfs->vel_multi;
01082                                     velocity_y[index] = state.vel[1]*sfs->vel_multi;
01083                                     velocity_z[index] = state.vel[2]*sfs->vel_multi;
01084                                 }                                       
01085                             }                                   
01086                             else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow                                 
01087                             {                                       
01088                                 heat[index] = 0.f;                                      
01089                                 density[index] = 0.f;                                       
01090                                 velocity_x[index] = 0.f;                                        
01091                                 velocity_y[index] = 0.f;                                        
01092                                 velocity_z[index] = 0.f;
01093                                 // we need different handling for the high-res feature
01094                                 if(bigdensity)
01095                                 {
01096                                     // init all surrounding cells according to amplification, too                                           
01097                                     int i, j, k;
01098                                     smoke_turbulence_get_res(smd->domain->wt, bigres);
01099 
01100                                     for(i = 0; i < smd->domain->amplify + 1; i++)
01101                                         for(j = 0; j < smd->domain->amplify + 1; j++)
01102                                             for(k = 0; k < smd->domain->amplify + 1; k++)
01103                                             {                                                       
01104                                                 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);                                                       
01105                                                 bigdensity[index] = 0.f;                                                    
01106                                             }                                       
01107                                 }
01108                             }
01109                             }   // particles loop
01110 
01111 
01112                             // apply emission values
01113                             if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) {
01114 
01115                                 // initialize variables
01116                                 int ii, jj, kk, x, y, z, block_size;
01117                                 size_t index, index_big;
01118 
01119                                 smoke_turbulence_get_res(smd->domain->wt, bigres);
01120                                 block_size = smd->domain->amplify + 1;  // high res block size
01121 
01122 
01123                                     // loop through every low res cell
01124                                     for(x = 0; x < sds->res[0]; x++)
01125                                         for(y = 0; y < sds->res[1]; y++)
01126                                             for(z = 0; z < sds->res[2]; z++)                                                    
01127                                             {
01128 
01129                                                 // neighbour cell emission densities (for high resolution smoke smooth interpolation)
01130                                                 float c000, c001, c010, c011,  c100, c101, c110, c111;
01131 
01132                                                 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;
01133                                                 c001 = (x>0 && y>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z)] : 0;
01134                                                 c010 = (x>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z-1)] : 0;
01135                                                 c011 = (x>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z)] : 0;
01136 
01137                                                 c100 = (y>0 && z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z-1)] : 0;
01138                                                 c101 = (y>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z)] : 0;
01139                                                 c110 = (z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z-1)] : 0;
01140                                                 c111 = temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z)];           // this cell
01141 
01142 
01143 
01144                                                 // get cell index
01145                                                 index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
01146 
01147                                                 // add emission to low resolution density
01148                                                 if (absolute_flow) {if (temp_emission_map[index]>0) density[index] = temp_emission_map[index];}
01149                                                 else {
01150                                                     density[index] += temp_emission_map[index];
01151                                                     if (density[index]>1) density[index]=1.0f;
01152                                                 }
01153 
01154                                                 smoke_turbulence_get_res(smd->domain->wt, bigres);
01155 
01156 
01157 
01158                                                 /*
01159                                                 loop through high res blocks if high res enabled
01160                                                 */
01161                                                 if (bigdensity)
01162                                                 for(ii = 0; ii < block_size; ii++)
01163                                                     for(jj = 0; jj < block_size; jj++)
01164                                                         for(kk = 0; kk < block_size; kk++)                                                  
01165                                                         {
01166 
01167                                                         float fx,fy,fz, interpolated_value;
01168                                                         int shift_x, shift_y, shift_z;
01169 
01170 
01171                                                         /*
01172                                                         * Do volume interpolation if emitter smoothing
01173                                                         * is enabled
01174                                                         */
01175                                                         if (high_emission_smoothing) {
01176                                                             // convert block position to relative
01177                                                             // for interpolation smoothing
01178                                                             fx = (float)ii/block_size + 0.5f/block_size;
01179                                                             fy = (float)jj/block_size + 0.5f/block_size;
01180                                                             fz = (float)kk/block_size + 0.5f/block_size;
01181 
01182                                                             // calculate trilinear interpolation
01183                                                             interpolated_value = c000 * (1-fx) * (1-fy) * (1-fz) +
01184                                                             c100 * fx * (1-fy) * (1-fz) +
01185                                                             c010 * (1-fx) * fy * (1-fz) +
01186                                                             c001 * (1-fx) * (1-fy) * fz +
01187                                                             c101 * fx * (1-fy) * fz +
01188                                                             c011 * (1-fx) * fy * fz +
01189                                                             c110 * fx * fy * (1-fz) +
01190                                                             c111 * fx * fy * fz;
01191 
01192 
01193                                                             // add some contrast / sharpness
01194                                                             // depending on hi-res block size
01195 
01196                                                             interpolated_value = (interpolated_value-0.4f*sfs->density)*(block_size/2) + 0.4f*sfs->density;
01197                                                             if (interpolated_value<0.0f) interpolated_value = 0.0f;
01198                                                             if (interpolated_value>1.0f) interpolated_value = 1.0f;
01199 
01200                                                             // shift smoke block index
01201                                                             // (because pixel center is actually
01202                                                             // in halfway of the low res block)
01203                                                             shift_x = (x < 1) ? 0 : block_size/2;
01204                                                             shift_y = (y < 1) ? 0 : block_size/2;
01205                                                             shift_z = (z < 1) ? 0 : block_size/2;
01206                                                         }
01207                                                         else {
01208                                                             // without interpolation use same low resolution
01209                                                             // block value for all hi-res blocks
01210                                                             interpolated_value = c111;
01211                                                             shift_x = 0;
01212                                                             shift_y = 0;
01213                                                             shift_z = 0;
01214                                                         }
01215 
01216                                                         // get shifted index for current high resolution block
01217                                                         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);                                                     
01218                                                         
01219                                                         // add emission data to high resolution density
01220                                                         if (absolute_flow) {if (interpolated_value > 0) bigdensity[index_big] = interpolated_value;}
01221                                                         else {
01222                                                             bigdensity[index_big] += interpolated_value;
01223                                                             if (bigdensity[index_big]>1) bigdensity[index_big]=1.0f;
01224                                                         }
01225 
01226                                                         } // end of hires loop
01227 
01228                                     }   // end of low res loop
01229 
01230                                 // free temporary emission map
01231                             if (temp_emission_map) MEM_freeN(temp_emission_map);
01232 
01233                             }   // end emission
01234 
01235 
01236                                         
01237                 }                           
01238                 else                            
01239                 {                               
01240                     /*                              
01241                     for()                               
01242                     {                                   
01243                         // no psys                                  
01244                         BVHTreeNearest nearest;
01245                         nearest.index = -1;
01246                         nearest.dist = FLT_MAX;
01247 
01248                         BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh);
01249                     }*/                         
01250                 }
01251             }                       
01252         }
01253             if(sds->fluid_group)
01254                 go = go->next;
01255             else
01256                 base= base->next;
01257         }
01258     }
01259 
01260     // do effectors
01261     {
01262         ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
01263 
01264         if(effectors)
01265         {
01266             float *density = smoke_get_density(sds->fluid);
01267             float *force_x = smoke_get_force_x(sds->fluid);
01268             float *force_y = smoke_get_force_y(sds->fluid);
01269             float *force_z = smoke_get_force_z(sds->fluid);
01270             float *velocity_x = smoke_get_velocity_x(sds->fluid);
01271             float *velocity_y = smoke_get_velocity_y(sds->fluid);
01272             float *velocity_z = smoke_get_velocity_z(sds->fluid);
01273             int x, y, z;
01274 
01275             // precalculate wind forces
01276             for(x = 0; x < sds->res[0]; x++)
01277                 for(y = 0; y < sds->res[1]; y++)
01278                     for(z = 0; z < sds->res[2]; z++)
01279             {   
01280                 EffectedPoint epoint;
01281                 float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0};
01282                 unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
01283 
01284                 if(density[index] < FLT_EPSILON)                    
01285                     continue;   
01286 
01287                 vel[0] = velocity_x[index];
01288                 vel[1] = velocity_y[index];
01289                 vel[2] = velocity_z[index];
01290 
01291                 voxelCenter[0] = sds->p0[0] + sds->dx *  x + sds->dx * 0.5;
01292                 voxelCenter[1] = sds->p0[1] + sds->dx *  y + sds->dx * 0.5;
01293                 voxelCenter[2] = sds->p0[2] + sds->dx *  z + sds->dx * 0.5;
01294 
01295                 pd_point_from_loc(scene, voxelCenter, vel, index, &epoint);
01296                 pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
01297 
01298                 // TODO dg - do in force!
01299                 force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); 
01300                 force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); 
01301                 force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0);
01302             }
01303         }
01304 
01305         pdEndEffectors(&effectors);
01306     }
01307 
01308 }
01309 void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
01310 {   
01311     if((smd->type & MOD_SMOKE_TYPE_FLOW))
01312     {
01313         if(scene->r.cfra >= smd->time)
01314             smokeModifier_init(smd, ob, scene, dm);
01315 
01316         if(scene->r.cfra > smd->time)
01317         {
01318             // XXX TODO
01319             smd->time = scene->r.cfra;
01320 
01321             // rigid movement support
01322             /*
01323             copy_m4_m4(smd->flow->mat_old, smd->flow->mat);
01324             copy_m4_m4(smd->flow->mat, ob->obmat);
01325             */
01326         }
01327         else if(scene->r.cfra < smd->time)
01328         {
01329             smd->time = scene->r.cfra;
01330             smokeModifier_reset(smd);
01331         }
01332     }
01333     else if(smd->type & MOD_SMOKE_TYPE_COLL)
01334     {
01335         if(scene->r.cfra >= smd->time)
01336             smokeModifier_init(smd, ob, scene, dm);
01337 
01338         if(scene->r.cfra > smd->time)
01339         {
01340             // XXX TODO
01341             smd->time = scene->r.cfra;
01342             
01343             if(smd->coll->dm)
01344                 smd->coll->dm->release(smd->coll->dm);
01345 
01346             smd->coll->dm = CDDM_copy(dm);
01347 
01348             // rigid movement support
01349             copy_m4_m4(smd->coll->mat_old, smd->coll->mat);
01350             copy_m4_m4(smd->coll->mat, ob->obmat);
01351         }
01352         else if(scene->r.cfra < smd->time)
01353         {
01354             smd->time = scene->r.cfra;
01355             smokeModifier_reset(smd);
01356         }
01357     }
01358     else if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
01359     {
01360         SmokeDomainSettings *sds = smd->domain;
01361         float light[3]; 
01362         PointCache *cache = NULL;
01363         PTCacheID pid;
01364         int startframe, endframe, framenr;
01365         float timescale;
01366 
01367         framenr = scene->r.cfra;
01368 
01369         //printf("time: %d\n", scene->r.cfra);
01370 
01371         cache = sds->point_cache[0];
01372         BKE_ptcache_id_from_smoke(&pid, ob, smd);
01373         BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
01374 
01375         if(!smd->domain->fluid || framenr == startframe)
01376         {
01377             BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
01378             BKE_ptcache_validate(cache, framenr);
01379             cache->flag &= ~PTCACHE_REDO_NEEDED;
01380         }
01381 
01382         if(!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0)
01383             return;
01384 
01385         smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
01386 
01387         CLAMP(framenr, startframe, endframe);
01388 
01389         /* If already viewing a pre/after frame, no need to reload */
01390         if ((smd->time == framenr) && (framenr != scene->r.cfra))
01391             return;
01392 
01393         // printf("startframe: %d, framenr: %d\n", startframe, framenr);
01394 
01395         if(smokeModifier_init(smd, ob, scene, dm)==0)
01396         {
01397             printf("bad smokeModifier_init\n");
01398             return;
01399         }
01400 
01401         /* try to read from cache */
01402         if(BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
01403             BKE_ptcache_validate(cache, framenr);
01404             smd->time = framenr;
01405             return;
01406         }
01407         
01408         /* only calculate something when we advanced a single frame */
01409         if(framenr != (int)smd->time+1)
01410             return;
01411 
01412         /* don't simulate if viewing start frame, but scene frame is not real start frame */
01413         if (framenr != scene->r.cfra)
01414             return;
01415 
01416         tstart();
01417 
01418         smoke_calc_domain(scene, ob, smd);
01419 
01420         /* if on second frame, write cache for first frame */
01421         if((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) {
01422             // create shadows straight after domain initialization so we get nice shadows for startframe, too
01423             if(get_lamp(scene, light))
01424                 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);
01425 
01426             if(sds->wt)
01427             {
01428                 if(sds->flags & MOD_SMOKE_DISSOLVE)
01429                     smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
01430                 smoke_turbulence_step(sds->wt, sds->fluid);
01431             }
01432 
01433             BKE_ptcache_write(&pid, startframe);
01434         }
01435         
01436         // set new time
01437         smd->time = scene->r.cfra;
01438 
01439         /* do simulation */
01440 
01441         // low res
01442 
01443         // simulate the actual smoke (c++ code in intern/smoke)
01444         // DG: interesting commenting this line + deactivating loading of noise files
01445         if(framenr!=startframe)
01446         {
01447             if(sds->flags & MOD_SMOKE_DISSOLVE)
01448                 smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
01449             smoke_step(sds->fluid, smd->time, scene->r.frs_sec / scene->r.frs_sec_base);
01450         }
01451 
01452         // create shadows before writing cache so they get stored
01453         if(get_lamp(scene, light))
01454             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);
01455 
01456         if(sds->wt)
01457         {
01458             if(sds->flags & MOD_SMOKE_DISSOLVE)
01459                 smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
01460             smoke_turbulence_step(sds->wt, sds->fluid);
01461         }
01462     
01463         BKE_ptcache_validate(cache, framenr);
01464         if(framenr != startframe)
01465             BKE_ptcache_write(&pid, framenr);
01466 
01467         tend();
01468         //printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() );
01469     }
01470 }
01471 
01472 static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
01473 {
01474     const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
01475 
01476     // T_ray *= T_vox
01477     *tRay *= exp(input[index]*correct);
01478     
01479     if(result[index] < 0.0f)    
01480     {
01481 #pragma omp critical        
01482         result[index] = *tRay;  
01483     }   
01484 
01485     return *tRay;
01486 }
01487 
01488 long long smoke_get_mem_req(int xres, int yres, int zres, int amplify)
01489 {
01490     int totalCells = xres * yres * zres;
01491     int amplifiedCells = totalCells * amplify * amplify * amplify;
01492 
01493     // print out memory requirements
01494     long long int coarseSize = sizeof(float) * totalCells * 22 +
01495     sizeof(unsigned char) * totalCells;
01496 
01497     long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
01498     sizeof(float) * totalCells * 8 +     // small grids
01499     sizeof(float) * 128 * 128 * 128;     // noise tile
01500 
01501     long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
01502 
01503     return totalMB;
01504 }
01505 
01506 static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, bresenham_callback cb, float *result, float *input, int res[3], float correct)
01507 {
01508     int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
01509     int pixel[3];
01510 
01511     pixel[0] = x1;
01512     pixel[1] = y1;
01513     pixel[2] = z1;
01514 
01515     dx = x2 - x1;
01516     dy = y2 - y1;
01517     dz = z2 - z1;
01518 
01519     x_inc = (dx < 0) ? -1 : 1;
01520     l = abs(dx);
01521     y_inc = (dy < 0) ? -1 : 1;
01522     m = abs(dy);
01523     z_inc = (dz < 0) ? -1 : 1;
01524     n = abs(dz);
01525     dx2 = l << 1;
01526     dy2 = m << 1;
01527     dz2 = n << 1;
01528 
01529     if ((l >= m) && (l >= n)) {
01530         err_1 = dy2 - l;
01531         err_2 = dz2 - l;
01532         for (i = 0; i < l; i++) {
01533             if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
01534                 break;
01535             if (err_1 > 0) {
01536                 pixel[1] += y_inc;
01537                 err_1 -= dx2;
01538             }
01539             if (err_2 > 0) {
01540                 pixel[2] += z_inc;
01541                 err_2 -= dx2;
01542             }
01543             err_1 += dy2;
01544             err_2 += dz2;
01545             pixel[0] += x_inc;
01546         }
01547     } else if ((m >= l) && (m >= n)) {
01548         err_1 = dx2 - m;
01549         err_2 = dz2 - m;
01550         for (i = 0; i < m; i++) {
01551             if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
01552                 break;
01553             if (err_1 > 0) {
01554                 pixel[0] += x_inc;
01555                 err_1 -= dy2;
01556             }
01557             if (err_2 > 0) {
01558                 pixel[2] += z_inc;
01559                 err_2 -= dy2;
01560             }
01561             err_1 += dx2;
01562             err_2 += dz2;
01563             pixel[1] += y_inc;
01564         }
01565     } else {
01566         err_1 = dy2 - n;
01567         err_2 = dx2 - n;
01568         for (i = 0; i < n; i++) {
01569             if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
01570                 break;
01571             if (err_1 > 0) {
01572                 pixel[1] += y_inc;
01573                 err_1 -= dz2;
01574             }
01575             if (err_2 > 0) {
01576                 pixel[0] += x_inc;
01577                 err_2 -= dz2;
01578             }
01579             err_1 += dy2;
01580             err_2 += dx2;
01581             pixel[2] += z_inc;
01582         }
01583     }
01584     cb(result, input, res, pixel, tRay, correct);
01585 }
01586 
01587 static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct)
01588 {
01589     float tmp[3];
01590 
01591     sub_v3_v3v3(tmp, pos, p0);
01592     mul_v3_fl(tmp, 1.0 / dx);
01593 
01594     if(correct)
01595     {
01596         cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0])));
01597         cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1])));
01598         cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2])));
01599     }
01600     else
01601     {
01602         cell[0] = (int)floor(tmp[0]);
01603         cell[1] = (int)floor(tmp[1]);
01604         cell[2] = (int)floor(tmp[2]);
01605     }
01606 }
01607 
01608 static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct)
01609 {
01610     float bv[6];
01611     int a, z, slabsize=res[0]*res[1], size= res[0]*res[1]*res[2];
01612 
01613     for(a=0; a<size; a++)
01614         result[a]= -1.0f;
01615 
01616     bv[0] = p0[0];
01617     bv[1] = p1[0];
01618     // y
01619     bv[2] = p0[1];
01620     bv[3] = p1[1];
01621     // z
01622     bv[4] = p0[2];
01623     bv[5] = p1[2];
01624 
01625 #pragma omp parallel for schedule(static,1)
01626     for(z = 0; z < res[2]; z++)
01627     {
01628         size_t index = z*slabsize;
01629         int x,y;
01630 
01631         for(y = 0; y < res[1]; y++)
01632             for(x = 0; x < res[0]; x++, index++)
01633             {
01634                 float voxelCenter[3];
01635                 float pos[3];
01636                 int cell[3];
01637                 float tRay = 1.0;
01638 
01639                 if(result[index] >= 0.0f)                   
01640                     continue;                               
01641                 voxelCenter[0] = p0[0] + dx *  x + dx * 0.5;
01642                 voxelCenter[1] = p0[1] + dx *  y + dx * 0.5;
01643                 voxelCenter[2] = p0[2] + dx *  z + dx * 0.5;
01644 
01645                 // get starting position (in voxel coords)
01646                 if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
01647                 {
01648                     // we're ouside
01649                     get_cell(p0, res, dx, pos, cell, 1);
01650                 }
01651                 else
01652                 {
01653                     // we're inside
01654                     get_cell(p0, res, dx, light, cell, 1);
01655                 }
01656 
01657                 bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, cb, result, input, res, correct);
01658 
01659                 // convention -> from a RGBA float array, use G value for tRay
01660 // #pragma omp critical
01661                 result[index] = tRay;           
01662             }
01663     }
01664 }
01665 
01666 #endif /* WITH_SMOKE */