Blender V2.61 - r43446

physics_fluid.c

Go to the documentation of this file.
00001 /*
00002  * fluidsim.c
00003  * 
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * The Original Code is Copyright (C) Blender Foundation
00022  * All rights reserved.
00023  *
00024  * The Original Code is: all of this file.
00025  *
00026  * Contributor(s): none yet.
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00038 #include <math.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <sys/stat.h>
00042 
00043 #include "MEM_guardedalloc.h"
00044 
00045 /* types */
00046 #include "DNA_anim_types.h"
00047 #include "DNA_action_types.h"
00048 #include "DNA_object_types.h"
00049 #include "DNA_object_fluidsim.h"    
00050 
00051 #include "BLI_blenlib.h"
00052 #include "BLI_threads.h"
00053 #include "BLI_math.h"
00054 #include "BLI_utildefines.h"
00055 
00056 #include "BKE_animsys.h"
00057 #include "BKE_armature.h"
00058 #include "BKE_blender.h"
00059 #include "BKE_context.h"
00060 #include "BKE_customdata.h"
00061 #include "BKE_DerivedMesh.h"
00062 #include "BKE_displist.h"
00063 #include "BKE_effect.h"
00064 #include "BKE_fluidsim.h"
00065 #include "BKE_global.h"
00066 #include "BKE_ipo.h"
00067 #include "BKE_key.h"
00068 #include "BKE_main.h"
00069 #include "BKE_modifier.h"
00070 #include "BKE_object.h"
00071 #include "BKE_report.h"
00072 #include "BKE_scene.h"
00073 #include "BKE_softbody.h"
00074 #include "BKE_unit.h"
00075 
00076 
00077 #include "LBM_fluidsim.h"
00078 
00079 #include "ED_screen.h"
00080 #include "ED_fluidsim.h"
00081 
00082 #include "WM_types.h"
00083 #include "WM_api.h"
00084 
00085 #include "physics_intern.h" // own include
00086 
00087 /* enable/disable overall compilation */
00088 #ifdef WITH_MOD_FLUID
00089 
00090 #include "WM_api.h"
00091 
00092 #include "DNA_scene_types.h"
00093 #include "DNA_ipo_types.h"
00094 #include "DNA_mesh_types.h"
00095 
00096 #include "PIL_time.h"
00097 
00098 
00099 static float get_fluid_viscosity(FluidsimSettings *settings)
00100 {
00101     switch (settings->viscosityMode) {
00102         case 0:     /* unused */
00103             return -1.0;
00104         case 2:     /* water */
00105             return 1.0e-6;
00106         case 3:     /* some (thick) oil */
00107             return 5.0e-5;
00108         case 4:     /* ca. honey */
00109             return 2.0e-3;
00110         case 1:     /* manual */
00111         default:
00112             return (1.0/pow(10.0, settings->viscosityExponent)) * settings->viscosityValue;
00113     }
00114 }
00115 
00116 static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss)
00117 {
00118     if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
00119         copy_v3_v3(gravity, scene->physics_settings.gravity);
00120     } else {
00121         copy_v3_v3(gravity, fss->grav);
00122     }
00123 }
00124 
00125 static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss)
00126 {
00127     if (!scene->unit.system) {
00128         return fss->realsize;
00129     } else {
00130         float dim[3];
00131         float longest_axis;
00132         
00133         object_get_dimensions(domainob, dim);
00134         longest_axis = MAX3(dim[0], dim[1], dim[2]);
00135         
00136         return longest_axis * scene->unit.scale_length;
00137     }
00138 }
00139 
00140 static int fluid_is_animated_mesh(FluidsimSettings *fss)
00141 {
00142     return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen);
00143 }
00144 
00145 /* ********************** fluid sim settings struct functions ********************** */
00146 
00147 #if 0
00148 /* helper function */
00149 void fluidsimGetGeometryObjFilename(Object *ob, char *dst) { //, char *srcname)
00150 {
00151     //BLI_snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
00152     BLI_snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
00153 }
00154 #endif
00155 
00156 
00157 /* ********************** fluid sim channel helper functions ********************** */
00158 
00159 typedef struct FluidAnimChannels {
00160     int length;
00161     
00162     double aniFrameTime;
00163     
00164     float *timeAtFrame;
00165     float *DomainTime;
00166     float *DomainGravity;
00167     float *DomainViscosity;
00168 } FluidAnimChannels;
00169 
00170 typedef struct FluidObject {
00171     struct FluidObject *next, *prev;
00172     
00173     struct Object *object;
00174     
00175     float *Translation;
00176     float *Rotation;
00177     float *Scale;
00178     float *Active;
00179     
00180     float *InitialVelocity;
00181     
00182     float *AttractforceStrength;
00183     float *AttractforceRadius;
00184     float *VelocityforceStrength;
00185     float *VelocityforceRadius;
00186     
00187     float *VertexCache;
00188     int numVerts, numTris;
00189 } FluidObject;
00190 
00191 // no. of entries for the two channel sizes
00192 #define CHANNEL_FLOAT 1
00193 #define CHANNEL_VEC   3
00194 
00195 // simplify channels before printing
00196 // for API this is done anyway upon init
00197 #if 0
00198 static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries) 
00199 { 
00200     int i,j; 
00201     int channelSize = paramsize; 
00202 
00203     if(entries==3) {
00204         elbeemSimplifyChannelVec3( channel, &channelSize); 
00205     } else if(entries==1) {
00206         elbeemSimplifyChannelFloat( channel, &channelSize); 
00207     } else {
00208         // invalid, cant happen?
00209     }
00210 
00211     fprintf(file, "      CHANNEL %s = \n", str); 
00212     for(i=0; i<channelSize;i++) { 
00213         fprintf(file,"        ");  
00214         for(j=0;j<=entries;j++) {  // also print time value
00215             fprintf(file," %f ", channel[i*(entries+1)+j] ); 
00216             if(j==entries-1){ fprintf(file,"  "); }
00217         } 
00218         fprintf(file," \n");  
00219     } 
00220 
00221     fprintf(file,  "      ; \n" ); 
00222 }
00223 #endif
00224 
00225 
00226 /* Note: fluid anim channel data layout
00227  * ------------------------------------
00228  * CHANNEL_FLOAT:
00229  * frame 1     |frame 2
00230  * [dataF][time][dataF][time]
00231  *
00232  * CHANNEL_VEC:
00233  * frame 1                   |frame 2
00234  * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time]
00235  *
00236  */
00237 
00238 static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels)
00239 {
00240     int i;
00241     
00242     channels->timeAtFrame = MEM_callocN( (channels->length+1)*sizeof(float), "timeAtFrame channel");
00243     
00244     channels->timeAtFrame[0] = channels->timeAtFrame[1] = domainSettings->animStart; // start at index 1
00245     
00246     for(i=2; i<=channels->length; i++) {
00247         channels->timeAtFrame[i] = channels->timeAtFrame[i-1] + channels->aniFrameTime;
00248     }
00249 }
00250 
00251 /* if this is slow, can replace with faster, less readable code */
00252 static void set_channel(float *channel, float time, float *value, int i, int size)
00253 {
00254     if (size == CHANNEL_FLOAT) {
00255         channel[(i * 2) + 0] = value[0];
00256         channel[(i * 2) + 1] = time;
00257     }
00258     else if (size == CHANNEL_VEC) {
00259         channel[(i * 4) + 0] = value[0];
00260         channel[(i * 4) + 1] = value[1];
00261         channel[(i * 4) + 2] = value[2];
00262         channel[(i * 4) + 3] = time;
00263     }
00264 }
00265 
00266 static void set_vertex_channel(float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i)
00267 {
00268     Object *ob = fobj->object;
00269     FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
00270     float *verts;
00271     int *tris=NULL, numVerts=0, numTris=0;
00272     int modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd);
00273     int framesize = (3*fobj->numVerts) + 1;
00274     int j;
00275     
00276     if (channel == NULL)
00277         return;
00278     
00279     initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
00280     
00281     /* don't allow mesh to change number of verts in anim sequence */
00282     if (numVerts != fobj->numVerts) {
00283         MEM_freeN(channel);
00284         channel = NULL;
00285         return;
00286     }
00287     
00288     /* fill frame of channel with vertex locations */
00289     for(j=0; j < (3*numVerts); j++) {
00290         channel[i*framesize + j] = verts[j];
00291     }
00292     channel[i*framesize + framesize-1] = time;
00293     
00294     MEM_freeN(verts);
00295     MEM_freeN(tris);
00296 }
00297 
00298 static void free_domain_channels(FluidAnimChannels *channels)
00299 {
00300     if (!channels->timeAtFrame)
00301         return;
00302     MEM_freeN(channels->timeAtFrame);
00303     channels->timeAtFrame = NULL;
00304     MEM_freeN(channels->DomainGravity);
00305     channels->DomainGravity = NULL;
00306     MEM_freeN(channels->DomainViscosity);
00307     channels->DomainViscosity = NULL;
00308 }
00309 
00310 static void free_all_fluidobject_channels(ListBase *fobjects)
00311 {
00312     FluidObject *fobj;
00313     
00314     for (fobj=fobjects->first; fobj; fobj=fobj->next) {
00315         if (fobj->Translation) {
00316             MEM_freeN(fobj->Translation);
00317             fobj->Translation = NULL;
00318             MEM_freeN(fobj->Rotation);
00319             fobj->Rotation = NULL;
00320             MEM_freeN(fobj->Scale);
00321             fobj->Scale = NULL;
00322             MEM_freeN(fobj->Active);
00323             fobj->Active = NULL;
00324             MEM_freeN(fobj->InitialVelocity);
00325             fobj->InitialVelocity = NULL;
00326         }
00327         
00328         if (fobj->AttractforceStrength) {
00329             MEM_freeN(fobj->AttractforceStrength);
00330             fobj->AttractforceStrength = NULL;
00331             MEM_freeN(fobj->AttractforceRadius);
00332             fobj->AttractforceRadius = NULL;
00333             MEM_freeN(fobj->VelocityforceStrength);
00334             fobj->VelocityforceStrength = NULL;
00335             MEM_freeN(fobj->VelocityforceRadius);
00336             fobj->VelocityforceRadius = NULL;
00337         }
00338         
00339         if (fobj->VertexCache) {
00340             MEM_freeN(fobj->VertexCache);
00341             fobj->VertexCache = NULL;
00342         }
00343     }
00344 }
00345 
00346 static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects)
00347 {
00348     Scene *scene = CTX_data_scene(C);
00349     Base *base;
00350     int i;
00351     int length = channels->length;
00352     float eval_time;
00353     
00354     /* XXX: first init time channel - temporary for now */
00355     /* init time values (should be done after evaluating animated time curve) */
00356     init_time(domainSettings, channels);
00357     
00358     /* allocate domain animation channels */
00359     channels->DomainGravity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "channel DomainGravity");
00360     channels->DomainViscosity = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainViscosity");
00361     //channels->DomainTime = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainTime");
00362     
00363     /* allocate fluid objects */
00364     for (base=scene->base.first; base; base= base->next) {
00365         Object *ob = base->object;
00366         FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
00367         
00368         if (fluidmd) {
00369             FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object");
00370             fobj->object = ob;
00371             
00372             if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
00373                 BLI_addtail(fobjects, fobj);
00374                 continue;
00375             }
00376             
00377             fobj->Translation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Translation");
00378             fobj->Rotation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Rotation");
00379             fobj->Scale = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Scale");
00380             fobj->Active = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject Active");
00381             fobj->InitialVelocity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject InitialVelocity");
00382             
00383             if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
00384                 fobj->AttractforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceStrength");
00385                 fobj->AttractforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceRadius");
00386                 fobj->VelocityforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceStrength");
00387                 fobj->VelocityforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceRadius");
00388             }
00389             
00390             if (fluid_is_animated_mesh(fluidmd->fss)) {
00391                 float *verts=NULL;
00392                 int *tris=NULL, modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd);
00393 
00394                 initElbeemMesh(scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex);
00395                 fobj->VertexCache = MEM_callocN( length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache");
00396                 
00397                 MEM_freeN(verts);
00398                 MEM_freeN(tris);
00399             }
00400             
00401             BLI_addtail(fobjects, fobj);
00402         }
00403     }
00404     
00405     /* now we loop over the frames and fill the allocated channels with data */
00406     for (i=0; i<channels->length; i++) {
00407         FluidObject *fobj;
00408         float viscosity, gravity[3];
00409         float timeAtFrame;
00410         
00411         eval_time = domainSettings->bakeStart + i;
00412         timeAtFrame = channels->timeAtFrame[i+1];
00413         
00414         /* XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation,
00415          * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ )
00416          * --> BKE_animsys_evaluate_all_animation(G.main, eval_time);
00417          * This doesn't work with drivers:
00418          * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL);
00419          */
00420         
00421         /* Modifying the global scene isn't nice, but we can do it in 
00422          * this part of the process before a threaded job is created */
00423         scene->r.cfra = (int)eval_time;
00424         ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1);
00425         
00426         /* now scene data should be current according to animation system, so we fill the channels */
00427         
00428         /* Domain properties - gravity/viscosity/time */
00429         get_fluid_gravity(gravity, scene, domainSettings);
00430         set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC);
00431         viscosity = get_fluid_viscosity(domainSettings);
00432         set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT);
00433         // XXX : set_channel(channels->DomainTime, timeAtFrame, &time, i, CHANNEL_VEC);
00434         
00435         /* object movement */
00436         for (fobj=fobjects->first; fobj; fobj=fobj->next) {
00437             Object *ob = fobj->object;
00438             FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
00439             float active= (float)(fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE);
00440             float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f};
00441             
00442             if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE))
00443                 continue;
00444             
00445             /* init euler rotation values and convert to elbeem format */
00446             /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */
00447             if(i) {
00448                 copy_v3_v3(old_rot, fobj->Rotation + 4*(i-1));
00449                 mul_v3_fl(old_rot, -M_PI/180.f);
00450             }
00451 
00452             mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat);
00453             mul_v3_fl(rot_d, -180.f/M_PI);
00454             
00455             set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC);
00456             set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC);
00457             set_channel(fobj->Scale, timeAtFrame, ob->size, i, CHANNEL_VEC);
00458             set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT);
00459             set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC);
00460             
00461             if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
00462                 set_channel(fobj->AttractforceStrength, timeAtFrame, &fluidmd->fss->attractforceStrength, i, CHANNEL_FLOAT);
00463                 set_channel(fobj->AttractforceRadius, timeAtFrame, &fluidmd->fss->attractforceRadius, i, CHANNEL_FLOAT);
00464                 set_channel(fobj->VelocityforceStrength, timeAtFrame, &fluidmd->fss->velocityforceStrength, i, CHANNEL_FLOAT);
00465                 set_channel(fobj->VelocityforceRadius, timeAtFrame, &fluidmd->fss->velocityforceRadius, i, CHANNEL_FLOAT);
00466             }
00467             
00468             if (fluid_is_animated_mesh(fluidmd->fss)) {
00469                 set_vertex_channel(fobj->VertexCache, timeAtFrame, scene, fobj, i);
00470             }
00471         }
00472     }
00473 }
00474 
00475 static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length)
00476 {
00477     FluidObject *fobj;
00478     
00479     for (fobj=fobjects->first; fobj; fobj=fobj->next) {
00480         Object *ob = fobj->object;
00481         FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
00482         int modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd);
00483         
00484         float *verts=NULL;
00485         int *tris=NULL;
00486         int numVerts=0, numTris=0;
00487         int deform = fluid_is_animated_mesh(fluidmd->fss);
00488         
00489         elbeemMesh fsmesh;
00490         
00491         if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE))
00492             continue;
00493         
00494         elbeemResetMesh( &fsmesh );
00495         
00496         fsmesh.type = fluidmd->fss->type;
00497         fsmesh.name = ob->id.name;
00498         
00499         initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
00500         
00501         fsmesh.numVertices   = numVerts;
00502         fsmesh.numTriangles  = numTris;
00503         fsmesh.vertices      = verts;
00504         fsmesh.triangles     = tris;
00505         
00506         fsmesh.channelSizeTranslation  = 
00507         fsmesh.channelSizeRotation     = 
00508         fsmesh.channelSizeScale        = 
00509         fsmesh.channelSizeInitialVel   = 
00510         fsmesh.channelSizeActive       = length;
00511         
00512         fsmesh.channelTranslation      = fobj->Translation;
00513         fsmesh.channelRotation         = fobj->Rotation;
00514         fsmesh.channelScale            = fobj->Scale;
00515         fsmesh.channelActive           = fobj->Active;
00516         
00517         if( ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
00518             fsmesh.channelInitialVel = fobj->InitialVelocity;
00519             fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD)?1:0);
00520         } 
00521         
00522         if(fluidmd->fss->typeFlags & OB_FSBND_NOSLIP)
00523             fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
00524         else if(fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP)
00525             fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
00526         else if(fluidmd->fss->typeFlags & OB_FSBND_FREESLIP)
00527             fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
00528         
00529         fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue;
00530         fsmesh.volumeInitType = fluidmd->fss->volumeInitType;
00531         fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value
00532         
00533         if (fsmesh.type == OB_FLUIDSIM_CONTROL) {
00534             fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart;
00535             fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd;
00536             fsmesh.cpsQuality = fluidmd->fss->cpsQuality;
00537             fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE);
00538             
00539             fsmesh.channelSizeAttractforceRadius = 
00540             fsmesh.channelSizeVelocityforceStrength = 
00541             fsmesh.channelSizeVelocityforceRadius = 
00542             fsmesh.channelSizeAttractforceStrength = length;
00543             
00544             fsmesh.channelAttractforceStrength = fobj->AttractforceStrength;
00545             fsmesh.channelAttractforceRadius = fobj->AttractforceRadius;
00546             fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength;
00547             fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius;
00548         }
00549         else {
00550             fsmesh.channelAttractforceStrength =
00551             fsmesh.channelAttractforceRadius = 
00552             fsmesh.channelVelocityforceStrength = 
00553             fsmesh.channelVelocityforceRadius = NULL; 
00554         }
00555         
00556         /* animated meshes */
00557         if(deform) {
00558             fsmesh.channelSizeVertices = length;
00559             fsmesh.channelVertices = fobj->VertexCache;
00560                 
00561             // remove channels
00562             fsmesh.channelTranslation      = 
00563             fsmesh.channelRotation         = 
00564             fsmesh.channelScale            = NULL; 
00565         }
00566         
00567         elbeemAddMesh(&fsmesh);
00568         
00569         if(verts) MEM_freeN(verts);
00570         if(tris) MEM_freeN(tris);
00571     }
00572 }
00573 
00574 static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDomain)
00575 {
00576     Base *base;
00577     Object *newdomain = NULL;
00578     int channelObjCount = 0;
00579     int fluidInputCount = 0;
00580 
00581     for(base=scene->base.first; base; base= base->next)
00582     {
00583         Object *ob = base->object;
00584         FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);            
00585 
00586         /* only find objects with fluid modifiers */
00587         if (!fluidmdtmp || ob->type != OB_MESH) continue;
00588             
00589         if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) {
00590             /* if no initial domain object given, find another potential domain */
00591             if (!fsDomain) {
00592                 newdomain = ob;
00593             }
00594             /* if there's more than one domain, cancel */
00595             else if (fsDomain && ob != fsDomain) {
00596                 BKE_report(reports, RPT_ERROR, "There should be only one domain object");
00597                 return 0;
00598             }
00599         }
00600         
00601         /* count number of objects needed for animation channels */
00602         if ( !ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE) )
00603             channelObjCount++;
00604         
00605         /* count number of fluid input objects */
00606         if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW))
00607             fluidInputCount++;
00608     }
00609 
00610     if (newdomain)
00611         fsDomain = newdomain;
00612     
00613     if (!fsDomain) {
00614         BKE_report(reports, RPT_ERROR, "No domain object found");
00615         return 0;
00616     }
00617     
00618     if (channelObjCount>=255) {
00619         BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects");
00620         return 0;
00621     }
00622     
00623     if (fluidInputCount == 0) {
00624         BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene");
00625         return 0;
00626     }
00627     
00628     return 1;
00629 }
00630 
00631 
00632 #define FLUID_SUFFIX_CONFIG     "fluidsim.cfg"
00633 #define FLUID_SUFFIX_SURFACE    "fluidsurface"
00634 
00635 static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer)
00636 {
00637     FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
00638     FluidsimSettings *domainSettings= fluidmd->fss; 
00639     FILE *fileCfg;
00640     int dirExist = 0;
00641     char newSurfdataPath[FILE_MAX]; // modified output settings
00642     const char *suffixConfig = FLUID_SUFFIX_CONFIG;
00643     int outStringsChanged = 0;
00644 
00645     // prepare names...
00646     const char *relbase= modifier_path_relbase(fsDomain);
00647 
00648     BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
00649     BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */
00650     BLI_path_abs(targetDir, relbase); // fixed #frame-no
00651 
00652     BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfig);
00653     /* .tmp: dont overwrite/delete original file */
00654     strncat(targetFile, ".tmp", FILE_MAX);
00655 
00656     // make sure all directories exist
00657     // as the bobjs use the same dir, this only needs to be checked
00658     // for the cfg output
00659     BLI_make_existing_file(targetFile);
00660     
00661     // check selected directory
00662     // simply try to open cfg file for writing to test validity of settings
00663     fileCfg = fopen(targetFile, "w");
00664     if(fileCfg) { 
00665         dirExist = 1; fclose(fileCfg); 
00666         // remove cfg dummy from  directory test
00667         BLI_delete(targetFile, 0,0);
00668     }
00669     
00670     if(targetDir[0] == '\0' || (!dirExist)) {
00671         char blendDir[FILE_MAX];
00672         char blendFile[FILE_MAX];
00673         
00674         // invalid dir, reset to current/previous
00675         BLI_strncpy(blendDir, G.main->name, FILE_MAX);
00676         BLI_splitdirstring(blendDir, blendFile);
00677         BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
00678 
00679         BLI_snprintf(newSurfdataPath, FILE_MAX ,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
00680         
00681         BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
00682         elbeemDebugOut(debugStrBuffer);
00683         outStringsChanged=1;
00684     }
00685     
00686     // check if modified output dir is ok
00687 #if 0
00688     if(outStringsChanged) {
00689         char dispmsg[FILE_MAX+256];
00690         int  selection=0;
00691         BLI_strncpy(dispmsg,"Output settings set to: '", sizeof(dispmsg));
00692         strcat(dispmsg, newSurfdataPath);
00693         strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0");
00694         
00695         // ask user if thats what he/she wants...
00696         selection = pupmenu(dispmsg);
00697         if(selection<1) return 0; // 0 from menu, or -1 aborted
00698         BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir));
00699         strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
00700         BLI_path_abs(targetDir, G.main->name); // fixed #frame-no 
00701     }
00702 #endif  
00703     return outStringsChanged;
00704 }
00705 
00706 /* ******************************************************************************** */
00707 /* ********************** write fluidsim config to file ************************* */
00708 /* ******************************************************************************** */
00709 
00710 typedef struct FluidBakeJob {
00711     /* from wmJob */
00712     void *owner;
00713     short *stop, *do_update;
00714     float *progress;
00715     int current_frame;
00716     elbeemSimulationSettings *settings;
00717 } FluidBakeJob;
00718 
00719 static void fluidbake_free(void *customdata)
00720 {
00721     FluidBakeJob *fb= (FluidBakeJob *)customdata;
00722     MEM_freeN(fb);
00723 }
00724 
00725 /* called by fluidbake, only to check job 'stop' value */
00726 static int fluidbake_breakjob(void *customdata)
00727 {
00728     FluidBakeJob *fb= (FluidBakeJob *)customdata;
00729 
00730     if(fb->stop && *(fb->stop))
00731         return 1;
00732     
00733     /* this is not nice yet, need to make the jobs list template better 
00734      * for identifying/acting upon various different jobs */
00735     /* but for now we'll reuse the render break... */
00736     return (G.afbreek);
00737 }
00738 
00739 /* called by fluidbake, wmJob sends notifier */
00740 static void fluidbake_updatejob(void *customdata, float progress)
00741 {
00742     FluidBakeJob *fb= (FluidBakeJob *)customdata;
00743     
00744     *(fb->do_update)= 1;
00745     *(fb->progress)= progress;
00746 }
00747 
00748 static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
00749 {
00750     FluidBakeJob *fb= (FluidBakeJob *)customdata;
00751     
00752     fb->stop= stop;
00753     fb->do_update = do_update;
00754     fb->progress = progress;
00755     
00756     G.afbreek= 0;   /* XXX shared with render - replace with job 'stop' switch */
00757     
00758     elbeemSimulate();
00759     *do_update= 1;
00760     *stop = 0;
00761 }
00762 
00763 static void fluidbake_endjob(void *customdata)
00764 {
00765     FluidBakeJob *fb= (FluidBakeJob *)customdata;
00766     
00767     if (fb->settings) {
00768         MEM_freeN(fb->settings);
00769         fb->settings = NULL;
00770     }
00771 }
00772 
00773 int runSimulationCallback(void *data, int status, int frame)
00774 {
00775     FluidBakeJob *fb = (FluidBakeJob *)data;
00776     elbeemSimulationSettings *settings = fb->settings;
00777     
00778     if (status == FLUIDSIM_CBSTATUS_NEWFRAME) {
00779         fluidbake_updatejob(fb, frame / (float)settings->noOfFrames);
00780         //printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d \n", status,frame, settings->domainId, settings->noOfFrames ); // DEBUG
00781     }
00782     
00783     if (fluidbake_breakjob(fb))  {
00784         return FLUIDSIM_CBRET_ABORT;
00785     }
00786     
00787     return FLUIDSIM_CBRET_CONTINUE;
00788 }
00789 
00790 static void fluidbake_free_data(FluidAnimChannels *channels, ListBase *fobjects, elbeemSimulationSettings *fsset, FluidBakeJob *fb)
00791 {
00792     free_domain_channels(channels);
00793     MEM_freeN(channels);
00794     channels = NULL;
00795 
00796     free_all_fluidobject_channels(fobjects);
00797     BLI_freelistN(fobjects);
00798     MEM_freeN(fobjects);
00799     fobjects = NULL;
00800     
00801     if (fsset) {
00802         MEM_freeN(fsset);
00803         fsset = NULL;
00804     }
00805     
00806     if (fb) {
00807         MEM_freeN(fb);
00808         fb = NULL;
00809     }
00810 }
00811 
00812 /* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
00813 static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
00814 {
00815     char targetDir[FILE_MAX], targetFile[FILE_MAX];
00816     char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX];
00817     char previewDir[FILE_MAX], previewFile[FILE_MAX];
00818     int curFrame = 1, exists = 0;
00819 
00820     BLI_join_dirfile(targetDir,    sizeof(targetDir),    fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
00821     BLI_join_dirfile(targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME);
00822     BLI_join_dirfile(previewDir,   sizeof(previewDir),   fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
00823 
00824     BLI_path_abs(targetDir,    relbase);
00825     BLI_path_abs(targetDirVel, relbase);
00826     BLI_path_abs(previewDir,   relbase);
00827 
00828     do {
00829         BLI_strncpy(targetFile, targetDir, sizeof(targetFile));
00830         BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel));
00831         BLI_strncpy(previewFile, previewDir, sizeof(previewFile));
00832 
00833         BLI_path_frame(targetFile, curFrame, 0);
00834         BLI_path_frame(targetFileVel, curFrame, 0);
00835         BLI_path_frame(previewFile, curFrame, 0);
00836 
00837         curFrame++;
00838 
00839         if((exists = BLI_exists(targetFile)))
00840         {
00841             BLI_delete(targetFile, 0, 0);
00842             BLI_delete(targetFileVel, 0, 0);
00843             BLI_delete(previewFile, 0, 0);
00844         }
00845     } while(exists);
00846 
00847     return;
00848 }
00849 
00850 static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
00851 {
00852     Scene *scene= CTX_data_scene(C);
00853     int i;
00854     FluidsimSettings *domainSettings;
00855 
00856     char debugStrBuffer[256];
00857     
00858     int gridlevels = 0;
00859     const char *relbase= modifier_path_relbase(fsDomain);
00860     const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
00861     const char *suffixConfig = FLUID_SUFFIX_CONFIG;
00862     const char *suffixSurface = FLUID_SUFFIX_SURFACE;
00863 
00864     char targetDir[FILE_MAX];  // store & modify output settings
00865     char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
00866     int  outStringsChanged = 0;             // modified? copy back before baking
00867 
00868     float domainMat[4][4];
00869     float invDomMat[4][4];
00870 
00871     int noFrames;
00872     int origFrame = scene->r.cfra;
00873     
00874     FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels");
00875     ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
00876     FluidsimModifierData *fluidmd = NULL;
00877     Mesh *mesh = NULL;
00878 
00879     FluidBakeJob *fb;
00880     elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings");
00881 
00882     fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
00883     
00884     if(getenv(strEnvName)) {
00885         int dlevel = atoi(getenv(strEnvName));
00886         elbeemSetDebugLevel(dlevel);
00887         BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer),"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName);
00888         elbeemDebugOut(debugStrBuffer);
00889     }
00890     
00891     /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */;
00892     noFrames = scene->r.efra - 0;
00893     if(noFrames<=0) {
00894         BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings");
00895         fluidbake_free_data(channels, fobjects, fsset, fb);
00896         return 0;
00897     }
00898     
00899     /* check scene for sane object/modifier settings */
00900     if (!fluid_validate_scene(reports, scene, fsDomain)) {
00901         fluidbake_free_data(channels, fobjects, fsset, fb);
00902         return 0;
00903     }
00904     
00905     /* these both have to be valid, otherwise we wouldnt be here */
00906     fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
00907     domainSettings = fluidmd->fss;
00908     mesh = fsDomain->data;
00909     
00910     domainSettings->bakeStart = 1;
00911     domainSettings->bakeEnd = scene->r.efra;
00912     
00913     // calculate bounding box
00914     fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize);
00915     
00916     // reset last valid frame
00917     domainSettings->lastgoodframe = -1;
00918 
00919     /* delete old baked files */
00920     fluidsim_delete_until_lastframe(domainSettings, relbase);
00921     
00922     /* rough check of settings... */
00923     if(domainSettings->previewresxyz > domainSettings->resolutionxyz) {
00924         BLI_snprintf(debugStrBuffer,sizeof(debugStrBuffer),"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz ,  domainSettings->resolutionxyz);
00925         elbeemDebugOut(debugStrBuffer);
00926         domainSettings->previewresxyz = domainSettings->resolutionxyz;
00927     }
00928     // set adaptive coarsening according to resolutionxyz
00929     // this should do as an approximation, with in/outflow
00930     // doing this more accurate would be overkill
00931     // perhaps add manual setting?
00932     if(domainSettings->maxRefine <0) {
00933         if(domainSettings->resolutionxyz>128) {
00934             gridlevels = 2;
00935         } else
00936         if(domainSettings->resolutionxyz>64) {
00937             gridlevels = 1;
00938         } else {
00939             gridlevels = 0;
00940         }
00941     } else {
00942         gridlevels = domainSettings->maxRefine;
00943     }
00944     BLI_snprintf(debugStrBuffer,sizeof(debugStrBuffer),"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels );
00945     elbeemDebugOut(debugStrBuffer);
00946     
00947     
00948     
00949     /* ******** prepare output file paths ******** */
00950     outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer);
00951     channels->length = scene->r.efra;
00952     channels->aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames;
00953     
00954     /* ******** initialise and allocate animation channels ******** */
00955     fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects);
00956 
00957     /* reset to original current frame */
00958     scene->r.cfra = origFrame;
00959     ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1);
00960     
00961     
00962     /* ---- XXX: No Time animation curve for now, leaving this code here for reference 
00963      
00964     { int timeIcu[1] = { FLUIDSIM_TIME };
00965         float timeDef[1] = { 1. };
00966 
00967         // time channel is a bit special, init by hand...
00968         timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex");
00969         for(i=0; i<=scene->r.efra; i++) {
00970             timeAtIndex[i] = (float)(i-startFrame);
00971         }
00972         fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
00973         // time channel is a multiplicator for 
00974         if(channelDomainTime) {
00975             for(i=0; i<allchannelSize; i++) { 
00976                 channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; 
00977                 if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.;
00978             }
00979         }
00980         timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe");
00981         timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1
00982         if(channelDomainTime) {
00983             for(i=2; i<=allchannelSize; i++) {
00984                 timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0];
00985             }
00986         fsset->} else {
00987             for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; }
00988         }
00989 
00990     } // domain channel init
00991     */
00992         
00993     /* ******** init domain object's matrix ******** */
00994     copy_m4_m4(domainMat, fsDomain->obmat);
00995     if(!invert_m4_m4(invDomMat, domainMat)) {
00996         BLI_snprintf(debugStrBuffer,sizeof(debugStrBuffer),"fluidsimBake::error - Invalid obj matrix?\n");
00997         elbeemDebugOut(debugStrBuffer);
00998         BKE_report(reports, RPT_ERROR, "Invalid object matrix"); 
00999 
01000         fluidbake_free_data(channels, fobjects, fsset, fb);
01001         return 0;
01002     }
01003 
01004     /* ********  start writing / exporting ******** */
01005     // use .tmp, dont overwrite/delete original file
01006     BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfig);
01007     strncat(targetFile, ".tmp", sizeof(targetFile));
01008     
01009     // make sure these directories exist as well
01010     if(outStringsChanged) {
01011         BLI_make_existing_file(targetFile);
01012     }
01013 
01014     /* ******** export domain to elbeem ******** */
01015     elbeemResetSettings(fsset);
01016     fsset->version = 1;
01017 
01018     // setup global settings
01019     copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
01020     copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
01021     
01022     // simulate with 50^3
01023     fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
01024     fsset->previewresxyz = (int)domainSettings->previewresxyz;
01025 
01026     fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
01027     fsset->viscosity = get_fluid_viscosity(domainSettings);
01028     get_fluid_gravity(fsset->gravity, scene, domainSettings);
01029 
01030     // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
01031     fsset->animStart = domainSettings->animStart;
01032     fsset->aniFrameTime = channels->aniFrameTime;
01033     fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
01034 
01035     BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
01036 
01037     // defaults for compressibility and adaptive grids
01038     fsset->gstar = domainSettings->gstar;
01039     fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
01040     fsset->generateParticles = domainSettings->generateParticles; 
01041     fsset->numTracerParticles = domainSettings->generateTracers; 
01042     fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; 
01043     fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; 
01044     fsset->farFieldSize = domainSettings->farFieldSize; 
01045     BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
01046 
01047     // domain channels
01048     fsset->channelSizeFrameTime = 
01049     fsset->channelSizeViscosity = 
01050     fsset->channelSizeGravity = channels->length;
01051     fsset->channelFrameTime = channels->DomainTime;
01052     fsset->channelViscosity = channels->DomainViscosity;
01053     fsset->channelGravity = channels->DomainGravity;
01054     
01055     fsset->runsimCallback = &runSimulationCallback;
01056     fsset->runsimUserData = fb;
01057 
01058     if (domainSettings->typeFlags & OB_FSBND_NOSLIP)        fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
01059     else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP)   fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
01060     else if (domainSettings->typeFlags&OB_FSBND_FREESLIP)   fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
01061     fsset->domainobsPartslip = domainSettings->partSlipValue;
01062 
01063     /* use domainobsType also for surface generation flag (bit: >=64) */
01064     if(domainSettings->typeFlags & OB_FSSG_NOOBS)
01065         fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS;
01066     else
01067         fsset->mFsSurfGenSetting = 0; // "normal" mode
01068 
01069     fsset->generateVertexVectors = (domainSettings->domainNovecgen==0);
01070 
01071     // init blender domain transform matrix
01072     { int j; 
01073     for(i=0; i<4; i++) {
01074         for(j=0; j<4; j++) {
01075             fsset->surfaceTrafo[i*4+j] = invDomMat[j][i];
01076         }
01077     } }
01078 
01079     /* ******** init solver with settings ******** */
01080     elbeemInit();
01081     elbeemAddDomain(fsset);
01082     
01083     /* ******** export all fluid objects to elbeem ******** */
01084     export_fluid_objects(fobjects, scene, channels->length);
01085     
01086     /* custom data for fluid bake job */
01087     fb->settings = fsset;
01088     
01089     if(do_job) {
01090         wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS);
01091 
01092         /* setup job */
01093         WM_jobs_customdata(steve, fb, fluidbake_free);
01094         WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
01095         WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
01096 
01097         WM_jobs_start(CTX_wm_manager(C), steve);
01098     }
01099     else {
01100         short dummy_stop, dummy_do_update;
01101         float dummy_progress;
01102 
01103         /* blocking, use with exec() */
01104         fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
01105         fluidbake_endjob((void *)fb);
01106         fluidbake_free((void *)fb);
01107     }
01108 
01109     /* ******** free stored animation data ******** */
01110     fluidbake_free_data(channels, fobjects, NULL, NULL);
01111 
01112     // elbeemFree();
01113     return 1;
01114 }
01115 
01116 void fluidsimFreeBake(Object *UNUSED(ob))
01117 {
01118     /* not implemented yet */
01119 }
01120 
01121 #else /* WITH_MOD_FLUID */
01122 
01123 /* compile dummy functions for disabled fluid sim */
01124 
01125 FluidsimSettings *fluidsimSettingsNew(Object *UNUSED(srcob))
01126 {
01127     return NULL;
01128 }
01129 
01130 void fluidsimSettingsFree(FluidsimSettings *UNUSED(fss))
01131 {
01132 }
01133 
01134 FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *UNUSED(fss))
01135 {
01136     return NULL;
01137 }
01138 
01139 /* only compile dummy functions */
01140 static int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object *UNUSED(ob), short UNUSED(do_job))
01141 {
01142     return 0;
01143 }
01144 
01145 #endif /* WITH_MOD_FLUID */
01146 
01147 /***************************** Operators ******************************/
01148 
01149 static int fluid_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
01150 {
01151     /* only one bake job at a time */
01152     if(WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
01153         return OPERATOR_CANCELLED;
01154 
01155     if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), TRUE))
01156         return OPERATOR_CANCELLED;
01157 
01158     return OPERATOR_FINISHED;
01159 }
01160 
01161 static int fluid_bake_exec(bContext *C, wmOperator *op)
01162 {
01163     if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), FALSE))
01164         return OPERATOR_CANCELLED;
01165 
01166     return OPERATOR_FINISHED;
01167 }
01168 
01169 void FLUID_OT_bake(wmOperatorType *ot)
01170 {
01171     /* identifiers */
01172     ot->name= "Fluid Simulation Bake";
01173     ot->description= "Bake fluid simulation";
01174     ot->idname= "FLUID_OT_bake";
01175     
01176     /* api callbacks */
01177     ot->invoke= fluid_bake_invoke;
01178     ot->exec= fluid_bake_exec;
01179     ot->poll= ED_operator_object_active_editable;
01180 }
01181