Point Cache Refactoring
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Thu, 10 Apr 2008 11:39:20 +0000 (11:39 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Thu, 10 Apr 2008 11:39:20 +0000 (11:39 +0000)
=======================

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.

42 files changed:
source/blender/blenkernel/BKE_cloth.h
source/blender/blenkernel/BKE_depsgraph.h
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/BKE_softbody.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cloth.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenlib/intern/fileops.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/butspace.h
source/blender/makesdna/DNA_cloth_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_object_force.h
source/blender/makesdna/DNA_particle_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/src/buttons_editing.c
source/blender/src/buttons_object.c
source/blender/src/drawview.c
source/blender/src/edit.c
source/blender/src/editipo.c
source/blender/src/editmesh.c
source/blender/src/editnla.c
source/blender/src/editobject.c
source/blender/src/editparticle.c
source/blender/src/fluidsim.c
source/blender/src/header_time.c
source/blender/src/interface_panel.c
source/blender/src/poselib.c
source/blender/src/space.c
source/blender/src/toets.c
source/blender/src/transform.c
source/blender/src/transform_conversions.c
source/blender/src/transform_generics.c
source/blender/src/vpaint.c

index 418102a..f1a439e 100644 (file)
@@ -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 */
index 294f61e..36f26d4 100644 (file)
@@ -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);
 
index f134c45..45be121 100644 (file)
@@ -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
index 12068f7..5bc4674 100644 (file)
 
 #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
index 91bc4cc..8a3688f 100644 (file)
@@ -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
 
index b0103fa..7624ca0 100644 (file)
@@ -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;
index 6123b1b..15f4051 100644 (file)
@@ -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 );
index 5f95ce6..ab6cf07 100644 (file)
@@ -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 */
index 2d60981..0f51c74 100644 (file)
@@ -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)
index 287708a..ff5dcb7 100644 (file)
 #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 */
index 6b2f2f9..6bdb4e6 100644 (file)
@@ -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                                                        */
 /************************************************/
index 8bde0af..cd0d6b5 100644 (file)
@@ -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);
 }
 
index cdb95e2..3b411e7 100644 (file)
  * ***** 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 */
 #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;
+}
+
index df6b0d3..c7440f3 100644 (file)
@@ -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;
+               }
+       }
 }
 
index e5b1141..a9da0c9 100644 (file)
@@ -333,7 +333,7 @@ int BLI_delete(char *file, int dir, int recursive)
        else {
                if (recursive) sprintf(str, "/bin/rm -rf \"%s\"", file);
                else if (dir) sprintf(str, "/bin/rmdir \"%s\"", file);
-               else sprintf(str, "/bin/rm -f \"%s\"", file);
+               else remove(file); //sprintf(str, "/bin/rm -f \"%s\"", file);
 
                return system(str);
        }
index b055e62..7fe023c 100644 (file)
 #include "BKE_node.h" // for tree type defines
 #include "BKE_object.h"
 #include "BKE_particle.h"
+#include "BKE_pointcache.h"
 #include "BKE_property.h" // for get_property
 #include "BKE_sca.h" // for init_actuator
 #include "BKE_scene.h"
@@ -2529,6 +2530,12 @@ static void direct_link_material(FileData *fd, Material *ma)
 
 /* ************ READ PARTICLE SETTINGS ***************** */
 
+static void direct_link_pointcache(FileData *fd, PointCache *cache)
+{
+       cache->flag &= ~(PTCACHE_SIMULATION_VALID|PTCACHE_BAKE_EDIT_ACTIVE);
+       cache->simframe= 0;
+}
+
 static void lib_link_particlesettings(FileData *fd, Main *main)
 {
        ParticleSettings *part;
@@ -2582,8 +2589,12 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
                }
                if(psys->particles && psys->particles->keys){
                        ParticleData *pa = psys->particles;
-                       for(a=0; a<psys->totpart; a++, pa++)
-                               pa->keys=newdataadr(fd,pa->keys);
+                       for(a=0; a<psys->totpart; a++, pa++) {
+                               pa->keys= NULL;
+                               pa->totkey= 0;
+                       }
+
+                       psys->flag &= ~PSYS_KEYED;
                }
                psys->child=newdataadr(fd,psys->child);
                psys->effectors.first=psys->effectors.last=0;
@@ -2595,12 +2606,20 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
                        sb->bpoint= NULL;       // init pointers so it gets rebuilt nicely
                        sb->bspring= NULL;
                        sb->scratch= NULL;
+
+                       sb->pointcache= newdataadr(fd, sb->pointcache);
+                       if(sb->pointcache)
+                               direct_link_pointcache(fd, sb->pointcache);
                }
 
                psys->edit = 0;
                psys->pathcache = 0;
                psys->childcache = 0;
                psys->reactevents.first = psys->reactevents.last = 0;
+
+               psys->pointcache= newdataadr(fd, psys->pointcache);
+               if(psys->pointcache)
+                       direct_link_pointcache(fd, psys->pointcache);
        }
        return;
 }
@@ -3009,8 +3028,8 @@ static void lib_link_object(FileData *fd, Main *main)
 }
 
 
-static void direct_link_pose(FileData *fd, bPose *pose) {
-
+static void direct_link_pose(FileData *fd, bPose *pose)
+{
        bPoseChannel *pchan;
 
        if (!pose)
@@ -3054,12 +3073,12 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
                        
                        clmd->sim_parms= newdataadr(fd, clmd->sim_parms);
                        clmd->coll_parms= newdataadr(fd, clmd->coll_parms);
+                       clmd->point_cache= newdataadr(fd, clmd->point_cache);
+
+                       if(clmd->point_cache)
+                               direct_link_pointcache(fd, clmd->point_cache);
                        
-                       if(clmd->sim_parms)
-                       {
-                               clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_LOADED;
-                               clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_EDITMODE;
-                               
+                       if(clmd->sim_parms) {
                                if(clmd->sim_parms->presets > 10)
                                        clmd->sim_parms->presets = 0;
                        }
@@ -3245,6 +3264,10 @@ static void direct_link_object(FileData *fd, Object *ob)
                                sb->keys[a]= newdataadr(fd, sb->keys[a]);
                        }
                }
+
+               sb->pointcache= newdataadr(fd, sb->pointcache);
+               if(sb->pointcache)
+                       direct_link_pointcache(fd, sb->pointcache);
        }
        ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */
        if(ob->fluidsimSettings) {
@@ -6910,6 +6933,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                Mesh *me;
                bNodeTree *ntree;
                Tex *tex;
+               ModifierData *md;
+               ParticleSystem *psys;
                
                /* unless the file was created 2.44.3 but not 2.45, update the constraints */
                if ( !(main->versionfile==244 && main->subversionfile==3) &&
@@ -7034,6 +7059,27 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                        }
                }
 
+               /* add point caches */
+               for(ob=main->object.first; ob; ob=ob->id.next) {
+                       if(ob->soft && !ob->soft->pointcache)
+                               ob->soft->pointcache= BKE_ptcache_add();
+
+                       for(psys=ob->particlesystem.first; psys; psys=psys->next) {
+                               if(psys->soft && !psys->soft->pointcache)
+                                       psys->soft->pointcache= BKE_ptcache_add();
+                               if(!psys->pointcache)
+                                       psys->pointcache= BKE_ptcache_add();
+                       }
+
+                       for(md=ob->modifiers.first; md; md=md->next) {
+                               if(md->type==eModifierType_Cloth) {
+                                       ClothModifierData *clmd = (ClothModifierData*) md;
+                                       if(!clmd->point_cache)
+                                               clmd->point_cache= BKE_ptcache_add();
+                               }
+                       }
+               }
+
                /* Copy over old per-level multires vertex data
                   into a single vertex array in struct Multires */
                for(me = main->mesh.first; me; me=me->id.next) {
@@ -7287,7 +7333,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
 
                                sb->keys = NULL;
                                sb->totkey = 0;
-                               ob->softflag &= ~OB_SB_BAKESET;
                        }
                }
        }
@@ -7311,7 +7356,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
 
                                sb->keys = NULL;
                                sb->totkey = 0;
-                               ob->softflag &= ~OB_SB_BAKESET;
                        }
 
                        /* convert old particles to new system */
@@ -7333,7 +7377,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                part->id.flag |= (ob->id.flag & LIB_NEEDLINK);
                                
                                psys->totpart=0;
-                               psys->flag=PSYS_ENABLED|PSYS_CURRENT;
+                               psys->flag= PSYS_ENABLED|PSYS_CURRENT;
 
                                BLI_addtail(&ob->particlesystem, psys);
 
index 6308f09..269ea1e 100644 (file)
@@ -576,16 +576,11 @@ static void write_particlesystems(WriteData *wd, ListBase *particles)
                                for(a=0; a<psys->totpart; a++, pa++)
                                        writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
                        }
-                       
-                       if(psys->particles->keys) {
-                               ParticleData *pa = psys->particles;
-
-                               for(a=0; a<psys->totpart; a++, pa++)
-                                       writestruct(wd, DATA, "ParticleKey", pa->totkey, pa->keys);
-                       }
                }
                if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child);
                writestruct(wd, DATA, "SoftBody", 1, psys->soft);
+               if(psys->soft) writestruct(wd, DATA, "PointCache", 1, psys->soft->pointcache);
+               writestruct(wd, DATA, "PointCache", 1, psys->pointcache);
        }
 }
 
@@ -864,7 +859,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
                        
                        writestruct(wd, DATA, "ClothSimSettings", 1, clmd->sim_parms);
                        writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms);
-                       
+                       writestruct(wd, DATA, "PointCache", 1, clmd->point_cache);
                } 
                else if (md->type==eModifierType_Collision) {
                        
@@ -930,6 +925,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
                        
                        writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
                        writestruct(wd, DATA, "SoftBody", 1, ob->soft);
+                       if(ob->soft) writestruct(wd, DATA, "PointCache", 1, ob->soft->pointcache);
                        writestruct(wd, DATA, "FluidsimSettings", 1, ob->fluidsimSettings); // NT
                        
                        write_particlesystems(wd, &ob->particlesystem);
index b3e0e1a..17a887e 100644 (file)
@@ -295,13 +295,10 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
 #define B_GROUP_RELINK                 1460
 #define B_OBJECT_IPOFLAG               1461
 
-#define B_BAKEABLE_CHANGE              1470
+#define B_BAKE_CACHE_CHANGE            1470
 
 /* Cloth sim button defines */
-#define B_CLOTH_CLEARCACHEALL  1480
-#define B_CLOTH_CLEARCACHEFRAME        1481
-#define B_CLOTH_CHANGEPREROLL  1482
-#define B_CLOTH_RENEW          1483
+#define B_CLOTH_CHANGEPREROLL  1480
 
 /* *********************** */
 #define B_WORLDBUTS            1600
index b8a6ddd..5f6aff0 100644 (file)
@@ -32,7 +32,6 @@
 #ifndef DNA_CLOTH_TYPES_H
 #define DNA_CLOTH_TYPES_H
 
-
 /**
 * This struct contains all the global data required to run a simulation.
 * At the time of this writing, this structure contains data appropriate
@@ -61,8 +60,8 @@ typedef struct ClothSimSettings
        float   structural;     /* Structural spring stiffness.                 */
        float   shear;          /* Shear spring stiffness.                      */
        float   bending;        /* Flexion spring stiffness.                    */
-       float   sim_time;
-       int     flags;          /* flags, see CSIMSETT_FLAGS enum above.        */
+       float   padf;
+       int             flags;          /* flags, see CSIMSETT_FLAGS enum above.        */
        short   solver_type;    /* which solver should be used?         txold   */
        short   vgroup_bend;    /* vertex group for scaling bending stiffness */
        float   maxgoal;        /* see SB */
@@ -74,21 +73,14 @@ typedef struct ClothSimSettings
        int     goalfrict;
        float   goalspring;
        int     maxspringlen;   /* in percent!; if tearing enabled, a spring will get cut */
-       int     lastframe;      /* frame on which simulation stops */
-       int     firstframe;     /* frame on which simulation starts */
-       int     lastcachedframe;
-       int     editedframe;    /* which frame is in buffer */
-       int     autoprotect;    /* starting from this frame, cache gets protected  */
        float   max_bend;       /* max bending scaling value, min is "bending" */
        float   max_struct;     /* max structural scaling value, min is "structural" */
        float   max_shear;      /* max shear scaling value, UNUSED */
-       int     firstcachedframe;
        float   avg_spring_len; /* used for normalized springs */
        short   presets; /* used for presets on GUI */
        short   pad;
        float   timescale; /* parameter how fast cloth runs */
-}
-ClothSimSettings;
+} ClothSimSettings;
 
 
 typedef struct ClothCollSettings
@@ -101,9 +93,7 @@ typedef struct ClothCollSettings
        struct  LinkNode *collision_list; /* e.g. pointer to temp memory for collisions */
        int     flags;                  /* collision flags defined in BKE_cloth.h */
        float   selfepsilon;            /* for selfcollision */
-}
-ClothCollSettings;
-
+} ClothCollSettings;
 
 /**
 * This structure describes a cloth object against which the
@@ -130,7 +120,6 @@ typedef struct Cloth
        struct Implicit_Data    *implicit;              /* our implicit solver connects to this pointer */
        struct Implicit_Data    *implicitEM;            /* our implicit solver connects to this pointer */
        struct EdgeHash         *edgehash;              /* used for selfcollisions */
-}
-Cloth;
+} Cloth;
 
 #endif
