Pointcache refresh part 1:
authorJanne Karhu <jhkarh@gmail.com>
Sun, 21 Jun 2009 10:16:52 +0000 (10:16 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Sun, 21 Jun 2009 10:16:52 +0000 (10:16 +0000)
* Particles support larger than 1 frame changes, bigger frame changes can result in inaccurate results, but it's super fast and you get a nice feeling of how the particles behave!
* "Cache to current frame" button calculates the exact result of particles at current frame.
* Current state of cache can be protected by making it a bake.
* Cache is now in memory by default, disk cache is an option.
* Only "viewport %" number of particles are calculated and cached in viewport, baking and rendering calculate all particles.
* Info on cached frames and memory usage given in ui.
* Support for exact "autocaching" of changes and large frame changes(disabled for now until exact place in event system is decided)
* "Continue physics" is probably deprecated after this and should be removed once sb & cloth use the new cache code.

Todo:
* Make softbody & cloth use the new cache things.

Other changes:
* Some cleanup of particle buttons.

17 files changed:
release/ui/buttons_particle.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/ED_pointcache.h [new file with mode: 0644]
source/blender/editors/physics/ed_pointcache.c [new file with mode: 0644]
source/blender/editors/space_api/spacetypes.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesdna/DNA_object_force.h
source/blender/makesrna/intern/rna_object_force.c
source/blender/makesrna/intern/rna_particle.c
source/blender/render/intern/source/pipeline.c

index 571cafb709d0727e3ae2a6f616bc396c9dce5085..3970f7069200379a0f3b6decb6c914ea11efe246 100644 (file)
@@ -34,43 +34,8 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
                if psys:
                        split.template_ID(context, psys, "settings")
 
-                       #if ob:
-                       #       split.itemR(ob, "active_particle_system_index", text="Active")
-
-               if psys:
-                       #row = layout.row()
-                       #row.itemL(text="Particle system datablock")
-                       #row.itemL(text="Viewport")
-                       #row.itemL(text="Render")
-                       
-                       part = psys.settings
-                       ptype = psys.settings.type
-                       
-                       if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
-                               layout.itemL(text="No settings for fluid particles")
-                               return
-                       
-                       row = layout.row()
-                       row.enabled = particle_panel_enabled(psys)
-                       row.itemR(part, "type")
-                       row.itemR(psys, "seed")
-                       
-                       row = layout.row()
-                       if part.type=='HAIR':
-                               if psys.editable==True:
-                                       row.itemO("PARTICLE_OT_editable_set", text="Free Edit")
-                               else:
-                                       row.itemO("PARTICLE_OT_editable_set", text="Make Editable")
-                               subrow = row.row()
-                               subrow.enabled = particle_panel_enabled(psys)
-                               subrow.itemR(part, "hair_step")
-                       elif part.type=='REACTOR':
-                               row.itemR(psys, "reactor_target_object")
-                               row.itemR(psys, "reactor_target_particle_system", text="Particle System")
-               
                if psys:
                        #row = layout.row()
-                       #row.itemL(text="Particle system datablock")
                        #row.itemL(text="Viewport")
                        #row.itemL(text="Render")
                        
@@ -80,24 +45,26 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
                        if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
                                layout.itemL(text="No settings for fluid particles")
                                return
+                               
+                       split = layout.split(percentage=0.65)
                        
-                       row = layout.row()
-                       row.enabled = particle_panel_enabled(psys)
-                       row.itemR(part, "type", expand=True)
-                       
+                       split.enabled = particle_panel_enabled(psys)
+                       split.itemR(part, "type")
+                       split.itemR(psys, "seed")
                        
-                       row = layout.row()
+                       split = layout.split(percentage=0.65)
                        if part.type=='HAIR':
                                if psys.editable==True:
-                                       row.itemO("PARTICLE_OT_editable_set", text="Free Edit")
+                                       split.itemO("PARTICLE_OT_editable_set", text="Free Edit")
                                else:
-                                       row.itemO("PARTICLE_OT_editable_set", text="Make Editable")
-                               subrow = row.row()
-                               subrow.enabled = particle_panel_enabled(psys)
-                               subrow.itemR(part, "hair_step")
+                                       split.itemO("PARTICLE_OT_editable_set", text="Make Editable")
+                               row = split.row()
+                               row.enabled = particle_panel_enabled(psys)
+                               row.itemR(part, "hair_step")
                        elif part.type=='REACTOR':
-                               row.itemR(psys, "reactor_target_object")
-                               row.itemR(psys, "reactor_target_particle_system", text="Particle System")
+                               split.enabled = particle_panel_enabled(psys)
+                               split.itemR(psys, "reactor_target_object")
+                               split.itemR(psys, "reactor_target_particle_system", text="Particle System")
                
 class PARTICLE_PT_emission(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_emission"
@@ -112,9 +79,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
                layout.enabled = particle_panel_enabled(psys)
                
                row = layout.row()
-               #col.itemL(text="TODO: Rate instead of amount")
                row.itemR(part, "amount")
-               row.itemR(psys, "seed")
                
                split = layout.split()
                
@@ -150,6 +115,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
 class PARTICLE_PT_cache(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_cache"
        __label__ = "Cache"
+       __default_closed__ = True
        
        def poll(self, context):
                psys = context.particle_system
@@ -163,15 +129,35 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
                part = psys.settings
                cache = psys.point_cache
                
-               #if cache.baked==True:
-                       #layout.itemO("PARTICLE_OT_free_bake", text="BAKE")
-               #else:
                row = layout.row()
-                       #row.itemO("PARTICLE_OT_bake", text="BAKE")
-               row.itemR(cache, "start_frame")
-               row.itemR(cache, "end_frame")
+               row.itemR(cache, "name", text="")
+               if cache.outdated:
+                       row.itemL(text="Cache is outdated.")
+               else:
+                       row.itemL(text="")
+               
+               row = layout.row()
+               
+               if cache.baked == True:
+                       row.itemO("PTCACHE_OT_free_bake_particle_system", text="Free Bake")
+               else:
+                       row.item_booleanO("PTCACHE_OT_cache_particle_system", "bake", True, text="Bake")
                        
-                       #layout.row().itemL(text="No simulation frames in disk cache.")
+               row = layout.row()
+               row.enabled = particle_panel_enabled(psys)
+               row.itemO("PTCACHE_OT_bake_from_particles_cache", text="Current Cache to Bake")
+               if cache.autocache == 0:
+                       row.itemO("PTCACHE_OT_cache_particle_system", text="Cache to Current Frame")
+       
+               row = layout.row()
+               row.enabled = particle_panel_enabled(psys)
+               #row.itemR(cache, "autocache")
+               row.itemR(cache, "disk_cache")
+               row.itemL(text=cache.info)
+               
+               # for particles these are figured out automatically
+               #row.itemR(cache, "start_frame")
+               #row.itemR(cache, "end_frame")
 
 class PARTICLE_PT_initial(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_initial"
@@ -184,8 +170,6 @@ class PARTICLE_PT_initial(ParticleButtonsPanel):
                part = psys.settings
                
                layout.enabled = particle_panel_enabled(psys)
-               
-               #layout.row().itemL(text="")
                                
                layout.row().itemL(text="Direction:")
        
@@ -362,27 +346,14 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
                        row = layout.row()
                        col = row.column()
                        
-                       
-#                      subrow = col.row()
-#                      subrow.active = part.render_strand == False
-#                      subrow.itemR(part, "render_adaptive")
-#                      col = row.column(align=True)
-#                      subrow = col.row()
-#                      subrow.active = part.render_adaptive or part.render_strand == True
-#                      subrow.itemR(part, "adaptive_angle")
-#                      subrow = col.row()
-#                      subrow.active = part.render_adaptive == True and part.render_strand == False
-#                      subrow.itemR(part, "adaptive_pix")
-                       
                        if part.type=='HAIR' and part.render_strand==True and part.child_type=='FACES':
                                layout.itemR(part, "enable_simplify")
                                if part.enable_simplify==True:
-                                       box = layout.box()
-                                       row = box.row()
+                                       row = layout.row()
                                        row.itemR(part, "simplify_refsize")
                                        row.itemR(part, "simplify_rate")
                                        row.itemR(part, "simplify_transition")
-                                       row = box.row()
+                                       row = layout.row()
                                        row.itemR(part, "viewport")
                                        subrow = row.row()
                                        subrow.active = part.viewport==True
@@ -438,6 +409,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
 class PARTICLE_PT_draw(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_draw"
        __label__ = "Display"
+       __default_closed__ = True
        
        def poll(self, context):
                return (context.particle_system != None)
@@ -490,6 +462,7 @@ class PARTICLE_PT_draw(ParticleButtonsPanel):
 class PARTICLE_PT_children(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_children"
        __label__ = "Children"
+       __default_closed__ = True
 
        def draw(self, context):
                layout = self.layout
@@ -557,6 +530,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel):
 class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_vertexgroups"
        __label__ = "Vertexgroups"
+       __default_closed__ = True
 
        def draw(self, context):
                layout = self.layout
index 4efd9a7f8baf5dddeebecdb394a2bc6189b212ab..0ecd71fc4a311676763835b67ef6b70ab01a12a7 100644 (file)
@@ -217,6 +217,7 @@ char *psys_menu_string(struct Object *ob, int for_sb);
 
 struct ParticleSystem *psys_get_current(struct Object *ob);
 short psys_get_current_num(struct Object *ob);
+struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
 //struct ParticleSystem *psys_get(struct Object *ob, int index);
 struct ParticleData *psys_get_selected_particle(struct ParticleSystem *psys, int *index);
 struct ParticleKey *psys_get_selected_key(struct ParticleSystem *psys, int pa_index, int *key_index);
@@ -251,6 +252,7 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P
 
 struct ParticleSettings *psys_new_settings(char *name, struct Main *main);
 struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part);
+int psys_count_autocache(struct Scene *scene, struct ParticleSettings *part);
 void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *part, int recalc);
 void make_local_particlesettings(struct ParticleSettings *part);
 
@@ -290,10 +292,13 @@ void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, str
 void psys_init_effectors(struct Scene *scene, struct Object *obsrc, struct Group *group, struct ParticleSystem *psys);
 void psys_end_effectors(struct ParticleSystem *psys);
 
+void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra);
+
 void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
 
 /* ----------- functions needed only inside particlesystem ------------ */
 /* particle.c */
+void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, int velocity);
 void psys_key_to_object(struct Object *ob, struct ParticleKey *key, float imat[][4]);
 //void psys_key_to_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key);
 //void psys_key_from_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key);
index 8ef3ff4d4b7190a26a163f73584803498b6ac714..b79357edf36953b8842145db8661d21db849f901 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "DNA_ID.h"
 
+#include "MEM_guardedalloc.h"
+
 /* 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
@@ -42,6 +44,7 @@
 #define PTCACHE_RESET_DEPSGRAPH                0
 #define PTCACHE_RESET_BAKED                    1
 #define PTCACHE_RESET_OUTDATED         2
+#define PTCACHE_RESET_FREE                     3
 
 /* Add the blendfile name after blendcache_ */
 #define PTCACHE_EXT ".bphys"
 #define PTCACHE_TYPE_PARTICLES 1
 #define PTCACHE_TYPE_CLOTH             2
 
+/* PTCache read return code */
+#define PTCACHE_READ_EXACT                             1
+#define PTCACHE_READ_INTERPOLATED              2
+#define PTCACHE_READ_OLD                               3
+
 /* Structs */
 struct Object;
 struct Scene;
@@ -80,6 +88,41 @@ typedef struct PTCacheID {
        struct PointCache *cache;
 } PTCacheID;
 
+typedef struct PTCacheWriter {
+       struct PTCacheID *pid;
+       int cfra;
+       int totelem;
+
+       float *(*elem_ptr)(int index, void *calldata);
+       void *calldata;
+} PTCacheWriter;
+
+typedef struct PTCacheReader {
+       struct Scene *scene;
+       struct PTCacheID *pid;
+       float cfra;
+       int totelem;
+
+       void (*set_elem)(int index, void *calldata, float *data);
+       void (*interpolate_elem)(int index, void *calldata, float frs_sec, float cfra, int cfra1, int cfra2, float *data1, float *data2);
+       void *calldata;
+
+       int allow_interpolate;
+       int allow_old;
+       int *old_frame;
+} PTCacheReader;
+
+typedef struct PTCacheBaker {
+       struct Scene *scene;
+       int bake;
+       int render;
+       struct PTCacheID *pid;
+       int (*break_test)(void *data);
+       void *break_data;
+       void (*progressbar)(void *data, int num);
+       void *progresscontext;
+} PTCacheBaker;
+
 /* 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);
@@ -93,9 +136,9 @@ void BKE_ptcache_remove(void);
 /* 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);
+int            BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode);
 void   BKE_ptcache_id_time(PTCacheID *pid, struct Scene *scene, float cfra, int *startframe, int *endframe, float *timescale);
-int            BKE_ptcache_object_reset(struct Object *ob, int mode);
+int            BKE_ptcache_object_reset(struct Scene *scene, struct Object *ob, int mode);
 
 /* File reading/writing */
 PTCacheFile    *BKE_ptcache_file_open(PTCacheID *id, int mode, int cfra);
@@ -103,6 +146,10 @@ 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);
 
