Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-04-10 15:39:20 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-04-10 15:39:20 +0400
commit1fe5302cce8de1bad875ad29a3fcff06d0c59654 (patch)
tree7ad40e8f9ee90d0c16185cf4dcb06ee025765b58 /source/blender/blenkernel
parent36288dabb8e39910b81dc09067db9065cc3004b9 (diff)
Point Cache Refactoring
======================= Caching and Baking: - The point cache is now cleared on DAG_object_flush_update(), and not cleared for time dependency graph updates. - There is now a Bake button instead of Protect. Also cache start and end frames were added to softbody and particles. - The cloth autoprotect feature was removed. - The Ctrl+B menu now also bakes cloth and particles next to softbody and fluids. Additionally there are now frree bake and free cache menu entries. - The point cache api has been changed. There is now a PTCacheID struct for each point cache type that can be filled and then used to call the point cache functions. - PointCache struct was added to DNA and is automatically allocated for each physics type. - Soft body now supports Bake Editing just like cloth. - Tried to make the systems deal consistently with time ipo's and offsets. Still not sure it all works correct, but too complicated to solve completely now. Library Linking: - Added some more warnings to prevent editing settings on library linked objects. - Linked objects now read from the cache located next to the original library file, and never write to it. This restores old behavior for softbodies. For local simulation the mesh and not the object should be linked. - Dupligroups and proxies can't create local point caches at the moment, how to implement that I'm not sure. We probably need a proxy point cache for that to work (ugh). Physics UI: - Renamed deflection panel to collision for consistency and reorganized the buttons. Also removed some softbody collision buttons from the softbody panel that were duplicated in this panel for cloth. - Tweaked field panel buttons to not jump around when changing options. - Tabbing e.g. Soft Body Collision into the Soft Body panel, it now only shows Collision to make the panel names readable. - I tried to make enabled/disabling physics more consistent, since all three system did things different. Now the two modifier buttons to enable the modifier for the viewport and rendering are also duplicated in the physics panels. Toggling the Soft Body and Cloth buttons now both remove their modifiers. - Fixed modifier error drawing glitch. Particles: - Particles are now recalculated more often than before. Previously it did partial updates based on the changes, but that doesn't work well with DAG_object_flush_update() .. - Fixed memory leak loading keyed particle system. Now keys are not written to file anymore but always created after loading. - Make particle threads work with autothreads. Continue Physics: - The timeline play now has a Continue Physics option in the playback menu, which keeps the simulations going without writing them to the cache. - This doesn't always work that well, some changes are not immediately updated, but this can be improved later. Still it's fun to get a feel for the physics. Todo: - Point cache can get out of sync with and undo and changing a file without saving it. - Change the point cache file format to store a version (so old point cache files can be either converted or at least ignored), and to do correct endian conversion. - Menu item and/or buttons for Ctrl+B. - A system("rm ..") was changed to remove() since the former is very slow for clearing point caches. These system() calls were already giving trouble in a bug in the tracker, but really most use of this system("") should be changed and tested. - The Soft Body Collision and Clot Collision panel titles don't mention there's point cache settings there too, doing that makes them unreadable with the default panel setup.. but may need to make the names longer anyway.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_cloth.h14
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h2
-rw-r--r--source/blender/blenkernel/BKE_particle.h15
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h74
-rw-r--r--source/blender/blenkernel/BKE_softbody.h5
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c6
-rw-r--r--source/blender/blenkernel/intern/cloth.c539
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c76
-rw-r--r--source/blender/blenkernel/intern/modifier.c12
-rw-r--r--source/blender/blenkernel/intern/object.c15
-rw-r--r--source/blender/blenkernel/intern/particle.c48
-rw-r--r--source/blender/blenkernel/intern/particle_system.c475
-rw-r--r--source/blender/blenkernel/intern/pointcache.c383
-rw-r--r--source/blender/blenkernel/intern/softbody.c732
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, &timescale);
+ 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, &timescale);
- 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;
+ }
+ }
}