Blender V2.61 - r43446

pointcache.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Campbell Barton <ideasman42@gmail.com>
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <sys/stat.h>
00035 #include <sys/types.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "DNA_ID.h"
00040 #include "DNA_cloth_types.h"
00041 #include "DNA_dynamicpaint_types.h"
00042 #include "DNA_modifier_types.h"
00043 #include "DNA_object_types.h"
00044 #include "DNA_object_force.h"
00045 #include "DNA_particle_types.h"
00046 #include "DNA_scene_types.h"
00047 #include "DNA_smoke_types.h"
00048 
00049 #include "BLI_blenlib.h"
00050 #include "BLI_threads.h"
00051 #include "BLI_math.h"
00052 #include "BLI_utildefines.h"
00053 
00054 #include "PIL_time.h"
00055 
00056 #include "WM_api.h"
00057 
00058 #include "BKE_anim.h"
00059 #include "BKE_blender.h"
00060 #include "BKE_cloth.h"
00061 #include "BKE_depsgraph.h"
00062 #include "BKE_dynamicpaint.h"
00063 #include "BKE_global.h"
00064 #include "BKE_library.h"
00065 #include "BKE_main.h"
00066 #include "BKE_object.h"
00067 #include "BKE_particle.h"
00068 #include "BKE_pointcache.h"
00069 #include "BKE_scene.h"
00070 #include "BKE_smoke.h"
00071 #include "BKE_softbody.h"
00072 #include "BKE_utildefines.h"
00073 
00074 #include "BIK_api.h"
00075 
00076 /* both in intern */
00077 #include "smoke_API.h"
00078 
00079 #ifdef WITH_LZO
00080 #include "minilzo.h"
00081 #else
00082 /* used for non-lzo cases */
00083 #define LZO_OUT_LEN(size)     ((size) + (size) / 16 + 64 + 3)
00084 #endif
00085 
00086 #ifdef WITH_LZMA
00087 #include "LzmaLib.h"
00088 #endif
00089 
00090 /* needed for directory lookup */
00091 /* untitled blend's need getpid for a unique name */
00092 #ifndef WIN32
00093   #include <dirent.h>
00094 #include <unistd.h>
00095 #else
00096 #include <process.h>
00097   #include "BLI_winstuff.h"
00098 #endif
00099 
00100 #define PTCACHE_DATA_FROM(data, type, from)     if(data[type]) { memcpy(data[type], from, ptcache_data_size[type]); }
00101 #define PTCACHE_DATA_TO(data, type, index, to)  if(data[type]) { memcpy(to, (char*)data[type] + (index ? index * ptcache_data_size[type] : 0), ptcache_data_size[type]); }
00102 
00103 /* could be made into a pointcache option */
00104 #define DURIAN_POINTCACHE_LIB_OK 1
00105 
00106 static int ptcache_data_size[] = {  
00107         sizeof(unsigned int), // BPHYS_DATA_INDEX
00108         3 * sizeof(float), // BPHYS_DATA_LOCATION
00109         3 * sizeof(float), // BPHYS_DATA_VELOCITY
00110         4 * sizeof(float), // BPHYS_DATA_ROTATION
00111         3 * sizeof(float), // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST
00112         sizeof(float), // BPHYS_DATA_SIZE
00113         3 * sizeof(float), // BPHYS_DATA_TIMES
00114         sizeof(BoidData) // case BPHYS_DATA_BOIDS
00115 };
00116 
00117 static int ptcache_extra_datasize[] = {
00118     0,
00119     sizeof(ParticleSpring)
00120 };
00121 
00122 /* forward declerations */
00123 static int ptcache_file_compressed_read(PTCacheFile *pf, unsigned char *result, unsigned int len);
00124 static int ptcache_file_compressed_write(PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode);
00125 static int ptcache_file_write(PTCacheFile *pf, const void *f, unsigned int tot, unsigned int size);
00126 static int ptcache_file_read(PTCacheFile *pf, void *f, unsigned int tot, unsigned int size);
00127 
00128 /* Common functions */
00129 static int ptcache_basic_header_read(PTCacheFile *pf)
00130 {
00131     int error=0;
00132 
00133     /* Custom functions should read these basic elements too! */
00134     if(!error && !fread(&pf->totpoint, sizeof(unsigned int), 1, pf->fp))
00135         error = 1;
00136     
00137     if(!error && !fread(&pf->data_types, sizeof(unsigned int), 1, pf->fp))
00138         error = 1;
00139 
00140     return !error;
00141 }
00142 static int ptcache_basic_header_write(PTCacheFile *pf)
00143 {
00144     /* Custom functions should write these basic elements too! */
00145     if(!fwrite(&pf->totpoint, sizeof(unsigned int), 1, pf->fp))
00146         return 0;
00147     
00148     if(!fwrite(&pf->data_types, sizeof(unsigned int), 1, pf->fp))
00149         return 0;
00150 
00151     return 1;
00152 }
00153 /* Softbody functions */
00154 static int  ptcache_softbody_write(int index, void *soft_v, void **data, int UNUSED(cfra))
00155 {
00156     SoftBody *soft= soft_v;
00157     BodyPoint *bp = soft->bpoint + index;
00158 
00159     PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, bp->pos);
00160     PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, bp->vec);
00161 
00162     return 1;
00163 }
00164 static void ptcache_softbody_read(int index, void *soft_v, void **data, float UNUSED(cfra), float *old_data)
00165 {
00166     SoftBody *soft= soft_v;
00167     BodyPoint *bp = soft->bpoint + index;
00168 
00169     if(old_data) {
00170         memcpy(bp->pos, data, 3 * sizeof(float));
00171         memcpy(bp->vec, data + 3, 3 * sizeof(float));
00172     }
00173     else {
00174         PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, bp->pos);
00175         PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, bp->vec);
00176     }
00177 }
00178 static void ptcache_softbody_interpolate(int index, void *soft_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
00179 {
00180     SoftBody *soft= soft_v;
00181     BodyPoint *bp = soft->bpoint + index;
00182     ParticleKey keys[4];
00183     float dfra;
00184 
00185     if(cfra1 == cfra2)
00186         return;
00187 
00188     copy_v3_v3(keys[1].co, bp->pos);
00189     copy_v3_v3(keys[1].vel, bp->vec);
00190 
00191     if(old_data) {
00192         memcpy(keys[2].co, old_data, 3 * sizeof(float));
00193         memcpy(keys[2].vel, old_data + 3, 3 * sizeof(float));
00194     }
00195     else
00196         BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
00197 
00198     dfra = cfra2 - cfra1;
00199 
00200     mul_v3_fl(keys[1].vel, dfra);
00201     mul_v3_fl(keys[2].vel, dfra);
00202 
00203     psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
00204 
00205     mul_v3_fl(keys->vel, 1.0f / dfra);
00206 
00207     copy_v3_v3(bp->pos, keys->co);
00208     copy_v3_v3(bp->vec, keys->vel);
00209 }
00210 static int  ptcache_softbody_totpoint(void *soft_v, int UNUSED(cfra))
00211 {
00212     SoftBody *soft= soft_v;
00213     return soft->totpoint;
00214 }
00215 /* Particle functions */
00216 void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
00217 {
00218     PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
00219     PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, index, key->vel);
00220     
00221     /* no rotation info, so make something nice up */
00222     if(data[BPHYS_DATA_ROTATION]==NULL) {
00223         vec_to_quat( key->rot, key->vel, OB_NEGX, OB_POSZ);
00224     }
00225     else {
00226         PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, key->rot);
00227     }
00228 
00229     PTCACHE_DATA_TO(data, BPHYS_DATA_AVELOCITY, index, key->ave);
00230     key->time = time;
00231 }
00232 static int  ptcache_particle_write(int index, void *psys_v, void **data, int cfra)
00233 {
00234     ParticleSystem *psys= psys_v;
00235     ParticleData *pa = psys->particles + index;
00236     BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
00237     float times[3];
00238     int step = psys->pointcache->step;
00239 
00240     /* No need to store unborn or died particles outside cache step bounds */
00241     if(data[BPHYS_DATA_INDEX] && (cfra < pa->time - step || cfra > pa->dietime + step))
00242         return 0;
00243 
00244     times[0]= pa->time;
00245     times[1]= pa->dietime;
00246     times[2]= pa->lifetime;
00247 
00248     PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index);
00249     PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co);
00250     PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, pa->state.vel);
00251     PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, pa->state.rot);
00252     PTCACHE_DATA_FROM(data, BPHYS_DATA_AVELOCITY, pa->state.ave);
00253     PTCACHE_DATA_FROM(data, BPHYS_DATA_SIZE, &pa->size);
00254     PTCACHE_DATA_FROM(data, BPHYS_DATA_TIMES, times);
00255 
00256     if(boid)
00257         PTCACHE_DATA_FROM(data, BPHYS_DATA_BOIDS, &boid->data);
00258 
00259     /* return flag 1+1=2 for newly born particles to copy exact birth location to previously cached frame */
00260     return 1 + (pa->state.time >= pa->time && pa->prev_state.time <= pa->time);
00261 }
00262 static void ptcache_particle_read(int index, void *psys_v, void **data, float cfra, float *old_data)
00263 {
00264     ParticleSystem *psys= psys_v;
00265     ParticleData *pa;
00266     BoidParticle *boid;
00267     float timestep = 0.04f*psys->part->timetweak;
00268 
00269     if(index >= psys->totpart)
00270         return;
00271 
00272     pa = psys->particles + index;
00273     boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
00274 
00275     if(cfra > pa->state.time)
00276         memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey));
00277 
00278     if(old_data){
00279         /* old format cache */
00280         memcpy(&pa->state, old_data, sizeof(ParticleKey));
00281         return;
00282     }
00283 
00284     BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra);
00285 
00286     /* set frames cached before birth to birth time */
00287     if(cfra < pa->time)
00288         pa->state.time = pa->time;
00289     else if(cfra > pa->dietime)
00290         pa->state.time = pa->dietime;
00291 
00292     if(data[BPHYS_DATA_SIZE])
00293         PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size);
00294     
00295     if(data[BPHYS_DATA_TIMES]) {
00296         float times[3];
00297         PTCACHE_DATA_TO(data, BPHYS_DATA_TIMES, 0, &times);
00298         pa->time = times[0];
00299         pa->dietime = times[1];
00300         pa->lifetime = times[2];
00301     }
00302 
00303     if(boid)
00304         PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data);
00305 
00306     /* determine velocity from previous location */
00307     if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
00308         if(cfra > pa->prev_state.time) {
00309             sub_v3_v3v3(pa->state.vel, pa->state.co, pa->prev_state.co);
00310             mul_v3_fl(pa->state.vel, (cfra - pa->prev_state.time) * timestep);
00311         }
00312         else {
00313             sub_v3_v3v3(pa->state.vel, pa->prev_state.co, pa->state.co);
00314             mul_v3_fl(pa->state.vel, (pa->prev_state.time - cfra) * timestep);
00315         }
00316     }
00317 
00318     /* determine rotation from velocity */
00319     if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
00320         vec_to_quat( pa->state.rot,pa->state.vel, OB_NEGX, OB_POSZ);
00321     }
00322 }
00323 static void ptcache_particle_interpolate(int index, void *psys_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
00324 {
00325     ParticleSystem *psys= psys_v;
00326     ParticleData *pa;
00327     ParticleKey keys[4];
00328     float dfra, timestep = 0.04f*psys->part->timetweak;
00329 
00330     if(index >= psys->totpart)
00331         return;
00332 
00333     pa = psys->particles + index;
00334 
00335     /* particle wasn't read from first cache so can't interpolate */
00336     if((int)cfra1 < pa->time - psys->pointcache->step || (int)cfra1 > pa->dietime + psys->pointcache->step)
00337         return;
00338 
00339     cfra = MIN2(cfra, pa->dietime);
00340     cfra1 = MIN2(cfra1, pa->dietime);
00341     cfra2 = MIN2(cfra2, pa->dietime);
00342 
00343     if(cfra1 == cfra2)
00344         return;
00345 
00346     memcpy(keys+1, &pa->state, sizeof(ParticleKey));
00347     if(old_data)
00348         memcpy(keys+2, old_data, sizeof(ParticleKey));
00349     else
00350         BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
00351 
00352     /* determine velocity from previous location */
00353     if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
00354         if(keys[1].time > keys[2].time) {
00355             sub_v3_v3v3(keys[2].vel, keys[1].co, keys[2].co);
00356             mul_v3_fl(keys[2].vel, (keys[1].time - keys[2].time) * timestep);
00357         }
00358         else {
00359             sub_v3_v3v3(keys[2].vel, keys[2].co, keys[1].co);
00360             mul_v3_fl(keys[2].vel, (keys[2].time - keys[1].time) * timestep);
00361         }
00362     }
00363 
00364     /* determine rotation from velocity */
00365     if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
00366         vec_to_quat( keys[2].rot,keys[2].vel, OB_NEGX, OB_POSZ);
00367     }
00368 
00369     if(cfra > pa->time)
00370         cfra1 = MAX2(cfra1, pa->time);
00371 
00372     dfra = cfra2 - cfra1;
00373 
00374     mul_v3_fl(keys[1].vel, dfra * timestep);
00375     mul_v3_fl(keys[2].vel, dfra * timestep);
00376 
00377     psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1);
00378     interp_qt_qtqt(pa->state.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
00379 
00380     mul_v3_fl(pa->state.vel, 1.f / (dfra * timestep));
00381 
00382     pa->state.time = cfra;
00383 }
00384 
00385 static int  ptcache_particle_totpoint(void *psys_v, int UNUSED(cfra))
00386 {
00387     ParticleSystem *psys = psys_v;
00388     return psys->totpart;
00389 }
00390 static int  ptcache_particle_totwrite(void *psys_v, int cfra)
00391 {
00392     ParticleSystem *psys = psys_v;
00393     ParticleData *pa= psys->particles;
00394     int p, step = psys->pointcache->step;
00395     int totwrite = 0;
00396 
00397     if(cfra == 0)
00398         return psys->totpart;
00399 
00400     for(p=0; p<psys->totpart; p++,pa++)
00401         totwrite += (cfra >= pa->time - step && cfra <= pa->dietime + step);
00402 
00403     return totwrite;
00404 }
00405 
00406 static void ptcache_particle_extra_write(void *psys_v, PTCacheMem *pm, int UNUSED(cfra))
00407 {
00408     ParticleSystem *psys = psys_v;
00409     PTCacheExtra *extra = NULL;
00410 
00411     if(psys->part->phystype == PART_PHYS_FLUID &&
00412         psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS &&
00413         psys->tot_fluidsprings && psys->fluid_springs) {
00414 
00415         extra = MEM_callocN(sizeof(PTCacheExtra), "Point cache: fluid extra data");
00416 
00417         extra->type = BPHYS_EXTRA_FLUID_SPRINGS;
00418         extra->totdata = psys->tot_fluidsprings;
00419 
00420         extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], "Point cache: extra data");
00421         memcpy(extra->data, psys->fluid_springs, extra->totdata * ptcache_extra_datasize[extra->type]);
00422 
00423         BLI_addtail(&pm->extradata, extra);
00424     }
00425 }
00426 
00427 static void ptcache_particle_extra_read(void *psys_v, PTCacheMem *pm, float UNUSED(cfra))
00428 {
00429     ParticleSystem *psys = psys_v;
00430     PTCacheExtra *extra = pm->extradata.first;
00431 
00432     for(; extra; extra=extra->next) {
00433         switch(extra->type) {
00434             case BPHYS_EXTRA_FLUID_SPRINGS:
00435             {
00436                 if(psys->fluid_springs)
00437                     MEM_freeN(psys->fluid_springs);
00438 
00439                 psys->fluid_springs = MEM_dupallocN(extra->data);
00440                 psys->tot_fluidsprings = psys->alloc_fluidsprings = extra->totdata;
00441                 break;
00442             }
00443         }
00444     }
00445 }
00446 
00447 /* Cloth functions */
00448 static int  ptcache_cloth_write(int index, void *cloth_v, void **data, int UNUSED(cfra))
00449 {
00450     ClothModifierData *clmd= cloth_v;
00451     Cloth *cloth= clmd->clothObject;
00452     ClothVertex *vert = cloth->verts + index;
00453 
00454     PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, vert->x);
00455     PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, vert->v);
00456     PTCACHE_DATA_FROM(data, BPHYS_DATA_XCONST, vert->xconst);
00457 
00458     return 1;
00459 }
00460 static void ptcache_cloth_read(int index, void *cloth_v, void **data, float UNUSED(cfra), float *old_data)
00461 {
00462     ClothModifierData *clmd= cloth_v;
00463     Cloth *cloth= clmd->clothObject;
00464     ClothVertex *vert = cloth->verts + index;
00465     
00466     if(old_data) {
00467         memcpy(vert->x, data, 3 * sizeof(float));
00468         memcpy(vert->xconst, data + 3, 3 * sizeof(float));
00469         memcpy(vert->v, data + 6, 3 * sizeof(float));
00470     }
00471     else {
00472         PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, vert->x);
00473         PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, vert->v);
00474         PTCACHE_DATA_TO(data, BPHYS_DATA_XCONST, 0, vert->xconst);
00475     }
00476 }
00477 static void ptcache_cloth_interpolate(int index, void *cloth_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
00478 {
00479     ClothModifierData *clmd= cloth_v;
00480     Cloth *cloth= clmd->clothObject;
00481     ClothVertex *vert = cloth->verts + index;
00482     ParticleKey keys[4];
00483     float dfra;
00484 
00485     if(cfra1 == cfra2)
00486         return;
00487 
00488     copy_v3_v3(keys[1].co, vert->x);
00489     copy_v3_v3(keys[1].vel, vert->v);
00490 
00491     if(old_data) {
00492         memcpy(keys[2].co, old_data, 3 * sizeof(float));
00493         memcpy(keys[2].vel, old_data + 6, 3 * sizeof(float));
00494     }
00495     else
00496         BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
00497 
00498     dfra = cfra2 - cfra1;
00499 
00500     mul_v3_fl(keys[1].vel, dfra);
00501     mul_v3_fl(keys[2].vel, dfra);
00502 
00503     psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
00504 
00505     mul_v3_fl(keys->vel, 1.0f / dfra);
00506 
00507     copy_v3_v3(vert->x, keys->co);
00508     copy_v3_v3(vert->v, keys->vel);
00509 
00510     /* should vert->xconst be interpolated somehow too? - jahka */
00511 }
00512 
00513 static int  ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra))
00514 {
00515     ClothModifierData *clmd= cloth_v;
00516     return clmd->clothObject ? clmd->clothObject->numverts : 0;
00517 }
00518 
00519 #ifdef WITH_SMOKE
00520 /* Smoke functions */
00521 static int  ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
00522 {
00523     SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
00524     SmokeDomainSettings *sds = smd->domain;
00525     
00526     if(sds->fluid) {
00527         return sds->res[0]*sds->res[1]*sds->res[2];
00528     }
00529     else
00530         return 0;
00531 }
00532 static int  ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
00533 {   
00534     SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
00535     SmokeDomainSettings *sds = smd->domain;
00536     int ret = 0;
00537     
00538     if(sds->fluid) {
00539         size_t res = sds->res[0]*sds->res[1]*sds->res[2];
00540         float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
00541         unsigned char *obstacles;
00542         unsigned int in_len = sizeof(float)*(unsigned int)res;
00543         unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer");
00544         //int mode = res >= 1000000 ? 2 : 1;
00545         int mode=1;     // light
00546         if (sds->cache_comp == SM_CACHE_HEAVY) mode=2;  // heavy
00547 
00548         smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
00549 
00550         ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
00551         ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
00552         ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len, out, mode); 
00553         ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
00554         ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
00555         ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
00556         ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
00557         ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
00558         ptcache_file_compressed_write(pf, (unsigned char *)vxold, in_len, out, mode);
00559         ptcache_file_compressed_write(pf, (unsigned char *)vyold, in_len, out, mode);
00560         ptcache_file_compressed_write(pf, (unsigned char *)vzold, in_len, out, mode);
00561         ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
00562         ptcache_file_write(pf, &dt, 1, sizeof(float));
00563         ptcache_file_write(pf, &dx, 1, sizeof(float));
00564 
00565         MEM_freeN(out);
00566         
00567         ret = 1;
00568     }
00569 
00570     if(sds->wt) {
00571         int res_big_array[3];
00572         int res_big;
00573         int res = sds->res[0]*sds->res[1]*sds->res[2];
00574         float *dens, *densold, *tcu, *tcv, *tcw;
00575         unsigned int in_len = sizeof(float)*(unsigned int)res;
00576         unsigned int in_len_big;
00577         unsigned char *out;
00578         int mode;
00579 
00580         smoke_turbulence_get_res(sds->wt, res_big_array);
00581         res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
00582         //mode =  res_big >= 1000000 ? 2 : 1;
00583         mode = 1;   // light
00584         if (sds->cache_high_comp == SM_CACHE_HEAVY) mode=2; // heavy
00585 
00586         in_len_big = sizeof(float) * (unsigned int)res_big;
00587 
00588         smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
00589 
00590         out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
00591         ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
00592         ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len_big, out, mode); 
00593         MEM_freeN(out);
00594 
00595         out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
00596         ptcache_file_compressed_write(pf, (unsigned char *)tcu, in_len, out, mode);
00597         ptcache_file_compressed_write(pf, (unsigned char *)tcv, in_len, out, mode);
00598         ptcache_file_compressed_write(pf, (unsigned char *)tcw, in_len, out, mode);
00599         MEM_freeN(out);
00600         
00601         ret = 1;
00602     }
00603 
00604     return ret;
00605 }
00606 static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
00607 {
00608     SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
00609     SmokeDomainSettings *sds = smd->domain;
00610     
00611     if(sds->fluid) {
00612         size_t res = sds->res[0]*sds->res[1]*sds->res[2];
00613         float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
00614         unsigned char *obstacles;
00615         unsigned int out_len = (unsigned int)res * sizeof(float);
00616         
00617         smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
00618 
00619         ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
00620         ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len);
00621         ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len);
00622         ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
00623         ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
00624         ptcache_file_compressed_read(pf, (unsigned char*)vx, out_len);
00625         ptcache_file_compressed_read(pf, (unsigned char*)vy, out_len);
00626         ptcache_file_compressed_read(pf, (unsigned char*)vz, out_len);
00627         ptcache_file_compressed_read(pf, (unsigned char*)vxold, out_len);
00628         ptcache_file_compressed_read(pf, (unsigned char*)vyold, out_len);
00629         ptcache_file_compressed_read(pf, (unsigned char*)vzold, out_len);
00630         ptcache_file_compressed_read(pf, (unsigned char*)obstacles, (unsigned int)res);
00631         ptcache_file_read(pf, &dt, 1, sizeof(float));
00632         ptcache_file_read(pf, &dx, 1, sizeof(float));
00633 
00634         if(pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
00635             int res = sds->res[0]*sds->res[1]*sds->res[2];
00636             int res_big, res_big_array[3];
00637             float *dens, *densold, *tcu, *tcv, *tcw;
00638             unsigned int out_len = sizeof(float)*(unsigned int)res;
00639             unsigned int out_len_big;
00640 
00641             smoke_turbulence_get_res(sds->wt, res_big_array);
00642             res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
00643             out_len_big = sizeof(float) * (unsigned int)res_big;
00644 
00645             smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
00646 
00647             ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len_big);
00648             ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len_big);
00649 
00650             ptcache_file_compressed_read(pf, (unsigned char*)tcu, out_len);
00651             ptcache_file_compressed_read(pf, (unsigned char*)tcv, out_len);
00652             ptcache_file_compressed_read(pf, (unsigned char*)tcw, out_len);
00653         }
00654     }
00655 
00656     return 1;
00657 }
00658 #else // WITH_SMOKE
00659 static int  ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; }
00660 static int  ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; }
00661 static int  ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; }
00662 #endif // WITH_SMOKE
00663 
00664 static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra))
00665 {
00666     DynamicPaintSurface *surface = (DynamicPaintSurface*)sd;
00667 
00668     if (!surface->data) return 0;
00669     else return surface->data->total_points;
00670 }
00671 
00672 #define DPAINT_CACHE_VERSION "1.01"
00673 
00674 static int  ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v)
00675 {   
00676     DynamicPaintSurface *surface = (DynamicPaintSurface*)dp_v;
00677     int cache_compress = 1;
00678 
00679     /* version header */
00680     ptcache_file_write(pf, DPAINT_CACHE_VERSION, 1, sizeof(char)*4);
00681 
00682     if(surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
00683         int total_points=surface->data->total_points;
00684         unsigned int in_len;
00685         unsigned char *out;
00686 
00687         /* cache type */
00688         ptcache_file_write(pf, &surface->type, 1, sizeof(int));
00689 
00690         if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
00691             in_len = sizeof(PaintPoint)*total_points;
00692         else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
00693                  surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
00694             in_len = sizeof(float)*total_points;
00695         else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
00696             in_len = sizeof(PaintWavePoint)*total_points;
00697         else return 0;
00698 
00699         out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
00700 
00701         ptcache_file_compressed_write(pf, (unsigned char *)surface->data->type_data, in_len, out, cache_compress);
00702         MEM_freeN(out);
00703 
00704     }
00705     return 1;
00706 }
00707 static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
00708 {
00709     DynamicPaintSurface *surface = (DynamicPaintSurface*)dp_v;
00710     char version[4];
00711     
00712     /* version header */
00713     ptcache_file_read(pf, version, 1, sizeof(char)*4);
00714     if (strncmp(version, DPAINT_CACHE_VERSION,4)) {printf("Dynamic Paint: Invalid cache version: %s!\n",version); return 0;}
00715 
00716     if(surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
00717         unsigned int data_len;
00718         int surface_type;
00719 
00720         /* cache type */
00721         ptcache_file_read(pf, &surface_type, 1, sizeof(int));
00722 
00723         if (surface_type != surface->type)
00724             return 0;
00725 
00726         /* read surface data */
00727         if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
00728             data_len = sizeof(PaintPoint);
00729         else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
00730                  surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
00731             data_len = sizeof(float);
00732         else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
00733             data_len = sizeof(PaintWavePoint);
00734         else return 0;
00735 
00736         ptcache_file_compressed_read(pf, (unsigned char*)surface->data->type_data, data_len*surface->data->total_points);
00737 
00738     }
00739     return 1;
00740 }
00741 
00742 /* Creating ID's */
00743 void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
00744 {
00745     memset(pid, 0, sizeof(PTCacheID));
00746 
00747     pid->ob= ob;
00748     pid->calldata= sb;
00749     pid->type= PTCACHE_TYPE_SOFTBODY;
00750     pid->cache= sb->pointcache;
00751     pid->cache_ptr= &sb->pointcache;
00752     pid->ptcaches= &sb->ptcaches;
00753     pid->totpoint= pid->totwrite= ptcache_softbody_totpoint;
00754 
00755     pid->write_point            = ptcache_softbody_write;
00756     pid->read_point             = ptcache_softbody_read;
00757     pid->interpolate_point      = ptcache_softbody_interpolate;
00758 
00759     pid->write_stream           = NULL;
00760     pid->read_stream            = NULL;
00761 
00762     pid->write_extra_data       = NULL;
00763     pid->read_extra_data        = NULL;
00764     pid->interpolate_extra_data = NULL;
00765 
00766     pid->write_header           = ptcache_basic_header_write;
00767     pid->read_header            = ptcache_basic_header_read;
00768 
00769     pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY);
00770     pid->info_types= 0;
00771 
00772     pid->stack_index = pid->cache->index;
00773 
00774     pid->default_step = 10;
00775     pid->max_step = 20;
00776 }
00777 void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
00778 {
00779     memset(pid, 0, sizeof(PTCacheID));
00780 
00781     pid->ob= ob;
00782     pid->calldata= psys;
00783     pid->type= PTCACHE_TYPE_PARTICLES;
00784     pid->stack_index= psys->pointcache->index;
00785     pid->cache= psys->pointcache;
00786     pid->cache_ptr= &psys->pointcache;
00787     pid->ptcaches= &psys->ptcaches;
00788 
00789     if(psys->part->type != PART_HAIR)
00790         pid->flag |= PTCACHE_VEL_PER_SEC;
00791 
00792     pid->totpoint               = ptcache_particle_totpoint;
00793     pid->totwrite               = ptcache_particle_totwrite;
00794 
00795     pid->write_point                = ptcache_particle_write;
00796     pid->read_point             = ptcache_particle_read;
00797     pid->interpolate_point      = ptcache_particle_interpolate;
00798 
00799     pid->write_stream           = NULL;
00800     pid->read_stream            = NULL;
00801 
00802     pid->write_extra_data       = NULL;
00803     pid->read_extra_data        = NULL;
00804     pid->interpolate_extra_data = NULL;
00805 
00806     pid->write_header           = ptcache_basic_header_write;
00807     pid->read_header            = ptcache_basic_header_read;
00808 
00809     pid->data_types = (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_INDEX);
00810 
00811     if(psys->part->phystype == PART_PHYS_BOIDS)
00812         pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS);
00813     else if(psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS) {
00814         pid->write_extra_data = ptcache_particle_extra_write;
00815         pid->read_extra_data = ptcache_particle_extra_read;
00816     }
00817 
00818     if(psys->part->rotmode!=PART_ROT_VEL
00819         || psys->part->avemode!=PART_AVE_SPIN || psys->part->avefac!=0.0f)
00820         pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION);
00821 
00822     if(psys->part->flag & PART_ROT_DYN)
00823         pid->data_types|= (1<<BPHYS_DATA_ROTATION);
00824 
00825     pid->info_types= (1<<BPHYS_DATA_TIMES);
00826 
00827     pid->default_step = 10;
00828     pid->max_step = 20;
00829 }
00830 void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
00831 {
00832     memset(pid, 0, sizeof(PTCacheID));
00833 
00834     pid->ob= ob;
00835     pid->calldata= clmd;
00836     pid->type= PTCACHE_TYPE_CLOTH;
00837     pid->stack_index= clmd->point_cache->index;
00838     pid->cache= clmd->point_cache;
00839     pid->cache_ptr= &clmd->point_cache;
00840     pid->ptcaches= &clmd->ptcaches;
00841     pid->totpoint= pid->totwrite= ptcache_cloth_totpoint;
00842 
00843     pid->write_point            = ptcache_cloth_write;
00844     pid->read_point             = ptcache_cloth_read;
00845     pid->interpolate_point      = ptcache_cloth_interpolate;
00846 
00847     pid->write_stream           = NULL;
00848     pid->read_stream            = NULL;
00849 
00850     pid->write_extra_data       = NULL;
00851     pid->read_extra_data        = NULL;
00852     pid->interpolate_extra_data = NULL;
00853 
00854     pid->write_header           = ptcache_basic_header_write;
00855     pid->read_header            = ptcache_basic_header_read;
00856 
00857     pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_XCONST);
00858     pid->info_types= 0;
00859 
00860     pid->default_step = 1;
00861     pid->max_step = 1;
00862 }
00863 void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd)
00864 {
00865     SmokeDomainSettings *sds = smd->domain;
00866 
00867     memset(pid, 0, sizeof(PTCacheID));
00868 
00869     pid->ob= ob;
00870     pid->calldata= smd;
00871     
00872     pid->type= PTCACHE_TYPE_SMOKE_DOMAIN;
00873     pid->stack_index= sds->point_cache[0]->index;
00874 
00875     pid->cache= sds->point_cache[0];
00876     pid->cache_ptr= &(sds->point_cache[0]);
00877     pid->ptcaches= &(sds->ptcaches[0]);
00878 
00879     pid->totpoint= pid->totwrite= ptcache_smoke_totpoint;
00880 
00881     pid->write_point            = NULL;
00882     pid->read_point             = NULL;
00883     pid->interpolate_point      = NULL;
00884 
00885     pid->read_stream            = ptcache_smoke_read;
00886     pid->write_stream           = ptcache_smoke_write;
00887 
00888     pid->write_extra_data       = NULL;
00889     pid->read_extra_data        = NULL;
00890     pid->interpolate_extra_data = NULL;
00891 
00892     pid->write_header           = ptcache_basic_header_write;
00893     pid->read_header            = ptcache_basic_header_read;
00894 
00895     pid->data_types= 0;
00896     pid->info_types= 0;
00897 
00898     if(sds->fluid)
00899         pid->data_types |= (1<<BPHYS_DATA_SMOKE_LOW);
00900     if(sds->wt)
00901         pid->data_types |= (1<<BPHYS_DATA_SMOKE_HIGH);
00902 
00903     pid->default_step = 1;
00904     pid->max_step = 1;
00905 }
00906 
00907 void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
00908 {
00909 
00910     memset(pid, 0, sizeof(PTCacheID));
00911 
00912     pid->ob= ob;
00913     pid->calldata= surface;
00914     pid->type= PTCACHE_TYPE_DYNAMICPAINT;
00915     pid->cache= surface->pointcache;
00916     pid->cache_ptr= &surface->pointcache;
00917     pid->ptcaches= &surface->ptcaches;
00918     pid->totpoint= pid->totwrite= ptcache_dynamicpaint_totpoint;
00919 
00920     pid->write_point            = NULL;
00921     pid->read_point             = NULL;
00922     pid->interpolate_point      = NULL;
00923 
00924     pid->write_stream           = ptcache_dynamicpaint_write;
00925     pid->read_stream            = ptcache_dynamicpaint_read;
00926 
00927     pid->write_extra_data       = NULL;
00928     pid->read_extra_data        = NULL;
00929     pid->interpolate_extra_data = NULL;
00930 
00931     pid->write_header           = ptcache_basic_header_write;
00932     pid->read_header            = ptcache_basic_header_read;
00933 
00934     pid->data_types= BPHYS_DATA_DYNAMICPAINT;
00935     pid->info_types= 0;
00936 
00937     pid->stack_index = pid->cache->index;
00938 
00939     pid->default_step = 1;
00940     pid->max_step = 1;
00941 }
00942 
00943 void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
00944 {
00945     PTCacheID *pid;
00946     ParticleSystem *psys;
00947     ModifierData *md;
00948 
00949     lb->first= lb->last= NULL;
00950 
00951     if(ob->soft) {
00952         pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
00953         BKE_ptcache_id_from_softbody(pid, ob, ob->soft);
00954         BLI_addtail(lb, pid);
00955     }
00956 
00957     for(psys=ob->particlesystem.first; psys; psys=psys->next) {
00958         if(psys->part==NULL)
00959             continue;
00960         
00961         /* check to make sure point cache is actually used by the particles */
00962         if(ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
00963             continue;
00964 
00965         /* hair needs to be included in id-list for cache edit mode to work */
00966         /* if(psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DYNAMICS)==0) */
00967         /*  continue; */
00968             
00969         if(psys->part->type == PART_FLUID)
00970             continue;
00971 
00972         pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
00973         BKE_ptcache_id_from_particles(pid, ob, psys);
00974         BLI_addtail(lb, pid);
00975     }
00976 
00977     for(md=ob->modifiers.first; md; md=md->next) {
00978         if(md->type == eModifierType_Cloth) {
00979             pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
00980             BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md);
00981             BLI_addtail(lb, pid);
00982         }
00983         else if(md->type == eModifierType_Smoke) {
00984             SmokeModifierData *smd = (SmokeModifierData *)md;
00985             if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
00986             {
00987                 pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
00988                 BKE_ptcache_id_from_smoke(pid, ob, (SmokeModifierData*)md);
00989                 BLI_addtail(lb, pid);
00990             }
00991         }
00992         else if(md->type == eModifierType_DynamicPaint) {
00993             DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
00994             if(pmd->canvas)
00995             {
00996                 DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
00997 
00998                 for (; surface; surface=surface->next) {
00999                     pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
01000                     BKE_ptcache_id_from_dynamicpaint(pid, ob, surface);
01001                     BLI_addtail(lb, pid);
01002                 }
01003             }
01004         }
01005     }
01006 
01007     if(scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
01008         ListBase *lb_dupli_ob;
01009 
01010         if((lb_dupli_ob=object_duplilist(scene, ob))) {
01011             DupliObject *dob;
01012             for(dob= lb_dupli_ob->first; dob; dob= dob->next) {
01013                 if(dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */
01014                     ListBase lb_dupli_pid;
01015                     BKE_ptcache_ids_from_object(&lb_dupli_pid, dob->ob, scene, duplis);
01016                     BLI_movelisttolist(lb, &lb_dupli_pid);
01017                     if(lb_dupli_pid.first)
01018                         printf("Adding Dupli\n");
01019                 }
01020             }
01021 
01022             free_object_duplilist(lb_dupli_ob); /* does restore */
01023         }
01024     }
01025 }
01026 
01027 /* File handling */
01028 
01029 /*  Takes an Object ID and returns a unique name
01030     - id: object id
01031     - cfra: frame for the cache, can be negative
01032     - stack_index: index in the modifier stack. we can have cache for more then one stack_index
01033 */
01034 
01035 #define MAX_PTCACHE_PATH FILE_MAX
01036 #define MAX_PTCACHE_FILE ((FILE_MAX)*2)
01037 
01038 static int ptcache_path(PTCacheID *pid, char *filename)
01039 {
01040     Library *lib= (pid->ob)? pid->ob->id.lib: NULL;
01041     const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: G.main->name;
01042     size_t i;
01043 
01044     if(pid->cache->flag & PTCACHE_EXTERNAL) {
01045         strcpy(filename, pid->cache->path);
01046 
01047         if(strncmp(filename, "//", 2)==0)
01048             BLI_path_abs(filename, blendfilename);
01049 
01050         return BLI_add_slash(filename); /* new strlen() */
01051     }
01052     else if (G.relbase_valid || lib) {
01053         char file[MAX_PTCACHE_PATH]; /* we dont want the dir, only the file */
01054 
01055         BLI_split_file_part(blendfilename, file, sizeof(file));
01056         i = strlen(file);
01057         
01058         /* remove .blend */
01059         if (i > 6)
01060             file[i-6] = '\0';
01061         
01062         BLI_snprintf(filename, MAX_PTCACHE_PATH, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */
01063         BLI_path_abs(filename, blendfilename);
01064         return BLI_add_slash(filename); /* new strlen() */
01065     }
01066     
01067     /* use the temp path. this is weak but better then not using point cache at all */
01068     /* temporary directory is assumed to exist and ALWAYS has a trailing slash */
01069     BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH"%d", BLI_temporary_dir(), abs(getpid()));
01070     
01071     return BLI_add_slash(filename); /* new strlen() */
01072 }
01073 
01074 static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext)
01075 {
01076     int len=0;
01077     char *idname;
01078     char *newname;
01079     filename[0] = '\0';
01080     newname = filename;
01081     
01082     if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return 0; /* save blend file before using disk pointcache */
01083     
01084     /* start with temp dir */
01085     if (do_path) {
01086         len = ptcache_path(pid, filename);
01087         newname += len;
01088     }
01089     if(pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL)==0) {
01090         idname = (pid->ob->id.name+2);
01091         /* convert chars to hex so they are always a valid filename */
01092         while('\0' != *idname) {
01093             BLI_snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++));
01094             newname+=2;
01095             len += 2;
01096         }
01097     }
01098     else {
01099         int temp = (int)strlen(pid->cache->name); 
01100         strcpy(newname, pid->cache->name); 
01101         newname+=temp;
01102         len += temp;
01103     }
01104 
01105     if (do_ext) {
01106 
01107         if(pid->cache->index < 0)
01108             pid->cache->index =  pid->stack_index = object_insert_ptcache(pid->ob);
01109 
01110         if(pid->cache->flag & PTCACHE_EXTERNAL) {
01111             if(pid->cache->index >= 0)
01112                 BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
01113             else
01114                 BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */
01115         }
01116         else {
01117             BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
01118         }
01119         len += 16;
01120     }
01121     
01122     return len; /* make sure the above string is always 16 chars */
01123 }
01124 
01125 /* youll need to close yourself after! */
01126 static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
01127 {
01128     PTCacheFile *pf;
01129     FILE *fp = NULL;
01130     char filename[(FILE_MAX)*2];
01131 
01132 #ifndef DURIAN_POINTCACHE_LIB_OK
01133     /* don't allow writing for linked objects */
01134     if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE)
01135         return NULL;
01136 #endif
01137     if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return NULL; /* save blend file before using disk pointcache */
01138     
01139     ptcache_filename(pid, filename, cfra, 1, 1);
01140 
01141     if (mode==PTCACHE_FILE_READ) {
01142         if (!BLI_exists(filename)) {
01143             return NULL;
01144         }
01145         fp = fopen(filename, "rb");
01146     } else if (mode==PTCACHE_FILE_WRITE) {
01147         BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */
01148         fp = fopen(filename, "wb");
01149     } else if (mode==PTCACHE_FILE_UPDATE) {
01150         BLI_make_existing_file(filename);
01151         fp = fopen(filename, "rb+");
01152     }
01153 
01154     if (!fp)
01155         return NULL;
01156 
01157     pf= MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile");
01158     pf->fp= fp;
01159     pf->old_format = 0;
01160     pf->frame = cfra;
01161 
01162     return pf;
01163 }
01164 static void ptcache_file_close(PTCacheFile *pf)
01165 {
01166     if(pf) {
01167         fclose(pf->fp);
01168         MEM_freeN(pf);
01169     }
01170 }
01171 
01172 static int ptcache_file_compressed_read(PTCacheFile *pf, unsigned char *result, unsigned int len)
01173 {
01174     int r = 0;
01175     unsigned char compressed = 0;
01176     size_t in_len;
01177 #ifdef WITH_LZO
01178     size_t out_len = len;
01179 #endif
01180     unsigned char *in;
01181     unsigned char *props = MEM_callocN(16*sizeof(char), "tmp");
01182 
01183     ptcache_file_read(pf, &compressed, 1, sizeof(unsigned char));
01184     if(compressed) {
01185         unsigned int size;
01186         ptcache_file_read(pf, &size, 1, sizeof(unsigned int));
01187         in_len = (size_t)size;
01188         if(in_len==0) {
01189             /* do nothing */
01190         }
01191         else {
01192             in = (unsigned char *)MEM_callocN(sizeof(unsigned char)*in_len, "pointcache_compressed_buffer");
01193             ptcache_file_read(pf, in, in_len, sizeof(unsigned char));
01194 #ifdef WITH_LZO
01195             if(compressed == 1)
01196                 r = lzo1x_decompress_safe(in, (lzo_uint)in_len, result, (lzo_uint *)&out_len, NULL);
01197 #endif
01198 #ifdef WITH_LZMA
01199             if(compressed == 2)
01200             {
01201                 size_t sizeOfIt;
01202                 size_t leni = in_len, leno = out_len;
01203                 ptcache_file_read(pf, &size, 1, sizeof(unsigned int));
01204                 sizeOfIt = (size_t)size;
01205                 ptcache_file_read(pf, props, sizeOfIt, sizeof(unsigned char));
01206                 r = LzmaUncompress(result, &leno, in, &leni, props, sizeOfIt);
01207             }
01208 #endif
01209             MEM_freeN(in);
01210         }
01211     }
01212     else {
01213         ptcache_file_read(pf, result, len, sizeof(unsigned char));
01214     }
01215 
01216     MEM_freeN(props);
01217 
01218     return r;
01219 }
01220 static int ptcache_file_compressed_write(PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode)
01221 {
01222     int r = 0;
01223     unsigned char compressed = 0;
01224     size_t out_len= 0;
01225     unsigned char *props = MEM_callocN(16*sizeof(char), "tmp");
01226     size_t sizeOfIt = 5;
01227 
01228     (void)mode; /* unused when building w/o compression */
01229 
01230 #ifdef WITH_LZO
01231     out_len= LZO_OUT_LEN(in_len);
01232     if(mode == 1) {
01233         LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS);
01234         
01235         r = lzo1x_1_compress(in, (lzo_uint)in_len, out, (lzo_uint *)&out_len, wrkmem);  
01236         if (!(r == LZO_E_OK) || (out_len >= in_len))
01237             compressed = 0;
01238         else
01239             compressed = 1;
01240     }
01241 #endif
01242 #ifdef WITH_LZMA
01243     if(mode == 2) {
01244         
01245         r = LzmaCompress(out, &out_len, in, in_len,//assume sizeof(char)==1....
01246                         props, &sizeOfIt, 5, 1 << 24, 3, 0, 2, 32, 2);
01247 
01248         if(!(r == SZ_OK) || (out_len >= in_len))
01249             compressed = 0;
01250         else
01251             compressed = 2;
01252     }
01253 #endif
01254     
01255     ptcache_file_write(pf, &compressed, 1, sizeof(unsigned char));
01256     if(compressed) {
01257         unsigned int size = out_len;
01258         ptcache_file_write(pf, &size, 1, sizeof(unsigned int));
01259         ptcache_file_write(pf, out, out_len, sizeof(unsigned char));
01260     }
01261     else
01262         ptcache_file_write(pf, in, in_len, sizeof(unsigned char));
01263 
01264     if(compressed == 2)
01265     {
01266         unsigned int size = sizeOfIt;
01267         ptcache_file_write(pf, &sizeOfIt, 1, sizeof(unsigned int));
01268         ptcache_file_write(pf, props, size, sizeof(unsigned char));
01269     }
01270 
01271     MEM_freeN(props);
01272 
01273     return r;
01274 }
01275 static int ptcache_file_read(PTCacheFile *pf, void *f, unsigned int tot, unsigned int size)
01276 {
01277     return (fread(f, size, tot, pf->fp) == tot);
01278 }
01279 static int ptcache_file_write(PTCacheFile *pf, const void *f, unsigned int tot, unsigned int size)
01280 {
01281     return (fwrite(f, size, tot, pf->fp) == tot);
01282 }
01283 static int ptcache_file_data_read(PTCacheFile *pf)
01284 {
01285     int i;
01286 
01287     for(i=0; i<BPHYS_TOT_DATA; i++) {
01288         if((pf->data_types & (1<<i)) && !ptcache_file_read(pf, pf->cur[i], 1, ptcache_data_size[i]))
01289             return 0;
01290     }
01291     
01292     return 1;
01293 }
01294 static int ptcache_file_data_write(PTCacheFile *pf)
01295 {       
01296     int i;
01297 
01298     for(i=0; i<BPHYS_TOT_DATA; i++) {
01299         if((pf->data_types & (1<<i)) && !ptcache_file_write(pf, pf->cur[i], 1, ptcache_data_size[i]))
01300             return 0;
01301     }
01302     
01303     return 1;
01304 }
01305 static int ptcache_file_header_begin_read(PTCacheFile *pf)
01306 {
01307     unsigned int typeflag=0;
01308     int error=0;
01309     char bphysics[8];
01310     
01311     pf->data_types = 0;
01312     
01313     if(fread(bphysics, sizeof(char), 8, pf->fp) != 8)
01314         error = 1;
01315     
01316     if(!error && strncmp(bphysics, "BPHYSICS", 8))
01317         error = 1;
01318 
01319     if(!error && !fread(&typeflag, sizeof(unsigned int), 1, pf->fp))
01320         error = 1;
01321 
01322     pf->type = (typeflag & PTCACHE_TYPEFLAG_TYPEMASK);
01323     pf->flag = (typeflag & PTCACHE_TYPEFLAG_FLAGMASK);
01324     
01325     /* if there was an error set file as it was */
01326     if(error)
01327         fseek(pf->fp, 0, SEEK_SET);
01328 
01329     return !error;
01330 }
01331 static int ptcache_file_header_begin_write(PTCacheFile *pf)
01332 {
01333     const char *bphysics = "BPHYSICS";
01334     unsigned int typeflag = pf->type + pf->flag;
01335     
01336     if(fwrite(bphysics, sizeof(char), 8, pf->fp) != 8)
01337         return 0;
01338 
01339     if(!fwrite(&typeflag, sizeof(unsigned int), 1, pf->fp))
01340         return 0;
01341     
01342     return 1;
01343 }
01344 
01345 /* Data pointer handling */
01346 int BKE_ptcache_data_size(int data_type)
01347 {
01348     return ptcache_data_size[data_type];
01349 }
01350 
01351 static void ptcache_file_pointers_init(PTCacheFile *pf)
01352 {
01353     int data_types = pf->data_types;
01354 
01355     pf->cur[BPHYS_DATA_INDEX] =     (data_types & (1<<BPHYS_DATA_INDEX))    ?       &pf->data.index : NULL;
01356     pf->cur[BPHYS_DATA_LOCATION] =  (data_types & (1<<BPHYS_DATA_LOCATION)) ?       &pf->data.loc   : NULL;
01357     pf->cur[BPHYS_DATA_VELOCITY] =  (data_types & (1<<BPHYS_DATA_VELOCITY)) ?       &pf->data.vel   : NULL;
01358     pf->cur[BPHYS_DATA_ROTATION] =  (data_types & (1<<BPHYS_DATA_ROTATION)) ?       &pf->data.rot   : NULL;
01359     pf->cur[BPHYS_DATA_AVELOCITY] = (data_types & (1<<BPHYS_DATA_AVELOCITY))?       &pf->data.ave   : NULL;
01360     pf->cur[BPHYS_DATA_SIZE] =      (data_types & (1<<BPHYS_DATA_SIZE))     ?       &pf->data.size  : NULL;
01361     pf->cur[BPHYS_DATA_TIMES] =     (data_types & (1<<BPHYS_DATA_TIMES))    ?       &pf->data.times : NULL;
01362     pf->cur[BPHYS_DATA_BOIDS] =     (data_types & (1<<BPHYS_DATA_BOIDS))    ?       &pf->data.boids : NULL;
01363 }
01364 
01365 /* Check to see if point number "index" is in pm, uses binary search for index data. */
01366 int BKE_ptcache_mem_index_find(PTCacheMem *pm, unsigned int index)
01367 {
01368     if(pm->data[BPHYS_DATA_INDEX]) {
01369         unsigned int *data = pm->data[BPHYS_DATA_INDEX];
01370         unsigned int mid, low = 0, high = pm->totpoint - 1;
01371 
01372         if(index < *data || index > *(data+high))
01373             return -1;
01374 
01375         /* check simple case for continuous indexes first */
01376         if(index-*data < high && data[index-*data] == index)
01377             return index-*data;
01378 
01379         while(low <= high) {
01380             mid= (low + high)/2;
01381 
01382             if(data[mid] > index)
01383                 high = mid - 1;
01384             else if(data[mid] < index)
01385                 low = mid + 1;
01386             else
01387                 return mid;
01388         }
01389 
01390         return -1;
01391     }
01392     else {
01393         return (index < pm->totpoint ? index : -1);
01394     }
01395 }
01396 
01397 void BKE_ptcache_mem_pointers_init(PTCacheMem *pm)
01398 {
01399     int data_types = pm->data_types;
01400     int i;
01401 
01402     for(i=0; i<BPHYS_TOT_DATA; i++)
01403         pm->cur[i] = ((data_types & (1<<i)) ? pm->data[i] : NULL);
01404 }
01405 
01406 void BKE_ptcache_mem_pointers_incr(PTCacheMem *pm)
01407 {
01408     int i;
01409 
01410     for(i=0; i<BPHYS_TOT_DATA; i++) {
01411         if(pm->cur[i])
01412             pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i];
01413     }
01414 }
01415 int  BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm)
01416 {
01417     int data_types = pm->data_types;
01418     int i, index = BKE_ptcache_mem_index_find(pm, point_index);
01419 
01420     if(index < 0) {
01421         /* Can't give proper location without reallocation, so don't give any location.
01422          * Some points will be cached improperly, but this only happens with simulation
01423          * steps bigger than cache->step, so the cache has to be recalculated anyways
01424          * at some point.
01425          */
01426         return 0;
01427     }
01428 
01429     for(i=0; i<BPHYS_TOT_DATA; i++)
01430         pm->cur[i] = data_types & (1<<i) ? (char*)pm->data[i] + index * ptcache_data_size[i] : NULL;
01431 
01432     return 1;
01433 }
01434 static void ptcache_data_alloc(PTCacheMem *pm)
01435 {
01436     int data_types = pm->data_types;
01437     int totpoint = pm->totpoint;
01438     int i;
01439 
01440     for(i=0; i<BPHYS_TOT_DATA; i++) {
01441         if(data_types & (1<<i))
01442             pm->data[i] = MEM_callocN(totpoint * ptcache_data_size[i], "PTCache Data");
01443     }
01444 }
01445 static void ptcache_data_free(PTCacheMem *pm)
01446 {
01447     void **data = pm->data;
01448     int i;
01449 
01450     for(i=0; i<BPHYS_TOT_DATA; i++) {
01451         if(data[i])
01452             MEM_freeN(data[i]);
01453     }
01454 }
01455 static void ptcache_data_copy(void *from[], void *to[])
01456 {
01457     int i;
01458     for(i=0; i<BPHYS_TOT_DATA; i++) {
01459     /* note, durian file 03.4b_comp crashes if to[i] is not tested
01460      * its NULL, not sure if this should be fixed elsewhere but for now its needed */
01461         if(from[i] && to[i])
01462             memcpy(to[i], from[i], ptcache_data_size[i]);
01463     }
01464 }
01465 
01466 static void ptcache_extra_free(PTCacheMem *pm)
01467 {
01468     PTCacheExtra *extra = pm->extradata.first;
01469 
01470     if(extra) {
01471         for(; extra; extra=extra->next) {
01472             if(extra->data)
01473                 MEM_freeN(extra->data);
01474         }
01475 
01476         BLI_freelistN(&pm->extradata);
01477     }
01478 }
01479 static int ptcache_old_elemsize(PTCacheID *pid)
01480 {
01481     if(pid->type==PTCACHE_TYPE_SOFTBODY)
01482         return 6 * sizeof(float);
01483     else if(pid->type==PTCACHE_TYPE_PARTICLES)
01484         return sizeof(ParticleKey);
01485     else if(pid->type==PTCACHE_TYPE_CLOTH)
01486         return 9 * sizeof(float);
01487 
01488     return 0;
01489 }
01490 
01491 static void ptcache_find_frames_around(PTCacheID *pid, unsigned int frame, int *fra1, int *fra2)
01492 {
01493     if(pid->cache->flag & PTCACHE_DISK_CACHE) {
01494         int cfra1=frame, cfra2=frame+1;
01495 
01496         while(cfra1 >= pid->cache->startframe && !BKE_ptcache_id_exist(pid, cfra1))
01497             cfra1--;
01498 
01499         if(cfra1 < pid->cache->startframe)
01500             cfra1 = 0;
01501 
01502         while(cfra2 <= pid->cache->endframe && !BKE_ptcache_id_exist(pid, cfra2))
01503             cfra2++;
01504 
01505         if(cfra2 > pid->cache->endframe)
01506             cfra2 = 0;
01507 
01508         if(cfra1 && !cfra2) {
01509             *fra1 = 0;
01510             *fra2 = cfra1;
01511         }
01512         else {
01513             *fra1 = cfra1;
01514             *fra2 = cfra2;
01515         }
01516     }
01517     else if(pid->cache->mem_cache.first) {
01518         PTCacheMem *pm = pid->cache->mem_cache.first;
01519         PTCacheMem *pm2 = pid->cache->mem_cache.last;
01520 
01521         while(pm->next && pm->next->frame <= frame)
01522             pm= pm->next;
01523 
01524         if(pm2->frame < frame) {
01525             pm2 = NULL;
01526         }
01527         else {
01528             while(pm2->prev && pm2->prev->frame > frame) {
01529                 pm2= pm2->prev;
01530             }
01531         }
01532 
01533         if(!pm2) {
01534             *fra1 = 0;
01535             *fra2 = pm->frame;
01536         }
01537         else {
01538             *fra1 = pm->frame;
01539             *fra2 = pm2->frame;
01540         }
01541     }
01542 }
01543 
01544 static PTCacheMem *ptcache_disk_frame_to_mem(PTCacheID *pid, int cfra)
01545 {
01546     PTCacheFile *pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
01547     PTCacheMem *pm = NULL;
01548     unsigned int i, error = 0;
01549 
01550     if(pf == NULL)
01551         return NULL;
01552 
01553     if(!ptcache_file_header_begin_read(pf))
01554         error = 1;
01555 
01556     if(!error && (pf->type != pid->type || !pid->read_header(pf)))
01557         error = 1;
01558 
01559     if(!error) {
01560         pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
01561 
01562         pm->totpoint = pf->totpoint;
01563         pm->data_types = pf->data_types;
01564         pm->frame = pf->frame;
01565 
01566         ptcache_data_alloc(pm);
01567 
01568         if(pf->flag & PTCACHE_TYPEFLAG_COMPRESS) {
01569             for(i=0; i<BPHYS_TOT_DATA; i++) {
01570                 unsigned int out_len = pm->totpoint*ptcache_data_size[i];
01571                 if(pf->data_types & (1<<i))
01572                     ptcache_file_compressed_read(pf, (unsigned char*)(pm->data[i]), out_len);
01573             }
01574         }
01575         else {
01576             BKE_ptcache_mem_pointers_init(pm);
01577             ptcache_file_pointers_init(pf);
01578 
01579             for(i=0; i<pm->totpoint; i++) {
01580                 if(!ptcache_file_data_read(pf)) {
01581                     error = 1;
01582                     break;
01583                 }
01584                 ptcache_data_copy(pf->cur, pm->cur);
01585                 BKE_ptcache_mem_pointers_incr(pm);
01586             }
01587         }
01588     }
01589 
01590     if(!error && pf->flag & PTCACHE_TYPEFLAG_EXTRADATA) {
01591         unsigned int extratype = 0;
01592 
01593         while(ptcache_file_read(pf, &extratype, 1, sizeof(unsigned int))) {
01594             PTCacheExtra *extra = MEM_callocN(sizeof(PTCacheExtra), "Pointcache extradata");
01595 
01596             extra->type = extratype;
01597 
01598             ptcache_file_read(pf, &extra->totdata, 1, sizeof(unsigned int));
01599 
01600             extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], "Pointcache extradata->data");
01601 
01602             if(pf->flag & PTCACHE_TYPEFLAG_COMPRESS)
01603                 ptcache_file_compressed_read(pf, (unsigned char*)(extra->data), extra->totdata*ptcache_extra_datasize[extra->type]);
01604             else
01605                 ptcache_file_read(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
01606 
01607             BLI_addtail(&pm->extradata, extra);
01608         }
01609     }
01610 
01611     if(error && pm) {
01612         ptcache_data_free(pm);
01613         ptcache_extra_free(pm);
01614         MEM_freeN(pm);
01615         pm = NULL;
01616     }
01617 
01618     ptcache_file_close(pf);
01619 
01620     if (error && G.f & G_DEBUG) 
01621         printf("Error reading from disk cache\n");
01622     
01623     return pm;
01624 }
01625 static int ptcache_mem_frame_to_disk(PTCacheID *pid, PTCacheMem *pm)
01626 {
01627     PTCacheFile *pf = NULL;
01628     unsigned int i, error = 0;
01629     
01630     BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, pm->frame);
01631 
01632     pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, pm->frame);
01633 
01634     if(pf==NULL) {
01635         if (G.f & G_DEBUG) 
01636             printf("Error opening disk cache file for writing\n");
01637         return 0;
01638     }
01639 
01640     pf->data_types = pm->data_types;
01641     pf->totpoint = pm->totpoint;
01642     pf->type = pid->type;
01643     pf->flag = 0;
01644     
01645     if(pm->extradata.first)
01646         pf->flag |= PTCACHE_TYPEFLAG_EXTRADATA;
01647     
01648     if(pid->cache->compression)
01649         pf->flag |= PTCACHE_TYPEFLAG_COMPRESS;
01650 
01651     if(!ptcache_file_header_begin_write(pf) || !pid->write_header(pf))
01652         error = 1;
01653 
01654     if(!error) {
01655         if(pid->cache->compression) {
01656             for(i=0; i<BPHYS_TOT_DATA; i++) {
01657                 if(pm->data[i]) {
01658                     unsigned int in_len = pm->totpoint*ptcache_data_size[i];
01659                     unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer");
01660                     ptcache_file_compressed_write(pf, (unsigned char*)(pm->data[i]), in_len, out, pid->cache->compression);
01661                     MEM_freeN(out);
01662                 }
01663             }
01664         }
01665         else {
01666             BKE_ptcache_mem_pointers_init(pm);
01667             ptcache_file_pointers_init(pf);
01668 
01669             for(i=0; i<pm->totpoint; i++) {
01670                 ptcache_data_copy(pm->cur, pf->cur);
01671                 if(!ptcache_file_data_write(pf)) {
01672                     error = 1;
01673                     break;
01674                 }
01675                 BKE_ptcache_mem_pointers_incr(pm);
01676             }
01677         }
01678     }
01679 
01680     if(!error && pm->extradata.first) {
01681         PTCacheExtra *extra = pm->extradata.first;
01682 
01683         for(; extra; extra=extra->next) {
01684             if(extra->data == NULL || extra->totdata == 0)
01685                 continue;
01686 
01687             ptcache_file_write(pf, &extra->type, 1, sizeof(unsigned int));
01688             ptcache_file_write(pf, &extra->totdata, 1, sizeof(unsigned int));
01689 
01690             if(pid->cache->compression) {
01691                 unsigned int in_len = extra->totdata * ptcache_extra_datasize[extra->type];
01692                 unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer");
01693                 ptcache_file_compressed_write(pf, (unsigned char*)(extra->data), in_len, out, pid->cache->compression);
01694                 MEM_freeN(out);
01695             }
01696             else {
01697                 ptcache_file_write(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
01698             }
01699         }
01700     }
01701 
01702     ptcache_file_close(pf);
01703     
01704     if (error && G.f & G_DEBUG) 
01705         printf("Error writing to disk cache\n");
01706 
01707     return error==0;
01708 }
01709 
01710 static int ptcache_read_stream(PTCacheID *pid, int cfra)
01711 {
01712     PTCacheFile *pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
01713     int error = 0;
01714 
01715     if(pid->read_stream == NULL)
01716         return 0;
01717 
01718     if(pf == NULL) {
01719         if (G.f & G_DEBUG) 
01720             printf("Error opening disk cache file for reading\n");
01721         return 0;
01722     }
01723 
01724     if(!ptcache_file_header_begin_read(pf))
01725         error = 1;
01726 
01727     if(!error && (pf->type != pid->type || !pid->read_header(pf)))
01728         error = 1;
01729 
01730     if(!error && pf->totpoint != pid->totpoint(pid->calldata, cfra))
01731         error = 1;
01732 
01733     if(!error) {
01734         ptcache_file_pointers_init(pf);
01735 
01736         // we have stream reading here
01737         if (!pid->read_stream(pf, pid->calldata))
01738             error = 1;
01739     }
01740 
01741     ptcache_file_close(pf);
01742     
01743     return error == 0;
01744 }
01745 static int ptcache_read(PTCacheID *pid, int cfra)
01746 {
01747     PTCacheMem *pm = NULL;
01748     int i;
01749     int *index = &i;
01750 
01751     /* get a memory cache to read from */
01752     if(pid->cache->flag & PTCACHE_DISK_CACHE) {
01753         pm = ptcache_disk_frame_to_mem(pid, cfra);
01754     }
01755     else {
01756         pm = pid->cache->mem_cache.first;
01757         
01758         while(pm && pm->frame != cfra)
01759             pm = pm->next;
01760     }
01761 
01762     /* read the cache */
01763     if(pm) {
01764         int totpoint = pm->totpoint;
01765 
01766         if((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0)
01767             totpoint = MIN2(totpoint, pid->totpoint(pid->calldata, cfra));
01768 
01769         BKE_ptcache_mem_pointers_init(pm);
01770 
01771         for(i=0; i<totpoint; i++) {
01772             if(pm->data_types & (1<<BPHYS_DATA_INDEX))
01773                 index = pm->cur[BPHYS_DATA_INDEX];
01774 
01775             pid->read_point(*index, pid->calldata, pm->cur, (float)pm->frame, NULL);
01776         
01777             BKE_ptcache_mem_pointers_incr(pm);
01778         }
01779 
01780         if(pid->read_extra_data && pm->extradata.first)
01781             pid->read_extra_data(pid->calldata, pm, (float)pm->frame);
01782 
01783         /* clean up temporary memory cache */
01784         if(pid->cache->flag & PTCACHE_DISK_CACHE) {
01785             ptcache_data_free(pm);
01786             ptcache_extra_free(pm);
01787             MEM_freeN(pm);
01788         }
01789     }
01790 
01791     return 1;
01792 }
01793 static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
01794 {
01795     PTCacheMem *pm = NULL;
01796     int i;
01797     int *index = &i;
01798 
01799     /* get a memory cache to read from */
01800     if(pid->cache->flag & PTCACHE_DISK_CACHE) {
01801         pm = ptcache_disk_frame_to_mem(pid, cfra2);
01802     }
01803     else {
01804         pm = pid->cache->mem_cache.first;
01805         
01806         while(pm && pm->frame != cfra2)
01807             pm = pm->next;
01808     }
01809 
01810     /* read the cache */
01811     if(pm) {
01812         int totpoint = pm->totpoint;
01813 
01814         if((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0)
01815             totpoint = MIN2(totpoint, pid->totpoint(pid->calldata, (int)cfra));
01816 
01817         BKE_ptcache_mem_pointers_init(pm);
01818 
01819         for(i=0; i<totpoint; i++) {
01820             if(pm->data_types & (1<<BPHYS_DATA_INDEX))
01821                 index = pm->cur[BPHYS_DATA_INDEX];
01822 
01823             pid->interpolate_point(*index, pid->calldata, pm->cur, cfra, (float)cfra1, (float)cfra2, NULL);
01824             BKE_ptcache_mem_pointers_incr(pm);
01825         }
01826 
01827         if(pid->interpolate_extra_data && pm->extradata.first)
01828             pid->interpolate_extra_data(pid->calldata, pm, cfra, (float)cfra1, (float)cfra2);
01829 
01830         /* clean up temporary memory cache */
01831         if(pid->cache->flag & PTCACHE_DISK_CACHE) {
01832             ptcache_data_free(pm);
01833             ptcache_extra_free(pm);
01834             MEM_freeN(pm);
01835         }
01836     }
01837 
01838     return 1;
01839 }
01840 /* reads cache from disk or memory */
01841 /* possible to get old or interpolated result */
01842 int BKE_ptcache_read(PTCacheID *pid, float cfra)
01843 {
01844     int cfrai = (int)floor(cfra), cfra1=0, cfra2=0;
01845     int ret = 0;
01846 
01847     /* nothing to read to */
01848     if(pid->totpoint(pid->calldata, cfrai) == 0)
01849         return 0;
01850 
01851     if(pid->cache->flag & PTCACHE_READ_INFO) {
01852         pid->cache->flag &= ~PTCACHE_READ_INFO;
01853         ptcache_read(pid, 0);
01854     }
01855 
01856     /* first check if we have the actual frame cached */
01857     if(cfra == (float)cfrai && BKE_ptcache_id_exist(pid, cfrai))
01858         cfra1 = cfrai;
01859 
01860     /* no exact cache frame found so try to find cached frames around cfra */
01861     if(cfra1 == 0)
01862         ptcache_find_frames_around(pid, cfrai, &cfra1, &cfra2);
01863 
01864     if(cfra1 == 0 && cfra2 == 0)
01865         return 0;
01866 
01867     /* don't read old cache if already simulated past cached frame */
01868     if(cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
01869         return 0;
01870     if(cfra1 && cfra1 == cfra2)
01871         return 0;
01872 
01873     if(cfra1) {
01874         
01875         if(pid->read_stream) {
01876             if (!ptcache_read_stream(pid, cfra1))
01877                 return 0;
01878         }
01879         else if(pid->read_point)
01880             ptcache_read(pid, cfra1);
01881     }
01882 
01883     if(cfra2) {
01884         
01885         if(pid->read_stream) {
01886             if (!ptcache_read_stream(pid, cfra2))
01887                 return 0;
01888         }
01889         else if(pid->read_point) {
01890             if(cfra1 && cfra2 && pid->interpolate_point)
01891                 ptcache_interpolate(pid, cfra, cfra1, cfra2);
01892             else
01893                 ptcache_read(pid, cfra2);
01894         }
01895     }
01896 
01897     if(cfra1)
01898         ret = (cfra2 ? PTCACHE_READ_INTERPOLATED : PTCACHE_READ_EXACT);
01899     else if(cfra2) {
01900         ret = PTCACHE_READ_OLD;
01901         pid->cache->simframe = cfra2;
01902     }
01903 
01904     if((pid->cache->flag & PTCACHE_QUICK_CACHE)==0) {
01905         cfrai = (int)cfra;
01906         /* clear invalid cache frames so that better stuff can be simulated */
01907         if(pid->cache->flag & PTCACHE_OUTDATED) {
01908             BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfrai);
01909         }
01910         else if(pid->cache->flag & PTCACHE_FRAMES_SKIPPED) {
01911             if(cfra <= pid->cache->last_exact)
01912                 pid->cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
01913 
01914             BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, MAX2(cfrai, pid->cache->last_exact));
01915         }
01916     }
01917 
01918     return ret;
01919 }
01920 static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint)
01921 {
01922     PTCacheFile *pf = NULL;
01923     int error = 0;
01924     
01925     BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
01926 
01927     pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, cfra);
01928 
01929     if(pf==NULL) {
01930         if (G.f & G_DEBUG) 
01931             printf("Error opening disk cache file for writing\n");
01932         return 0;
01933     }
01934 
01935     pf->data_types = pid->data_types;
01936     pf->totpoint = totpoint;
01937     pf->type = pid->type;
01938     pf->flag = 0;
01939 
01940     if(!error && (!ptcache_file_header_begin_write(pf) || !pid->write_header(pf)))
01941         error = 1;
01942 
01943     if(!error && pid->write_stream)
01944         pid->write_stream(pf, pid->calldata);
01945 
01946     ptcache_file_close(pf);
01947 
01948     if (error && G.f & G_DEBUG) 
01949         printf("Error writing to disk cache\n");
01950 
01951     return error == 0;
01952 }
01953 static int ptcache_write(PTCacheID *pid, int cfra, int overwrite)
01954 {
01955     PointCache *cache = pid->cache;
01956     PTCacheMem *pm=NULL, *pm2=NULL;
01957     int totpoint = pid->totpoint(pid->calldata, cfra);
01958     int i, error = 0;
01959 
01960     pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
01961 
01962     pm->totpoint = pid->totwrite(pid->calldata, cfra);
01963     pm->data_types = cfra ? pid->data_types : pid->info_types;
01964 
01965     ptcache_data_alloc(pm);
01966     BKE_ptcache_mem_pointers_init(pm);
01967 
01968     if(overwrite) {
01969         if(cache->flag & PTCACHE_DISK_CACHE) {
01970             int fra = cfra-1;
01971 
01972             while(fra >= cache->startframe && !BKE_ptcache_id_exist(pid, fra))
01973                 fra--;
01974             
01975             pm2 = ptcache_disk_frame_to_mem(pid, fra);
01976         }
01977         else
01978             pm2 = cache->mem_cache.last;
01979     }
01980 
01981     if(pid->write_point) {
01982         for(i=0; i<totpoint; i++) {
01983             int write = pid->write_point(i, pid->calldata, pm->cur, cfra);
01984             if(write) {
01985                 BKE_ptcache_mem_pointers_incr(pm);
01986 
01987                 /* newly born particles have to be copied to previous cached frame */
01988                 if(overwrite && write == 2 && pm2 && BKE_ptcache_mem_pointers_seek(i, pm2))
01989                     pid->write_point(i, pid->calldata, pm2->cur, cfra);
01990             }
01991         }
01992     }
01993 
01994     if(pid->write_extra_data)
01995         pid->write_extra_data(pid->calldata, pm, cfra);
01996 
01997     pm->frame = cfra;
01998 
01999     if(cache->flag & PTCACHE_DISK_CACHE) {
02000         error += !ptcache_mem_frame_to_disk(pid, pm);
02001 
02002         // if(pm) /* pm is always set */
02003         {
02004             ptcache_data_free(pm);
02005             ptcache_extra_free(pm);
02006             MEM_freeN(pm);
02007         }
02008 
02009         if(pm2) {
02010             error += !ptcache_mem_frame_to_disk(pid, pm2);
02011             ptcache_data_free(pm2);
02012             ptcache_extra_free(pm2);
02013             MEM_freeN(pm2);
02014         }
02015     }
02016     else {
02017         BLI_addtail(&cache->mem_cache, pm);
02018     }
02019 
02020     return error;
02021 }
02022 static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
02023 {
02024     PointCache *cache = pid->cache;
02025     int ofra = 0, efra = cache->endframe;
02026 
02027     /* allways start from scratch on the first frame */
02028     if(cfra && cfra == cache->startframe) {
02029         BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, cfra);
02030         cache->flag &= ~PTCACHE_REDO_NEEDED;
02031         return 1;
02032     }
02033 
02034     if(pid->cache->flag & PTCACHE_DISK_CACHE) {
02035         if(cfra==0 && cache->startframe > 0)
02036             return 1;
02037 
02038                 /* find last cached frame */
02039         while(efra > cache->startframe && !BKE_ptcache_id_exist(pid, efra))
02040             efra--;
02041 
02042         /* find second last cached frame */
02043         ofra = efra-1;
02044         while(ofra > cache->startframe && !BKE_ptcache_id_exist(pid, ofra))
02045             ofra--;
02046     }
02047     else {
02048         PTCacheMem *pm = cache->mem_cache.last;
02049         /* don't write info file in memory */
02050         if(cfra == 0)
02051             return 0;
02052 
02053         if(pm == NULL)
02054             return 1;
02055 
02056         efra = pm->frame;
02057         ofra = (pm->prev ? pm->prev->frame : efra - cache->step);
02058     }
02059 
02060     if(efra >= cache->startframe && cfra > efra) {
02061         if(ofra >= cache->startframe && efra - ofra < cache->step) {
02062             /* overwrite previous frame */
02063             BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, efra);
02064             *overwrite = 1;
02065         }
02066         return 1;
02067     }
02068 
02069     return 0;
02070 }
02071 /* writes cache to disk or memory */
02072 int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
02073 {
02074     PointCache *cache = pid->cache;
02075     int totpoint = pid->totpoint(pid->calldata, cfra);
02076     int overwrite = 0, error = 0;
02077 
02078     if(totpoint == 0 || (cfra ? pid->data_types == 0 : pid->info_types == 0))
02079         return 0;
02080 
02081     if(ptcache_write_needed(pid, cfra, &overwrite)==0)
02082         return 0;
02083 
02084     if(pid->write_stream) {
02085         ptcache_write_stream(pid, cfra, totpoint);
02086     }
02087     else if(pid->write_point) {
02088         error += ptcache_write(pid, cfra, overwrite);
02089     }
02090 
02091     /* Mark frames skipped if more than 1 frame forwards since last non-skipped frame. */
02092     if(cfra - cache->last_exact == 1 || cfra == cache->startframe) {
02093         cache->last_exact = cfra;
02094         cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
02095     }
02096     /* Don't mark skipped when writing info file (frame 0) */
02097     else if(cfra)
02098         cache->flag |= PTCACHE_FRAMES_SKIPPED;
02099 
02100     /* Update timeline cache display */
02101     if(cfra && cache->cached_frames)
02102         cache->cached_frames[cfra-cache->startframe] = 1;
02103 
02104     BKE_ptcache_update_info(pid);
02105 
02106     return !error;
02107 }
02108 /* youll need to close yourself after!
02109  * mode - PTCACHE_CLEAR_ALL, 
02110 
02111 */
02112 /* Clears & resets */
02113 void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
02114 {
02115     unsigned int len; /* store the length of the string */
02116     unsigned int sta, end;
02117 
02118     /* mode is same as fopen's modes */
02119     DIR *dir; 
02120     struct dirent *de;
02121     char path[MAX_PTCACHE_PATH];
02122     char filename[MAX_PTCACHE_FILE];
02123     char path_full[MAX_PTCACHE_FILE];
02124     char ext[MAX_PTCACHE_PATH];
02125 
02126     if(!pid || !pid->cache || pid->cache->flag & PTCACHE_BAKED)
02127         return;
02128 
02129     if (pid->cache->flag & PTCACHE_IGNORE_CLEAR)
02130         return;
02131 
02132     sta = pid->cache->startframe;
02133     end = pid->cache->endframe;
02134 
02135 #ifndef DURIAN_POINTCACHE_LIB_OK
02136     /* don't allow clearing for linked objects */
02137     if(pid->ob->id.lib)
02138         return;
02139 #endif
02140 
02141     /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */
02142     
02143     /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
02144     switch (mode) {
02145     case PTCACHE_CLEAR_ALL:
02146     case PTCACHE_CLEAR_BEFORE:  
02147     case PTCACHE_CLEAR_AFTER:
02148         if(pid->cache->flag & PTCACHE_DISK_CACHE) {
02149             ptcache_path(pid, path);
02150             
02151             len = ptcache_filename(pid, filename, cfra, 0, 0); /* no path */
02152             
02153             dir = opendir(path);
02154             if (dir==NULL)
02155                 return;
02156 
02157             BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
02158             
02159             while ((de = readdir(dir)) != NULL) {
02160                 if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
02161                     if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
02162                         if (mode == PTCACHE_CLEAR_ALL) {
02163                             pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
02164                             BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
02165                             BLI_delete(path_full, 0, 0);
02166                         } else {
02167                             /* read the number of the file */
02168                             unsigned int frame, len2 = (int)strlen(de->d_name);
02169                             char num[7];
02170 
02171                             if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
02172                                 BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
02173                                 frame = atoi(num);
02174                                 
02175                                 if((mode==PTCACHE_CLEAR_BEFORE && frame < cfra) || 
02176                                 (mode==PTCACHE_CLEAR_AFTER && frame > cfra) ) {
02177                                     
02178                                     BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
02179                                     BLI_delete(path_full, 0, 0);
02180                                     if(pid->cache->cached_frames && frame >=sta && frame <= end)
02181                                         pid->cache->cached_frames[frame-sta] = 0;
02182                                 }
02183                             }
02184                         }
02185                     }
02186                 }
02187             }
02188             closedir(dir);
02189 
02190             if(mode == PTCACHE_CLEAR_ALL && pid->cache->cached_frames)
02191                 memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
02192         }
02193         else {
02194             PTCacheMem *pm= pid->cache->mem_cache.first;
02195             PTCacheMem *link= NULL;
02196 
02197             if(mode == PTCACHE_CLEAR_ALL) {
02198                 /*we want startframe if the cache starts before zero*/
02199                 pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
02200                 for(; pm; pm=pm->next) {
02201                     ptcache_data_free(pm);
02202                     ptcache_extra_free(pm);
02203                 }
02204                 BLI_freelistN(&pid->cache->mem_cache);
02205 
02206                 if(pid->cache->cached_frames) 
02207                     memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
02208             } else {
02209                 while(pm) {
02210                     if((mode==PTCACHE_CLEAR_BEFORE && pm->frame < cfra) || 
02211                     (mode==PTCACHE_CLEAR_AFTER && pm->frame > cfra) ) {
02212                         link = pm;
02213                         if(pid->cache->cached_frames && pm->frame >=sta && pm->frame <= end)
02214                             pid->cache->cached_frames[pm->frame-sta] = 0;
02215                         ptcache_data_free(pm);
02216                         ptcache_extra_free(pm);
02217                         pm = pm->next;
02218                         BLI_freelinkN(&pid->cache->mem_cache, link);
02219                     }
02220                     else
02221                         pm = pm->next;
02222                 }
02223             }
02224         }
02225         break;
02226         
02227     case PTCACHE_CLEAR_FRAME:
02228         if(pid->cache->flag & PTCACHE_DISK_CACHE) {
02229             if(BKE_ptcache_id_exist(pid, cfra)) {
02230                 ptcache_filename(pid, filename, cfra, 1, 1); /* no path */
02231                 BLI_delete(filename, 0, 0);
02232             }
02233         }
02234         else {
02235             PTCacheMem *pm = pid->cache->mem_cache.first;
02236 
02237             for(; pm; pm=pm->next) {
02238                 if(pm->frame == cfra) {
02239                     ptcache_data_free(pm);
02240                     ptcache_extra_free(pm);
02241                     BLI_freelinkN(&pid->cache->mem_cache, pm);
02242                     break;
02243                 }
02244             }
02245         }
02246         if(pid->cache->cached_frames && cfra>=sta && cfra<=end)
02247             pid->cache->cached_frames[cfra-sta] = 0;
02248         break;
02249     }
02250 
02251     BKE_ptcache_update_info(pid);
02252 }
02253 int  BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
02254 {
02255     if(!pid->cache)
02256         return 0;
02257 
02258     if(cfra<pid->cache->startframe || cfra > pid->cache->endframe)
02259         return 0;
02260 
02261     if(pid->cache->cached_frames && pid->cache->cached_frames[cfra-pid->cache->startframe]==0)
02262         return 0;
02263     
02264     if(pid->cache->flag & PTCACHE_DISK_CACHE) {
02265         char filename[MAX_PTCACHE_FILE];
02266         
02267         ptcache_filename(pid, filename, cfra, 1, 1);
02268 
02269         return BLI_exists(filename);
02270     }
02271     else {
02272         PTCacheMem *pm = pid->cache->mem_cache.first;
02273 
02274         for(; pm; pm=pm->next) {
02275             if(pm->frame==cfra)
02276                 return 1;
02277         }
02278         return 0;
02279     }
02280 }
02281 void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
02282 {
02283     /* Object *ob; */ /* UNUSED */
02284     PointCache *cache;
02285     /* float offset; unused for now */
02286     float time, nexttime;
02287 
02288     /* TODO: this has to be sorter out once bsystem_time gets redone, */
02289     /*       now caches can handle interpolating etc. too - jahka */
02290 
02291     /* time handling for point cache:
02292      * - simulation time is scaled by result of bsystem_time
02293      * - for offsetting time only time offset is taken into account, since
02294      *   that's always the same and can't be animated. a timeoffset which
02295      *   varies over time is not simpe to support.
02296      * - field and motion blur offsets are currently ignored, proper solution
02297      *   is probably to interpolate results from two frames for that ..
02298      */
02299 
02300     /* ob= pid->ob; */ /* UNUSED */
02301     cache= pid->cache;
02302 
02303     if(timescale) {
02304         time= BKE_curframe(scene);
02305         nexttime= BKE_frame_to_ctime(scene, CFRA+1);
02306         
02307         *timescale= MAX2(nexttime - time, 0.0f);
02308     }
02309 
02310     if(startframe && endframe) {
02311         *startframe= cache->startframe;
02312         *endframe= cache->endframe;
02313 
02314         /* TODO: time handling with object offsets and simulated vs. cached
02315          * particles isn't particularly easy, so for now what you see is what
02316          * you get. In the future point cache could handle the whole particle
02317          * system timing. */
02318 #if 0
02319         if ((ob->partype & PARSLOW)==0) {
02320             offset= ob->sf;
02321 
02322             *startframe += (int)(offset+0.5f);
02323             *endframe += (int)(offset+0.5f);
02324         }
02325 #endif
02326     }
02327 
02328     /* verify cached_frames array is up to date */
02329     if(cache->cached_frames) {
02330         if(MEM_allocN_len(cache->cached_frames) != sizeof(char) * (cache->endframe-cache->startframe+1)) {
02331             MEM_freeN(cache->cached_frames);
02332             cache->cached_frames = NULL;
02333         }   
02334     }
02335 
02336     if(cache->cached_frames==NULL && cache->endframe > cache->startframe) {
02337         unsigned int sta=cache->startframe;
02338         unsigned int end=cache->endframe;
02339 
02340         cache->cached_frames = MEM_callocN(sizeof(char) * (cache->endframe-cache->startframe+1), "cached frames array");
02341 
02342         if(pid->cache->flag & PTCACHE_DISK_CACHE) {
02343             /* mode is same as fopen's modes */
02344             DIR *dir; 
02345             struct dirent *de;
02346             char path[MAX_PTCACHE_PATH];
02347             char filename[MAX_PTCACHE_FILE];
02348             char ext[MAX_PTCACHE_PATH];
02349             unsigned int len; /* store the length of the string */
02350 
02351             ptcache_path(pid, path);
02352             
02353             len = ptcache_filename(pid, filename, (int)cfra, 0, 0); /* no path */
02354             
02355             dir = opendir(path);
02356             if (dir==NULL)
02357                 return;
02358 
02359             BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
02360             
02361             while ((de = readdir(dir)) != NULL) {
02362                 if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
02363                     if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
02364                         /* read the number of the file */
02365                         unsigned int frame, len2 = (int)strlen(de->d_name);
02366                         char num[7];
02367 
02368                         if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
02369                             BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
02370                             frame = atoi(num);
02371                             
02372                             if(frame >= sta && frame <= end)
02373                                 cache->cached_frames[frame-sta] = 1;
02374                         }
02375                     }
02376                 }
02377             }
02378             closedir(dir);
02379         }
02380         else {
02381             PTCacheMem *pm= pid->cache->mem_cache.first;
02382 
02383             while(pm) {
02384                 if(pm->frame >= sta && pm->frame <= end)
02385                     cache->cached_frames[pm->frame-sta] = 1;
02386                 pm = pm->next;
02387             }
02388         }
02389     }
02390 }
02391 int  BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
02392 {
02393     PointCache *cache;
02394     int reset, clear, after;
02395 
02396     if(!pid->cache)
02397         return 0;
02398 
02399     cache= pid->cache;
02400     reset= 0;
02401     clear= 0;
02402     after= 0;
02403 
02404     if(mode == PTCACHE_RESET_DEPSGRAPH) {
02405         if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) {
02406             if(cache->flag & PTCACHE_QUICK_CACHE)
02407                 clear= 1;
02408 
02409             after= 1;
02410         }
02411 
02412         cache->flag |= PTCACHE_OUTDATED;
02413     }
02414     else if(mode == PTCACHE_RESET_BAKED) {
02415         if(!BKE_ptcache_get_continue_physics()) {
02416             reset= 1;
02417             clear= 1;
02418         }
02419         else
02420             cache->flag |= PTCACHE_OUTDATED;
02421     }
02422     else if(mode == PTCACHE_RESET_OUTDATED) {
02423         reset = 1;
02424 
02425         if(cache->flag & PTCACHE_OUTDATED && !(cache->flag & PTCACHE_BAKED)) {
02426             clear= 1;
02427             cache->flag &= ~PTCACHE_OUTDATED;
02428         }
02429     }
02430 
02431     if(reset) {
02432         BKE_ptcache_invalidate(cache);
02433         cache->flag &= ~PTCACHE_REDO_NEEDED;
02434 
02435         if(pid->type == PTCACHE_TYPE_CLOTH)
02436             cloth_free_modifier(pid->calldata);
02437         else if(pid->type == PTCACHE_TYPE_SOFTBODY)
02438             sbFreeSimulation(pid->calldata);
02439         else if(pid->type == PTCACHE_TYPE_PARTICLES)
02440             psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
02441         else if(pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
02442             smokeModifier_reset(pid->calldata);
02443         else if(pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
02444             smokeModifier_reset_turbulence(pid->calldata);
02445         else if(pid->type == PTCACHE_TYPE_DYNAMICPAINT)
02446             dynamicPaint_clearSurface((DynamicPaintSurface*)pid->calldata);
02447     }
02448     if(clear)
02449         BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
02450     else if(after)
02451         BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, CFRA);
02452 
02453     return (reset || clear || after);
02454 }
02455 int  BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
02456 {
02457     PTCacheID pid;
02458     ParticleSystem *psys;
02459     ModifierData *md;
02460     int reset, skip;
02461 
02462     reset= 0;
02463     skip= 0;
02464 
02465     if(ob->soft) {
02466         BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
02467         reset |= BKE_ptcache_id_reset(scene, &pid, mode);
02468     }
02469 
02470     for(psys=ob->particlesystem.first; psys; psys=psys->next) {
02471         /* children or just redo can be calculated without reseting anything */
02472         if(psys->recalc & PSYS_RECALC_REDO || psys->recalc & PSYS_RECALC_CHILD)
02473             skip = 1;
02474         /* Baked cloth hair has to be checked too, because we don't want to reset */
02475         /* particles or cloth in that case -jahka */
02476         else if(psys->clmd) {
02477             BKE_ptcache_id_from_cloth(&pid, ob, psys->clmd);
02478             if(mode == PSYS_RESET_ALL || !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED))) 
02479                 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
02480             else
02481                 skip = 1;
02482         }
02483 
02484         if(skip == 0 && psys->part) {
02485             BKE_ptcache_id_from_particles(&pid, ob, psys);
02486             reset |= BKE_ptcache_id_reset(scene, &pid, mode);
02487         }
02488     }
02489 
02490     for(md=ob->modifiers.first; md; md=md->next) {
02491         if(md->type == eModifierType_Cloth) {
02492             BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md);
02493             reset |= BKE_ptcache_id_reset(scene, &pid, mode);
02494         }
02495         if(md->type == eModifierType_Smoke) {
02496             SmokeModifierData *smd = (SmokeModifierData *)md;
02497             if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
02498             {
02499                 BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData*)md);
02500                 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
02501             }
02502         }
02503         if(md->type == eModifierType_DynamicPaint) {
02504             DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
02505             if(pmd->canvas)
02506             {
02507                 DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
02508 
02509                 for (; surface; surface=surface->next) {
02510                     BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
02511                     reset |= BKE_ptcache_id_reset(scene, &pid, mode);
02512                 }
02513             }
02514         }
02515     }
02516 
02517     if (ob->type == OB_ARMATURE)
02518         BIK_clear_cache(ob->pose);
02519 
02520     return reset;
02521 }
02522 
02523 /* Use this when quitting blender, with unsaved files */
02524 void BKE_ptcache_remove(void)
02525 {
02526     char path[MAX_PTCACHE_PATH];
02527     char path_full[MAX_PTCACHE_PATH];
02528     int rmdir = 1;
02529     
02530     ptcache_path(NULL, path);
02531 
02532     if (BLI_exists(path)) {
02533         /* The pointcache dir exists? - remove all pointcache */
02534 
02535         DIR *dir; 
02536         struct dirent *de;
02537 
02538         dir = opendir(path);
02539         if (dir==NULL)
02540             return;
02541         
02542         while ((de = readdir(dir)) != NULL) {
02543             if( strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) {
02544                 /* do nothing */
02545             } else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
02546                 BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
02547                 BLI_delete(path_full, 0, 0);
02548             } else {
02549                 rmdir = 0; /* unknown file, dont remove the dir */
02550             }
02551         }
02552 
02553         closedir(dir);
02554     } else { 
02555         rmdir = 0; /* path dosnt exist  */
02556     }
02557     
02558     if (rmdir) {
02559         BLI_delete(path, 1, 0);
02560     }
02561 }
02562 
02563 /* Continuous Interaction */
02564 
02565 static int CONTINUE_PHYSICS = 0;
02566 
02567 void BKE_ptcache_set_continue_physics(Main *bmain, Scene *scene, int enable)
02568 {
02569     Object *ob;
02570 
02571     if(CONTINUE_PHYSICS != enable) {
02572         CONTINUE_PHYSICS = enable;
02573 
02574         if(CONTINUE_PHYSICS == 0) {
02575             for(ob=bmain->object.first; ob; ob=ob->id.next)
02576                 if(BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED))
02577                     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02578         }
02579     }
02580 }
02581 
02582 int  BKE_ptcache_get_continue_physics(void)
02583 {
02584     return CONTINUE_PHYSICS;
02585 }
02586 
02587 /* Point Cache handling */
02588 
02589 PointCache *BKE_ptcache_add(ListBase *ptcaches)
02590 {
02591     PointCache *cache;
02592 
02593     cache= MEM_callocN(sizeof(PointCache), "PointCache");
02594     cache->startframe= 1;
02595     cache->endframe= 250;
02596     cache->step= 10;
02597     cache->index = -1;
02598 
02599     BLI_addtail(ptcaches, cache);
02600 
02601     return cache;
02602 }
02603 
02604 void BKE_ptcache_free_mem(ListBase *mem_cache)
02605 {
02606     PTCacheMem *pm = mem_cache->first;
02607 
02608     if(pm) {
02609         for(; pm; pm=pm->next) {
02610             ptcache_data_free(pm);
02611             ptcache_extra_free(pm);
02612         }
02613 
02614         BLI_freelistN(mem_cache);
02615     }
02616 }
02617 void BKE_ptcache_free(PointCache *cache)
02618 {
02619     BKE_ptcache_free_mem(&cache->mem_cache);
02620     if(cache->edit && cache->free_edit)
02621         cache->free_edit(cache->edit);
02622     if(cache->cached_frames)
02623         MEM_freeN(cache->cached_frames);
02624     MEM_freeN(cache);
02625 }
02626 void BKE_ptcache_free_list(ListBase *ptcaches)
02627 {
02628     PointCache *cache = ptcaches->first;
02629 
02630     while(cache) {
02631         BLI_remlink(ptcaches, cache);
02632         BKE_ptcache_free(cache);
02633         cache = ptcaches->first;
02634     }
02635 }
02636 
02637 static PointCache *ptcache_copy(PointCache *cache)
02638 {
02639     PointCache *ncache;
02640 
02641     ncache= MEM_dupallocN(cache);
02642 
02643     /* hmm, should these be copied over instead? */
02644     ncache->mem_cache.first = NULL;
02645     ncache->mem_cache.last = NULL;
02646     ncache->cached_frames = NULL;
02647     ncache->edit = NULL;
02648 
02649     ncache->flag= 0;
02650     ncache->simframe= 0;
02651 
02652     return ncache;
02653 }
02654 /* returns first point cache */
02655 PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old)
02656 {
02657     PointCache *cache = ptcaches_old->first;
02658 
02659     ptcaches_new->first = ptcaches_new->last = NULL;
02660 
02661     for(; cache; cache=cache->next)
02662         BLI_addtail(ptcaches_new, ptcache_copy(cache));
02663 
02664     return ptcaches_new->first;
02665 }
02666 
02667 
02668 /* Baking */
02669 void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene)
02670 {
02671     PTCacheBaker baker;
02672 
02673     baker.bake=0;
02674     baker.break_data=NULL;
02675     baker.break_test=NULL;
02676     baker.pid=NULL;
02677     baker.progressbar=NULL;
02678     baker.progressend=NULL;
02679     baker.progresscontext=NULL;
02680     baker.render=0;
02681     baker.anim_init = 0;
02682     baker.main=bmain;
02683     baker.scene=scene;
02684     baker.quick_step=scene->physics_settings.quick_cache_step;
02685 
02686     BKE_ptcache_bake(&baker);
02687 }
02688 
02689 /* Simulation thread, no need for interlocks as data written in both threads
02690  are only unitary integers (I/O assumed to be atomic for them) */
02691 typedef struct {
02692     int break_operation;
02693     int thread_ended;
02694     int endframe;
02695     int step;
02696     int *cfra_ptr;
02697     Main *main;
02698     Scene *scene;
02699 } ptcache_bake_data;
02700 
02701 static void ptcache_dt_to_str(char *str, double dtime)
02702 {
02703     if(dtime > 60.0) {
02704         if(dtime > 3600.0)
02705             sprintf(str, "%ih %im %is", (int)(dtime/3600), ((int)(dtime/60))%60, ((int)dtime) % 60);
02706         else
02707             sprintf(str, "%im %is", ((int)(dtime/60))%60, ((int)dtime) % 60);
02708     }
02709     else
02710         sprintf(str, "%is", ((int)dtime) % 60);
02711 }
02712 
02713 static void *ptcache_bake_thread(void *ptr)
02714 {
02715     int usetimer = 0, sfra, efra;
02716     double stime, ptime, ctime, fetd;
02717     char run[32], cur[32], etd[32];
02718 
02719     ptcache_bake_data *data = (ptcache_bake_data*)ptr;
02720 
02721     stime = ptime = PIL_check_seconds_timer();
02722     sfra = *data->cfra_ptr;
02723     efra = data->endframe;
02724 
02725     for(; (*data->cfra_ptr <= data->endframe) && !data->break_operation; *data->cfra_ptr+=data->step) {
02726         scene_update_for_newframe(data->main, data->scene, data->scene->lay);
02727         if(G.background) {
02728             printf("bake: frame %d :: %d\n", (int)*data->cfra_ptr, data->endframe);
02729         }
02730         else {
02731             ctime = PIL_check_seconds_timer();
02732 
02733             fetd = (ctime-ptime)*(efra-*data->cfra_ptr)/data->step;
02734 
02735             if(usetimer || fetd > 60.0) {
02736                 usetimer = 1;
02737 
02738                 ptcache_dt_to_str(cur, ctime-ptime);
02739                 ptcache_dt_to_str(run, ctime-stime);
02740                 ptcache_dt_to_str(etd, fetd);
02741 
02742                 printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s          \r", run, *data->cfra_ptr-sfra+1, efra-sfra+1, ctime-ptime, etd);
02743             }
02744             ptime = ctime;
02745         }
02746     }
02747 
02748     if(usetimer) {
02749         ptcache_dt_to_str(run, PIL_check_seconds_timer()-stime);
02750         printf("Bake %s %s (%i frames simulated).                       \n", (data->break_operation ? "canceled after" : "finished in"), run, *data->cfra_ptr-sfra);
02751     }
02752 
02753     data->thread_ended = TRUE;
02754     return NULL;
02755 }
02756 
02757 /* if bake is not given run simulations to current frame */
02758 void BKE_ptcache_bake(PTCacheBaker* baker)
02759 {
02760     Main *bmain = baker->main;
02761     Scene *scene = baker->scene;
02762     Scene *sce_iter; /* SETLOOPER macro only */
02763     Base *base;
02764     ListBase pidlist;
02765     PTCacheID *pid = baker->pid;
02766     PointCache *cache = NULL;
02767     float frameleno = scene->r.framelen;
02768     int cfrao = CFRA;
02769     int startframe = MAXFRAME;
02770     int bake = baker->bake;
02771     int render = baker->render;
02772     ListBase threads;
02773     ptcache_bake_data thread_data;
02774     int progress, old_progress;
02775     
02776     thread_data.endframe = baker->anim_init ? scene->r.sfra : CFRA;
02777     thread_data.step = baker->quick_step;
02778     thread_data.cfra_ptr = &CFRA;
02779     thread_data.scene = baker->scene;
02780     thread_data.main = baker->main;
02781 
02782     G.afbreek = 0;
02783 
02784     /* set caches to baking mode and figure out start frame */
02785     if(pid) {
02786         /* cache/bake a single object */
02787         cache = pid->cache;
02788         if((cache->flag & PTCACHE_BAKED)==0) {
02789             if(pid->type==PTCACHE_TYPE_PARTICLES) {
02790                 ParticleSystem *psys= pid->calldata;
02791 
02792                 /* a bit confusing, could make this work better in the UI */
02793                 if(psys->part->type == PART_EMITTER)
02794                     psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe);
02795             }
02796             else if(pid->type == PTCACHE_TYPE_SMOKE_HIGHRES) {
02797                 /* get all pids from the object and search for smoke low res */
02798                 ListBase pidlist2;
02799                 PTCacheID *pid2;
02800                 BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
02801                 for(pid2=pidlist2.first; pid2; pid2=pid2->next) {
02802                     if(pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) 
02803                     {
02804                         if(pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
02805                             if(bake || pid2->cache->flag & PTCACHE_REDO_NEEDED)
02806                                 BKE_ptcache_id_clear(pid2, PTCACHE_CLEAR_ALL, 0);
02807                             if(bake) {
02808                                 pid2->cache->flag |= PTCACHE_BAKING;
02809                                 pid2->cache->flag &= ~PTCACHE_BAKED;
02810                             }
02811                         }
02812                     }
02813                 }
02814                 BLI_freelistN(&pidlist2);
02815             }
02816 
02817             if(bake || cache->flag & PTCACHE_REDO_NEEDED)
02818                 BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
02819 
02820             startframe = MAX2(cache->last_exact, cache->startframe);
02821 
02822             if(bake) {
02823                 thread_data.endframe = cache->endframe;
02824                 cache->flag |= PTCACHE_BAKING;
02825             }
02826             else {
02827                 thread_data.endframe = MIN2(thread_data.endframe, cache->endframe);
02828             }
02829 
02830             cache->flag &= ~PTCACHE_BAKED;
02831         }
02832     }
02833     else for(SETLOOPER(scene, sce_iter, base)) {
02834         /* cache/bake everything in the scene */
02835         BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
02836 
02837         for(pid=pidlist.first; pid; pid=pid->next) {
02838             cache = pid->cache;
02839             if((cache->flag & PTCACHE_BAKED)==0) {
02840                 if(pid->type==PTCACHE_TYPE_PARTICLES) {
02841                     ParticleSystem *psys = (ParticleSystem*)pid->calldata;
02842                     /* skip hair & keyed particles */
02843                     if(psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED)
02844                         continue;
02845 
02846                     psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe);
02847                 }
02848 
02849                 if((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0)
02850                     && ((cache->flag & PTCACHE_QUICK_CACHE)==0 || render || bake))
02851                     BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
02852 
02853                 startframe = MIN2(startframe, cache->startframe);
02854 
02855                 if(bake || render) {
02856                     cache->flag |= PTCACHE_BAKING;
02857 
02858                     if(bake)
02859                         thread_data.endframe = MAX2(thread_data.endframe, cache->endframe);
02860                 }
02861 
02862                 cache->flag &= ~PTCACHE_BAKED;
02863 
02864             }
02865         }
02866         BLI_freelistN(&pidlist);
02867     }
02868 
02869     CFRA = startframe;
02870     scene->r.framelen = 1.0;
02871     thread_data.break_operation = FALSE;
02872     thread_data.thread_ended = FALSE;
02873     old_progress = -1;
02874 
02875     WM_cursor_wait(1);
02876     
02877     if(G.background) {
02878         ptcache_bake_thread((void*)&thread_data);
02879     }
02880     else {
02881         BLI_init_threads(&threads, ptcache_bake_thread, 1);
02882         BLI_insert_thread(&threads, (void*)&thread_data);
02883 
02884         while (thread_data.thread_ended == FALSE) {
02885 
02886             if(bake)
02887                 progress = (int)(100.0f * (float)(CFRA - startframe)/(float)(thread_data.endframe-startframe));
02888             else
02889                 progress = CFRA;
02890 
02891             /* NOTE: baking should not redraw whole ui as this slows things down */
02892             if ((baker->progressbar) && (progress != old_progress)) {
02893                 baker->progressbar(baker->progresscontext, progress);
02894                 old_progress = progress;
02895             }
02896 
02897             /* Delay to lessen CPU load from UI thread */
02898             PIL_sleep_ms(200);
02899 
02900             /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
02901             if(blender_test_break() && !thread_data.break_operation) {
02902                 thread_data.break_operation = TRUE;
02903                 if (baker->progressend)
02904                     baker->progressend(baker->progresscontext);
02905                 WM_cursor_wait(1);
02906             }
02907         }
02908 
02909     BLI_end_threads(&threads);
02910     }
02911     /* clear baking flag */
02912     if(pid) {
02913         cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED);
02914         cache->flag |= PTCACHE_SIMULATION_VALID;
02915         if(bake) {
02916             cache->flag |= PTCACHE_BAKED;
02917             /* write info file */
02918             if(cache->flag & PTCACHE_DISK_CACHE)
02919                 BKE_ptcache_write(pid, 0);
02920         }
02921     }
02922     else for(SETLOOPER(scene, sce_iter, base)) {
02923         BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
02924 
02925         for(pid=pidlist.first; pid; pid=pid->next) {
02926             /* skip hair particles */
02927             if(pid->type==PTCACHE_TYPE_PARTICLES && ((ParticleSystem*)pid->calldata)->part->type == PART_HAIR)
02928                 continue;
02929         
02930             cache = pid->cache;
02931 
02932             if(thread_data.step > 1)
02933                 cache->flag &= ~(PTCACHE_BAKING|PTCACHE_OUTDATED);
02934             else
02935                 cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED);
02936 
02937             cache->flag |= PTCACHE_SIMULATION_VALID;
02938 
02939             if(bake) {
02940                 cache->flag |= PTCACHE_BAKED;
02941                 if(cache->flag & PTCACHE_DISK_CACHE)
02942                     BKE_ptcache_write(pid, 0);
02943             }
02944         }
02945         BLI_freelistN(&pidlist);
02946     }
02947 
02948     scene->r.framelen = frameleno;
02949     CFRA = cfrao;
02950     
02951     if(bake) /* already on cfra unless baking */
02952         scene_update_for_newframe(bmain, scene, scene->lay);
02953 
02954     if (thread_data.break_operation)
02955         WM_cursor_wait(0);
02956     else if (baker->progressend)
02957         baker->progressend(baker->progresscontext);
02958 
02959     WM_cursor_wait(0);
02960 
02961     /* TODO: call redraw all windows somehow */
02962 }
02963 /* Helpers */
02964 void BKE_ptcache_disk_to_mem(PTCacheID *pid)
02965 {
02966     PointCache *cache = pid->cache;
02967     PTCacheMem *pm = NULL;
02968     int baked = cache->flag & PTCACHE_BAKED;
02969     int cfra, sfra = cache->startframe, efra = cache->endframe;
02970 
02971     /* Remove possible bake flag to allow clear */
02972     cache->flag &= ~PTCACHE_BAKED;
02973 
02974     /* PTCACHE_DISK_CACHE flag was cleared already */
02975     BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
02976 
02977     /* restore possible bake flag */
02978     cache->flag |= baked;
02979 
02980     for(cfra=sfra; cfra <= efra; cfra++) {
02981         pm = ptcache_disk_frame_to_mem(pid, cfra);
02982 
02983         if(pm)
02984             BLI_addtail(&pid->cache->mem_cache, pm);
02985     }
02986 }
02987 void BKE_ptcache_mem_to_disk(PTCacheID *pid)
02988 {
02989     PointCache *cache = pid->cache;
02990     PTCacheMem *pm = cache->mem_cache.first;
02991     int baked = cache->flag & PTCACHE_BAKED;
02992 
02993     /* Remove possible bake flag to allow clear */
02994     cache->flag &= ~PTCACHE_BAKED;
02995 
02996     /* PTCACHE_DISK_CACHE flag was set already */
02997     BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
02998 
02999     /* restore possible bake flag */
03000     cache->flag |= baked;
03001 
03002     for(; pm; pm=pm->next) {
03003         if(ptcache_mem_frame_to_disk(pid, pm)==0) {
03004             cache->flag &= ~PTCACHE_DISK_CACHE;
03005             break;
03006         }
03007     }
03008 
03009     /* write info file */
03010     if(cache->flag & PTCACHE_BAKED)
03011         BKE_ptcache_write(pid, 0);
03012 }
03013 void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
03014 {
03015     PointCache *cache = pid->cache;
03016     int last_exact = cache->last_exact;
03017 
03018     if (!G.relbase_valid){
03019         cache->flag &= ~PTCACHE_DISK_CACHE;
03020         if (G.f & G_DEBUG) 
03021             printf("File must be saved before using disk cache!\n");
03022         return;
03023     }
03024 
03025     if(cache->cached_frames) {
03026         MEM_freeN(cache->cached_frames);
03027         cache->cached_frames=NULL;
03028     }
03029 
03030     if(cache->flag & PTCACHE_DISK_CACHE)
03031         BKE_ptcache_mem_to_disk(pid);
03032     else
03033         BKE_ptcache_disk_to_mem(pid);
03034 
03035     cache->flag ^= PTCACHE_DISK_CACHE;
03036     BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
03037     cache->flag ^= PTCACHE_DISK_CACHE;
03038     
03039     cache->last_exact = last_exact;
03040 
03041     BKE_ptcache_id_time(pid, NULL, 0.0f, NULL, NULL, NULL);
03042 
03043     BKE_ptcache_update_info(pid);
03044 }
03045 
03046 void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const char *name_dst)
03047 {
03048     char old_name[80];
03049     int len; /* store the length of the string */
03050     /* mode is same as fopen's modes */
03051     DIR *dir; 
03052     struct dirent *de;
03053     char path[MAX_PTCACHE_PATH];
03054     char old_filename[MAX_PTCACHE_FILE];
03055     char new_path_full[MAX_PTCACHE_FILE];
03056     char old_path_full[MAX_PTCACHE_FILE];
03057     char ext[MAX_PTCACHE_PATH];
03058 
03059     /* save old name */
03060     BLI_strncpy(old_name, pid->cache->name, sizeof(old_name));
03061 
03062     /* get "from" filename */
03063     BLI_strncpy(pid->cache->name, name_src, sizeof(pid->cache->name));
03064 
03065     len = ptcache_filename(pid, old_filename, 0, 0, 0); /* no path */
03066 
03067     ptcache_path(pid, path);
03068     dir = opendir(path);
03069     if(dir==NULL) {
03070         BLI_strncpy(pid->cache->name, old_name, sizeof(pid->cache->name));
03071         return;
03072     }
03073 
03074     BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
03075 
03076     /* put new name into cache */
03077     BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name));
03078 
03079     while ((de = readdir(dir)) != NULL) {
03080         if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
03081             if (strncmp(old_filename, de->d_name, len ) == 0) { /* do we have the right prefix */
03082                 /* read the number of the file */
03083                 int frame, len2 = (int)strlen(de->d_name);
03084                 char num[7];
03085 
03086                 if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
03087                     BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
03088                     frame = atoi(num);
03089 
03090                     BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
03091                     ptcache_filename(pid, new_path_full, frame, 1, 1);
03092                     BLI_rename(old_path_full, new_path_full);
03093                 }
03094             }
03095         }
03096     }
03097     closedir(dir);
03098 
03099     BLI_strncpy(pid->cache->name, old_name, sizeof(pid->cache->name));
03100 }
03101 
03102 void BKE_ptcache_load_external(PTCacheID *pid)
03103 {
03104     /*todo*/
03105     PointCache *cache = pid->cache;
03106     int len; /* store the length of the string */
03107     int info = 0;
03108     int start = MAXFRAME;
03109     int end = -1;
03110 
03111     /* mode is same as fopen's modes */
03112     DIR *dir; 
03113     struct dirent *de;
03114     char path[MAX_PTCACHE_PATH];
03115     char filename[MAX_PTCACHE_FILE];
03116     char ext[MAX_PTCACHE_PATH];
03117 
03118     if(!cache)
03119         return;
03120 
03121     ptcache_path(pid, path);
03122     
03123     len = ptcache_filename(pid, filename, 1, 0, 0); /* no path */
03124     
03125     dir = opendir(path);
03126     if (dir==NULL)
03127         return;
03128 
03129     if(cache->index >= 0)
03130         BLI_snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index);
03131     else
03132         BLI_strncpy(ext, PTCACHE_EXT, sizeof(ext));
03133     
03134     while ((de = readdir(dir)) != NULL) {
03135         if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
03136             if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
03137                 /* read the number of the file */
03138                 int frame, len2 = (int)strlen(de->d_name);
03139                 char num[7];
03140 
03141                 if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
03142                     BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
03143                     frame = atoi(num);
03144 
03145                     if(frame) {
03146                         start = MIN2(start, frame);
03147                         end = MAX2(end, frame);
03148                     }
03149                     else
03150                         info = 1;
03151                 }
03152             }
03153         }
03154     }
03155     closedir(dir);
03156 
03157     if(start != MAXFRAME) {
03158         PTCacheFile *pf;
03159 
03160         cache->startframe = start;
03161         cache->endframe = end;
03162         cache->totpoint = 0;
03163 
03164         if(pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
03165             ; /*necessary info in every file*/
03166         /* read totpoint from info file (frame 0) */
03167         else if(info) {
03168             pf= ptcache_file_open(pid, PTCACHE_FILE_READ, 0);
03169 
03170             if(pf) {
03171                 if(ptcache_file_header_begin_read(pf)) {
03172                     if(pf->type == pid->type && pid->read_header(pf)) {
03173                         cache->totpoint = pf->totpoint;
03174                         cache->flag |= PTCACHE_READ_INFO;
03175                     }
03176                     else {
03177                         cache->totpoint = 0;
03178                     }
03179                 }
03180                 ptcache_file_close(pf);
03181             }
03182         }
03183         /* or from any old format cache file */
03184         else {
03185             float old_data[14];
03186             int elemsize = ptcache_old_elemsize(pid);
03187             pf= ptcache_file_open(pid, PTCACHE_FILE_READ, cache->startframe);
03188 
03189             if(pf) {
03190                 while(ptcache_file_read(pf, old_data, 1, elemsize))
03191                     cache->totpoint++;
03192                 
03193                 ptcache_file_close(pf);
03194             }
03195         }
03196         cache->flag |= (PTCACHE_BAKED|PTCACHE_DISK_CACHE|PTCACHE_SIMULATION_VALID);
03197         cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_FRAMES_SKIPPED);
03198     }
03199 
03200     BKE_ptcache_update_info(pid);
03201 }
03202 
03203 void BKE_ptcache_update_info(PTCacheID *pid)
03204 {
03205     PointCache *cache = pid->cache;
03206     PTCacheExtra *extra = NULL;
03207     int totframes = 0;
03208     char mem_info[64];
03209 
03210     if(cache->flag & PTCACHE_EXTERNAL) {
03211         int cfra = cache->startframe;
03212 
03213         for(; cfra<=cache->endframe; cfra++) {
03214             if(BKE_ptcache_id_exist(pid, cfra))
03215                 totframes++;
03216         }
03217 
03218         /* smoke doesn't use frame 0 as info frame so can't check based on totpoint */
03219         if(pid->type == PTCACHE_TYPE_SMOKE_DOMAIN && totframes)
03220             BLI_snprintf(cache->info, sizeof(cache->info), "%i frames found!", totframes);
03221         else if(totframes && cache->totpoint)
03222             BLI_snprintf(cache->info, sizeof(cache->info), "%i points found!", cache->totpoint);
03223         else
03224             BLI_snprintf(cache->info, sizeof(cache->info), "No valid data to read!");
03225         return;
03226     }
03227 
03228     if(cache->flag & PTCACHE_DISK_CACHE) {
03229         if(pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
03230         {
03231             int totpoint = pid->totpoint(pid->calldata, 0);
03232 
03233             if(cache->totpoint > totpoint)
03234                 BLI_snprintf(mem_info, sizeof(mem_info), "%i cells + High Resolution cached", totpoint);
03235             else
03236                 BLI_snprintf(mem_info, sizeof(mem_info), "%i cells cached", totpoint);
03237         }
03238         else {
03239             int cfra = cache->startframe;
03240 
03241             for(; cfra<=cache->endframe; cfra++) {
03242                 if(BKE_ptcache_id_exist(pid, cfra))
03243                     totframes++;
03244             }
03245 
03246             BLI_snprintf(mem_info, sizeof(mem_info), "%i frames on disk", totframes);
03247         }
03248     }
03249     else {
03250         PTCacheMem *pm = cache->mem_cache.first;        
03251         float bytes = 0.0f;
03252         int i, mb;
03253         
03254         for(; pm; pm=pm->next) {
03255             for(i=0; i<BPHYS_TOT_DATA; i++)
03256                 bytes += MEM_allocN_len(pm->data[i]);
03257 
03258             for(extra=pm->extradata.first; extra; extra=extra->next) {
03259                 bytes += MEM_allocN_len(extra->data);
03260                 bytes += sizeof(PTCacheExtra);
03261             }
03262 
03263             bytes += sizeof(PTCacheMem);
03264             
03265             totframes++;
03266         }
03267 
03268         mb = (bytes > 1024.0f * 1024.0f);
03269 
03270         BLI_snprintf(mem_info, sizeof(mem_info), "%i frames in memory (%.1f %s)",
03271             totframes,
03272             bytes / (mb ? 1024.0f * 1024.0f : 1024.0f),
03273             mb ? "Mb" : "kb");
03274     }
03275 
03276     if(cache->flag & PTCACHE_OUTDATED) {
03277         BLI_snprintf(cache->info, sizeof(cache->info), "%s, cache is outdated!", mem_info);
03278     }
03279     else if(cache->flag & PTCACHE_FRAMES_SKIPPED) {
03280         BLI_snprintf(cache->info, sizeof(cache->info), "%s, not exact since frame %i.", mem_info, cache->last_exact);
03281     }
03282     else {
03283         BLI_snprintf(cache->info, sizeof(cache->info), "%s.", mem_info);
03284     }
03285 }
03286 
03287 void BKE_ptcache_validate(PointCache *cache, int framenr)
03288 {
03289     if(cache) {
03290         cache->flag |= PTCACHE_SIMULATION_VALID;
03291         cache->simframe = framenr;
03292     }
03293 }
03294 void BKE_ptcache_invalidate(PointCache *cache)
03295 {
03296     if(cache) {
03297         cache->flag &= ~PTCACHE_SIMULATION_VALID;
03298         cache->simframe = 0;
03299         cache->last_exact = MIN2(cache->startframe, 0);
03300     }
03301 }
03302