+/* General cache reading/writing */
+int                     BKE_ptcache_read_cache(PTCacheReader *reader);
+int                     BKE_ptcache_write_cache(PTCacheWriter *writer);
+
 /* Continue physics */
 void BKE_ptcache_set_continue_physics(struct Scene *scene, int enable);
 int BKE_ptcache_get_continue_physics(void);
@@ -112,4 +159,9 @@ struct PointCache *BKE_ptcache_add(void);
 void BKE_ptcache_free(struct PointCache *cache);
 struct PointCache *BKE_ptcache_copy(struct PointCache *cache);
 
+/* Baking */
+void BKE_ptcache_autocache_all(struct Scene *scene);
+void BKE_ptcache_make_cache(struct PTCacheBaker* baker);
+void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
+
 #endif
index 8bb34bde12210802cad4ec89d84844e49281e232..b57b8b7a6da1878d0d371007dd8898f790e94d9b 100644 (file)
@@ -1831,7 +1831,7 @@ static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime)
 }
 
 /* node was checked to have lasttime != curtime , and is of type ID_OB */
-static void flush_pointcache_reset(DagNode *node, int curtime, int reset)
+static void flush_pointcache_reset(Scene *scene, DagNode *node, int curtime, int reset)
 {
        DagAdjList *itA;
        Object *ob;
@@ -1844,13 +1844,13 @@ static void flush_pointcache_reset(DagNode *node, int curtime, int reset)
                                ob= (Object*)(node->ob);
 
                                if(reset || (ob->recalc & OB_RECALC)) {
-                                       if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH))
+                                       if(BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH))
                                                ob->recalc |= OB_RECALC_DATA;
 
-                                       flush_pointcache_reset(itA->node, curtime, 1);
+                                       flush_pointcache_reset(scene, itA->node, curtime, 1);
                                }
                                else
-                                       flush_pointcache_reset(itA->node, curtime, 0);
+                                       flush_pointcache_reset(scene, itA->node, curtime, 0);
                        }
                }
        }
@@ -1908,13 +1908,13 @@ void DAG_scene_flush_update(Scene *sce, unsigned int lay, int time)
                                ob= (Object*)(itA->node->ob);
 
                                if(ob->recalc & OB_RECALC) {
-                                       if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH))
+                                       if(BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH))
                                                ob->recalc |= OB_RECALC_DATA;
 
-                                       flush_pointcache_reset(itA->node, lasttime, 1);
+                                       flush_pointcache_reset(sce, itA->node, lasttime, 1);
                                }
                                else
-                                       flush_pointcache_reset(itA->node, lasttime, 0);
+                                       flush_pointcache_reset(sce, itA->node, lasttime, 0);
                        }
                }
        }
@@ -2132,7 +2132,7 @@ 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);
+       BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH);
        
        /* all users of this ob->data should be checked */
        /* BUT! displists for curves are still only on cu */
@@ -2147,7 +2147,7 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag)
                                        for (obt=G.main->object.first; obt; obt= obt->id.next) {
                                                if (obt != ob && obt->data==ob->data) {
                                                        obt->recalc |= OB_RECALC_DATA;
-                                                       BKE_ptcache_object_reset(obt, PTCACHE_RESET_DEPSGRAPH);
+                                                       BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
                                                }
                                        }
                                }
index 34e69b2d736a54a8314194beb90c22fd190ec6bf..5b3720cd6b01879c5bc78b4d863d0954cec870da 100644 (file)
@@ -222,6 +222,45 @@ short psys_get_current_num(Object *ob)
        
        return i;
 }
+Object *psys_find_object(Scene *scene, ParticleSystem *psys)
+{
+       Base *base = scene->base.first;
+       ParticleSystem *tpsys;
+
+       for(base = scene->base.first; base; base = base->next) {
+               for(tpsys = base->object->particlesystem.first; psys; psys=psys->next) {
+                       if(tpsys == psys)
+                               return base->object;
+               }
+       }
+
+       return NULL;
+}
+int psys_count_autocache(Scene *scene, ParticleSettings *part)
+{
+       Base *base = scene->base.first;
+       ParticleSystem *psys;
+       PTCacheID pid;
+       int autocache_count= 0;
+
+       for(base = scene->base.first; base; base = base->next) {
+               for(psys = base->object->particlesystem.first; psys; psys=psys->next) {
+                       if(part && psys->part != part)
+                               continue;
+
+                       BKE_ptcache_id_from_particles(&pid, base->object, psys);
+
+                       if((psys->pointcache->flag & PTCACHE_BAKED)
+                               || (psys->pointcache->flag & PTCACHE_AUTOCACHE)==0)
+                               continue;
+
+                       if((psys->pointcache->flag & PTCACHE_OUTDATED)
+                               || BKE_ptcache_id_exist(&pid, CFRA)==0)
+                               autocache_count++;
+               }
+       }
+       return autocache_count;
+}
 /* change object's active particle system */
 void psys_change_act(void *ob_v, void *act_v)
 {
@@ -864,7 +903,7 @@ static void weighted_particle_vector(float *v1, float *v2, float *v3, float *v4,
        vec[1]= weights[0]*v1[1] + weights[1]*v2[1] + weights[2]*v3[1] + weights[3]*v4[1];
        vec[2]= weights[0]*v1[2] + weights[1]*v2[2] + weights[2]*v3[2] + weights[3]*v4[2];
 }
-static void interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result, int velocity)
+void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result, int velocity)
 {
        float t[4];
 
@@ -2569,7 +2608,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
                        }
 
                        /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/
-                       interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
+                       psys_interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
                                : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
                                ,keys, keytime, &result, 0);
 
@@ -3062,7 +3101,6 @@ void make_local_particlesettings(ParticleSettings *part)
                }
        }
 }
-
 void psys_flush_particle_settings(Scene *scene, ParticleSettings *part, int recalc)
 {
        Base *base = scene->base.first;
@@ -3495,7 +3533,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
                        QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime);
                }
 
-               interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
+               psys_interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
                        : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
                        ,keys, keytime, state, 1);
 
@@ -3776,7 +3814,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy
                                                        VecMulf(keys[1].vel, dfra / frs_sec);
                                                        VecMulf(keys[2].vel, dfra / frs_sec);
                                                        
-                                                       interpolate_particle(-1, keys, keytime, state, 1);
+                                                       psys_interpolate_particle(-1, keys, keytime, state, 1);
                                                        
                                                        /* convert back to real velocity */
                                                        VecMulf(state->vel, frs_sec / dfra);
