diff options
author | Janne Karhu <jhkarh@gmail.com> | 2009-06-21 14:16:52 +0400 |
---|---|---|
committer | Janne Karhu <jhkarh@gmail.com> | 2009-06-21 14:16:52 +0400 |
commit | 6b15024f4a7b999331694d8a9135d47e4b783a34 (patch) | |
tree | 0b5a5c3b02778a7ca9df7628e742f98704505bb7 /source/blender | |
parent | 64274de2fe8ef3b9a98a5cb3bd7d691fa1cee600 (diff) |
Pointcache refresh part 1:
* 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.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_particle.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_pointcache.h | 56 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/depsgraph.c | 18 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 48 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 187 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 753 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 24 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 20 | ||||
-rw-r--r-- | source/blender/editors/include/ED_pointcache.h | 38 | ||||
-rw-r--r-- | source/blender/editors/physics/ed_pointcache.c | 270 | ||||
-rw-r--r-- | source/blender/editors/space_api/spacetypes.c | 2 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_object_force.h | 19 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_object_force.c | 105 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_particle.c | 86 | ||||
-rw-r--r-- | source/blender/render/intern/source/pipeline.c | 18 |
16 files changed, 1489 insertions, 162 deletions
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 4efd9a7f8ba..0ecd71fc4a3 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -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); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 8ef3ff4d4b7..b79357edf36 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -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" @@ -56,6 +59,11 @@ #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 diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 8bb34bde122..b57b8b7a6da 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -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); } } } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 34e69b2d736..5b3720cd6b0 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -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); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 52f13eeadb8..fc6413849d1 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -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; } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index b00755f7135..f59336518d7 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -51,9 +51,11 @@ #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 diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a4856944d8a..77e256f1435 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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 diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index f8112406e80..9ef062bd7b6 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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 index 00000000000..7bf51d9d53d --- /dev/null +++ b/source/blender/editors/include/ED_pointcache.h @@ -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 index 00000000000..e47f44c5c1a --- /dev/null +++ b/source/blender/editors/physics/ed_pointcache.c @@ -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); +//} + diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 4f9c1f4b7a7..510103895f4 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -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(); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 6c7aa1ee49d..efe5122ad01 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -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 */ diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 718d1a17834..a8d402fc503 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -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 diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index d144ed5f28b..bc3f0733a0d 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -32,8 +32,87 @@ #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) diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 8ee71b6fd9e..2c4c75e45eb 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -38,6 +38,7 @@ #include "DNA_scene_types.h" #include "WM_types.h" +#include "WM_api.h" #ifdef RNA_RUNTIME @@ -45,48 +46,93 @@ #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"); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 07560edb76b..f7aae88519f 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -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); |