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