index 52f13eeadb8fda45a79bf269bfba12ebe3876087..fc6413849d11b05ba00f92fd0f01481694ee89e9 100644 (file)
@@ -104,7 +104,8 @@ static int get_current_display_percentage(ParticleSystem *psys)
 {
        ParticleSettings *part=psys->part;
 
-       if(psys->renderdata || (part->child_nbr && part->childtype)) 
+       if(psys->renderdata || (part->child_nbr && part->childtype)
+               || (psys->pointcache->flag & PTCACHE_BAKING))
                return 100;
 
        if(part->phystype==PART_PHYS_KEYED){
@@ -2195,57 +2196,80 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o
 /************************************************/
 /*                     Point Cache                                                     */
 /************************************************/
-
-static void write_particles_to_cache(Object *ob, ParticleSystem *psys, int cfra)
+void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
 {
-       PTCacheID pid;
-       PTCacheFile *pf;
-       ParticleData *pa;
-       int i, totpart= psys->totpart;
+       ParticleSettings *part = psys->part;
 
-       if(totpart == 0)
-               return;
+       *sfra = MAX2(1, (int)part->sta);
+       *efra = MIN2((int)(part->end + part->lifetime + 1.0), scene->r.efra);
+}
+static float *particle_state_ptr(int index, ParticleSystem *psys)
+{
+       return (float *)(&(psys->particles+index)->state);
+}
+static void particle_read_state(int index, ParticleSystem *psys, float *data)
+{
+       ParticleData *pa = psys->particles + index;
+       ParticleKey *key = (ParticleKey *)data;
 
-       BKE_ptcache_id_from_particles(&pid, ob, psys);
-       pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, cfra);
-       if(!pf)
-               return;
+       if(key->time > pa->state.time)
+               copy_particle_key(&pa->prev_state, &pa->state, 1);
 
-       /* assuming struct consists of tightly packed floats */
-       for(i=0, pa=psys->particles; i<totpart; i++, pa++)
-               BKE_ptcache_file_write_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float));
-       
-       BKE_ptcache_file_close(pf);
+       copy_particle_key(&pa->state, key, 1);
 }
+static void particle_cache_interpolate(int index, ParticleSystem *psys, float frs_sec, float cfra, int cfra1, int cfra2, float *data1, float *data2)
+{
+       ParticleData *pa = psys->particles + index;
+       ParticleKey keys[4];
+       float dfra;
+
+       keys[1] = *((ParticleKey*)data1);
+       keys[2] = *((ParticleKey*)data2);
+
+       dfra = keys[2].time - keys[1].time;
 
-static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra)
+       VecMulf(keys[1].vel, dfra / frs_sec);
+       VecMulf(keys[2].vel, dfra / frs_sec);
+
+       psys_interpolate_particle(-1, keys, (keys[1].time - cfra) / dfra, &pa->state, 1);
+
+       VecMulf(pa->state.vel, frs_sec / dfra);
+}
+static void write_particles_to_cache(Object *ob, ParticleSystem *psys, int cfra)
 {
+       PTCacheWriter writer;
        PTCacheID pid;
-       PTCacheFile *pf;
-       ParticleData *pa;
-       int i, totpart= psys->totpart;
-
-       if(totpart == 0)
-               return 0;
 
        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(cfra!=pa->state.time)
-                       copy_particle_key(&pa->prev_state,&pa->state,1);
-               if(!BKE_ptcache_file_read_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float))) {
-                       BKE_ptcache_file_close(pf);
-                       return 0;
-               }
-       }
+       writer.calldata = psys;
+       writer.cfra = cfra;
+       writer.elem_ptr = particle_state_ptr;
+       writer.pid = &pid;
+       writer.totelem = psys->totpart;
 
-       BKE_ptcache_file_close(pf);
+       BKE_ptcache_write_cache(&writer);
+}
 
-       return 1;
+static int get_particles_from_cache(Scene *scene, Object *ob, ParticleSystem *psys, float cfra, int allow_interpolate, int allow_old, int *old_frame)
+{
+       PTCacheReader reader;
+       PTCacheID pid;
+       
+       BKE_ptcache_id_from_particles(&pid, ob, psys);
+
+       reader.allow_interpolate = allow_interpolate;
+       reader.allow_old = allow_old;
+       reader.calldata = psys;
+       reader.cfra = cfra;
+       reader.interpolate_elem = particle_cache_interpolate;
+       reader.old_frame = old_frame;
+       reader.pid = &pid;
+       reader.scene = scene;
+       reader.set_elem = particle_read_state;
+       reader.totelem = psys->totpart;
+
+       return BKE_ptcache_read_cache(&reader);
 }
 
 /************************************************/
@@ -4085,7 +4109,7 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
 
                /* main loop: calculate physics for all particles */
                for(p=0, pa=psys->particles; p<totpart; p++,pa++){
-                       if(pa->flag & PARS_UNEXIST) continue;
+                       if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
 
                        copy_particle_key(&pa->prev_state,&pa->state,1);
                        
@@ -4110,25 +4134,26 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
                        if(pa->alive==PARS_UNBORN
                                || pa->alive==PARS_KILLED
                                || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)
-                               || birthtime >= cfra){
+                               || birthtime >= psys->cfra){
                                reset_particle(scene, pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot);
                        }
 
                        pa_dfra = dfra;
                        pa_dtime = dtime;
 
-                       if(birthtime <= cfra && birthtime >= psys->cfra){
+
+                       if(dietime <= cfra && psys->cfra < dietime){
+                               /* particle dies some time between this and last step */
+                               pa_dfra = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra);
+                               pa_dtime = pa_dfra * timestep;
+                               pa->alive = PARS_DYING;
+                       }
+                       else if(birthtime <= cfra && birthtime >= psys->cfra){
                                /* particle is born some time between this and last step*/
                                pa->alive = PARS_ALIVE;
                                pa_dfra = cfra - birthtime;
                                pa_dtime = pa_dfra*timestep;
                        }
-                       else if(dietime <= cfra && psys->cfra < dietime){
-                               /* particle dies some time between this and last step */
-                               pa_dfra = dietime - psys->cfra;
-                               pa_dtime = pa_dfra * timestep;
-                               pa->alive = PARS_DYING;
-                       }
                        else if(dietime < cfra){
                                /* nothing to be done when particle is dead */
                        }
@@ -4520,7 +4545,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
        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, only_children_changed= 0;
-       int framenr, framedelta, startframe, endframe;
+       int framenr, framedelta, startframe, endframe, old_framenr;
 
        part= psys->part;
        cache= psys->pointcache;
@@ -4528,6 +4553,10 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
        framenr= (int)scene->r.cfra;
        framedelta= framenr - cache->simframe;
 
+       /* set suitable cache range automatically */
+       if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0)
+               psys_get_pointcache_start_end(scene, psys, &cache->startframe, &cache->endframe);
+
        BKE_ptcache_id_from_particles(&pid, ob, psys);
        BKE_ptcache_id_time(&pid, scene, 0.0f, &startframe, &endframe, NULL);
 
@@ -4600,9 +4629,13 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
 
        if(init) {
                if(distr) {
-                       if(alloc)
+                       if(alloc) {
                                realloc_particles(ob, psys, totpart);
 
+                               if(usecache)
+                                       BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
+                       }
+
                        distribute_particles(scene, ob, psys, part->from);
 
                        if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE))
@@ -4616,9 +4649,11 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
                        free_keyed_keys(psys);
 
                        initialize_all_particles(ob, psys, psmd);
+                       
 
-                       if(alloc)
+                       if(alloc) {
                                reset_all_particles(scene, ob, psys, psmd, 0.0, cfra, oldtotpart);
+                       }
                }
 
                /* flag for possible explode modifiers after this system */
@@ -4627,25 +4662,47 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
 
        /* 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(scene, ob, psys);
-                       }
+               int result = get_particles_from_cache(scene, ob, psys, (float)framenr, 0, 1, &old_framenr);
+
+               if(result == PTCACHE_READ_EXACT) {
+                       //if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) {
+                       //      psys_count_keyed_targets(ob,psys);
+                       //      set_keyed_keys(scene, ob, psys);
+                       //}
 
                        cached_step(scene, 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(scene, ob, psmd, psys, framenr);
-                       }
+                       //if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) {
+                       //      psys_update_path_cache(scene, ob, psmd, psys, framenr);
+                       //}
 
                        cache->simframe= framenr;
                        cache->flag |= PTCACHE_SIMULATION_VALID;
 
+                       if(cache->flag & PTCACHE_OUTDATED)
+                               BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_FREE);
+
                        return;
                }
+               else if((cache->flag & PTCACHE_AUTOCACHE)==0 && result==PTCACHE_READ_OLD) {
+                       /* clear cache after current frame */
+                       BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_FREE);
+
+                       /* set old cfra */
+                       psys->cfra = (float)old_framenr;
+
+                       for(p=0, pa=psys->particles; p<totpart; p++, pa++) {
+                               /* update alive status */
+                               if(pa->time > psys->cfra)
+                                       pa->alive = PARS_UNBORN;
+                               else if(pa->dietime <= psys->cfra)
+                                       pa->alive = PARS_DEAD;
+                               else
+                                       pa->alive = PARS_ALIVE;
+                       }
+               }
                else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) {
                        psys_reset(psys, PSYS_RESET_CACHE_MISS);
                        psys->cfra=cfra;
@@ -4653,8 +4710,10 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
                        return;
                }
 
-               if(framenr != startframe && framedelta != 1) {
-                       psys_reset(psys, PSYS_RESET_CACHE_MISS);
+               if(framenr != startframe && framedelta != 1 && cache->flag & PTCACHE_AUTOCACHE) {
+                       //psys_reset(psys, PSYS_RESET_CACHE_MISS);
+                       /* make sure cache is recalculated */
+                       BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_FRAME, (int)cfra);
                        psys->cfra = cfra;
                        psys->recalc = 0;
                        return;
@@ -4663,10 +4722,11 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
        else {
                cache->flag &= ~PTCACHE_SIMULATION_VALID;
                cache->simframe= 0;
+               cache->last_exact= 0;
        }
 
        /* if on second frame, write cache for first frame */
-       if(usecache && framenr == startframe+1)
+       if(usecache && psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
                write_particles_to_cache(ob, psys, startframe);
 
        if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED)
@@ -4768,8 +4828,7 @@ static void psys_to_softbody(Scene *scene, Object *ob, ParticleSystem *psys)
 static int hair_needs_recalc(ParticleSystem *psys)
 {
        if((psys->flag & PSYS_EDITED)==0 &&
-               ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_REDO)) {
-               psys->recalc &= ~PSYS_RECALC_REDO;
+               ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET)) {
                return 1;
        }
 
index b00755f7135bfeac50ef7ca60470e4a5c207d89f..f59336518d7711693907a350581eb7dae0e373e2 100644 (file)
 #include "BKE_object.h"
 #include "BKE_particle.h"
 #include "BKE_pointcache.h"
+#include "BKE_scene.h"
 #include "BKE_softbody.h"
 #include "BKE_utildefines.h"
 
+#include "BLI_blenlib.h"
 
 /* needed for directory lookup */
 #ifndef WIN32
