diff options
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_depsgraph.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_particle.h | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_pointcache.h | 74 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_softbody.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 539 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/depsgraph.c | 76 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/modifier.c | 12 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 48 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 475 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 383 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/softbody.c | 732 |
14 files changed, 1454 insertions, 942 deletions
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 418102aa973..f1a439e2e04 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -147,16 +147,18 @@ ClothSpring; /* These are the bits used in SimSettings.flags. */ typedef enum { - CLOTH_SIMSETTINGS_FLAG_RESET = ( 1 << 1 ), // The CM object requires a reinitializaiton. + //CLOTH_SIMSETTINGS_FLAG_RESET = ( 1 << 1 ), // The CM object requires a reinitializaiton. CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled - CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT = ( 1 << 5 ), // true if tearing is enabled - CLOTH_SIMSETTINGS_FLAG_EDITMODE = ( 1 << 6 ), // are we in editmode? -several things disabled - CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE = ( 1 << 7 ), /* force cache freeing */ + //CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT = ( 1 << 5 ), // true if tearing is enabled + //CLOTH_SIMSETTINGS_FLAG_EDITMODE = ( 1 << 6 ), // are we in editmode? -several things disabled + //CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE = ( 1 << 7 ), /* force cache freeing */ CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */ - CLOTH_SIMSETTINGS_FLAG_LOADED = ( 1 << 9 ), /* did we just got load? */ - CLOTH_SIMSETTINGS_FLAG_AUTOPROTECT = ( 1 << 10 ), /* is autoprotect enabled? */ + //CLOTH_SIMSETTINGS_FLAG_LOADED = ( 1 << 9 ), /* did we just got load? */ + //CLOTH_SIMSETTINGS_FLAG_AUTOPROTECT = ( 1 << 10 ), /* is autoprotect enabled? */ + //CLOTH_SIMSETTINGS_FLAG_CCACHE_OUTDATED = (1 << 11), /* while protected, did cache get outdated? */ + CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12) /* edit cache in editmode */ } CLOTH_SIMSETTINGS_FLAGS; /* COLLISION FLAGS */ diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index 294f61e54bd..36f26d42cee 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -104,7 +104,7 @@ void DAG_scene_update_flags(struct Scene *sce, unsigned int lay); void DAG_object_update_flags(struct Scene *sce, struct Object *ob, unsigned int lay); /* flushes all recalc flags in objects down the dependency tree */ -void DAG_scene_flush_update(struct Scene *sce, unsigned int lay); +void DAG_scene_flush_update(struct Scene *sce, unsigned int lay, int time); /* flushes all recalc flags for this object down the dependency tree */ void DAG_object_flush_update(struct Scene *sce, struct Object *ob, short flag); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index f134c4597c1..45be121661b 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -41,6 +41,7 @@ struct ParticleSystemModifierData; struct ParticleSystem; struct ParticleKey; +struct ParticleSettings; struct HairKey; struct Main; @@ -222,9 +223,6 @@ void psys_render_restore(struct Object *ob, struct ParticleSystem *psys); int psys_render_simplify_distribution(struct ParticleThreadContext *ctx, int tot); int psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params); -void clear_particles_from_cache(struct Object *ob, struct ParticleSystem *psys, int cfra); -//void psys_remove_from_particle_list(struct Object *ob, short nbr, struct ParticleSystem *psys); - void psys_interpolate_uvs(struct MTFace *tface, int quad, float *uv, float *uvco); void psys_interpolate_mcol(struct MCol *mcol, int quad, float *uv, struct MCol *mc); @@ -237,6 +235,10 @@ struct ParticleSettings *psys_new_settings(char *name, struct Main *main); struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part); void psys_flush_settings(struct ParticleSettings *part, int event, int hair_recalc); +struct LinkNode *psys_using_settings(struct ParticleSettings *part, int flush_update); +void psys_changed_type(struct ParticleSystem *psys); +void psys_reset(struct ParticleSystem *psys, int mode); + void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys); void psys_cache_paths(struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); @@ -251,7 +253,7 @@ int psys_get_particle_state(struct Object *ob, struct ParticleSystem *psys, int void psys_get_dupli_texture(struct Object *ob, struct ParticleSettings *part, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, float *uv, float *orco); void psys_get_dupli_path_transform(struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, struct ParticleCacheKey *cache, float mat[][4], float *scale); -ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys, int totthread); +ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys); int psys_threads_init_distribution(ParticleThread *threads, struct DerivedMesh *dm, int from); int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate); void psys_threads_free(ParticleThread *threads); @@ -298,6 +300,11 @@ void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys); int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node); +/* psys_reset */ +#define PSYS_RESET_ALL 1 +#define PSYS_RESET_DEPSGRAPH 2 +#define PSYS_RESET_CHILDREN 3 + /* ParticleEffectorCache->type */ #define PSYS_EC_EFFECTOR 1 #define PSYS_EC_DEFLECT 2 diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 12068f7dedf..5bc467465a8 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -31,24 +31,84 @@ #include "DNA_ID.h" -/* options for clearing pointcache - used for BKE_ptcache_id_clear - Before and after are non inclusive (they wont remove the cfra) */ +/* Point cache clearing option, for BKE_ptcache_id_clear, before + * and after are non inclusive (they wont remove the cfra) */ #define PTCACHE_CLEAR_ALL 0 #define PTCACHE_CLEAR_FRAME 1 #define PTCACHE_CLEAR_BEFORE 2 #define PTCACHE_CLEAR_AFTER 3 +/* Point cache reset options */ +#define PTCACHE_RESET_DEPSGRAPH 0 +#define PTCACHE_RESET_BAKED 1 +#define PTCACHE_RESET_OUTDATED 2 + /* Add the blendfile name after blendcache_ */ #define PTCACHE_EXT ".bphys" #define PTCACHE_PATH "blendcache_" +/* File open options, for BKE_ptcache_file_open */ +#define PTCACHE_FILE_READ 0 +#define PTCACHE_FILE_WRITE 1 + +/* PTCacheID types */ +#define PTCACHE_TYPE_SOFTBODY 0 +#define PTCACHE_TYPE_PARTICLES 1 +#define PTCACHE_TYPE_CLOTH 2 + +/* Structs */ +struct Object; +struct SoftBody; +struct ParticleSystem; +struct ClothModifierData; +struct PointCache; +struct ListBase; + +typedef struct PTCacheFile { + FILE *fp; +} PTCacheFile; + +typedef struct PTCacheID { + struct PTCacheID *next, *prev; + + struct Object *ob; + void *data; + int type; + int stack_index; + + struct PointCache *cache; +} PTCacheID; + +/* Creating ID's */ +void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb); +void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys); +void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd); + +void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob); + /* Global funcs */ void BKE_ptcache_remove(void); -/* Object spesific funcs */ -int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext); -FILE * BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index); -void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index); -int BKE_ptcache_id_exist(struct ID *id, int cfra, int stack_index); +/* ID specific functions */ +void BKE_ptcache_id_clear(PTCacheID *id, int mode, int cfra); +int BKE_ptcache_id_exist(PTCacheID *id, int cfra); +int BKE_ptcache_id_reset(PTCacheID *id, int mode); +void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale); +int BKE_ptcache_object_reset(struct Object *ob, int mode); + +/* File reading/writing */ +PTCacheFile *BKE_ptcache_file_open(PTCacheID *id, int mode, int cfra); +void BKE_ptcache_file_close(PTCacheFile *pf); +int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot); +int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot); + +/* Continue physics */ +void BKE_ptcache_set_continue_physics(int enable); +int BKE_ptcache_get_continue_physics(void); + +/* Point Cache */ +struct PointCache *BKE_ptcache_add(void); +void BKE_ptcache_free(struct PointCache *cache); +struct PointCache *BKE_ptcache_copy(struct PointCache *cache); #endif diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h index 91bc4cc070d..8a3688fbe09 100644 --- a/source/blender/blenkernel/BKE_softbody.h +++ b/source/blender/blenkernel/BKE_softbody.h @@ -55,7 +55,8 @@ extern struct SoftBody *sbNew(void); /* frees internal data and softbody itself */ extern void sbFree(struct SoftBody *sb); -extern void softbody_clear_cache(struct Object *ob, float framenr); +/* frees simulation data to reset simulation */ +extern void sbFreeSimulation(struct SoftBody *sb); /* do one simul step, reading and writing vertex locs from given array */ extern void sbObjectStep(struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts); @@ -67,6 +68,8 @@ extern void sbObjectToSoftbody(struct Object *ob); /* pass NULL to unlink again */ extern void sbSetInterruptCallBack(int (*f)(void)); +/* writing to cache for bake editing */ +extern void sbWriteCache(struct Object *ob, int framenr); #endif diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index b0103fa812b..7624ca04984 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2012,8 +2012,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], if((md->mode & required_mode) != required_mode) continue; if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue; if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires " - "original data (bad stack position)."); + modifier_setError(md, "Modifier requires original data, bad stack position."); continue; } if(mti->isDisabled && mti->isDisabled(md)) continue; @@ -2194,8 +2193,7 @@ static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) if((md->mode & required_mode) != required_mode) return 0; if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires" - "original data (bad stack position)."); + modifier_setError(md, "Modifier requires original data, bad stack position."); return 0; } if(mti->isDisabled && mti->isDisabled(md)) return 0; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 6123b1b5e35..15f4051c109 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -34,6 +34,7 @@ #include "DNA_cloth_types.h" #include "DNA_mesh_types.h" +#include "DNA_object_force.h" #include "DNA_scene_types.h" #include "BKE_deform.h" @@ -92,7 +93,7 @@ static CM_SOLVER_DEF solvers [] = */ static void cloth_to_object (Object *ob, ClothModifierData *clmd, DerivedMesh *dm); static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ); -static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr); +static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first); int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ); static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ); @@ -121,18 +122,11 @@ void cloth_init ( ClothModifierData *clmd ) clmd->sim_parms->Cvi = 1.0; clmd->sim_parms->mass = 0.3f; clmd->sim_parms->stepsPerFrame = 5; - clmd->sim_parms->sim_time = 1.0; - clmd->sim_parms->flags = CLOTH_SIMSETTINGS_FLAG_AUTOPROTECT; + clmd->sim_parms->flags = 0; clmd->sim_parms->solver_type = 0; clmd->sim_parms->preroll = 0; clmd->sim_parms->maxspringlen = 10; - clmd->sim_parms->firstframe = 1; - clmd->sim_parms->lastframe = 250; clmd->sim_parms->vgroup_mass = 0; - clmd->sim_parms->lastcachedframe = 0; - clmd->sim_parms->editedframe = 0; - clmd->sim_parms->autoprotect = 25; - clmd->sim_parms->firstcachedframe = -1.0; clmd->sim_parms->avg_spring_len = 0.0; clmd->sim_parms->presets = 2; /* cotton as start setting */ clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */ @@ -246,395 +240,266 @@ int modifiers_indexInObject(Object *ob, ModifierData *md_seek); int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr) { - FILE *fp = NULL; - int stack_index = -1; - unsigned int a, ret = 1; + PTCacheID pid; + PTCacheFile *pf; Cloth *cloth = clmd->clothObject; + unsigned int a, ret = 1; if(!cloth) return 0; - stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - - fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index); - if(!fp) - ret = 0; - else { - for(a = 0; a < cloth->numverts; a++) - { - if(fread(&cloth->verts[a].x, sizeof(float), 3, fp) != 3) - { + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr); + if(pf) { + for(a = 0; a < cloth->numverts; a++) { + if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].x, 3)) { ret = 0; break; } - if(fread(&cloth->verts[a].xconst, sizeof(float), 3, fp) != 3) - { + if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].xconst, 3)) { ret = 0; break; } - if(fread(&cloth->verts[a].v, sizeof(float), 3, fp) != 3) - { + if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].v, 3)) { ret = 0; break; } } - fclose(fp); - - if(clmd->sim_parms->lastcachedframe < framenr) - { - if(G.rt > 0) - printf("cloth_read_cache problem: lnex - f#: %f, lastCF: %d\n", framenr, clmd->sim_parms->lastcachedframe); - } - - if(G.rt > 0) - printf("cloth_read_cache: %f successfully \n", framenr); + BKE_ptcache_file_close(pf); } - - if(G.rt > 0) - printf("cloth_read_cache: %f\n", framenr); + else + ret = 0; return ret; } void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr) { - int stack_index = -1; + PTCacheID pid; + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + // don't do anything as long as we're in editmode! - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE) - { - /* delete cache free request */ - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - + if(pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE) return; - } - - /* clear cache if specific frame cleaning requested or cache is not protected */ - if((!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)) || (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE)) - { - stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - - BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_AFTER, framenr, stack_index); - - /* update last cached frame # */ - clmd->sim_parms->lastcachedframe = framenr; - - /* update first cached frame # */ - if((framenr < clmd->sim_parms->firstcachedframe) && (clmd->sim_parms->firstcachedframe >=0.0)) - clmd->sim_parms->firstcachedframe = -1.0; - - if(G.rt > 0) - printf("cloth_clear_cache: %f\n", framenr); - } - - /* delete cache free request */ - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr); } + void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr) { - FILE *fp = NULL; - int stack_index = -1; - unsigned int a; Cloth *cloth = clmd->clothObject; - - if(G.rt > 0) - printf("cloth_write_cache: %f\n", framenr); + PTCacheID pid; + PTCacheFile *pf; + unsigned int a; if(!cloth) - { - if(G.rt > 0) - printf("cloth_write_cache: no cloth\n"); return; - } - - stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index); - if(!fp) - { - if(G.rt > 0) - printf("cloth_write_cache: no fp\n"); + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr); + if(!pf) return; - } - for(a = 0; a < cloth->numverts; a++) - { - fwrite(&cloth->verts[a].x, sizeof(float),3,fp); - fwrite(&cloth->verts[a].xconst, sizeof(float),3,fp); - fwrite(&cloth->verts[a].v, sizeof(float),3,fp); + for(a = 0; a < cloth->numverts; a++) { + BKE_ptcache_file_write_floats(pf, cloth->verts[a].x, 3); + BKE_ptcache_file_write_floats(pf, cloth->verts[a].xconst, 3); + BKE_ptcache_file_write_floats(pf, cloth->verts[a].v, 3); } - /* update last cached frame # */ - clmd->sim_parms->lastcachedframe = MAX2(clmd->sim_parms->lastcachedframe, framenr); + BKE_ptcache_file_close(pf); +} + +static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) +{ + PointCache *cache; + + cache= clmd->point_cache; + + /* initialize simulation data if it didn't exist already */ + if(clmd->clothObject == NULL) { + if(!cloth_from_object(ob, clmd, result, framenr, 1)) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + return 0; + } + + if(clmd->clothObject == NULL) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + return 0; + } - /* update first cached frame # */ - if((clmd->sim_parms->firstcachedframe < 0.0) || ((framenr < clmd->sim_parms->firstcachedframe) && (clmd->sim_parms->firstcachedframe > 0.0))) - clmd->sim_parms->firstcachedframe = framenr; + implicit_set_positions(clmd); + } + + return 1; +} + +static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) +{ + ClothVertex *verts = NULL; + Cloth *cloth; + ListBase *effectors = NULL; + MVert *mvert; + int i, ret = 0; + + /* simulate 1 frame forward */ + cloth = clmd->clothObject; + verts = cloth->verts; + mvert = result->getVertArray(result); + + /* force any pinned verts to their constrained location. */ + for(i = 0; i < clmd->clothObject->numverts; i++, verts++) { + /* save the previous position. */ + VECCOPY(verts->xold, verts->xconst); + VECCOPY(verts->txold, verts->x); + + /* Get the current position. */ + VECCOPY(verts->xconst, mvert[i].co); + Mat4MulVecfl(ob->obmat, verts->xconst); + } - if(G.rt > 0) - printf("lcf: %d, framenr: %f\n", clmd->sim_parms->lastcachedframe, framenr); + tstart(); + + /* call the solver. */ + if(solvers [clmd->sim_parms->solver_type].solver) + ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors); + + tend(); - fclose(fp); + /* printf ( "Cloth simulation time: %f\n", ( float ) tval() ); */ + + return ret; } /************************************************ * clothModifier_do - main simulation function ************************************************/ -DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) - +DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { - unsigned int i; - Cloth *cloth = clmd->clothObject; - float framenr = G.scene->r.cfra; - float current_time = bsystem_time ( ob, ( float ) G.scene->r.cfra, 0.0 ); - ListBase *effectors = NULL; - ClothVertex *verts = NULL; - float deltaTime = current_time - clmd->sim_parms->sim_time; - unsigned int numverts = -1; - unsigned int numedges = -1; - unsigned int numfaces = -1; - MVert *mvert = NULL; - MEdge *medge = NULL; - MFace *mface = NULL; - DerivedMesh *result = NULL; - int ret = 0; - - if(G.rt > 0) - printf("clothModifier_do start\n"); - - /* we're getting called two times during file load, - resulting in a not valid G.relbase on the first time (cache makes problems) - --> just return back */ - if((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_LOADED) && (!G.relbase_valid)) - { - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_LOADED; - return dm; - } - + DerivedMesh *result; + PointCache *cache; + PTCacheID pid; + float timescale; + int framedelta, framenr, startframe, endframe; + + framenr= (int)G.scene->r.cfra; + cache= clmd->point_cache; result = CDDM_copy(dm); - - if(!result) - { + + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, ×cale); + clmd->sim_parms->timescale= timescale; + + /* TODO: use timescale somewhere! */ + + if(!result) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; return dm; } - numverts = result->getNumVerts(result); - numedges = result->getNumEdges(result); - numfaces = result->getNumFaces(result); - mvert = result->getVertArray(result); - medge = result->getEdgeArray(result); - mface = result->getFaceArray(result); - - /* check if cache is active / if file is already saved */ - /* - if ((!G.relbase_valid) && ( deltaTime != 1.0f )) - { - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET; -} - */ - - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_RESET) - { - cloth_free_modifier (ob, clmd); - if(G.rt > 0) - printf("clothModifier_do CLOTH_SIMSETTINGS_FLAG_RESET\n"); - - // prevent rebuilding of cloth each time you move backward - if(deltaTime < 0.0) + /* verify we still have the same number of vertices, if not do nothing. + * note that this should only happen if the number of vertices changes + * during an animation due to a preceding modifier, this should not + * happen because of object changes! */ + if(clmd->clothObject) { + if(result->getNumVerts(result) != clmd->clothObject->numverts) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; return result; + } } // unused in the moment, calculated seperately in implicit.c clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; - - if ( ( clmd->clothObject == NULL ) || (clmd->clothObject && (numverts != clmd->clothObject->numverts )) ) - { - /* only force free the cache if we have a different number of verts */ - if(clmd->clothObject && (numverts != clmd->clothObject->numverts )) - { - if(G.rt > 0) - printf("Force Freeing: numverts != clmd->clothObject->numverts\n"); - - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - cloth_free_modifier ( ob, clmd ); - } - - cloth_clear_cache(ob, clmd, 0); - - if ( !cloth_from_object ( ob, clmd, result, framenr ) ) - return result; - - if ( clmd->clothObject == NULL ) + + /* handle continuous simulation with the play button */ + if(BKE_ptcache_get_continue_physics()) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + + /* do simulation */ + if(!do_init_cloth(ob, clmd, result, framenr)) return result; - - cloth = clmd->clothObject; - - if(!cloth_read_cache(ob, clmd, framenr)) - { - /* save first frame in case we have a reseted object - and we move one frame forward. - In that case we would only start with the SECOND frame - if we don't save the current state before - TODO PROBLEM: IMHO we can't track external movement from the - first frame in this case! */ - /* - if ( deltaTime == 1.0f ) - cloth_write_cache(ob, clmd, framenr-1.0); - */ - if(G.rt > 0) - printf("cloth_from_object NO cloth_read_cache cloth_write_cache\n"); - } - else - { - if(G.rt > 0) - printf("cloth_from_object cloth_read_cache\n"); - - implicit_set_positions(clmd); - } - - clmd->sim_parms->sim_time = current_time; - } - - // only be active during a specific period: - // that's "first frame" and "last frame" on GUI - if ( current_time < clmd->sim_parms->firstframe ) - { - if(G.rt > 0) - printf("current_time < clmd->sim_parms->firstframe\n"); + + do_step_cloth(ob, clmd, result, framenr); + cloth_to_object(ob, clmd, result); + return result; } - else if ( current_time > clmd->sim_parms->lastframe ) - { - int stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - - if(G.rt > 0) - printf("current_time > clmd->sim_parms->lastframe\n"); - - if(BKE_ptcache_id_exist((ID *)ob, clmd->sim_parms->lastcachedframe, stack_index)) - { - if(cloth_read_cache(ob, clmd, clmd->sim_parms->lastcachedframe)) - { - implicit_set_positions(clmd); - - // Copy the result back to the object. - cloth_to_object (ob, clmd, result); - } - } + + /* simulation is only active during a specific period */ + if(framenr < startframe) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; return result; } - - // check for autoprotection, but only if cache active - if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_AUTOPROTECT) - { - if((framenr >= clmd->sim_parms->autoprotect) && (G.relbase_valid)) - { - if(G.rt > 0) - printf("fr#: %f, auto: %d\n", framenr, clmd->sim_parms->autoprotect); - - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT; - } + else if(framenr > endframe) { + framenr= endframe; } - /* nice moving one frame forward */ - if ( deltaTime == 1.0f ) - { - clmd->sim_parms->sim_time = current_time; - - if(G.rt > 0) - printf("clothModifier_do deltaTime=1\n"); - - if(!cloth_read_cache(ob, clmd, framenr)) - { - verts = cloth->verts; + /* dt is unused at the moment, calculated seperately in implicit.c */ + clmd->sim_parms->dt= 1.0f/clmd->sim_parms->stepsPerFrame; - // Force any pinned verts to their constrained location. - for ( i = 0; i < clmd->clothObject->numverts; i++, verts++ ) - { - // Save the previous position. - VECCOPY ( verts->xold, verts->xconst ); - VECCOPY ( verts->txold, verts->x ); + if(cache->flag & PTCACHE_SIMULATION_VALID) + framedelta= framenr - cache->simframe; + else + framedelta= -1; - // Get the current position. - VECCOPY ( verts->xconst, mvert[i].co ); - Mat4MulVecfl ( ob->obmat, verts->xconst ); - } - - tstart(); + /* initialize simulation data if it didn't exist already */ + if(!do_init_cloth(ob, clmd, result, framenr)) + return result; - // Call the solver. - if ( solvers [clmd->sim_parms->solver_type].solver ) - { - ret = solvers [clmd->sim_parms->solver_type].solver ( ob, framenr, clmd, effectors ); - } + /* try to read from cache */ + if(cloth_read_cache(ob, clmd, framenr)) { + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; - tend(); - // printf ( "Cloth simulation time: %f\n", ( float ) tval() ); - - if(ret) - cloth_write_cache(ob, clmd, framenr); - else - clmd->sim_parms->sim_time--; - } - else - { - if(G.rt > 0) - printf("clothModifier_do deltaTime=1 cacheread\n"); - implicit_set_positions(clmd); - } - - // Copy the result back to the object. + implicit_set_positions(clmd); cloth_to_object (ob, clmd, result); + + return result; } - else if(deltaTime == 0.0f) - { - if(G.rt > 0) - printf("dt = 0, %f\n", framenr); - if(cloth_read_cache(ob, clmd, framenr)) - { - cloth_to_object (ob, clmd, result); - implicit_set_positions(clmd); - } - else /* same cache parts are missing */ - { - /* jump to a non-existing frame makes sim reset if cache is not protected */ - if(!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)) - { - /* prevent freeing when used with vectorblur */ - if(!useRenderParams) - { - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - cloth_clear_cache(ob, clmd, 0); - - cloth_write_cache(ob, clmd, framenr); - } - } - } + else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + /* if baked and nothing in cache, do nothing */ + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + return result; } - else - { - if(G.rt > 0) - printf("dt > 1.0 || dt < 0.0, %f, st: %f, ct: %f\n", framenr, clmd->sim_parms->sim_time, current_time); - if(cloth_read_cache(ob, clmd, framenr)) - { - cloth_to_object (ob, clmd, result); - implicit_set_positions(clmd); + + if(framenr == startframe) { + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + + /* don't write cache on first frame, but on second frame write + * cache for frame 1 and 2 */ + } + else if(framedelta == 1) { + /* if on second frame, write cache for first frame */ + if(framenr == startframe+1) + cloth_write_cache(ob, clmd, startframe); + + /* do simulation */ + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + + if(!do_step_cloth(ob, clmd, result, framenr)) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; } else - { - /* jump to a non-existing frame makes sim reset if cache is not protected */ - if(!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)) - { - /* prevent freeing when used with vectorblur */ - if(!useRenderParams) - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET; - } - } - clmd->sim_parms->sim_time = current_time; + cloth_write_cache(ob, clmd, framenr); + + cloth_to_object (ob, clmd, result); } - + else { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } + return result; } @@ -702,7 +567,6 @@ void cloth_free_modifier ( Object *ob, ClothModifierData *clmd ) MEM_freeN ( cloth ); clmd->clothObject = NULL; } - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_RESET; } /* frees all */ @@ -888,13 +752,12 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) } } -static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr) +static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first) { unsigned int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float tnull[3] = {0,0,0}; - int cache_there = 0; Cloth *cloth = NULL; // If we have a clothObject, free it. @@ -926,21 +789,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d cloth_from_mesh ( ob, clmd, dm ); - if((clmd->sim_parms->firstcachedframe < 0.0) || ((clmd->sim_parms->firstcachedframe >= 0.0) && (!cloth_read_cache(ob, clmd, clmd->sim_parms->firstcachedframe)))) - { - // no cache there - cache_there = 0; - if(G.rt > 0) - printf("cache_there = 0\n"); - } - else - { - // we have a cache - cache_there = 1; - if(G.rt > 0) - printf("cache_there = 1, fcf: %d\n", clmd->sim_parms->firstcachedframe); - } - // create springs clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; @@ -951,7 +799,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d // set initial values for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { - if(!cache_there) + if(first) { VECCOPY ( verts->x, mvert[i].co ); Mat4MulVecfl ( ob->obmat, verts->x ); @@ -998,10 +846,11 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d } // init our solver - if ( solvers [clmd->sim_parms->solver_type].init ) + if ( solvers [clmd->sim_parms->solver_type].init ) { solvers [clmd->sim_parms->solver_type].init ( ob, clmd ); + } - if(cache_there) + if(!first) implicit_set_positions(clmd); clmd->clothObject->tree = bvh_build_from_cloth ( clmd, clmd->coll_parms->epsilon ); diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 5f95ce61aca..ab6cf070a80 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -74,6 +74,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_utildefines.h" #include "BKE_scene.h" @@ -1647,6 +1648,7 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) ob= node->ob; if(ob && (ob->recalc & OB_RECALC)) { all_layer= ob->lay; + /* got an object node that changes, now check relations */ for(itA = node->child; itA; itA= itA->next) { all_layer |= itA->lay; @@ -1720,18 +1722,24 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) } /* node was checked to have lasttime != curtime , and is of type ID_OB */ -static unsigned int flush_layer_node(DagNode *node, int curtime) +static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) { + Base *base; DagAdjList *itA; node->lasttime= curtime; - node->lay= ((Object *)node->ob)->lay; + node->lay= 0; + for(base= sce->base.first; base; base= base->next) { + if(node->ob == base->object) { + node->lay= ((Object *)node->ob)->lay; + break; + } + } for(itA = node->child; itA; itA= itA->next) { if(itA->node->type==ID_OB) { if(itA->node->lasttime!=curtime) { - itA->lay= flush_layer_node(itA->node, curtime); // lay is only set once for each relation - //printf("layer %d for relation %s to %s\n", itA->lay, ((Object *)node->ob)->id.name, ((Object *)itA->node->ob)->id.name); + itA->lay= flush_layer_node(sce, itA->node, curtime); // lay is only set once for each relation } else itA->lay= itA->node->lay; @@ -1742,11 +1750,32 @@ static unsigned int flush_layer_node(DagNode *node, int curtime) return node->lay; } +/* node was checked to have lasttime != curtime , and is of type ID_OB */ +static void flush_pointcache_reset(DagNode *node, int curtime) +{ + DagAdjList *itA; + Object *ob; + + node->lasttime= curtime; + + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB) { + if(itA->node->lasttime!=curtime) { + ob= (Object*)(node->ob); + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) + ob->recalc |= OB_RECALC_DATA; + flush_pointcache_reset(itA->node, curtime); + } + } + } +} + /* flushes all recalc flags in objects down the dependency tree */ -void DAG_scene_flush_update(Scene *sce, unsigned int lay) +void DAG_scene_flush_update(Scene *sce, unsigned int lay, int time) { DagNode *firstnode; DagAdjList *itA; + Object *ob; int lasttime; if(sce->theDag==NULL) { @@ -1755,21 +1784,37 @@ void DAG_scene_flush_update(Scene *sce, unsigned int lay) } firstnode= sce->theDag->DagNode.first; // always scene node + + for(itA = firstnode->child; itA; itA= itA->next) + itA->lay= 0; /* first we flush the layer flags */ sce->theDag->time++; // so we know which nodes were accessed lasttime= sce->theDag->time; - for(itA = firstnode->child; itA; itA= itA->next) { + + for(itA = firstnode->child; itA; itA= itA->next) if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) - flush_layer_node(itA->node, lasttime); - } + flush_layer_node(sce, itA->node, lasttime); /* then we use the relationships + layer info to flush update events */ sce->theDag->time++; // so we know which nodes were accessed lasttime= sce->theDag->time; - for(itA = firstnode->child; itA; itA= itA->next) { - if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) + for(itA = firstnode->child; itA; itA= itA->next) + if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) flush_update_node(itA->node, lay, lasttime); + + /* if update is not due to time change, do pointcache clears */ + if(!time) { + sce->theDag->time++; // so we know which nodes were accessed + lasttime= sce->theDag->time; + for(itA = firstnode->child; itA; itA= itA->next) { + if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) { + ob= (Object*)(itA->node->ob); + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) + ob->recalc |= OB_RECALC_DATA; + flush_pointcache_reset(itA->node, lasttime); + } + } } } @@ -1955,7 +2000,7 @@ void DAG_scene_update_flags(Scene *scene, unsigned int lay) } for(sce= scene; sce; sce= sce->set) - DAG_scene_flush_update(sce, lay); + DAG_scene_flush_update(sce, lay, 1); /* test: set time flag, to disable baked systems to update */ for(SETLOOPER(scene, base)) { @@ -2005,7 +2050,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) { if(ob==NULL || sce->theDag==NULL) return; + ob->recalc |= flag; + BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH); /* all users of this ob->data should be checked */ /* BUT! displists for curves are still only on cu */ @@ -2018,8 +2065,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) else { Object *obt; for (obt=G.main->object.first; obt; obt= obt->id.next) { - if (obt->data==ob->data) { + if (obt != ob && obt->data==ob->data) { obt->recalc |= OB_RECALC_DATA; + BKE_ptcache_object_reset(obt, PTCACHE_RESET_DEPSGRAPH); } } } @@ -2028,9 +2076,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) } if(G.curscreen) - DAG_scene_flush_update(sce, dag_screen_view3d_layers()); + DAG_scene_flush_update(sce, dag_screen_view3d_layers(), 0); else - DAG_scene_flush_update(sce, sce->lay); + DAG_scene_flush_update(sce, sce->lay, 0); } /* recursively descends tree, each node only checked once */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 2d609811efe..0f51c74c248 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -3453,7 +3453,7 @@ static DerivedMesh *decimateModifier_applyModifier( if(numTris<3) { modifier_setError(md, - "There must be more than 3 input faces (triangles)."); + "Modifier requires more than 3 input faces (triangles)."); goto exit; } @@ -5057,9 +5057,10 @@ static void clothModifier_initData(ModifierData *md) clmd->sim_parms = MEM_callocN(sizeof(ClothSimSettings), "cloth sim parms"); clmd->coll_parms = MEM_callocN(sizeof(ClothCollSettings), "cloth coll parms"); + clmd->point_cache = BKE_ptcache_add(); /* check for alloc failing */ - if(!clmd->sim_parms || !clmd->coll_parms) + if(!clmd->sim_parms || !clmd->coll_parms || !clmd->point_cache) return; cloth_init (clmd); @@ -5138,11 +5139,9 @@ static void clothModifier_copyData(ModifierData *md, ModifierData *target) tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms); - - tclmd->sim_parms->lastcachedframe = 0; + tclmd->point_cache = BKE_ptcache_copy(clmd->point_cache); } - static int clothModifier_dependsOnTime(ModifierData *md) { return 1; @@ -5163,6 +5162,8 @@ static void clothModifier_freeData(ModifierData *md) MEM_freeN(clmd->sim_parms); if(clmd->coll_parms) MEM_freeN(clmd->coll_parms); + if(clmd->point_cache) + BKE_ptcache_free(clmd->point_cache); } } @@ -5435,7 +5436,6 @@ static void particleSystemModifier_freeData(ModifierData *md) psmd->dm=0; } - psmd->psys->flag &= ~PSYS_ENABLED; psmd->psys->flag |= PSYS_DELETE; } static void particleSystemModifier_copyData(ModifierData *md, ModifierData *target) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 287708a8ed4..ff5dcb763f4 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -105,6 +105,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_property.h" #include "BKE_sca.h" #include "BKE_scene.h" @@ -295,6 +296,7 @@ void unlink_object(Object *ob) Camera *camera; bConstraint *con; bActionStrip *strip; + ModifierData *md; int a; unlink_controllers(&ob->controllers); @@ -397,6 +399,11 @@ void unlink_object(Object *ob) obt->recalc |= OB_RECALC_DATA; else if(obt->soft) obt->recalc |= OB_RECALC_DATA; + + /* cloth */ + for(md=obt->modifiers.first; md; md=md->next) + if(md->type == eModifierType_Cloth) + obt->recalc |= OB_RECALC_DATA; } /* strips */ @@ -1011,12 +1018,14 @@ SoftBody *copy_softbody(SoftBody *sb) sbn->totspring= sbn->totpoint= 0; sbn->bpoint= NULL; sbn->bspring= NULL; - sbn->ctime= 0.0f; sbn->keys= NULL; sbn->totkey= sbn->totpointkey= 0; sbn->scratch= NULL; + + sbn->pointcache= BKE_ptcache_copy(sb->pointcache); + return sbn; } @@ -1047,6 +1056,8 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys) psysn->edit= NULL; psysn->effectors.first= psysn->effectors.last= 0; + psysn->pointcache= BKE_ptcache_copy(psys->pointcache); + id_us_plus((ID *)psysn->part); return psysn; @@ -2180,7 +2191,7 @@ void object_handle_update(Object *ob) if(ob->recalc & OB_RECALC) { if(ob->recalc & OB_RECALC_OB) { - + // printf("recalcob %s\n", ob->id.name+2); /* handle proxy copy for target */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 6b2f2f911c6..6bdb4e6f8d3 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -78,6 +78,7 @@ #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_cdderivedmesh.h" +#include "BKE_pointcache.h" #include "blendef.h" #include "RE_render_ext.h" @@ -226,14 +227,14 @@ void psys_disable_all(Object *ob) ParticleSystem *psys=ob->particlesystem.first; for(; psys; psys=psys->next) - psys->flag &= ~PSYS_ENABLED; + psys->flag |= PSYS_DISABLED; } void psys_enable_all(Object *ob) { ParticleSystem *psys=ob->particlesystem.first; for(; psys; psys=psys->next) - psys->flag |= PSYS_ENABLED; + psys->flag &= ~PSYS_DISABLED; } int psys_ob_has_hair(Object *ob) { @@ -253,7 +254,7 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd; - if(!(psys->flag & PSYS_ENABLED)) + if(psys->flag & PSYS_DISABLED) return 0; psmd= psys_get_modifier(ob, psys); @@ -370,6 +371,9 @@ void psys_free(Object *ob, ParticleSystem * psys) } MEM_freeN(psys); + + if(psys->pointcache) + BKE_ptcache_free(psys->pointcache); } } @@ -2251,7 +2255,7 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed int i, totchild, totparent, totthread; unsigned long totchildstep; - pthreads= psys_threads_create(ob, psys, G.scene->r.threads); + pthreads= psys_threads_create(ob, psys); if(!psys_threads_init_path(pthreads, cfra, editupdate)) { psys_threads_free(pthreads); @@ -3080,6 +3084,42 @@ void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc) } } } + +LinkNode *psys_using_settings(ParticleSettings *part, int flush_update) +{ + Object *ob, *tob; + ParticleSystem *psys, *tpsys; + LinkNode *node= NULL; + int found; + + /* update all that have same particle settings */ + for(ob=G.main->object.first; ob; ob=ob->id.next) { + found= 0; + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + if(psys->part == part) { + BLI_linklist_append(&node, psys); + found++; + } + else if(psys->part->type == PART_REACTOR){ + tob= (psys->target_ob)? psys->target_ob: ob; + tpsys= BLI_findlink(&tob->particlesystem, psys->target_psys-1); + + if(tpsys && tpsys->part==part) { + BLI_linklist_append(&node, tpsys); + found++; + } + } + } + + if(flush_update && found) + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + + return node; +} + + /************************************************/ /* Textures */ /************************************************/ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 8bde0afb752..cd0d6b5d113 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -121,7 +121,48 @@ static int get_current_display_percentage(ParticleSystem *psys) return psys->part->disp; } -static void alloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) +void psys_reset(ParticleSystem *psys, int mode) +{ + ParticleSettings *part= psys->part; + ParticleData *pa; + int i; + + if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) { + if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->flag & PSYS_EDITED))) { + if(psys->particles) { + if(psys->particles->keys) + MEM_freeN(psys->particles->keys); + + for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) + if(pa->hair) MEM_freeN(pa->hair); + + MEM_freeN(psys->particles); + psys->particles= NULL; + } + + psys->totpart= 0; + psys->totkeyed= 0; + psys->flag &= ~(PSYS_HAIR_DONE|PSYS_KEYED); + } + } + + /* reset children */ + if(psys->child) { + MEM_freeN(psys->child); + psys->child= 0; + } + + psys->totchild= 0; + + /* reset path cache */ + psys_free_path_cache(psys); + + /* reset point cache */ + psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID; + psys->pointcache->simframe= 0; +} + +static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) { ParticleData *newpars = 0, *pa; int i, totpart, totsaved = 0; @@ -145,6 +186,12 @@ static void alloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) if(totsaved) memcpy(newpars,psys->particles,totsaved*sizeof(ParticleData)); + if(psys->particles->keys) + MEM_freeN(psys->particles->keys); + + for(i=0, pa=psys->particles; i<totsaved; i++, pa++) + if(pa->keys) pa->keys= NULL; + for(i=totsaved, pa=psys->particles+totsaved; i<psys->totpart; i++, pa++) if(pa->hair) MEM_freeN(pa->hair); @@ -1313,7 +1360,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl ParticleThreadContext *ctx; int i, totthread; - pthreads= psys_threads_create(ob, psys, G.scene->r.threads); + pthreads= psys_threads_create(ob, psys); if(!psys_threads_init_distribution(pthreads, finaldm, from)) { psys_threads_free(pthreads); @@ -1385,11 +1432,16 @@ static void distribute_particles(Object *ob, ParticleSystem *psys, int from) } /* threaded child particle distribution and path caching */ -ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys, int totthread) +ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys) { ParticleThread *threads; ParticleThreadContext *ctx; - int i; + int i, totthread; + + if(G.scene->r.mode & R_FIXED_THREADS) + totthread= G.scene->r.threads; + else + totthread= BLI_system_thread_count(); threads= MEM_callocN(sizeof(ParticleThread)*totthread, "ParticleThread"); ctx= MEM_callocN(sizeof(ParticleThreadContext), "ParticleThreadContext"); @@ -1922,7 +1974,8 @@ int psys_count_keyed_targets(Object *ob, ParticleSystem *psys) BLI_freelistN(&lb); return select; } -void set_keyed_keys(Object *ob, ParticleSystem *psys) + +static void set_keyed_keys(Object *ob, ParticleSystem *psys) { Object *kob = ob; ParticleSystem *kpsys = psys; @@ -1932,17 +1985,16 @@ void set_keyed_keys(Object *ob, ParticleSystem *psys) float prevtime, nexttime, keyedtime; /* no proper targets so let's clear and bail out */ - if(psys->totkeyed==0){ + if(psys->totkeyed==0) { free_keyed_keys(psys); psys->flag &= ~PSYS_KEYED; return; } - if(totpart && psys->particles->totkey != totkeys){ + if(totpart && psys->particles->totkey != totkeys) { free_keyed_keys(psys); - psys->particles->keys = MEM_callocN(psys->totpart * totkeys * sizeof(ParticleKey),"Keyed keys"); - + psys->particles->keys = MEM_callocN(psys->totpart*totkeys*sizeof(ParticleKey), "Keyed keys"); psys->particles->totkey = totkeys; for(i=1, pa=psys->particles+1; i<totpart; i++,pa++){ @@ -1954,9 +2006,10 @@ void set_keyed_keys(Object *ob, ParticleSystem *psys) psys->flag &= ~PSYS_KEYED; state.time=-1.0; - for(k=0; k<totkeys; k++){ - for(i=0,pa=psys->particles; i<totpart; i++, pa++){ - psys_get_particle_state(kob, kpsys, i%kpsys->totpart, pa->keys + k, 1); + for(k=0; k<totkeys; k++) { + for(i=0,pa=psys->particles; i<totpart; i++, pa++) { + if(kpsys->totpart > 0) + psys_get_particle_state(kob, kpsys, i%kpsys->totpart, pa->keys + k, 1); if(k==0) pa->keys->time = pa->time; @@ -2097,60 +2150,57 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o /************************************************/ /* Point Cache */ /************************************************/ -void clear_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) -{ - ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); - int stack_index = modifiers_indexInObject(ob,(ModifierData*)psmd); - - BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_ALL, cfra, stack_index); - /* reactors need to initialize particles always since their birth times might have changed */ - if(psys && psys->part && psys->part->type == PART_REACTOR) - psys->recalc |= PSYS_INIT; -} static void write_particles_to_cache(Object *ob, ParticleSystem *psys, int cfra) { - FILE *fp = NULL; - ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); + PTCacheID pid; + PTCacheFile *pf; ParticleData *pa; - int stack_index = modifiers_indexInObject(ob,(ModifierData*)psmd); - int i, totpart = psys->totpart; + int i, totpart= psys->totpart; - if(totpart == 0) return; + if(totpart == 0) + return; - fp = BKE_ptcache_id_fopen((ID *)ob, 'w', cfra, stack_index); - if(!fp) return; + BKE_ptcache_id_from_particles(&pid, ob, psys); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, cfra); + if(!pf) + return; + /* assuming struct consists of tightly packed floats */ for(i=0, pa=psys->particles; i<totpart; i++, pa++) - fwrite(&pa->state, sizeof(ParticleKey), 1, fp); + BKE_ptcache_file_write_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float)); - fclose(fp); + BKE_ptcache_file_close(pf); } + static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) { - FILE *fp = NULL; - ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); + PTCacheID pid; + PTCacheFile *pf; ParticleData *pa; - int stack_index = modifiers_indexInObject(ob,(ModifierData*)psmd); - int i, totpart = psys->totpart, ret = 1; + int i, totpart= psys->totpart; - if(totpart == 0) return 0; + if(totpart == 0) + return 0; - fp = BKE_ptcache_id_fopen((ID *)ob, 'r', cfra, stack_index); - if(!fp) - ret = 0; - else { - for(i=0, pa=psys->particles; i<totpart; i++, pa++) - if((fread(&pa->state, sizeof(ParticleKey), 1, fp)) != 1) { - ret = 0; - break; - } - - fclose(fp); + BKE_ptcache_id_from_particles(&pid, ob, psys); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, cfra); + if(!pf) + return 0; + + /* assuming struct consists of tightly packed floats */ + for(i=0, pa=psys->particles; i<totpart; i++, pa++) { + if(!BKE_ptcache_file_read_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float))) { + BKE_ptcache_file_close(pf); + return 0; + } } - return ret; + BKE_ptcache_file_close(pf); + + return 1; } + /************************************************/ /* Effectors */ /************************************************/ @@ -4203,7 +4253,7 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi copy_particle_key(key,&pa->state,1); } - if(dfra>0.0 || psys->recalc){ + if(1) { if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0) react_to_events(psys,p); @@ -4306,7 +4356,7 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd, if(distr){ if(alloc) - alloc_particles(ob,psys,psys->totpart); + realloc_particles(ob,psys,psys->totpart); if(get_psys_tot_child(psys)) { /* don't generate children while computing the hair keys */ @@ -4366,7 +4416,7 @@ static void hair_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSyst } /* updates cached particles' alive & other flags etc..*/ -static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra, float *vg_size) +static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { ParticleSettings *part=psys->part; ParticleData *pa; @@ -4374,7 +4424,10 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy IpoCurve *icu_esize=find_ipocurve(part->ipo,PART_EMIT_SIZE); Material *ma=give_current_material(ob,part->omat); int p; - float ipotime=cfra, disp, birthtime, dietime; + float ipotime=cfra, disp, birthtime, dietime, *vg_size= NULL; + + if(part->from!=PART_FROM_PARTICLE) + vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); if(psys->effectors.first) psys_end_effectors(psys); @@ -4437,10 +4490,48 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy /* make sure that children are up to date */ if(psys->part->childtype && psys->totchild != get_psys_tot_child(psys)) { - alloc_particles(ob, psys, psys->totpart); + realloc_particles(ob, psys, psys->totpart); distribute_particles(ob, psys, PART_FROM_CHILD); } + + if(vg_size) + MEM_freeN(vg_size); } + +void psys_changed_type(ParticleSystem *psys) +{ + ParticleSettings *part; + + part= psys->part; + + /* system type has changed so set sensible defaults and clear non applicable flags */ + if(part->from == PART_FROM_PARTICLE) { + if(part->type != PART_REACTOR) + part->from = PART_FROM_FACE; + if(part->distr == PART_DISTR_GRID) + part->distr = PART_DISTR_JIT; + } + + if(psys->part->phystype != PART_PHYS_KEYED) + psys->flag &= ~PSYS_KEYED; + + if(part->type == PART_HAIR) { + part->draw_as = PART_DRAW_PATH; + part->rotfrom = PART_ROT_IINCR; + } + else { + free_hair(psys, 1); + + if(part->draw_as == PART_DRAW_PATH) + if(psys->part->phystype != PART_PHYS_KEYED) + part->draw_as = PART_DRAW_DOT; + } + + psys->softflag= 0; + + psys_reset(psys, PSYS_RESET_ALL); +} + static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) { if(psys->particles){ @@ -4448,6 +4539,7 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) psys->particles = 0; psys->totpart = 0; } + /* fluid sim particle import handling, actual loading of particles from file */ #ifndef DISABLE_ELBEEM if( (1) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // broken, disabled for now! @@ -4488,7 +4580,7 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) part->lifetime = G.scene->r.efra + 1; /* initialize particles */ - alloc_particles(ob, psys, part->totpart); + realloc_particles(ob, psys, part->totpart); initialize_all_particles(ob, psys, 0); // set up reading mask @@ -4496,8 +4588,7 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) for(p=0, pa=psys->particles; p<totpart; p++, pa++) { int ptype=0; - short shsize=0; - float convertSize=0.0; + gzread(gzf, &ptype, sizeof( ptype )); if(ptype&readMask) { activeParts++; @@ -4540,113 +4631,107 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) } // fluid sim particles done #endif // DISABLE_ELBEEM } + /* Calculates the next state for all particles of the system */ /* In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)*/ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) { ParticleSettings *part; ParticleData *pa; - int totpart,oldtotpart=0,p; - float disp, *vg_vel=0, *vg_tan=0, *vg_rot=0, *vg_size=0; - int init=0,distr=0,alloc=0; + PointCache *cache; + PTCacheID pid; + int totpart, oldtotpart, totchild, oldtotchild, p; + float disp, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; + int init= 0, distr= 0, alloc= 0, usecache= 0; + int framenr, framedelta, startframe, endframe; - /*----start validity checks----*/ + part= psys->part; + cache= psys->pointcache; - part=psys->part; + framenr= (int)CFRA; + framedelta= framenr - cache->simframe; - if(part->flag&PART_ABS_TIME && part->ipo){ + BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_time(&pid, 0.0f, &startframe, &endframe, NULL); + + /* update ipo's */ + if((part->flag & PART_ABS_TIME) && part->ipo) { calc_ipo(part->ipo, cfra); execute_ipo((ID *)part, part->ipo); } - if(part->from!=PART_FROM_PARTICLE && part->type!=PART_FLUID) - vg_size=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); - - if(part->type == PART_HAIR) { - if(psys->flag & PSYS_HAIR_DONE) { - hair_step(ob, psmd, psys, cfra); - psys->cfra = cfra; - psys->recalc = 0; - return; - } + /* hair if it's already done is handled separate */ + if(part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)) { + hair_step(ob, psmd, psys, cfra); + psys->cfra = cfra; + psys->recalc = 0; + return; } + /* fluid is also handled separate */ else if(part->type == PART_FLUID) { - particles_fluid_step(ob, psys, (int)cfra); + particles_fluid_step(ob, psys, framenr); psys->cfra = cfra; psys->recalc = 0; return; } - else if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) - ; /* cache shouldn't be used for "none" or "keyed" physics */ - else { - if(psys->recalc && (psys->flag & PSYS_PROTECT_CACHE) == 0) - clear_particles_from_cache(ob,psys,(int)cfra); - else if(get_particles_from_cache(ob, psys, (int)cfra)) { - cached_step(ob,psmd,psys,cfra,vg_size); - psys->cfra=cfra; - psys->recalc = 0; - return; - } - } - /* if still here react to events */ + /* cache shouldn't be used for hair or "none" or "first keyed" physics */ + if(part->type == PART_HAIR || part->phystype == PART_PHYS_NO) + usecache= 0; + else if(part->type == PART_PHYS_KEYED && (psys->flag & PSYS_FIRST_KEYED)) + usecache= 0; + else if(BKE_ptcache_get_continue_physics()) + usecache= 0; + else + usecache= 1; - if(psys->recalc&PSYS_TYPE) { - /* system type has changed so set sensible defaults and clear non applicable flags */ - if(part->from == PART_FROM_PARTICLE) { - if(part->type != PART_REACTOR) - part->from = PART_FROM_FACE; - if(part->distr == PART_DISTR_GRID) - part->distr = PART_DISTR_JIT; + if(usecache) { + /* frame clamping */ + if(framenr < startframe) { + psys_reset(psys, PSYS_RESET_DEPSGRAPH); + psys->cfra = cfra; + psys->recalc = 0; + return; } - - if(psys->part->phystype != PART_PHYS_KEYED) - psys->flag &= ~PSYS_KEYED; - - if(part->type == PART_HAIR) { - part->draw_as = PART_DRAW_PATH; - part->rotfrom = PART_ROT_IINCR; + else if(framenr > endframe) { + framenr= endframe; } - else - free_hair(psys, 1); - - psys->softflag= 0; - psys->recalc &= ~PSYS_TYPE; - alloc = 1; - - /* this is a bad level call, but currently type change - * can happen after redraw, so force redraw from here */ - allqueue(REDRAWBUTSOBJECT, 0); } - else - oldtotpart = psys->totpart; + + /* verify if we need to reallocate */ + oldtotpart = psys->totpart; + oldtotchild = psys->totchild; if(part->distr == PART_DISTR_GRID) - totpart = part->grid_res * part->grid_res * part->grid_res; + totpart = part->grid_res*part->grid_res*part->grid_res; else totpart = psys->part->totpart; + totchild = get_psys_tot_child(psys); - if(oldtotpart != totpart || psys->recalc&PSYS_ALLOC || (psys->part->childtype && psys->totchild != get_psys_tot_child(psys))) + if(oldtotpart != totpart || (psys->part->childtype && oldtotchild != totchild)) { + realloc_particles(ob, psys, totpart); alloc = 1; + distr= 1; + init= 1; + } - if(alloc || psys->recalc&PSYS_DISTR || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT) && ob==OBACT)) - distr = 1; - - if(distr || psys->recalc&PSYS_INIT) - init = 1; + if(psys->recalc & PSYS_DISTR) { + distr= 1; + init= 1; + } if(init) { if(distr) { if(alloc) - alloc_particles(ob, psys, totpart); + realloc_particles(ob, psys, totpart); distribute_particles(ob, psys, part->from); if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) - /* don't generate children while growing hair - waste of time */ - psys_free_children(psys); - else if(get_psys_tot_child(psys)) - distribute_particles(ob, psys, PART_FROM_CHILD); + /* don't generate children while growing hair - waste of time */ + psys_free_children(psys); + else if(get_psys_tot_child(psys)) + distribute_particles(ob, psys, PART_FROM_CHILD); } initialize_all_particles(ob, psys, psmd); @@ -4657,17 +4742,59 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier psmd->flag |= eParticleSystemFlag_Pars; } + /* try to read from the cache */ + if(usecache) { + if(get_particles_from_cache(ob, psys, framenr)) { + if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { + psys_count_keyed_targets(ob,psys); + set_keyed_keys(ob, psys); + } + + cached_step(ob,psmd,psys,cfra); + psys->cfra=cfra; + psys->recalc = 0; + + if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { + psys_update_path_cache(ob,psmd,psys,framenr); + } + + return; + } + else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + psys_reset(psys, PSYS_RESET_DEPSGRAPH); + psys->cfra=cfra; + psys->recalc = 0; + return; + } + + if(framenr != startframe && framedelta != 1) { + psys_reset(psys, PSYS_RESET_DEPSGRAPH); + psys->cfra = cfra; + psys->recalc = 0; + return; + } + } + else { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } + + /* if on second frame, write cache for first frame */ + if(usecache && framenr == startframe+1) + write_particles_to_cache(ob, psys, startframe); if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) psys_count_keyed_targets(ob,psys); - if(part->from!=PART_FROM_PARTICLE){ - vg_vel=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_VEL); - vg_tan=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_TAN); - vg_rot=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); + /* initialize vertex groups */ + if(part->from!=PART_FROM_PARTICLE) { + vg_vel= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_VEL); + vg_tan= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_TAN); + vg_rot= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); + vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); } - /* set particles to be not calculated */ + /* set particles to be not calculated TODO: can't work with pointcache */ disp= (float)get_current_display_percentage(psys)/50.0f-1.0f; for(p=0, pa=psys->particles; p<totpart; p++,pa++){ @@ -4680,15 +4807,16 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier /* ok now we're all set so let's go */ if(psys->totpart) dynamics_step(ob,psys,psmd,cfra,vg_vel,vg_tan,vg_rot,vg_size); + + cache->simframe= framenr; + cache->flag |= PTCACHE_SIMULATION_VALID; psys->recalc = 0; psys->cfra = cfra; - if(part->type == PART_HAIR || part->phystype == PART_PHYS_NO - || (part->phystype == PART_PHYS_KEYED && psys->flag & PSYS_FIRST_KEYED)) - ; /* cache shouldn't be used for hair or "none" or "first keyed" physics */ - else - write_particles_to_cache(ob, psys, cfra); + /* only write cache starting from second frame */ + if(usecache && framenr != startframe) + write_particles_to_cache(ob, psys, framenr); /* for keyed particles the path is allways known so it can be drawn */ if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED){ @@ -4698,9 +4826,11 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier else if(psys->pathcache) psys_free_path_cache(psys); + /* cleanup */ if(vg_vel) MEM_freeN(vg_vel); if(vg_tan) MEM_freeN(vg_tan); if(vg_rot) MEM_freeN(vg_rot); + if(vg_size) MEM_freeN(vg_size); if(psys->lattice){ end_latt_deform(); @@ -4708,106 +4838,97 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier } } -void psys_to_softbody(Object *ob, ParticleSystem *psys, int force_recalc) +void psys_to_softbody(Object *ob, ParticleSystem *psys) { SoftBody *sb; short softflag; - if((psys->softflag&OB_SB_ENABLE)==0) return; - - if(psys->recalc || force_recalc) - psys->softflag|=OB_SB_REDO; + if(!(psys->softflag & OB_SB_ENABLE)) + return; /* let's replace the object's own softbody with the particle softbody */ /* a temporary solution before cloth simulation is implemented, jahka */ /* save these */ - sb=ob->soft; - softflag=ob->softflag; + sb= ob->soft; + softflag= ob->softflag; /* swich to new ones */ - ob->soft=psys->soft; - ob->softflag=psys->softflag; + ob->soft= psys->soft; + ob->softflag= psys->softflag; /* do softbody */ sbObjectStep(ob, (float)G.scene->r.cfra, NULL, psys_count_keys(psys)); /* return things back to normal */ - psys->soft=ob->soft; - psys->softflag=ob->softflag; + psys->soft= ob->soft; + psys->softflag= ob->softflag; - ob->soft=sb; - ob->softflag=softflag; + ob->soft= sb; + ob->softflag= softflag; } + static int hair_needs_recalc(ParticleSystem *psys) { - if((psys->flag & PSYS_EDITED)==0 && ( - (psys->flag & PSYS_HAIR_DONE)==0 - || psys->recalc & PSYS_RECALC_HAIR) - ) { + if((psys->flag & PSYS_EDITED)==0 && + ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_HAIR)) { psys->recalc &= ~PSYS_RECALC_HAIR; return 1; } return 0; } -/* main particle update call, checks that things are ok on the large scale before actual particle calculations */ -void particle_system_update(Object *ob, ParticleSystem *psys){ - ParticleSystemModifierData *psmd=0; +/* main particle update call, checks that things are ok on the large scale before actual particle calculations */ +void particle_system_update(Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd; float cfra; if(!psys_check_enabled(ob, psys)) return; - cfra=bsystem_time(ob,(float)CFRA,0.0); + cfra= bsystem_time(ob, CFRA, 0.0f); psmd= psys_get_modifier(ob, psys); /* system was already updated from modifier stack */ - if(psmd->flag&eParticleSystemFlag_psys_updated) { + if(psmd->flag & eParticleSystemFlag_psys_updated) { psmd->flag &= ~eParticleSystemFlag_psys_updated; /* make sure it really was updated to cfra */ - if(psys->cfra==cfra) + if(psys->cfra == cfra) return; } if(!psmd->dm) return; - /* baked path softbody */ - if(psys->part->type==PART_HAIR && psys->soft) - psys_to_softbody(ob, psys, 0); - - /* not needed, this is all handled in hair_step */ - ///* is the mesh changing under the edited particles? */ - //if((psys->flag & PSYS_EDITED) && psys->part->type==PART_HAIR && psys->recalc & PSYS_RECALC_HAIR) { - // /* Just update the particles on the mesh */ - // psys_update_edithair_dmfaces(ob, psmd->dm, psys); - //} - - if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)){ + /* (re-)create hair */ + if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) { float hcfra=0.0f; int i; free_hair(psys, 0); /* first step is negative so particles get killed and reset */ - psys->cfra=1.0f; + psys->cfra= 1.0f; for(i=0; i<=psys->part->hair_step; i++){ hcfra=100.0f*(float)i/(float)psys->part->hair_step; - system_step(ob,psys,psmd,hcfra); - save_hair(ob,psys,psmd,hcfra); + system_step(ob, psys, psmd, hcfra); + save_hair(ob, psys, psmd, hcfra); } psys->flag |= PSYS_HAIR_DONE; - - if(psys->softflag&OB_SB_ENABLE) - psys_to_softbody(ob,psys,1); } - system_step(ob,psys,psmd,cfra); + /* handle softbody hair */ + if(psys->part->type==PART_HAIR && psys->soft) + psys_to_softbody(ob, psys); + + /* the main particle system step */ + system_step(ob, psys, psmd, cfra); - Mat4Invert(psys->imat, ob->obmat); /* used for duplicators */ + /* save matrix for duplicators */ + Mat4Invert(psys->imat, ob->obmat); } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index cdb95e2f015..3b411e758c0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -27,21 +27,36 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ - #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> -#include "BKE_pointcache.h" +#include "MEM_guardedalloc.h" -#include "BKE_utildefines.h" -#include "BKE_global.h" -#include "BKE_library.h" +#include "DNA_ID.h" +#include "DNA_cloth_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" #include "BLI_blenlib.h" + +#include "BKE_cloth.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_pointcache.h" +#include "BKE_softbody.h" #include "BKE_utildefines.h" + #include "blendef.h" /* needed for directory lookup */ @@ -58,19 +73,114 @@ #include <unistd.h> #endif +/* Creating ID's */ + +void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) +{ + ParticleSystemModifierData *psmd; + ModifierData *md; + int a; + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= sb; + pid->type= PTCACHE_TYPE_SOFTBODY; + pid->cache= sb->pointcache; + + if(sb->particles) { + psmd= psys_get_modifier(ob, sb->particles); + pid->stack_index= modifiers_indexInObject(ob, (ModifierData*)psmd); + } + else { + for(a=0, md=ob->modifiers.first; md; md=md->next, a++) { + if(md->type == eModifierType_Softbody) { + pid->stack_index = a; + break; + } + } + } +} + +void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= psys; + pid->type= PTCACHE_TYPE_PARTICLES; + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)psmd); + pid->cache= psys->pointcache; +} + +void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd) +{ + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= clmd; + pid->type= PTCACHE_TYPE_CLOTH; + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)clmd); + pid->cache= clmd->point_cache; +} + +void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) +{ + PTCacheID *pid; + ParticleSystem *psys; + ModifierData *md; + + lb->first= lb->last= NULL; + + if(ob->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, ob->soft); + BLI_addtail(lb, pid); + } + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_particles(pid, ob, psys); + BLI_addtail(lb, pid); + + if(psys->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, psys->soft); + BLI_addtail(lb, pid); + } + } + + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type == eModifierType_Cloth) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md); + BLI_addtail(lb, pid); + } + } +} + /* Takes an Object ID and returns a unique name - id: object id - cfra: frame for the cache, can be negative - stack_index: index in the modifier stack. we can have cache for more then one stack_index */ -static int ptcache_path(char *filename) +static int ptcache_path(PTCacheID *pid, char *filename) { + Library *lib; int i; - if (G.relbase_valid) { + + lib= (pid)? pid->ob->id.lib: NULL; + + if (G.relbase_valid || lib) { char dir[FILE_MAX], file[FILE_MAX]; /* we dont want the dir, only the file */ - - BLI_split_dirfile(G.sce, dir, file); + char *blendfilename; + + blendfilename= (lib)? lib->filename: G.sce; + + BLI_split_dirfile(blendfilename, dir, file); i = strlen(file); /* remove .blend */ @@ -78,7 +188,7 @@ static int ptcache_path(char *filename) file[i-6] = '\0'; sprintf(filename, "//"PTCACHE_PATH"%s/", file); /* add blend file name to pointcache dir */ - BLI_convertstringcode(filename, G.sce, 0); + BLI_convertstringcode(filename, blendfilename, 0); return strlen(filename); } @@ -87,7 +197,7 @@ static int ptcache_path(char *filename) return sprintf(filename, "%s"PTCACHE_PATH"%d/", btempdir, abs(getpid())); } -int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext) +static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) { int len=0; char *idname; @@ -99,10 +209,10 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i /* start with temp dir */ if (do_path) { - len = ptcache_path(filename); + len = ptcache_path(pid, filename); newname += len; } - idname = (id->name+2); + idname = (pid->ob->id.name+2); /* convert chars to hex so they are always a valid filename */ while('\0' != *idname) { sprintf(newname, "%02X", (char)(*idname++)); @@ -111,7 +221,7 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i } if (do_ext) { - sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, stack_index); /* always 6 chars */ + sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ len += 16; } @@ -119,31 +229,53 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i } /* youll need to close yourself after! */ -FILE *BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index) +PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra) { - /* mode is same as fopen's modes */ + PTCacheFile *pf; FILE *fp = NULL; char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; + /* don't allow writing for linked objects */ + if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE) + return NULL; + /*if (!G.relbase_valid) return NULL; *//* save blend file before using pointcache */ - BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); - if (mode=='r') { + if (mode==PTCACHE_FILE_READ) { if (!BLI_exists(filename)) { return NULL; } fp = fopen(filename, "rb"); - } else if (mode=='w') { + } else if (mode==PTCACHE_FILE_WRITE) { BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */ fp = fopen(filename, "wb"); } - if (!fp) { + if (!fp) return NULL; - } + + pf= MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile"); + pf->fp= fp; - return fp; + return pf; +} + +void BKE_ptcache_file_close(PTCacheFile *pf) +{ + fclose(pf->fp); + MEM_freeN(pf); +} + +int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot) +{ + return (fread(f, sizeof(float), tot, pf->fp) == tot); +} + +int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot) +{ + return (fwrite(f, sizeof(float), tot, pf->fp) == tot); } /* youll need to close yourself after! @@ -151,7 +283,7 @@ FILE *BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index) */ -void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) +void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) { int len; /* store the length of the string */ @@ -161,7 +293,14 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) char path[FILE_MAX]; char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; char path_full[(FILE_MAXDIR+FILE_MAXFILE)*2]; - + + if(!pid->cache) + return; + + /* don't allow clearing for linked objects */ + if(pid->ob->id.lib) + return; + /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */ /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ @@ -169,9 +308,9 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) case PTCACHE_CLEAR_ALL: case PTCACHE_CLEAR_BEFORE: case PTCACHE_CLEAR_AFTER: - ptcache_path(path); + ptcache_path(pid, path); - len = BKE_ptcache_id_filename(id, filename, cfra, stack_index, 0, 0); /* no path */ + len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */ dir = opendir(path); if (dir==NULL) @@ -206,22 +345,149 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) break; case PTCACHE_CLEAR_FRAME: - len = BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); /* no path */ + len = BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */ BLI_delete(filename, 0, 0); break; } - return; } -int BKE_ptcache_id_exist(struct ID *id, int cfra, int stack_index) +int BKE_ptcache_id_exist(PTCacheID *pid, int cfra) { char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; + + if(!pid->cache) + return 0; - BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); return BLI_exists(filename); } +void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale) +{ + Object *ob; + PointCache *cache; + float offset, time, nexttime; + + /* time handling for point cache: + * - simulation time is scaled by result of bsystem_time + * - for offsetting time only time offset is taken into account, since + * that's always the same and can't be animated. a timeoffset which + * varies over time is not simpe to support. + * - field and motion blur offsets are currently ignored, proper solution + * is probably to interpolate results from two frames for that .. + */ + + ob= pid->ob; + cache= pid->cache; + + if(timescale) { + time= bsystem_time(ob, cfra, 0.0f); + nexttime= bsystem_time(ob, cfra+1.0f, 0.0f); + + *timescale= MAX2(nexttime - time, 0.0f); + } + + if(startframe && endframe) { + *startframe= cache->startframe; + *endframe= cache->endframe; + + if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) { + offset= give_timeoffset(ob); + + *startframe += (int)(offset+0.5f); + *endframe += (int)(offset+0.5f); + } + } +} + +int BKE_ptcache_id_reset(PTCacheID *pid, int mode) +{ + PointCache *cache; + int reset, clear; + + if(!pid->cache) + return 0; + + cache= pid->cache; + reset= 0; + clear= 0; + + if(mode == PTCACHE_RESET_DEPSGRAPH) { + if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) { + reset= 1; + clear= 1; + } + else + cache->flag |= PTCACHE_OUTDATED; + } + else if(mode == PTCACHE_RESET_BAKED) { + if(!BKE_ptcache_get_continue_physics()) { + reset= 1; + clear= 1; + } + else + cache->flag |= PTCACHE_OUTDATED; + } + else if(mode == PTCACHE_RESET_OUTDATED) { + reset = 1; + + if(cache->flag & PTCACHE_OUTDATED) + if(!(cache->flag & PTCACHE_BAKED)) + clear= 1; + } + + if(reset) { + cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_SIMULATION_VALID); + cache->simframe= 0; + + if(pid->type == PTCACHE_TYPE_CLOTH) + cloth_free_modifier(pid->ob, pid->data); + else if(pid->type == PTCACHE_TYPE_SOFTBODY) + sbFreeSimulation(pid->data); + else if(pid->type == PTCACHE_TYPE_PARTICLES) + psys_reset(pid->data, PSYS_RESET_DEPSGRAPH); + } + if(clear) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + return (reset || clear); +} + +int BKE_ptcache_object_reset(Object *ob, int mode) +{ + PTCacheID pid; + ParticleSystem *psys; + ModifierData *md; + int reset; + + reset= 0; + + if(ob->soft) { + BKE_ptcache_id_from_softbody(&pid, ob, ob->soft); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + BKE_ptcache_id_from_particles(&pid, ob, psys); + reset |= BKE_ptcache_id_reset(&pid, mode); + + if(psys->soft) { + BKE_ptcache_id_from_softbody(&pid, ob, psys->soft); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + } + + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type == eModifierType_Cloth) { + BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + } + + return reset; +} + /* Use this when quitting blender, with unsaved files */ void BKE_ptcache_remove(void) { @@ -229,7 +495,7 @@ void BKE_ptcache_remove(void) char path_full[FILE_MAX]; int rmdir = 1; - ptcache_path(path); + ptcache_path(NULL, path); if (BLI_exists(path)) { /* TODO, Check with win32, probably needs last slash removed */ @@ -260,3 +526,58 @@ void BKE_ptcache_remove(void) BLI_delete(path, 1, 0); } } + +/* Continuous Interaction */ + +static int CONTINUE_PHYSICS = 0; + +void BKE_ptcache_set_continue_physics(int enable) +{ + Object *ob; + + if(CONTINUE_PHYSICS != enable) { + CONTINUE_PHYSICS = enable; + + if(CONTINUE_PHYSICS == 0) { + for(ob=G.main->object.first; ob; ob=ob->id.next) + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_OUTDATED)) + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + } +} + +int BKE_ptcache_get_continue_physics() +{ + return CONTINUE_PHYSICS; +} + +/* Point Cache */ + +PointCache *BKE_ptcache_add() +{ + PointCache *cache; + + cache= MEM_callocN(sizeof(PointCache), "PointCache"); + cache->startframe= 1; + cache->endframe= 250; + + return cache; +} + +void BKE_ptcache_free(PointCache *cache) +{ + MEM_freeN(cache); +} + +PointCache *BKE_ptcache_copy(PointCache *cache) +{ + PointCache *ncache; + + ncache= MEM_dupallocN(cache); + + ncache->flag= 0; + ncache->simframe= 0; + + return ncache; +} + diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index df6b0d37867..c7440f39a0c 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -3219,105 +3219,66 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, } } -void softbody_clear_cache(Object *ob, float framenr) +void sbWriteCache(Object *ob, int framenr) { - SoftBody *sb = ob->soft; - ModifierData *md = ob->modifiers.first; - int stack_index = -1; - int a; - - if(sb==NULL) return; - - if(sb->particles) - stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); - else { - for(a=0; md; md=md->next, a++) { - if(md->type == eModifierType_Softbody) { - stack_index = a; - break; - } - } - } - - BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_ALL, framenr, stack_index); -} -static void softbody_write_cache(Object *ob, float framenr) -{ - FILE *fp = NULL; - SoftBody *sb = ob->soft; + SoftBody *sb= ob->soft; BodyPoint *bp; - ModifierData *md = ob->modifiers.first; - int stack_index = -1; + PTCacheID pid; + PTCacheFile *pf; int a; - if(sb->totpoint == 0) return; - - if(sb->particles) - stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); - else { - for(a=0; md; md=md->next, a++) { - if(md->type == eModifierType_Softbody) { - stack_index = a; - break; - } - } - } - - fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index); - if(!fp) return; + if(sb->totpoint == 0) + return; + BKE_ptcache_id_from_softbody(&pid, ob, sb); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr); + if(!pf) + return; + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - fwrite(&bp->pos, sizeof(float), 3, fp); -/*write velocities too */ + BKE_ptcache_file_write_floats(pf, bp->pos, 3); + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - fwrite(&bp->vec, sizeof(float), 3, fp); - - fclose(fp); + BKE_ptcache_file_write_floats(pf, bp->vec, 3); + + BKE_ptcache_file_close(pf); } + static int softbody_read_cache(Object *ob, float framenr) { - FILE *fp = NULL; - SoftBody *sb = ob->soft; + SoftBody *sb= ob->soft; BodyPoint *bp; - ModifierData *md = ob->modifiers.first; - int stack_index = -1; - int a, ret = 1; - - if(sb->totpoint == 0) return 0; + PTCacheID pid; + PTCacheFile *pf; + int a; + if(sb->totpoint == 0) + return 0; + + BKE_ptcache_id_from_softbody(&pid, ob, sb); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr); + if(!pf) + return 0; - if(sb->particles) - stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); - else { - for(a=0; md; md=md->next, a++) { - if(md->type == eModifierType_Softbody) { - stack_index = a; - break; - } + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) { + if(!BKE_ptcache_file_read_floats(pf, bp->pos, 3)) { + BKE_ptcache_file_close(pf); + return 0; } } - fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index); - if(!fp) - ret = 0; - else { - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - if(fread(&bp->pos, sizeof(float), 3, fp) != 3) { - ret = 0; - break; - } - /*read velocities too !*/ - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++){ - if(fread(&bp->vec, sizeof(float), 3, fp) != 3) { - ret = 0; - break; - } - } - fclose(fp); + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) { + if(!BKE_ptcache_file_read_floats(pf, bp->vec, 3)) { + BKE_ptcache_file_close(pf); + return 0; + } } - return ret; + BKE_ptcache_file_close(pf); + + return 1; } + /* +++ ************ maintaining scratch *************** */ void sb_new_scratch(SoftBody *sb) { @@ -3376,6 +3337,9 @@ SoftBody *sbNew(void) /*todo backward file compat should set sb->shearstiff = 1.0f while reading old files*/ sb->shearstiff = 1.0f; sb->solverflags |= SBSO_OLDERR; + + sb->pointcache = BKE_ptcache_add(); + return sb; } @@ -3383,14 +3347,19 @@ SoftBody *sbNew(void) void sbFree(SoftBody *sb) { free_softbody_intern(sb); + BKE_ptcache_free(sb->pointcache); MEM_freeN(sb); } +void sbFreeSimulation(SoftBody *sb) +{ + free_softbody_intern(sb); +} /* makes totally fresh start situation */ void sbObjectToSoftbody(Object *ob) { - ob->softflag |= OB_SB_REDO; + //ob->softflag |= OB_SB_REDO; free_softbody_intern(ob->soft); } @@ -3414,323 +3383,406 @@ void sbSetInterruptCallBack(int (*f)(void)) SB_localInterruptCallBack = f; } - -/* simulates one step. framenr is in frames */ -void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts) +static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) { - ParticleSystemModifierData *psmd=0; - ParticleData *pa=0; - SoftBody *sb; + ParticleSystemModifierData *psmd= NULL; + ParticleData *pa= NULL; HairKey *key= NULL; BodyPoint *bp; + float hairmat[4][4]; int a; - float dtime,ctime,forcetime; + + /* update the vertex locations */ + if(sb->particles) { + psmd= psys_get_modifier(ob,sb->particles); + pa= sb->particles->particles; + key= pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + + for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { + /* store where goals are now */ + VECCOPY(bp->origS, bp->origE); + /* copy the position of the goals at desired end time */ + if(sb->particles) { + if(key == pa->hair + pa->totkey) { + pa++; + key = pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + VECCOPY(bp->origE, key->co); + Mat4MulVecfl(hairmat,bp->origE); + + key++; + } + else{ + VECCOPY(bp->origE, vertexCos[a]); + /* vertexCos came from local world, go global */ + Mat4MulVecfl(ob->obmat, bp->origE); + } + /* just to be save give bp->origT a defined value + will be calulated in interpolate_exciter()*/ + VECCOPY(bp->origT, bp->origE); + } +} + +static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) +{ + ParticleSystemModifierData *psmd= NULL; + HairKey *key= NULL; + ParticleData *pa= NULL; + BodyPoint *bp; float hairmat[4][4]; + int a; - /* This part only sets goals and springs, based on original mesh/curve/lattice data. - Copying coordinates happens in next chunk by setting softbody flag OB_SB_RESET */ - /* remake softbody if: */ - if( (ob->softflag & OB_SB_REDO) || /* signal after weightpainting */ - (ob->soft==NULL) || /* just to be nice we allow full init */ - (ob->soft->bpoint==NULL) || /* after reading new file, or acceptable as signal to refresh */ - (numVerts!=ob->soft->totpoint) || /* should never happen, just to be safe */ - ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) /* happens when in UI edges was set */ - { - if(ob->soft && ob->soft->bpoint) /* don't clear on file load */ - softbody_clear_cache(ob, framenr); + if(sb->particles) { + psmd= psys_get_modifier(ob, sb->particles); + pa= sb->particles->particles; + key= pa->hair; - if(ob->soft->particles){ - particles_to_softbody(ob); + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + + for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { + if(sb->particles) { + if(key == pa->hair + pa->totkey) { + pa++; + key = pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + VECCOPY(bp->pos, key->co); + Mat4MulVecfl(hairmat, bp->pos); + key++; + } + else { + VECCOPY(bp->pos, vertexCos[a]); + Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ } - else switch(ob->type) { + VECCOPY(bp->origS, bp->pos); + VECCOPY(bp->origE, bp->pos); + VECCOPY(bp->origT, bp->pos); + bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; + + /* the bp->prev*'s are for rolling back from a canceled try to propagate in time + adaptive step size algo in a nutshell: + 1. set sheduled time step to new dtime + 2. try to advance the sheduled time step, beeing optimistic execute it + 3. check for success + 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so! + 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2. + 4. check if we did reach dtime + 4.a nope we need to do some more at 2. + 4.b yup we're done + */ + + VECCOPY(bp->prevpos, bp->pos); + VECCOPY(bp->prevvec, bp->vec); + VECCOPY(bp->prevdx, bp->vec); + VECCOPY(bp->prevdv, bp->vec); + } + + /* make a nice clean scratch struc */ + free_scratch(sb); /* clear if any */ + sb_new_scratch(sb); /* make a new */ + sb->scratch->needstobuildcollider=1; + + if((sb->particles)==0) { + /* copy some info to scratch */ + switch(ob->type) { case OB_MESH: - mesh_to_softbody(ob); + if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); break; case OB_LATTICE: - lattice_to_softbody(ob); break; case OB_CURVE: case OB_SURF: - curve_surf_to_softbody(ob); break; default: - renew_softbody(ob, numVerts, 0); break; } - - /* still need to update to correct vertex locations, happens on next step */ - ob->softflag |= OB_SB_RESET; - ob->softflag &= ~OB_SB_REDO; } +} - sb= ob->soft; +static void softbody_step(Object *ob, SoftBody *sb, float dtime) +{ + /* the simulator */ + float forcetime; + double sct,sst=PIL_check_seconds_timer(); + ccd_update_deflector_hache(ob,sb->scratch->colliderhash); - /* still no points? go away */ - if(sb->totpoint==0) return; + if(sb->scratch->needstobuildcollider){ + if (query_external_colliders(ob)){ + ccd_build_deflector_hache(ob,sb->scratch->colliderhash); + } + sb->scratch->needstobuildcollider=0; + } + + if (sb->solver_ID < 2) { + /* special case of 2nd order Runge-Kutta type AKA Heun */ + int mid_flags=0; + float err = 0; + float forcetimemax = 1.0f; + float forcetimemin = 0.001f; + float timedone =0.0; /* how far did we get without violating error condition */ + /* loops = counter for emergency brake + * we don't want to lock up the system if physics fail + */ + int loops =0 ; + SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ + if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; + + if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; + + if(sb->solver_ID>0) mid_flags |= MID_PRESERVE; + + //forcetime = dtime; /* hope for integrating in one step */ + forcetime =forcetimemax; /* hope for integrating in one step */ + while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) + { + /* set goals in time */ + interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); + + sb->scratch->flag &= ~SBF_DOFUZZY; + /* do predictive euler step */ + softbody_calc_forces(ob, forcetime,timedone/dtime,0); + softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); - if(sb->particles){ - psmd=psys_get_modifier(ob,sb->particles); - pa=sb->particles->particles; - } - /* checking time: */ + /* crop new slope values to do averaged slope step */ + softbody_calc_forces(ob, forcetime,timedone/dtime,0); + softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); - ctime= bsystem_time(ob, framenr, 0.0); + softbody_apply_goalsnap(ob); + + if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ + + if (forcetime > forcetimemin){ + forcetime = MAX2(forcetime / 2.0f,forcetimemin); + softbody_restore_prev_step(ob); + //printf("down,"); + } + else { + timedone += forcetime; + } + } + else { + float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ + + if (sb->scratch->flag & SBF_DOFUZZY){ + //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ + newtime = forcetime; + //} + } + else { + if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ + newtime = forcetime; + } + } + timedone += forcetime; + newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); + //if (newtime > forcetime) printf("up,"); + if (forcetime > 0.0) + forcetime = MIN2(dtime - timedone,newtime); + else + forcetime = MAX2(dtime - timedone,newtime); + } + loops++; + if(sb->solverflags & SBSO_MONITOR ){ + sct=PIL_check_seconds_timer(); + if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); + } + /* ask for user break */ + if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; - if (ob->softflag&OB_SB_RESET) { - dtime = 0.0; - } else { - dtime= ctime - sb->ctime; + } + /* move snapped to final position */ + interpolate_exciter(ob, 2, 2); + softbody_apply_goalsnap(ob); + + // if(G.f & G_DEBUG){ + if(sb->solverflags & SBSO_MONITOR ){ + if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ + printf("\r needed %d steps/frame ",loops); + } + } + else if (sb->solver_ID == 2) + {/* do semi "fake" implicit euler */ + //removed + }/*SOLVER SELECT*/ + else if (sb->solver_ID == 4) + { + /* do semi "fake" implicit euler */ + }/*SOLVER SELECT*/ + else if (sb->solver_ID == 3){ + /* do "stupid" semi "fake" implicit euler */ + //removed - if(softbody_read_cache(ob, framenr)) { - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, sb->local); - sb->ctime = ctime; - return; + }/*SOLVER SELECT*/ + else{ + printf("softbody no valid solver ID!"); + }/*SOLVER SELECT*/ + if(sb->plastic){ apply_spring_memory(ob);} + + if(sb->solverflags & SBSO_MONITOR ){ + sct=PIL_check_seconds_timer(); + if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name); } +} - /* the simulator */ +/* simulates one step. framenr is in frames */ +void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) +{ + ParticleSystemModifierData *psmd=0; + ParticleData *pa=0; + SoftBody *sb= ob->soft; + PointCache *cache; + PTCacheID pid; + float dtime, timescale; + int framedelta, framenr, startframe, endframe; - /* update the vertex locations */ - if (dtime!=0.0) { - if(sb->particles) { - pa=sb->particles->particles; - key = pa->hair; + cache= sb->pointcache; - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } + framenr= (int)cfra; + framedelta= framenr - cache->simframe; - for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { - /* store where goals are now */ - VECCOPY(bp->origS, bp->origE); - /* copy the position of the goals at desired end time */ - if(sb->particles) { - if(key == pa->hair + pa->totkey) { - pa++; - key = pa->hair; + BKE_ptcache_id_from_softbody(&pid, ob, sb); + BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, ×cale); - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - VECCOPY(bp->origE, key->co); - Mat4MulVecfl(hairmat,bp->origE); + /* check for changes in mesh, should only happen in case the mesh + * structure changes during an animation */ + if(sb->bpoint && numVerts != sb->totpoint) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; - key++; - } - else{ - VECCOPY(bp->origE, vertexCos[a]); - /* vertexCos came from local world, go global */ - Mat4MulVecfl(ob->obmat, bp->origE); - } - /* just to be save give bp->origT a defined value - will be calulated in interpolate_exciter()*/ - VECCOPY(bp->origT, bp->origE); - } + return; } - if((ob->softflag&OB_SB_RESET) || /* got a reset signal */ - (dtime<0.0) || /* back in time */ - (dtime>=9.9*G.scene->r.framelen) /* too far forward in time --> goals won't be accurate enough */ - ) - { - if(sb->particles) { - pa=sb->particles->particles; - key = pa->hair; - - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } + /* clamp frame ranges */ + if(framenr < startframe) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; - for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { - if(sb->particles) { - if(key == pa->hair + pa->totkey) { - pa++; - key = pa->hair; + return; + } + else if(framenr > endframe) { + framenr = endframe; + } - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - VECCOPY(bp->pos, key->co); - Mat4MulVecfl(hairmat, bp->pos); - key++; - } - else { - VECCOPY(bp->pos, vertexCos[a]); - Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ - } - VECCOPY(bp->origS, bp->pos); - VECCOPY(bp->origE, bp->pos); - VECCOPY(bp->origT, bp->pos); - bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; - - /* the bp->prev*'s are for rolling back from a canceled try to propagate in time - adaptive step size algo in a nutshell: - 1. set sheduled time step to new dtime - 2. try to advance the sheduled time step, beeing optimistic execute it - 3. check for success - 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so! - 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2. - 4. check if we did reach dtime - 4.a nope we need to do some more at 2. - 4.b yup we're done - */ + /* verify if we need to create the softbody data */ + if(sb->bpoint == NULL || + ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) { - VECCOPY(bp->prevpos, bp->pos); - VECCOPY(bp->prevvec, bp->vec); - VECCOPY(bp->prevdx, bp->vec); - VECCOPY(bp->prevdv, bp->vec); + if(sb->particles){ + particles_to_softbody(ob); } - /* make a nice clean scratch struc */ - free_scratch(sb); /* clear if any */ - sb_new_scratch(sb); /* make a new */ - sb->scratch->needstobuildcollider=1; - - if((sb->particles)==0) { - /* copy some info to scratch */ + else { switch(ob->type) { - case OB_MESH: - if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); - break; - case OB_LATTICE: - break; - case OB_CURVE: - case OB_SURF: - break; - default: - break; + case OB_MESH: + mesh_to_softbody(ob); + break; + case OB_LATTICE: + lattice_to_softbody(ob); + break; + case OB_CURVE: + case OB_SURF: + curve_surf_to_softbody(ob); + break; + default: + renew_softbody(ob, numVerts, 0); + break; } } - ob->softflag &= ~OB_SB_RESET; + softbody_update_positions(ob, sb, vertexCos, numVerts); + softbody_reset(ob, sb, vertexCos, numVerts); } - else if(dtime>0.0) { - double sct,sst=PIL_check_seconds_timer(); - ccd_update_deflector_hache(ob,sb->scratch->colliderhash); + /* continue physics special case */ + if(BKE_ptcache_get_continue_physics()) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; - if(sb->scratch->needstobuildcollider){ - if (query_external_colliders(ob)){ - ccd_build_deflector_hache(ob,sb->scratch->colliderhash); - } - sb->scratch->needstobuildcollider=0; - } + /* do simulation */ + dtime = timescale; + softbody_update_positions(ob, sb, vertexCos, numVerts); + softbody_step(ob, sb, dtime); - if (sb->solver_ID < 2) { - /* special case of 2nd order Runge-Kutta type AKA Heun */ - int mid_flags=0; - float err = 0; - float forcetimemax = 1.0f; - float forcetimemin = 0.001f; - float timedone =0.0; /* how far did we get without violating error condition */ - /* loops = counter for emergency brake - * we don't want to lock up the system if physics fail - */ - int loops =0 ; - SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ - if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; - - if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, 0); - if(sb->solver_ID>0) mid_flags |= MID_PRESERVE; - - //forcetime = dtime; /* hope for integrating in one step */ - forcetime =forcetimemax; /* hope for integrating in one step */ - while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) - { - /* set goals in time */ - interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); - - sb->scratch->flag &= ~SBF_DOFUZZY; - /* do predictive euler step */ - softbody_calc_forces(ob, forcetime,timedone/dtime,0); - softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); + return; + } + /* still no points? go away */ + if(sb->totpoint==0) return; - /* crop new slope values to do averaged slope step */ - softbody_calc_forces(ob, forcetime,timedone/dtime,0); - softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); + if(sb->particles){ + psmd= psys_get_modifier(ob, sb->particles); + pa= sb->particles->particles; + } - softbody_apply_goalsnap(ob); - - if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ - - if (forcetime > forcetimemin){ - forcetime = MAX2(forcetime / 2.0f,forcetimemin); - softbody_restore_prev_step(ob); - //printf("down,"); - } - else { - timedone += forcetime; - } - } - else { - float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ - - if (sb->scratch->flag & SBF_DOFUZZY){ - //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - //} - } - else { - if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - } - } - timedone += forcetime; - newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); - //if (newtime > forcetime) printf("up,"); - if (forcetime > 0.0) - forcetime = MIN2(dtime - timedone,newtime); - else - forcetime = MAX2(dtime - timedone,newtime); - } - loops++; - if(sb->solverflags & SBSO_MONITOR ){ - sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); - } - /* ask for user break */ - if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; + /* try to read from cache */ + if(softbody_read_cache(ob, framenr)) { + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, sb->local); - } - /* move snapped to final position */ - interpolate_exciter(ob, 2, 2); - softbody_apply_goalsnap(ob); - - // if(G.f & G_DEBUG){ - if(sb->solverflags & SBSO_MONITOR ){ - if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ - printf("\r needed %d steps/frame ",loops); - } - - } - else if (sb->solver_ID == 2) - {/* do semi "fake" implicit euler */ - //removed - }/*SOLVER SELECT*/ - else if (sb->solver_ID == 4) - { - /* do semi "fake" implicit euler */ - }/*SOLVER SELECT*/ - else if (sb->solver_ID == 3){ - /* do "stupid" semi "fake" implicit euler */ - //removed + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; - }/*SOLVER SELECT*/ - else{ - printf("softbody no valid solver ID!"); - }/*SOLVER SELECT*/ - if(sb->plastic){ apply_spring_memory(ob);} + return; + } + else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + /* if baked and nothing in cache, do nothing */ + if(cache->flag & PTCACHE_SIMULATION_VALID) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } - if(sb->solverflags & SBSO_MONITOR ){ - sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name); - } + return; } - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, 0); - sb->ctime= ctime; + if(framenr == startframe) { + /* first frame, no simulation to do, just set the positions */ + softbody_update_positions(ob, sb, vertexCos, numVerts); + + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + + /* don't write cache on first frame, but on second frame write + * cache for frame 1 and 2 */ + } + else if(framedelta == 1) { + /* if on second frame, write cache for first frame */ + if(framenr == startframe+1) + sbWriteCache(ob, startframe); + + softbody_update_positions(ob, sb, vertexCos, numVerts); + + /* do simulation */ + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + + /* checking time: */ + dtime = framedelta*timescale; - softbody_write_cache(ob, framenr); + softbody_step(ob, sb, dtime); + + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, 0); + + sbWriteCache(ob, framenr); + } + else { + /* time step backwards or too large forward - do nothing */ + if(cache->flag & PTCACHE_SIMULATION_VALID) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } + } } |