diff options
Diffstat (limited to 'source/blender/editors/physics/physics_fluid.c')
-rw-r--r-- | source/blender/editors/physics/physics_fluid.c | 1832 |
1 files changed, 965 insertions, 867 deletions
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index d3b57a09a9e..2769d1a9dc3 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -50,156 +50,153 @@ #include "WM_types.h" #include "WM_api.h" -#include "physics_intern.h" // own include +#include "physics_intern.h" // own include /* enable/disable overall compilation */ #ifdef WITH_MOD_FLUID -#include "LBM_fluidsim.h" +# include "LBM_fluidsim.h" -#include "BLI_blenlib.h" -#include "BLI_path_util.h" -#include "BLI_math.h" +# include "BLI_blenlib.h" +# include "BLI_path_util.h" +# include "BLI_math.h" -#include "BKE_global.h" -#include "BKE_main.h" +# include "BKE_global.h" +# include "BKE_main.h" -#include "WM_api.h" - -#include "DNA_scene_types.h" -#include "DNA_mesh_types.h" +# include "WM_api.h" +# include "DNA_scene_types.h" +# include "DNA_mesh_types.h" static float get_fluid_viscosity(FluidsimSettings *settings) { - return (1.0f/powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue; + return (1.0f / powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue; } static float get_fluid_rate(FluidsimSettings *settings) { - float rate = 1.0f; /* default rate if not animated... */ + float rate = 1.0f; /* default rate if not animated... */ - rate = settings->animRate; + rate = settings->animRate; - if (rate < 0.0f) - rate = 0.0f; + if (rate < 0.0f) + rate = 0.0f; - return rate; + return rate; } 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->grav); - } + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(gravity, scene->physics_settings.gravity); + } + else { + copy_v3_v3(gravity, fss->grav); + } } 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; - - BKE_object_dimensions_get(domainob, dim); - longest_axis = max_fff(dim[0], dim[1], dim[2]); - - return longest_axis * scene->unit.scale_length; - } + if (!scene->unit.system) { + return fss->realsize; + } + else { + float dim[3]; + float longest_axis; + + BKE_object_dimensions_get(domainob, dim); + longest_axis = max_fff(dim[0], dim[1], dim[2]); + + return longest_axis * scene->unit.scale_length; + } } static bool fluid_is_animated_mesh(FluidsimSettings *fss) { - return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen); + return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen); } /* ********************** fluid sim settings struct functions ********************** */ -#if 0 +# if 0 /* helper function */ void fluidsimGetGeometryObjFilename(Object *ob, char *dst) //, char *srcname) { - //BLI_snprintf(dst, FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name); - BLI_snprintf(dst, FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name); + //BLI_snprintf(dst, FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name); + BLI_snprintf(dst, FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name); } -#endif - +# endif /* ********************** fluid sim channel helper functions ********************** */ typedef struct FluidAnimChannels { - int length; + int length; - double aniFrameTime; + double aniFrameTime; - float *timeAtFrame; - float *DomainTime; - float *DomainGravity; - float *DomainViscosity; + float *timeAtFrame; + float *DomainTime; + float *DomainGravity; + float *DomainViscosity; } FluidAnimChannels; typedef struct FluidObject { - struct FluidObject *next, *prev; + struct FluidObject *next, *prev; - struct Object *object; + struct Object *object; - float *Translation; - float *Rotation; - float *Scale; - float *Active; + float *Translation; + float *Rotation; + float *Scale; + float *Active; - float *InitialVelocity; + float *InitialVelocity; - float *AttractforceStrength; - float *AttractforceRadius; - float *VelocityforceStrength; - float *VelocityforceRadius; + float *AttractforceStrength; + float *AttractforceRadius; + float *VelocityforceStrength; + float *VelocityforceRadius; - float *VertexCache; - int numVerts, numTris; + float *VertexCache; + int numVerts, numTris; } FluidObject; // no. of entries for the two channel sizes -#define CHANNEL_FLOAT 1 -#define CHANNEL_VEC 3 +# define CHANNEL_FLOAT 1 +# define CHANNEL_VEC 3 // simplify channels before printing // for API this is done anyway upon init -#if 0 +# if 0 static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries) { - int i, j; - int channelSize = paramsize; - - if (entries == 3) { - elbeemSimplifyChannelVec3(channel, &channelSize); - } - else if (entries == 1) { - elbeemSimplifyChannelFloat(channel, &channelSize); - } - else { - /* invalid, cant happen? */ - } - - fprintf(file, " CHANNEL %s =\n", str); - for (i=0; i < channelSize; i++) { - fprintf(file, " "); - for (j=0;j <= entries;j++) { // also print time value - fprintf(file, " %f ", channel[i*(entries + 1) + j]); - if (j == entries-1) { fprintf(file, " "); } - } - fprintf(file, "\n"); - } - - fprintf(file, " ;\n"); + int i, j; + int channelSize = paramsize; + + if (entries == 3) { + elbeemSimplifyChannelVec3(channel, &channelSize); + } + else if (entries == 1) { + elbeemSimplifyChannelFloat(channel, &channelSize); + } + else { + /* invalid, cant happen? */ + } + + fprintf(file, " CHANNEL %s =\n", str); + for (i=0; i < channelSize; i++) { + fprintf(file, " "); + for (j=0;j <= entries;j++) { // also print time value + fprintf(file, " %f ", channel[i*(entries + 1) + j]); + if (j == entries-1) { fprintf(file, " "); } + } + fprintf(file, "\n"); + } + + fprintf(file, " ;\n"); } -#endif - +# endif /* Note: fluid anim channel data layout * ------------------------------------ @@ -214,472 +211,534 @@ static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels) { - int i; + int i; - channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float), "timeAtFrame channel"); + channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float), + "timeAtFrame channel"); - channels->timeAtFrame[0] = channels->timeAtFrame[1] = domainSettings->animStart; // start at index 1 + 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] + (float)channels->aniFrameTime; - } + for (i = 2; i <= channels->length; i++) { + channels->timeAtFrame[i] = channels->timeAtFrame[i - 1] + (float)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; - } + 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; + } } -static void set_vertex_channel(Depsgraph *depsgraph, float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i) +static void set_vertex_channel(Depsgraph *depsgraph, + 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 = BLI_findindex(&ob->modifiers, fluidmd); - int framesize = (3*fobj->numVerts) + 1; - int j; - - if (channel == NULL) - return; - - initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); - - /* don't allow mesh to change number of verts in anim sequence */ - if (numVerts != fobj->numVerts) { - MEM_freeN(channel); - channel = NULL; - return; - } - - /* 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); + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( + ob, eModifierType_Fluidsim); + float *verts; + int *tris = NULL, numVerts = 0, numTris = 0; + int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd); + int framesize = (3 * fobj->numVerts) + 1; + int j; + + if (channel == NULL) + return; + + initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); + + /* don't allow mesh to change number of verts in anim sequence */ + if (numVerts != fobj->numVerts) { + MEM_freeN(channel); + channel = NULL; + return; + } + + /* 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); } static void free_domain_channels(FluidAnimChannels *channels) { - if (!channels->timeAtFrame) - return; - MEM_freeN(channels->timeAtFrame); - channels->timeAtFrame = NULL; - MEM_freeN(channels->DomainGravity); - channels->DomainGravity = NULL; - MEM_freeN(channels->DomainViscosity); - channels->DomainViscosity = NULL; - MEM_freeN(channels->DomainTime); - channels->DomainTime = NULL; + if (!channels->timeAtFrame) + return; + MEM_freeN(channels->timeAtFrame); + channels->timeAtFrame = NULL; + MEM_freeN(channels->DomainGravity); + channels->DomainGravity = NULL; + MEM_freeN(channels->DomainViscosity); + channels->DomainViscosity = NULL; + MEM_freeN(channels->DomainTime); + channels->DomainTime = NULL; } 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; - } - } + 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; + } + } } -static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects) +static void fluid_init_all_channels(bContext *C, + Object *UNUSED(fsDomain), + FluidsimSettings *domainSettings, + FluidAnimChannels *channels, + ListBase *fobjects) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Base *base; - int i; - int length = channels->length; - float eval_time; - - /* init time values (assuming that time moves at a constant speed; may be overridden later) */ - init_time(domainSettings, channels); - - /* 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 = FIRSTBASE(view_layer); 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 = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd); - - initElbeemMesh(depsgraph, scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex); - fobj->VertexCache = MEM_callocN(length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache"); - - MEM_freeN(verts); - MEM_freeN(tris); - } - - BLI_addtail(fobjects, fobj); - } - } - - /* now we loop over the frames and fill the allocated channels with data */ - for (i=0; i < channels->length; i++) { - FluidObject *fobj; - float viscosity, gravity[3]; - float timeAtFrame, time; - - eval_time = domainSettings->bakeStart + i; - - /* 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(CTX_data_main(C), depsgraph); - - /* now scene data should be current according to animation system, so we fill the channels */ - - /* Domain time */ - // TODO: have option for not running sim, time mangling, in which case second case comes in handy - if (channels->DomainTime) { - time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime; - timeAtFrame = channels->timeAtFrame[i] + time; - - channels->timeAtFrame[i+1] = timeAtFrame; - set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT); - } - else { - timeAtFrame = channels->timeAtFrame[i+1]; - } - - /* Domain properties - gravity/viscosity */ - 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); - - /* 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) ? 1 : 0); - float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f}; - - if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) - continue; - - /* init euler rotation values and convert to elbeem format */ - /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */ - if (i) { - copy_v3_v3(old_rot, fobj->Rotation + 4*(i-1)); - mul_v3_fl(old_rot, (float)-M_PI / 180.f); - } - - mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat); - mul_v3_fl(rot_d, -180.0f / (float)M_PI); - - 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->scale, i, CHANNEL_VEC); - set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); - set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); - - // printf("Active: %f, Frame: %f\n", active, timeAtFrame); - - 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(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i); - } - } - } + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Base *base; + int i; + int length = channels->length; + float eval_time; + + /* init time values (assuming that time moves at a constant speed; may be overridden later) */ + init_time(domainSettings, channels); + + /* 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 = FIRSTBASE(view_layer); 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 = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd); + + initElbeemMesh(depsgraph, + scene, + ob, + &fobj->numVerts, + &verts, + &fobj->numTris, + &tris, + 0, + modifierIndex); + fobj->VertexCache = MEM_callocN(length * ((fobj->numVerts * CHANNEL_VEC) + 1) * + sizeof(float), + "fluidobject VertexCache"); + + MEM_freeN(verts); + MEM_freeN(tris); + } + + BLI_addtail(fobjects, fobj); + } + } + + /* now we loop over the frames and fill the allocated channels with data */ + for (i = 0; i < channels->length; i++) { + FluidObject *fobj; + float viscosity, gravity[3]; + float timeAtFrame, time; + + eval_time = domainSettings->bakeStart + i; + + /* 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(CTX_data_main(C), depsgraph); + + /* now scene data should be current according to animation system, so we fill the channels */ + + /* Domain time */ + // TODO: have option for not running sim, time mangling, in which case second case comes in handy + if (channels->DomainTime) { + time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime; + timeAtFrame = channels->timeAtFrame[i] + time; + + channels->timeAtFrame[i + 1] = timeAtFrame; + set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT); + } + else { + timeAtFrame = channels->timeAtFrame[i + 1]; + } + + /* Domain properties - gravity/viscosity */ + 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); + + /* 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) ? 1 : 0); + float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f}; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) + continue; + + /* init euler rotation values and convert to elbeem format */ + /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */ + if (i) { + copy_v3_v3(old_rot, fobj->Rotation + 4 * (i - 1)); + mul_v3_fl(old_rot, (float)-M_PI / 180.f); + } + + mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat); + mul_v3_fl(rot_d, -180.0f / (float)M_PI); + + 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->scale, i, CHANNEL_VEC); + set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); + set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); + + // printf("Active: %f, Frame: %f\n", active, timeAtFrame); + + 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(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i); + } + } + } } static void export_fluid_objects(const bContext *C, ListBase *fobjects, Scene *scene, int length) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - FluidObject *fobj; - - for (fobj=fobjects->first; fobj; fobj=fobj->next) { - Object *ob = fobj->object; - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); - int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd); - - float *verts=NULL; - int *tris=NULL; - int numVerts=0, numTris=0; - bool 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(depsgraph, 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; - - /* Override user settings, only noslip is supported here! */ - if (fsmesh.type != OB_FLUIDSIM_CONTROL) - fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; - } - - elbeemAddMesh(&fsmesh); - - if (verts) MEM_freeN(verts); - if (tris) MEM_freeN(tris); - } + Depsgraph *depsgraph = CTX_data_depsgraph(C); + FluidObject *fobj; + + for (fobj = fobjects->first; fobj; fobj = fobj->next) { + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( + ob, eModifierType_Fluidsim); + int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd); + + float *verts = NULL; + int *tris = NULL; + int numVerts = 0, numTris = 0; + bool 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(depsgraph, 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; + + /* Override user settings, only noslip is supported here! */ + if (fsmesh.type != OB_FLUIDSIM_CONTROL) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; + } + + elbeemAddMesh(&fsmesh); + + if (verts) + MEM_freeN(verts); + if (tris) + MEM_freeN(tris); + } } static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain) { - Base *base; - Object *newdomain = NULL; - int channelObjCount = 0; - int fluidInputCount = 0; - - for (base = FIRSTBASE(view_layer); 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; - } - } - - /* 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++; - } - - 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 than 256 objects"); - return 0; - } - - if (fluidInputCount == 0) { - BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene"); - return 0; - } - - return 1; + Base *base; + Object *newdomain = NULL; + int channelObjCount = 0; + int fluidInputCount = 0; + + for (base = FIRSTBASE(view_layer); 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; + } + } + + /* 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++; + } + + 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 than 256 objects"); + return 0; + } + + if (fluidInputCount == 0) { + BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene"); + return 0; + } + + return 1; } +# define FLUID_SUFFIX_CONFIG "fluidsim.cfg" +# define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp") +# define FLUID_SUFFIX_SURFACE "fluidsurface" -#define FLUID_SUFFIX_CONFIG "fluidsim.cfg" -#define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp") -#define FLUID_SUFFIX_SURFACE "fluidsurface" - -static bool fluid_init_filepaths( - Main *bmain, ReportList *reports, FluidsimSettings *domainSettings, Object *fsDomain, - char *targetDir, char *targetFile) +static bool fluid_init_filepaths(Main *bmain, + ReportList *reports, + FluidsimSettings *domainSettings, + Object *fsDomain, + char *targetDir, + char *targetFile) { - const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; - - /* prepare names... */ - const char *relbase = modifier_path_relbase(bmain, fsDomain); - - /* We do not accept empty paths, they can end in random places silently, see T51176. */ - if (domainSettings->surfdataPath[0] == '\0') { - modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath), - OB_FLUIDSIM_SURF_DIR_DEFAULT); - BKE_reportf(reports, RPT_WARNING, "Fluidsim: empty cache path, reset to default '%s'", - domainSettings->surfdataPath); - } - - BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, relbase); - - /* .tmp: don't overwrite/delete original file */ - BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); - - /* Ensure whole path exists and is wirtable. */ - const bool dir_exists = BLI_dir_create_recursive(targetDir); - const bool is_writable = BLI_file_is_writable(targetFile); - - /* We change path to some presumably valid default value, but do not allow bake process to continue, - * this gives user chance to set manually another path. */ - if (!dir_exists || !is_writable) { - modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath), - OB_FLUIDSIM_SURF_DIR_DEFAULT); - - if (!dir_exists) { - BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not create cache directory '%s', reset to default '%s'", - targetDir, domainSettings->surfdataPath); - } - else { - BKE_reportf(reports, RPT_ERROR, "Fluidsim: cache directory '%s' is not writable, reset to default '%s'", - targetDir, domainSettings->surfdataPath); - } - - BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, relbase); - - /* .tmp: don't overwrite/delete original file */ - BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); - - /* Ensure whole path exists and is wirtable. */ - if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) { - BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not use default cache directory '%s', " - "please define a valid cache path manually", targetDir); - } - return false; - } - - return true; + const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; + + /* prepare names... */ + const char *relbase = modifier_path_relbase(bmain, fsDomain); + + /* We do not accept empty paths, they can end in random places silently, see T51176. */ + if (domainSettings->surfdataPath[0] == '\0') { + modifier_path_init(domainSettings->surfdataPath, + sizeof(domainSettings->surfdataPath), + OB_FLUIDSIM_SURF_DIR_DEFAULT); + BKE_reportf(reports, + RPT_WARNING, + "Fluidsim: empty cache path, reset to default '%s'", + domainSettings->surfdataPath); + } + + BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, relbase); + + /* .tmp: don't overwrite/delete original file */ + BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); + + /* Ensure whole path exists and is wirtable. */ + const bool dir_exists = BLI_dir_create_recursive(targetDir); + const bool is_writable = BLI_file_is_writable(targetFile); + + /* We change path to some presumably valid default value, but do not allow bake process to continue, + * this gives user chance to set manually another path. */ + if (!dir_exists || !is_writable) { + modifier_path_init(domainSettings->surfdataPath, + sizeof(domainSettings->surfdataPath), + OB_FLUIDSIM_SURF_DIR_DEFAULT); + + if (!dir_exists) { + BKE_reportf(reports, + RPT_ERROR, + "Fluidsim: could not create cache directory '%s', reset to default '%s'", + targetDir, + domainSettings->surfdataPath); + } + else { + BKE_reportf(reports, + RPT_ERROR, + "Fluidsim: cache directory '%s' is not writable, reset to default '%s'", + targetDir, + domainSettings->surfdataPath); + } + + BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, relbase); + + /* .tmp: don't overwrite/delete original file */ + BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); + + /* Ensure whole path exists and is wirtable. */ + if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) { + BKE_reportf(reports, + RPT_ERROR, + "Fluidsim: could not use default cache directory '%s', " + "please define a valid cache path manually", + targetDir); + } + return false; + } + + return true; } /* ******************************************************************************** */ @@ -687,392 +746,431 @@ static bool fluid_init_filepaths( /* ******************************************************************************** */ typedef struct FluidBakeJob { - /* from wmJob */ - void *owner; - short *stop, *do_update; - float *progress; - int current_frame; - elbeemSimulationSettings *settings; + /* from wmJob */ + void *owner; + short *stop, *do_update; + float *progress; + int current_frame; + elbeemSimulationSettings *settings; } FluidBakeJob; static void fluidbake_free(void *customdata) { - FluidBakeJob *fb= (FluidBakeJob *)customdata; - MEM_freeN(fb); + FluidBakeJob *fb = (FluidBakeJob *)customdata; + MEM_freeN(fb); } /* called by fluidbake, only to check job 'stop' value */ static int fluidbake_breakjob(void *customdata) { - FluidBakeJob *fb= (FluidBakeJob *)customdata; + FluidBakeJob *fb = (FluidBakeJob *)customdata; - if (fb->stop && *(fb->stop)) - return 1; + if (fb->stop && *(fb->stop)) + return 1; - /* 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.is_break); + /* 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.is_break); } /* called by fluidbake, wmJob sends notifier */ static void fluidbake_updatejob(void *customdata, float progress) { - FluidBakeJob *fb= (FluidBakeJob *)customdata; + FluidBakeJob *fb = (FluidBakeJob *)customdata; - *(fb->do_update) = true; - *(fb->progress) = progress; + *(fb->do_update) = true; + *(fb->progress) = progress; } static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress) { - FluidBakeJob *fb= (FluidBakeJob *)customdata; + FluidBakeJob *fb = (FluidBakeJob *)customdata; - fb->stop= stop; - fb->do_update = do_update; - fb->progress = progress; + fb->stop = stop; + fb->do_update = do_update; + fb->progress = progress; - G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */ + G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */ - elbeemSimulate(); - *do_update = true; - *stop = 0; + elbeemSimulate(); + *do_update = true; + *stop = 0; } static void fluidbake_endjob(void *customdata) { - FluidBakeJob *fb= (FluidBakeJob *)customdata; + FluidBakeJob *fb = (FluidBakeJob *)customdata; - if (fb->settings) { - MEM_freeN(fb->settings); - fb->settings = NULL; - } + if (fb->settings) { + MEM_freeN(fb->settings); + fb->settings = NULL; + } } static int runSimulationCallback(void *data, int status, int frame) { - FluidBakeJob *fb = (FluidBakeJob *)data; - elbeemSimulationSettings *settings = fb->settings; + FluidBakeJob *fb = (FluidBakeJob *)data; + elbeemSimulationSettings *settings = fb->settings; - if (status == FLUIDSIM_CBSTATUS_NEWFRAME) { - fluidbake_updatejob(fb, frame / (float)settings->noOfFrames); - //printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n", status, frame, settings->domainId, settings->noOfFrames ); // DEBUG - } + if (status == FLUIDSIM_CBSTATUS_NEWFRAME) { + fluidbake_updatejob(fb, frame / (float)settings->noOfFrames); + //printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n", status, frame, settings->domainId, settings->noOfFrames ); // DEBUG + } - if (fluidbake_breakjob(fb)) { - return FLUIDSIM_CBRET_ABORT; - } + if (fluidbake_breakjob(fb)) { + return FLUIDSIM_CBRET_ABORT; + } - return FLUIDSIM_CBRET_CONTINUE; + return FLUIDSIM_CBRET_CONTINUE; } -static void fluidbake_free_data(FluidAnimChannels *channels, ListBase *fobjects, elbeemSimulationSettings *fsset, FluidBakeJob *fb) +static void fluidbake_free_data(FluidAnimChannels *channels, + ListBase *fobjects, + elbeemSimulationSettings *fsset, + FluidBakeJob *fb) { - free_domain_channels(channels); - MEM_freeN(channels); - channels = NULL; - - free_all_fluidobject_channels(fobjects); - BLI_freelistN(fobjects); - MEM_freeN(fobjects); - fobjects = NULL; - - if (fsset) { - MEM_freeN(fsset); - fsset = NULL; - } - - if (fb) { - MEM_freeN(fb); - fb = NULL; - } + free_domain_channels(channels); + MEM_freeN(channels); + channels = NULL; + + free_all_fluidobject_channels(fobjects); + BLI_freelistN(fobjects); + MEM_freeN(fobjects); + fobjects = NULL; + + if (fsset) { + MEM_freeN(fsset); + fsset = NULL; + } + + if (fb) { + MEM_freeN(fb); + fb = NULL; + } } /* copied from rna_fluidsim.c: fluidsim_find_lastframe() */ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase) { - char targetDir[FILE_MAX], targetFile[FILE_MAX]; - char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX]; - char previewDir[FILE_MAX], previewFile[FILE_MAX]; - int curFrame = 1, exists = 0; - - BLI_join_dirfile(targetDir, sizeof(targetDir), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); - BLI_join_dirfile(targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME); - BLI_join_dirfile(previewDir, sizeof(previewDir), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); - - BLI_path_abs(targetDir, relbase); - BLI_path_abs(targetDirVel, relbase); - BLI_path_abs(previewDir, relbase); - - do { - BLI_strncpy(targetFile, targetDir, sizeof(targetFile)); - BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel)); - BLI_strncpy(previewFile, previewDir, sizeof(previewFile)); - - BLI_path_frame(targetFile, curFrame, 0); - BLI_path_frame(targetFileVel, curFrame, 0); - BLI_path_frame(previewFile, curFrame, 0); - - curFrame++; - - if ((exists = BLI_exists(targetFile))) { - BLI_delete(targetFile, false, false); - BLI_delete(targetFileVel, false, false); - BLI_delete(previewFile, false, false); - } - } while (exists); - - return; + char targetDir[FILE_MAX], targetFile[FILE_MAX]; + char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX]; + char previewDir[FILE_MAX], previewFile[FILE_MAX]; + int curFrame = 1, exists = 0; + + BLI_join_dirfile( + targetDir, sizeof(targetDir), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); + BLI_join_dirfile( + targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME); + BLI_join_dirfile( + previewDir, sizeof(previewDir), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); + + BLI_path_abs(targetDir, relbase); + BLI_path_abs(targetDirVel, relbase); + BLI_path_abs(previewDir, relbase); + + do { + BLI_strncpy(targetFile, targetDir, sizeof(targetFile)); + BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel)); + BLI_strncpy(previewFile, previewDir, sizeof(previewFile)); + + BLI_path_frame(targetFile, curFrame, 0); + BLI_path_frame(targetFileVel, curFrame, 0); + BLI_path_frame(previewFile, curFrame, 0); + + curFrame++; + + if ((exists = BLI_exists(targetFile))) { + BLI_delete(targetFile, false, false); + BLI_delete(targetFileVel, false, false); + BLI_delete(previewFile, false, false); + } + } while (exists); + + return; } static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - int i; - FluidsimSettings *domainSettings; - - char debugStrBuffer[256]; - - int gridlevels = 0; - const char *relbase= modifier_path_relbase(bmain, fsDomain); - const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp - const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; - const char *suffixSurface = FLUID_SUFFIX_SURFACE; - - char targetDir[FILE_MAX]; // store & modify output settings - char targetFile[FILE_MAX]; // temp. store filename from targetDir for access - - float domainMat[4][4]; - float invDomMat[4][4]; - - 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; - - FluidBakeJob *fb; - elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); - - fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); - - if (BLI_getenv(strEnvName)) { - int dlevel = atoi(BLI_getenv(strEnvName)); - elbeemSetDebugLevel(dlevel); - BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", strEnvName); - elbeemDebugOut(debugStrBuffer); - } - - /* 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)"); - fluidbake_free_data(channels, fobjects, fsset, fb); - return 0; - } - - /* check scene for sane object/modifier settings */ - if (!fluid_validate_scene(reports, view_layer, fsDomain)) { - fluidbake_free_data(channels, fobjects, fsset, fb); - return 0; - } - - /* these both have to be valid, otherwise we wouldn't be here */ - fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); - domainSettings = fluidmd->fss; - 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); - - // reset last valid frame - domainSettings->lastgoodframe = -1; - - /* delete old baked files */ - fluidsim_delete_until_lastframe(domainSettings, relbase); - - /* rough check of settings... */ - if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { - BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz, domainSettings->resolutionxyz); - elbeemDebugOut(debugStrBuffer); - domainSettings->previewresxyz = domainSettings->resolutionxyz; - } - // set adaptive coarsening according to resolutionxyz - // this should do as an approximation, with in/outflow - // doing this more accurate would be overkill - // perhaps add manual setting? - if (domainSettings->maxRefine <0) { - if (domainSettings->resolutionxyz>128) { - gridlevels = 2; - } - else if (domainSettings->resolutionxyz > 64) { - gridlevels = 1; - } - else { - gridlevels = 0; - } - } - else { - gridlevels = domainSettings->maxRefine; - } - BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name, gridlevels); - elbeemDebugOut(debugStrBuffer); - - - - /* ******** prepare output file paths ******** */ - if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) { - fluidbake_free_data(channels, fobjects, fsset, fb); - return false; - } - - channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) - channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames; - - /* ******** initialize and allocate animation channels ******** */ - fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); - - /* reset to original current frame */ - scene->r.cfra = origFrame; - ED_update_for_newframe(CTX_data_main(C), depsgraph); - - /* ******** init domain object's matrix ******** */ - copy_m4_m4(domainMat, fsDomain->obmat); - if (!invert_m4_m4(invDomMat, domainMat)) { - BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); - elbeemDebugOut(debugStrBuffer); - BKE_report(reports, RPT_ERROR, "Invalid object matrix"); - - fluidbake_free_data(channels, fobjects, fsset, fb); - return 0; - } - - /* ******** start writing / exporting ******** */ - // use .tmp, don't overwrite/delete original file - BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); - - /* ******** export domain to elbeem ******** */ - elbeemResetSettings(fsset); - fsset->version = 1; - fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : domainSettings->threads; - // 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 - - BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, 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; - BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); - - // 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; - - /* use domainobsType also for surface generation flag (bit: >=64) */ - if (domainSettings->typeFlags & OB_FSSG_NOOBS) - fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; - else - fsset->mFsSurfGenSetting = 0; // "normal" mode - - 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]; - } - } } - - /* ******** init solver with settings ******** */ - elbeemInit(); - elbeemAddDomain(fsset); - - /* ******** export all fluid objects to elbeem ******** */ - export_fluid_objects(C, fobjects, scene, channels->length); - - /* custom data for fluid bake job */ - fb->settings = fsset; - - if (do_job) { - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", - WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_FLUID); - - /* setup job */ - WM_jobs_customdata_set(wm_job, fb, fluidbake_free); - WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); - WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); - - WM_jobs_start(CTX_wm_manager(C), wm_job); - } - else { - short dummy_stop = 0, dummy_do_update = 0; - float dummy_progress = 0.0f; - - /* blocking, use with exec() */ - fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); - fluidbake_endjob((void *)fb); - fluidbake_free((void *)fb); - } - - /* ******** free stored animation data ******** */ - fluidbake_free_data(channels, fobjects, NULL, NULL); - - // elbeemFree(); - return 1; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int i; + FluidsimSettings *domainSettings; + + char debugStrBuffer[256]; + + int gridlevels = 0; + const char *relbase = modifier_path_relbase(bmain, fsDomain); + const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp + const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; + const char *suffixSurface = FLUID_SUFFIX_SURFACE; + + char targetDir[FILE_MAX]; // store & modify output settings + char targetFile[FILE_MAX]; // temp. store filename from targetDir for access + + float domainMat[4][4]; + float invDomMat[4][4]; + + 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; + + FluidBakeJob *fb; + elbeemSimulationSettings *fsset = MEM_callocN(sizeof(elbeemSimulationSettings), + "Fluid sim settings"); + + fb = MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); + + if (BLI_getenv(strEnvName)) { + int dlevel = atoi(BLI_getenv(strEnvName)); + elbeemSetDebugLevel(dlevel); + BLI_snprintf(debugStrBuffer, + sizeof(debugStrBuffer), + "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", + strEnvName); + elbeemDebugOut(debugStrBuffer); + } + + /* 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)"); + fluidbake_free_data(channels, fobjects, fsset, fb); + return 0; + } + + /* check scene for sane object/modifier settings */ + if (!fluid_validate_scene(reports, view_layer, fsDomain)) { + fluidbake_free_data(channels, fobjects, fsset, fb); + return 0; + } + + /* these both have to be valid, otherwise we wouldn't be here */ + fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); + domainSettings = fluidmd->fss; + 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); + + // reset last valid frame + domainSettings->lastgoodframe = -1; + + /* delete old baked files */ + fluidsim_delete_until_lastframe(domainSettings, relbase); + + /* rough check of settings... */ + if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { + BLI_snprintf(debugStrBuffer, + sizeof(debugStrBuffer), + "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", + domainSettings->previewresxyz, + domainSettings->resolutionxyz); + elbeemDebugOut(debugStrBuffer); + domainSettings->previewresxyz = domainSettings->resolutionxyz; + } + // set adaptive coarsening according to resolutionxyz + // this should do as an approximation, with in/outflow + // doing this more accurate would be overkill + // perhaps add manual setting? + if (domainSettings->maxRefine < 0) { + if (domainSettings->resolutionxyz > 128) { + gridlevels = 2; + } + else if (domainSettings->resolutionxyz > 64) { + gridlevels = 1; + } + else { + gridlevels = 0; + } + } + else { + gridlevels = domainSettings->maxRefine; + } + BLI_snprintf(debugStrBuffer, + sizeof(debugStrBuffer), + "fluidsimBake::msg: Baking %s, refine: %d\n", + fsDomain->id.name, + gridlevels); + elbeemDebugOut(debugStrBuffer); + + /* ******** prepare output file paths ******** */ + if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) { + fluidbake_free_data(channels, fobjects, fsset, fb); + return false; + } + + channels->length = + scene->r + .efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) + channels->aniFrameTime = (double)((double)domainSettings->animEnd - + (double)domainSettings->animStart) / + (double)noFrames; + + /* ******** initialize and allocate animation channels ******** */ + fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); + + /* reset to original current frame */ + scene->r.cfra = origFrame; + ED_update_for_newframe(CTX_data_main(C), depsgraph); + + /* ******** init domain object's matrix ******** */ + copy_m4_m4(domainMat, fsDomain->obmat); + if (!invert_m4_m4(invDomMat, domainMat)) { + BLI_snprintf( + debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); + elbeemDebugOut(debugStrBuffer); + BKE_report(reports, RPT_ERROR, "Invalid object matrix"); + + fluidbake_free_data(channels, fobjects, fsset, fb); + return 0; + } + + /* ******** start writing / exporting ******** */ + // use .tmp, don't overwrite/delete original file + BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); + + /* ******** export domain to elbeem ******** */ + elbeemResetSettings(fsset); + fsset->version = 1; + fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : + domainSettings->threads; + // 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 + + BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, 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; + BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); + + // 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; + + /* use domainobsType also for surface generation flag (bit: >=64) */ + if (domainSettings->typeFlags & OB_FSSG_NOOBS) + fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; + else + fsset->mFsSurfGenSetting = 0; // "normal" mode + + 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]; + } + } + } + + /* ******** init solver with settings ******** */ + elbeemInit(); + elbeemAddDomain(fsset); + + /* ******** export all fluid objects to elbeem ******** */ + export_fluid_objects(C, fobjects, scene, channels->length); + + /* custom data for fluid bake job */ + fb->settings = fsset; + + if (do_job) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Fluid Simulation", + WM_JOB_PROGRESS, + WM_JOB_TYPE_OBJECT_SIM_FLUID); + + /* setup job */ + WM_jobs_customdata_set(wm_job, fb, fluidbake_free); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + short dummy_stop = 0, dummy_do_update = 0; + float dummy_progress = 0.0f; + + /* blocking, use with exec() */ + fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); + fluidbake_endjob((void *)fb); + fluidbake_free((void *)fb); + } + + /* ******** free stored animation data ******** */ + fluidbake_free_data(channels, fobjects, NULL, NULL); + + // elbeemFree(); + return 1; } static void UNUSED_FUNCTION(fluidsimFreeBake)(Object *UNUSED(ob)) { - /* not implemented yet */ + /* not implemented yet */ } #else /* WITH_MOD_FLUID */ /* only compile dummy functions */ -static int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object *UNUSED(ob), short UNUSED(do_job)) +static int fluidsimBake(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Object *UNUSED(ob), + short UNUSED(do_job)) { - return 0; + return 0; } #endif /* WITH_MOD_FLUID */ @@ -1081,33 +1179,33 @@ static int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - /* only one bake job at a time */ - if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) - return OPERATOR_CANCELLED; + /* only one bake job at a time */ + if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) + return OPERATOR_CANCELLED; - if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), true)) - return OPERATOR_CANCELLED; + if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), true)) + return OPERATOR_CANCELLED; - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int fluid_bake_exec(bContext *C, wmOperator *op) { - if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) - return OPERATOR_CANCELLED; + if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) + return OPERATOR_CANCELLED; - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FLUID_OT_bake(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Fluid Simulation Bake"; - ot->description = "Bake fluid simulation"; - ot->idname = "FLUID_OT_bake"; - - /* api callbacks */ - ot->invoke = fluid_bake_invoke; - ot->exec = fluid_bake_exec; - ot->poll = ED_operator_object_active_editable; + /* identifiers */ + ot->name = "Fluid Simulation Bake"; + ot->description = "Bake fluid simulation"; + ot->idname = "FLUID_OT_bake"; + + /* api callbacks */ + ot->invoke = fluid_bake_invoke; + ot->exec = fluid_bake_exec; + ot->poll = ED_operator_object_active_editable; } |