@@ -213,21 +215,29 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho
        filename[0] = '\0';
        newname = filename;
        
-       /*if (!G.relbase_valid) return 0; *//* save blend file before using pointcache */
+       if (!G.relbase_valid) return 0; /* save blend file before using disk pointcache */
        
        /* start with temp dir */
        if (do_path) {
                len = ptcache_path(pid, filename);
                newname += len;
        }
-       idname = (pid->ob->id.name+2);
-       /* convert chars to hex so they are always a valid filename */
-       while('\0' != *idname) {
-               snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++));
-               newname+=2;
-               len += 2;
+       if(strcmp(pid->cache->name, "")==0) {
+               idname = (pid->ob->id.name+2);
+               /* convert chars to hex so they are always a valid filename */
+               while('\0' != *idname) {
+                       snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++));
+                       newname+=2;
+                       len += 2;
+               }
        }
-       
+       else {
+               int temp = strlen(pid->cache->name); 
+               strcpy(newname, pid->cache->name); 
+               newname+=temp;
+               len += temp;
+       }
+
        if (do_ext) {
                snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
                len += 16;
@@ -247,7 +257,7 @@ PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra)
        if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE)
                return NULL;
 
-       /*if (!G.relbase_valid) return NULL; *//* save blend file before using pointcache */
+       if (!G.relbase_valid) return NULL; /* save blend file before using disk pointcache */
        
        BKE_ptcache_id_filename(pid, filename, cfra, 1, 1);
 
@@ -286,6 +296,323 @@ int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot)
        return (fwrite(f, sizeof(float), tot, pf->fp) == tot);
 }
 
+static int ptcache_pid_elemsize(PTCacheID *pid)
+{
+       if(pid->type==PTCACHE_TYPE_SOFTBODY)
+               return 0; // TODO
+       else if(pid->type==PTCACHE_TYPE_PARTICLES)
+               return sizeof(ParticleKey);
+       else if(pid->type==PTCACHE_TYPE_CLOTH)
+               return 0; // TODO
+
+       return 0;
+}
+static int ptcache_pid_totelem(PTCacheID *pid)
+{
+       if(pid->type==PTCACHE_TYPE_SOFTBODY)
+               return 0; // TODO
+       else if(pid->type==PTCACHE_TYPE_PARTICLES) {
+               ParticleSystem *psys = pid->data;
+               return psys->totpart;
+       }
+       else if(pid->type==PTCACHE_TYPE_CLOTH)
+               return 0; // TODO
+
+       return 0;
+}
+
+void ptcache_update_info(PTCacheID *pid)
+{
+       PointCache *cache = pid->cache;
+       int totframes = 0;
+
+       if(cache->flag & PTCACHE_DISK_CACHE) {
+               int cfra = cache->startframe;
+
+               for(; cfra<=cache->endframe; cfra++) {
+                       if(BKE_ptcache_id_exist(pid, cfra))
+                               totframes++;
+               }
+
+               sprintf(cache->info, "%i frames on disk.", totframes);
+       }
+       else {
+               PTCacheMem *pm = cache->mem_cache.first;                
+               float framesize = 0.0f, bytes = 0.0f;
+               int mb;
+
+               if(pm)
+                       framesize = (float)ptcache_pid_elemsize(pid) * (float)pm->totpoint;
+               
+               for(; pm; pm=pm->next)
+                       totframes++;
+
+               bytes = totframes * framesize;
+
+               mb = (bytes > 1024.0f * 1024.0f);
+
+               sprintf(cache->info, "%i frames in memory (%.1f %s).",
+                       totframes,
+                       bytes / (mb ? 1024.0f * 1024.0f : 1024.0f),
+                       mb ? "Mb" : "kb");
+       }
+}
+/* reads cache from disk or memory */
+/* possible to get old or interpolated result */
+int BKE_ptcache_read_cache(PTCacheReader *reader)
+{
+       PTCacheID *pid = reader->pid;
+       PTCacheFile *pf=NULL, *pf2=NULL;
+       PTCacheMem *pm=NULL, *pm2=NULL;
+       int totelem = reader->totelem;
+       float cfra = reader->cfra;
+       int cfrai = (int)cfra;
+       int elemsize = ptcache_pid_elemsize(pid);
+       int i, incr = elemsize / sizeof(float);
+       float frs_sec = reader->scene->r.frs_sec;
+
+       if(totelem == 0)
+               return 0;
+
+       /* first check if we have the actual frame cached */
+       if(cfra == (float)cfrai) {
+               if(pid->cache->flag & PTCACHE_DISK_CACHE) {
+                       pf= BKE_ptcache_file_open(pid, PTCACHE_FILE_READ, cfrai);
+               }
+               else {
+                       pm = pid->cache->mem_cache.first;
+
+                       for(; pm; pm=pm->next) {
+                               if(pm->frame == cfrai)
+                                       break;
+                       }
+               }
+       }
+
+       /* if found, use exact frame */
+       if(pf || pm) {
+               float *data;
+
+               if(pm)
+                       data = pm->data;
+               else
+                       data = MEM_callocN(elemsize, "pointcache read data");
+
+               for(i=0; i<totelem; i++) {
+                       if(pf) {
+                               if(!BKE_ptcache_file_read_floats(pf, data, incr)) {
+                                       BKE_ptcache_file_close(pf);
+                                       MEM_freeN(data);
+                                       return 0;
+                               }
+
+                               reader->set_elem(i, reader->calldata, data);
+                       }
+                       else {
+                               reader->set_elem(i, reader->calldata, data);
+                               data += incr;
+                       }
+               }
+
+               if(pf) {
+                       BKE_ptcache_file_close(pf);
+                       MEM_freeN(data);
+               }
+
+               return PTCACHE_READ_EXACT;
+       }
+       /* no exact cache frame found so try to find cached frames around cfra */
+       if(reader->allow_interpolate || reader->allow_old) {
+               int cfra1, cfra2;
+
+               if(pid->cache->flag & PTCACHE_DISK_CACHE) {
+                       pf=NULL;
+                       while(cfrai > pid->cache->startframe && !pf) {
+                               cfrai--;
+                               pf= BKE_ptcache_file_open(pid, PTCACHE_FILE_READ, cfrai);
+                               cfra1 = cfrai;
+                       }
+
+                       *(reader->old_frame) = cfrai;
+
+                       cfrai = (int)cfra;
+                       while(cfrai < pid->cache->endframe && !pf2) {
+                               cfrai++;
+                               pf2= BKE_ptcache_file_open(pid, PTCACHE_FILE_READ, cfrai);
+                               cfra2 = cfrai;
+                       }
+               }
+               else if(pid->cache->mem_cache.first){
+                       pm = pid->cache->mem_cache.first;
+
+                       while(pm->next && pm->next->frame < cfra)
+                               pm= pm->next;
+
+                       if(pm) {
+                               *(reader->old_frame) = pm->frame;
+                               cfra1 = pm->frame;
+                       }
+
+                       pm2 = pid->cache->mem_cache.last;
+
+                       while(pm2->prev && pm2->frame > cfra)
+                               pm2= pm2->prev;
+
+                       if(pm2)
+                               cfra2 = pm2->frame;
+               }
+
+               if(reader->allow_interpolate && ((pf && pf2) || (pm && pm2))) {
+                       /* interpolate from nearest frames */
+                       float *data1, *data2;
+
+                       if(pm) {
+                               data1 = pm->data;
+                               data2 = pm2->data;
+                       }
+                       else {
+                               data1 = MEM_callocN(elemsize, "pointcache read data1");
+                               data2 = MEM_callocN(elemsize, "pointcache read data2");
+                       }
+
+                       for(i=0; i<totelem; i++) {
+                               if(pf && pf2) {
+                                       if(!BKE_ptcache_file_read_floats(pf, data1, incr)) {
+                                               BKE_ptcache_file_close(pf);
+                                               BKE_ptcache_file_close(pf2);
+                                               MEM_freeN(data1);
+                                               MEM_freeN(data2);
+                                               return 0;
+                                       }
+                                       if(!BKE_ptcache_file_read_floats(pf2, data2, incr)) {
+                                               BKE_ptcache_file_close(pf);
+                                               BKE_ptcache_file_close(pf2);
+                                               MEM_freeN(data1);
+                                               MEM_freeN(data2);
+                                               return 0;
+                                       }
+                                       reader->interpolate_elem(i, reader->calldata, frs_sec, cfra, cfra1, cfra2, data1, data2);
+                               }
+                               else {
+                                       reader->interpolate_elem(i, reader->calldata, frs_sec, cfra, cfra1, cfra2, data1, data2);
+                                       data1 += incr;
+                                       data2 += incr;
+                               }
+                       }
+
+                       if(pf) {
+                               BKE_ptcache_file_close(pf);
+                               BKE_ptcache_file_close(pf2);
+                               MEM_freeN(data1);
+                               MEM_freeN(data2);
+                       }
+
+                       return PTCACHE_READ_INTERPOLATED;
+               }
+               else if(reader->allow_old && (pf || pm)) {
+                       /* use last valid cache frame */
+                       float *data;
+
+                       if(pm)
+                               data = pm->data;
+                       else
+                               data = MEM_callocN(elemsize, "pointcache read data");
+
+                       for(i=0; i<totelem; i++) {
+                               if(pf) {
+                                       if(!BKE_ptcache_file_read_floats(pf, data, incr)) {
+                                               BKE_ptcache_file_close(pf);
+                                               if(pf2)
+                                                       BKE_ptcache_file_close(pf2);
+                                               return 0;
+                                       }
+                                       reader->set_elem(i, reader->calldata, data);
+                               }
+                               else {
+                                       reader->set_elem(i, reader->calldata, data);
+                                       data += incr;
+                               }
+                       }
+
+                       if(pf) {
+                               BKE_ptcache_file_close(pf);
+                               MEM_freeN(data);
+                       }
+                       if(pf2)
+                               BKE_ptcache_file_close(pf2);
+
+                       return PTCACHE_READ_OLD;
+               }
+       }
+
+       if(pf)
+               BKE_ptcache_file_close(pf);
+       if(pf2)
+               BKE_ptcache_file_close(pf2);
+
+       return 0;
+}
+/* writes cache to disk or memory */
+int BKE_ptcache_write_cache(PTCacheWriter *writer)
+{
+       PointCache *cache = writer->pid->cache;
+       PTCacheFile *pf= NULL;
+       int elemsize = ptcache_pid_elemsize(writer->pid);
+       int i, incr = elemsize / sizeof(float);
+
+       if(writer->totelem == 0 || writer->cfra <= 0)
+               return 0;
+
+       if(cache->flag & PTCACHE_DISK_CACHE) {
+               pf = BKE_ptcache_file_open(writer->pid, PTCACHE_FILE_WRITE, writer->cfra);
+               if(!pf)
+                       return 0;
+
+               for(i=0; i<writer->totelem; i++)
+                       BKE_ptcache_file_write_floats(pf, writer->elem_ptr(i, writer->calldata), incr);
+       }
+       else {
+               PTCacheMem *pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
+               PTCacheMem *pm2;
+               float *pmdata;
+
+               pm->data = MEM_callocN(elemsize * writer->totelem, "Pointcache mem data");
+               pmdata = pm->data;
+
+               for(i=0; i<writer->totelem; i++, pmdata+=incr)
+                       memcpy(pmdata, writer->elem_ptr(i, writer->calldata), elemsize);
+
+               pm->frame = writer->cfra;
+               pm->totpoint = writer->totelem;
+
+               /* find add location */
+               pm2 = cache->mem_cache.first;
+               if(!pm2)
+                       BLI_addtail(&cache->mem_cache, pm);
+               else if(pm2->frame == writer->cfra) {
+                       /* overwrite same frame */
+                       MEM_freeN(pm2->data);
+                       pm2->data = pm->data;
+                       MEM_freeN(pm);
+               }
+               else {
+                       while(pm2->next && pm2->next->frame < writer->cfra)
+                               pm2 = pm2->next;
+
+                       BLI_insertlinkafter(&cache->mem_cache, pm2, pm);
+               }
+       }
+
+       if(writer->cfra - cache->last_exact == 1)
+               cache->last_exact = writer->cfra;
+       
+       if(pf)
+               BKE_ptcache_file_close(pf);
+
+       ptcache_update_info(writer->pid);
+
+       return 1;
+}
 /* youll need to close yourself after!
  * mode - PTCACHE_CLEAR_ALL, 
 
@@ -317,62 +644,116 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
        case PTCACHE_CLEAR_ALL:
        case PTCACHE_CLEAR_BEFORE:      
        case PTCACHE_CLEAR_AFTER:
-               ptcache_path(pid, path);
-               
-               len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */
-               
-               dir = opendir(path);
-               if (dir==NULL)
-                       return;
-
-               snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index);
-               
-               while ((de = readdir(dir)) != NULL) {
-                       if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
-                               if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
-                                       if (mode == PTCACHE_CLEAR_ALL) {
-                                               BLI_join_dirfile(path_full, path, de->d_name);
-                                               BLI_delete(path_full, 0, 0);
-                                       } else {
-                                               /* read the number of the file */
-                                               int frame, len2 = strlen(de->d_name);
-                                               char num[7];
-
-                                               if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
-                                                       BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
-                                                       frame = atoi(num);
-                                                       
-                                                       if((mode==PTCACHE_CLEAR_BEFORE && frame < cfra) || 
-                                                          (mode==PTCACHE_CLEAR_AFTER && frame > cfra)  ) {
+               if(pid->cache->flag & PTCACHE_DISK_CACHE) {
+                       ptcache_path(pid, path);
+                       
+                       len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */
+                       
+                       dir = opendir(path);
+                       if (dir==NULL)
+                               return;
+
+                       snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index);
+                       
+                       while ((de = readdir(dir)) != NULL) {
+                               if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
+                                       if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
+                                               if (mode == PTCACHE_CLEAR_ALL) {
+                                                       pid->cache->last_exact = 0;
+                                                       BLI_join_dirfile(path_full, path, de->d_name);
+                                                       BLI_delete(path_full, 0, 0);
+                                               } else {
+                                                       /* read the number of the file */
+                                                       int frame, len2 = strlen(de->d_name);
+                                                       char num[7];
+
+                                                       if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
+                                                               BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
+                                                               frame = atoi(num);
                                                                
-                                                               BLI_join_dirfile(path_full, path, de->d_name);
-                                                               BLI_delete(path_full, 0, 0);
+                                                               if((mode==PTCACHE_CLEAR_BEFORE && frame < cfra) || 
+                                                               (mode==PTCACHE_CLEAR_AFTER && frame > cfra)     ) {
+                                                                       
+                                                                       BLI_join_dirfile(path_full, path, de->d_name);
+                                                                       BLI_delete(path_full, 0, 0);
+                                                               }
                                                        }
                                                }
                                        }
                                }
                        }
