From 33f880e8666e9bb0ed954fccb82bc23255a97868 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 25 Mar 2010 06:27:25 +0000 Subject: Restored Fluid Sim baking This commit restores fluid sim baking functionality in 2.5, it's been on the todo for a while, and was previously almost completely non-functional. The old code was quite complicated and specific to the 2.4 animation system, so I've pretty much rewritten most of it. This includes: * Animated variables work again - just key them in the UI. Non-animateable values should be already set non-animateable in RNA, hopefully I got them all. Available are: Domain Gravity / Domain Viscosity / Object loc/rot/scale / Object initial velocity / Deforming meshes / Fluid control Attract strength / Fluid control Attract radius / Fluid control Velocity strength / Fluid control Velocity radius / Object Active status (checkbox next to fluid type) The Domain time scale is still not yet implemented. * Fluid sim now use global scene units data by default - when enabled, the scene's global gravity value is used and when units are set (metric/imperial) the simulation real world size is taken from the object's actual measurements. * The baking process is now done in the background, using the nifty threaded Jobs system. It's non-blocking and your domain object will show the simulated fluid as it becomes available for that frame. A nice extra thing for the future would be to improve the visualisation of the object's state while baking, and also the jobs system/ui could do with some touchups - currently it has to share a bit from the 'render' job, and appears as 'Render' in the header. Progress bars for jobs in the header would be great too. --- source/blender/blenkernel/BKE_object.h | 2 + source/blender/blenkernel/intern/fluidsim.c | 2 +- source/blender/blenkernel/intern/object.c | 38 + source/blender/blenloader/intern/readfile.c | 4 +- source/blender/editors/include/ED_fluidsim.h | 2 - source/blender/editors/physics/physics_fluid.c | 1552 +++++++++----------- .../blender/editors/space_buttons/space_buttons.c | 1 + source/blender/makesdna/DNA_object_fluidsim.h | 10 +- source/blender/makesrna/intern/rna_fluidsim.c | 79 +- source/blender/makesrna/intern/rna_object.c | 32 +- 10 files changed, 825 insertions(+), 897 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 1362a191919..84995b60f4b 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -111,6 +111,8 @@ void where_is_object_simul(struct Scene *scene, struct Object *ob); struct BoundBox *unit_boundbox(void); void boundbox_set_from_min_max(struct BoundBox *bb, float min[3], float max[3]); struct BoundBox *object_get_boundbox(struct Object *ob); +void object_get_dimensions(struct Object *ob, float *value); +void object_set_dimensions(struct Object *ob, const float *value); void object_boundbox_flag(struct Object *ob, int flag, int set); void minmax_object(struct Object *ob, float *min, float *max); int minmax_object_duplis(struct Scene *scene, struct Object *ob, float *min, float *max); diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index fe0f52e9b00..118a44507c9 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -148,7 +148,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd) fss->lastgoodframe = -1; - fss->flag = 0; + fss->flag |= OB_FLUIDSIM_ACTIVE; } #endif diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 64abffa5119..e4350cfde7f 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2305,6 +2305,44 @@ void object_boundbox_flag(Object *ob, int flag, int set) } } +void object_get_dimensions(Object *ob, float *value) +{ + BoundBox *bb = NULL; + + bb= object_get_boundbox(ob); + if (bb) { + float scale[3]; + + mat4_to_size( scale,ob->obmat); + + value[0] = fabs(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]); + value[1] = fabs(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]); + value[2] = fabs(scale[2]) * (bb->vec[1][2] - bb->vec[0][2]); + } else { + value[0] = value[1] = value[2] = 0.f; + } +} + +void object_set_dimensions(Object *ob, const float *value) +{ + BoundBox *bb = NULL; + + bb= object_get_boundbox(ob); + if (bb) { + float scale[3], len[3]; + + mat4_to_size( scale,ob->obmat); + + len[0] = bb->vec[4][0] - bb->vec[0][0]; + len[1] = bb->vec[2][1] - bb->vec[0][1]; + len[2] = bb->vec[1][2] - bb->vec[0][2]; + + if (len[0] > 0.f) ob->size[0] = value[0] / len[0]; + if (len[1] > 0.f) ob->size[1] = value[1] / len[1]; + if (len[2] > 0.f) ob->size[2] = value[2] / len[2]; + } +} + void minmax_object(Object *ob, float *min, float *max) { BoundBox bb; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a894df1bd79..dbdd1685c81 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -10659,8 +10659,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for(md= ob->modifiers.first; md; md= md->next) { if (md->type == eModifierType_Fluidsim) { FluidsimModifierData *fmd = (FluidsimModifierData *)md; - /* fmd->fss->flag |= OB_FLUIDSIM_ACTIVE; - temporarily commented out for matt_ebb */ + fmd->fss->flag |= OB_FLUIDSIM_ACTIVE; + fmd->fss->flag |= OB_FLUIDSIM_OVERRIDE_TIME; } } } diff --git a/source/blender/editors/include/ED_fluidsim.h b/source/blender/editors/include/ED_fluidsim.h index 8a9a294d423..a1ab3ba2fcc 100644 --- a/source/blender/editors/include/ED_fluidsim.h +++ b/source/blender/editors/include/ED_fluidsim.h @@ -34,8 +34,6 @@ struct Object; struct FluidsimSettings; -extern double fluidsimViscosityPreset[6]; -extern char* fluidsimViscosityPresetString[6]; /* allocates and initializes fluidsim data */ struct FluidsimSettings* fluidsimSettingsNew(struct Object *srcob); diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 8c05a4efcf6..6f5b8924a13 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -45,12 +45,17 @@ #include "MEM_guardedalloc.h" /* types */ +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_object_types.h" #include "DNA_object_fluidsim.h" #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_math.h" +#include "BKE_animsys.h" +#include "BKE_armature.h" #include "BKE_blender.h" #include "BKE_context.h" #include "BKE_customdata.h" @@ -67,6 +72,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_softbody.h" +#include "BKE_unit.h" #include "LBM_fluidsim.h" @@ -90,77 +96,102 @@ #include "PIL_time.h" -/* XXX */ -/* from header info.c */ -static int start_progress_bar(void) {return 0;}; -static void end_progress_bar(struct wmWindow *win) {WM_cursor_restore(win);}; -static void waitcursor(int val) {}; -static int progress_bar(wmWindow *win, float done, char *busy_info) { WM_timecursor(win,done*100); return 0;} -static int pupmenu() {return 0;} -/* XXX */ - - -double fluidsimViscosityPreset[6] = { - -1.0, /* unused */ - -1.0, /* manual */ - 1.0e-6, /* water */ - 5.0e-5, /* some (thick) oil */ - 2.0e-3, /* ca. honey */ - -1.0 /* end */ -}; - -char* fluidsimViscosityPresetString[6] = { - "UNUSED", /* unused */ - "UNUSED", /* manual */ - " = 1.0 * 10^-6", /* water */ - " = 5.0 * 10^-5", /* some (thick) oil */ - " = 2.0 * 10^-3", /* ca. honey */ - "INVALID" /* end */ -}; + +static float get_fluid_viscosity(FluidsimSettings *settings) +{ + switch (settings->viscosityMode) { + case 0: /* unused */ + return -1.0; + case 2: /* water */ + return 1.0e-6; + case 3: /* some (thick) oil */ + return 5.0e-5; + case 4: /* ca. honey */ + return 2.0e-3; + case 1: /* manual */ + default: + return (1.0/pow(10.0, settings->viscosityExponent)) * settings->viscosityValue; + } +} + +static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss) +{ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(gravity, scene->physics_settings.gravity); + } else { + copy_v3_v3(gravity, &fss->gravx); + } +} + +static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss) +{ + if (!scene->unit.system) { + return fss->realsize; + } else { + float dim[3]; + float longest_axis; + + object_get_dimensions(domainob, dim); + longest_axis = MAX3(dim[0], dim[1], dim[2]); + + return longest_axis * scene->unit.scale_length; + } +} + +static int fluid_is_animated_mesh(FluidsimSettings *fss) +{ + return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen); +} /* ********************** fluid sim settings struct functions ********************** */ +#if 0 /* helper function */ void fluidsimGetGeometryObjFilename(Object *ob, char *dst) { //, char *srcname) { //snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name); snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name); } +#endif - - -/* ******************************************************************************** */ /* ********************** fluid sim channel helper functions ********************** */ -/* ******************************************************************************** */ + +typedef struct FluidAnimChannels { + int length; + + double aniFrameTime; + + float *timeAtFrame; + float *DomainTime; + float *DomainGravity; + float *DomainViscosity; +} FluidAnimChannels; + +typedef struct FluidObject { + struct FluidObject *next, *prev; + + struct Object *object; + + float *Translation; + float *Rotation; + float *Scale; + float *Active; + + float *InitialVelocity; + + float *AttractforceStrength; + float *AttractforceRadius; + float *VelocityforceStrength; + float *VelocityforceRadius; + + float *VertexCache; + int numVerts, numTris; +} FluidObject; // no. of entries for the two channel sizes #define CHANNEL_FLOAT 1 #define CHANNEL_VEC 3 -#define FS_FREE_ONECHANNEL(c,str) { \ - if(c){ MEM_freeN(c); c=NULL; } \ -} // end ONE CHANN, debug: fprintf(stderr,"freeing " str " \n"); - -#define FS_FREE_CHANNELS { \ - FS_FREE_ONECHANNEL(timeAtIndex,"timeAtIndex");\ - FS_FREE_ONECHANNEL(timeAtFrame,"timeAtFrame");\ - FS_FREE_ONECHANNEL(channelDomainTime,"channelDomainTime"); \ - FS_FREE_ONECHANNEL(channelDomainGravity,"channelDomainGravity");\ - FS_FREE_ONECHANNEL(channelDomainViscosity,"channelDomainViscosity");\ - for(i=0;i<256;i++) { \ - FS_FREE_ONECHANNEL(channelObjMove[i][0],"channelObjMove0"); \ - FS_FREE_ONECHANNEL(channelObjMove[i][1],"channelObjMove1"); \ - FS_FREE_ONECHANNEL(channelObjMove[i][2],"channelObjMove2"); \ - FS_FREE_ONECHANNEL(channelObjInivel[i],"channelObjInivel"); \ - FS_FREE_ONECHANNEL(channelObjActive[i],"channelObjActive"); \ - FS_FREE_ONECHANNEL(channelAttractforceStrength[i],"channelAttractforceStrength"); \ - FS_FREE_ONECHANNEL(channelAttractforceRadius[i],"channelAttractforceRadius"); \ - FS_FREE_ONECHANNEL(channelVelocityforceStrength[i],"channelVelocityforceStrength"); \ - FS_FREE_ONECHANNEL(channelVelocityforceRadius[i],"channelVelocityforceRadius"); \ - } \ -} // end FS FREE CHANNELS - - // simplify channels before printing // for API this is done anyway upon init #if 0 @@ -191,336 +222,616 @@ static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char } #endif -static void fluidsimInitChannel(Scene *scene, float **setchannel, int size, float *time, - int *icuIds, float *defaults, Ipo* ipo, int entries) + +/* Note: fluid anim channel data layout + * ------------------------------------ + * CHANNEL_FLOAT: + * frame 1 |frame 2 + * [dataF][time][dataF][time] + * + * CHANNEL_VEC: + * frame 1 |frame 2 + * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time] + * + */ + +static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels) { + int i; + + channels->timeAtFrame = MEM_callocN( (channels->length+1)*sizeof(float), "timeAtFrame channel"); + + channels->timeAtFrame[0] = channels->timeAtFrame[1] = domainSettings->animStart; // start at index 1 + + for(i=2; i<=channels->length; i++) { + channels->timeAtFrame[i] = channels->timeAtFrame[i-1] + channels->aniFrameTime; + } +} + +/* if this is slow, can replace with faster, less readable code */ +static void set_channel(float *channel, float time, float *value, int i, int size) +{ + if (size == CHANNEL_FLOAT) { + channel[(i * 2) + 0] = value[0]; + channel[(i * 2) + 1] = time; + } + else if (size == CHANNEL_VEC) { + channel[(i * 4) + 0] = value[0]; + channel[(i * 4) + 1] = value[1]; + channel[(i * 4) + 2] = value[2]; + channel[(i * 4) + 3] = time; + } +} - int i, j; - char *cstr = NULL; - float *channel = NULL; +static void set_vertex_channel(float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i) +{ + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + float *verts; + int *tris=NULL, numVerts=0, numTris=0; + int modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd); + int framesize = (3*fobj->numVerts) + 1; + int j; + + if (channel == NULL) + return; - cstr = "fluidsiminit_channelfloat"; - if(entries>1) cstr = "fluidsiminit_channelvec"; - channel = MEM_callocN( size* (entries+1)* sizeof(float), cstr ); + initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); - /* defaults for now */ - for(j=0; jnumVerts) { + MEM_freeN(channel); + channel = NULL; + return; } - for(i=1; i<=size; i++) { - channel[(i-1)*(entries+1) + entries] = time[i]; + /* fill frame of channel with vertex locations */ + for(j=0; j < (3*numVerts); j++) { + channel[i*framesize + j] = verts[j]; } + channel[i*framesize + framesize-1] = time; + + MEM_freeN(verts); + MEM_freeN(tris); +} - *setchannel = channel; +static void free_domain_channels(FluidAnimChannels *channels) +{ + MEM_freeN(channels->timeAtFrame); + channels->timeAtFrame = NULL; + MEM_freeN(channels->DomainGravity); + channels->DomainGravity = NULL; + MEM_freeN(channels->DomainViscosity); + channels->DomainViscosity = NULL; +} -#if 0 - /* goes away completely */ - int i,j; - IpoCurve* icus[3]; - char *cstr = NULL; - float *channel = NULL; - float aniFrlen = scene->r.framelen; - int current_frame = scene->r.cfra; - if((entries<1) || (entries>3)) { - printf("fluidsimInitChannel::Error - invalid no. of entries: %d\n",entries); - entries = 1; +static void free_all_fluidobject_channels(ListBase *fobjects) +{ + FluidObject *fobj; + + for (fobj=fobjects->first; fobj; fobj=fobj->next) { + if (fobj->Translation) { + MEM_freeN(fobj->Translation); + fobj->Translation = NULL; + MEM_freeN(fobj->Rotation); + fobj->Rotation = NULL; + MEM_freeN(fobj->Scale); + fobj->Scale = NULL; + MEM_freeN(fobj->Active); + fobj->Active = NULL; + MEM_freeN(fobj->InitialVelocity); + fobj->InitialVelocity = NULL; + } + + if (fobj->AttractforceStrength) { + MEM_freeN(fobj->AttractforceStrength); + fobj->AttractforceStrength = NULL; + MEM_freeN(fobj->AttractforceRadius); + fobj->AttractforceRadius = NULL; + MEM_freeN(fobj->VelocityforceStrength); + fobj->VelocityforceStrength = NULL; + MEM_freeN(fobj->VelocityforceRadius); + fobj->VelocityforceRadius = NULL; + } + + if (fobj->VertexCache) { + MEM_freeN(fobj->VertexCache); + fobj->VertexCache = NULL; + } } +} - cstr = "fluidsiminit_channelfloat"; - if(entries>1) cstr = "fluidsiminit_channelvec"; - channel = MEM_callocN( size* (entries+1)* sizeof(float), cstr ); +static void fluid_init_all_channels(bContext *C, Object *fsDomain, FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects) +{ + Scene *scene = CTX_data_scene(C); + Base *base; + int i; + int length = channels->length; + float eval_time; - if(ipo) { - for(j=0; jr.cfra = floor(aniFrlen*((float)i)); + /* allocate domain animation channels */ + channels->DomainGravity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "channel DomainGravity"); + channels->DomainViscosity = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainViscosity"); + //channels->DomainTime = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainTime"); + + /* allocate fluid objects */ + for (base=scene->base.first; base; base= base->next) { + Object *ob = base->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + + if (fluidmd) { + FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object"); + fobj->object = ob; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { + BLI_addtail(fobjects, fobj); + continue; + } + + fobj->Translation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Translation"); + fobj->Rotation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Rotation"); + fobj->Scale = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Scale"); + fobj->Active = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject Active"); + fobj->InitialVelocity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject InitialVelocity"); + + if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { + fobj->AttractforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceStrength"); + fobj->AttractforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceRadius"); + fobj->VelocityforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceStrength"); + fobj->VelocityforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceRadius"); + } + + if (fluid_is_animated_mesh(fluidmd->fss)) { + float *verts=NULL; + int *tris=NULL, modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd); + + initElbeemMesh(scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex); + fobj->VertexCache = MEM_callocN( length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache"); - // XXX calc_icu(icus[j], aniFrlen*((float)i) ); - channel[(i-1)*(entries+1) + j] = icus[j]->curval; + MEM_freeN(verts); + MEM_freeN(tris); } - } else { - for(i=1; i<=size; i++) { channel[(i-1)*(entries+1) + j] = defaults[j]; } + + BLI_addtail(fobjects, fobj); } - //printf("fluidsimInitChannel entry:%d , ",j); for(i=1; i<=size; i++) { printf(" val%d:%f ",i, channel[(i-1)*(entries+1) + j] ); } printf(" \n"); // DEBUG } - // set time values - for(i=1; i<=size; i++) { - channel[(i-1)*(entries+1) + entries] = time[i]; + + /* now we loop over the frames and fill the allocated channels with data */ + for (i=0; ilength; i++) { + FluidObject *fobj; + float viscosity, gravity[3]; + float timeAtFrame; + + eval_time = domainSettings->bakeStart + i; + timeAtFrame = channels->timeAtFrame[i+1]; + + /* XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation, + * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) + * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); + * This doesn't work with drivers: + * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); + */ + + /* Modifying the global scene isn't nice, but we can do it in + * this part of the process before a threaded job is created */ + scene->r.cfra = (int)eval_time; + ED_update_for_newframe(C, 1); + + /* now scene data should be current according to animation system, so we fill the channels */ + + /* Domain properties - gravity/viscosity/time */ + get_fluid_gravity(gravity, scene, domainSettings); + set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC); + viscosity = get_fluid_viscosity(domainSettings); + set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT); + // XXX : set_channel(channels->DomainTime, timeAtFrame, &time, i, CHANNEL_VEC); + + /* object movement */ + for (fobj=fobjects->first; fobj; fobj=fobj->next) { + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + float active= (float)(fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE); + float rot_d[3], rot_360[3] = {360.f, 360.f, 360.f}; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) + continue; + + /* init euler rotation values and convert to elbeem format */ + BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotAxis, &ob->rotAngle, ob->rotmode, ROT_MODE_EUL); + mul_v3_v3fl(rot_d, ob->rot, 180.f/M_PI); + sub_v3_v3v3(rot_d, rot_360, rot_d); + + set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC); + set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC); + set_channel(fobj->Scale, timeAtFrame, ob->size, i, CHANNEL_VEC); + set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); + set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); + + if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { + set_channel(fobj->AttractforceStrength, timeAtFrame, &fluidmd->fss->attractforceStrength, i, CHANNEL_FLOAT); + set_channel(fobj->AttractforceRadius, timeAtFrame, &fluidmd->fss->attractforceRadius, i, CHANNEL_FLOAT); + set_channel(fobj->VelocityforceStrength, timeAtFrame, &fluidmd->fss->velocityforceStrength, i, CHANNEL_FLOAT); + set_channel(fobj->VelocityforceRadius, timeAtFrame, &fluidmd->fss->velocityforceRadius, i, CHANNEL_FLOAT); + } + + if (fluid_is_animated_mesh(fluidmd->fss)) { + set_vertex_channel(fobj->VertexCache, timeAtFrame, scene, fobj, i); + } + } } - scene->r.cfra = current_frame; - *setchannel = channel; -#endif } -static void fluidsimInitMeshChannel(bContext *C, float **setchannel, int size, Object *obm, int vertices, - float *time, int modifierIndex) +static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length) { - Scene *scene= CTX_data_scene(C); - float *channel = NULL; - int mallsize = size* (3*vertices+1); - int frame,i; - int numVerts=0, numTris=0; - int setsize = 3*vertices+1; - - channel = MEM_callocN( mallsize* sizeof(float), "fluidsim_meshchannel" ); - - //fprintf(stderr,"\n\nfluidsimInitMeshChannel size%d verts%d mallsize%d \n\n\n",size,vertices,mallsize); - for(frame=1; frame<=size; frame++) { + FluidObject *fobj; + + for (fobj=fobjects->first; fobj; fobj=fobj->next) { + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + int modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd); + float *verts=NULL; int *tris=NULL; - scene->r.cfra = frame; - ED_update_for_newframe(C, 1); + int numVerts=0, numTris=0; + int deform = fluid_is_animated_mesh(fluidmd->fss); + + elbeemMesh fsmesh; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) + continue; + + elbeemResetMesh( &fsmesh ); + + fsmesh.type = fluidmd->fss->type; + fsmesh.name = ob->id.name; + + initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex); + + fsmesh.numVertices = numVerts; + fsmesh.numTriangles = numTris; + fsmesh.vertices = verts; + fsmesh.triangles = tris; + + fsmesh.channelSizeTranslation = + fsmesh.channelSizeRotation = + fsmesh.channelSizeScale = + fsmesh.channelSizeInitialVel = + fsmesh.channelSizeActive = length; + + fsmesh.channelTranslation = fobj->Translation; + fsmesh.channelRotation = fobj->Rotation; + fsmesh.channelScale = fobj->Scale; + fsmesh.channelActive = fobj->Active; + + if( ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) { + fsmesh.channelInitialVel = fobj->InitialVelocity; + fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD)?1:0); + } + + if(fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; + else if(fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP; + else if(fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP; + + fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue; + fsmesh.volumeInitType = fluidmd->fss->volumeInitType; + fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value + + if (fsmesh.type == OB_FLUIDSIM_CONTROL) { + fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart; + fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd; + fsmesh.cpsQuality = fluidmd->fss->cpsQuality; + fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE); + + fsmesh.channelSizeAttractforceRadius = + fsmesh.channelSizeVelocityforceStrength = + fsmesh.channelSizeVelocityforceRadius = + fsmesh.channelSizeAttractforceStrength = length; + + fsmesh.channelAttractforceStrength = fobj->AttractforceStrength; + fsmesh.channelAttractforceRadius = fobj->AttractforceRadius; + fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength; + fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius; + } + else { + fsmesh.channelAttractforceStrength = + fsmesh.channelAttractforceRadius = + fsmesh.channelVelocityforceStrength = + fsmesh.channelVelocityforceRadius = NULL; + } + + /* animated meshes */ + if(deform) { + fsmesh.channelSizeVertices = length; + fsmesh.channelVertices = fobj->VertexCache; + + // remove channels + fsmesh.channelTranslation = + fsmesh.channelRotation = + fsmesh.channelScale = NULL; + } + + elbeemAddMesh(&fsmesh); + + if(verts) MEM_freeN(verts); + if(tris) MEM_freeN(tris); + if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices); + } +} + +static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDomain) +{ + Base *base; + Object *newdomain = NULL; + int channelObjCount = 0; + int fluidInputCount = 0; - initElbeemMesh(scene, obm, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); - //fprintf(stderr,"\nfluidsimInitMeshChannel frame%d verts%d/%d \n\n",frame,vertices,numVerts); - for(i=0; i<3*vertices;i++) { - channel[(frame-1)*setsize + i] = verts[i]; - //fprintf(stdout," frame%d vert%d=%f \n",frame,i,verts[i]); - //if(i%3==2) fprintf(stdout,"\n"); + for(base=scene->base.first; base; base= base->next) + { + Object *ob = base->object; + FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + + /* only find objects with fluid modifiers */ + if (!fluidmdtmp || ob->type != OB_MESH) continue; + + if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) { + /* if no initial domain object given, find another potential domain */ + if (!fsDomain) { + newdomain = ob; + } + /* if there's more than one domain, cancel */ + else if (fsDomain && ob != fsDomain) { + BKE_report(reports, RPT_ERROR, "There should be only one domain object."); + return 0; + } } - channel[(frame-1)*setsize + setsize-1] = time[frame]; + + /* count number of objects needed for animation channels */ + if ( !ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE) ) + channelObjCount++; + + /* count number of fluid input objects */ + if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) + fluidInputCount++; + } - MEM_freeN(verts); - MEM_freeN(tris); + if (newdomain) + fsDomain = newdomain; + + if (!fsDomain) { + BKE_report(reports, RPT_ERROR, "No domain object found."); + return 0; + } + + if (channelObjCount>=255) { + BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects."); + return 0; } - *setchannel = channel; + + if (fluidInputCount == 0) { + BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene."); + return 0; + } + + return 1; } -/* ******************************************************************************** */ -/* ********************** simulation thread ************************* */ -/* ******************************************************************************** */ +#define FLUID_SUFFIX_CONFIG "fluidsim.cfg" +#define FLUID_SUFFIX_SURFACE "fluidsurface" -static volatile int globalBakeState = 0; // 0 everything ok, -1 abort simulation, -2 sim error, 1 sim done -static volatile int globalBakeFrame = 0; -static volatile int g_break= 0; - -// run simulation in seperate thread -static void *fluidsimSimulateThread(void *unused) { // *ptr) { - //char* fnameCfgPath = (char*)(ptr); - int ret=0; - - ret = elbeemSimulate(); - BLI_lock_thread(LOCK_CUSTOM1); - if(globalBakeState==0) { - if(ret==0) { - // if no error, set to normal exit - globalBakeState = 1; - } else { - // simulation failed, display error - globalBakeState = -2; +static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer) +{ + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); + FluidsimSettings *domainSettings= fluidmd->fss; + FILE *fileCfg; + int dirExist = 0; + char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings + char *suffixConfig = FLUID_SUFFIX_CONFIG; + int outStringsChanged = 0; + + // prepare names... + strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); + strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, G.sce); // fixed #frame-no + + strcpy(targetFile, targetDir); + strcat(targetFile, suffixConfig); + strcat(targetFile,".tmp"); // dont overwrite/delete original file + // make sure all directories exist + // as the bobjs use the same dir, this only needs to be checked + // for the cfg output + BLI_make_existing_file(targetFile); + + // check selected directory + // simply try to open cfg file for writing to test validity of settings + fileCfg = fopen(targetFile, "w"); + if(fileCfg) { + dirExist = 1; fclose(fileCfg); + // remove cfg dummy from directory test + BLI_delete(targetFile, 0,0); + } + + if((strlen(targetDir)<1) || (!dirExist)) { + char blendDir[FILE_MAXDIR+FILE_MAXFILE]; + char blendFile[FILE_MAXDIR+FILE_MAXFILE]; + + // invalid dir, reset to current/previous + strcpy(blendDir, G.sce); + BLI_splitdirstring(blendDir, blendFile); + if(strlen(blendFile)>6){ + int len = strlen(blendFile); + if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&& + (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){ + blendFile[len-6] = '\0'; + } } + // todo... strip .blend ? + snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); + + snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); + elbeemDebugOut(debugStrBuffer); + outStringsChanged=1; } - BLI_unlock_thread(LOCK_CUSTOM1); - return NULL; + + // check if modified output dir is ok +#if 0 + if(outStringsChanged) { + char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256]; + int selection=0; + strcpy(dispmsg,"Output settings set to: '"); + strcat(dispmsg, newSurfdataPath); + strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0"); + + // ask user if thats what he/she wants... + selection = pupmenu(dispmsg); + if(selection<1) return 0; // 0 from menu, or -1 aborted + strcpy(targetDir, newSurfdataPath); + strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, G.sce); // fixed #frame-no + } +#endif + return outStringsChanged; +} + +/* ******************************************************************************** */ +/* ********************** write fluidsim config to file ************************* */ +/* ******************************************************************************** */ + +typedef struct FluidBakeJob { + /* from wmJob */ + void *owner; + short *stop, *do_update; + + int current_frame; + elbeemSimulationSettings *settings; +} FluidBakeJob; + +static void fluidbake_free(void *customdata) +{ + FluidBakeJob *fb= customdata; + MEM_freeN(fb); +} + +/* called by fluidbake, only to check job 'stop' value */ +static int fluidbake_breakjob(void *customdata) +{ + //FluidBakeJob *fb= (FluidBakeJob *)customdata; + //return *(fb->stop); + + /* this is not nice yet, need to make the jobs list template better + * for identifying/acting upon various different jobs */ + /* but for now we'll reuse the render break... */ + return (G.afbreek); +} + +/* called by fluidbake, wmJob sends notifier */ +static void fluidbake_updatejob(void *customdata, char *str) +{ + FluidBakeJob *fb= customdata; + + *(fb->do_update)= 1; } +static void fluidbake_startjob(void *customdata, short *stop, short *do_update) +{ + FluidBakeJob *fb= customdata; + + fb->stop= stop; + fb->do_update = do_update; + + G.afbreek= 0; /* XXX shared with render - replace with job 'stop' switch */ + + elbeemSimulate(); + *do_update= 1; + *stop = 0; +} int runSimulationCallback(void *data, int status, int frame) { - //elbeemSimulationSettings *settings = (elbeemSimulationSettings*)data; + FluidBakeJob *fb = (FluidBakeJob *)data; + + //elbeemSimulationSettings *settings = fb->settings; //printf("elbeem blender cb s%d, f%d, domainid:%d \n", status,frame, settings->domainId ); // DEBUG - int state = 0; - if(status==FLUIDSIM_CBSTATUS_NEWFRAME) { - BLI_lock_thread(LOCK_CUSTOM1); - globalBakeFrame = frame-1; - BLI_unlock_thread(LOCK_CUSTOM1); - } - //if((frameCounter==3) && (!frameStop)) { frameStop=1; return 1; } - - BLI_lock_thread(LOCK_CUSTOM1); - state = globalBakeState; - BLI_unlock_thread(LOCK_CUSTOM1); + if (status == FLUIDSIM_CBSTATUS_NEWFRAME) + fluidbake_updatejob(fb, ""); - if(state!=0) { + if (fluidbake_breakjob(fb)) { return FLUIDSIM_CBRET_ABORT; } return FLUIDSIM_CBRET_CONTINUE; } - -/* ******************************************************************************** */ -/* ********************** write fluidsim config to file ************************* */ -/* ******************************************************************************** */ - -int fluidsimBake(bContext *C, ReportList *reports, Object *ob) +int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain) { Scene *scene= CTX_data_scene(C); - FILE *fileCfg; int i; - Object *fsDomain = NULL; FluidsimSettings *domainSettings; - Object *obit = NULL; /* object iterator */ - Base *base; - int origFrame = scene->r.cfra; + char debugStrBuffer[256]; - int dirExist = 0; + int gridlevels = 0; - int simAborted = 0; // was the simulation aborted by user? - int doExportOnly = 0; - char *exportEnvStr = "BLENDER_ELBEEMEXPORTONLY"; const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp - //char *channelNames[3] = { "translation","rotation","scale" }; + char *suffixConfig = FLUID_SUFFIX_CONFIG; + char *suffixSurface = FLUID_SUFFIX_SURFACE; - char *suffixConfig = "fluidsim.cfg"; - char *suffixSurface = "fluidsurface"; - char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings char targetDir[FILE_MAXDIR+FILE_MAXFILE]; // store & modify output settings char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking - int haveSomeFluid = 0; // check if any fluid objects are set - // config vars, inited before either export or run... - double calcViscosity = 0.0; - int noFrames; - double aniFrameTime; - float aniFrlen; - int channelObjCount; - float *bbStart = NULL; - float *bbSize = NULL; float domainMat[4][4]; float invDomMat[4][4]; - // channel data - int allchannelSize; // fixed by no. of frames - int startFrame = 1; // dont use scene->r.sfra here, always start with frame 1 - // easy frame -> sim time calc - float *timeAtFrame=NULL, *timeAtIndex=NULL; - // domain - float *channelDomainTime = NULL; - float *channelDomainViscosity = NULL; - float *channelDomainGravity = NULL; - // objects (currently max. 256 objs) - float *channelObjMove[256][3]; // object movments , 0=trans, 1=rot, 2=scale - float *channelObjInivel[256]; // initial velocities - float *channelObjActive[256]; // obj active channel - - /* fluid control channels */ - float *channelAttractforceStrength[256]; - float *channelAttractforceRadius[256]; - float *channelVelocityforceStrength[256]; - float *channelVelocityforceRadius[256]; + + int noFrames; + int origFrame = scene->r.cfra; + + FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); + ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; + wmJob *steve; + FluidBakeJob *fb; + elbeemSimulationSettings fsset; + + steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, 0); + fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); + if(getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); elbeemDebugOut(debugStrBuffer); } - if(getenv(exportEnvStr)) { - doExportOnly = atoi(getenv(exportEnvStr)); - snprintf(debugStrBuffer,256,"fluidsimBake::msg: Exporting mode set to '%d' due to envvar '%s'\n",doExportOnly, exportEnvStr); - elbeemDebugOut(debugStrBuffer); - } - - // make sure it corresponds to startFrame setting - // old: noFrames = scene->r.efra - scene->r.sfra +1; + + /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */; noFrames = scene->r.efra - 0; if(noFrames<=0) { BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings."); return 0; } - - /* no object pointer, find in selected ones.. */ - if(!ob) { - for(base=scene->base.first; base; base= base->next) { - if ((base)->flag & SELECT) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - - if(fluidmdtmp && (base->object->type==OB_MESH)) - { - if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) - { - ob = base->object; - break; - } - } - } - } - // no domains found? - if(!ob) return 0; - } - channelObjCount = 0; - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - if( fluidmdtmp && - (obit->type==OB_MESH) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH - (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) - { - channelObjCount++; - } - } - - if (channelObjCount>=255) { - BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects."); + /* check scene for sane object/modifier settings */ + if (!fluid_validate_scene(reports, scene, fsDomain)) { return 0; } - /* check if there's another domain... */ - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - if( fluidmdtmp &&(obit->type==OB_MESH)) - { - if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) - { - if(obit != ob) - { - BKE_report(reports, RPT_ERROR, "There should be only one domain object."); - return 0; - } - } - } - } - - // check if theres any fluid - // abort baking if not... - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - if( fluidmdtmp && - (obit->type==OB_MESH) && - ((fluidmdtmp->fss->type == OB_FLUIDSIM_FLUID) || - (fluidmdtmp->fss->type == OB_FLUIDSIM_INFLOW) )) - { - haveSomeFluid = 1; - break; - } - } - if(!haveSomeFluid) { - BKE_report(reports, RPT_ERROR, "No fluid objects in scene."); - return 0; - } /* these both have to be valid, otherwise we wouldnt be here */ - /* dont use ob here after...*/ - fsDomain = ob; - fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; - ob = NULL; mesh = fsDomain->data; + domainSettings->bakeStart = 1; + domainSettings->bakeEnd = scene->r.efra; + // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); @@ -551,107 +862,26 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *ob) } snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); elbeemDebugOut(debugStrBuffer); - - // prepare names... - strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, G.sce); // fixed #frame-no - - strcpy(targetFile, targetDir); - strcat(targetFile, suffixConfig); - if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file - // make sure all directories exist - // as the bobjs use the same dir, this only needs to be checked - // for the cfg output - BLI_make_existing_file(targetFile); - - // check selected directory - // simply try to open cfg file for writing to test validity of settings - fileCfg = fopen(targetFile, "w"); - if(fileCfg) { - dirExist = 1; fclose(fileCfg); - // remove cfg dummy from directory test - if(!doExportOnly) { BLI_delete(targetFile, 0,0); } - } - - if((strlen(targetDir)<1) || (!dirExist)) { - char blendDir[FILE_MAXDIR+FILE_MAXFILE], blendFile[FILE_MAXDIR+FILE_MAXFILE]; - // invalid dir, reset to current/previous - strcpy(blendDir, G.sce); - BLI_splitdirstring(blendDir, blendFile); - if(strlen(blendFile)>6){ - int len = strlen(blendFile); - if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&& - (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){ - blendFile[len-6] = '\0'; - } - } - // todo... strip .blend ? - snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); - - snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); - elbeemDebugOut(debugStrBuffer); - outStringsChanged=1; - } - - // check if modified output dir is ok - if(outStringsChanged) { - char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256]; - int selection=0; - strcpy(dispmsg,"Output settings set to: '"); - strcat(dispmsg, newSurfdataPath); - strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0"); - - // ask user if thats what he/she wants... - selection = pupmenu(dispmsg); - if(selection<1) return 0; // 0 from menu, or -1 aborted - strcpy(targetDir, newSurfdataPath); - strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, G.sce); // fixed #frame-no - } - // -------------------------------------------------------------------------------------------- - // dump data for start frame - // CHECK more reasonable to number frames according to blender? - // dump data for frame 0 - scene->r.cfra = startFrame; - ED_update_for_newframe(C, 1); - // init common export vars for both file export and run - for(i=0; i<256; i++) { - channelObjMove[i][0] = channelObjMove[i][1] = channelObjMove[i][2] = NULL; - channelObjInivel[i] = NULL; - channelObjActive[i] = NULL; - channelAttractforceStrength[i] = NULL; - channelAttractforceRadius[i] = NULL; - channelVelocityforceStrength[i] = NULL; - channelVelocityforceRadius[i] = NULL; - } - allchannelSize = scene->r.efra; // always use till last frame - aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; - // blender specific - scale according to map old/new settings in anim panel: - aniFrlen = scene->r.framelen; - if(domainSettings->viscosityMode==1) { - /* manual mode, visc=value/(10^-vexp) */ - calcViscosity = (1.0/pow(10.0,domainSettings->viscosityExponent)) * domainSettings->viscosityValue; - } else { - calcViscosity = fluidsimViscosityPreset[ domainSettings->viscosityMode ]; - } - - bbStart = domainSettings->bbStart; - bbSize = domainSettings->bbSize; + + /* ******** prepare output file paths ******** */ + outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); + channels->length = scene->r.efra; + channels->aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; + + /* ******** initialise and allocate animation channels ******** */ + fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); - // always init + /* reset to original current frame */ + scene->r.cfra = origFrame; + ED_update_for_newframe(C, 1); + + + /* ---- XXX: No Time animation curve for now, leaving this code here for reference + { int timeIcu[1] = { FLUIDSIM_TIME }; float timeDef[1] = { 1. }; - int gravIcu[3] = { FLUIDSIM_GRAV_X, FLUIDSIM_GRAV_Y, FLUIDSIM_GRAV_Z }; - float gravDef[3]; - int viscIcu[1] = { FLUIDSIM_VISC }; - float viscDef[1] = { 1. }; - - gravDef[0] = domainSettings->gravx; - gravDef[1] = domainSettings->gravy; - gravDef[2] = domainSettings->gravz; // time channel is a bit special, init by hand... timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex"); @@ -659,7 +889,7 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *ob) timeAtIndex[i] = (float)(i-startFrame); } fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB - // time channel is a multiplicator for aniFrameTime + // time channel is a multiplicator for if(channelDomainTime) { for(i=0; iipo, CHANNEL_FLOAT ); // NDEB - if(channelDomainViscosity) { - for(i=0; iipo, CHANNEL_VEC ); } // domain channel init - - // init obj movement channels - channelObjCount=0; - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - - if( fluidmdtmp && - (obit->type==OB_MESH) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH - (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) { - - // cant use fluidsimInitChannel for obj channels right now, due - // to the special DXXX channels, and the rotation specialities - IpoCurve *icuex[3][3]; - //IpoCurve *par_icuex[3][3]; -#if 0 - int icuIds[3][3] = { - {OB_LOC_X, OB_LOC_Y, OB_LOC_Z}, - {OB_ROT_X, OB_ROT_Y, OB_ROT_Z}, - {OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z} - }; - int icudIds[3][3] = { - {OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z}, - {OB_DROT_X, OB_DROT_Y, OB_DROT_Z}, - {OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z} - }; -#endif - // relative ipos - IpoCurve *icudex[3][3]; - //IpoCurve *par_icudex[3][3]; - int j,k; - float vals[3] = {0.0,0.0,0.0}; - int o = channelObjCount; - int inivelIcu[3] = { FLUIDSIM_VEL_X, FLUIDSIM_VEL_Y, FLUIDSIM_VEL_Z }; - float inivelDefs[3]; - int activeIcu[1] = { FLUIDSIM_ACTIVE }; - float activeDefs[1] = { 1 }; // default to on - - inivelDefs[0] = fluidmdtmp->fss->iniVelx; - inivelDefs[1] = fluidmdtmp->fss->iniVely; - inivelDefs[2] = fluidmdtmp->fss->iniVelz; - - // check & init loc,rot,size - for(j=0; j<3; j++) { - for(k=0; k<3; k++) { - // XXX prevent invalid memory access until this works - icuex[j][k]= NULL; - icudex[j][k]= NULL; - - // XXX icuex[j][k] = find_ipocurve(obit->ipo, icuIds[j][k] ); - // XXX icudex[j][k] = find_ipocurve(obit->ipo, icudIds[j][k] ); - // XXX lines below were already disabled! - //if(obit->parent) { - //par_icuex[j][k] = find_ipocurve(obit->parent->ipo, icuIds[j][k] ); - //par_icudex[j][k] = find_ipocurve(obit->parent->ipo, icudIds[j][k] ); - //} - } - } - - for(j=0; j<3; j++) { - channelObjMove[o][j] = MEM_callocN( allchannelSize*4*sizeof(float), "fluidsiminit_objmovchannel"); - for(i=1; i<=allchannelSize; i++) { - - for(k=0; k<3; k++) { - if(icuex[j][k]) { - // IPO exists, use it ... - // XXX calc_icu(icuex[j][k], aniFrlen*((float)i) ); - vals[k] = icuex[j][k]->curval; - if(obit->parent) { - // add parent transform, multiply scaling, add trafo&rot - //calc_icu(par_icuex[j][k], aniFrlen*((float)i) ); - //if(j==2) { vals[k] *= par_icuex[j][k]->curval; } - //else { vals[k] += par_icuex[j][k]->curval; } - } - } else { - // use defaults from static values - float setval=0.0; - if(j==0) { - setval = obit->loc[k]; - if(obit->parent){ setval += obit->parent->loc[k]; } - } else if(j==1) { - setval = ( 180.0*obit->rot[k] )/( 10.0*M_PI ); - if(obit->parent){ setval = ( 180.0*(obit->rot[k]+obit->parent->rot[k]) )/( 10.0*M_PI ); } - } else { - setval = obit->size[k]; - if(obit->parent){ setval *= obit->parent->size[k]; } - } - vals[k] = setval; - } - if(icudex[j][k]) { - // XXX calc_icu(icudex[j][k], aniFrlen*((float)i) ); - //vals[k] += icudex[j][k]->curval; - // add transform, multiply scaling, add trafo&rot - if(j==2) { vals[k] *= icudex[j][k]->curval; } - else { vals[k] += icudex[j][k]->curval; } - if(obit->parent) { - // add parent transform, multiply scaling, add trafo&rot - //calc_icu(par_icuex[j][k], aniFrlen*((float)i) ); - //if(j==2) { vals[k] *= par_icudex[j][k]->curval; } - //else { vals[k] += par_icudex[j][k]->curval; } - } - } - } // k - - for(k=0; k<3; k++) { - float set = vals[k]; - if(j==1) { // rot is downscaled by 10 for ipo !? - set = 360.0 - (10.0*set); - } - channelObjMove[o][j][(i-1)*4 + k] = set; - } // k - channelObjMove[o][j][(i-1)*4 + 3] = timeAtFrame[i]; - } - } - - { - int attrFSIcu[1] = { FLUIDSIM_ATTR_FORCE_STR }; - int attrFRIcu[1] = { FLUIDSIM_ATTR_FORCE_RADIUS }; - int velFSIcu[1] = { FLUIDSIM_VEL_FORCE_STR }; - int velFRIcu[1] = { FLUIDSIM_VEL_FORCE_RADIUS }; - - float attrFSDefs[1]; - float attrFRDefs[1]; - float velFSDefs[1]; - float velFRDefs[1]; - - attrFSDefs[0] = fluidmdtmp->fss->attractforceStrength; - attrFRDefs[0] = fluidmdtmp->fss->attractforceRadius; - velFSDefs[0] = fluidmdtmp->fss->velocityforceStrength; - velFRDefs[0] = fluidmdtmp->fss->velocityforceRadius; - - fluidsimInitChannel(scene, &channelAttractforceStrength[o], allchannelSize, timeAtFrame, attrFSIcu,attrFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - fluidsimInitChannel(scene, &channelAttractforceRadius[o], allchannelSize, timeAtFrame, attrFRIcu,attrFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - fluidsimInitChannel(scene, &channelVelocityforceStrength[o], allchannelSize, timeAtFrame, velFSIcu,velFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - fluidsimInitChannel(scene, &channelVelocityforceRadius[o], allchannelSize, timeAtFrame, velFRIcu,velFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - } - - fluidsimInitChannel(scene, &channelObjInivel[o], allchannelSize, timeAtFrame, inivelIcu,inivelDefs, fluidmdtmp->fss->ipo, CHANNEL_VEC ); - fluidsimInitChannel(scene, &channelObjActive[o], allchannelSize, timeAtFrame, activeIcu,activeDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); + */ - - channelObjCount++; - - } - } - - // init trafo matrix + /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if(!invert_m4_m4(invDomMat, domainMat)) { snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix."); - // FIXME add fatal msg - FS_FREE_CHANNELS; + + free_domain_channels(channels); + MEM_freeN(channels); + + free_all_fluidobject_channels(fobjects); + BLI_freelistN(fobjects); + MEM_freeN(fobjects); return 0; } - // -------------------------------------------------------------------------------------------- - // start writing / exporting + /* ******** start writing / exporting ******** */ strcpy(targetFile, targetDir); strcat(targetFile, suffixConfig); - if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file + strcat(targetFile,".tmp"); // dont overwrite/delete original file + // make sure these directories exist as well if(outStringsChanged) { BLI_make_existing_file(targetFile); } - if(!doExportOnly) { - ListBase threads; - - // perform simulation with El'Beem api and threads - elbeemSimulationSettings fsset; - elbeemResetSettings(&fsset); - fsset.version = 1; + /* ******** export domain to elbeem ******** */ + elbeemResetSettings(&fsset); + fsset.version = 1; - // setup global settings - for(i=0 ; i<3; i++) fsset.geoStart[i] = bbStart[i]; - for(i=0 ; i<3; i++) fsset.geoSize[i] = bbSize[i]; - - // simulate with 50^3 - fsset.resolutionxyz = (int)domainSettings->resolutionxyz; - fsset.previewresxyz = (int)domainSettings->previewresxyz; - // 10cm water domain - fsset.realsize = domainSettings->realsize; - fsset.viscosity = calcViscosity; - // earth gravity - fsset.gravity[0] = domainSettings->gravx; - fsset.gravity[1] = domainSettings->gravy; - fsset.gravity[2] = domainSettings->gravz; - // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz - fsset.animStart = domainSettings->animStart; - fsset.aniFrameTime = aniFrameTime; - fsset.noOfFrames = noFrames; // is otherwise subtracted in parser - strcpy(targetFile, targetDir); - strcat(targetFile, suffixSurface); - // defaults for compressibility and adaptive grids - fsset.gstar = domainSettings->gstar; - fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels - fsset.generateParticles = domainSettings->generateParticles; - fsset.numTracerParticles = domainSettings->generateTracers; - fsset.surfaceSmoothing = domainSettings->surfaceSmoothing; - fsset.surfaceSubdivs = domainSettings->surfaceSubdivs; - fsset.farFieldSize = domainSettings->farFieldSize; - strcpy( fsset.outputPath, targetFile); - - // domain channels - fsset.channelSizeFrameTime = - fsset.channelSizeViscosity = - fsset.channelSizeGravity = allchannelSize; - fsset.channelFrameTime = channelDomainTime; - fsset.channelViscosity = channelDomainViscosity; - fsset.channelGravity = channelDomainGravity; - - fsset.runsimCallback = &runSimulationCallback; - fsset.runsimUserData = &fsset; - - if( (domainSettings->typeFlags&OB_FSBND_NOSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; - else if((domainSettings->typeFlags&OB_FSBND_PARTSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; - else if((domainSettings->typeFlags&OB_FSBND_FREESLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; - fsset.domainobsPartslip = domainSettings->partSlipValue; - fsset.generateVertexVectors = (domainSettings->domainNovecgen==0); - - // init blender trafo matrix - // fprintf(stderr,"elbeemInit - mpTrafo:\n"); - { int j; - for(i=0; i<4; i++) { - for(j=0; j<4; j++) { - fsset.surfaceTrafo[i*4+j] = invDomMat[j][i]; - // fprintf(stderr,"elbeemInit - mpTrafo %d %d = %f (%d) \n", i,j, fsset.surfaceTrafo[i*4+j] , (i*4+j) ); - } - } } - - // init solver with settings - elbeemInit(); - elbeemAddDomain(&fsset); - - // init objects - channelObjCount = 0; - for(base=scene->base.first; base; base= base->next) { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG - if( fluidmdtmp && // if has to match 3 places! // CHECKMATCH - (obit->type==OB_MESH) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE)) - { - float *verts=NULL; - int *tris=NULL; - int numVerts=0, numTris=0; - int o = channelObjCount; - int deform = (fluidmdtmp->fss->domainNovecgen); // misused value - // todo - use blenderInitElbeemMesh - int modifierIndex = modifiers_indexInObject(obit, (ModifierData *)fluidmdtmp); - - elbeemMesh fsmesh; - elbeemResetMesh( &fsmesh ); - fsmesh.type = fluidmdtmp->fss->type; - // get name of object for debugging solver - fsmesh.name = obit->id.name; - - initElbeemMesh(scene, obit, &numVerts, &verts, &numTris, &tris, 0, modifierIndex); - fsmesh.numVertices = numVerts; - fsmesh.numTriangles = numTris; - fsmesh.vertices = verts; - fsmesh.triangles = tris; - - fsmesh.channelSizeTranslation = - fsmesh.channelSizeRotation = - fsmesh.channelSizeScale = - fsmesh.channelSizeInitialVel = - fsmesh.channelSizeActive = allchannelSize; - - fsmesh.channelTranslation = channelObjMove[o][0]; - fsmesh.channelRotation = channelObjMove[o][1]; - fsmesh.channelScale = channelObjMove[o][2]; - fsmesh.channelActive = channelObjActive[o]; - if( (fsmesh.type == OB_FLUIDSIM_FLUID) || - (fsmesh.type == OB_FLUIDSIM_INFLOW)) { - fsmesh.channelInitialVel = channelObjInivel[o]; - fsmesh.localInivelCoords = ((fluidmdtmp->fss->typeFlags&OB_FSINFLOW_LOCALCOORD)?1:0); - } - - if( (fluidmdtmp->fss->typeFlags&OB_FSBND_NOSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; - else if((fluidmdtmp->fss->typeFlags&OB_FSBND_PARTSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP; - else if((fluidmdtmp->fss->typeFlags&OB_FSBND_FREESLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP; - fsmesh.obstaclePartslip = fluidmdtmp->fss->partSlipValue; - fsmesh.volumeInitType = fluidmdtmp->fss->volumeInitType; - fsmesh.obstacleImpactFactor = fluidmdtmp->fss->surfaceSmoothing; // misused value - - if(fsmesh.type == OB_FLUIDSIM_CONTROL) - { - // control fluids will get exported as whole - deform = 1; - - fsmesh.cpsTimeStart = fluidmdtmp->fss->cpsTimeStart; - fsmesh.cpsTimeEnd = fluidmdtmp->fss->cpsTimeEnd; - fsmesh.cpsQuality = fluidmdtmp->fss->cpsQuality; - fsmesh.obstacleType = (fluidmdtmp->fss->flag & OB_FLUIDSIM_REVERSE); - - fsmesh.channelSizeAttractforceRadius = - fsmesh.channelSizeVelocityforceStrength = - fsmesh.channelSizeVelocityforceRadius = - fsmesh.channelSizeAttractforceStrength = allchannelSize; - - fsmesh.channelAttractforceStrength = channelAttractforceStrength[o]; - fsmesh.channelAttractforceRadius = channelAttractforceRadius[o]; - fsmesh.channelVelocityforceStrength = channelVelocityforceStrength[o]; - fsmesh.channelVelocityforceRadius = channelVelocityforceRadius[o]; - } - else - { - // set channels to 0 - fsmesh.channelAttractforceStrength = - fsmesh.channelAttractforceRadius = - fsmesh.channelVelocityforceStrength = - fsmesh.channelVelocityforceRadius = NULL; - } - - // animated meshes - if(deform) { - fsmesh.channelSizeVertices = allchannelSize; - fluidsimInitMeshChannel(C, &fsmesh.channelVertices, allchannelSize, obit, numVerts, timeAtFrame, modifierIndex); - scene->r.cfra = startFrame; - ED_update_for_newframe(C, 1); - // remove channels - fsmesh.channelTranslation = - fsmesh.channelRotation = - fsmesh.channelScale = NULL; - } - - elbeemAddMesh(&fsmesh); - - if(verts) MEM_freeN(verts); - if(tris) MEM_freeN(tris); - if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices); - channelObjCount++; - } // valid mesh - } // objects - //domainSettings->type = OB_FLUIDSIM_DOMAIN; // enable for bake display again - - // set to neutral, -1 means user abort, -2 means init error - globalBakeState = 0; - globalBakeFrame = 0; - - BLI_init_threads(&threads, fluidsimSimulateThread, 1); - BLI_insert_thread(&threads, targetFile); - - { - int done = 0; - float noFramesf = (float)noFrames; - float percentdone = 0.0, oldpercentdone = -1.0; - int lastRedraw = -1; - - g_break= 0; - G.afbreek= 0; /* blender_test_break uses this global */ - - start_progress_bar(); - - while(done==0) { - char busy_mess[80]; - - waitcursor(1); - - // lukep we add progress bar as an interim mesure - percentdone = globalBakeFrame / noFramesf; - if (percentdone != oldpercentdone) { - sprintf(busy_mess, "baking fluids %d / %d |||", globalBakeFrame, (int) noFramesf); - percentdone = percentdone < 0.0 ? 0.0:percentdone; - progress_bar(CTX_wm_window(C), percentdone, busy_mess ); - oldpercentdone = percentdone; - } - - //XXX no more need for longer delay to prevent frequent redrawing - PIL_sleep_ms(200); - - BLI_lock_thread(LOCK_CUSTOM1); - if(globalBakeState != 0) done = 1; // 1=ok, <0=error/abort - BLI_unlock_thread(LOCK_CUSTOM1); - - if (!G.background) { - g_break= blender_test_break(); - - if(g_break) - { - // abort... - BLI_lock_thread(LOCK_CUSTOM1); - - if(domainSettings) - domainSettings->lastgoodframe = startFrame+globalBakeFrame; - - done = -1; - globalBakeFrame = 0; - globalBakeState = -1; - simAborted = 1; - BLI_unlock_thread(LOCK_CUSTOM1); - break; - } - } - - // redraw the 3D for showing progress once in a while... - if(lastRedraw!=globalBakeFrame) { -#if 0 - ScrArea *sa; - scene->r.cfra = startFrame+globalBakeFrame; - lastRedraw = globalBakeFrame; - ED_update_for_newframe(C, 1); - sa= G.curscreen->areabase.first; - while(sa) { - if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); } - sa= sa->next; - } - screen_swapbuffers(); -#endif - } // redraw - } - end_progress_bar(CTX_wm_window(C)); + // setup global settings + copy_v3_v3(fsset.geoStart, domainSettings->bbStart); + copy_v3_v3(fsset.geoSize, domainSettings->bbSize); + + // simulate with 50^3 + fsset.resolutionxyz = (int)domainSettings->resolutionxyz; + fsset.previewresxyz = (int)domainSettings->previewresxyz; + + fsset.realsize = get_fluid_size_m(scene, fsDomain, domainSettings); + fsset.viscosity = get_fluid_viscosity(domainSettings); + get_fluid_gravity(fsset.gravity, scene, domainSettings); + + // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz + fsset.animStart = domainSettings->animStart; + fsset.aniFrameTime = channels->aniFrameTime; + fsset.noOfFrames = noFrames; // is otherwise subtracted in parser + strcpy(targetFile, targetDir); + strcat(targetFile, suffixSurface); + // defaults for compressibility and adaptive grids + fsset.gstar = domainSettings->gstar; + fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels + fsset.generateParticles = domainSettings->generateParticles; + fsset.numTracerParticles = domainSettings->generateTracers; + fsset.surfaceSmoothing = domainSettings->surfaceSmoothing; + fsset.surfaceSubdivs = domainSettings->surfaceSubdivs; + fsset.farFieldSize = domainSettings->farFieldSize; + strcpy( fsset.outputPath, targetFile); + + // domain channels + fsset.channelSizeFrameTime = + fsset.channelSizeViscosity = + fsset.channelSizeGravity = channels->length; + fsset.channelFrameTime = channels->DomainTime; + fsset.channelViscosity = channels->DomainViscosity; + fsset.channelGravity = channels->DomainGravity; + + fsset.runsimCallback = &runSimulationCallback; + fsset.runsimUserData = fb; + + if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; + else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; + else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; + fsset.domainobsPartslip = domainSettings->partSlipValue; + fsset.generateVertexVectors = (domainSettings->domainNovecgen==0); + + // init blender domain transform matrix + { int j; + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + fsset.surfaceTrafo[i*4+j] = invDomMat[j][i]; } - BLI_end_threads(&threads); - } // El'Beem API init, thread creation - // -------------------------------------------------------------------------------------------- - else - { // write config file to be run with command line simulator - BKE_report(reports, RPT_WARNING, "Config file export not supported."); - } // config file export done! - - // -------------------------------------------------------------------------------------------- - FS_FREE_CHANNELS; + } } - // go back to "current" blender time - waitcursor(0); + /* ******** init solver with settings ******** */ + elbeemInit(); + elbeemAddDomain(&fsset); - if(globalBakeState >= 0) - { - if(domainSettings) - domainSettings->lastgoodframe = startFrame+globalBakeFrame; - } + /* ******** export all fluid objects to elbeem ******** */ + export_fluid_objects(fobjects, scene, channels->length); - scene->r.cfra = origFrame; - ED_update_for_newframe(C, 1); - - if(!simAborted) { - char elbeemerr[256]; + /* custom data for fluid bake job */ + fb->settings = &fsset; + + /* setup job */ + WM_jobs_customdata(steve, fb, fluidbake_free); + WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); + WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL); + + WM_jobs_start(CTX_wm_manager(C), steve); - // check if some error occurred - if(globalBakeState==-2) { - elbeemGetErrorString(elbeemerr); - BKE_reportf(reports, RPT_ERROR, "Failed to initialize [Msg: %s]", elbeemerr); - return 0; - } // init error - } + /* ******** free stored animation data ******** */ + free_domain_channels(channels); + MEM_freeN(channels); + free_all_fluidobject_channels(fobjects); + BLI_freelistN(fobjects); + MEM_freeN(fobjects); + // elbeemFree(); return 1; } @@ -1181,7 +1062,6 @@ static int fluid_bake_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); - // XXX TODO redraw, escape, non-blocking, .. if(!fluidsimBake(C, op->reports, ob)) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 370076b5b07..fa9308111b0 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -258,6 +258,7 @@ static void buttons_area_listener(ScrArea *sa, wmNotifier *wmn) buttons_area_redraw(sa, BCONTEXT_TEXTURE); buttons_area_redraw(sa, BCONTEXT_WORLD); buttons_area_redraw(sa, BCONTEXT_DATA); + buttons_area_redraw(sa, BCONTEXT_PHYSICS); sbuts->preview= 1; break; case ND_OB_ACTIVE: diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h index fa918fc30d9..700021eaceb 100644 --- a/source/blender/makesdna/DNA_object_fluidsim.h +++ b/source/blender/makesdna/DNA_object_fluidsim.h @@ -63,8 +63,10 @@ typedef struct FluidsimSettings { short viscosityExponent; /* gravity strength */ float gravx,gravy,gravz; - /* anim start end time */ + /* anim start end time (in seconds) */ float animStart, animEnd; + /* bake start end time (in blender frames) */ + int bakeStart, bakeEnd; /* g star param (LBM compressibility) */ float gstar; /* activate refinement? */ @@ -160,8 +162,10 @@ typedef struct FluidsimSettings { #define OB_FSPART_FLOAT (1<<4) #define OB_FSPART_TRACER (1<<5) -// new fluid bit flags for fss->flags - dg -#define OB_FLUIDSIM_REVERSE (1 << 0) +// new fluid bit flags for fss->flags +#define OB_FLUIDSIM_REVERSE (1 << 0) +#define OB_FLUIDSIM_ACTIVE (1 << 1) +#define OB_FLUIDSIM_OVERRIDE_TIME (1 << 2) #ifdef __cplusplus } diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 01563877068..0782ee4fb84 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -172,6 +172,7 @@ static void rna_def_fluidsim_slip(StructRNA *srna) prop= RNA_def_property(srna, "slip_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "typeFlags"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, slip_items); RNA_def_property_ui_text(prop, "Slip Type", ""); @@ -215,16 +216,6 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) RNA_def_property_range(prop, 1, 100); RNA_def_property_ui_text(prop, "Preview Resolution", "Preview resolution in X,Y and Z direction"); - prop= RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); - RNA_def_property_float_sdna(prop, NULL, "animStart"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Start Time", "Simulation time of the first blender frame"); - - prop= RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME); - RNA_def_property_float_sdna(prop, NULL, "animEnd"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "End Time", "Simulation time of the last blender frame"); - prop= RNA_def_property(srna, "viewport_display_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "guiDisplayMode"); RNA_def_property_enum_items(prop, quality_items); @@ -252,13 +243,31 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Memory Estimate", "Estimated amount of memory needed for baking the domain"); /* advanced settings */ - prop= RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION); RNA_def_property_float_sdna(prop, NULL, "gravx"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, -1000.1, 1000.1); RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction"); - + + prop= RNA_def_property(srna, "override_time", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_OVERRIDE_TIME); + RNA_def_property_ui_text(prop, "Override Time", "Use a custom start and end time (in seconds) instead of the scene's timeline"); + + prop= RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); + RNA_def_property_float_sdna(prop, NULL, "animStart"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Start Time", "Simulation time of the first blender frame"); + + prop= RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME); + RNA_def_property_float_sdna(prop, NULL, "animEnd"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "End Time", "Simulation time of the last blender frame"); + + prop= RNA_def_property(srna, "real_world_size", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "realsize"); + RNA_def_property_range(prop, 0.001, 10); + RNA_def_property_ui_text(prop, "Real World Size", "Size of the simulation domain in metres"); + prop= RNA_def_property(srna, "viscosity_preset", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "viscosityMode"); RNA_def_property_enum_items(prop, viscosity_items); @@ -274,18 +283,15 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_text(prop, "Viscosity Exponent", "Negative exponent for the viscosity value (to simplify entering small values e.g. 5*10^-6.)"); - prop= RNA_def_property(srna, "real_world_size", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "realsize"); - RNA_def_property_range(prop, 0.001, 10); - RNA_def_property_ui_text(prop, "Real World Size", "Size of the simulation domain in metres"); - prop= RNA_def_property(srna, "grid_levels", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "maxRefine"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, -1, 4); RNA_def_property_ui_text(prop, "Grid Levels", "Number of coarsened grids to use (-1 for automatic)"); prop= RNA_def_property(srna, "compressibility", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "gstar"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.001, 0.1); RNA_def_property_ui_text(prop, "Compressibility", "Allowed compressibility due to gravitational force for standing fluid. (directly affects simulation step size)"); @@ -295,27 +301,32 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) prop= RNA_def_property(srna, "surface_smoothing", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0, 5.0); RNA_def_property_ui_text(prop, "Surface Smoothing", "Amount of surface smoothing. A value of 0 is off, 1 is normal smoothing and more than 1 is extra smoothing"); prop= RNA_def_property(srna, "surface_subdivisions", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "surfaceSubdivs"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0, 5); RNA_def_property_ui_text(prop, "Surface Subdivisions", "Number of isosurface subdivisions. This is necessary for the inclusion of particles into the surface generation. Warning - can lead to longer computation times!"); prop= RNA_def_property(srna, "generate_speed_vectors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "domainNovecgen", 0); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Generate Speed Vectors", "Generate speed vectors for vector blur"); /* particles */ prop= RNA_def_property(srna, "tracer_particles", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "generateTracers"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Tracer Particles", "Number of tracer particles to generate"); prop= RNA_def_property(srna, "generate_particles", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "generateParticles"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0, 10.0); RNA_def_property_ui_text(prop, "Generate Particles", "Amount of particles to generate (0=off, 1=normal, >1=more)"); } @@ -332,14 +343,25 @@ static void rna_def_fluidsim_volume(StructRNA *srna) prop= RNA_def_property(srna, "volume_initialization", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "volumeInitType"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, volume_type_items); RNA_def_property_ui_text(prop, "Volume Initialization", "Volume initialization type"); prop= RNA_def_property(srna, "export_animated_mesh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "domainNovecgen", 0); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Export Animated Mesh", "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it"); } +static void rna_def_fluidsim_active(StructRNA *srna) +{ + PropertyRNA *prop; + + prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_ACTIVE); + RNA_def_property_ui_text(prop, "Active", "Object contributes to the fluid simulation"); +} + static void rna_def_fluidsim_fluid(BlenderRNA *brna) { StructRNA *srna; @@ -349,8 +371,9 @@ static void rna_def_fluidsim_fluid(BlenderRNA *brna) RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_ui_text(srna, "Fluid Fluid Simulation Settings", "Fluid simulation settings for the fluid in the simulation"); + rna_def_fluidsim_active(srna); rna_def_fluidsim_volume(srna); - + prop= RNA_def_property(srna, "initial_velocity", PROP_FLOAT, PROP_VELOCITY); RNA_def_property_float_sdna(prop, NULL, "iniVelx"); RNA_def_property_array(prop, 3); @@ -363,15 +386,17 @@ static void rna_def_fluidsim_obstacle(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna= RNA_def_struct(brna, "ObstacleFluidSettings", "FluidSettings"); + srna= RNA_def_struct(brna, "ObstacleFluidSettings", "FluidSettings"); RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_ui_text(srna, "Obstacle Fluid Simulation Settings", "Fluid simulation settings for obstacles in the simulation"); + rna_def_fluidsim_active(srna); rna_def_fluidsim_volume(srna); rna_def_fluidsim_slip(srna); prop= RNA_def_property(srna, "impact_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, -2.0, 10.0); RNA_def_property_ui_text(prop, "Impact Factor", "This is an unphysical value for moving objects - it controls the impact an obstacle has on the fluid, =0 behaves a bit like outflow (deleting fluid), =1 is default, while >1 results in high forces. Can be used to tweak total mass"); } @@ -381,10 +406,11 @@ static void rna_def_fluidsim_inflow(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna= RNA_def_struct(brna, "InflowFluidSettings", "FluidSettings"); + srna= RNA_def_struct(brna, "InflowFluidSettings", "FluidSettings"); RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_ui_text(srna, "Inflow Fluid Simulation Settings", "Fluid simulation settings for objects adding fluids in the simulation"); + rna_def_fluidsim_active(srna); rna_def_fluidsim_volume(srna); prop= RNA_def_property(srna, "inflow_velocity", PROP_FLOAT, PROP_VELOCITY); @@ -394,6 +420,7 @@ static void rna_def_fluidsim_inflow(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Inflow Velocity", "Initial velocity of fluid"); prop= RNA_def_property(srna, "local_coordinates", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSINFLOW_LOCALCOORD); RNA_def_property_ui_text(prop, "Local Coordinates", "Use local coordinates for inflow. (e.g. for rotating objects)"); } @@ -402,10 +429,11 @@ static void rna_def_fluidsim_outflow(BlenderRNA *brna) { StructRNA *srna; - srna= RNA_def_struct(brna, "OutflowFluidSettings", "FluidSettings"); + srna= RNA_def_struct(brna, "OutflowFluidSettings", "FluidSettings"); RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_ui_text(srna, "Outflow Fluid Simulation Settings", "Fluid simulation settings for objects removing fluids from the simulation"); + rna_def_fluidsim_active(srna); rna_def_fluidsim_volume(srna); } @@ -414,7 +442,7 @@ static void rna_def_fluidsim_particle(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna= RNA_def_struct(brna, "ParticleFluidSettings", "FluidSettings"); + srna= RNA_def_struct(brna, "ParticleFluidSettings", "FluidSettings"); RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_ui_text(srna, "Particle Fluid Simulation Settings", "Fluid simulation settings for objects storing fluid particles generated by the simulation"); @@ -452,10 +480,12 @@ static void rna_def_fluidsim_control(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna= RNA_def_struct(brna, "ControlFluidSettings", "FluidSettings"); + srna= RNA_def_struct(brna, "ControlFluidSettings", "FluidSettings"); RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_ui_text(srna, "Control Fluid Simulation Settings", "Fluid simulation settings for objects controlling the motion of fluid in the simulation"); + rna_def_fluidsim_active(srna); + prop= RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "cpsTimeStart"); RNA_def_property_range(prop, 0.0, 100.0); @@ -488,11 +518,13 @@ static void rna_def_fluidsim_control(BlenderRNA *brna) prop= RNA_def_property(srna, "quality", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "cpsQuality"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 5.0, 100.0); RNA_def_property_ui_text(prop, "Quality", "Specifies the quality which is used for object sampling. (higher = better but slower)"); prop= RNA_def_property(srna, "reverse_frames", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse control object movement"); } @@ -522,6 +554,7 @@ void RNA_def_fluidsim(BlenderRNA *brna) prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, prop_fluid_type_items); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Type", "Type of participation in the fluid simulation"); RNA_def_property_update(prop, 0, "rna_FluidSettings_update_type"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 86767342586..3823af25619 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -579,41 +579,13 @@ static void rna_Object_rotation_mode_set(PointerRNA *ptr, int value) static void rna_Object_dimensions_get(PointerRNA *ptr, float *value) { Object *ob= ptr->data; - BoundBox *bb = NULL; - - bb= object_get_boundbox(ob); - if (bb) { - float scale[3]; - - mat4_to_size( scale,ob->obmat); - - value[0] = fabs(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]); - value[1] = fabs(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]); - value[2] = fabs(scale[2]) * (bb->vec[1][2] - bb->vec[0][2]); - } else { - value[0] = value[1] = value[2] = 0.f; - } + object_get_dimensions(ob, value); } static void rna_Object_dimensions_set(PointerRNA *ptr, const float *value) { Object *ob= ptr->data; - BoundBox *bb = NULL; - - bb= object_get_boundbox(ob); - if (bb) { - float scale[3], len[3]; - - mat4_to_size( scale,ob->obmat); - - len[0] = bb->vec[4][0] - bb->vec[0][0]; - len[1] = bb->vec[2][1] - bb->vec[0][1]; - len[2] = bb->vec[1][2] - bb->vec[0][2]; - - if (len[0] > 0.f) ob->size[0] = value[0] / len[0]; - if (len[1] > 0.f) ob->size[1] = value[1] / len[1]; - if (len[2] > 0.f) ob->size[2] = value[2] / len[2]; - } + object_set_dimensions(ob, value); } static int rna_Object_location_editable(PointerRNA *ptr, int index) -- cgit v1.2.3