Blender  V2.59
physics_fluid.c
Go to the documentation of this file.
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