+                       closedir(dir);
+               }
+               else {
+                       PTCacheMem *pm= pid->cache->mem_cache.first;
+                       PTCacheMem *link= NULL;
+
+                       if(mode == PTCACHE_CLEAR_ALL) {
+                               pid->cache->last_exact = 0;
+                               for(; pm; pm=pm->next)
+                                       MEM_freeN(pm->data);
+                               BLI_freelistN(&pid->cache->mem_cache);
+                       } else {
+                               while(pm) {
+                                       if((mode==PTCACHE_CLEAR_BEFORE && pm->frame < cfra)     || 
+                                       (mode==PTCACHE_CLEAR_AFTER && pm->frame > cfra) ) {
+                                               link = pm;
+                                               pm = pm->next;
+                                               MEM_freeN(link->data);
+                                               BLI_freelinkN(&pid->cache->mem_cache, link);
+                                       }
+                                       else
+                                               pm = pm->next;
+                               }
+                       }
                }
-               closedir(dir);
                break;
                
        case PTCACHE_CLEAR_FRAME:
-               len = BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */
-               BLI_delete(filename, 0, 0);
+               if(pid->cache->flag & PTCACHE_DISK_CACHE) {
+                       if(BKE_ptcache_id_exist(pid, cfra)) {
+                               BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */
+                               BLI_delete(filename, 0, 0);
+                       }
+               }
+               else {
+                       PTCacheMem *pm = pid->cache->mem_cache.first;
+
+                       for(; pm; pm=pm->next) {
+                               if(pm->frame == cfra) {
+                                       MEM_freeN(pm->data);
+                                       BLI_freelinkN(&pid->cache->mem_cache, pm);
+                                       break;
+                               }
+                       }
+               }
                break;
        }
+
+       ptcache_update_info(pid);
 }
 
 int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
 {
-       char filename[MAX_PTCACHE_FILE];
-
        if(!pid->cache)
                return 0;
        
-       BKE_ptcache_id_filename(pid, filename, cfra, 1, 1);
+       if(pid->cache->flag & PTCACHE_DISK_CACHE) {
+               char filename[MAX_PTCACHE_FILE];
+               
+               BKE_ptcache_id_filename(pid, filename, cfra, 1, 1);
 
-       return BLI_exists(filename);
+               return BLI_exists(filename);
+       }
+       else {
+               PTCacheMem *pm = pid->cache->mem_cache.first;
+
+               for(; pm; pm=pm->next) {
+                       if(pm->frame==cfra)
+                               return 1;
+               }
+               return 0;
+       }
 }
 
 void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
@@ -414,10 +795,10 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
        }
 }
 
-int BKE_ptcache_id_reset(PTCacheID *pid, int mode)
+int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
 {
        PointCache *cache;
-       int reset, clear;
+       int reset, clear, current, after;
 
        if(!pid->cache)
                return 0;
@@ -425,11 +806,20 @@ int BKE_ptcache_id_reset(PTCacheID *pid, int mode)
        cache= pid->cache;
        reset= 0;
        clear= 0;
+       current= 0;
+       after= 0;
 
        if(mode == PTCACHE_RESET_DEPSGRAPH) {
                if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) {
-                       reset= 1;
-                       clear= 1;
+                       if(cache->flag & PTCACHE_AUTOCACHE) {
+                               reset= 1;
+                               clear= 1;
+                       }
+                       else {
+                               current= 1;
+                               after= 1;
+                               cache->flag |= PTCACHE_OUTDATED;
+                       }
                }
                else
                        cache->flag |= PTCACHE_OUTDATED;
@@ -449,10 +839,19 @@ int BKE_ptcache_id_reset(PTCacheID *pid, int mode)
                        if(!(cache->flag & PTCACHE_BAKED))
                                clear= 1;
        }
+       else if(mode == PTCACHE_RESET_FREE) {
+               if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) {
+                       if((cache->flag & PTCACHE_AUTOCACHE)==0) {
+                               current= 1;
+                               after= 1;
+                       }
+               }
+       }
 
        if(reset) {
                cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_SIMULATION_VALID);
                cache->simframe= 0;
+               cache->last_exact= 0;
 
                if(pid->type == PTCACHE_TYPE_CLOTH)
                        cloth_free_modifier(pid->ob, pid->data);
@@ -463,11 +862,15 @@ int BKE_ptcache_id_reset(PTCacheID *pid, int mode)
        }
        if(clear)
                BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+       if(after)
+               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, CFRA);
+       if(current)
+               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, CFRA);
 
-       return (reset || clear);
+       return (reset || clear || current || after);
 }
 
-int BKE_ptcache_object_reset(Object *ob, int mode)
+int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
 {
        PTCacheID pid;
        ParticleSystem *psys;
@@ -479,7 +882,7 @@ int BKE_ptcache_object_reset(Object *ob, int mode)
 
        if(ob->soft) {
                BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
-               reset |= BKE_ptcache_id_reset(&pid, mode);
+               reset |= BKE_ptcache_id_reset(scene, &pid, mode);
        }
 
        for(psys=ob->particlesystem.first; psys; psys=psys->next) {
@@ -488,23 +891,23 @@ int BKE_ptcache_object_reset(Object *ob, int mode)
                if(psys->soft) {
                        BKE_ptcache_id_from_softbody(&pid, ob, psys->soft);
                        if(mode == PSYS_RESET_ALL || !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED))) 
-                               reset |= BKE_ptcache_id_reset(&pid, mode);
+                               reset |= BKE_ptcache_id_reset(scene, &pid, mode);
                        else
                                skip = 1;
                }
