Blender V2.61 - r43446

MOD_fluidsim_util.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) 2005 by the Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Daniel Dunbar
00022  *                 Ton Roosendaal,
00023  *                 Ben Batt,
00024  *                 Brecht Van Lommel,
00025  *                 Campbell Barton
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  *
00029  */
00030 
00036 #include <stddef.h>
00037 #include <zlib.h>
00038 
00039 #include "DNA_object_types.h"
00040 #include "DNA_scene_types.h"
00041 #include "DNA_mesh_types.h"
00042 #include "DNA_meshdata_types.h"
00043 #include "DNA_object_types.h"
00044 #include "DNA_object_fluidsim.h"
00045 
00046 #include "BLI_blenlib.h"
00047 #include "BLI_math.h"
00048 #include "BLI_utildefines.h"
00049 
00050 #include "BKE_main.h"
00051 #include "BKE_fluidsim.h" /* ensure definitions here match */
00052 #include "BKE_cdderivedmesh.h"
00053 #include "BKE_mesh.h"
00054 #include "BKE_utildefines.h"
00055 #include "BKE_global.h" /* G.main->name only */
00056 
00057 #include "MOD_fluidsim_util.h"
00058 #include "MOD_modifiertypes.h"
00059 
00060 #include "MEM_guardedalloc.h"
00061 
00062 // headers for fluidsim bobj meshes
00063 #include "LBM_fluidsim.h"
00064 
00065 
00066 void fluidsim_init(FluidsimModifierData *fluidmd)
00067 {
00068 #ifdef WITH_MOD_FLUID
00069     if(fluidmd)
00070     {
00071         FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
00072 
00073         fluidmd->fss = fss;
00074         
00075         if(!fss)
00076             return;
00077         
00078         fss->fmd = fluidmd;
00079         fss->type = OB_FLUIDSIM_ENABLE;
00080         fss->show_advancedoptions = 0;
00081 
00082         fss->resolutionxyz = 65;
00083         fss->previewresxyz = 45;
00084         fss->realsize = 0.5;
00085         fss->guiDisplayMode = 2; // preview
00086         fss->renderDisplayMode = 3; // render
00087 
00088         fss->viscosityMode = 2; // default to water
00089         fss->viscosityValue = 1.0;
00090         fss->viscosityExponent = 6;
00091         
00092         fss->grav[0] = 0.0;
00093         fss->grav[1] = 0.0;
00094         fss->grav[2] = -9.81;
00095 
00096         fss->animStart = 0.0; 
00097         fss->animEnd = 4.0;
00098         fss->gstar = 0.005; // used as normgstar
00099         fss->maxRefine = -1;
00100         // maxRefine is set according to resolutionxyz during bake
00101 
00102         // fluid/inflow settings
00103         // fss->iniVel --> automatically set to 0
00104 
00105         modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid");
00106 
00107         // first init of bounding box
00108         // no bounding box needed
00109         
00110         // todo - reuse default init from elbeem!
00111         fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS;
00112         fss->domainNovecgen = 0;
00113         fss->volumeInitType = 1; // volume
00114         fss->partSlipValue = 0.2;
00115 
00116         fss->generateTracers = 0;
00117         fss->generateParticles = 0.0;
00118         fss->surfaceSmoothing = 1.0;
00119         fss->surfaceSubdivs = 0.0;
00120         fss->particleInfSize = 0.0;
00121         fss->particleInfAlpha = 0.0;
00122     
00123         // init fluid control settings
00124         fss->attractforceStrength = 0.2;
00125         fss->attractforceRadius = 0.75;
00126         fss->velocityforceStrength = 0.2;
00127         fss->velocityforceRadius = 0.75;
00128         fss->cpsTimeStart = fss->animStart;
00129         fss->cpsTimeEnd = fss->animEnd;
00130         fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
00131         
00132         /*
00133         BAD TODO: this is done in buttons_object.c in the moment 
00134         Mesh *mesh = ob->data;
00135         // calculate bounding box
00136         fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); 
00137         */
00138         
00139         fss->meshVelocities = NULL;
00140         
00141         fss->lastgoodframe = -1;
00142         
00143         fss->flag |= OB_FLUIDSIM_ACTIVE;
00144 
00145     }
00146 #else
00147     (void)fluidmd; /* unused */
00148 #endif
00149     return;
00150 }
00151 
00152 void fluidsim_free(FluidsimModifierData *fluidmd)
00153 {
00154 #ifdef WITH_MOD_FLUID
00155     if(fluidmd)
00156     {
00157         if(fluidmd->fss->meshVelocities)
00158         {
00159             MEM_freeN(fluidmd->fss->meshVelocities);
00160             fluidmd->fss->meshVelocities = NULL;
00161         }
00162         MEM_freeN(fluidmd->fss);
00163     }
00164 #else
00165     (void)fluidmd; /* unused */
00166 #endif
00167     
00168     return;
00169 }
00170 
00171 #ifdef WITH_MOD_FLUID
00172 /* read .bobj.gz file into a fluidsimDerivedMesh struct */
00173 static DerivedMesh *fluidsim_read_obj(const char *filename)
00174 {
00175     int wri = 0,i;
00176     int gotBytes;
00177     gzFile gzf;
00178     int numverts = 0, numfaces = 0;
00179     DerivedMesh *dm = NULL;
00180     MFace *mf;
00181     MVert *mv;
00182     short *normals, *no_s;
00183     float no[3];
00184 
00185     // ------------------------------------------------
00186     // get numverts + numfaces first
00187     // ------------------------------------------------
00188     gzf = gzopen(filename, "rb");
00189     if (!gzf)
00190     {
00191         return NULL;
00192     }
00193 
00194     // read numverts
00195     gotBytes = gzread(gzf, &wri, sizeof(wri));
00196     numverts = wri;
00197 
00198     // skip verts
00199     gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
00200 
00201 
00202     // read number of normals
00203     if(gotBytes)
00204         gotBytes = gzread(gzf, &wri, sizeof(wri));
00205 
00206     // skip normals
00207     gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
00208 
00209     /* get no. of triangles */
00210     if(gotBytes)
00211         gotBytes = gzread(gzf, &wri, sizeof(wri));
00212     numfaces = wri;
00213 
00214     gzclose( gzf );
00215     // ------------------------------------------------
00216 
00217     if(!numfaces || !numverts || !gotBytes)
00218         return NULL;
00219 
00220     gzf = gzopen(filename, "rb");
00221     if (!gzf)
00222     {
00223         return NULL;
00224     }
00225 
00226     dm = CDDM_new(numverts, 0, numfaces);
00227 
00228     if(!dm)
00229     {
00230         gzclose( gzf );
00231         return NULL;
00232     }
00233 
00234     // read numverts
00235     gotBytes = gzread(gzf, &wri, sizeof(wri));
00236 
00237     // read vertex position from file
00238     mv = CDDM_get_verts(dm);
00239 
00240     for(i=0; i<numverts; i++, mv++)
00241         gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);
00242 
00243     // should be the same as numverts
00244     gotBytes = gzread(gzf, &wri, sizeof(wri));
00245     if(wri != numverts)
00246     {
00247         if(dm)
00248             dm->release(dm);
00249         gzclose( gzf );
00250         return NULL;
00251     }
00252 
00253     normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
00254     if(!normals)
00255     {
00256         if(dm)
00257             dm->release(dm);
00258         gzclose( gzf );
00259         return NULL;
00260     }
00261 
00262     // read normals from file (but don't save them yet)
00263     for(i=numverts, no_s= normals; i>0; i--, no_s += 3)
00264     {
00265         gotBytes = gzread(gzf, no, sizeof(float) * 3);
00266         normal_float_to_short_v3(no_s, no);
00267     }
00268 
00269     /* read no. of triangles */
00270     gotBytes = gzread(gzf, &wri, sizeof(wri));
00271 
00272     if(wri!=numfaces) {
00273         printf("Fluidsim: error in reading data from file.\n");
00274         if(dm)
00275             dm->release(dm);
00276         gzclose( gzf );
00277         MEM_freeN(normals);
00278         return NULL;
00279     }
00280 
00281     // read triangles from file
00282     mf = CDDM_get_faces(dm);
00283     for(i=numfaces; i>0; i--, mf++)
00284     {
00285         int face[3];
00286 
00287         gotBytes = gzread(gzf, face, sizeof(int) * 3);
00288 
00289         // check if 3rd vertex has index 0 (not allowed in blender)
00290         if(face[2])
00291         {
00292             mf->v1 = face[0];
00293             mf->v2 = face[1];
00294             mf->v3 = face[2];
00295         }
00296         else
00297         {
00298             mf->v1 = face[1];
00299             mf->v2 = face[2];
00300             mf->v3 = face[0];
00301         }
00302         mf->v4 = 0;
00303 
00304         test_index_face(mf, NULL, 0, 3);
00305     }
00306 
00307     gzclose( gzf );
00308 
00309     CDDM_calc_edges(dm);
00310 
00311     CDDM_apply_vert_normals(dm, (short (*)[3])normals);
00312     MEM_freeN(normals);
00313 
00314     // CDDM_calc_normals(result);
00315 
00316     return dm;
00317 }
00318 
00319 
00320 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
00321          /*RET*/ float start[3], /*RET*/ float size[3] )
00322 {
00323     float bbsx=0.0, bbsy=0.0, bbsz=0.0;
00324     float bbex=1.0, bbey=1.0, bbez=1.0;
00325     int i;
00326     float vec[3];
00327 
00328     if(totvert == 0) {
00329         zero_v3(start);
00330         zero_v3(size);
00331         return;
00332     }
00333 
00334     copy_v3_v3(vec, mvert[0].co);
00335     mul_m4_v3(obmat, vec);
00336     bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
00337     bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
00338 
00339     for(i = 1; i < totvert; i++) {
00340         copy_v3_v3(vec, mvert[i].co);
00341         mul_m4_v3(obmat, vec);
00342 
00343         if(vec[0] < bbsx){ bbsx= vec[0]; }
00344         if(vec[1] < bbsy){ bbsy= vec[1]; }
00345         if(vec[2] < bbsz){ bbsz= vec[2]; }
00346         if(vec[0] > bbex){ bbex= vec[0]; }
00347         if(vec[1] > bbey){ bbey= vec[1]; }
00348         if(vec[2] > bbez){ bbez= vec[2]; }
00349     }
00350 
00351     // return values...
00352     if(start) {
00353         start[0] = bbsx;
00354         start[1] = bbsy;
00355         start[2] = bbsz;
00356     }
00357     if(size) {
00358         size[0] = bbex-bbsx;
00359         size[1] = bbey-bbsy;
00360         size[2] = bbez-bbsz;
00361     }
00362 }
00363 
00364 //-------------------------------------------------------------------------------
00365 // old interface
00366 //-------------------------------------------------------------------------------
00367 
00368 void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
00369 {
00370     Mesh *mesh;
00371 
00372     value[0]= '\0';
00373 
00374     if(ob->type == OB_MESH) {
00375         /* use mesh bounding box and object scaling */
00376         mesh= ob->data;
00377 
00378         fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
00379         elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0],fss->bbSize[1],fss->bbSize[2], fss->maxRefine, value);
00380     }
00381 }
00382 
00383 
00384 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
00385 static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename)
00386 {
00387     int wri, i, j;
00388     float wrf;
00389     gzFile gzf;
00390     FluidsimSettings *fss = fluidmd->fss;
00391     int len = strlen(filename);
00392     int totvert = dm->getNumVerts(dm);
00393     FluidVertexVelocity *velarray = NULL;
00394 
00395     // mesh and vverts have to be valid from loading...
00396 
00397     if(fss->meshVelocities)
00398         MEM_freeN(fss->meshVelocities);
00399 
00400     if(len<7)
00401     {
00402         return;
00403     }
00404 
00405     if(fss->domainNovecgen>0) return;
00406 
00407     fss->meshVelocities = MEM_callocN(sizeof(FluidVertexVelocity)*dm->getNumVerts(dm), "Fluidsim_velocities");
00408     fss->totvert = totvert;
00409 
00410     velarray = fss->meshVelocities;
00411 
00412     // .bobj.gz , correct filename
00413     // 87654321
00414     filename[len-6] = 'v';
00415     filename[len-5] = 'e';
00416     filename[len-4] = 'l';
00417 
00418     gzf = gzopen(filename, "rb");
00419     if (!gzf)
00420     {
00421         MEM_freeN(fss->meshVelocities);
00422         fss->meshVelocities = NULL;
00423         return;
00424     }
00425 
00426     gzread(gzf, &wri, sizeof( wri ));
00427     if(wri != totvert)
00428     {
00429         MEM_freeN(fss->meshVelocities);
00430         fss->meshVelocities = NULL;
00431         return;
00432     }
00433 
00434     for(i=0; i<totvert;i++)
00435     {
00436         for(j=0; j<3; j++)
00437         {
00438             gzread(gzf, &wrf, sizeof( wrf ));
00439             velarray[i].vel[j] = wrf;
00440         }
00441     }
00442 
00443     gzclose(gzf);
00444 }
00445 
00446 static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
00447 {
00448     int displaymode = 0;
00449     int curFrame = framenr - 1 /*scene->r.sfra*/; /* start with 0 at start frame */
00450     char targetFile[FILE_MAX];
00451     FluidsimSettings *fss = fluidmd->fss;
00452     DerivedMesh *dm = NULL;
00453     MFace *mface;
00454     int numfaces;
00455     int mat_nr, flag, i;
00456 
00457     if(!useRenderParams) {
00458         displaymode = fss->guiDisplayMode;
00459     } else {
00460         displaymode = fss->renderDisplayMode;
00461     }
00462 
00463     switch (displaymode) {
00464     case 1:
00465         /* just display original object */
00466         return NULL;
00467     case 2:
00468         /* use preview mesh */
00469         BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
00470         break;
00471     default: /* 3 */
00472         /* 3. use final mesh */
00473         BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
00474         break;
00475     }
00476 
00477     BLI_path_abs(targetFile, modifier_path_relbase(ob));
00478     BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no
00479 
00480     dm = fluidsim_read_obj(targetFile);
00481 
00482     if(!dm)
00483     {
00484         // switch, abort background rendering when fluidsim mesh is missing
00485         const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
00486 
00487         if(G.background==1) {
00488             if(getenv(strEnvName2)) {
00489                 int elevel = atoi(getenv(strEnvName2));
00490                 if(elevel>0) {
00491                     printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
00492                     exit(1);
00493                 }
00494             }
00495         }
00496 
00497         // display org. object upon failure which is in dm
00498         return NULL;
00499     }
00500 
00501     // assign material + flags to new dm
00502     // if there's no faces in original dm, keep materials and flags unchanged
00503     mface = orgdm->getFaceArray(orgdm);
00504 
00505     if(mface) {
00506         mat_nr = mface[0].mat_nr;
00507         flag = mface[0].flag;
00508 
00509         mface = dm->getFaceArray(dm);
00510         numfaces = dm->getNumFaces(dm);
00511         for(i=0; i<numfaces; i++)
00512             {
00513                 mface[i].mat_nr = mat_nr;
00514                 mface[i].flag = flag;
00515             }
00516     }
00517 
00518     // load vertex velocities, if they exist...
00519     // TODO? use generate flag as loading flag as well?
00520     // warning, needs original .bobj.gz mesh loading filename
00521     if(displaymode==3)
00522     {
00523         fluidsim_read_vel_cache(fluidmd, dm, targetFile);
00524     }
00525     else
00526     {
00527         if(fss->meshVelocities)
00528             MEM_freeN(fss->meshVelocities);
00529 
00530         fss->meshVelocities = NULL;
00531     }
00532 
00533     return dm;
00534 }
00535 #endif // WITH_MOD_FLUID
00536 
00537 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene,
00538                         Object *ob,
00539                         DerivedMesh *dm,
00540                         int useRenderParams, int UNUSED(isFinalCalc))
00541 {
00542 #ifdef WITH_MOD_FLUID
00543     DerivedMesh *result = NULL;
00544     int framenr;
00545     FluidsimSettings *fss = NULL;
00546 
00547     framenr= (int)scene->r.cfra;
00548     
00549     // only handle fluidsim domains
00550     if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
00551         return dm;
00552     
00553     // sanity check
00554     if(!fluidmd || (fluidmd && !fluidmd->fss))
00555         return dm;
00556     
00557     fss = fluidmd->fss;
00558     
00559     // timescale not supported yet
00560     // clmd->sim_parms->timescale= timescale;
00561 
00562     // support reversing of baked fluid frames here
00563     if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
00564     {
00565         framenr = fss->lastgoodframe - framenr + 1;
00566         CLAMP(framenr, 1, fss->lastgoodframe);
00567     }
00568     
00569     /* try to read from cache */
00570     /* if the frame is there, fine, otherwise don't do anything */
00571     if((result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams)))
00572         return result;
00573     
00574     return dm;
00575 #else
00576     /* unused */
00577     (void)fluidmd;
00578     (void)scene;
00579     (void)ob;
00580     (void)dm;
00581     (void)useRenderParams;
00582     return NULL;
00583 #endif
00584 }