Blender V2.61 - r43446
|
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