index c62d012..b7b4381 100644 (file)
@@ -371,6 +371,7 @@ typedef struct ClothModifierData {
    struct Cloth *clothObject; /* The internal data structure for cloth. */
    struct ClothSimSettings *sim_parms; /* definition is in DNA_cloth_types.h */
    struct ClothCollSettings *coll_parms; /* definition is in DNA_cloth_types.h */
+   struct PointCache *point_cache;     /* definition is in DNA_object_force.h */
 } ClothModifierData;
 
 typedef struct CollisionModifierData {
index 70e0e91..192c742 100644 (file)
@@ -72,6 +72,13 @@ typedef struct PartDeflect {
        struct Tex *tex;        /* Texture of the texture effector */
 } PartDeflect;
 
+typedef struct PointCache {
+       int flag;               /* generic flag */
+       int simframe;   /* current frame of simulation (only if SIMULATION_VALID) */
+       int startframe; /* simulation start frame */
+       int endframe;   /* simulation end frame */
+       int editframe;  /* frame being edited (runtime only) */
+} PointCache;
 
 typedef struct SBVertex {
        float vec[4];
@@ -84,7 +91,7 @@ typedef struct SoftBody {
        int totpoint, totspring;
        struct BodyPoint *bpoint;               /* not saved in file */
        struct BodySpring *bspring;             /* not saved in file */
-       float ctime;                                    /* last time calculated */
+       float pad;
        
        /* part of UI: */
        
@@ -137,6 +144,8 @@ typedef struct SoftBody {
        float shearstiff;
        float inpush;
 
+       struct PointCache *pointcache;
+
 } SoftBody;
 
 /* pd->forcefield:  Effector Fields types */
@@ -177,21 +186,29 @@ typedef struct SoftBody {
 #define PFIELD_TEX_GRAD        1
 #define PFIELD_TEX_CURL        2
 
+/* pointcache->flag */
+#define PTCACHE_BAKED                          1
+#define PTCACHE_OUTDATED                       2
+#define PTCACHE_SIMULATION_VALID       4
+#define PTCACHE_BAKING                         8
+#define PTCACHE_BAKE_EDIT                      16
+#define PTCACHE_BAKE_EDIT_ACTIVE       32
+
 /* ob->softflag */
 #define OB_SB_ENABLE   1
 #define OB_SB_GOAL             2
 #define OB_SB_EDGES            4
 #define OB_SB_QUADS            8
 #define OB_SB_POSTDEF  16
-#define OB_SB_REDO             32
-#define OB_SB_BAKESET  64
-#define OB_SB_BAKEDO   128
-#define OB_SB_RESET            256
+// #define OB_SB_REDO          32
+// #define OB_SB_BAKESET       64
+// #define OB_SB_BAKEDO        128
+// #define OB_SB_RESET         256
 #define OB_SB_SELF             512
 #define OB_SB_FACECOLL  1024
 #define OB_SB_EDGECOLL  2048
 #define OB_SB_COLLFINAL 4096
-#define OB_SB_PROTECT_CACHE    8192
+//#define OB_SB_PROTECT_CACHE  8192
 #define OB_SB_AERO_ANGLE       16384
 
 /* sb->solverflags */
index 2203de1..d2f2766 100644 (file)
@@ -206,6 +206,9 @@ typedef struct ParticleSystem{
 
        /* temporary storage during render */
        void *renderdata;
+
+       /* point cache */
+       struct PointCache *pointcache;
 }ParticleSystem;
 
 /* general particle maximums */
@@ -387,7 +390,7 @@ typedef struct ParticleSystem{
 //#define PSYS_BAKING                  2
 //#define PSYS_BAKE_UI         4
 #define        PSYS_KEYED_TIME         8
-#define PSYS_ENABLED           16
+#define PSYS_ENABLED           16      /* deprecated */
 #define PSYS_FIRST_KEYED       32
 #define PSYS_DRAWING           64
 //#define PSYS_SOFT_BAKE               128
@@ -395,7 +398,8 @@ typedef struct ParticleSystem{
 #define PSYS_HAIR_DONE         512
 #define PSYS_KEYED                     1024
 #define PSYS_EDITED                    2048
-#define PSYS_PROTECT_CACHE     4096
+//#define PSYS_PROTECT_CACHE   4096
+#define PSYS_DISABLED          8192
 
 /* pars->flag */
 #define PARS_UNEXIST           1
index f96a4fe..9e49b3a 100644 (file)
@@ -633,6 +633,7 @@ typedef struct SpaceImaSel {
 #define TIME_WITH_SEQ_AUDIO            16
 #define TIME_SEQ                               32
 #define TIME_ALL_IMAGE_WIN             64
+#define TIME_CONTINUE_PHYSICS  128
 
 /* sseq->mainb */
 #define SEQ_DRAW_SEQUENCE         0
index 144b266..80ca4db 100644 (file)
@@ -930,7 +930,6 @@ void do_modifier_panels(unsigned short event)
                break;
 
        case B_MODIFIER_RECALC:
-               ob->softflag |= OB_SB_RESET;
                allqueue(REDRAWBUTSEDIT, 0);
                allqueue(REDRAWVIEW3D, 0);
                allqueue(REDRAWIMAGE, 0);
@@ -2230,11 +2229,11 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                                uiButSetFunc(but, modifiers_reassignHook, ob, md);
                        }
                } else if (md->type==eModifierType_Softbody) {
-                       uiDefBut(block, LABEL, 1, "See Softbody panel.",        lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
+                       uiDefBut(block, LABEL, 1, "See Soft Body panel.",       lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
                } else if (md->type==eModifierType_Cloth) {
                        uiDefBut(block, LABEL, 1, "See Cloth panel.",   lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
                } else if (md->type==eModifierType_Collision) {
-                       uiDefBut(block, LABEL, 1, "See Deflection panel.",      lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
+                       uiDefBut(block, LABEL, 1, "See Collision panel.",       lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
                } else if (md->type==eModifierType_Boolean) {
                        BooleanModifierData *bmd = (BooleanModifierData*) md;
                        uiDefButI(block, MENU, B_MODIFIER_RECALC, "Operation%t|Intersect%x0|Union%x1|Difference%x2",    lx,(cy-=19),buttonWidth,19, &bmd->operation, 0.0, 1.0, 0, 0, "Boolean operation to perform");
@@ -2444,17 +2443,17 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
        }
 
        if (md->error) {
-               char str[512];
-
-               y -= 20;
+               y -= 6;
 
                uiBlockSetCol(block, color);
                                        /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
                uiDefBut(block, ROUNDBOX, 0, "", x-10, y, width, 20, NULL, 5.0, 0.0, 15, 40, ""); 
                uiBlockSetCol(block, TH_AUTO);
 
-               sprintf(str, "Modifier Error: %s", md->error);
-               uiDefBut(block, LABEL, B_NOP, str, x+15, y+15, width-35, 19, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+               uiDefIconBut(block,LABEL,B_NOP,ICON_ERROR, x-9, y,19,19, 0,0,0,0,0, "");
+               uiDefBut(block, LABEL, B_NOP, md->error, x+5, y, width-15, 19, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+
+               y -= 18;
        }
 
        uiClearButLock();
@@ -2481,7 +2480,7 @@ static void editing_panel_modifiers(Object *ob)
        uiDefBlockBut(block, modifiers_add_menu, ob, "Add Modifier", 0, 190, 130, 20, "Add a new modifier");
 
        sprintf(str, "To: %s", ob->id.name+2);
-       uiDefBut(block, LABEL, 1, str,  140, 190, 150, 20, NULL, 0.0, 0.0, 0, 0, "Object whose modifier stack is being edited");
+       uiDefBut(block, LABEL, 1, str,  140, 190, 160, 20, NULL, 0.0, 0.0, 0, 0, "Object whose modifier stack is being edited");
 
        xco = 0;
        yco = 160;
@@ -3708,11 +3707,6 @@ void do_latticebuts(unsigned short event)
                        lt = ob->data;
                        if(ob==G.obedit) resizelattice(editLatt, lt->opntsu, lt->opntsv, lt->opntsw, NULL);
                        else resizelattice(ob->data, lt->opntsu, lt->opntsv, lt->opntsw, NULL);
-                       ob->softflag |= OB_SB_REDO;
-                       if(modifiers_isClothEnabled(ob)) {
-                               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-                               clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-                       }
                        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
                        allqueue(REDRAWVIEW3D, 0);
                }
@@ -3720,11 +3714,6 @@ void do_latticebuts(unsigned short event)
                if(ob) {
                        lt = ob->data;
                        resizelattice(ob->data, lt->opntsu, lt->opntsv, lt->opntsw, ob);
-                       ob->softflag |= OB_SB_REDO;
-                       if(modifiers_isClothEnabled(ob)) {
-                               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-                               clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-                       }
                        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
                        allqueue(REDRAWVIEW3D, 0);
                }
@@ -5032,7 +5021,7 @@ static void editing_panel_mesh_tools1(Object *ob, Mesh *me)
 
 
        block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools1", UI_EMBOSS, UI_HELV, curarea->win);
-       if(uiNewPanel(curarea, block, "Mesh Tools 1", "Editing", 960, 0, 318, 204)==0) return;
+       if(uiNewPanel(curarea, block, "Mesh Tools More", "Editing", 960, 0, 318, 204)==0) return;
 
        uiBlockBeginAlign(block);
        uiDefBut(block, BUT,B_SELSWAP,  "Select Swap",  955, 200,  106, 19, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces (Ctrl+I)");
index c88f280..aeb94ff 100644 (file)
@@ -54,6 +54,7 @@
 #include "BKE_softbody.h"
 #include "BKE_utildefines.h"
 #include "BKE_particle.h"
+#include "BKE_pointcache.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"
@@ -2052,72 +2053,133 @@ void do_constraintbuts(unsigned short event)
        allqueue (REDRAWBUTSOBJECT, 0);
 }
 
-void softbody_bake(Object *ob)
+void pointcache_bake(PTCacheID *pid, int startframe)
 {
        Base *base;
-       SoftBody *sb;
        ScrArea *sa;
+    PointCache *cache;
+       ListBase pidlist;
        float frameleno= G.scene->r.framelen;
-       int cfrao= CFRA, sfra=100000, efra=0, didbreak =0;
-       
+       int cfrao= CFRA, didbreak =0, endframe, cstart, cend;
        
        G.scene->r.framelen= 1.0;               // baking has to be in uncorrected time
        sbSetInterruptCallBack(blender_test_break); // make softbody module ESC aware
        G.afbreek=0; // init global break system
        
-       if(ob) {
-               sb= ob->soft;
-               sfra= MIN2(sfra, sb->sfra);
-               efra= MAX2(efra, sb->efra);
-               sbObjectToSoftbody(ob); // put softbody in restposition, free bake
-               ob->softflag |= OB_SB_BAKEDO;
+       if(pid) {
+           cache= pid->cache;
+
+               BKE_ptcache_id_time(pid, 0.0f, &cstart, &cend, NULL);
+
+               startframe= startframe;
+               endframe= cend;
+
+               cache->flag |= PTCACHE_BAKING;
+               cache->flag &= ~PTCACHE_BAKED;
        }
        else {
+               startframe= MAXFRAME;
+               endframe= 0;
+
                for(base=G.scene->base.first; base; base= base->next) {
                        if(TESTBASELIB(base)) {
-                               if(base->object->soft) {
-                                       sb= base->object->soft;
-                                       sfra= MIN2(sfra, sb->sfra);
-                                       efra= MAX2(efra, sb->efra);
-                                       sbObjectToSoftbody(base->object);       // put softbody in restposition, free bake
-                                       base->object->softflag |= OB_SB_BAKEDO;
+                               BKE_ptcache_ids_from_object(&pidlist, base->object);
+
+                               for(pid=pidlist.first; pid; pid=pid->next) {
+                                       cache= pid->cache;
+
+                                       BKE_ptcache_id_time(pid, 0.0f, &cstart, &cend, NULL);
+
+                                       startframe= MIN2(startframe, cstart);
+                                       endframe= MAX2(endframe, cend);
+
+                                       cache->flag |= PTCACHE_BAKING;
+                                       cache->flag &= ~PTCACHE_BAKED;
                                }
+
+                               BLI_freelistN(&pidlist);
                        }
                }
        }
        
-       CFRA= sfra;
+       CFRA= startframe;
        update_for_newframe_muted();    // put everything on this frame
        
        curarea->win_swap= 0;           // clean swapbuffers
        
-       for(; CFRA <= efra; CFRA++) {
+       for(; CFRA <= endframe; CFRA++) {
                set_timecursor(CFRA);
                
                update_for_newframe_muted();
                
-               for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
-                       if(sa->spacetype == SPACE_VIEW3D) {
+               for(sa= G.curscreen->areabase.first; sa; sa= sa->next)
+                       if(sa->spacetype == SPACE_VIEW3D)
                                scrarea_do_windraw(sa);
-                       }
-               }
                screen_swapbuffers();
+
                //blender_test_break() has a granularity of 10 ms, who cares .. baking the unit cube is kinda boring
-               if (blender_test_break()){ 
+               if(blender_test_break()) {
                        didbreak = 1;
                        break;
                }
+       }
+
+       if(didbreak && G.qual!=LR_SHIFTKEY) {
+               /* failed to bake, free the frames we baked */
+               if(pid) {
+                       cache= pid->cache;
+
+                       BKE_ptcache_id_time(pid, 0.0f, &cstart, &cend, NULL);
+
+                       cache->flag &= ~PTCACHE_BAKING;
+                       if(startframe == cstart)
+                               cache->flag &= ~PTCACHE_BAKED;
+
+                       BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, startframe-1);
+               }
+               else {
+                       for(base=G.scene->base.first; base; base= base->next) {
+                               if(TESTBASELIB(base)) {
+                                       BKE_ptcache_ids_from_object(&pidlist, base->object);
 
+                                       for(pid=pidlist.first; pid; pid=pid->next) {
+                                               cache= pid->cache;
+
+                                               BKE_ptcache_id_time(pid, 0.0f, &cstart, &cend, NULL);
+
+                                               cache->flag &= ~PTCACHE_BAKING;
+                                               if(startframe == cstart)
+                                                       cache->flag &= ~PTCACHE_BAKED;
+
+                                               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, startframe-1);
+                                       }
+
+                                       BLI_freelistN(&pidlist);
+                               }
+                       }
+               }
        }
-       if((didbreak)&&(G.qual!=LR_SHIFTKEY)) {
-               if(ob) 
-                       sbObjectToSoftbody(ob); // free bake
+       else {
+               /* succesfully finished baking */
+               if(pid) {
+                       cache= pid->cache;
+
+                       cache->flag &= ~PTCACHE_BAKING;
+                       cache->flag |= PTCACHE_BAKED;
+               }
                else {
                        for(base=G.scene->base.first; base; base= base->next) {
                                if(TESTBASELIB(base)) {
-                                       if(base->object->soft) {
-                                               sbObjectToSoftbody(base->object);       // free bake
+                                       BKE_ptcache_ids_from_object(&pidlist, base->object);
+
+                                       for(pid=pidlist.first; pid; pid=pid->next) {
+                                               cache= pid->cache;
+
+                                               cache->flag &= ~PTCACHE_BAKING;
+                                               cache->flag |= PTCACHE_BAKED;
                                        }
+
+                                       BLI_freelistN(&pidlist);
                                }
                        }
                }
@@ -2127,16 +2189,7 @@ void softbody_bake(Object *ob)
        waitcursor(0);
        sbSetInterruptCallBack(NULL); // softbody module won't ESC
        G.afbreek=0; // reset global break system
-       
-       if(ob) 
-               ob->softflag &= ~OB_SB_BAKEDO;
-       else {
-               for(base=G.scene->base.first; base; base= base->next)
-                       if(TESTBASELIB(base))
-                               if(base->object->soft)
-                                       base->object->softflag &= ~OB_SB_BAKEDO;
-       }
-       
+
        CFRA= cfrao;
        G.scene->r.framelen= frameleno;
        update_for_newframe_muted();
@@ -2144,6 +2197,42 @@ void softbody_bake(Object *ob)
        allqueue(REDRAWBUTSOBJECT, 0);
 }
 
+void pointcache_free(PTCacheID *pid, int cacheonly)
+{
+       Base *base;
+       ListBase pidlist;
+       
+       if(pid) {
+               if(cacheonly)
+                       BKE_ptcache_id_reset(pid, PTCACHE_RESET_DEPSGRAPH);
+               else
+                       BKE_ptcache_id_reset(pid, PTCACHE_RESET_BAKED);
+
+               DAG_object_flush_update(G.scene, pid->ob, OB_RECALC_DATA);
+       }
+       else {
+               for(base=G.scene->base.first; base; base= base->next) {
+                       if(TESTBASELIB(base)) {
+                               BKE_ptcache_ids_from_object(&pidlist, base->object);
+
+                               for(pid=pidlist.first; pid; pid=pid->next) {
+                                       if(cacheonly)
+                                               BKE_ptcache_id_reset(pid, PTCACHE_RESET_DEPSGRAPH);
+                                       else
+                                               BKE_ptcache_id_reset(pid, PTCACHE_RESET_BAKED);
+
+                                       DAG_object_flush_update(G.scene, pid->ob, OB_RECALC_DATA);
+                               }
+
+                               BLI_freelistN(&pidlist);
+                       }
+               }
+       }
+
+       allqueue(REDRAWVIEW3D, 0);
+       allqueue(REDRAWBUTSOBJECT, 0);
+}
+
 // store processed path & file prefix for fluidsim bake directory
 void fluidsimFilesel(char *selection)
 {
@@ -2274,34 +2363,15 @@ void do_object_panels(unsigned short event)
                allqueue(REDRAWVIEW3D, 0);
                break;
        
-       case B_SOFTBODY_CHANGE:
-               ob= OBACT;
-               if(ob) {
-                       ParticleSystem *psys = PE_get_current(ob);
-                       if(psys)
-                               psys->softflag |= OB_SB_REDO;
-                       else
-                               ob->softflag |= OB_SB_REDO;
-                       allqueue(REDRAWBUTSOBJECT, 0);
-                       allqueue(REDRAWVIEW3D, 0);
-               }
-               break;
        case B_SOFTBODY_DEL_VG:
                if(ob->soft) {
                        ob->soft->vertgroup= 0;
-                       ob->softflag |= OB_SB_REDO;
+                       //ob->softflag |= OB_SB_REDO;
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
                        allqueue(REDRAWBUTSOBJECT, 0);
                        allqueue(REDRAWVIEW3D, 0);
                }
                break;
-       case B_SOFTBODY_BAKE:
-               if(ob->soft) softbody_bake(ob);
-               break;
-       case B_SOFTBODY_BAKE_FREE:
-               if(ob->soft) sbObjectToSoftbody(ob);
-               allqueue(REDRAWBUTSOBJECT, 0);
-               allqueue(REDRAWVIEW3D, 0);
-               break;
        case B_FLUIDSIM_BAKE:
                /* write config files (currently no simulation) */
                fluidsimBake(ob);
@@ -2316,6 +2386,7 @@ void do_object_panels(unsigned short event)
 
                        part->type = PART_FLUID;
                        psys->part = part;
+                       psys->pointcache = BKE_ptcache_add();
                        psys->flag |= PSYS_ENABLED;
 
                        ob->fluidsimSettings->type = OB_FLUIDSIM_PARTICLE;
@@ -2375,63 +2446,21 @@ void do_object_panels(unsigned short event)
                group_relink_nla_objects(ob);
                allqueue(REDRAWVIEW3D, 0);
                break;
-       case B_BAKEABLE_CHANGE:
-               allqueue(REDRAWBUTSOBJECT, 0);
-               allqueue(REDRAWVIEW3D, 0);
-               break;
        case B_OBJECT_IPOFLAG:
                if(ob->ipo) ob->ipo->showkey= (ob->ipoflag & OB_DRAWKEY)?1:0;
                allqueue(REDRAWVIEW3D, 0);
                break;
-       case B_CLOTH_CLEARCACHEALL:
-       {
-               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-               if(clmd)
-               {
-                       // do nothing in editmode
-                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
-                               break;
-                       
-                       /* force freeing because user wants */
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
-                       
-                       /*user wants to free all, so free whole cloth, this helps to start sim at later frame */
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-                       
-                       CFRA= 1;
-                       update_for_newframe_muted();
-                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
-                       cloth_clear_cache(ob, clmd, 0); 
-                       allqueue(REDRAWBUTSOBJECT, 0);
-                       allqueue(REDRAWVIEW3D, 0);
-               }       
-       }
-       break;  
-       case B_CLOTH_CLEARCACHEFRAME:
-       {
-               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-               if(clmd)
-               {
-                       // do nothing in editmode
-                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
-                               break;
-                       
-                       /* force freeing because user wants */
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
-                       
-                       cloth_clear_cache(ob, clmd, MAX2(0.0,G.scene->r.cfra)); 
-                       // MAX2(1.0,G.scene->r.cfra + 1.0)
-                       allqueue(REDRAWBUTSOBJECT, 0);
-               }
-       }
-       break;  
        case B_CLOTH_CHANGEPREROLL:
        {
                ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
                if(clmd)
                {
+                       PTCacheID pid;
+
+                       BKE_ptcache_id_from_cloth(&pid, ob, clmd);
+
                        // do nothing in editmode
-                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
+                       if(pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)
                                break;
                        
                        CFRA= 1;
@@ -2442,17 +2471,11 @@ void do_object_panels(unsigned short event)
                }
        }
        break;  
-       case B_CLOTH_RENEW:
+       case B_BAKE_CACHE_CHANGE:
        {
-               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-       
-               if(clmd)
-               {
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
-                       allqueue(REDRAWBUTSOBJECT, 0);
-                       allqueue(REDRAWVIEW3D, 0);
-               }
+               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
+               allqueue(REDRAWBUTSOBJECT, 0);
+               allqueue(REDRAWVIEW3D, 0);
        }
        break;
                
@@ -2833,6 +2856,7 @@ void do_effects_panels(unsigned short event)
        ParticleSystemModifierData *psmd;
        ParticleSystem *psys;
        ParticleSettings *part;
+       LinkNode *node, *firstnode;
        ID *id,*idtest;
        int nr;
        
@@ -3013,6 +3037,8 @@ void do_effects_panels(unsigned short event)
                                short nr=0;
                                if(id==0){ /* no psys previously -> no modifier -> need to create that also */
                                        psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
+                                       psys->pointcache = BKE_ptcache_add();
+                                       psys->flag |= PSYS_ENABLED;
                                        BLI_addtail(&ob->particlesystem,psys);
 
                                        md= modifier_new(eModifierType_ParticleSystem);
@@ -3025,7 +3051,7 @@ void do_effects_panels(unsigned short event)
                                idtest->us++;
                                psys->part=(ParticleSettings*)idtest;
                                psys->totpart=0;
-                               psys->flag=PSYS_ENABLED|PSYS_CURRENT;
+                               psys->flag= PSYS_ENABLED|PSYS_CURRENT;
                                psys->cfra=bsystem_time(ob,G.scene->r.cfra+1,0.0);
 
                                /* check need for dupliobjects */
@@ -3094,6 +3120,27 @@ void do_effects_panels(unsigned short event)
                        }
                }
                break;
+
+       case B_PART_ALLOC:
+       case B_PART_DISTR:
+       case B_PART_INIT:
+       case B_PART_RECALC:
+       case B_PART_ALLOC_CHILD:
+       case B_PART_DISTR_CHILD:
+       case B_PART_INIT_CHILD:
+       case B_PART_RECALC_CHILD:
+               if(psys) {
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+                       allqueue(REDRAWVIEW3D, 0);
+                       allqueue(REDRAWBUTSOBJECT, 0);
+               }
+               break;
+       
+       /* there were separate update events before the pointcache refactor,
+        * now it only does a flush update which means it is recalculating
+        * more than strictly needed, but how to restore such partial updates
+        * i'm not sure - brecht. */
+#if 0
        case B_PART_ALLOC:
        case B_PART_ALLOC_CHILD:
                if(psys){
@@ -3103,6 +3150,7 @@ void do_effects_panels(unsigned short event)
                        allqueue(REDRAWOOPS, 0);
                }
                break;
+
        case B_PART_DISTR:
        case B_PART_DISTR_CHILD:
                if(psys){
@@ -3129,13 +3177,8 @@ void do_effects_panels(unsigned short event)
                        allqueue(REDRAWBUTSEDIT, 0);
                }
                break;
-       case B_PART_RECALC:
-       case B_PART_RECALC_CHILD:
-               if(psys){
-                       psys_flush_settings(psys->part,0,event==B_PART_RECALC);
-                       allqueue(REDRAWOOPS, 0);
-               }
                /* no break! */
+#endif
        case B_PART_REDRAW_DEPS:
                if(event == B_PART_REDRAW_DEPS)
                        DAG_scene_sort(G.scene);
@@ -3155,13 +3198,17 @@ void do_effects_panels(unsigned short event)
                allqueue(REDRAWBUTSOBJECT, 0);
                break;
        case B_PARTTYPE:
-               if((psys=psys_get_current(ob))){
-                       DAG_scene_sort(G.scene);
+               if(psys) {
+                       /* 1 = do DAG_object_flush_update */
+                       firstnode= psys_using_settings(psys->part, 1);
 
-                       psys_flush_settings(psys->part,PSYS_TYPE,1);
+                       for(node=firstnode; node; node=node->next)
+                               psys_changed_type(node->link);
+                       
+                       BLI_linklist_free(firstnode, NULL);
+                       allqueue(REDRAWVIEW3D, 0);
+                       allqueue(REDRAWBUTSOBJECT, 0);
                }
-               allqueue(REDRAWVIEW3D, 0);
-               allqueue(REDRAWBUTSOBJECT, 0);
                break;
        case B_PARTACT:
                allqueue(REDRAWVIEW3D, 0);
@@ -3318,15 +3365,16 @@ static void object_collision__enabletoggle ( void *ob_v, void *arg2 )
 }
 
 /* Panels for particle interaction settings */
-static void object_panel_deflection(Object *ob)
+static void object_panel_collision(Object *ob)
 {
        uiBlock *block;
        uiBut *but;
 
        block= uiNewBlock(&curarea->uiblocks, "object_panel_deflection", UI_EMBOSS, UI_HELV, curarea->win);
-       if(uiNewPanel(curarea, block, "Deflection", "Physics", 0, 0, 318, 204)==0) return;
+       uiNewPanelTabbed("Fields", "Physics");
+       if(uiNewPanel(curarea, block, "Collision", "Physics", 0, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
        
        /* should become button, option? */
        if(ob->pd==NULL) {
@@ -3341,27 +3389,33 @@ static void object_panel_deflection(Object *ob)
        if(ob->pd && ob->type==OB_MESH) {
                PartDeflect *pd= ob->pd;
                
-               but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
+               but = uiDefButBitS(block, TOG, 1, B_REDR, "Collision",10,160,150,20, &pd->deflect, 0, 0, 0, 0, "Enable this objects as a collider for physics systems");
                uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
+
+               uiDefBut(block, LABEL, 0, "",160,160,150,2, NULL, 0.0, 0, 0, 0, "");
                
                if(pd->deflect) {
-                       uiDefBut(block, LABEL, 0, "Particles",                  160,140,75,20, NULL, 0.0, 0, 0, 0, "");
-                       uiDefButBitS(block, TOG, PDEFLE_KILL_PART, B_DIFF, "Kill",235,140,75,20, &pd->flag, 0, 0, 0, 0, "Kill collided particles");
+                       uiDefBut(block, LABEL, 0, "Particle Interaction",                       10,135,310,20, NULL, 0.0, 0, 0, 0, "");
 
                        uiBlockBeginAlign(block);
-                       uiDefButF(block, NUM, B_DIFF, "Damping: ",              160,120,75,20, &pd->pdef_damp, 0.0, 1.0, 10, 0, "Amount of damping during particle collision");
-                       uiDefButF(block, NUM, B_DIFF, "Rnd Damping: ",  235,120,75,20, &pd->pdef_rdamp, 0.0, 1.0, 10, 0, "Random variation of damping");
-                       uiDefButF(block, NUM, B_DIFF, "Friction: ",             160,100,75,20, &pd->pdef_frict, 0.0, 1.0, 10, 0, "Amount of friction during particle collision");
-                       uiDefButF(block, NUM, B_DIFF, "Rnd Friction: ", 235,100,75,20, &pd->pdef_rfrict, 0.0, 1.0, 10, 0, "Random variation of friction");
-                       uiDefButF(block, NUM, B_DIFF, "Permeability: ", 160,80,150,20, &pd->pdef_perm, 0.0, 1.0, 10, 0, "Chance that the particle will pass through the mesh");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping: ",              10,115,105,20, &pd->pdef_damp, 0.0, 1.0, 10, 2, "Amount of damping during particle collision");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Rnd: ",  115,115,75,20, &pd->pdef_rdamp, 0.0, 1.0, 10, 2, "Random variation of damping");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Friction: ",             10,95,105,20, &pd->pdef_frict, 0.0, 1.0, 10, 2, "Amount of friction during particle collision");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Rnd: ",  115,95,75,20, &pd->pdef_rfrict, 0.0, 1.0, 10, 2, "Random variation of friction");
                        uiBlockEndAlign(block);
+
+                       uiDefButBitS(block, TOG, PDEFLE_KILL_PART, B_FIELD_CHANGE, "Kill",200,115,120,20, &pd->flag, 0, 0, 0, 0, "Kill collided particles");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Permeability: ", 200,90,120,20, &pd->pdef_perm, 0.0, 1.0, 10, 2, "Chance that the particle will pass through the mesh");
                        
-                       uiDefBut(block, LABEL, 0, "Soft Body / Cloth",                  160,60,150,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL, 0, "Soft Body and Cloth Interaction",                    10,65,310,20, NULL, 0.0, 0, 0, 0, "");
 
                        uiBlockBeginAlign(block);
-                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:",       160,40,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
-                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 160,20,150,20, &pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
-                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 160, 0,150,20, &pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:",       10,45,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during collision");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 10,25,150,20, &pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
+                       uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 10, 5,150,20, &pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
+                       uiBlockEndAlign(block);
+
+                       uiDefButBitS(block, TOG, OB_SB_COLLFINAL, B_FIELD_CHANGE, "Ev.M.Stack", 170,45,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack (softbody only)");
                }
        }
 }
@@ -3373,10 +3427,9 @@ static void object_panel_fields(Object *ob)
        static short actpsys=-1;
 
        block= uiNewBlock(&curarea->uiblocks, "object_panel_fields", UI_EMBOSS, UI_HELV, curarea->win);
-       uiNewPanelTabbed("Deflection", "Physics");
        if(uiNewPanel(curarea, block, "Fields", "Physics", 0, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
        
        /* should become button, option? */
        if(ob->pd==NULL) {
@@ -3391,6 +3444,8 @@ static void object_panel_fields(Object *ob)
                PartDeflect *pd= ob->pd;
                char *menustr= MEM_mallocN(256, "temp string");
                char *tipstr="Choose field type";
+
+               uiBlockBeginAlign(block);
                
                if(ob->particlesystem.first) {
                        ParticleSystem *psys;
@@ -3443,6 +3498,9 @@ static void object_panel_fields(Object *ob)
                else
                        uiDefButS(block, MENU, B_FIELD_DEP, menustr,                    10,180,140,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr);
 
+               uiBlockEndAlign(block);
+               uiDefBut(block, LABEL, 0, "",160,180,150,2, NULL, 0.0, 0, 0, 0, "");
+
                MEM_freeN(menustr);
                
                if(pd->forcefield) {
@@ -3460,10 +3518,12 @@ static void object_panel_fields(Object *ob)
                                uiDefButF(block, NUM, B_FIELD_CHANGE, "Strength: ",     10,140,140,20, &pd->f_strength, -1000, 1000, 10, 3, "Strength of force field");
                                
                                if(pd->forcefield == PFIELD_TEXTURE){
-                                       uiDefIDPoinBut(block, field_testTexture, ID_TE, B_FIELD_CHANGE, "Texture: ", 10, 120, 140, 20, &pd->tex, "Texture to use as force");
-                                       uiDefButBitS(block, TOG, PFIELD_TEX_OBJECT, B_FIELD_CHANGE, "Use Object Co",    10,100,140,20, &pd->flag, 0.0, 0, 0, 0, "Use object/global coordinates for texture");
-                                       uiDefButBitS(block, TOG, PFIELD_TEX_ROOTCO, B_FIELD_CHANGE, "Root TexCo",       10,80,120,20, &pd->flag, 0.0, 0, 0, 0, "Texture coords from root particle locations");
-                                       uiDefButBitS(block, TOG, PFIELD_TEX_2D, B_FIELD_CHANGE, "2D",   130,80,20,20, &pd->flag, 0.0, 0, 0, 0, "Apply force only in 2d");
+                                       uiDefIDPoinBut(block, field_testTexture, ID_TE, B_FIELD_CHANGE, "Texture: ", 10,120,140,20, &pd->tex, "Texture to use as force");
+                                       uiBlockEndAlign(block);
+                                       uiBlockBeginAlign(block);
+                                       uiDefButBitS(block, TOG, PFIELD_TEX_OBJECT, B_FIELD_CHANGE, "Use Object Co",    10,95,140,20, &pd->flag, 0.0, 0, 0, 0, "Use object/global coordinates for texture");
+                                       uiDefButBitS(block, TOG, PFIELD_TEX_ROOTCO, B_FIELD_CHANGE, "Root TexCo",       10,75,100,20, &pd->flag, 0.0, 0, 0, 0, "Texture coords from root particle locations");
+                                       uiDefButBitS(block, TOG, PFIELD_TEX_2D, B_FIELD_CHANGE, "2D",   120,75,30,20, &pd->flag, 0.0, 0, 0, 0, "Apply force only in 2d");
                                }
                                else if(pd->forcefield == PFIELD_HARMONIC) 
                                        uiDefButF(block, NUM, B_FIELD_CHANGE, "Damp: ", 10,120,140,20, &pd->f_damp, 0, 10, 10, 0, "Damping of the harmonic force");     
@@ -3475,13 +3535,13 @@ static void object_panel_fields(Object *ob)
                                uiDefButBitS(block, TOG, PFIELD_GUIDE_PATH_ADD, B_FIELD_CHANGE, "Additive",     10,40,140,20, &pd->flag, 0.0, 0, 0, 0, "Based on distance/falloff it adds a portion of the entire path");
                        }
                        else if(pd->forcefield==PFIELD_TEXTURE){
-                               uiDefButS(block, MENU, B_FIELD_CHANGE, "Texture mode%t|RGB%x0|Gradient%x1|Curl%x2",     10,40,140,20, &pd->tex_mode, 0.0, 0.0, 0, 0, "How the texture effect is calculated (RGB & Curl need a RGB texture else Gradient will be used instead)");
+                               uiDefButS(block, MENU, B_FIELD_CHANGE, "Texture mode%t|RGB%x0|Gradient%x1|Curl%x2",     10,50,140,20, &pd->tex_mode, 0.0, 0.0, 0, 0, "How the texture effect is calculated (RGB & Curl need a RGB texture else Gradient will be used instead)");
        
-                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Nabla:", 10,20,140,20, &pd->tex_nabla, 0.0001f, 1.0, 1, 0, "Specify the dimension of the area for gradient and curl calculation");
+                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Nabla:", 10,30,140,20, &pd->tex_nabla, 0.0001f, 1.0, 1, 0, "Specify the dimension of the area for gradient and curl calculation");
                        }
                        else if(particles==0 && ELEM(pd->forcefield,PFIELD_VORTEX,PFIELD_WIND)==0){
                                //uiDefButF(block, NUM, B_FIELD_CHANGE, "Distance: ",   10,20,140,20, &pd->f_dist, 0, 1000.0, 10, 0, "Falloff power (real gravitational fallof = 2)");
-                               uiDefButBitS(block, TOG, PFIELD_PLANAR, B_FIELD_CHANGE, "Planar",       10,0,140,20, &pd->flag, 0.0, 0, 0, 0, "Create planar field");
+                               uiDefButBitS(block, TOG, PFIELD_PLANAR, B_FIELD_CHANGE, "Planar",       10,15,140,20, &pd->flag, 0.0, 0, 0, 0, "Create planar field");
                        }
                        uiBlockEndAlign(block);
                        
@@ -3542,30 +3602,159 @@ static void object_panel_fields(Object *ob)
        }
 }
 
+/* Generic physics baking buttons */
+
+static void object_physics__baketoggle(void *pid_v, void *unused_v)
+{
+       PTCacheID *pid = pid_v;
+       Object *ob = pid->ob;
+       PointCache *cache = pid->cache;
+       ClothModifierData *clmd;
+       int cageIndex, stack_index, startframe, endframe;
+
+       // automatically enable modifier in editmode when we have a protected cache
+       if(!(cache->flag & PTCACHE_BAKED)) {
+               BKE_ptcache_id_time(pid, 0.0f, &startframe, &endframe, NULL);
+               pointcache_bake(pid, startframe);
+
+               if(pid->type == PTCACHE_TYPE_CLOTH) {
+                       clmd= (ClothModifierData*)pid->data;
+                       cageIndex = modifiers_getCageIndex(ob, NULL );
+                       stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
+                       if(stack_index >= cageIndex)
+                               ((ModifierData *)clmd)->mode ^= eModifierMode_OnCage;
+               }
+       }
+       else {
+               if(cache->flag & PTCACHE_BAKE_EDIT_ACTIVE) {
+                       notice("Can't free bake in editmode");
+               }
+               else {
+                       if(pid->type == PTCACHE_TYPE_CLOTH) {
+                               clmd= (ClothModifierData*)pid->data;
+                               ((ModifierData *)clmd)->mode ^= eModifierMode_OnCage;
+                       }
+
+                       cache->flag &= ~PTCACHE_BAKED;
+                       BKE_ptcache_id_reset(pid, PTCACHE_RESET_OUTDATED);
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+               }
+       }
+}
+
+static void object_physics__rebake(void *pid_v, void *unused_v)
+{
+       PTCacheID *pid = pid_v;
+       int curframe = (int)G.scene->r.cfra;
+
+       BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, curframe);
+       pointcache_bake(pid, curframe);
+}
+
+static void object_physics__clearcache(void *pid_v, void *unused_v)
+{
+       PTCacheID *pid = pid_v;
+       Object *ob = pid->ob;
+       PointCache *cache = pid->cache;
+
+       if(cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)
+               return;
+
+       BKE_ptcache_id_reset(pid, PTCACHE_RESET_BAKED);
+       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
+
+       allqueue(REDRAWBUTSOBJECT, 0);
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+static void object_physics_bake_buttons(uiBlock *block, PTCacheID *pid, int y, int libdata)
+{
+       uiBut *but;
+       PointCache *cache;
+       
+       cache= pid->cache;
+
+       if(!libdata && G.obedit)
+               uiSetButLock(1, "Can't change bake settings in editmode");
+
+       if(cache->flag & PTCACHE_BAKED)
+               but = uiDefBut(block, BUT, REDRAWBUTSOBJECT, "Free Bake", 10,y+25,85,20, NULL, 0.0, 0.0, 0, 0, "Free baked simulation");
+       else
+               but = uiDefBut(block, BUT, REDRAWBUTSOBJECT, "Bake", 10,y+25,85,20, NULL, 0.0, 0.0, 0, 0, "Bake specified frame range");
+       uiButSetFunc(but, object_physics__baketoggle, pid, NULL);
+
+       if(!libdata && !G.obedit && (cache->flag & PTCACHE_BAKED))
+               uiSetButLock(1, "Simulation frames are baked");
+
+       uiBlockBeginAlign(block);
+       uiDefButI(block, NUM, B_BAKE_CACHE_CHANGE, "Start:", 100,y+25,105,20, &cache->startframe, 1, MAXFRAME, 1, 0, "Frame on which the simulation starts");
+       uiDefButI(block, NUM, B_BAKE_CACHE_CHANGE, "End:", 205,y+25,105,20, &cache->endframe, 1, MAXFRAME, 1, 0, "Frame on which the simulation stops");
+       uiBlockEndAlign(block);
+                       
+       if(cache->flag & PTCACHE_BAKED) {
+               if(pid->type == PTCACHE_TYPE_CLOTH ||
+                  (pid->type == PTCACHE_TYPE_SOFTBODY && !((SoftBody*)pid->data)->particles)) {
+                       if(!libdata && !G.obedit)
+                               uiClearButLock();
+
+                       uiBlockBeginAlign(block);
+                       uiDefButBitI(block, TOG, PTCACHE_BAKE_EDIT, REDRAWVIEW3D, "Bake Editing",       10,y,100,20, &cache->flag, 0, 0, 0, 0, "Enable editing of the baked results in editmode.");
+                       but= uiDefBut(block, BUT, REDRAWBUTSOBJECT, "Rebake From Current Frame", 110,y,200,20, NULL, 0.0, 0.0, 0, 0, "Bake again from current frame");
+                       uiButSetFunc(but, object_physics__rebake, pid, NULL);
+                       uiBlockEndAlign(block);
+               }
+
+               if(!libdata)
+                       uiClearButLock();
+       }
+       else {
+               char str[512];
+               int exist, startframe, endframe;
+
+               if(!libdata)
+                       uiClearButLock();
+               
+               BKE_ptcache_id_time(pid, 0.0f, &startframe, &endframe, NULL);
+               exist= BKE_ptcache_id_exist(pid, startframe);
+
+               sprintf(str, "%simulation frames in disk cache.", (exist)? "S": "No s");
+               uiDefBut(block, LABEL, 0, str, 10,y,200,20, NULL, 0.0, 0, 0, 0, "");
+
+               if(exist) {
+                       but= uiDefBut(block, BUT, REDRAWBUTSOBJECT, "Free Cache", 210,y,100,20, NULL, 0.0, 0.0, 0, 0, "Free cached simulation results");
+                       uiButSetFunc(but, object_physics__clearcache, pid, NULL);
+               }
+       }
+}
+
 /* Panel for softbodies */
 static void object_softbodies__enable(void *ob_v, void *arg2)
 {
        Object *ob = ob_v;
        ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+       PTCacheID pid;
 
-       if (modifiers_isSoftbodyEnabled(ob)) {
-               if (md) {
-                       md->mode &= ~(eModifierMode_Render|eModifierMode_Realtime);
-               }
-       } else {
-               if (!md) {
-                       md = modifier_new(eModifierType_Softbody);
-                       BLI_addhead(&ob->modifiers, md);
-               }
+       if(md) {
+               BLI_remlink(&ob->modifiers, md);
+               modifier_free(md);
+               BIF_undo_push("Del modifier");
 
-               md->mode |= eModifierMode_Render|eModifierMode_Realtime;
+               ob->softflag &= ~OB_SB_ENABLE;
+       } else {
+               md = modifier_new(eModifierType_Softbody);
+               BLI_addhead(&ob->modifiers, md);
 
                if (!ob->soft) {
                        ob->soft= sbNew();
                        ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
-                       softbody_clear_cache(ob, CFRA);
+
+                       BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
+                       BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
                }
+
+               ob->softflag |= OB_SB_ENABLE;
        }
+
        /* needed so that initial state is cached correctly */
        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
 
@@ -3589,7 +3778,7 @@ static void object_softbodies__enable_psys(void *ob_v, void *psys_v)
        ParticleSystem *psys = psys_v;
        Object *ob = ob_v;
 
-       if(psys->softflag & OB_SB_ENABLE){
+       if(psys->softflag & OB_SB_ENABLE) {
                psys->softflag &= ~OB_SB_ENABLE;
        }
        else{
@@ -3597,7 +3786,6 @@ static void object_softbodies__enable_psys(void *ob_v, void *psys_v)
                        psys->soft= sbNew();
                        psys->softflag |= OB_SB_GOAL|OB_SB_EDGES;
                        psys->soft->particles=psys;
-                       clear_particles_from_cache(ob, psys, CFRA);
                }
                psys->softflag |= OB_SB_ENABLE;
        }
@@ -3620,10 +3808,12 @@ static void object_softbodies_collision(Object *ob)
 {
        SoftBody *sb=ob->soft;
        uiBlock *block;
-       uiBut *but = NULL;
        static int val;
        short *softflag=&ob->softflag, psys_cur=0;
        int ob_has_hair=psys_ob_has_hair(ob);
+       static PTCacheID staticpid;
+       int libdata;
+
     if(!_can_softbodies_at_all(ob)) return;
        /*bah that is ugly! creating missing data members in UI code*/
        if(ob->pd == NULL){
@@ -3636,7 +3826,8 @@ static void object_softbodies_collision(Object *ob)
        uiNewPanelTabbed("Soft Body", "Physics"); 
        if(uiNewPanel(curarea, block, "Soft Body Collision", "Physics", 651, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       libdata= object_is_libdata(ob);
+       uiSetButLock(libdata, ERROR_LIBDATA_MESSAGE);
 
        if(ob_has_hair) {
                if(PE_get_current_num(ob) >= 0) {
@@ -3662,64 +3853,43 @@ static void object_softbodies_collision(Object *ob)
                uiDefBut(block, LABEL, 0, "",10,10,1,2, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
                uiBlockBeginAlign(block);
                if(psys_cur){
-                       uiDefBut(block, LABEL, 0, "Hair is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
-                       uiDefBut(block, LABEL, 0, "However the emitter can deflect a softbody",10,170,300,20, NULL, 0.0, 0, 0, 0, ""); 
+                       uiDefBut(block, LABEL, 0, "Hair is not a softbody.",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
                }
                else {
-                       uiDefBut(block, LABEL, 0, "Object is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
-                       uiDefBut(block, LABEL, 0, "However it can deflect a softbody",10,170,300,20, NULL, 0.0, 0, 0, 0, ""); 
-               }
-               /* OTHER OBJECTS COLLISION STUFF */
-               if (ob->type==OB_MESH){
-                       uiBlockBeginAlign(block);
-                       but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to softbody objects");
-                       uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
-                       if(ob->pd->deflect) {
-                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:",       160,50,150,20, &ob->pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
-                               uiDefButBitS(block, TOG,OB_SB_COLLFINAL , B_DIFF, "Ev.M.Stack",10,30,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack");
-                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 160,30,150,20, &ob->pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
-                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 160,10,150,20, &ob->pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
-                       }
+                       uiDefBut(block, LABEL, 0, "Object is not a softbody.",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
                }
                uiBlockEndAlign(block);
        }
        else{
+               BKE_ptcache_id_from_softbody(&staticpid, ob, sb);
+               object_physics_bake_buttons(block, &staticpid, 125, libdata);
+
                /* SELF COLLISION STUFF */
                if ((ob->type==OB_MESH)||(ob->type==OB_CURVE) ) {
                        uiBlockBeginAlign(block);
                        if (*softflag & OB_SB_EDGES){
-                               uiDefButBitS(block, TOG, OB_SB_SELF, B_SOFTBODY_CHANGE, "Self Collision",               10,170,150,20, softflag, 0, 0, 0, 0, "enable naive vertex ball self collision");
+                               uiDefButBitS(block, TOG, OB_SB_SELF, B_BAKE_CACHE_CHANGE, "Self Collision",             10,80,150,20, softflag, 0, 0, 0, 0, "enable naive vertex ball self collision");
                                if(*softflag & OB_SB_SELF){
-                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Ball Size:", 160,170,150,20, &sb->colball, -10.0,  10.0, 10, 0, "Absolute ball size or factor if not manual adjusted");
-                                       uiDefButS(block, ROW, B_DIFF, "Man",10,150,60,20, &sb->sbc_mode, 4.0,SBC_MODE_MANUAL, 0, 0, "Manual adjust");
-                                       uiDefButS(block, ROW, B_DIFF, "Av",70,150,60,20, &sb->sbc_mode, 4.0,SBC_MODE_AVG, 0, 0, "Average Spring lenght * Ball Size");
-                                       uiDefButS(block, ROW, B_DIFF, "Min",130,150,60,20, &sb->sbc_mode, 4.0,SBC_MODE_MIN, 0, 0, "Minimal Spring lenght * Ball Size");
-                                       uiDefButS(block, ROW, B_DIFF, "Max",190,150,60,20, &sb->sbc_mode, 4.0,SBC_MODE_MAX, 0, 0, "Maximal Spring lenght * Ball Size");
-                                       uiDefButS(block, ROW, B_DIFF, "AvMiMa",250,150,60,20, &sb->sbc_mode, 4.0,SBC_MODE_AVGMINMAX, 0, 0, "(Min+Max)/2 * Ball Size");
-                                       uiDefButF(block, NUM, B_DIFF, "B Stiff:", 10,130,150,20, &sb->ballstiff, 0.001,  100.0, 10, 0, "Ball inflating presure");
-                                       uiDefButF(block, NUM, B_DIFF, "B Damp:", 160,130,150,20, &sb->balldamp,  0.001,  1.0, 10, 0, "Blending to inelastic collision");
+                                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Ball Size:", 160,80,150,20, &sb->colball, -10.0,  10.0, 10, 0, "Absolute ball size or factor if not manual adjusted");
+                                       uiDefButS(block, ROW, B_BAKE_CACHE_CHANGE, "Man",10,60,60,20, &sb->sbc_mode, 4.0,SBC_MODE_MANUAL, 0, 0, "Manual adjust");
+                                       uiDefButS(block, ROW, B_BAKE_CACHE_CHANGE, "Av",70,60,60,20, &sb->sbc_mode, 4.0,SBC_MODE_AVG, 0, 0, "Average Spring lenght * Ball Size");
+                                       uiDefButS(block, ROW, B_BAKE_CACHE_CHANGE, "Min",130,60,60,20, &sb->sbc_mode, 4.0,SBC_MODE_MIN, 0, 0, "Minimal Spring lenght * Ball Size");
+                                       uiDefButS(block, ROW, B_BAKE_CACHE_CHANGE, "Max",190,60,60,20, &sb->sbc_mode, 4.0,SBC_MODE_MAX, 0, 0, "Maximal Spring lenght * Ball Size");
+                                       uiDefButS(block, ROW, B_BAKE_CACHE_CHANGE, "AvMiMa",250,60,60,20, &sb->sbc_mode, 4.0,SBC_MODE_AVGMINMAX, 0, 0, "(Min+Max)/2 * Ball Size");
+                                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "B Stiff:", 10,40,150,20, &sb->ballstiff, 0.001,  100.0, 10, 0, "Ball inflating presure");
+                                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "B Damp:", 160,40,150,20, &sb->balldamp,  0.001,  1.0, 10, 0, "Blending to inelastic collision");
                                }
                        }
                        else{
-                               uiDefBut(block, LABEL, 0, "<Self Collision> not available because there",10,170,300,20, NULL, 0.0, 0, 0, 0, ""); 
-                               uiDefBut(block, LABEL, 0, "are no edges, enable <Use Edges>",10,150,300,20, NULL, 0.0, 0, 0, 0, ""); 
+                               uiDefBut(block, LABEL, 0, "<Self Collision> not available because there",10,80,300,20, NULL, 0.0, 0, 0, 0, ""); 
+                               uiDefBut(block, LABEL, 0, "are no edges, enable <Use Edges>",10,60,300,20, NULL, 0.0, 0, 0, 0, ""); 
                        }
 
                        uiBlockEndAlign(block);
                        /*SOLVER SETTINGS*/
                        /* done in another panel now*/
                }
-               /* OTHER OBJECTS COLLISION STUFF */
-               if (ob->type==OB_MESH){
-                       but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to other softbody objects");
-                       uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
-                       if(ob->pd->deflect) {
-                               uiDefButF(block, NUM, B_DIFF, "Damping:",       160,50,150,20, &ob->pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
-                           uiDefButBitS(block, TOG,OB_SB_COLLFINAL , B_DIFF, "Ev.M.Stack",10,30,150,20, softflag, 0, 0, 0, 0, "Pick collision object from modifier stack");
-                               uiDefButF(block, NUM, B_DIFF, "Inner:", 160,30,150,20, &ob->pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
-                               uiDefButF(block, NUM, B_DIFF, "Outer:", 160,10,150,20, &ob->pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
-                       }
-               }
+
                uiDefBut(block, LABEL, 0, "",10,10,1,2, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
        }
        uiBlockEndAlign(block);
@@ -3736,7 +3906,8 @@ static void object_softbodies_solver(Object *ob)
        uiNewPanelTabbed("Soft Body", "Physics"); 
        if(uiNewPanel(curarea, block, "Soft Body Solver", "Physics", 651, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
        /* doubt that is really needed here but for now */ 
        if(ob_has_hair) {
                if(PE_get_current_num(ob) >= 0) {
@@ -3761,10 +3932,10 @@ static void object_softbodies_solver(Object *ob)
        if(!val) { 
                uiDefBut(block, LABEL, 0, "",10,10,1,2, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
                if(psys_cur){
-                       uiDefBut(block, LABEL, 0, "Hair is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
+                       uiDefBut(block, LABEL, 0, "Hair is not a softbody.",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
                }
                else {
-                       uiDefBut(block, LABEL, 0, "Object is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
+                       uiDefBut(block, LABEL, 0, "Object is not a softbody.",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
                }
        }
        else{ 
@@ -3772,7 +3943,7 @@ static void object_softbodies_solver(Object *ob)
                        /*SOLVER SETTINGS*/
                        uiBlockBeginAlign(block);
                        uiDefBut(block, LABEL, 0, "Solver select",10,200,300,20, NULL, 0.0, 0, 0, 0, ""); 
-                       uiDefButS(block, MENU, B_SOFTBODY_CHANGE, sbsolvers,10,180,300,20, &sb->solver_ID, 14.0, 0.0, 0, 0, "Select Solver");
+                       uiDefButS(block, MENU, B_BAKE_CACHE_CHANGE, sbsolvers,10,180,300,20, &sb->solver_ID, 14.0, 0.0, 0, 0, "Select Solver");
                        uiBlockEndAlign(block);
 
                        /*some have adapive step size - some not*/
@@ -3787,31 +3958,31 @@ static void object_softbodies_solver(Object *ob)
                        if(adaptive_mode){
                                uiBlockBeginAlign(block);
                                uiDefBut(block, LABEL, 0, "Step size controls",10,160,300,20, NULL, 0.0, 0, 0, 0, "");
-                               uiDefButF(block, NUM, B_DIFF, "Error Lim:",     10,140,280,20, &sb->rklimit , 0.001, 10.0, 10, 0, "The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed");
-                               uiDefButBitS(block, TOG, SBSO_OLDERR, B_DIFF,"V", 290,140,20,20, &sb->solverflags,  0,  0, 0, 0, "Use velocities for automagic step sizes");
-                               uiDefButS(block, NUM, B_DIFF, "MinS:", 10,120,150,20, &sb->minloops,  0.00,  30000.0, 10, 0, "Minimal # solver steps/frame ");
-                               uiDefButS(block, NUM, B_DIFF, "MaxS:", 160,120,150,20, &sb->maxloops,  0.00,  30000.0, 10, 0, "Maximal # solver steps/frame ");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Error Lim:",        10,140,280,20, &sb->rklimit , 0.001, 10.0, 10, 0, "The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed");
+                               uiDefButBitS(block, TOG, SBSO_OLDERR, B_BAKE_CACHE_CHANGE,"V", 290,140,20,20, &sb->solverflags,  0,  0, 0, 0, "Use velocities for automagic step sizes");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "MinS:", 10,120,150,20, &sb->minloops,  0.00,  30000.0, 10, 0, "Minimal # solver steps/frame ");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "MaxS:", 160,120,150,20, &sb->maxloops,  0.00,  30000.0, 10, 0, "Maximal # solver steps/frame ");
                                uiBlockEndAlign(block);
 
                                uiBlockBeginAlign(block);
                                uiDefBut(block, LABEL, 0, "Collision helpers",10,100,300,20, NULL, 0.0, 0, 0, 0, "");
-                               uiDefButS(block, NUM, B_DIFF, "Choke:", 10,80,150,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
-                               uiDefButS(block, NUM, B_DIFF, "Fuzzy:", 160,80,150,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Choke:", 10,80,150,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Fuzzy:", 160,80,150,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
                                uiBlockEndAlign(block);
 
                                uiBlockBeginAlign(block);
                                uiDefBut(block, LABEL, 0, "Diagnosis",10,60,300,20, NULL, 0.0, 0, 0, 0, "");
-                               uiDefButBitS(block, TOG, SBSO_MONITOR, B_DIFF,"Print Performance to Console", 10,40,300,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");                              
+                               uiDefButBitS(block, TOG, SBSO_MONITOR, B_BAKE_CACHE_CHANGE,"Print Performance to Console", 10,40,300,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");                         
                                uiBlockEndAlign(block);
                        } 
                        else{
                                uiBlockEndAlign(block);
                                uiBlockBeginAlign(block);
-                               uiDefButS(block, NUM, B_DIFF, "Fuzzy:", 210,100,90,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
-                               uiDefButBitS(block, TOG, SBSO_MONITOR, B_DIFF,"M", 290,100,20,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Fuzzy:", 210,100,90,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
+                               uiDefButBitS(block, TOG, SBSO_MONITOR, B_BAKE_CACHE_CHANGE,"M", 290,100,20,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");
                                uiBlockEndAlign(block);
-                               uiDefButS(block, NUM, B_DIFF, "Steps:", 10,80,100,20, &sb->minloops,  1.00,  30000.0, 10, 0, "Solver steps/frame ");
-                               uiDefButS(block, NUM, B_DIFF, "Choke:", 210,80,100,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Steps:", 10,80,100,20, &sb->minloops,  1.00,  30000.0, 10, 0, "Solver steps/frame ");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Choke:", 210,80,100,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
                        }
 
                        uiBlockEndAlign(block);
@@ -3821,22 +3992,13 @@ static void object_softbodies_solver(Object *ob)
        uiBlockEndAlign(block);
 }
 
-static void sb_clear_cache(void *ob_v, void *actsoft_v)
-{
-       Object *ob = ob_v;
-       short *actsoft = actsoft_v;
-
-       if(actsoft)
-               clear_particles_from_cache(ob, BLI_findlink(&ob->particlesystem, *actsoft), CFRA);
-       else
-               softbody_clear_cache(ob, CFRA);
-}
 static void object_softbodies(Object *ob)
 {
        SoftBody *sb=ob->soft;
        ParticleSystem *psys=NULL;
        uiBlock *block;
        uiBut *but;
+       ModifierData *md;
        static int val;
        short *softflag=&ob->softflag, psys_cur=0;
        int ob_has_hair = psys_ob_has_hair(ob);
@@ -3846,12 +4008,11 @@ static void object_softbodies(Object *ob)
        block= uiNewBlock(&curarea->uiblocks, "object_softbodies", UI_EMBOSS, UI_HELV, curarea->win);
        uiNewPanelTabbed("Soft Body", "Physics"); 
        if(uiNewPanel(curarea, block, "Soft Body", "Physics", 640, 0, 318, 204)==0) return;
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
 
        if(ob_has_hair) {
-               char *menustr = psys_menu_string(ob,1);
-
                psys= psys_get_current(ob);
+
                if(psys && actsoft >= 0) {
                        actsoft= psys_get_current_num(ob)+1;
 
@@ -3861,52 +4022,56 @@ static void object_softbodies(Object *ob)
                }
                else
                        actsoft= -1; /* -1 = object */
-
-               but=uiDefButS(block, MENU, B_BAKE_REDRAWEDIT, menustr, 10,200,100,20, &actsoft, 14.0, 0.0, 0, 0, "Browse systems");
-               uiButSetFunc(but, PE_change_act, ob, &actsoft);
-               
-               MEM_freeN(menustr);
        }
 
-       if(psys_cur && psys){
+       if(psys_cur && psys) {
                if(*softflag & OB_SB_ENABLE)
-                       val=1;
+                       val = 1;
                else
-                       val=0;
+                       val = 0;
 
-               but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body",      110,200,70,20, &val, 0, 0, 0, 0, "Sets hair to become soft body");
+               but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body",      10,200,130,20, &val, 0, 0, 0, 0, "Sets hair to become soft body");
                uiButSetFunc(but, object_softbodies__enable_psys, ob, psys);
        }
-       else{
-               val = modifiers_isSoftbodyEnabled(ob);
+       else {
+               md = modifiers_findByType(ob, eModifierType_Softbody);
+               val = (md != NULL);
+
                if(ob_has_hair)
-                       but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body",      110,200,70,20, &val, 0, 0, 0, 0, "Sets object to become soft body");
+                       but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body",      10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become soft body");
                else
                        but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body",      10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become soft body");
 
-
                uiButSetFunc(but, object_softbodies__enable, ob, NULL);
+
+               if(md) {
+                       uiBlockBeginAlign(block);
+                       uiDefIconButBitI(block, TOG, eModifierMode_Render, B_BAKE_CACHE_CHANGE, ICON_SCENE, 145, 200, 20, 20,&md->mode, 0, 0, 1, 0, "Enable soft body during rendering");
+                       but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_BAKE_CACHE_CHANGE, VICON_VIEW3D, 165, 200, 20, 20,&md->mode, 0, 0, 1, 0, "Enable soft body during interactive display");
+                       uiBlockEndAlign(block);
+               }
        }
+
+       if(ob_has_hair) {
+               char *menustr = psys_menu_string(ob,1);
+
+               but=uiDefButS(block, MENU, B_BAKE_REDRAWEDIT, menustr, 210,200,100,20, &actsoft, 14.0, 0.0, 0, 0, "Browse systems");
+               uiButSetFunc(but, PE_change_act, ob, &actsoft);
+               
+               MEM_freeN(menustr);
+       }
+
+
        
        uiDefBut(block, LABEL, 0, "",10,10,300,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
 
-       if(val){
+       if(val) {
                int defCount;
                char *menustr;
                static char str[128];
 
-               //uiDefButBitS(block, TOG, OB_SB_BAKESET, REDRAWBUTSOBJECT, "Bake settings",    180,200,130,20, &ob->softflag, 0, 0, 0, 0, "To convert simulation into baked (cached) result");
-
-               //if(sb->keys) uiSetButLock(1, "Soft Body is baked, free it first");
-               uiBlockBeginAlign(block);
-               uiDefButBitS(block, TOG, OB_SB_PROTECT_CACHE, REDRAWBUTSOBJECT, "Protect",      180,200,50,20, softflag, 0.0, 0.0, 10, 0, "Protect the cache");
-               but=uiDefBut(block, BUT, B_SOFTBODY_CHANGE, "Clear",                            230,200,50,20, NULL, 0.0, 0.0, 10, 0, "Clear the cache");
-               if((*softflag & PSYS_PROTECT_CACHE)==0)
-                       uiButSetFunc(but, sb_clear_cache, ob, &actsoft);
-
-               uiBlockEndAlign(block);
-
-               if(*softflag & OB_SB_PROTECT_CACHE) uiSetButLock(1, "Cache is protected");
+               if(sb->pointcache->flag & PTCACHE_BAKED)
+                       uiSetButLock(1, "Simulation frames are baked");
 
                //if(ob->softflag & OB_SB_BAKESET) {
                //      uiBlockBeginAlign(block);
@@ -3939,66 +4104,66 @@ static void object_softbodies(Object *ob)
                        sprintf(str, "Vertex Mass");
                        }
                        uiBlockBeginAlign(block);
-                       uiDefButF(block, NUM, B_DIFF, "Friction:", 10, 170,150,20, &sb->mediafrict, 0.0, 50.0, 10, 0, "General media friction for point movements");
-                       uiDefButF(block, NUM, B_DIFF, "Mass:",     160, 170,150,20, &sb->nodemass , 0.001, 50000.0, 10, 0, str);
-                       uiDefButF(block, NUM, B_DIFF, "Grav:",     10,150,150,20, &sb->grav , -10.0, 10.0, 10, 0, "Apply gravitation to point movement");
-                       uiDefButF(block, NUM, B_DIFF, "Speed:",    160,150,150,20, &sb->physics_speed , 0.01, 100.0, 10, 0, "Tweak timing for physics to control frequency and speed");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Friction:", 10, 170,150,20, &sb->mediafrict, 0.0, 50.0, 10, 0, "General media friction for point movements");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Mass:",        160, 170,150,20, &sb->nodemass , 0.001, 50000.0, 10, 0, str);
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Grav:",        10,150,150,20, &sb->grav , -10.0, 10.0, 10, 0, "Apply gravitation to point movement");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Speed:",       160,150,150,20, &sb->physics_speed , 0.01, 100.0, 10, 0, "Tweak timing for physics to control frequency and speed");
                        uiBlockEndAlign(block);
 
                        /* GOAL STUFF */
                        uiBlockBeginAlign(block);
-                       uiDefButBitS(block, TOG, OB_SB_GOAL, B_SOFTBODY_CHANGE, "Use Goal",     10,120,130,20, softflag, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
+                       uiDefButBitS(block, TOG, OB_SB_GOAL, B_BAKE_CACHE_CHANGE, "Use Goal",   10,120,130,20, softflag, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
                        if (*softflag & OB_SB_GOAL){
                                if(ob->type==OB_MESH) {
                                        menustr= get_vertexgroup_menustr(ob);
                                        defCount=BLI_countlist(&ob->defbase);
                                        if(defCount==0) sb->vertgroup= 0;
-                                       uiDefButS(block, MENU, B_SOFTBODY_CHANGE, menustr,      140,120,20,20, &sb->vertgroup, 0, defCount, 0, 0, "Browses available vertex groups");
+                                       uiDefButS(block, MENU, B_BAKE_CACHE_CHANGE, menustr,    140,120,20,20, &sb->vertgroup, 0, defCount, 0, 0, "Browses available vertex groups");
                                        MEM_freeN (menustr);
 
                                        if(sb->vertgroup) {
                                                bDeformGroup *defGroup = BLI_findlink(&ob->defbase, sb->vertgroup-1);
                                                if(defGroup)
-                                                       uiDefBut(block, BUT, B_DIFF, defGroup->name,    160,120,130,20, NULL, 0.0, 0.0, 0, 0, "Name of current vertex group");
+                                                       uiDefBut(block, BUT, B_BAKE_CACHE_CHANGE, defGroup->name,       160,120,130,20, NULL, 0.0, 0.0, 0, 0, "Name of current vertex group");
                                                else
-                                                       uiDefBut(block, BUT, B_DIFF, "(no group)",      160,120,130,20, NULL, 0.0, 0.0, 0, 0, "Vertex Group doesn't exist anymore");
+                                                       uiDefBut(block, BUT, B_BAKE_CACHE_CHANGE, "(no group)", 160,120,130,20, NULL, 0.0, 0.0, 0, 0, "Vertex Group doesn't exist anymore");
                                                uiDefIconBut(block, BUT, B_SOFTBODY_DEL_VG, ICON_X, 290,120,20,20, 0, 0, 0, 0, 0, "Disable use of vertex group");
                                        }
                                        else
-                                               uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Goal:",       160,120,150,20, &sb->defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
+                                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Goal:",     160,120,150,20, &sb->defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
                                }
                                else {
-                                       uiDefButS(block, TOG, B_SOFTBODY_CHANGE, "W",                   140,120,20,20, &sb->vertgroup, 0, 1, 0, 0, "Use control point weight values");
-                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Goal:",       160,120,150,20, &sb->defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
+                                       uiDefButS(block, TOG, B_BAKE_CACHE_CHANGE, "W",                 140,120,20,20, &sb->vertgroup, 0, 1, 0, 0, "Use control point weight values");
+                                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Goal:",     160,120,150,20, &sb->defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
                                }
 
-                               uiDefButF(block, NUM, B_DIFF, "G Stiff:",       10,100,150,20, &sb->goalspring, 0.0, 0.999, 10, 0, "Goal (vertex target position) spring stiffness");
-                               uiDefButF(block, NUM, B_DIFF, "G Damp:",        160,100,150,20, &sb->goalfrict  , 0.0, 50.0, 10, 0, "Goal (vertex target position) friction");
-                               uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "G Min:",              10,80,150,20, &sb->mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
-                               uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "G Max:",              160,80,150,20, &sb->maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "G Stiff:",  10,100,150,20, &sb->goalspring, 0.0, 0.999, 10, 0, "Goal (vertex target position) spring stiffness");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "G Damp:",   160,100,150,20, &sb->goalfrict  , 0.0, 50.0, 10, 0, "Goal (vertex target position) friction");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "G Min:",            10,80,150,20, &sb->mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "G Max:",            160,80,150,20, &sb->maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
                        }
                        uiBlockEndAlign(block);
 
                        /* EDGE SPRING STUFF */
                        if(ob->type!=OB_SURF) {
                                uiBlockBeginAlign(block);
-                               uiDefButBitS(block, TOG, OB_SB_EDGES, B_SOFTBODY_CHANGE, "Use Edges",           10,50,90,20, softflag, 0, 0, 0, 0, "Use Edges as springs");
+                               uiDefButBitS(block, TOG, OB_SB_EDGES, B_BAKE_CACHE_CHANGE, "Use Edges",         10,50,90,20, softflag, 0, 0, 0, 0, "Use Edges as springs");
                        if (*softflag & OB_SB_EDGES){
-                               uiDefButBitS(block, TOG, OB_SB_QUADS, B_SOFTBODY_CHANGE, "Stiff Quads",         110,50,90,20, softflag, 0, 0, 0, 0, "Adds diagonal springs on 4-gons");
-                               uiDefButBitS(block, TOG, OB_SB_EDGECOLL, B_DIFF, "CEdge",               220,50,45,20, softflag, 0, 0, 0, 0, "Edge collide too"); 
-                               uiDefButBitS(block, TOG, OB_SB_FACECOLL, B_DIFF, "CFace",               265,50,45,20, softflag, 0, 0, 0, 0, "Faces collide too SLOOOOOW warning "); 
-                               uiDefButF(block, NUM, B_DIFF, "Pull:",  10,30,75,20, &sb->inspring, 0.0,  0.999, 10, 0, "Edge spring stiffness when longer than rest length");
-                               uiDefButF(block, NUM, B_DIFF, "Push:",  85,30,75,20, &sb->inpush, 0.0,  0.999, 10, 0, "Edge spring stiffness when shorter than rest length");
-                               uiDefButF(block, NUM, B_DIFF, "Damp:",  160,30,70,20, &sb->infrict, 0.0,  50.0, 10, 0, "Edge spring friction");
-                           uiDefButS(block, NUM, B_SOFTBODY_CHANGE, "SL:",250 ,30,60,20, &sb->springpreload, 0.0,  200.0, 10, 0, "Alter spring lenght to shrink/blow up (unit %) 0 to disable ");
-                               
-                               uiDefButBitS(block, TOG,OB_SB_AERO_ANGLE,B_SOFTBODY_CHANGE, "N",10,10,20,20, softflag, 0, 0, 0, 0, "New aero(uses angle and length)");
-                               uiDefButS(block, NUM, B_DIFF, "Aero:",     30,10,60,20, &sb->aeroedge,  0.00,  30000.0, 10, 0, "Make edges 'sail'");
-                           uiDefButS(block, NUM, B_SOFTBODY_CHANGE, "Plas:", 90,10,60,20, &sb->plastic, 0.0,  100.0, 10, 0, "Permanent deform");
+                               uiDefButBitS(block, TOG, OB_SB_QUADS, B_BAKE_CACHE_CHANGE, "Stiff Quads",               110,50,90,20, softflag, 0, 0, 0, 0, "Adds diagonal springs on 4-gons");
+                               uiDefButBitS(block, TOG, OB_SB_EDGECOLL, B_BAKE_CACHE_CHANGE, "CEdge",          220,50,45,20, softflag, 0, 0, 0, 0, "Edge collide too"); 
+                               uiDefButBitS(block, TOG, OB_SB_FACECOLL, B_BAKE_CACHE_CHANGE, "CFace",          265,50,45,20, softflag, 0, 0, 0, 0, "Faces collide too SLOOOOOW warning "); 
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Pull:",     10,30,75,20, &sb->inspring, 0.0,  0.999, 10, 0, "Edge spring stiffness when longer than rest length");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Push:",     85,30,75,20, &sb->inpush, 0.0,  0.999, 10, 0, "Edge spring stiffness when shorter than rest length");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Damp:",     160,30,70,20, &sb->infrict, 0.0,  50.0, 10, 0, "Edge spring friction");
+                           uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "SL:",250 ,30,60,20, &sb->springpreload, 0.0,  200.0, 10, 0, "Alter spring lenght to shrink/blow up (unit %) 0 to disable ");
+                               
+                               uiDefButBitS(block, TOG,OB_SB_AERO_ANGLE,B_BAKE_CACHE_CHANGE, "N",10,10,20,20, softflag, 0, 0, 0, 0, "New aero(uses angle and length)");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Aero:",     30,10,60,20, &sb->aeroedge,  0.00,  30000.0, 10, 0, "Make edges 'sail'");
+                           uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Plas:", 90,10,60,20, &sb->plastic, 0.0,  100.0, 10, 0, "Permanent deform");
                                if(ob->type==OB_MESH) {
-                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Be:", 150,10,80,20, &sb->secondspring, 0.0,  10.0, 10, 0, "Bendig Stiffness");
+                                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Be:", 150,10,80,20, &sb->secondspring, 0.0,  10.0, 10, 0, "Bendig Stiffness");
                                        if (*softflag & OB_SB_QUADS){ 
-                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Sh:", 230,10,80,20, &sb->shearstiff, 0.0,  1.0, 10, 0, "Shear Stiffness");
+                                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Sh:", 230,10,80,20, &sb->shearstiff, 0.0,  1.0, 10, 0, "Shear Stiffness");
                                        }
                                }
                                else sb->secondspring = 0;
@@ -4011,6 +4176,28 @@ static void object_softbodies(Object *ob)
        uiBlockEndAlign(block);
 }
 
+static void object_panel_particle_bake(Object *ob)
+{
+       uiBlock *block;
+       ParticleSystem *psys= psys_get_current(ob);
+       static PTCacheID staticpid;
+       int libdata;
+
+       if (psys==NULL || psys->part==NULL) return;
+       if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) return;
+       if (psys->part->phystype == PART_PHYS_KEYED) return;
+       
+       block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_bake", UI_EMBOSS, UI_HELV, curarea->win);
+       uiNewPanelTabbed("Particle System", "Particle");
+       if(uiNewPanel(curarea, block, "Bake", "Particle", 320, 0, 318, 204)==0) return;
+       
+       libdata= object_is_libdata(ob);
+       uiSetButLock(libdata, ERROR_LIBDATA_MESSAGE);
+       
+       BKE_ptcache_id_from_particles(&staticpid, ob, psys);
+       object_physics_bake_buttons(block, &staticpid, 10, libdata);
+}
+
  /* Panels for new particles*/
 static void object_panel_particle_children(Object *ob)
 {
@@ -4025,8 +4212,10 @@ static void object_panel_particle_children(Object *ob)
        if(part==NULL) return;
                
        block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_child", UI_EMBOSS, UI_HELV, curarea->win);
-       if(uiNewPanel(curarea, block, "Children", "Particle", 1300, 0, 318, 204)==0) return;
        uiNewPanelTabbed("Extras", "Particle");
+       if(uiNewPanel(curarea, block, "Children", "Particle", 1300, 0, 318, 204)==0) return;
+
+       uiSetButLock((part->id.lib != NULL), ERROR_LIBDATA_MESSAGE);
 
        if(part->type == PART_FLUID) {
                uiDefBut(block, LABEL, 0, "No settings for fluid particles",                                    butx,(buty-=2*buth),2*butw,buth, NULL, 0.0, 0, 0, 0, "");
@@ -4037,7 +4226,7 @@ static void object_panel_particle_children(Object *ob)
 
        if(part->childtype==0) return;
 
-       if(part->childtype==PART_CHILD_FACES && (psys->flag&(PSYS_HAIR_DONE|PSYS_KEYED))==0) {
+       if(part->childtype==PART_CHILD_FACES && !(part->phystype==PART_PHYS_KEYED || part->type==PART_HAIR)) {
                uiDefBut(block, LABEL, 0, "Hair or keyed",      butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                uiDefBut(block, LABEL, 0, "particles needed!",  butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                return;
@@ -4083,12 +4272,12 @@ static void object_panel_particle_children(Object *ob)
        butx=160;
        buty=180;
 
-       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED))
+       if(part->phystype==PART_PHYS_KEYED || part->type==PART_HAIR)
                uiDefButBitS(block, TOG, 1, B_PART_REDRAW, "Kink/Branch",        butx,(buty-=buth),butw,buth, &kink_ui, 0, 0, 0, 0, "Show kink and branch options");
        else
                buty-=buth;
 
-       if(kink_ui || (psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)) == 0) {
+       if(kink_ui || !(part->phystype==PART_PHYS_KEYED || part->type==PART_HAIR)) {
                buty -= buth/2;
 
                /* kink */
@@ -4106,7 +4295,7 @@ static void object_panel_particle_children(Object *ob)
                }
                uiBlockEndAlign(block);
 
-               if(part->childtype==PART_CHILD_PARTICLES && psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)) {
+               if(part->childtype==PART_CHILD_PARTICLES && (part->phystype==PART_PHYS_KEYED || part->type==PART_HAIR)) {
                        if(part->flag & PART_BRANCHING) {
                                uiDefButBitI(block, TOG, PART_BRANCHING, B_PART_RECALC_CHILD, "Branching",      butx,(buty-=2*buth),butw,buth, &part->flag, 0, 0, 0, 0, "Branch child paths from eachother");
                                uiDefButBitI(block, TOG, PART_ANIM_BRANCHING, B_PART_RECALC_CHILD, "Animated",  butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Animate branching");
@@ -4183,6 +4372,8 @@ static void object_panel_particle_extra(Object *ob)
        block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_extra", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Extras", "Particle", 980, 0, 318, 204)==0) return;
 
+       uiSetButLock((part->id.lib != NULL), ERROR_LIBDATA_MESSAGE);
+
        if(part->type == PART_FLUID) {
                uiDefBut(block, LABEL, 0, "No settings for fluid particles",                                    butx,(buty-=2*buth),2*butw,buth, NULL, 0.0, 0, 0, 0, "");
                return;
@@ -4363,7 +4554,7 @@ static void object_panel_particle_visual(Object *ob)
                        uiDefButF(block, NUM, B_PART_REDRAW, "Front:", butx,(buty-=buth),butw,buth, &part->draw_line[1], 0.0, 10.0, 0, 0, "Length of the line's head");
                        break;
                case PART_DRAW_PATH:
-                       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)) {
+                       if(part->phystype==PART_PHYS_KEYED || part->type==PART_HAIR) {
                                uiDefButS(block, NUM, B_PART_RECALC, "Steps:",  butx,(buty+=buth),butw,buth, &part->draw_step, 0.0, 7.0, 0, 0, "How many steps paths are drawn with (power of 2)");
                                uiDefButS(block, NUM, B_PART_REDRAW, "Render:", butx,(buty-=buth),butw,buth, &part->ren_step, 0.0, 9.0, 0, 0, "How many steps paths are rendered with (power of 2)");
 
@@ -4484,11 +4675,12 @@ static void object_panel_particle_physics(Object *ob)
                return;
        }
 
-       if(ob->id.lib) uiSetButLock(1, "Can't edit library data");
-       
-       if(psys->flag & PSYS_EDITED || psys->flag & PSYS_PROTECT_CACHE) {
-               uiSetButLock(1, "Hair is edited or cache is protected!");
-       }
+       if(ob->id.lib)
+               uiSetButLock(1, "Can't edit library data");
+       else if(psys->flag & PSYS_EDITED)
+               uiSetButLock(1, "Hair is edited!");
+       else if(psys->pointcache->flag & PTCACHE_BAKED)
+               uiSetButLock(1, "Simulation frames are baked!");
 
        if(part->phystype==PART_PHYS_KEYED){
                uiBlockBeginAlign(block);
@@ -4641,10 +4833,6 @@ static void object_panel_particle_physics(Object *ob)
        }
 }
 
-static void psys_clear_cache(void *ob_v, void *psys_v)
-{
-       clear_particles_from_cache((Object *)ob_v, (ParticleSystem *)psys_v, CFRA);
-}
 static void object_panel_particle_system(Object *ob)
 {
        uiBlock *block;
@@ -4652,10 +4840,11 @@ static void object_panel_particle_system(Object *ob)
        ParticleSystem *psys=NULL;
        ParticleSettings *part;
        ID *id, *idfrom;
+       ModifierData *md;
        short butx=0, buty=160, butw=150, buth=20;
-       char str[30];
+       char str[30], *lockmessage= NULL;
        static short partact;
-       short totpart, lock;
+       short totpart, lock= 0;
 
        block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_system", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Particle System", "Particle", 0, 0, 318, 204)==0) return;
@@ -4685,7 +4874,7 @@ static void object_panel_particle_system(Object *ob)
        partact=psys_get_current_num(ob)+1;
        totpart=BLI_countlist(&ob->particlesystem);
        sprintf(str, "%d Part", totpart);
-       but=uiDefButS(block, NUM, B_PARTACT, str, 224,buty,88,buth, &partact, 1.0, totpart+1, 0, 0, "Shows the number of particle systems in the object and the active particle system");
+       but=uiDefButS(block, NUM, B_PARTACT, str, 230,buty,83,buth, &partact, 1.0, totpart+1, 0, 0, "Shows the number of particle systems in the object and the active particle system");
        uiButSetFunc(but, PE_change_act, ob, &partact);
 
        if(psys==NULL)
@@ -4697,38 +4886,43 @@ static void object_panel_particle_system(Object *ob)
                return;
 
        butx=0;
-       buty-=5;
 
        if(part->type == PART_FLUID) {
-               uiDefButBitI(block, TOG, PSYS_ENABLED, B_PART_ENABLE, "Enabled",         0, buty+5, 100,buth, &psys->flag, 0, 0, 0, 0, "Sets particle system to be calculated and shown");
-               uiDefBut(block, LABEL, 0, "No settings for fluid particles",                                    butx,(buty-=2*buth),2*butw,buth, NULL, 0.0, 0, 0, 0, "");
+               uiDefBut(block, LABEL, 0, "No settings for fluid particles",                                    butx,buty,2*butw,buth, NULL, 0.0, 0, 0, 0, "");
                return;
        }
-       else
-               uiDefButBitI(block, TOG, PSYS_ENABLED, B_PART_ENABLE, "Enabled",         0,(buty-=buth),100,buth, &psys->flag, 0, 0, 0, 0, "Sets particle system to be calculated and shown");
+
+       buty -= (buth+5);
 
        if(part->type == PART_HAIR){
                if(psys->flag & PSYS_EDITED)
-                       uiDefBut(block, BUT, B_PART_EDITABLE, "Free Edit",              105,buty,100,buth, NULL, 0.0, 0.0, 10, 0, "Free editing");
+                       uiDefBut(block, BUT, B_PART_EDITABLE, "Free Edit",              butx+butw+10,buty,butw,buth, NULL, 0.0, 0.0, 10, 0, "Free editing");
                else
-                       uiDefBut(block, BUT, B_PART_EDITABLE, "Set Editable",   105,buty,100,buth, NULL, 0.0, 0.0, 10, 0, "Finalize hair to enable editing in particle mode");
+                       uiDefBut(block, BUT, B_PART_EDITABLE, "Set Editable",   butx+butw+10,buty,butw,buth, NULL, 0.0, 0.0, 10, 0, "Finalize hair to enable editing in particle mode");
 
        }
-       else {
-               uiBlockBeginAlign(block);
-               uiDefButBitI(block, TOG, PSYS_PROTECT_CACHE, B_PART_REDRAW, "Protect",          105,buty,50,buth, &psys->flag, 0.0, 0.0, 10, 0, "Protect the cache");
-               but=uiDefBut(block, BUT, B_PART_RECALC, "Clear",                155,buty,50,buth, NULL, 0.0, 0.0, 10, 0, "Clear the cache");
-               if((psys->flag & PSYS_PROTECT_CACHE)==0)
-                       uiButSetFunc(but, psys_clear_cache, ob, &partact);
 
-               uiBlockEndAlign(block);
+       if(psys->flag & PSYS_EDITED) {
+               lockmessage= "Hair is edited!";
+               lock= 1;
+       }
+       else if(psys->pointcache->flag & PTCACHE_BAKED) {
+               lockmessage= "Simulation frames are baked!";
+               lock= 1;
        }
 
-       lock= (psys->flag & PSYS_EDITED || psys->flag & PSYS_PROTECT_CACHE);
        if(lock)
-               uiSetButLock(1, "Hair is edited or cache is protected!");
+               uiSetButLock(1, lockmessage);
+
+       uiDefButS(block, MENU, B_PARTTYPE, "Type%t|Hair%x2|Reactor%x1|Emitter%x0", butx,buty,butw-45,buth, &part->type, 14.0, 0.0, 0, 0, "Type of particle system");
 
-       uiDefButS(block, MENU, B_PARTTYPE, "Type%t|Hair%x2|Reactor%x1|Emitter%x0", 210,buty,100,buth, &part->type, 14.0, 0.0, 0, 0, "Type of particle system");
+       md= (ModifierData*)psys_get_modifier(ob, psys);
+       if(md) {
+               uiBlockBeginAlign(block);
+               uiDefIconButBitI(block, TOG, eModifierMode_Render, B_PART_RECALC, ICON_SCENE, butx+butw-40, buty, 20, 20,&md->mode, 0, 0, 1, 0, "Enable particle system during rendering");
+               but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_PART_RECALC, VICON_VIEW3D, butx+butw-20, buty, 20, 20,&md->mode, 0, 0, 1, 0, "Enable particle system during interactive display");
+               uiBlockEndAlign(block);
+       }
 
        buty-=5;
        uiDefBut(block, LABEL, 0, "Basic:",                                     butx,(buty-=buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
@@ -4775,7 +4969,7 @@ static void object_panel_particle_system(Object *ob)
 
        if(lock) uiClearButLock();
        uiDefButBitI(block, TOG, PART_TRAND, B_PART_DISTR, "Random",    butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Emit in random order of elements");
-       if(lock) uiSetButLock(1, "Hair is edited or cache is protected!");
+       if(lock) uiSetButLock(1, lockmessage);
 
        if(part->type==PART_REACTOR)
                uiDefButS(block, MENU, B_PART_DISTR, "Particle %x3|Volume %x2|Faces %x1|Verts %x0", butx+butw/2,buty,butw/2,buth, &part->from, 14.0, 0.0, 0, 0, "Where to emit particles from");
@@ -4785,7 +4979,7 @@ static void object_panel_particle_system(Object *ob)
        if(ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)) {
                if(lock) uiClearButLock();
                uiDefButBitI(block, TOG, PART_EDISTR, B_PART_DISTR, "Even",butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Use even distribution from faces based on face areas or edge lengths");
-               if(lock) uiSetButLock(1, "Hair is edited or cache is protected!");
+               if(lock) uiSetButLock(1, lockmessage);
                uiDefButS(block, MENU, B_PART_DISTR, "Distribution %t|Grid%x2|Random%x1|Jittered%x0", butx+butw/2,buty,butw/2,buth, &part->distr, 14.0, 0.0, 0, 0, "How to distribute particles on selected element");
                if(part->distr==PART_DISTR_JIT) {
                        uiDefButF(block, NUM, B_PART_DISTR, "Amount:",          butx,(buty-=buth),butw,buth, &part->jitfac, 0, 2.0, 1, 1, "Amount of jitter applied to the sampling");
@@ -4847,9 +5041,9 @@ static void object_panel_fluidsim(Object *ob)
        char *msg = NULL;
        
        block= uiNewBlock(&curarea->uiblocks, "object_fluidsim", UI_EMBOSS, UI_HELV, curarea->win);
-       if(uiNewPanel(curarea, block, "Fluid Simulation", "Physics", 1060, 0, 318, 204)==0) return;
+       if(uiNewPanel(curarea, block, "Fluid", "Physics", 1060, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
        
        if(ob->type==OB_MESH) {
                if(((Mesh *)ob->data)->totvert == 0) {
@@ -5143,10 +5337,10 @@ static void object_panel_fluidsim(Object *ob)
                        return;
 
                } else {
-                       msg = "Object not enabled for fluid simulation...";
+                       msg = "Object not enabled for fluid simulation.";
                }
        } else {
-               msg = "Only Mesh Objects can participate.";
+               msg = "Only mesh objects can do fluid simulation.";
        }
 errMessage:
        yline -= lineHeight + 5;
@@ -5183,7 +5377,7 @@ static void object_cloth__enabletoggle(void *ob_v, void *arg2)
 
                BIF_undo_push("Del modifier");
                
-               ob->softflag |= OB_SB_RESET;
+               //ob->softflag |= OB_SB_RESET;
                allqueue(REDRAWBUTSEDIT, 0);
                allqueue(REDRAWVIEW3D, 0);
                allqueue(REDRAWIMAGE, 0);
@@ -5266,10 +5460,15 @@ static void object_panel_cloth(Object *ob)
        uiBut *but=NULL;
        static int val, val2;
        ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+       PointCache *cache;
+       ModifierData *md;
+       int libdata = 0;
        
        block= uiNewBlock(&curarea->uiblocks, "object_cloth", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Cloth ", "Physics", 640, 0, 318, 204)==0) return;
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+       libdata= object_is_libdata(ob);
+       uiSetButLock(libdata, ERROR_LIBDATA_MESSAGE);
        
        val = (clmd ? 1:0);
        
@@ -5281,6 +5480,14 @@ static void object_panel_cloth(Object *ob)
        {
                but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Cloth",  10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become cloth");
                uiButSetFunc(but, object_cloth__enabletoggle, ob, NULL);
+
+               md = (ModifierData*)clmd;
+               if(md) {
+                       uiBlockBeginAlign(block);
+                       uiDefIconButBitI(block, TOG, eModifierMode_Render, B_BAKE_CACHE_CHANGE, ICON_SCENE, 145, 200, 20, 20,&md->mode, 0, 0, 1, 0, "Enable cloth during rendering");
+                       but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_BAKE_CACHE_CHANGE, VICON_VIEW3D, 165, 200, 20, 20,&md->mode, 0, 0, 1, 0, "Enable cloth during interactive display");
+                       uiBlockEndAlign(block);
+               }
        }
 
        uiDefBut(block, LABEL, 0, "",10,10,300,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
@@ -5292,45 +5499,50 @@ static void object_panel_cloth(Object *ob)
                char clmvg [] = "Vertex Groups%t|";
 
                val2=0;
+               cache= clmd->point_cache;
                
                /* GENERAL STUFF */
-               uiClearButLock();
-               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE) uiSetButLock(1, "Please leave editmode.");
-               else if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) uiSetButLock(1, "Cache is protected");
+               if(!libdata) {
+                       uiClearButLock();
+                       if(cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)
+                               uiSetButLock(1, "Please leave editmode.");
+                       else if(cache->flag & PTCACHE_BAKED)
+                               uiSetButLock(1, "Simulation frames are baked");
+               }
                
                uiDefBut(block, LABEL, 0, "Material Preset:",  10,170,150,20, NULL, 0.0, 0, 0, 0, "");
-               but=uiDefButS(block, MENU, B_CLOTH_RENEW, "Silk %x1|Cotton %x2|Rubber %x3|Denim %x4|Leather %x5|Custom %x0",
+               but=uiDefButS(block, MENU, B_BAKE_CACHE_CHANGE, "Silk %x1|Cotton %x2|Rubber %x3|Denim %x4|Leather %x5|Custom %x0",
                             160,170,150,20, &clmd->sim_parms->presets, 0, 0, 0, 0, "");
                uiButSetFunc(but, cloth_presets_material, ob, NULL);
                
                uiBlockBeginAlign(block);
-               but = uiDefButF(block, NUM, B_CLOTH_RENEW, "StructStiff:", 10,150,150,20, &clmd->sim_parms->structural, 1.0, 10000.0, 100, 0, "Overall stiffness of structure");
+               but = uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "StructStiff:", 10,150,150,20, &clmd->sim_parms->structural, 1.0, 10000.0, 100, 0, "Overall stiffness of structure");
                uiButSetFunc(but, cloth_presets_custom_material, ob, NULL);
                
-               but = uiDefButF(block, NUM, B_CLOTH_RENEW, "BendStiff:", 160,150,150,20, &clmd->sim_parms->bending, 0.0, 10000.0, 1000, 0, "Wrinkle coefficient (higher = less smaller but more big wrinkles)");
+               but = uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "BendStiff:", 160,150,150,20, &clmd->sim_parms->bending, 0.0, 10000.0, 1000, 0, "Wrinkle coefficient (higher = less smaller but more big wrinkles)");
                uiButSetFunc(but, cloth_presets_custom_material, ob, NULL);
                
-               but = uiDefButF(block, NUM, B_CLOTH_RENEW, "Spring Damp:", 10,130,150,20, &clmd->sim_parms->Cdis, 0.0, 50.0, 100, 0, "Damping of cloth velocity (higher = more smooth, less jiggling)");
+               but = uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Spring Damp:", 10,130,150,20, &clmd->sim_parms->Cdis, 0.0, 50.0, 100, 0, "Damping of cloth velocity (higher = more smooth, less jiggling)");
                uiButSetFunc(but, cloth_presets_custom_material, ob, NULL);
 
-               uiDefButF(block, NUM, B_CLOTH_RENEW, "Air Damp:", 160,130,150,20, &clmd->sim_parms->Cvi, 0.0, 10.0, 10, 0, "Air has normaly some thickness which slows falling things down");
+               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Air Damp:", 160,130,150,20, &clmd->sim_parms->Cvi, 0.0, 10.0, 10, 0, "Air has normaly some thickness which slows falling things down");
                
-               uiDefButI(block, NUM, B_CLOTH_RENEW, "Quality:", 10,110,150,20, &clmd->sim_parms->stepsPerFrame, 4.0, 80.0, 5, 0, "Quality of the simulation (higher=better=slower)");
+               uiDefButI(block, NUM, B_BAKE_CACHE_CHANGE, "Quality:", 10,110,150,20, &clmd->sim_parms->stepsPerFrame, 4.0, 80.0, 5, 0, "Quality of the simulation (higher=better=slower)");
                
-               uiDefButF(block, NUM, B_CLOTH_RENEW, "Mass:", 160,110,150,20, &clmd->sim_parms->mass, 0.0, 10.0, 1000, 0, "Mass of cloth material.");
+               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Mass:", 160,110,150,20, &clmd->sim_parms->mass, 0.0, 10.0, 1000, 0, "Mass of cloth material.");
                
                uiDefBut(block, LABEL, 0, "Gravity:",  10,90,60,20, NULL, 0.0, 0, 0, 0, "");
                
-               uiDefButF(block, NUM, B_CLOTH_RENEW, "X:", 70,90,80,20, &clmd->sim_parms->gravity[0], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
-               uiDefButF(block, NUM, B_CLOTH_RENEW, "Y:", 150,90,80,20, &clmd->sim_parms->gravity[1], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
-               uiDefButF(block, NUM, B_CLOTH_RENEW, "Z:", 230,90,80,20, &clmd->sim_parms->gravity[2], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
+               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "X:", 70,90,80,20, &clmd->sim_parms->gravity[0], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
+               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Y:", 150,90,80,20, &clmd->sim_parms->gravity[1], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
+               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Z:", 230,90,80,20, &clmd->sim_parms->gravity[2], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
                uiBlockEndAlign(block);
                
                /* GOAL STUFF */
                uiBlockBeginAlign(block);
                
                
-               uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_GOAL, B_CLOTH_RENEW, "Pinning of cloth",        10,60,150,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
+               uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_GOAL, B_BAKE_CACHE_CHANGE, "Pinning of cloth",  10,60,150,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
                
                if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (BLI_countlist (&ob->defbase) > 0))
                {
@@ -5359,18 +5571,18 @@ static void object_panel_cloth(Object *ob)
                                                        
                                sprintf (clvg2, "%s%s", clmvg, clvg1);
                                
-                               uiDefButS(block, MENU, B_CLOTH_RENEW, clvg2, 160,60,150,20, &clmd->sim_parms->vgroup_mass, 0, defCount, 0, 0, "Browses available vertex groups");
+                               uiDefButS(block, MENU, B_BAKE_CACHE_CHANGE, clvg2, 160,60,150,20, &clmd->sim_parms->vgroup_mass, 0, defCount, 0, 0, "Browses available vertex groups");
                                MEM_freeN (clvg1);
                                MEM_freeN (clvg2);
                        }
                        
-                       uiDefButF(block, NUM, B_CLOTH_RENEW, "Pin Stiff:", 10,40,150,20, &clmd->sim_parms->goalspring, 0.0, 50.0, 50, 0, "Pin (vertex target position) spring stiffness");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Pin Stiff:", 10,40,150,20, &clmd->sim_parms->goalspring, 0.0, 50.0, 50, 0, "Pin (vertex target position) spring stiffness");
                        uiDefBut(block, LABEL, 0, "",160,40,150,20, NULL, 0.0, 0, 0, 0, "");    
-                       // uiDefButI(block, NUM, B_CLOTH_RENEW, "Pin Damp:", 160,50,150,20, &clmd->sim_parms->goalfrict, 1.0, 100.0, 10, 0, "Pined damping (higher = doesn't oszilate so much)");
+                       // uiDefButI(block, NUM, B_BAKE_CACHE_CHANGE, "Pin Damp:", 160,50,150,20, &clmd->sim_parms->goalfrict, 1.0, 100.0, 10, 0, "Pined damping (higher = doesn't oszilate so much)");
                        /*
                        // nobody is changing these ones anyway
-                       uiDefButF(block, NUM, B_CLOTH_RENEW, "G Min:",          10,30,150,20, &clmd->sim_parms->mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
-                       uiDefButF(block, NUM, B_CLOTH_RENEW, "G Max:",          160,30,150,20, &clmd->sim_parms->maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "G Min:",            10,30,150,20, &clmd->sim_parms->mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "G Max:",            160,30,150,20, &clmd->sim_parms->maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
                        */
                }
                else if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL)
@@ -5400,78 +5612,42 @@ static void object_panel_cloth(Object *ob)
        uiBlockEndAlign(block);
 }
 
-static void object_cloth__protecttoggle(void *ob_v, void *arg2)
-{
-       Object *ob = ob_v;
-       int cageIndex, stack_index;
-       ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-       
-       // automatically enable modifier in editmode when we havee a protected cache
-       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)
-       {
-               cageIndex = modifiers_getCageIndex(ob_v, NULL );
-               stack_index = modifiers_indexInObject(ob_v, (ModifierData *)clmd);
-               if( stack_index >= cageIndex )
-                       ((ModifierData *)clmd)->mode ^= eModifierMode_OnCage;
-       }
-       else
-       {
-               ((ModifierData *)clmd)->mode ^= eModifierMode_OnCage;
-       }
-       
-}
-
-
 static void object_panel_cloth_II(Object *ob)
 {
        uiBlock *block;
-       uiBut *but = NULL;
        ClothModifierData *clmd = NULL;
+       PointCache *cache;
+       static PTCacheID staticpid;
+       int libdata;
 
        block= uiNewBlock(&curarea->uiblocks, "object_cloth_II", UI_EMBOSS, UI_HELV, curarea->win);
        uiNewPanelTabbed("Cloth ", "Physics");
-       if(uiNewPanel(curarea, block, "Cloth Cache/Collisions", "Physics", 651, 0, 318, 204)==0) return;
+       if(uiNewPanel(curarea, block, "Cloth Collision", "Physics", 651, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       libdata= object_is_libdata(ob);
+       uiSetButLock(libdata, ERROR_LIBDATA_MESSAGE);
        
        clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
        
        if(clmd)
-       {       
-               uiClearButLock();
-               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE) uiSetButLock(1, "Please leave editmode.");
-               else if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) uiSetButLock(1, "Cache is protected");
-               
-               uiDefButI(block, NUM, B_CLOTH_RENEW, "First Frame:",10,160,150,20, &clmd->sim_parms->firstframe, 0, MAXFRAME, 1, 0, "Frame on which the simulation starts");
-               uiDefButI(block, NUM, B_CLOTH_RENEW, "Last Frame:",160,160,150,20, &clmd->sim_parms->lastframe, 0, MAXFRAME, 1, 0, "Frame on which the simulation stops");
-               
-               uiDefBut(block, LABEL, 0, "",10,140,300,20, NULL, 0.0, 0, 0, 0, "");
-               
-               if(!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE))
-               {
-                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)
-                               uiClearButLock();
-               }
-               
-               if (!G.relbase_valid)
-               {
-                       uiDefBut(block, LABEL, 0, "Cache deactivated until file is saved.",  10,120,300,20, NULL, 0.0, 0, 0, 0, "");
-                       uiDefBut(block, LABEL, 0, " ",  10,100,300,40, NULL, 0.0, 0, 0, 0, "");
-               }
-               else
-               {
-                       but = uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT, REDRAWVIEW3D, "Protect Cache & Enable Cache Editing",     10,120,300,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "Protect cache from automatic freeing when scene changed. This also enabled the cache beeing edited in editmode.");
-                       uiButSetFunc(but, object_cloth__protecttoggle, ob, NULL);
-                       uiDefBut(block, LABEL, 0, "Clear cache:",  10,100,90,20, NULL, 0.0, 0, 0, 0, "");
-                       uiDefBut(block, BUT, B_CLOTH_CLEARCACHEALL, "All", 100, 100,100,20, NULL, 0.0, 0.0, 10, 0, "Free ALL cloth cache without preroll");
-                       uiDefBut(block, BUT, B_CLOTH_CLEARCACHEFRAME, "From next frame", 200, 100,110,20, NULL, 0.0, 0.0, 10, 0, "Free cloth cache starting from next frame");  
-                       uiDefBut(block, LABEL, 0, " ",  10,80,300,20, NULL, 0.0, 0, 0, 0, "");
+       {
+               BKE_ptcache_id_from_cloth(&staticpid, ob, clmd);
+               cache= staticpid.cache;
+
+               if(!libdata) {
+                       uiClearButLock();
+                       if(cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)
+                               uiSetButLock(1, "Please leave editmode.");
                }
-               
-               if(!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE))
-               {
-                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) 
-                               uiSetButLock(1, "Cache is protected");
+
+               object_physics_bake_buttons(block, &staticpid, 135, libdata);
+
+               uiDefBut(block, LABEL, 0, "",10,140,300,20, NULL, 0.0, 0, 0, 0, "");
+
+               if(!libdata) {
+                       if(!(cache->flag & PTCACHE_BAKE_EDIT_ACTIVE))
+                               if(cache->flag & PTCACHE_BAKED)
+                                       uiSetButLock(1, "Simulation frames are baked");
                }
                
                /*
@@ -5482,19 +5658,19 @@ static void object_panel_cloth_II(Object *ob)
                uiDefBut(block, LABEL, 0, " ",  10,80,145,20, NULL, 0.0, 0, 0, 0, "");
                */
 #if WITH_BULLET == 1
-               uiDefButBitI(block, TOG, CLOTH_COLLSETTINGS_FLAG_ENABLED, B_CLOTH_RENEW, "Enable collisions",   10,60,150,20, &clmd->coll_parms->flags, 0, 0, 0, 0, "Enable collisions with this object");
+               uiDefButBitI(block, TOG, CLOTH_COLLSETTINGS_FLAG_ENABLED, B_BAKE_CACHE_CHANGE, "Enable collisions",     10,60,150,20, &clmd->coll_parms->flags, 0, 0, 0, 0, "Enable collisions with this object");
                if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)
                {
-                       uiDefButF(block, NUM, B_CLOTH_RENEW, "Min Distance:",      160,60,150,20, &clmd->coll_parms->epsilon, 0.001f, 1.0, 0.01f, 0, "Minimum distance between collision objects before collision response takes in, can be changed for each frame");
-                       uiDefButS(block, NUM, B_CLOTH_RENEW, "Collision Quality:",         10,40,150,20, &clmd->coll_parms->loop_count, 1.0, 20.0, 1.0, 0, "How many collision iterations should be done. (higher = better = slower)");
-                       uiDefButF(block, NUM, B_CLOTH_RENEW, "Friction:",          160,40,150,20, &clmd->coll_parms->friction, 0.0, 80.0, 1.0, 0, "Friction force if a collision happened (0=movement not changed, 100=no movement left)");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Min Distance:",        160,60,150,20, &clmd->coll_parms->epsilon, 0.001f, 1.0, 0.01f, 0, "Minimum distance between collision objects before collision response takes in, can be changed for each frame");
+                       uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Collision Quality:",           10,40,150,20, &clmd->coll_parms->loop_count, 1.0, 20.0, 1.0, 0, "How many collision iterations should be done. (higher = better = slower)");
+                       uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Friction:",    160,40,150,20, &clmd->coll_parms->friction, 0.0, 80.0, 1.0, 0, "Friction force if a collision happened (0=movement not changed, 100=no movement left)");
                        
-                       uiDefButBitI(block, TOG, CLOTH_COLLSETTINGS_FLAG_SELF, B_CLOTH_RENEW, "Enable selfcollisions",  10,20,150,20, &clmd->coll_parms->flags, 0, 0, 0, 0, "Enable selfcollisions with this object");
+                       uiDefButBitI(block, TOG, CLOTH_COLLSETTINGS_FLAG_SELF, B_BAKE_CACHE_CHANGE, "Enable selfcollisions",    10,20,150,20, &clmd->coll_parms->flags, 0, 0, 0, 0, "Enable selfcollisions with this object");
                        if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)     
                        {
-                               uiDefButF(block, NUM, B_CLOTH_RENEW, "Min Distance:",      160,20,150,20, &clmd->coll_parms->selfepsilon, 0.5f, 1.0, 0.01f, 0, "0.5 means no distance at all, 1.0 is maximum distance");
+                               uiDefButF(block, NUM, B_BAKE_CACHE_CHANGE, "Min Distance:",        160,20,150,20, &clmd->coll_parms->selfepsilon, 0.5f, 1.0, 0.01f, 0, "0.5 means no distance at all, 1.0 is maximum distance");
                                // self_loop_count
-                               uiDefButS(block, NUM, B_CLOTH_RENEW, "Selfcoll Quality:",          10,0,150,20, &clmd->coll_parms->self_loop_count, 1.0, 10.0, 1.0, 0, "How many selfcollision iterations should be done. (higher = better = slower), can be changed for each frame");
+                               uiDefButS(block, NUM, B_BAKE_CACHE_CHANGE, "Selfcoll Quality:",    10,0,150,20, &clmd->coll_parms->self_loop_count, 1.0, 10.0, 1.0, 0, "How many selfcollision iterations should be done. (higher = better = slower), can be changed for each frame");
                        }
                        else
                                uiDefBut(block, LABEL, 0, "",160,20,150,20, NULL, 0.0, 0, 0, 0, "");    
@@ -5514,12 +5690,15 @@ static void object_panel_cloth_III(Object *ob)
 {
        uiBlock *block;
        ClothModifierData *clmd = NULL;
+       PointCache *cache;
+       int libdata;
 
        block= uiNewBlock(&curarea->uiblocks, "object_cloth_III", UI_EMBOSS, UI_HELV, curarea->win);
        uiNewPanelTabbed("Cloth ", "Physics");
        if(uiNewPanel(curarea, block, "Cloth Advanced", "Physics", 651, 0, 318, 204)==0) return;
 
-       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       libdata= object_is_libdata(ob);
+       uiSetButLock(libdata, ERROR_LIBDATA_MESSAGE);
        
        clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
        
@@ -5529,23 +5708,18 @@ static void object_panel_cloth_III(Object *ob)
                char *clvg1, *clvg2;
                char clmvg [] = "Vertex Groups%t|None%x0|";
                char clmvg2 [] = "Vertex Groups%t|None%x0|";
+
<