-               else if((psys->recalc & PSYS_RECALC_RESET)==0)
+               else if(psys->recalc & PSYS_RECALC_REDO || psys->recalc & PSYS_RECALC_CHILD)
                        skip = 1;
 
                if(skip == 0) {
                        BKE_ptcache_id_from_particles(&pid, ob, psys);
-                       reset |= BKE_ptcache_id_reset(&pid, mode);
+                       reset |= BKE_ptcache_id_reset(scene, &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);
+                       reset |= BKE_ptcache_id_reset(scene, &pid, mode);
                }
        }
 
@@ -564,7 +967,7 @@ void BKE_ptcache_set_continue_physics(Scene *scene, int 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))
+                               if(BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED))
                                        DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
                }
        }
@@ -590,6 +993,14 @@ PointCache *BKE_ptcache_add()
 
 void BKE_ptcache_free(PointCache *cache)
 {
+       PTCacheMem *pm = cache->mem_cache.first;
+       if(pm) {
+               for(; pm; pm=pm->next)
+                       MEM_freeN(pm->data);
+
+               BLI_freelistN(&cache->mem_cache);
+       }
+
        MEM_freeN(cache);
 }
 
@@ -605,3 +1016,231 @@ PointCache *BKE_ptcache_copy(PointCache *cache)
        return ncache;
 }
 
+
+
+/* Baking */
+void BKE_ptcache_autocache_all(Scene *scene)
+{
+       PTCacheBaker baker;
+
+       baker.bake=0;
+       baker.break_data=NULL;
+       baker.break_test=NULL;
+       baker.pid=NULL;
+       baker.progressbar=NULL;
+       baker.progresscontext=NULL;
+       baker.render=0;
+       baker.scene=scene;
+
+       if(psys_count_autocache(scene, NULL))
+               BKE_ptcache_make_cache(&baker);
+}
+
+/* if bake is not given run simulations to current frame */
+void BKE_ptcache_make_cache(PTCacheBaker* baker)
+{
+       Scene *scene = baker->scene;
+       Base *base;
+       ListBase pidlist;
+       PTCacheID *pid = baker->pid;
+       PointCache *cache;
+       float frameleno = scene->r.framelen;
+       int cfrao = CFRA;
+       int startframe = MAXFRAME;
+       int endframe = CFRA;
+       int bake = baker->bake;
+       int render = baker->render;
+       int end = 0;
+
+       G.afbreek = 0;
+
+       //printf("Caching physics...");
+
+       /* set caches to baking mode and figure out start frame */
+       if(pid) {
+               /* cache/bake a single object */
+               cache = pid->cache;
+               if((cache->flag & PTCACHE_BAKED)==0) {
+                       if(pid->type==PTCACHE_TYPE_PARTICLES)
+                               psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe);
+
+                       if(bake || cache->flag & PTCACHE_OUTDATED)
+                               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+                       startframe = MAX2(cache->last_exact, cache->startframe);
+
+                       if(bake) {
+                               endframe = cache->endframe;
+                               cache->flag |= PTCACHE_BAKING;
+                       }
+                       else
+                               endframe = MIN2(endframe, cache->endframe);
+
+                       cache->flag &= ~PTCACHE_BAKED;
+               }
+       }
+       else for(base=scene->base.first; base; base= base->next) {
+               /* cache/bake everything in the scene */
+               BKE_ptcache_ids_from_object(&pidlist, base->object);
+
+               for(pid=pidlist.first; pid; pid=pid->next) {
+                       cache = pid->cache;
+                       if((cache->flag & PTCACHE_BAKED)==0) {
+                               if(pid->type==PTCACHE_TYPE_PARTICLES)
+                                       psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe);
+
+                               if(cache->flag & PTCACHE_OUTDATED)
+                                       BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+                               startframe = MIN2(startframe, cache->startframe);
+
+                               if(bake) {
+                                       endframe = MAX2(endframe, cache->endframe);
+                                       cache->flag |= PTCACHE_BAKING;
+                               }
+                               else if(render)
+                                       cache->flag |= PTCACHE_BAKING;
+
+                               cache->flag &= ~PTCACHE_BAKED;
+
+                       }
+               }
+
+               BLI_freelistN(&pidlist);
+       }
+
+       CFRA= startframe;
+       scene->r.framelen = 1.0;
+       scene_update_for_newframe(scene, scene->lay);
+
+       for(; CFRA <= endframe; CFRA++) {
+               float prog;
+
+               if(bake)
+                       prog = (int)(100.0 * (float)(CFRA - startframe)/(float)(endframe-startframe));
+               else
+                       prog = CFRA;
+
+               /* NOTE: baking should not redraw whole ui as this slows things down */
+               if(baker->progressbar)
+                       baker->progressbar(baker->progresscontext, prog);
+               
+               scene_update_for_newframe(scene, scene->lay);
+
+               /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
+               if(baker->break_test && baker->break_test(baker->break_data))
+                       break;
+       }
+
+       /* clear baking flag */
+       if(pid) {
+               cache->flag &= ~(PTCACHE_BAKING|PTCACHE_OUTDATED);
+               if(bake)
+                       cache->flag |= PTCACHE_BAKED;
+       }
+       else for(base=scene->base.first; base; base= base->next) {
+               BKE_ptcache_ids_from_object(&pidlist, base->object);
+
+               for(pid=pidlist.first; pid; pid=pid->next) {
+                       cache->flag &= ~(PTCACHE_BAKING|PTCACHE_OUTDATED);
+                       if(bake)
+                               cache->flag |= PTCACHE_BAKED;
+               }
+       }
+       
+       //printf("done!\n");
+
+       scene->r.framelen = frameleno;
+       CFRA = cfrao;
+       scene_update_for_newframe(scene, scene->lay);
+}
+
+void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) {
+       PointCache *cache = pid->cache;
+       PTCacheFile *pf;
+       PTCacheMem *pm;
+       int totelem=0;
+       int float_count=0;
+       int tot;
+       int write_error=0;
+
+       if (!G.relbase_valid){
+               cache->flag &= ~PTCACHE_DISK_CACHE;
+               return;
+       }
+
+       totelem = ptcache_pid_totelem(pid);
+       float_count = ptcache_pid_elemsize(pid) / sizeof(float);
+
+       if(totelem==0 || float_count==0)
+               return;
+
+       tot = totelem*float_count;
+
+       /* MEM -> DISK */
+       if(cache->flag & PTCACHE_DISK_CACHE) {
+               pm = cache->mem_cache.first;
+
+               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+               for(; pm; pm=pm->next) {
+                       pf = BKE_ptcache_file_open(pid, PTCACHE_FILE_WRITE, pm->frame);
+
+                       if(pf) {
+                               if(fwrite(pm->data, sizeof(float), tot, pf->fp) != tot) {
+                                       printf("Error writing to disk cache\n");
+                                       
+                                       cache->flag &= ~PTCACHE_DISK_CACHE;
+
+                                       BKE_ptcache_file_close(pf);
+                                       return;
+                               }
+                               BKE_ptcache_file_close(pf);
+                       }
+                       else
+                               printf("Error creating disk cache file\n");
+               }
+
+               cache->flag &= ~PTCACHE_DISK_CACHE;
+               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+               cache->flag |= PTCACHE_DISK_CACHE;
+       }
+       /* DISK -> MEM */
+       else {
+               int cfra;
+               int sfra = cache->startframe;
+               int efra = cache->endframe;
+
+               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+               for(cfra=sfra; cfra <= efra; cfra++) {
+                       pf = BKE_ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
+
+                       if(pf) {
+                               pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
+                               pm->data = MEM_callocN(sizeof(float)*tot, "Pointcache mem data");
+
+                               if(fread(pm->data, sizeof(float), tot, pf->fp)!= tot) {
+                                       printf("Error reading from disk cache\n");
+
+                                       cache->flag |= PTCACHE_DISK_CACHE;
+
+                                       MEM_freeN(pm->data);
+                                       MEM_freeN(pm);
+                                       BKE_ptcache_file_close(pf);
+                                       return;
+                               }
+
+                               pm->frame = cfra;
+
+                               BLI_addtail(&pid->cache->mem_cache, pm);
+
+                               BKE_ptcache_file_close(pf);
+                       }
+               }
+
+               cache->flag |= PTCACHE_DISK_CACHE;
+               BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+               cache->flag &= ~PTCACHE_DISK_CACHE;
+       }
+}
\ No newline at end of file
index a4856944d8a325f5d372ffd1479e4463f4af52a4..77e256f1435bc732bcc19b0178751a958ebb86bb 100644 (file)
@@ -2878,6 +2878,16 @@ static void direct_link_material(FileData *fd, Material *ma)
 
 static void direct_link_pointcache(FileData *fd, PointCache *cache)
 {
+       if((cache->flag & PTCACHE_DISK_CACHE)==0) {
+               PTCacheMem *pm;
+
+               link_list(fd, &cache->mem_cache);
+
+               pm = cache->mem_cache.first;
+
+               for(; pm; pm=pm->next)
+                       pm->data = newdataadr(fd, pm->data);
+       }
        cache->flag &= ~(PTCACHE_SIMULATION_VALID|PTCACHE_BAKE_EDIT_ACTIVE);
        cache->simframe= 0;
 }
@@ -8996,6 +9006,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                Scene *sce;
                Tex *tx;
                ParticleSettings *part;
+               Object *ob;
                
                for(screen= main->screen.first; screen; screen= screen->id.next) {
                        do_versions_windowmanager_2_50(screen);
@@ -9038,7 +9049,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                        me->drawflag= ME_DRAWEDGES|ME_DRAWFACES|ME_DRAWCREASES;
                }
 
-               /* particle settings conversion */
+               /* particle draw and render types */
                for(part= main->particle.first; part; part= part->id.next) {
                        if(part->draw_as) {
                                if(part->draw_as == PART_DRAW_DOT) {
@@ -9054,6 +9065,17 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                }
                        }
                }
