Fix for bug [#13479] Particle system "corrupts" when changing material colour and...
[blender-staging.git] / source / blender / blenkernel / intern / pointcache.c
1 /**
2  *
3  * ***** BEGIN GPL 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.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22 * Contributor(s): Campbell Barton <ideasman42@gmail.com>
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_ID.h"
36 #include "DNA_cloth_types.h"
37 #include "DNA_modifier_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_object_force.h"
40 #include "DNA_particle_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "BLI_blenlib.h"
44
45 #include "BKE_cloth.h"
46 #include "BKE_depsgraph.h"
47 #include "BKE_global.h"
48 #include "BKE_library.h"
49 #include "BKE_main.h"
50 #include "BKE_modifier.h"
51 #include "BKE_object.h"
52 #include "BKE_particle.h"
53 #include "BKE_pointcache.h"
54 #include "BKE_softbody.h"
55 #include "BKE_utildefines.h"
56
57 #include "blendef.h"
58
59 /* needed for directory lookup */
60 #ifndef WIN32
61   #include <dirent.h>
62 #else
63   #include "BLI_winstuff.h"
64 #endif
65
66 /* untitled blend's need getpid for a unique name */
67 #ifdef WIN32
68 #include <process.h>
69 #else
70 #include <unistd.h>
71 #endif
72
73 /* Creating ID's */
74
75 void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
76 {
77         ParticleSystemModifierData *psmd;
78         ModifierData *md;
79         int a;
80
81         memset(pid, 0, sizeof(PTCacheID));
82
83         pid->ob= ob;
84         pid->data= sb;
85         pid->type= PTCACHE_TYPE_SOFTBODY;
86         pid->cache= sb->pointcache;
87
88         if(sb->particles) {
89                 psmd= psys_get_modifier(ob, sb->particles);
90                 pid->stack_index= modifiers_indexInObject(ob, (ModifierData*)psmd);
91         }
92         else {
93                 for(a=0, md=ob->modifiers.first; md; md=md->next, a++) {
94                         if(md->type == eModifierType_Softbody) {
95                                 pid->stack_index = a;
96                                 break;
97                         }
98                 }
99         }
100 }
101
102 void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
103 {
104         ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
105
106         memset(pid, 0, sizeof(PTCacheID));
107
108         pid->ob= ob;
109         pid->data= psys;
110         pid->type= PTCACHE_TYPE_PARTICLES;
111         pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)psmd);
112         pid->cache= psys->pointcache;
113 }
114
115 void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
116 {
117         memset(pid, 0, sizeof(PTCacheID));
118
119         pid->ob= ob;
120         pid->data= clmd;
121         pid->type= PTCACHE_TYPE_CLOTH;
122         pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)clmd);
123         pid->cache= clmd->point_cache;
124 }
125
126 void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob)
127 {
128         PTCacheID *pid;
129         ParticleSystem *psys;
130         ModifierData *md;
131
132         lb->first= lb->last= NULL;
133
134         if(ob->soft) {
135                 pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
136                 BKE_ptcache_id_from_softbody(pid, ob, ob->soft);
137                 BLI_addtail(lb, pid);
138         }
139
140         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
141                 pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
142                 BKE_ptcache_id_from_particles(pid, ob, psys);
143                 BLI_addtail(lb, pid);
144
145                 if(psys->soft) {
146                         pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
147                         BKE_ptcache_id_from_softbody(pid, ob, psys->soft);
148                         BLI_addtail(lb, pid);
149                 }
150         }
151
152         for(md=ob->modifiers.first; md; md=md->next) {
153                 if(md->type == eModifierType_Cloth) {
154                         pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
155                         BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md);
156                         BLI_addtail(lb, pid);
157                 }
158         }
159 }
160
161 /*      Takes an Object ID and returns a unique name
162         - id: object id
163         - cfra: frame for the cache, can be negative
164         - stack_index: index in the modifier stack. we can have cache for more then one stack_index
165 */
166
167 static int ptcache_path(PTCacheID *pid, char *filename)
168 {
169         Library *lib;
170         int i;
171
172         lib= (pid)? pid->ob->id.lib: NULL;
173
174         if (G.relbase_valid || lib) {
175                 char file[FILE_MAX]; /* we dont want the dir, only the file */
176                 char *blendfilename;
177
178                 blendfilename= (lib)? lib->filename: G.sce;
179
180                 BLI_split_dirfile_basic(blendfilename, NULL, file);
181                 i = strlen(file);
182                 
183                 /* remove .blend */
184                 if (i > 6)
185                         file[i-6] = '\0';
186                 
187                 sprintf(filename, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */
188                 BLI_convertstringcode(filename, blendfilename);
189                 BLI_add_slash(filename);
190                 return strlen(filename);
191         }
192         
193         /* use the temp path. this is weak but better then not using point cache at all */
194         /* btempdir is assumed to exist and ALWAYS has a trailing slash */
195         sprintf(filename, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid()));
196         BLI_add_slash(filename);
197         return strlen(filename);
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, skip;
463
464         reset= 0;
465         skip= 0;
466
467         if(ob->soft) {
468                 BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
469                 reset |= BKE_ptcache_id_reset(&pid, mode);
470         }
471
472         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
473                 /* Baked softbody hair has to be checked first, because we don't want to reset */
474                 /* particles or softbody in that case -jahka */
475                 if(psys->soft) {
476                         BKE_ptcache_id_from_softbody(&pid, ob, psys->soft);
477                         if(mode == PSYS_RESET_ALL || !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED))) 
478                                 reset |= BKE_ptcache_id_reset(&pid, mode);
479                         else
480                                 skip = 1;
481                 }
482
483                 if(skip == 0) {
484                         BKE_ptcache_id_from_particles(&pid, ob, psys);
485                         reset |= BKE_ptcache_id_reset(&pid, mode);
486                 }
487         }
488
489         for(md=ob->modifiers.first; md; md=md->next) {
490                 if(md->type == eModifierType_Cloth) {
491                         BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md);
492                         reset |= BKE_ptcache_id_reset(&pid, mode);
493                 }
494         }
495
496         return reset;
497 }
498
499 /* Use this when quitting blender, with unsaved files */
500 void BKE_ptcache_remove(void)
501 {
502         char path[FILE_MAX];
503         char path_full[FILE_MAX];
504         int rmdir = 1;
505         
506         ptcache_path(NULL, path);
507
508         if (BLI_exist(path)) {
509                 /* The pointcache dir exists? - remove all pointcache */
510
511                 DIR *dir; 
512                 struct dirent *de;
513
514                 dir = opendir(path);
515                 if (dir==NULL)
516                         return;
517                 
518                 while ((de = readdir(dir)) != NULL) {
519                         if( strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) {
520                                 /* do nothing */
521                         } else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
522                                 BLI_join_dirfile(path_full, path, de->d_name);
523                                 BLI_delete(path_full, 0, 0);
524                         } else {
525                                 rmdir = 0; /* unknown file, dont remove the dir */
526                         }
527                 }
528
529                 closedir(dir);
530         } else { 
531                 rmdir = 0; /* path dosnt exist  */
532         }
533         
534         if (rmdir) {
535                 BLI_delete(path, 1, 0);
536         }
537 }
538
539 /* Continuous Interaction */
540
541 static int CONTINUE_PHYSICS = 0;
542
543 void BKE_ptcache_set_continue_physics(int enable)
544 {
545         Object *ob;
546
547         if(CONTINUE_PHYSICS != enable) {
548                 CONTINUE_PHYSICS = enable;
549
550                 if(CONTINUE_PHYSICS == 0) {
551                         for(ob=G.main->object.first; ob; ob=ob->id.next)
552                                 if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_OUTDATED))
553                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
554                 }
555         }
556 }
557
558 int BKE_ptcache_get_continue_physics()
559 {
560         return CONTINUE_PHYSICS;
561 }
562
563 /* Point Cache */
564
565 PointCache *BKE_ptcache_add()
566 {
567         PointCache *cache;
568
569         cache= MEM_callocN(sizeof(PointCache), "PointCache");
570         cache->startframe= 1;
571         cache->endframe= 250;
572
573         return cache;
574 }
575
576 void BKE_ptcache_free(PointCache *cache)
577 {
578         MEM_freeN(cache);
579 }
580
581 PointCache *BKE_ptcache_copy(PointCache *cache)
582 {
583         PointCache *ncache;
584
585         ncache= MEM_dupallocN(cache);
586
587         ncache->flag= 0;
588         ncache->simframe= 0;
589
590         return ncache;
591 }
592