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