+               /* set old pointcaches to have disk cache flag */
+               for(ob = main->object.first; ob; ob= ob->id.next) {
+                       ParticleSystem *psys = ob->particlesystem.first;
+
+                       for(; psys; psys=psys->next) {
+                               if(psys->pointcache)
+                                       psys->pointcache->flag |= PTCACHE_DISK_CACHE;
+                       }
+
+                       /* TODO: softbody & cloth caches */
+               }
        }
 
        /* TODO: should be moved into one of the version blocks once this branch moves to trunk and we can
index f8112406e805d4de802020e7602111ec15449e8c..9ef062bd7b643f4fdbc5d893f6af8191d095539f 100644 (file)
@@ -549,6 +549,22 @@ static void write_userdef(WriteData *wd)
        }
 }
 
+/* TODO: replace *cache with *cachelist once it's coded */
+#define PTCACHE_WRITE_PSYS     0
+static void write_pointcaches(WriteData *wd, PointCache *cache, int type)
+{
+       writestruct(wd, DATA, "PointCache", 1, cache);
+
+       if((cache->flag & PTCACHE_DISK_CACHE)==0) {
+               PTCacheMem *pm = cache->mem_cache.first;
+
+               for(; pm; pm=pm->next) {
+                       writestruct(wd, DATA, "PTCacheMem", 1, pm);
+                       if(type==PTCACHE_WRITE_PSYS)
+                               writestruct(wd, DATA, "ParticleKey", pm->totpoint, pm->data);
+               }
+       }
+}
 static void write_particlesettings(WriteData *wd, ListBase *idbase)
 {
        ParticleSettings *part;
@@ -585,8 +601,8 @@ static void write_particlesystems(WriteData *wd, ListBase *particles)
                }
                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);
+               if(psys->soft) write_pointcaches(wd, psys->soft->pointcache, PTCACHE_WRITE_PSYS);
+               write_pointcaches(wd, psys->pointcache, PTCACHE_WRITE_PSYS);
        }
 }
 
diff --git a/source/blender/editors/include/ED_pointcache.h b/source/blender/editors/include/ED_pointcache.h
new file mode 100644 (file)
index 0000000..7bf51d9
--- /dev/null
@@ -0,0 +1,38 @@
+/* 
+ * $Id: ED_editparticle.h $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef ED_PHYSICS_H
+#define ED_PHYSICS_H
+
+/* operators */
+void ED_operatortypes_pointcache(void);
+//void ED_keymap_pointcache(struct wmWindowManager *wm);
+
+#endif /* ED_PHYSICS_H */
+
diff --git a/source/blender/editors/physics/ed_pointcache.c b/source/blender/editors/physics/ed_pointcache.c
new file mode 100644 (file)
index 0000000..e47f44c
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
+
+#include "BKE_context.h"
+#include "BKE_particle.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h" 
+#include "BKE_pointcache.h"
+#include "BKE_global.h"
+#include "BKE_multires.h"
+
+#include "BLI_blenlib.h"
+
+#include "ED_screen.h"
+#include "ED_pointcache.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "physics_intern.h"
+
+static int cache_break_test(void *cbd) {
+       return G.afbreek==1;
+}
+/**************************** general **********************************/
+static int ptcache_bake_all_poll(bContext *C)
+{
+       Scene *scene= CTX_data_scene(C);
+
+       if(!scene)
+               return 0;
+       
+       return 1;
+}
+
+static int ptcache_bake_all_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       PTCacheBaker baker;
+
+
+       baker.scene = scene;
+       baker.pid = NULL;
+       baker.bake = RNA_boolean_get(op->ptr, "bake");
+       baker.render = 0;
+       baker.break_test = cache_break_test;
+       baker.break_data = NULL;
+       baker.progressbar = WM_timecursor;
+       baker.progresscontext = CTX_wm_window(C);
+
+       BKE_ptcache_make_cache(&baker);
+
+       WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
+
+       return OPERATOR_FINISHED;
+}
+static int ptcache_free_bake_all_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Base *base;
+       PTCacheID *pid;
+       ListBase pidlist;
+
+       for(base=scene->base.first; base; base= base->next) {
+               BKE_ptcache_ids_from_object(&pidlist, base->object);
+
+               for(pid=pidlist.first; pid; pid=pid->next) {
+                       pid->cache->flag &= ~PTCACHE_BAKED;
+                       BKE_ptcache_id_reset(scene, pid, PTCACHE_RESET_OUTDATED);
+               }
+       }
+
+       BLI_freelistN(&pidlist);
+
+       WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
+
+       return OPERATOR_FINISHED;
+}
+
+void PTCACHE_OT_bake_all(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Bake All Physics";
+       ot->idname= "PTCACHE_OT_bake_all";
+       
+       /* api callbacks */
+       ot->exec= ptcache_bake_all_exec;
+       ot->poll= ptcache_bake_all_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Free All Physics Bakes";
+       ot->idname= "PTCACHE_OT_free_bake_all";
+       
+       /* api callbacks */
+       ot->exec= ptcache_free_bake_all_exec;
+       ot->poll= ptcache_bake_all_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/**************************** particles **********************************/
+static int ptcache_bake_particle_system_poll(bContext *C)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+
+       if(!scene || !ob || ob->id.lib)
+               return 0;
+       
+       return (ob->particlesystem.first != NULL);
+}
+
+static int ptcache_bake_particle_system_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys =psys_get_current(ob);
+       PTCacheID pid;
+       PTCacheBaker baker;
+
+       BKE_ptcache_id_from_particles(&pid, ob, psys);
+
+       baker.scene = scene;
+       baker.pid = &pid;
+       baker.bake = RNA_boolean_get(op->ptr, "bake");
+       baker.render = 0;
+       baker.break_test = cache_break_test;
+       baker.break_data = NULL;
+       baker.progressbar = WM_timecursor;
+       baker.progresscontext = CTX_wm_window(C);
+
+       BKE_ptcache_make_cache(&baker);
+
+       WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
+
+       return OPERATOR_FINISHED;
+}
+static int ptcache_free_bake_particle_system_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= psys_get_current(ob);
+       PTCacheID pid;
+
+       BKE_ptcache_id_from_particles(&pid, ob, psys);
+       psys->pointcache->flag &= ~PTCACHE_BAKED;
+       BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+
+       WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
+
+       return OPERATOR_FINISHED;
+}
+void PTCACHE_OT_cache_particle_system(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Bake Particles";
+       ot->idname= "PTCACHE_OT_cache_particle_system";
+       
+       /* api callbacks */
+       ot->exec= ptcache_bake_particle_system_exec;
+       ot->poll= ptcache_bake_particle_system_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       RNA_def_boolean(ot->srna, "bake", 0, "Bake", "");
+}
+void PTCACHE_OT_free_bake_particle_system(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Free Particles Bake";
+       ot->idname= "PTCACHE_OT_free_bake_particle_system";
+       
+       /* api callbacks */
+       ot->exec= ptcache_free_bake_particle_system_exec;
+       ot->poll= ptcache_bake_particle_system_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+static int ptcache_bake_from_particles_cache_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= psys_get_current(ob);
+       PTCacheID pid;
+
+       BKE_ptcache_id_from_particles(&pid, ob, psys);
+       psys->pointcache->flag |= PTCACHE_BAKED;
+
+       return OPERATOR_FINISHED;
+}
+void PTCACHE_OT_bake_from_particles_cache(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Bake From Cache";
+       ot->idname= "PTCACHE_OT_bake_from_particles_cache";
+       
+       /* api callbacks */
+       ot->exec= ptcache_bake_from_particles_cache_exec;
+       ot->poll= ptcache_bake_particle_system_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/**************************** registration **********************************/
+
+void ED_operatortypes_pointcache(void)
+{
+       WM_operatortype_append(PTCACHE_OT_bake_all);
+       WM_operatortype_append(PTCACHE_OT_free_bake_all);
+       WM_operatortype_append(PTCACHE_OT_cache_particle_system);
+       WM_operatortype_append(PTCACHE_OT_free_bake_particle_system);
+       WM_operatortype_append(PTCACHE_OT_bake_from_particles_cache);
+}
+
+//void ED_keymap_pointcache(wmWindowManager *wm)
+//{
+//     ListBase *keymap= WM_keymap_listbase(wm, "Pointcache", 0, 0);
+//     
+//     WM_keymap_add_item(keymap, "PHYSICS_OT_bake_all", AKEY, KM_PRESS, 0, 0);
+//     WM_keymap_add_item(keymap, "PHYSICS_OT_free_all", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
+//     WM_keymap_add_item(keymap, "PHYSICS_OT_bake_particle_system", PADMINUS, KM_PRESS, KM_CTRL, 0);
+//     WM_keymap_add_item(keymap, "PHYSICS_OT_free_particle_system", LKEY, KM_PRESS, 0, 0);
+//}
+
index 4f9c1f4b7a77ac5be2f38bc4b92f4277e72bcb33..510103895f4103a338b56dfc8085446765d6ca3a 100644 (file)
@@ -50,6 +50,7 @@
 #include "ED_screen.h"
 #include "ED_space_api.h"
 #include "ED_uvedit.h"
+#include "ED_pointcache.h"
 
 /* only call once on startup, storage is global in BKE kernel listbase */
 void ED_spacetypes_init(void)
@@ -89,6 +90,7 @@ void ED_spacetypes_init(void)
        ED_operatortypes_curve();
        ED_operatortypes_armature();
        ED_marker_operatortypes();
+       ED_operatortypes_pointcache();
        
        ui_view2d_operatortypes();
        
index 6c7aa1ee49d63b21f98b154e3bc3e82cc083e366..efe5122ad010a0ff25b32165430447b6ad4b442c 100644 (file)
@@ -4672,7 +4672,7 @@ void special_aftertrans_update(TransInfo *t)
                        
                        if (base->flag & SELECT && (t->mode != TFM_DUMMY)) {
                                /* pointcache refresh */
-                               if (BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH))
+                               if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH))
                                        ob->recalc |= OB_RECALC_DATA;
                                
                                /* Set autokey if necessary */
