Point Cache Refactoring
[blender-staging.git] / source / blender / blenkernel / intern / pointcache.c
1 /**
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25 * Contributor(s): Campbell Barton <ideasman42@gmail.com>
26  *
27  * ***** END GPL/BL DUAL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_ID.h"
39 #include "DNA_cloth_types.h"
40 #include "DNA_modifier_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_object_force.h"
43 #include "DNA_particle_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "BLI_blenlib.h"
47
48 #include "BKE_cloth.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_global.h"
51 #include "BKE_library.h"
52 #include "BKE_main.h"
53 #include "BKE_modifier.h"
54 #include "BKE_object.h"
55 #include "BKE_particle.h"
56 #include "BKE_pointcache.h"
57 #include "BKE_softbody.h"
58 #include "BKE_utildefines.h"
59
60 #include "blendef.h"
61
62 /* needed for directory lookup */
63 #ifndef WIN32
64   #include <dirent.h>
65 #else
66   #include "BLI_winstuff.h"
67 #endif
68
69 /* untitled blend's need getpid for a unique name */
70 #ifdef WIN32
71 #include <process.h>
72 #else
73 #include <unistd.h>
74 #endif
75
76 /* Creating ID's */
77
78 void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
79 {
80         ParticleSystemModifierData *psmd;
81         ModifierData *md;
82         int a;
83
84         memset(pid, 0, sizeof(PTCacheID));
85
86         pid->ob= ob;
87         pid->data= sb;
88         pid->type= PTCACHE_TYPE_SOFTBODY;
89         pid->cache= sb->pointcache;
90
91         if(sb->particles) {
92                 psmd= psys_get_modifier(ob, sb->particles);
93                 pid->stack_index= modifiers_indexInObject(ob, (ModifierData*)psmd);
94         }
95         else {
96                 for(a=0, md=ob->modifiers.first; md; md=md->next, a++) {
97                         if(md->type == eModifierType_Softbody) {
98                                 pid->stack_index = a;
99                                 break;
100                         }
101                 }
102         }
103 }
104
105 void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
106 {
107         ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
108
109         memset(pid, 0, sizeof(PTCacheID));
110
111         pid->ob= ob;
112         pid->data= psys;
113         pid->type= PTCACHE_TYPE_PARTICLES;
114         pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)psmd);
115         pid->cache= psys->pointcache;
116 }
117
118 void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
119 {
120         memset(pid, 0, sizeof(PTCacheID));
121
122         pid->ob= ob;
123         pid->data= clmd;
124         pid->type= PTCACHE_TYPE_CLOTH;
125         pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)clmd);
126         pid->cache= clmd->point_cache;
127 }
128
129 void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob)
130 {
131         PTCacheID *pid;
132         ParticleSystem *psys;
133         ModifierData *md;
134
135         lb->first= lb->last= NULL;
136
137         if(ob->soft) {
138                 pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
139                 BKE_ptcache_id_from_softbody(pid, ob, ob->soft);
140                 BLI_addtail(lb, pid);
141         }
142
143         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
144                 pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
145                 BKE_ptcache_id_from_particles(pid, ob, psys);
146                 BLI_addtail(lb, pid);
147
148                 if(psys->soft) {
149                         pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
150                         BKE_ptcache_id_from_softbody(pid, ob, psys->soft);
151                         BLI_addtail(lb, pid);
152                 }
153         }
154
155         for(md=ob->modifiers.first; md; md=md->next) {
156                 if(md->type == eModifierType_Cloth) {
157                         pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
158                         BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md);
159                         BLI_addtail(lb, pid);
160                 }
161         }
162 }
163
164 /*      Takes an Object ID and returns a unique name
165         - id: object id
166         - cfra: frame for the cache, can be negative
167         - stack_index: index in the modifier stack. we can have cache for more then one stack_index
168 */
169
170 static int ptcache_path(PTCacheID *pid, char *filename)
171 {
172         Library *lib;
173         int i;
174
175         lib= (pid)? pid->ob->id.lib: NULL;
176
177         if (G.relbase_valid || lib) {
178                 char dir[FILE_MAX], file[FILE_MAX]; /* we dont want the dir, only the file */
179                 char *blendfilename;
180
181                 blendfilename= (lib)? lib->filename: G.sce;
182
183                 BLI_split_dirfile(blendfilename, dir, file);
184                 i = strlen(file);
185                 
186                 /* remove .blend */
187                 if (i > 6)
188                         file[i-6] = '\0';
189                 
190                 sprintf(filename, "//"PTCACHE_PATH"%s/", file); /* add blend file name to pointcache dir */
191                 BLI_convertstringcode(filename, blendfilename, 0);
192                 return strlen(filename);
193         }
194         
195         /* use the temp path. this is weak but better then not using point cache at all */
196         /* btempdir is assumed to exist and ALWAYS has a trailing slash */
197         return sprintf(filename, "%s"PTCACHE_PATH"%d/", btempdir, abs(getpid()));
198 }
199
200 static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext)
201 {
202         int len=0;
203         char *idname;
204         char *newname;
205         filename[0] = '\0';
206         newname = filename;
207         
208         /*if (!G.relbase_valid) return 0; *//* save blend file before using pointcache */
209         
210         /* start with temp dir */
211         if (do_path) {
212                 len = ptcache_path(pid, filename);
213                 newname += len;
214         }
215         idname = (pid->ob->id.name+2);
216         /* convert chars to hex so they are always a valid filename */
217         while('\0' != *idname) {
218                 sprintf(newname, "%02X", (char)(*idname++));
219                 newname+=2;
220                 len += 2;
221         }
222         
223         if (do_ext) {
224                 sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
225                 len += 16;
226         }
227         
228         return len; /* make sure the above string is always 16 chars */
229 }
230
231 /* youll need to close yourself after! */
232 PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra)
233 {
234         PTCacheFile *pf;
235         FILE *fp = NULL;
236         char filename[(FILE_MAXDIR+FILE_MAXFILE)*2];
237
238         /* don't allow writing for linked objects */
239         if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE)
240                 return NULL;
241
242         /*if (!G.relbase_valid) return NULL; *//* save blend file before using pointcache */
243         
244         BKE_ptcache_id_filename(pid, filename, cfra, 1, 1);
245
246         if (mode==PTCACHE_FILE_READ) {
247                 if (!BLI_exists(filename)) {
248                         return NULL;
249                 }
250                 fp = fopen(filename, "rb");
251         } else if (mode==PTCACHE_FILE_WRITE) {
252                 BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */
253                 fp = fopen(filename, "wb");
254         }
255
256         if (!fp)
257                 return NULL;
258         
259         pf= MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile");
260         pf->fp= fp;
261         
262         return pf;
263 }
264
265 void BKE_ptcache_file_close(PTCacheFile *pf)
266 {
267         fclose(pf->fp);
268         MEM_freeN(pf);
269 }
270
271 int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot)
272 {
273         return (fread(f, sizeof(float), tot, pf->fp) == tot);
274 }
275
276 int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot)
277 {
278         return (fwrite(f, sizeof(float), tot, pf->fp) == tot);
279 }
280
281 /* youll need to close yourself after!
282  * mode - PTCACHE_CLEAR_ALL, 
283
284 */
285
286 void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
287 {
288         int len; /* store the length of the string */
289
290         /* mode is same as fopen's modes */
291         DIR *dir; 
292         struct dirent *de;
293         char path[FILE_MAX];
294         char filename[(FILE_MAXDIR+FILE_MAXFILE)*2];
295         char path_full[(FILE_MAXDIR+FILE_MAXFILE)*2];
296
297         if(!pid->cache)
298                 return;
299
300         /* don't allow clearing for linked objects */
301         if(pid->ob->id.lib)
302                 return;
303
304         /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */
305         
306         /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
307         switch (mode) {
308         case PTCACHE_CLEAR_ALL:
309         case PTCACHE_CLEAR_BEFORE:      
310         case PTCACHE_CLEAR_AFTER:
311                 ptcache_path(pid, path);
312                 
313                 len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */
314                 
315                 dir = opendir(path);
316                 if (dir==NULL)
317                         return;
318                 
319                 while ((de = readdir(dir)) != NULL) {
320                         if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
321                                 if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
322                                         if (mode == PTCACHE_CLEAR_ALL) {
323                                                 BLI_join_dirfile(path_full, path, de->d_name);
324                                                 BLI_delete(path_full, 0, 0);
325                                         } else {
326                                                 /* read the number of the file */
327                                                 int frame, len2 = strlen(de->d_name);
328                                                 char num[7];
329                                                 if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
330                                                         strncpy(num, de->d_name + (strlen(de->d_name) - 15), 6);
331                                                         frame = atoi(num);
332                                                         
333                                                         if((mode==PTCACHE_CLEAR_BEFORE && frame < cfra) || 
334                                                            (mode==PTCACHE_CLEAR_AFTER && frame > cfra)  ) {
335                                                                 
336                                                                 BLI_join_dirfile(path_full, path, de->d_name);
337                                                                 BLI_delete(path_full, 0, 0);
338                                                         }
339                                                 }
340                                         }
341                                 }
342                         }
343                 }
344                 closedir(dir);
345                 break;
346                 
347         case PTCACHE_CLEAR_FRAME:
348                 len = BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */
349                 BLI_delete(filename, 0, 0);
350                 break;
351         }
352 }
353
354 int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
355 {
356         char filename[(FILE_MAXDIR+FILE_MAXFILE)*2];
357
358         if(!pid->cache)
359                 return 0;
360         
361         BKE_ptcache_id_filename(pid, filename, cfra, 1, 1);
362
363         return BLI_exists(filename);
364 }
365
366 void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale)
367 {
368         Object *ob;
369         PointCache *cache;
370         float offset, time, nexttime;
371
372         /* time handling for point cache:
373          * - simulation time is scaled by result of bsystem_time
374          * - for offsetting time only time offset is taken into account, since
375          *   that's always the same and can't be animated. a timeoffset which
376          *   varies over time is not simpe to support.
377          * - field and motion blur offsets are currently ignored, proper solution
378          *   is probably to interpolate results from two frames for that ..
379          */
380
381         ob= pid->ob;
382         cache= pid->cache;
383
384         if(timescale) {
385                 time= bsystem_time(ob, cfra, 0.0f);
386                 nexttime= bsystem_time(ob, cfra+1.0f, 0.0f);
387
388                 *timescale= MAX2(nexttime - time, 0.0f);
389         }
390
391         if(startframe && endframe) {
392                 *startframe= cache->startframe;
393                 *endframe= cache->endframe;
394
395                 if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) {
396                         offset= give_timeoffset(ob);
397
398                         *startframe += (int)(offset+0.5f);
399                         *endframe += (int)(offset+0.5f);
400                 }
401         }
402 }
403
404 int BKE_ptcache_id_reset(PTCacheID *pid, int mode)
405 {
406         PointCache *cache;
407         int reset, clear;
408
409         if(!pid->cache)
410                 return 0;
411
412         cache= pid->cache;
413         reset= 0;
414         clear= 0;
415
416         if(mode == PTCACHE_RESET_DEPSGRAPH) {
417                 if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) {
418                         reset= 1;
419                         clear= 1;
420                 }
421                 else
422                         cache->flag |= PTCACHE_OUTDATED;
423         }
424         else if(mode == PTCACHE_RESET_BAKED) {
425                 if(!BKE_ptcache_get_continue_physics()) {
426                         reset= 1;
427                         clear= 1;
428                 }
429                 else
430                         cache->flag |= PTCACHE_OUTDATED;
431         }
432         else if(mode == PTCACHE_RESET_OUTDATED) {
433                 reset = 1;
434
435                 if(cache->flag & PTCACHE_OUTDATED)
436                         if(!(cache->flag & PTCACHE_BAKED))
437                                 clear= 1;
438         }
439
440         if(reset) {
441                 cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_SIMULATION_VALID);
442                 cache->simframe= 0;
443
444                 if(pid->type == PTCACHE_TYPE_CLOTH)
445                         cloth_free_modifier(pid->ob, pid->data);
446                 else if(pid->type == PTCACHE_TYPE_SOFTBODY)
447                         sbFreeSimulation(pid->data);
448                 else if(pid->type == PTCACHE_TYPE_PARTICLES)
449                         psys_reset(pid->data, PSYS_RESET_DEPSGRAPH);
450         }
451         if(clear)
452                 BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
453
454         return (reset || clear);
455 }
456
457 int BKE_ptcache_object_reset(Object *ob, int mode)
458 {
459         PTCacheID pid;
460         ParticleSystem *psys;
461         ModifierData *md;
462         int reset;
463
464         reset= 0;
465
466         if(ob->soft) {
467                 BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
468                 reset |= BKE_ptcache_id_reset(&pid, mode);
469         }
470
471         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
472                 BKE_ptcache_id_from_particles(&pid, ob, psys);
473                 reset |= BKE_ptcache_id_reset(&pid, mode);
474
475                 if(psys->soft) {
476                         BKE_ptcache_id_from_softbody(&pid, ob, psys->soft);
477                         reset |= BKE_ptcache_id_reset(&pid, mode);
478                 }
479         }
480
481         for(md=ob->modifiers.first; md; md=md->next) {
482                 if(md->type == eModifierType_Cloth) {
483                         BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md);
484                         reset |= BKE_ptcache_id_reset(&pid, mode);
485                 }
486         }
487
488         return reset;
489 }
490
491 /* Use this when quitting blender, with unsaved files */
492 void BKE_ptcache_remove(void)
493 {
494         char path[FILE_MAX];
495         char path_full[FILE_MAX];
496         int rmdir = 1;
497         
498         ptcache_path(NULL, path);
499
500         if (BLI_exists(path)) {
501         /* TODO, Check with win32, probably needs last slash removed */
502                 /* The pointcache dir exists? - remove all pointcache */
503
504                 DIR *dir; 
505                 struct dirent *de;
506                 
507                 dir = opendir(path);
508                 if (dir==NULL)
509                         return;
510                 
511                 while ((de = readdir(dir)) != NULL) {
512                         if( strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) {
513                                 /* do nothing */
514                         } else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
515                                 BLI_join_dirfile(path_full, path, de->d_name);
516                                 BLI_delete(path_full, 0, 0);
517                         } else {
518                                 rmdir = 0; /* unknown file, dont remove the dir */
519                         }
520                 }
521         } else { 
522                 rmdir = 0; /* path dosnt exist  */
523         }
524         
525         if (rmdir) {
526                 BLI_delete(path, 1, 0);
527         }
528 }
529
530 /* Continuous Interaction */
531
532 static int CONTINUE_PHYSICS = 0;
533
534 void BKE_ptcache_set_continue_physics(int enable)
535 {
536         Object *ob;
537
538         if(CONTINUE_PHYSICS != enable) {
539                 CONTINUE_PHYSICS = enable;
540
541                 if(CONTINUE_PHYSICS == 0) {
542                         for(ob=G.main->object.first; ob; ob=ob->id.next)
543                                 if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_OUTDATED))
544                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
545                 }
546         }
547 }
548
549 int BKE_ptcache_get_continue_physics()
550 {
551         return CONTINUE_PHYSICS;
552 }
553
554 /* Point Cache */
555
556 PointCache *BKE_ptcache_add()
557 {
558         PointCache *cache;
559
560         cache= MEM_callocN(sizeof(PointCache), "PointCache");
561         cache->startframe= 1;
562         cache->endframe= 250;
563
564         return cache;
565 }
566
567 void BKE_ptcache_free(PointCache *cache)
568 {
569         MEM_freeN(cache);
570 }
571
572 PointCache *BKE_ptcache_copy(PointCache *cache)
573 {
574         PointCache *ncache;
575
576         ncache= MEM_dupallocN(cache);
577
578         ncache->flag= 0;
579         ncache->simframe= 0;
580
581         return ncache;
582 }
583