diff options
Diffstat (limited to 'source/blender/blenkernel/intern/pointcache.c')
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 383 |
1 files changed, 352 insertions, 31 deletions
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index cdb95e2f015..3b411e758c0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -27,21 +27,36 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ - #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> -#include "BKE_pointcache.h" +#include "MEM_guardedalloc.h" -#include "BKE_utildefines.h" -#include "BKE_global.h" -#include "BKE_library.h" +#include "DNA_ID.h" +#include "DNA_cloth_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" #include "BLI_blenlib.h" + +#include "BKE_cloth.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_pointcache.h" +#include "BKE_softbody.h" #include "BKE_utildefines.h" + #include "blendef.h" /* needed for directory lookup */ @@ -58,19 +73,114 @@ #include <unistd.h> #endif +/* Creating ID's */ + +void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) +{ + ParticleSystemModifierData *psmd; + ModifierData *md; + int a; + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= sb; + pid->type= PTCACHE_TYPE_SOFTBODY; + pid->cache= sb->pointcache; + + if(sb->particles) { + psmd= psys_get_modifier(ob, sb->particles); + pid->stack_index= modifiers_indexInObject(ob, (ModifierData*)psmd); + } + else { + for(a=0, md=ob->modifiers.first; md; md=md->next, a++) { + if(md->type == eModifierType_Softbody) { + pid->stack_index = a; + break; + } + } + } +} + +void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= psys; + pid->type= PTCACHE_TYPE_PARTICLES; + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)psmd); + pid->cache= psys->pointcache; +} + +void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd) +{ + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= clmd; + pid->type= PTCACHE_TYPE_CLOTH; + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)clmd); + pid->cache= clmd->point_cache; +} + +void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) +{ + PTCacheID *pid; + ParticleSystem *psys; + ModifierData *md; + + lb->first= lb->last= NULL; + + if(ob->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, ob->soft); + BLI_addtail(lb, pid); + } + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_particles(pid, ob, psys); + BLI_addtail(lb, pid); + + if(psys->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, psys->soft); + BLI_addtail(lb, pid); + } + } + + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type == eModifierType_Cloth) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md); + BLI_addtail(lb, pid); + } + } +} + /* Takes an Object ID and returns a unique name - id: object id - cfra: frame for the cache, can be negative - stack_index: index in the modifier stack. we can have cache for more then one stack_index */ -static int ptcache_path(char *filename) +static int ptcache_path(PTCacheID *pid, char *filename) { + Library *lib; int i; - if (G.relbase_valid) { + + lib= (pid)? pid->ob->id.lib: NULL; + + if (G.relbase_valid || lib) { char dir[FILE_MAX], file[FILE_MAX]; /* we dont want the dir, only the file */ - - BLI_split_dirfile(G.sce, dir, file); + char *blendfilename; + + blendfilename= (lib)? lib->filename: G.sce; + + BLI_split_dirfile(blendfilename, dir, file); i = strlen(file); /* remove .blend */ @@ -78,7 +188,7 @@ static int ptcache_path(char *filename) file[i-6] = '\0'; sprintf(filename, "//"PTCACHE_PATH"%s/", file); /* add blend file name to pointcache dir */ - BLI_convertstringcode(filename, G.sce, 0); + BLI_convertstringcode(filename, blendfilename, 0); return strlen(filename); } @@ -87,7 +197,7 @@ static int ptcache_path(char *filename) return sprintf(filename, "%s"PTCACHE_PATH"%d/", btempdir, abs(getpid())); } -int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext) +static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) { int len=0; char *idname; @@ -99,10 +209,10 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i /* start with temp dir */ if (do_path) { - len = ptcache_path(filename); + len = ptcache_path(pid, filename); newname += len; } - idname = (id->name+2); + idname = (pid->ob->id.name+2); /* convert chars to hex so they are always a valid filename */ while('\0' != *idname) { sprintf(newname, "%02X", (char)(*idname++)); @@ -111,7 +221,7 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i } if (do_ext) { - sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, stack_index); /* always 6 chars */ + sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ len += 16; } @@ -119,31 +229,53 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i } /* youll need to close yourself after! */ -FILE *BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index) +PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra) { - /* mode is same as fopen's modes */ + PTCacheFile *pf; FILE *fp = NULL; char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; + /* don't allow writing for linked objects */ + if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE) + return NULL; + /*if (!G.relbase_valid) return NULL; *//* save blend file before using pointcache */ - BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); - if (mode=='r') { + if (mode==PTCACHE_FILE_READ) { if (!BLI_exists(filename)) { return NULL; } fp = fopen(filename, "rb"); - } else if (mode=='w') { + } else if (mode==PTCACHE_FILE_WRITE) { BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */ fp = fopen(filename, "wb"); } - if (!fp) { + if (!fp) return NULL; - } + + pf= MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile"); + pf->fp= fp; - return fp; + return pf; +} + +void BKE_ptcache_file_close(PTCacheFile *pf) +{ + fclose(pf->fp); + MEM_freeN(pf); +} + +int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot) +{ + return (fread(f, sizeof(float), tot, pf->fp) == tot); +} + +int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot) +{ + return (fwrite(f, sizeof(float), tot, pf->fp) == tot); } /* youll need to close yourself after! @@ -151,7 +283,7 @@ FILE *BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index) */ -void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) +void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) { int len; /* store the length of the string */ @@ -161,7 +293,14 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) char path[FILE_MAX]; char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; char path_full[(FILE_MAXDIR+FILE_MAXFILE)*2]; - + + if(!pid->cache) + return; + + /* don't allow clearing for linked objects */ + if(pid->ob->id.lib) + return; + /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */ /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ @@ -169,9 +308,9 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) case PTCACHE_CLEAR_ALL: case PTCACHE_CLEAR_BEFORE: case PTCACHE_CLEAR_AFTER: - ptcache_path(path); + ptcache_path(pid, path); - len = BKE_ptcache_id_filename(id, filename, cfra, stack_index, 0, 0); /* no path */ + len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */ dir = opendir(path); if (dir==NULL) @@ -206,22 +345,149 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) break; case PTCACHE_CLEAR_FRAME: - len = BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); /* no path */ + len = BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */ BLI_delete(filename, 0, 0); break; } - return; } -int BKE_ptcache_id_exist(struct ID *id, int cfra, int stack_index) +int BKE_ptcache_id_exist(PTCacheID *pid, int cfra) { char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; + + if(!pid->cache) + return 0; - BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); return BLI_exists(filename); } +void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale) +{ + Object *ob; + PointCache *cache; + float offset, time, nexttime; + + /* time handling for point cache: + * - simulation time is scaled by result of bsystem_time + * - for offsetting time only time offset is taken into account, since + * that's always the same and can't be animated. a timeoffset which + * varies over time is not simpe to support. + * - field and motion blur offsets are currently ignored, proper solution + * is probably to interpolate results from two frames for that .. + */ + + ob= pid->ob; + cache= pid->cache; + + if(timescale) { + time= bsystem_time(ob, cfra, 0.0f); + nexttime= bsystem_time(ob, cfra+1.0f, 0.0f); + + *timescale= MAX2(nexttime - time, 0.0f); + } + + if(startframe && endframe) { + *startframe= cache->startframe; + *endframe= cache->endframe; + + if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) { + offset= give_timeoffset(ob); + + *startframe += (int)(offset+0.5f); + *endframe += (int)(offset+0.5f); + } + } +} + +int BKE_ptcache_id_reset(PTCacheID *pid, int mode) +{ + PointCache *cache; + int reset, clear; + + if(!pid->cache) + return 0; + + cache= pid->cache; + reset= 0; + clear= 0; + + if(mode == PTCACHE_RESET_DEPSGRAPH) { + if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) { + reset= 1; + clear= 1; + } + else + cache->flag |= PTCACHE_OUTDATED; + } + else if(mode == PTCACHE_RESET_BAKED) { + if(!BKE_ptcache_get_continue_physics()) { + reset= 1; + clear= 1; + } + else + cache->flag |= PTCACHE_OUTDATED; + } + else if(mode == PTCACHE_RESET_OUTDATED) { + reset = 1; + + if(cache->flag & PTCACHE_OUTDATED) + if(!(cache->flag & PTCACHE_BAKED)) + clear= 1; + } + + if(reset) { + cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_SIMULATION_VALID); + cache->simframe= 0; + + if(pid->type == PTCACHE_TYPE_CLOTH) + cloth_free_modifier(pid->ob, pid->data); + else if(pid->type == PTCACHE_TYPE_SOFTBODY) + sbFreeSimulation(pid->data); + else if(pid->type == PTCACHE_TYPE_PARTICLES) + psys_reset(pid->data, PSYS_RESET_DEPSGRAPH); + } + if(clear) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + return (reset || clear); +} + +int BKE_ptcache_object_reset(Object *ob, int mode) +{ + PTCacheID pid; + ParticleSystem *psys; + ModifierData *md; + int reset; + + reset= 0; + + if(ob->soft) { + BKE_ptcache_id_from_softbody(&pid, ob, ob->soft); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + BKE_ptcache_id_from_particles(&pid, ob, psys); + reset |= BKE_ptcache_id_reset(&pid, mode); + + if(psys->soft) { + BKE_ptcache_id_from_softbody(&pid, ob, psys->soft); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + } + + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type == eModifierType_Cloth) { + BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + } + + return reset; +} + /* Use this when quitting blender, with unsaved files */ void BKE_ptcache_remove(void) { @@ -229,7 +495,7 @@ void BKE_ptcache_remove(void) char path_full[FILE_MAX]; int rmdir = 1; - ptcache_path(path); + ptcache_path(NULL, path); if (BLI_exists(path)) { /* TODO, Check with win32, probably needs last slash removed */ @@ -260,3 +526,58 @@ void BKE_ptcache_remove(void) BLI_delete(path, 1, 0); } } + +/* Continuous Interaction */ + +static int CONTINUE_PHYSICS = 0; + +void BKE_ptcache_set_continue_physics(int enable) +{ + Object *ob; + + if(CONTINUE_PHYSICS != enable) { + CONTINUE_PHYSICS = enable; + + if(CONTINUE_PHYSICS == 0) { + for(ob=G.main->object.first; ob; ob=ob->id.next) + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_OUTDATED)) + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + } +} + +int BKE_ptcache_get_continue_physics() +{ + return CONTINUE_PHYSICS; +} + +/* Point Cache */ + +PointCache *BKE_ptcache_add() +{ + PointCache *cache; + + cache= MEM_callocN(sizeof(PointCache), "PointCache"); + cache->startframe= 1; + cache->endframe= 250; + + return cache; +} + +void BKE_ptcache_free(PointCache *cache) +{ + MEM_freeN(cache); +} + +PointCache *BKE_ptcache_copy(PointCache *cache) +{ + PointCache *ncache; + + ncache= MEM_dupallocN(cache); + + ncache->flag= 0; + ncache->simframe= 0; + + return ncache; +} + |