index 718d1a1783466a92c6f0f263d16548fdd9de2fbf..a8d402fc503e878f6ed5f785487b9b02d41dbb50 100644 (file)
@@ -33,6 +33,8 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+
+#include "DNA_listBase.h"
        
 typedef struct PartDeflect {
        short deflect;          /* Deflection flag - does mesh deflect particles*/
@@ -72,12 +74,25 @@ typedef struct PartDeflect {
        int seed; /* wind noise random seed */
 } PartDeflect;
 
+typedef struct PTCacheMem {
+       struct PTCacheMem *next, *prev;
+       int frame, totpoint;
+       float *data;    /* data points */
+       void *xdata;    /* extra data */
+} PTCacheMem;
+
 typedef struct PointCache {
-       int flag;               /* generic flag */
+       int flag, rt;           /* 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) */
+       int last_exact; /* last exact frame that's cached */
+       int xdata_type; /* type of extra data */
+       char name[64];
+       char prev_name[64];
+       char info[64];
+       struct ListBase mem_cache;
 } PointCache;
 
 typedef struct SBVertex {
@@ -247,6 +262,8 @@ typedef struct SoftBody {
 #define PTCACHE_BAKING                         8
 #define PTCACHE_BAKE_EDIT                      16
 #define PTCACHE_BAKE_EDIT_ACTIVE       32
+#define PTCACHE_DISK_CACHE                     64
+#define PTCACHE_AUTOCACHE                      128
 
 /* ob->softflag */
 #define OB_SB_ENABLE   1
index d144ed5f28b8eab688ffa1aa37888b5868aaca1d..bc3f0733a0ddc341b24df07479726eabb80eb1d6 100644 (file)
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
 
+#include "WM_types.h"
+
 #ifdef RNA_RUNTIME
 
+#include "MEM_guardedalloc.h"
+
+#include "BKE_context.h"
+#include "BKE_pointcache.h"
+
+#include "BLI_blenlib.h"
+
+static void rna_Cache_toggle_disk_cache(bContext *C, PointerRNA *ptr)
+{
+       Object *ob = CTX_data_active_object(C);
+       PointCache *cache = (PointCache*)ptr->data;
+       PTCacheID *pid = NULL;
+       ListBase pidlist;
+
+       if(!ob)
+               return;
+
+       BKE_ptcache_ids_from_object(&pidlist, ob);
+
+       for(pid=pidlist.first; pid; pid=pid->next) {
+               if(pid->cache==cache)
+                       break;
+       }
+
+       if(pid)
+               BKE_ptcache_toggle_disk_cache(pid);
+
+       BLI_freelistN(&pidlist);
+}
+
+static void rna_Cache_idname_change(bContext *C, PointerRNA *ptr)
+{
+       Object *ob = CTX_data_active_object(C);
+       PointCache *cache = (PointCache*)ptr->data;
+       PTCacheID *pid = NULL, *pid2;
+       ListBase pidlist;
+       int new_name = 1;
+       char name[80];
+
+       if(!ob)
+               return;
+
+       /* TODO: check for proper characters */
+
+       BKE_ptcache_ids_from_object(&pidlist, ob);
+
+       for(pid=pidlist.first; pid; pid=pid->next) {
+               if(pid->cache==cache)
+                       pid2 = pid;
+               else if(strcmp(cache->name, "") && strcmp(cache->name,pid->cache->name)==0) {
+                       /*TODO: report "name exists" to user */
+                       strcpy(cache->name, cache->prev_name);
+                       new_name = 0;
+               }
+       }
+
+       if(new_name) {
+               if(pid2 && cache->flag & PTCACHE_DISK_CACHE) {
+                       strcpy(name, cache->name);
+                       strcpy(cache->name, cache->prev_name);
+
+                       cache->flag &= ~PTCACHE_DISK_CACHE;
+
+                       BKE_ptcache_toggle_disk_cache(pid2);
+
+                       strcpy(cache->name, name);
+
+                       cache->flag |= PTCACHE_DISK_CACHE;
+
+                       BKE_ptcache_toggle_disk_cache(pid2);
+               }
+
+               strcpy(cache->prev_name, cache->name);
+       }
+
+       BLI_freelistN(&pidlist);
+}
 #else
 
 static void rna_def_pointcache(BlenderRNA *brna)
@@ -60,6 +139,32 @@ static void rna_def_pointcache(BlenderRNA *brna)
 
        prop= RNA_def_property(srna, "baking", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_BAKING);
+
+       prop= RNA_def_property(srna, "disk_cache", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_DISK_CACHE);
+       RNA_def_property_ui_text(prop, "Disk Cache", "Save cache files to disk");
+       RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_toggle_disk_cache");
+
+       prop= RNA_def_property(srna, "outdated", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_OUTDATED);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Cache is outdated", "");
+
+       prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "name");
+       RNA_def_property_ui_text(prop, "Name", "Cache name");
+       RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_idname_change");
+
+       prop= RNA_def_property(srna, "autocache", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_AUTOCACHE);
+       RNA_def_property_ui_text(prop, "Auto Cache", "Cache changes automatically");
+       //RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_toggle_autocache");
+
+       prop= RNA_def_property(srna, "info", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "info");
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Cache Info", "Info on current cache status.");
+
 }
 
 static void rna_def_collision(BlenderRNA *brna)
index 8ee71b6fd9eced5479e2cce9dfb518223d0baf79..2c4c75e45ebfe2a2278531f5247005f3d4965f37 100644 (file)
@@ -38,6 +38,7 @@
 #include "DNA_scene_types.h"
 
 #include "WM_types.h"
+#include "WM_api.h"
 
 #ifdef RNA_RUNTIME
 
 #include "BKE_depsgraph.h"
 #include "BKE_particle.h"
 
+#include "BLI_arithb.h"
+
+/* property update functions */
 static void rna_Particle_redo(bContext *C, PointerRNA *ptr)
 {
+       Scene *scene = CTX_data_scene(C);
        ParticleSettings *part;
-       if(ptr->type==&RNA_ParticleSystem)
-               part = ((ParticleSystem*)ptr->data)->part;
-       else
+       if(ptr->type==&RNA_ParticleSystem) {
+               ParticleSystem *psys = (ParticleSystem*)ptr->data;
+               Object *ob = psys_find_object(scene, psys);
+               
+               psys->recalc = PSYS_RECALC_REDO;
+
+               if(ob)
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+       }
+       else {
                part = ptr->id.data;
-
-       psys_flush_particle_settings(CTX_data_scene(C), part, PSYS_RECALC_REDO);
+               psys_flush_particle_settings(scene, part, PSYS_RECALC_REDO);
+       }
 }
 
 static void rna_Particle_reset(bContext *C, PointerRNA *ptr)
 {
+       Scene *scene = CTX_data_scene(C);
        ParticleSettings *part;
-       if(ptr->type==&RNA_ParticleSystem)
-               part = ((ParticleSystem*)ptr->data)->part;
-       else
-               part = ptr->id.data;
 
-       psys_flush_particle_settings(CTX_data_scene(C), part, PSYS_RECALC_RESET|PSYS_RECALC_REDO);
+       if(ptr->type==&RNA_ParticleSystem) {
+               ParticleSystem *psys = (ParticleSystem*)ptr->data;
+               Object *ob = psys_find_object(scene, psys);
+               
+               psys->recalc = PSYS_RECALC_RESET;
+
+               if(ob) {
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+                       //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
+               }
+       }
+       else {
+               part = ptr->id.data;
+               psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET);
+               //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
+       }
 }
 
 static void rna_Particle_change_type(bContext *C, PointerRNA *ptr)
 {
+       Scene *scene = CTX_data_scene(C);
        ParticleSettings *part;
-       if(ptr->type==&RNA_ParticleSystem)
-               part = ((ParticleSystem*)ptr->data)->part;
-       else
-               part = ptr->id.data;
 
-       psys_flush_particle_settings(CTX_data_scene(C), part, PSYS_RECALC_RESET|PSYS_RECALC_TYPE|PSYS_RECALC_REDO);
+       if(ptr->type==&RNA_ParticleSystem) {
+               ParticleSystem *psys = (ParticleSystem*)ptr->data;
+               Object *ob = psys_find_object(scene, psys);
+               
+               psys->recalc = PSYS_RECALC_RESET|PSYS_RECALC_TYPE;
+
+               if(ob) {
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+                       //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
+               }
+       }
+       else {
+               part = ptr->id.data;
+               psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET|PSYS_RECALC_TYPE);
+               //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
+       }
 }
 
 static void rna_Particle_redo_child(bContext *C, PointerRNA *ptr)
 {
+       Scene *scene = CTX_data_scene(C);
        ParticleSettings *part;
-       if(ptr->type==&RNA_ParticleSystem)
-               part = ((ParticleSystem*)ptr->data)->part;
-       else
+
+       if(ptr->type==&RNA_ParticleSystem) {
+               ParticleSystem *psys = (ParticleSystem*)ptr->data;
+               Object *ob = psys_find_object(scene, psys);
+               
+               psys->recalc = PSYS_RECALC_CHILD;
+
+               if(ob)
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+       }
+       else {
                part = ptr->id.data;
 
-       psys_flush_particle_settings(CTX_data_scene(C), part, PSYS_RECALC_CHILD);
+               psys_flush_particle_settings(scene, part, PSYS_RECALC_CHILD);
+       }
 }
 static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value)
 {
@@ -887,7 +933,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
        RNA_def_property_int_sdna(prop, NULL, "disp");
        RNA_def_property_range(prop, 0, 100);
        RNA_def_property_ui_text(prop, "Display", "Percentage of particles to display in 3d view");
-       RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
+       RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
 
        prop= RNA_def_property(srna, "material", PROP_INT, PROP_NONE);
        RNA_def_property_int_sdna(prop, NULL, "omat");
index 07560edb76be25ad275c7d9725c6010d4c14ff92..f7aae88519f41f05ad87b451da1e86f7805fb18f 100644 (file)
@@ -46,6 +46,7 @@
 #include "BKE_object.h"
 #include "BKE_scene.h"
 #include "BKE_writeavi.h"      /* <------ should be replaced once with generic movie module */
+#include "BKE_pointcache.h"
 
 #include "MEM_guardedalloc.h"
 
@@ -2413,6 +2414,20 @@ static int is_rendering_allowed(Render *re)
        return 1;
 }
 
+static void update_physics_cache(Render *re, Scene *scene)
+{
+       PTCacheBaker baker;
+
+       baker.scene = scene;
+       baker.pid = NULL;
+       baker.bake = 0;
+       baker.render = 1;
+       baker.break_test = re->test_break;
+       baker.break_data = re->tbh;
+       baker.progressbar = NULL;
+
+       BKE_ptcache_make_cache(&baker);
+}
 /* evaluating scene options for general Blender render */
 static int render_initialize_from_scene(Render *re, Scene *scene, int anim)
 {
@@ -2450,6 +2465,9 @@ static int render_initialize_from_scene(Render *re, Scene *scene, int anim)
        
        /* check all scenes involved */
        tag_scenes_for_render(re);
+
+       /* make sure dynamics are up to date */
+       update_physics_cache(re, scene);
        
        if(scene->r.scemode & R_SINGLE_LAYER)
                push_render_result(re);