Blender V4.3
pointcache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <cstdio>
11#include <cstdlib>
12#include <cstring>
13#include <sys/stat.h>
14#include <sys/types.h>
15
16/* needed for directory lookup */
17#ifndef WIN32
18# include <dirent.h>
19#else
20# include "BLI_winstuff.h"
21#endif
22
23#include "CLG_log.h"
24
25#include "MEM_guardedalloc.h"
26
27#include "DNA_ID.h"
30#include "DNA_fluid_types.h"
31#include "DNA_modifier_types.h"
33#include "DNA_object_types.h"
34#include "DNA_particle_types.h"
35#include "DNA_rigidbody_types.h"
36#include "DNA_scene_types.h"
37
38#include "BLI_blenlib.h"
39#include "BLI_endian_switch.h"
40#include "BLI_math_rotation.h"
41#include "BLI_math_vector.h"
42#include "BLI_string.h"
43#include "BLI_time.h"
44#include "BLI_utildefines.h"
45
46#include "BLT_translation.hh"
47
48#include "BKE_appdir.hh"
49#include "BKE_cloth.hh"
50#include "BKE_collection.hh"
51#include "BKE_dynamicpaint.h"
52#include "BKE_fluid.h"
53#include "BKE_global.hh"
54#include "BKE_lib_id.hh"
55#include "BKE_main.hh"
56#include "BKE_modifier.hh"
57#include "BKE_object.hh"
58#include "BKE_particle.h"
59#include "BKE_pointcache.h"
60#include "BKE_scene.hh"
61#include "BKE_softbody.h"
62
63#include "BLO_read_write.hh"
64
66
67#include "BIK_api.h"
68
69#ifdef WITH_BULLET
70# include "RBI_api.h"
71#endif
72
73#ifdef WITH_LZO
74# ifdef WITH_SYSTEM_LZO
75# include <lzo/lzo1x.h>
76# else
77# include "minilzo.h"
78# endif
79# define LZO_HEAP_ALLOC(var, size) \
80 lzo_align_t __LZO_MMODEL var[((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)]
81#endif
82
83#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3)
84
85#ifdef WITH_LZMA
86# include "LzmaLib.h"
87#endif
88
89#define PTCACHE_DATA_FROM(data, type, from) \
90 if (data[type]) { \
91 memcpy(data[type], from, ptcache_data_size[type]); \
92 } \
93 (void)0
94
95#define PTCACHE_DATA_TO(data, type, index, to) \
96 if (data[type]) { \
97 memcpy(to, \
98 (char *)(data)[type] + ((index) ? (index) * ptcache_data_size[type] : 0), \
99 ptcache_data_size[type]); \
100 } \
101 (void)0
102
103/* could be made into a pointcache option */
104#define DURIAN_POINTCACHE_LIB_OK 1
105
106static CLG_LogRef LOG = {"bke.pointcache"};
107
108static int ptcache_data_size[] = {
109 sizeof(uint), /* BPHYS_DATA_INDEX */
110 sizeof(float[3]), /* BPHYS_DATA_LOCATION */
111 sizeof(float[3]), /* BPHYS_DATA_VELOCITY */
112 sizeof(float[4]), /* BPHYS_DATA_ROTATION */
113 sizeof(float[3]), /* BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
114 sizeof(float), /* BPHYS_DATA_SIZE */
115 sizeof(float[3]), /* BPHYS_DATA_TIMES */
116 sizeof(BoidData), /* case BPHYS_DATA_BOIDS */
117};
118
120 0,
121 sizeof(ParticleSpring),
122 sizeof(float[3]),
123};
124
125/* forward declarations */
128 PTCacheFile *pf, uchar *in, uint in_len, uchar *out, int mode);
129static int ptcache_file_write(PTCacheFile *pf, const void *f, uint tot, uint size);
130static int ptcache_file_read(PTCacheFile *pf, void *f, uint tot, uint size);
131
132/* Common functions */
134{
135 int error = 0;
136
137 /* Custom functions should read these basic elements too! */
138 if (!error && !fread(&pf->totpoint, sizeof(uint), 1, pf->fp)) {
139 error = 1;
140 }
141
142 if (!error && !fread(&pf->data_types, sizeof(uint), 1, pf->fp)) {
143 error = 1;
144 }
145
146 return !error;
147}
149{
150 /* Custom functions should write these basic elements too! */
151 if (!fwrite(&pf->totpoint, sizeof(uint), 1, pf->fp)) {
152 return 0;
153 }
154
155 if (!fwrite(&pf->data_types, sizeof(uint), 1, pf->fp)) {
156 return 0;
157 }
158
159 return 1;
160}
161static void ptcache_add_extra_data(PTCacheMem *pm, uint type, uint count, void *data)
162{
163 PTCacheExtra *extra = static_cast<PTCacheExtra *>(
164 MEM_callocN(sizeof(PTCacheExtra), "Point cache: extra data descriptor"));
165
166 extra->type = type;
167 extra->totdata = count;
168
169 size_t size = extra->totdata * ptcache_extra_datasize[extra->type];
170
171 extra->data = MEM_mallocN(size, "Point cache: extra data");
172 memcpy(extra->data, data, size);
173
174 BLI_addtail(&pm->extradata, extra);
175}
176/* Softbody functions */
177static int ptcache_softbody_write(int index, void *soft_v, void **data, int /*cfra*/)
178{
179 SoftBody *soft = static_cast<SoftBody *>(soft_v);
180 BodyPoint *bp = soft->bpoint + index;
181
184
185 return 1;
186}
188 int index, void *soft_v, void **data, float /*cfra*/, const float *old_data)
189{
190 SoftBody *soft = static_cast<SoftBody *>(soft_v);
191 BodyPoint *bp = soft->bpoint + index;
192
193 if (old_data) {
194 memcpy(bp->pos, data, sizeof(float[3]));
195 memcpy(bp->vec, data + 3, sizeof(float[3]));
196 }
197 else {
200 }
201}
202static void ptcache_softbody_interpolate(int index,
203 void *soft_v,
204 void **data,
205 float cfra,
206 float cfra1,
207 float cfra2,
208 const float *old_data)
209{
210 SoftBody *soft = static_cast<SoftBody *>(soft_v);
211 BodyPoint *bp = soft->bpoint + index;
212 ParticleKey keys[4];
213 float dfra;
214
215 if (cfra1 == cfra2) {
216 return;
217 }
218
219 copy_v3_v3(keys[1].co, bp->pos);
220 copy_v3_v3(keys[1].vel, bp->vec);
221
222 if (old_data) {
223 memcpy(keys[2].co, old_data, sizeof(float[3]));
224 memcpy(keys[2].vel, old_data + 3, sizeof(float[3]));
225 }
226 else {
227 BKE_ptcache_make_particle_key(keys + 2, 0, data, cfra2);
228 }
229
230 dfra = cfra2 - cfra1;
231
232 mul_v3_fl(keys[1].vel, dfra);
233 mul_v3_fl(keys[2].vel, dfra);
234
235 psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, true);
236
237 mul_v3_fl(keys->vel, 1.0f / dfra);
238
239 copy_v3_v3(bp->pos, keys->co);
240 copy_v3_v3(bp->vec, keys->vel);
241}
242static int ptcache_softbody_totpoint(void *soft_v, int /*cfra*/)
243{
244 SoftBody *soft = static_cast<SoftBody *>(soft_v);
245 return soft->totpoint;
246}
247static void ptcache_softbody_error(const ID * /*owner_id*/,
248 void * /*soft_v*/,
249 const char * /*message*/)
250{
251 /* ignored for now */
252}
253
254/* Particle functions. */
255
256void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
257{
258 PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
259 PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, index, key->vel);
260
261 /* no rotation info, so make something nice up */
262 if (data[BPHYS_DATA_ROTATION] == nullptr) {
263 vec_to_quat(key->rot, key->vel, OB_NEGX, OB_POSZ);
264 }
265 else {
266 PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, key->rot);
267 }
268
269 PTCACHE_DATA_TO(data, BPHYS_DATA_AVELOCITY, index, key->ave);
270 key->time = time;
271}
272static int ptcache_particle_write(int index, void *psys_v, void **data, int cfra)
273{
274 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
275 ParticleData *pa = psys->particles + index;
276 BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : nullptr;
277 float times[3];
278 int step = psys->pointcache->step;
279
280 /* Skip some particles that are not stored in the cache. */
281 if (data[BPHYS_DATA_INDEX]) {
282 if (psys->part->flag & PART_DIED) {
283 /* Dead particles are stored when they are displayed. */
284 if (cfra < pa->time - step) {
285 return 0;
286 }
287 }
288 else {
289 /* Inclusive ranges for particle lifetime (`dietime - 1` for an inclusive end-frame). */
290 const int pa_sfra = int(pa->time) - step;
291 const int pa_efra = (int(pa->dietime) - 1) + step;
292 if (!(cfra >= pa_sfra && cfra <= pa_efra)) {
293 return 0;
294 }
295 }
296 }
297
298 times[0] = pa->time;
299 times[1] = pa->dietime;
300 times[2] = pa->lifetime;
301
302 PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index);
309
310 if (boid) {
312 }
313
314 /* Return flag 1+1=2 for newly born particles
315 * to copy exact birth location to previously cached frame. */
316 return 1 + (pa->state.time >= pa->time && pa->prev_state.time <= pa->time);
317}
319 int index, void *psys_v, void **data, float cfra, const float *old_data)
320{
321 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
322 ParticleData *pa;
323 BoidParticle *boid;
324 float timestep = 0.04f * psys->part->timetweak;
325
326 if (index >= psys->totpart) {
327 return;
328 }
329
330 pa = psys->particles + index;
331 boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : nullptr;
332
333 if (cfra > pa->state.time) {
334 memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey));
335 }
336
337 if (old_data) {
338 /* old format cache */
339 memcpy(&pa->state, old_data, sizeof(ParticleKey));
340 return;
341 }
342
343 BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra);
344
345 /* set frames cached before birth to birth time */
346 if (cfra < pa->time) {
347 pa->state.time = pa->time;
348 }
349 else if (cfra > pa->dietime) {
350 pa->state.time = pa->dietime;
351 }
352
353 if (data[BPHYS_DATA_SIZE]) {
354 PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size);
355 }
356
357 if (data[BPHYS_DATA_TIMES]) {
358 float times[3];
359 PTCACHE_DATA_TO(data, BPHYS_DATA_TIMES, 0, &times);
360 pa->time = times[0];
361 pa->dietime = times[1];
362 pa->lifetime = times[2];
363 }
364
365 if (boid) {
366 PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data);
367 }
368
369 /* determine velocity from previous location */
370 if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
371 if (cfra > pa->prev_state.time) {
372 sub_v3_v3v3(pa->state.vel, pa->state.co, pa->prev_state.co);
373 mul_v3_fl(pa->state.vel, (cfra - pa->prev_state.time) * timestep);
374 }
375 else {
376 sub_v3_v3v3(pa->state.vel, pa->prev_state.co, pa->state.co);
377 mul_v3_fl(pa->state.vel, (pa->prev_state.time - cfra) * timestep);
378 }
379 }
380
381 /* default to no rotation */
382 if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
383 unit_qt(pa->state.rot);
384 }
385}
386static void ptcache_particle_interpolate(int index,
387 void *psys_v,
388 void **data,
389 float cfra,
390 float cfra1,
391 float cfra2,
392 const float *old_data)
393{
394 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
395 ParticleData *pa;
396 ParticleKey keys[4];
397 float dfra, timestep = 0.04f * psys->part->timetweak;
398
399 if (index >= psys->totpart) {
400 return;
401 }
402
403 pa = psys->particles + index;
404
405 /* Inclusive ranges for particle lifetime (`dietime - 1` for an inclusive end-frame). */
406 const int pa_sfra = int(pa->time) - psys->pointcache->step;
407 const int pa_efra = (int(pa->dietime) - 1) + psys->pointcache->step;
408
409 /* Particle wasn't read from first cache so can't interpolate. */
410 if (!(cfra1 >= pa_sfra && cfra1 <= pa_efra)) {
411 return;
412 }
413
414 cfra = std::min(cfra, pa->dietime);
415 cfra1 = std::min(cfra1, pa->dietime);
416 cfra2 = std::min(cfra2, pa->dietime);
417
418 if (cfra1 == cfra2) {
419 return;
420 }
421
422 memcpy(keys + 1, &pa->state, sizeof(ParticleKey));
423 if (old_data) {
424 memcpy(keys + 2, old_data, sizeof(ParticleKey));
425 }
426 else {
427 BKE_ptcache_make_particle_key(keys + 2, 0, data, cfra2);
428 }
429
430 /* determine velocity from previous location */
431 if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
432 if (keys[1].time > keys[2].time) {
433 sub_v3_v3v3(keys[2].vel, keys[1].co, keys[2].co);
434 mul_v3_fl(keys[2].vel, (keys[1].time - keys[2].time) * timestep);
435 }
436 else {
437 sub_v3_v3v3(keys[2].vel, keys[2].co, keys[1].co);
438 mul_v3_fl(keys[2].vel, (keys[2].time - keys[1].time) * timestep);
439 }
440 }
441
442 /* default to no rotation */
443 if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
444 unit_qt(keys[2].rot);
445 }
446
447 if (cfra > pa->time) {
448 cfra1 = std::max(cfra1, pa->time);
449 }
450
451 dfra = cfra2 - cfra1;
452
453 mul_v3_fl(keys[1].vel, dfra * timestep);
454 mul_v3_fl(keys[2].vel, dfra * timestep);
455
456 psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, true);
457 interp_qt_qtqt(pa->state.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
458
459 mul_v3_fl(pa->state.vel, 1.0f / (dfra * timestep));
460
461 pa->state.time = cfra;
462}
463
464static int ptcache_particle_totpoint(void *psys_v, int /*cfra*/)
465{
466 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
467 return psys->totpart;
468}
469
470static void ptcache_particle_error(const ID * /*owner_id*/,
471 void * /*psys_v*/,
472 const char * /*message*/)
473{
474 /* ignored for now */
475}
476
477static int ptcache_particle_totwrite(void *psys_v, int cfra)
478{
479 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
480 ParticleData *pa = psys->particles;
481 int p, step = psys->pointcache->step;
482 int totwrite = 0;
483
484 if (cfra == 0) {
485 return psys->totpart;
486 }
487
488 if (psys->part->flag & PART_DIED) {
489 /* Also store dead particles when they are displayed. */
490 for (p = 0; p < psys->totpart; p++, pa++) {
491 const int pa_sfra = int(pa->time) - step;
492 totwrite += (cfra >= pa_sfra);
493 }
494 }
495 else {
496 for (p = 0; p < psys->totpart; p++, pa++) {
497 /* Inclusive ranges for particle lifetime (`dietime - 1` for an inclusive end-frame). */
498 const int pa_sfra = int(pa->time) - step;
499 const int pa_efra = (int(pa->dietime) - 1) + step;
500 totwrite += (cfra >= pa_sfra) && (cfra <= pa_efra);
501 }
502 }
503
504 return totwrite;
505}
506
507static void ptcache_particle_extra_write(void *psys_v, PTCacheMem *pm, int /*cfra*/)
508{
509 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
510
511 if (psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid &&
513 psys->fluid_springs)
514 {
517 }
518}
519
520static void ptcache_particle_extra_read(void *psys_v, PTCacheMem *pm, float /*cfra*/)
521{
522 ParticleSystem *psys = static_cast<ParticleSystem *>(psys_v);
523 PTCacheExtra *extra = static_cast<PTCacheExtra *>(pm->extradata.first);
524
525 for (; extra; extra = extra->next) {
526 switch (extra->type) {
528 if (psys->fluid_springs) {
530 }
531
532 psys->fluid_springs = static_cast<ParticleSpring *>(MEM_dupallocN(extra->data));
533 psys->tot_fluidsprings = psys->alloc_fluidsprings = extra->totdata;
534 break;
535 }
536 }
537 }
538}
539
540/* Cloth functions */
541static int ptcache_cloth_write(int index, void *cloth_v, void **data, int /*cfra*/)
542{
543 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
544 Cloth *cloth = clmd->clothObject;
545 ClothVertex *vert = cloth->verts + index;
546
550
551 return 1;
552}
554 int index, void *cloth_v, void **data, float /*cfra*/, const float *old_data)
555{
556 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
557 Cloth *cloth = clmd->clothObject;
558 ClothVertex *vert = cloth->verts + index;
559
560 if (old_data) {
561 memcpy(vert->x, data, sizeof(float[3]));
562 memcpy(vert->xconst, data + 3, sizeof(float[3]));
563 memcpy(vert->v, data + 6, sizeof(float[3]));
564 }
565 else {
566 PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, vert->x);
567 PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, vert->v);
569 }
570}
571static void ptcache_cloth_interpolate(int index,
572 void *cloth_v,
573 void **data,
574 float cfra,
575 float cfra1,
576 float cfra2,
577 const float *old_data)
578{
579 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
580 Cloth *cloth = clmd->clothObject;
581 ClothVertex *vert = cloth->verts + index;
582 ParticleKey keys[4];
583 float dfra;
584
585 if (cfra1 == cfra2) {
586 return;
587 }
588
589 copy_v3_v3(keys[1].co, vert->x);
590 copy_v3_v3(keys[1].vel, vert->v);
591
592 if (old_data) {
593 memcpy(keys[2].co, old_data, sizeof(float[3]));
594 memcpy(keys[2].vel, old_data + 6, sizeof(float[3]));
595 }
596 else {
597 BKE_ptcache_make_particle_key(keys + 2, 0, data, cfra2);
598 }
599
600 dfra = cfra2 - cfra1;
601
602 mul_v3_fl(keys[1].vel, dfra);
603 mul_v3_fl(keys[2].vel, dfra);
604
605 psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, true);
606
607 mul_v3_fl(keys->vel, 1.0f / dfra);
608
609 copy_v3_v3(vert->x, keys->co);
610 copy_v3_v3(vert->v, keys->vel);
611
612 /* should vert->xconst be interpolated somehow too? - jahka */
613}
614
615static void ptcache_cloth_extra_write(void *cloth_v, PTCacheMem *pm, int /*cfra*/)
616{
617 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
618 Cloth *cloth = clmd->clothObject;
619
620 if (!is_zero_v3(cloth->average_acceleration)) {
621 ptcache_add_extra_data(pm, BPHYS_EXTRA_CLOTH_ACCELERATION, 1, cloth->average_acceleration);
622 }
623}
624static void ptcache_cloth_extra_read(void *cloth_v, PTCacheMem *pm, float /*cfra*/)
625{
626 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
627 Cloth *cloth = clmd->clothObject;
628 PTCacheExtra *extra = static_cast<PTCacheExtra *>(pm->extradata.first);
629
630 zero_v3(cloth->average_acceleration);
631
632 for (; extra; extra = extra->next) {
633 switch (extra->type) {
635 copy_v3_v3(cloth->average_acceleration, static_cast<const float *>(extra->data));
636 break;
637 }
638 }
639 }
640}
641
642static int ptcache_cloth_totpoint(void *cloth_v, int /*cfra*/)
643{
644 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
645 return clmd->clothObject ? clmd->clothObject->mvert_num : 0;
646}
647
648static void ptcache_cloth_error(const ID *owner_id, void *cloth_v, const char *message)
649{
650 ClothModifierData *clmd = static_cast<ClothModifierData *>(cloth_v);
651 BLI_assert(GS(owner_id->name) == ID_OB);
652 if (clmd->hairdata == nullptr) {
653 /* If there is hair data, this modifier does not actually exist on the object. */
654 BKE_modifier_set_error((Object *)owner_id, &clmd->modifier, "%s", message);
655 }
656}
657
658static int ptcache_dynamicpaint_totpoint(void *sd, int /*cfra*/)
659{
661
662 if (!surface->data) {
663 return 0;
664 }
665
666 return surface->data->total_points;
667}
668
669static void ptcache_dynamicpaint_error(const ID * /*owner_id*/,
670 void * /*sd*/,
671 const char * /*message*/)
672{
673 /* ignored for now */
674}
675
676#define DPAINT_CACHE_VERSION "1.01"
677
679{
680 DynamicPaintSurface *surface = (DynamicPaintSurface *)dp_v;
681 int cache_compress = PTCACHE_COMPRESS_LZO;
682
683 /* version header */
684 ptcache_file_write(pf, DPAINT_CACHE_VERSION, 1, sizeof(char[4]));
685
686 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
687 int total_points = surface->data->total_points;
688 uint in_len;
689 uchar *out;
690
691 /* cache type */
692 ptcache_file_write(pf, &surface->type, 1, sizeof(int));
693
694 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
695 in_len = sizeof(PaintPoint) * total_points;
696 }
698 in_len = sizeof(float) * total_points;
699 }
700 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
701 in_len = sizeof(PaintWavePoint) * total_points;
702 }
703 else {
704 return 0;
705 }
706
707 out = (uchar *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
708
710 pf, (uchar *)surface->data->type_data, in_len, out, cache_compress);
711 MEM_freeN(out);
712 }
713 return 1;
714}
716{
717 DynamicPaintSurface *surface = (DynamicPaintSurface *)dp_v;
718 char version[4];
719
720 /* version header */
721 ptcache_file_read(pf, version, 1, sizeof(char[4]));
722 if (!STREQLEN(version, DPAINT_CACHE_VERSION, 4)) {
723 CLOG_ERROR(&LOG, "Dynamic Paint: Invalid cache version: '%c%c%c%c'!", UNPACK4(version));
724 return 0;
725 }
726
727 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
728 uint data_len;
729 int surface_type;
730
731 /* cache type */
732 ptcache_file_read(pf, &surface_type, 1, sizeof(int));
733
734 if (surface_type != surface->type) {
735 return 0;
736 }
737
738 /* read surface data */
739 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
740 data_len = sizeof(PaintPoint);
741 }
743 data_len = sizeof(float);
744 }
745 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
746 data_len = sizeof(PaintWavePoint);
747 }
748 else {
749 return 0;
750 }
751
753 pf, (uchar *)surface->data->type_data, data_len * surface->data->total_points);
754 }
755 return 1;
756}
757
758/* Rigid Body functions */
759static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int /*cfra*/)
760{
761 RigidBodyWorld *rbw = static_cast<RigidBodyWorld *>(rb_v);
762 Object *ob = nullptr;
763
764 if (rbw->objects) {
765 ob = rbw->objects[index];
766 }
767
768 if (ob && ob->rigidbody_object) {
769 RigidBodyOb *rbo = ob->rigidbody_object;
770
771 if (rbo->type == RBO_TYPE_ACTIVE && rbo->shared->physics_object != nullptr) {
772#ifdef WITH_BULLET
773 RB_body_get_position(static_cast<rbRigidBody *>(rbo->shared->physics_object), rbo->pos);
774 RB_body_get_orientation(static_cast<rbRigidBody *>(rbo->shared->physics_object), rbo->orn);
775#endif
778 }
779 }
780
781 return 1;
782}
784 int index, void *rb_v, void **data, float /*cfra*/, const float *old_data)
785{
786 RigidBodyWorld *rbw = static_cast<RigidBodyWorld *>(rb_v);
787 Object *ob = nullptr;
788
789 if (rbw->objects) {
790 ob = rbw->objects[index];
791 }
792
793 if (ob && ob->rigidbody_object) {
794 RigidBodyOb *rbo = ob->rigidbody_object;
795
796 if (rbo->type == RBO_TYPE_ACTIVE) {
797
798 if (old_data) {
799 memcpy(rbo->pos, data, sizeof(float[3]));
800 memcpy(rbo->orn, data + 3, sizeof(float[4]));
801 }
802 else {
805 }
806 }
807 }
808}
809static void ptcache_rigidbody_interpolate(int index,
810 void *rb_v,
811 void **data,
812 float cfra,
813 float cfra1,
814 float cfra2,
815 const float *old_data)
816{
817 RigidBodyWorld *rbw = static_cast<RigidBodyWorld *>(rb_v);
818 Object *ob = nullptr;
819
820 if (rbw->objects) {
821 ob = rbw->objects[index];
822 }
823
824 if (ob && ob->rigidbody_object) {
825 RigidBodyOb *rbo = ob->rigidbody_object;
826
827 if (rbo->type == RBO_TYPE_ACTIVE) {
828 /* It may be possible to improve results by taking into account velocity
829 * for interpolation using psys_interpolate_particle, however this is
830 * not currently cached. */
831 float pos[3], orn[4];
832
833 if (old_data) {
834 memcpy(pos, data, sizeof(float[3]));
835 memcpy(orn, data + 3, sizeof(float[4]));
836 }
837 else {
840 }
841
842 const float t = (cfra - cfra1) / (cfra2 - cfra1);
843 interp_v3_v3v3(rbo->pos, rbo->pos, pos, t);
844 interp_qt_qtqt(rbo->orn, rbo->orn, orn, t);
845 }
846 }
847}
848static int ptcache_rigidbody_totpoint(void *rb_v, int /*cfra*/)
849{
850 RigidBodyWorld *rbw = static_cast<RigidBodyWorld *>(rb_v);
851
852 return rbw->numbodies;
853}
854
855static void ptcache_rigidbody_error(const ID * /*owner_id*/,
856 void * /*rb_v*/,
857 const char * /*message*/)
858{
859 /* ignored for now */
860}
861
862/* Creating ID's */
863
865{
866 memset(pid, 0, sizeof(PTCacheID));
867
868 pid->owner_id = &ob->id;
869 pid->calldata = sb;
871 pid->cache = sb->shared->pointcache;
872 pid->cache_ptr = &sb->shared->pointcache;
873 pid->ptcaches = &sb->shared->ptcaches;
876
880
881 pid->write_stream = nullptr;
882 pid->read_stream = nullptr;
883
884 pid->write_extra_data = nullptr;
885 pid->read_extra_data = nullptr;
886 pid->interpolate_extra_data = nullptr;
887
890
892 pid->info_types = 0;
893
894 pid->stack_index = pid->cache->index;
895
896 pid->default_step = 1;
897 pid->max_step = 20;
899}
901{
902 memset(pid, 0, sizeof(PTCacheID));
903
904 pid->owner_id = &ob->id;
905 pid->calldata = psys;
907 pid->stack_index = psys->pointcache->index;
908 pid->cache = psys->pointcache;
909 pid->cache_ptr = &psys->pointcache;
910 pid->ptcaches = &psys->ptcaches;
911
912 if (psys->part->type != PART_HAIR) {
914 }
915
919
923
924 pid->write_stream = nullptr;
925 pid->read_stream = nullptr;
926
927 pid->write_extra_data = nullptr;
928 pid->read_extra_data = nullptr;
929 pid->interpolate_extra_data = nullptr;
930
933
934 pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_VELOCITY) |
935 (1 << BPHYS_DATA_INDEX);
936
937 if (psys->part->phystype == PART_PHYS_BOIDS) {
938 pid->data_types |= (1 << BPHYS_DATA_AVELOCITY) | (1 << BPHYS_DATA_ROTATION) |
939 (1 << BPHYS_DATA_BOIDS);
940 }
941 else if (psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid &&
943 {
946 }
947
948 if (psys->part->flag & PART_ROTATIONS) {
949 pid->data_types |= (1 << BPHYS_DATA_ROTATION);
950
951 if (psys->part->rotmode != PART_ROT_VEL || psys->part->avemode == PART_AVE_RAND ||
952 psys->part->avefac != 0.0f)
953 {
954 pid->data_types |= (1 << BPHYS_DATA_AVELOCITY);
955 }
956 }
957
958 pid->info_types = (1 << BPHYS_DATA_TIMES);
959
960 pid->default_step = 1;
961 pid->max_step = 20;
963}
965{
966 memset(pid, 0, sizeof(PTCacheID));
967
968 pid->owner_id = &ob->id;
969 pid->calldata = clmd;
971 pid->stack_index = clmd->point_cache->index;
972 pid->cache = clmd->point_cache;
973 pid->cache_ptr = &clmd->point_cache;
974 pid->ptcaches = &clmd->ptcaches;
977
981
982 pid->write_stream = nullptr;
983 pid->read_stream = nullptr;
984
987 pid->interpolate_extra_data = nullptr;
988
991
992 pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_VELOCITY) |
993 (1 << BPHYS_DATA_XCONST);
994 pid->info_types = 0;
995
996 pid->default_step = 1;
997 pid->max_step = 1;
999}
1000
1002{
1003 FluidDomainSettings *fds = fmd->domain;
1004
1005 memset(pid, 0, sizeof(PTCacheID));
1006
1007 pid->owner_id = &ob->id;
1008 pid->calldata = fmd;
1009
1011 pid->stack_index = fds->point_cache[0]->index;
1012
1013 pid->cache = fds->point_cache[0];
1014 pid->cache_ptr = &(fds->point_cache[0]);
1015 pid->ptcaches = &(fds->ptcaches[0]);
1016}
1017
1019{
1020
1021 memset(pid, 0, sizeof(PTCacheID));
1022
1023 pid->owner_id = &ob->id;
1024 pid->calldata = surface;
1026 pid->cache = surface->pointcache;
1027 pid->cache_ptr = &surface->pointcache;
1028 pid->ptcaches = &surface->ptcaches;
1031
1032 pid->write_point = nullptr;
1033 pid->read_point = nullptr;
1034 pid->interpolate_point = nullptr;
1035
1038
1039 pid->write_extra_data = nullptr;
1040 pid->read_extra_data = nullptr;
1041 pid->interpolate_extra_data = nullptr;
1042
1045
1047 pid->info_types = 0;
1048
1049 pid->stack_index = pid->cache->index;
1050
1051 pid->default_step = 1;
1052 pid->max_step = 1;
1054}
1055
1057{
1058
1059 memset(pid, 0, sizeof(PTCacheID));
1060
1061 pid->owner_id = ob != nullptr ? &ob->id : nullptr;
1062 pid->calldata = rbw;
1064 pid->cache = rbw->shared->pointcache;
1065 pid->cache_ptr = &rbw->shared->pointcache;
1066 pid->ptcaches = &rbw->shared->ptcaches;
1069
1073
1074 pid->write_stream = nullptr;
1075 pid->read_stream = nullptr;
1076
1077 pid->write_extra_data = nullptr;
1078 pid->read_extra_data = nullptr;
1079 pid->interpolate_extra_data = nullptr;
1080
1083
1084 pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_ROTATION);
1085 pid->info_types = 0;
1086
1087 pid->stack_index = pid->cache->index;
1088
1089 pid->default_step = 1;
1090 pid->max_step = 1;
1092}
1093
1095{
1096 PTCacheID result = {nullptr};
1097
1098 ListBase pidlist;
1099 BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
1100
1101 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
1102 if (pid->cache == cache) {
1103 result = *pid;
1104 break;
1105 }
1106 }
1107
1108 BLI_freelistN(&pidlist);
1109
1110 return result;
1111}
1112
1113/* Callback which is used by point cache foreach() family of functions.
1114 *
1115 * Receives ID of the point cache.
1116 *
1117 * NOTE: This ID is owned by foreach() routines and can not be used outside of
1118 * the foreach loop. This means that if one wants to store them those are to be
1119 * malloced and copied over.
1120 *
1121 * If the function returns false, then foreach() loop aborts.
1122 */
1123
1125{
1126 PTCacheID pid;
1127 for (ParticleSystem *psys = static_cast<ParticleSystem *>(object->particlesystem.first);
1128 psys != nullptr;
1129 psys = psys->next)
1130 {
1131 if (psys->part == nullptr) {
1132 continue;
1133 }
1134 /* Check to make sure point cache is actually used by the particles. */
1135 if (ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
1136 continue;
1137 }
1138/* Hair needs to be included in id-list for cache edit mode to work. */
1139#if 0
1140 if ((psys->part->type == PART_HAIR) && (psys->flag & PSYS_HAIR_DYNAMICS) == 0) {
1141 continue;
1142 }
1143#endif
1144 if (psys->part->type == PART_FLUID) {
1145 continue;
1146 }
1147 BKE_ptcache_id_from_particles(&pid, object, psys);
1148 /* TODO figure out the particle modifier for this system and put it here. */
1149 if (!callback(pid, nullptr)) {
1150 return false;
1151 }
1152 }
1153 return true;
1154}
1155
1157{
1158 PTCacheID pid;
1159 for (ModifierData *md = static_cast<ModifierData *>(object->modifiers.first); md != nullptr;
1160 md = md->next)
1161 {
1162 if (md->type == eModifierType_Cloth) {
1163 BKE_ptcache_id_from_cloth(&pid, object, (ClothModifierData *)md);
1164 if (!callback(pid, md)) {
1165 return false;
1166 }
1167 }
1168 else if (md->type == eModifierType_Fluid) {
1170 if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
1171 BKE_ptcache_id_from_smoke(&pid, object, (FluidModifierData *)md);
1172 if (!callback(pid, md)) {
1173 return false;
1174 }
1175 }
1176 }
1177 else if (md->type == eModifierType_DynamicPaint) {
1179 if (pmd->canvas) {
1180 DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(
1181 pmd->canvas->surfaces.first);
1182 for (; surface; surface = surface->next) {
1183 BKE_ptcache_id_from_dynamicpaint(&pid, object, surface);
1184 if (!callback(pid, md)) {
1185 return false;
1186 }
1187 }
1188 }
1189 }
1190 }
1191 return true;
1192}
1193
1194/* Return false if any of callbacks returned false. */
1196 Object *object,
1197 int duplis,
1199{
1200 PTCacheID pid;
1201
1202 if (object != nullptr) {
1203 /* Soft body. */
1204 if (object->soft != nullptr) {
1205 BKE_ptcache_id_from_softbody(&pid, object, object->soft);
1206 if (!callback(pid, nullptr)) {
1207 return false;
1208 }
1209 }
1210 /* Particle systems. */
1212 return false;
1213 }
1214 /* Modifiers. */
1216 return false;
1217 }
1218 /* Consider all object in dupli-groups to be part of the same object,
1219 * for baking with linking dupli-groups. Once we have better overrides
1220 * this can be revisited so users select the local objects directly. */
1221 if (scene != nullptr && (duplis-- > 0) && (object->instance_collection != nullptr)) {
1222 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
1223 if (current_object == object) {
1224 continue;
1225 }
1226 foreach_object_ptcache(scene, current_object, duplis, callback);
1227 }
1229 }
1230 }
1231
1232 /* Rigid body. */
1233 if (scene != nullptr && (object == nullptr || object->rigidbody_object != nullptr) &&
1234 scene->rigidbody_world != nullptr)
1235 {
1236 BKE_ptcache_id_from_rigidbody(&pid, object, scene->rigidbody_world);
1237 if (!callback(pid, nullptr)) {
1238 return false;
1239 }
1240 }
1241 return true;
1242}
1243
1244void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
1245{
1246 lb->first = lb->last = nullptr;
1247 foreach_object_ptcache(scene, ob, duplis, [&](PTCacheID &pid, ModifierData * /*md*/) -> bool {
1248 PTCacheID *own_pid = static_cast<PTCacheID *>(MEM_mallocN(sizeof(PTCacheID), "PTCacheID"));
1249 *own_pid = pid;
1250 BLI_addtail(lb, own_pid);
1251 return true;
1252 });
1253}
1254
1256{
1257 foreach_object_ptcache(&scene, &ob, duplis, fn);
1258}
1259
1260bool BKE_ptcache_object_has(Scene *scene, Object *ob, int duplis)
1261{
1262 bool has_point_cache = false;
1263 foreach_object_ptcache(scene, ob, duplis, [&](PTCacheID & /*pid*/, ModifierData * /*md*/) {
1264 has_point_cache = true;
1265 return false;
1266 });
1267 return has_point_cache;
1268}
1269
1270/* File handling */
1271
1272static const char *ptcache_file_extension(const PTCacheID *pid)
1273{
1274 switch (pid->file_type) {
1275 default:
1277 return PTCACHE_EXT;
1278 }
1279}
1280
1284static int ptcache_frame_from_filename(const char *filename, const char *ext)
1285{
1286 const int frame_len = 6;
1287 const int ext_len = frame_len + strlen(ext);
1288 const int len = strlen(filename);
1289
1290 /* could crash if trying to copy a string out of this range */
1291 if (len > ext_len) {
1292 /* Using frame_len here gives compile error (VLA). */
1293 char num[/*frame_len*/ 6 + 1];
1294 STRNCPY(num, filename + len - ext_len);
1295
1296 return atoi(num);
1297 }
1298
1299 return -1;
1300}
1301
1302/* Takes an Object ID and returns a unique name
1303 * - id: object id
1304 * - cfra: frame for the cache, can be negative
1305 * - stack_index: index in the modifier stack. we can have cache for more than one stack_index
1306 */
1307
1308#define MAX_PTCACHE_PATH FILE_MAX
1309#define MAX_PTCACHE_FILE (FILE_MAX * 2)
1310
1312{
1313 const char *blendfile_path = BKE_main_blendfile_path_from_global();
1314 Library *lib = (pid->owner_id) ? pid->owner_id->lib : nullptr;
1315 const char *blendfile_path_lib = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
1316 lib->runtime.filepath_abs :
1317 blendfile_path;
1318
1319 if (pid->cache->flag & PTCACHE_EXTERNAL) {
1321
1322 if (BLI_path_is_rel(dirname)) {
1323 BLI_path_abs(dirname, blendfile_path_lib);
1324 }
1325
1326 return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
1327 }
1328 if ((blendfile_path[0] != '\0') || lib) {
1329 char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
1330
1331 BLI_path_split_file_part(blendfile_path_lib, file, sizeof(file));
1332 /* Remove the `.blend` extension. */
1334
1335 /* Add blend file name to pointcache dir. */
1337
1338 BLI_path_abs(dirname, blendfile_path_lib);
1339 return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
1340 }
1341
1342 /* use the temp path. this is weak but better than not using point cache at all */
1343 /* temporary directory is assumed to exist and ALWAYS has a trailing slash */
1345
1346 return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
1347}
1348
1350 char filepath[MAX_PTCACHE_FILE],
1351 const size_t filepath_len,
1352 const bool use_frame_number,
1353 const int cfra)
1354{
1355 size_t len = filepath_len;
1356 char *filename_ext;
1357 filename_ext = filepath + filepath_len;
1358 *filename_ext = '\0';
1359
1360 /* PointCaches are inserted in object's list on demand, we need a valid index now. */
1361 if (pid->cache->index < 0) {
1362 BLI_assert(GS(pid->owner_id->name) == ID_OB);
1364 }
1365
1366 const char *ext = ptcache_file_extension(pid);
1367 if (use_frame_number) {
1368 if (pid->cache->flag & PTCACHE_EXTERNAL) {
1369 if (pid->cache->index >= 0) {
1371 filename_ext, MAX_PTCACHE_FILE - len, "_%06d_%02u%s", cfra, pid->stack_index, ext);
1372 }
1373 else {
1374 len += BLI_snprintf_rlen(filename_ext, MAX_PTCACHE_FILE - len, "_%06d%s", cfra, ext);
1375 }
1376 }
1377 else {
1379 filename_ext, MAX_PTCACHE_FILE - len, "_%06d_%02u%s", cfra, pid->stack_index, ext);
1380 }
1381 }
1382 else {
1383 if (pid->cache->flag & PTCACHE_EXTERNAL) {
1384 if (pid->cache->index >= 0) {
1386 filename_ext, MAX_PTCACHE_FILE - len, "_%02u%s", pid->stack_index, ext);
1387 }
1388 else {
1389 len += BLI_snprintf_rlen(filename_ext, MAX_PTCACHE_FILE - len, "%s", ext);
1390 }
1391 }
1392 else {
1394 filename_ext, MAX_PTCACHE_FILE - len, "_%02u%s", pid->stack_index, ext);
1395 }
1396 }
1397
1398 return len;
1399}
1400
1402 char filepath[MAX_PTCACHE_FILE],
1403 int cfra,
1404 const bool do_path,
1405 const bool do_ext)
1406{
1407 int len = 0;
1408 const char *idname;
1409 char *newname;
1410 filepath[0] = '\0';
1411 newname = filepath;
1412
1413 if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
1414 const char *blendfile_path = BKE_main_blendfile_path_from_global();
1415 if (blendfile_path[0] == '\0') {
1416 return 0; /* save blend file before using disk pointcache */
1417 }
1418 }
1419
1420 /* start with temp dir */
1421 if (do_path) {
1422 len = ptcache_path(pid, filepath);
1423 newname += len;
1424 }
1425 if (pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
1426 idname = (pid->owner_id->name + 2);
1427 /* convert chars to hex so they are always a valid filename */
1428 while ('\0' != *idname) {
1429 /* Always 2 unless there isn't enough room in the string. */
1430 const int temp = BLI_snprintf_rlen(newname, MAX_PTCACHE_FILE - len, "%02X", uint(*idname++));
1431 newname += temp;
1432 len += temp;
1433 }
1434 }
1435 else {
1436 int temp = BLI_strncpy_rlen(newname, pid->cache->name, MAX_PTCACHE_FILE - len);
1437 newname += temp;
1438 len += temp;
1439 }
1440 UNUSED_VARS(newname);
1441
1442 if (do_ext) {
1443 len += ptcache_filepath_ext_append(pid, filepath, size_t(len), true, cfra);
1444 }
1445
1446 return len; /* make sure the above string is always 16 chars */
1447}
1448
1452static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
1453{
1454 PTCacheFile *pf;
1455 FILE *fp = nullptr;
1456 char filepath[MAX_PTCACHE_FILE];
1457
1458#ifndef DURIAN_POINTCACHE_LIB_OK
1459 /* don't allow writing for linked objects */
1460 if (pid->owner_id->lib && mode == PTCACHE_FILE_WRITE) {
1461 return nullptr;
1462 }
1463#endif
1464 if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
1465 const char *blendfile_path = BKE_main_blendfile_path_from_global();
1466 if (blendfile_path[0] == '\0') {
1467 return nullptr; /* save blend file before using disk pointcache */
1468 }
1469 }
1470
1471 ptcache_filepath(pid, filepath, cfra, true, true);
1472
1473 if (mode == PTCACHE_FILE_READ) {
1474 fp = BLI_fopen(filepath, "rb");
1475 }
1476 else if (mode == PTCACHE_FILE_WRITE) {
1478 fp = BLI_fopen(filepath, "wb");
1479 }
1480 else if (mode == PTCACHE_FILE_UPDATE) {
1482 fp = BLI_fopen(filepath, "rb+");
1483 }
1484
1485 if (!fp) {
1486 return nullptr;
1487 }
1488
1489 pf = static_cast<PTCacheFile *>(MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile"));
1490 pf->fp = fp;
1491 pf->old_format = 0;
1492 pf->frame = cfra;
1493
1494 return pf;
1495}
1497{
1498 if (pf) {
1499 fclose(pf->fp);
1500 MEM_freeN(pf);
1501 }
1502}
1503
1505{
1506 int r = 0;
1507 uchar compressed = 0;
1508 size_t in_len;
1509#ifdef WITH_LZO
1510 size_t out_len = len;
1511#endif
1512 uchar *in;
1513 uchar *props = static_cast<uchar *>(MEM_callocN(sizeof(char[16]), "tmp"));
1514
1515 ptcache_file_read(pf, &compressed, 1, sizeof(uchar));
1516 if (compressed) {
1517 uint size;
1518 ptcache_file_read(pf, &size, 1, sizeof(uint));
1519 in_len = size_t(size);
1520 if (in_len == 0) {
1521 /* do nothing */
1522 }
1523 else {
1524 in = (uchar *)MEM_callocN(sizeof(uchar) * in_len, "pointcache_compressed_buffer");
1525 ptcache_file_read(pf, in, in_len, sizeof(uchar));
1526#ifdef WITH_LZO
1527 if (compressed == 1) {
1528 r = lzo1x_decompress_safe(in, (lzo_uint)in_len, result, (lzo_uint *)&out_len, nullptr);
1529 }
1530#endif
1531#ifdef WITH_LZMA
1532 if (compressed == 2) {
1533 size_t sizeOfIt;
1534 size_t leni = in_len, leno = len;
1535 ptcache_file_read(pf, &size, 1, sizeof(uint));
1536 sizeOfIt = size_t(size);
1537 ptcache_file_read(pf, props, sizeOfIt, sizeof(uchar));
1538 r = LzmaUncompress(result, &leno, in, &leni, props, sizeOfIt);
1539 }
1540#endif
1541 MEM_freeN(in);
1542 }
1543 }
1544 else {
1545 ptcache_file_read(pf, result, len, sizeof(uchar));
1546 }
1547
1548 MEM_freeN(props);
1549
1550 return r;
1551}
1553 PTCacheFile *pf, uchar *in, uint in_len, uchar *out, int mode)
1554{
1555 int r = 0;
1556 uchar compressed = 0;
1557 size_t out_len = 0;
1558 uchar *props = static_cast<uchar *>(MEM_callocN(sizeof(char[16]), "tmp"));
1559 size_t sizeOfIt = 5;
1560
1561 (void)mode; /* unused when building w/o compression */
1562
1563#ifdef WITH_LZO
1564 out_len = LZO_OUT_LEN(in_len);
1565 if (mode == PTCACHE_COMPRESS_LZO) {
1566 LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS);
1567
1568 r = lzo1x_1_compress(in, (lzo_uint)in_len, out, (lzo_uint *)&out_len, wrkmem);
1569 if (!(r == LZO_E_OK) || (out_len >= in_len)) {
1570 compressed = 0;
1571 }
1572 else {
1573 compressed = 1;
1574 }
1575 }
1576#endif
1577#ifdef WITH_LZMA
1578 if (mode == PTCACHE_COMPRESS_LZMA) {
1579
1580 r = LzmaCompress(out,
1581 &out_len,
1582 in,
1583 in_len, /* Assume `sizeof(char) == 1`. */
1584 props,
1585 &sizeOfIt,
1586 5,
1587 1 << 24,
1588 3,
1589 0,
1590 2,
1591 32,
1592 2);
1593
1594 if (!(r == SZ_OK) || (out_len >= in_len)) {
1595 compressed = 0;
1596 }
1597 else {
1598 compressed = 2;
1599 }
1600 }
1601#endif
1602
1603 ptcache_file_write(pf, &compressed, 1, sizeof(uchar));
1604 if (compressed) {
1605 uint size = out_len;
1606 ptcache_file_write(pf, &size, 1, sizeof(uint));
1607 ptcache_file_write(pf, out, out_len, sizeof(uchar));
1608 }
1609 else {
1610 ptcache_file_write(pf, in, in_len, sizeof(uchar));
1611 }
1612
1613 if (compressed == 2) {
1614 uint size = sizeOfIt;
1615 ptcache_file_write(pf, &sizeOfIt, 1, sizeof(uint));
1616 ptcache_file_write(pf, props, size, sizeof(uchar));
1617 }
1618
1619 MEM_freeN(props);
1620
1621 return r;
1622}
1623static int ptcache_file_read(PTCacheFile *pf, void *f, uint tot, uint size)
1624{
1625 return (fread(f, size, tot, pf->fp) == tot);
1626}
1627static int ptcache_file_write(PTCacheFile *pf, const void *f, uint tot, uint size)
1628{
1629 return (fwrite(f, size, tot, pf->fp) == tot);
1630}
1632{
1633 int i;
1634
1635 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1636 if ((pf->data_types & (1 << i)) && !ptcache_file_read(pf, pf->cur[i], 1, ptcache_data_size[i]))
1637 {
1638 return 0;
1639 }
1640 }
1641
1642 return 1;
1643}
1645{
1646 int i;
1647
1648 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1649 if ((pf->data_types & (1 << i)) &&
1650 !ptcache_file_write(pf, pf->cur[i], 1, ptcache_data_size[i]))
1651 {
1652 return 0;
1653 }
1654 }
1655
1656 return 1;
1657}
1659{
1660 uint typeflag = 0;
1661 int error = 0;
1662 char bphysics[8];
1663
1664 pf->data_types = 0;
1665
1666 if (fread(bphysics, sizeof(char), 8, pf->fp) != 8) {
1667 error = 1;
1668 }
1669
1670 if (!error && !STREQLEN(bphysics, "BPHYSICS", 8)) {
1671 error = 1;
1672 }
1673
1674 if (!error && !fread(&typeflag, sizeof(uint), 1, pf->fp)) {
1675 error = 1;
1676 }
1677
1678 pf->type = (typeflag & PTCACHE_TYPEFLAG_TYPEMASK);
1679 pf->flag = (typeflag & PTCACHE_TYPEFLAG_FLAGMASK);
1680
1681 /* if there was an error set file as it was */
1682 if (error) {
1683 BLI_fseek(pf->fp, 0, SEEK_SET);
1684 }
1685
1686 return !error;
1687}
1689{
1690 const char *bphysics = "BPHYSICS";
1691 uint typeflag = pf->type + pf->flag;
1692
1693 if (fwrite(bphysics, sizeof(char), 8, pf->fp) != 8) {
1694 return 0;
1695 }
1696
1697 if (!fwrite(&typeflag, sizeof(uint), 1, pf->fp)) {
1698 return 0;
1699 }
1700
1701 return 1;
1702}
1703
1704/* Data pointer handling. */
1705
1706int BKE_ptcache_data_size(int data_type)
1707{
1708 return ptcache_data_size[data_type];
1709}
1710
1712{
1713 int data_types = pf->data_types;
1714
1715 pf->cur[BPHYS_DATA_INDEX] = (data_types & (1 << BPHYS_DATA_INDEX)) ? &pf->data.index : nullptr;
1716 pf->cur[BPHYS_DATA_LOCATION] = (data_types & (1 << BPHYS_DATA_LOCATION)) ? &pf->data.loc :
1717 nullptr;
1718 pf->cur[BPHYS_DATA_VELOCITY] = (data_types & (1 << BPHYS_DATA_VELOCITY)) ? &pf->data.vel :
1719 nullptr;
1720 pf->cur[BPHYS_DATA_ROTATION] = (data_types & (1 << BPHYS_DATA_ROTATION)) ? &pf->data.rot :
1721 nullptr;
1722 pf->cur[BPHYS_DATA_AVELOCITY] = (data_types & (1 << BPHYS_DATA_AVELOCITY)) ? &pf->data.ave :
1723 nullptr;
1724 pf->cur[BPHYS_DATA_SIZE] = (data_types & (1 << BPHYS_DATA_SIZE)) ? &pf->data.size : nullptr;
1725 pf->cur[BPHYS_DATA_TIMES] = (data_types & (1 << BPHYS_DATA_TIMES)) ? &pf->data.times : nullptr;
1726 pf->cur[BPHYS_DATA_BOIDS] = (data_types & (1 << BPHYS_DATA_BOIDS)) ? &pf->data.boids : nullptr;
1727}
1728
1730{
1731 if (pm->totpoint > 0 && pm->data[BPHYS_DATA_INDEX]) {
1732 uint *data = static_cast<uint *>(pm->data[BPHYS_DATA_INDEX]);
1733 uint mid, low = 0, high = pm->totpoint - 1;
1734
1735 if (index < *data || index > *(data + high)) {
1736 return -1;
1737 }
1738
1739 /* check simple case for continuous indexes first */
1740 if (index - *data < high && data[index - *data] == index) {
1741 return index - *data;
1742 }
1743
1744 while (low <= high) {
1745 mid = (low + high) / 2;
1746
1747 if (data[mid] > index) {
1748 high = mid - 1;
1749 }
1750 else if (data[mid] < index) {
1751 low = mid + 1;
1752 }
1753 else {
1754 return mid;
1755 }
1756 }
1757
1758 return -1;
1759 }
1760
1761 return (index < pm->totpoint ? index : -1);
1762}
1763
1765{
1766 int data_types = pm->data_types;
1767 int i;
1768
1769 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1770 cur[i] = ((data_types & (1 << i)) ? pm->data[i] : nullptr);
1771 }
1772}
1773
1775{
1776 int i;
1777
1778 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1779 if (cur[i]) {
1780 cur[i] = (char *)cur[i] + ptcache_data_size[i];
1781 }
1782 }
1783}
1784int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm, void *cur[BPHYS_TOT_DATA])
1785{
1786 int data_types = pm->data_types;
1787 int i, index = BKE_ptcache_mem_index_find(pm, point_index);
1788
1789 if (index < 0) {
1790 /* Can't give proper location without reallocation, so don't give any location.
1791 * Some points will be cached improperly, but this only happens with simulation
1792 * steps bigger than cache->step, so the cache has to be recalculated anyways
1793 * at some point.
1794 */
1795 return 0;
1796 }
1797
1798 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1799 cur[i] = (data_types & (1 << i)) ? (char *)pm->data[i] + index * ptcache_data_size[i] :
1800 nullptr;
1801 }
1802
1803 return 1;
1804}
1806{
1807 int data_types = pm->data_types;
1808 int totpoint = pm->totpoint;
1809 int i;
1810
1811 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1812 if (data_types & (1 << i)) {
1813 pm->data[i] = MEM_callocN(totpoint * ptcache_data_size[i], "PTCache Data");
1814 }
1815 }
1816}
1818{
1819 void **data = pm->data;
1820 int i;
1821
1822 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1823 if (data[i]) {
1824 MEM_freeN(data[i]);
1825 }
1826 }
1827}
1828static void ptcache_data_copy(void *from[], void *to[])
1829{
1830 int i;
1831 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1832 /* NOTE: durian file 03.4b_comp crashes if to[i] is not tested
1833 * its nullptr, not sure if this should be fixed elsewhere but for now its needed */
1834 if (from[i] && to[i]) {
1835 memcpy(to[i], from[i], ptcache_data_size[i]);
1836 }
1837 }
1838}
1839
1841{
1842 PTCacheExtra *extra = static_cast<PTCacheExtra *>(pm->extradata.first);
1843
1844 if (extra) {
1845 for (; extra; extra = extra->next) {
1846 if (extra->data) {
1847 MEM_freeN(extra->data);
1848 }
1849 }
1850
1852 }
1853}
1854
1856{
1859}
1860
1862{
1863 if (pid->type == PTCACHE_TYPE_SOFTBODY) {
1864 return sizeof(float[6]);
1865 }
1866 if (pid->type == PTCACHE_TYPE_PARTICLES) {
1867 return sizeof(ParticleKey);
1868 }
1869 if (pid->type == PTCACHE_TYPE_CLOTH) {
1870 return sizeof(float[9]);
1871 }
1872
1873 return 0;
1874}
1875
1876static void ptcache_find_frames_around(PTCacheID *pid, uint frame, int *r_fra1, int *r_fra2)
1877{
1878 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
1879 int cfra1 = frame, cfra2 = frame + 1;
1880
1881 while (cfra1 >= pid->cache->startframe && !BKE_ptcache_id_exist(pid, cfra1)) {
1882 cfra1--;
1883 }
1884
1885 if (cfra1 < pid->cache->startframe) {
1886 cfra1 = 0;
1887 }
1888
1889 while (cfra2 <= pid->cache->endframe && !BKE_ptcache_id_exist(pid, cfra2)) {
1890 cfra2++;
1891 }
1892
1893 if (cfra2 > pid->cache->endframe) {
1894 cfra2 = 0;
1895 }
1896
1897 if (cfra1 && !cfra2) {
1898 *r_fra1 = 0;
1899 *r_fra2 = cfra1;
1900 }
1901 else {
1902 *r_fra1 = cfra1;
1903 *r_fra2 = cfra2;
1904 }
1905 }
1906 else if (pid->cache->mem_cache.first) {
1907 PTCacheMem *pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
1908 PTCacheMem *pm2 = static_cast<PTCacheMem *>(pid->cache->mem_cache.last);
1909
1910 while (pm->next && pm->next->frame <= frame) {
1911 pm = pm->next;
1912 }
1913
1914 if (pm2->frame < frame) {
1915 pm2 = nullptr;
1916 }
1917 else {
1918 while (pm2->prev && pm2->prev->frame > frame) {
1919 pm2 = pm2->prev;
1920 }
1921 }
1922
1923 if (!pm2) {
1924 *r_fra1 = 0;
1925 *r_fra2 = pm->frame;
1926 }
1927 else {
1928 *r_fra1 = pm->frame;
1929 *r_fra2 = pm2->frame;
1930 }
1931 }
1932}
1933
1935{
1937 PTCacheMem *pm = nullptr;
1938 uint i, error = 0;
1939
1940 if (pf == nullptr) {
1941 return nullptr;
1942 }
1943
1945 error = 1;
1946 }
1947
1948 if (!error && (pf->type != pid->type || !pid->read_header(pf))) {
1949 error = 1;
1950 }
1951
1952 if (!error) {
1953 pm = static_cast<PTCacheMem *>(MEM_callocN(sizeof(PTCacheMem), "Pointcache mem"));
1954
1955 pm->totpoint = pf->totpoint;
1956 pm->data_types = pf->data_types;
1957 pm->frame = pf->frame;
1958
1960
1961 if (pf->flag & PTCACHE_TYPEFLAG_COMPRESS) {
1962 for (i = 0; i < BPHYS_TOT_DATA; i++) {
1963 uint out_len = pm->totpoint * ptcache_data_size[i];
1964 if (pf->data_types & (1 << i)) {
1965 ptcache_file_compressed_read(pf, (uchar *)(pm->data[i]), out_len);
1966 }
1967 }
1968 }
1969 else {
1970 void *cur[BPHYS_TOT_DATA];
1973
1974 for (i = 0; i < pm->totpoint; i++) {
1975 if (!ptcache_file_data_read(pf)) {
1976 error = 1;
1977 break;
1978 }
1979 ptcache_data_copy(pf->cur, cur);
1981 }
1982 }
1983 }
1984
1985 if (!error && pf->flag & PTCACHE_TYPEFLAG_EXTRADATA) {
1986 uint extratype = 0;
1987
1988 while (ptcache_file_read(pf, &extratype, 1, sizeof(uint))) {
1989 PTCacheExtra *extra = static_cast<PTCacheExtra *>(
1990 MEM_callocN(sizeof(PTCacheExtra), "Pointcache extradata"));
1991
1992 extra->type = extratype;
1993
1994 ptcache_file_read(pf, &extra->totdata, 1, sizeof(uint));
1995
1996 extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type],
1997 "Pointcache extradata->data");
1998
1999 if (pf->flag & PTCACHE_TYPEFLAG_COMPRESS) {
2001 pf, (uchar *)(extra->data), extra->totdata * ptcache_extra_datasize[extra->type]);
2002 }
2003 else {
2004 ptcache_file_read(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
2005 }
2006
2007 BLI_addtail(&pm->extradata, extra);
2008 }
2009 }
2010
2011 if (error && pm) {
2013 MEM_freeN(pm);
2014 pm = nullptr;
2015 }
2016
2018
2019 if (error && G.debug & G_DEBUG) {
2020 printf("Error reading from disk cache\n");
2021 }
2022
2023 return pm;
2024}
2026{
2027 PTCacheFile *pf = nullptr;
2028 uint i, error = 0;
2029
2031
2033
2034 if (pf == nullptr) {
2035 if (G.debug & G_DEBUG) {
2036 printf("Error opening disk cache file for writing\n");
2037 }
2038 return 0;
2039 }
2040
2041 pf->data_types = pm->data_types;
2042 pf->totpoint = pm->totpoint;
2043 pf->type = pid->type;
2044 pf->flag = 0;
2045
2046 if (pm->extradata.first) {
2048 }
2049
2050 if (pid->cache->compression) {
2052 }
2053
2055 error = 1;
2056 }
2057
2058 if (!error) {
2059 if (pid->cache->compression) {
2060 for (i = 0; i < BPHYS_TOT_DATA; i++) {
2061 if (pm->data[i]) {
2062 uint in_len = pm->totpoint * ptcache_data_size[i];
2063 uchar *out = (uchar *)MEM_callocN(LZO_OUT_LEN(in_len) * 4, "pointcache_lzo_buffer");
2065 pf, (uchar *)(pm->data[i]), in_len, out, pid->cache->compression);
2066 MEM_freeN(out);
2067 }
2068 }
2069 }
2070 else {
2071 void *cur[BPHYS_TOT_DATA];
2074
2075 for (i = 0; i < pm->totpoint; i++) {
2076 ptcache_data_copy(cur, pf->cur);
2078 error = 1;
2079 break;
2080 }
2082 }
2083 }
2084 }
2085
2086 if (!error && pm->extradata.first) {
2087 PTCacheExtra *extra = static_cast<PTCacheExtra *>(pm->extradata.first);
2088
2089 for (; extra; extra = extra->next) {
2090 if (extra->data == nullptr || extra->totdata == 0) {
2091 continue;
2092 }
2093
2094 ptcache_file_write(pf, &extra->type, 1, sizeof(uint));
2095 ptcache_file_write(pf, &extra->totdata, 1, sizeof(uint));
2096
2097 if (pid->cache->compression) {
2098 uint in_len = extra->totdata * ptcache_extra_datasize[extra->type];
2099 uchar *out = (uchar *)MEM_callocN(LZO_OUT_LEN(in_len) * 4, "pointcache_lzo_buffer");
2101 pf, (uchar *)(extra->data), in_len, out, pid->cache->compression);
2102 MEM_freeN(out);
2103 }
2104 else {
2105 ptcache_file_write(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
2106 }
2107 }
2108 }
2109
2111
2112 if (error && G.debug & G_DEBUG) {
2113 printf("Error writing to disk cache\n");
2114 }
2115
2116 return error == 0;
2117}
2118
2119static int ptcache_read_stream(PTCacheID *pid, int cfra)
2120{
2122 int error = 0;
2123
2124 if (pid->read_stream == nullptr) {
2125 return 0;
2126 }
2127
2128 if (pf == nullptr) {
2129 if (G.debug & G_DEBUG) {
2130 printf("Error opening disk cache file for reading\n");
2131 }
2132 return 0;
2133 }
2134
2136 pid->error(pid->owner_id, pid->calldata, "Failed to read point cache file");
2137 error = 1;
2138 }
2139 else if (pf->type != pid->type) {
2140 pid->error(pid->owner_id, pid->calldata, "Point cache file has wrong type");
2141 error = 1;
2142 }
2143 else if (!pid->read_header(pf)) {
2144 pid->error(pid->owner_id, pid->calldata, "Failed to read point cache file header");
2145 error = 1;
2146 }
2147 else if (pf->totpoint != pid->totpoint(pid->calldata, cfra)) {
2148 pid->error(pid->owner_id, pid->calldata, "Number of points in cache does not match mesh");
2149 error = 1;
2150 }
2151
2152 if (!error) {
2154
2155 /* We have stream reading here. */
2156 if (!pid->read_stream(pf, pid->calldata)) {
2157 pid->error(pid->owner_id, pid->calldata, "Failed to read point cache file data");
2158 error = 1;
2159 }
2160 }
2161
2163
2164 return error == 0;
2165}
2166
2167static int ptcache_read(PTCacheID *pid, int cfra)
2168{
2169 PTCacheMem *pm = nullptr;
2170 int i;
2171 int *index = &i;
2172
2173 /* get a memory cache to read from */
2174 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2175 pm = ptcache_disk_frame_to_mem(pid, cfra);
2176 }
2177 else {
2178 pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
2179
2180 while (pm && pm->frame != cfra) {
2181 pm = pm->next;
2182 }
2183 }
2184
2185 /* read the cache */
2186 if (pm) {
2187 int totpoint = pm->totpoint;
2188
2189 if ((pid->data_types & (1 << BPHYS_DATA_INDEX)) == 0) {
2190 int pid_totpoint = pid->totpoint(pid->calldata, cfra);
2191
2192 if (totpoint != pid_totpoint) {
2193 pid->error(pid->owner_id, pid->calldata, "Number of points in cache does not match mesh");
2194 totpoint = std::min(totpoint, pid_totpoint);
2195 }
2196 }
2197
2198 void *cur[BPHYS_TOT_DATA];
2200
2201 for (i = 0; i < totpoint; i++) {
2202 if (pm->data_types & (1 << BPHYS_DATA_INDEX)) {
2203 index = static_cast<int *>(cur[BPHYS_DATA_INDEX]);
2204 }
2205
2206 pid->read_point(*index, pid->calldata, cur, float(pm->frame), nullptr);
2207
2209 }
2210
2211 if (pid->read_extra_data && pm->extradata.first) {
2212 pid->read_extra_data(pid->calldata, pm, float(pm->frame));
2213 }
2214
2215 /* clean up temporary memory cache */
2216 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2218 MEM_freeN(pm);
2219 }
2220 }
2221
2222 return 1;
2223}
2224static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
2225{
2226 PTCacheMem *pm = nullptr;
2227 int i;
2228 int *index = &i;
2229
2230 /* get a memory cache to read from */
2231 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2232 pm = ptcache_disk_frame_to_mem(pid, cfra2);
2233 }
2234 else {
2235 pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
2236
2237 while (pm && pm->frame != cfra2) {
2238 pm = pm->next;
2239 }
2240 }
2241
2242 /* read the cache */
2243 if (pm) {
2244 int totpoint = pm->totpoint;
2245
2246 if ((pid->data_types & (1 << BPHYS_DATA_INDEX)) == 0) {
2247 int pid_totpoint = pid->totpoint(pid->calldata, int(cfra));
2248
2249 if (totpoint != pid_totpoint) {
2250 pid->error(pid->owner_id, pid->calldata, "Number of points in cache does not match mesh");
2251 totpoint = std::min(totpoint, pid_totpoint);
2252 }
2253 }
2254
2255 void *cur[BPHYS_TOT_DATA];
2257
2258 for (i = 0; i < totpoint; i++) {
2259 if (pm->data_types & (1 << BPHYS_DATA_INDEX)) {
2260 index = static_cast<int *>(cur[BPHYS_DATA_INDEX]);
2261 }
2262
2263 pid->interpolate_point(
2264 *index, pid->calldata, cur, cfra, float(cfra1), float(cfra2), nullptr);
2266 }
2267
2268 if (pid->interpolate_extra_data && pm->extradata.first) {
2269 pid->interpolate_extra_data(pid->calldata, pm, cfra, float(cfra1), float(cfra2));
2270 }
2271
2272 /* clean up temporary memory cache */
2273 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2275 MEM_freeN(pm);
2276 }
2277 }
2278
2279 return 1;
2280}
2281
2282int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
2283{
2284 int cfrai = int(floor(cfra)), cfra1 = 0, cfra2 = 0;
2285 int ret = 0;
2286
2287 /* nothing to read to */
2288 if (pid->totpoint(pid->calldata, cfrai) == 0) {
2289 return 0;
2290 }
2291
2292 if (pid->cache->flag & PTCACHE_READ_INFO) {
2293 pid->cache->flag &= ~PTCACHE_READ_INFO;
2294 ptcache_read(pid, 0);
2295 }
2296
2297 /* first check if we have the actual frame cached */
2298 if (cfra == float(cfrai) && BKE_ptcache_id_exist(pid, cfrai)) {
2299 cfra1 = cfrai;
2300 }
2301
2302 /* no exact cache frame found so try to find cached frames around cfra */
2303 if (cfra1 == 0) {
2304 ptcache_find_frames_around(pid, cfrai, &cfra1, &cfra2);
2305 }
2306
2307 if (cfra1 == 0 && cfra2 == 0) {
2308 return 0;
2309 }
2310
2311 /* don't read old cache if already simulated past cached frame */
2312 if (no_extrapolate_old) {
2313 if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe) {
2314 return 0;
2315 }
2316 if (cfra1 && cfra1 == cfra2) {
2317 return 0;
2318 }
2319 }
2320 else {
2321 /* avoid calling interpolate between the same frame values */
2322 if (cfra1 && cfra1 == cfra2) {
2323 cfra1 = 0;
2324 }
2325 }
2326
2327 if (cfra1) {
2328 if (pid->read_stream) {
2329 if (!ptcache_read_stream(pid, cfra1)) {
2330 return 0;
2331 }
2332 }
2333 else if (pid->read_point) {
2334 ptcache_read(pid, cfra1);
2335 }
2336 }
2337
2338 if (cfra2) {
2339 if (pid->read_stream) {
2340 if (!ptcache_read_stream(pid, cfra2)) {
2341 return 0;
2342 }
2343 }
2344 else if (pid->read_point) {
2345 if (cfra1 && cfra2 && pid->interpolate_point) {
2346 ptcache_interpolate(pid, cfra, cfra1, cfra2);
2347 }
2348 else {
2349 ptcache_read(pid, cfra2);
2350 }
2351 }
2352 }
2353
2354 if (cfra1) {
2356 }
2357 else if (cfra2) {
2359 pid->cache->simframe = cfra2;
2360 }
2361
2362 cfrai = int(cfra);
2363 /* clear invalid cache frames so that better stuff can be simulated */
2364 if (pid->cache->flag & PTCACHE_OUTDATED) {
2366 }
2367 else if (pid->cache->flag & PTCACHE_FRAMES_SKIPPED) {
2368 if (cfra <= pid->cache->last_exact) {
2369 pid->cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
2370 }
2371
2372 BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, std::max(cfrai, pid->cache->last_exact));
2373 }
2374
2375 return ret;
2376}
2377static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint)
2378{
2379 PTCacheFile *pf = nullptr;
2380 int error = 0;
2381
2383
2385
2386 if (pf == nullptr) {
2387 if (G.debug & G_DEBUG) {
2388 printf("Error opening disk cache file for writing\n");
2389 }
2390 return 0;
2391 }
2392
2393 pf->data_types = pid->data_types;
2394 pf->totpoint = totpoint;
2395 pf->type = pid->type;
2396 pf->flag = 0;
2397
2398 if (!error && (!ptcache_file_header_begin_write(pf) || !pid->write_header(pf))) {
2399 error = 1;
2400 }
2401
2402 if (!error && pid->write_stream) {
2403 pid->write_stream(pf, pid->calldata);
2404 }
2405
2407
2408 if (error && G.debug & G_DEBUG) {
2409 printf("Error writing to disk cache\n");
2410 }
2411
2412 return error == 0;
2413}
2414
2415static int ptcache_write(PTCacheID *pid, int cfra, int overwrite)
2416{
2417 PointCache *cache = pid->cache;
2418 PTCacheMem *pm = nullptr, *pm2 = nullptr;
2419 int totpoint = pid->totpoint(pid->calldata, cfra);
2420 int i, error = 0;
2421
2422 pm = static_cast<PTCacheMem *>(MEM_callocN(sizeof(PTCacheMem), "Pointcache mem"));
2423
2424 pm->totpoint = pid->totwrite(pid->calldata, cfra);
2425 pm->data_types = cfra ? pid->data_types : pid->info_types;
2426
2428 void *cur[BPHYS_TOT_DATA];
2430
2431 if (overwrite) {
2432 if (cache->flag & PTCACHE_DISK_CACHE) {
2433 int fra = cfra - 1;
2434
2435 while (fra >= cache->startframe && !BKE_ptcache_id_exist(pid, fra)) {
2436 fra--;
2437 }
2438
2439 pm2 = ptcache_disk_frame_to_mem(pid, fra);
2440 }
2441 else {
2442 pm2 = static_cast<PTCacheMem *>(cache->mem_cache.last);
2443 }
2444 }
2445
2446 if (pid->write_point) {
2447 for (i = 0; i < totpoint; i++) {
2448 int write = pid->write_point(i, pid->calldata, cur, cfra);
2449 if (write) {
2451
2452 void *cur2[BPHYS_TOT_DATA];
2453 /* newly born particles have to be copied to previous cached frame */
2454 if (overwrite && write == 2 && pm2 && BKE_ptcache_mem_pointers_seek(i, pm2, cur2)) {
2455 pid->write_point(i, pid->calldata, cur2, cfra);
2456 }
2457 }
2458 }
2459 }
2460
2461 if (pid->write_extra_data) {
2462 pid->write_extra_data(pid->calldata, pm, cfra);
2463 }
2464
2465 pm->frame = cfra;
2466
2467 if (cache->flag & PTCACHE_DISK_CACHE) {
2468 error += !ptcache_mem_frame_to_disk(pid, pm);
2469
2470 // if (pm) /* pm is always set */
2471 {
2473 MEM_freeN(pm);
2474 }
2475
2476 if (pm2) {
2477 error += !ptcache_mem_frame_to_disk(pid, pm2);
2478 ptcache_mem_clear(pm2);
2479 MEM_freeN(pm2);
2480 }
2481 }
2482 else {
2483 BLI_addtail(&cache->mem_cache, pm);
2484 }
2485
2486 return error;
2487}
2488static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
2489{
2490 PointCache *cache = pid->cache;
2491 int ofra = 0, efra = cache->endframe;
2492
2493 /* always start from scratch on the first frame */
2494 if (cfra && cfra == cache->startframe) {
2496 cache->flag &= ~PTCACHE_REDO_NEEDED;
2497 return 1;
2498 }
2499
2500 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2501 if (cfra == 0 && cache->startframe > 0) {
2502 return 1;
2503 }
2504
2505 /* find last cached frame */
2506 while (efra > cache->startframe && !BKE_ptcache_id_exist(pid, efra)) {
2507 efra--;
2508 }
2509
2510 /* find second last cached frame */
2511 ofra = efra - 1;
2512 while (ofra > cache->startframe && !BKE_ptcache_id_exist(pid, ofra)) {
2513 ofra--;
2514 }
2515 }
2516 else {
2517 PTCacheMem *pm = static_cast<PTCacheMem *>(cache->mem_cache.last);
2518 /* don't write info file in memory */
2519 if (cfra == 0) {
2520 return 0;
2521 }
2522
2523 if (pm == nullptr) {
2524 return 1;
2525 }
2526
2527 efra = pm->frame;
2528 ofra = (pm->prev ? pm->prev->frame : efra - cache->step);
2529 }
2530
2531 if (efra >= cache->startframe && cfra > efra) {
2532 if (ofra >= cache->startframe && efra - ofra < cache->step) {
2533 /* overwrite previous frame */
2535 *overwrite = 1;
2536 }
2537 return 1;
2538 }
2539
2540 return 0;
2541}
2543{
2544 PointCache *cache = pid->cache;
2545 if (!pid->totpoint) {
2546 /* This happens when `pid->type == PTCACHE_TYPE_SMOKE_DOMAIN`. The fluid system does not
2547 * actually use the pointcache anymore for caching. */
2548 return 0;
2549 }
2550
2551 int totpoint = pid->totpoint(pid->calldata, cfra);
2552 int overwrite = 0, error = 0;
2553
2554 if (totpoint == 0 || (cfra ? pid->data_types == 0 : pid->info_types == 0)) {
2555 return 0;
2556 }
2557
2558 if (ptcache_write_needed(pid, cfra, &overwrite) == 0) {
2559 return 0;
2560 }
2561
2562 if (pid->write_stream) {
2563 ptcache_write_stream(pid, cfra, totpoint);
2564 }
2565 else if (pid->write_point) {
2566 error += ptcache_write(pid, cfra, overwrite);
2567 }
2568
2569 /* Mark frames skipped if more than 1 frame forwards since last non-skipped frame. */
2570 if (cfra - cache->last_exact == 1 || cfra == cache->startframe) {
2571 cache->last_exact = cfra;
2572 cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
2573 }
2574 /* Don't mark skipped when writing info file (frame 0) */
2575 else if (cfra) {
2576 cache->flag |= PTCACHE_FRAMES_SKIPPED;
2577 }
2578
2579 /* Update timeline cache display */
2580 if (cfra && cache->cached_frames) {
2581 cache->cached_frames[cfra - cache->startframe] = 1;
2582 }
2583
2584 cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
2585
2586 return !error;
2587}
2588/* you'll need to close yourself after!
2589 * mode - PTCACHE_CLEAR_ALL,
2590 */
2591
2592/* Clears & resets. */
2593
2594void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
2595{
2596 uint len; /* store the length of the string */
2597 uint sta, end;
2598
2599 /* mode is same as fopen's modes */
2600 DIR *dir;
2601 dirent *de;
2602 char path[MAX_PTCACHE_PATH];
2603 char filepath[MAX_PTCACHE_FILE];
2604 char path_full[MAX_PTCACHE_FILE];
2605 char ext[MAX_PTCACHE_FILE];
2606
2607 if (!pid || !pid->cache || pid->cache->flag & PTCACHE_BAKED) {
2608 return;
2609 }
2610
2611 if (pid->cache->flag & PTCACHE_IGNORE_CLEAR) {
2612 return;
2613 }
2614
2615 sta = pid->cache->startframe;
2616 end = pid->cache->endframe;
2617
2618#ifndef DURIAN_POINTCACHE_LIB_OK
2619 /* don't allow clearing for linked objects */
2620 if (pid->owner_id->lib) {
2621 return;
2622 }
2623#endif
2624
2625 /* Clear all files in the temp dir with the prefix of the ID and the `.bphys` suffix. */
2626 switch (mode) {
2627 case PTCACHE_CLEAR_ALL:
2630 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2631 ptcache_path(pid, path);
2632
2633 dir = opendir(path);
2634 if (dir == nullptr) {
2635 return;
2636 }
2637
2638 len = ptcache_filepath(pid, filepath, cfra, false, false); /* no path */
2639 /* append underscore terminator to ensure we don't match similar names
2640 * from objects whose names start with the same prefix
2641 */
2642 if (len < sizeof(filepath) - 2) {
2643 BLI_strncpy(filepath + len, "_", sizeof(filepath) - 2 - len);
2644 len += 1;
2645 }
2646
2647 ptcache_filepath_ext_append(pid, ext, 0, false, 0);
2648
2649 while ((de = readdir(dir)) != nullptr) {
2650 if (strstr(de->d_name, ext)) { /* Do we have the right extension? */
2651 if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */
2652 if (mode == PTCACHE_CLEAR_ALL) {
2653 pid->cache->last_exact = std::min(pid->cache->startframe, 0);
2654 BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
2655 BLI_delete(path_full, false, false);
2656 }
2657 else {
2658 /* read the number of the file */
2659 const int frame = ptcache_frame_from_filename(de->d_name, ext);
2660
2661 if (frame != -1) {
2662 if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
2663 (mode == PTCACHE_CLEAR_AFTER && frame > cfra))
2664 {
2665 BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
2666 BLI_delete(path_full, false, false);
2667 if (pid->cache->cached_frames && frame >= sta && frame <= end) {
2668 pid->cache->cached_frames[frame - sta] = 0;
2669 }
2670 }
2671 }
2672 }
2673 }
2674 }
2675 }
2676 closedir(dir);
2677
2678 if (mode == PTCACHE_CLEAR_ALL && pid->cache->cached_frames) {
2679 memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
2680 }
2681 }
2682 else {
2683 PTCacheMem *pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
2684 PTCacheMem *link = nullptr;
2685
2686 if (mode == PTCACHE_CLEAR_ALL) {
2687 /* We want startframe if the cache starts before zero. */
2688 pid->cache->last_exact = std::min(pid->cache->startframe, 0);
2689 for (; pm; pm = pm->next) {
2691 }
2693
2694 if (pid->cache->cached_frames) {
2695 memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
2696 }
2697 }
2698 else {
2699 while (pm) {
2700 if ((mode == PTCACHE_CLEAR_BEFORE && pm->frame < cfra) ||
2701 (mode == PTCACHE_CLEAR_AFTER && pm->frame > cfra))
2702 {
2703 link = pm;
2704 if (pid->cache->cached_frames && pm->frame >= sta && pm->frame <= end) {
2705 pid->cache->cached_frames[pm->frame - sta] = 0;
2706 }
2708 pm = pm->next;
2709 BLI_freelinkN(&pid->cache->mem_cache, link);
2710 }
2711 else {
2712 pm = pm->next;
2713 }
2714 }
2715 }
2716 }
2717 break;
2718
2720 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2721 if (BKE_ptcache_id_exist(pid, cfra)) {
2722 ptcache_filepath(pid, filepath, cfra, true, true); /* no path */
2723 BLI_delete(filepath, false, false);
2724 }
2725 }
2726 else {
2727 PTCacheMem *pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
2728
2729 for (; pm; pm = pm->next) {
2730 if (pm->frame == cfra) {
2732 BLI_freelinkN(&pid->cache->mem_cache, pm);
2733 break;
2734 }
2735 }
2736 }
2737 if (pid->cache->cached_frames && cfra >= sta && cfra <= end) {
2738 pid->cache->cached_frames[cfra - sta] = 0;
2739 }
2740 break;
2741 }
2742
2744}
2745
2747{
2748 if (!pid->cache) {
2749 return false;
2750 }
2751
2752 if (cfra < pid->cache->startframe || cfra > pid->cache->endframe) {
2753 return false;
2754 }
2755
2756 if (pid->cache->cached_frames && pid->cache->cached_frames[cfra - pid->cache->startframe] == 0) {
2757 return false;
2758 }
2759
2760 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2761 char filepath[MAX_PTCACHE_FILE];
2762
2763 ptcache_filepath(pid, filepath, cfra, true, true);
2764
2765 return BLI_exists(filepath);
2766 }
2767
2768 PTCacheMem *pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
2769
2770 for (; pm; pm = pm->next) {
2771 if (pm->frame == cfra) {
2772 return true;
2773 }
2774 }
2775 return false;
2776}
2778 PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
2779{
2780 // Object *ob; /* UNUSED */
2781 PointCache *cache;
2782 /* float offset; unused for now */
2783 float time, nexttime;
2784
2785 /* TODO: this has to be sorted out once bsystem_time gets redone, */
2786 /* now caches can handle interpolating etc. too - jahka */
2787
2788 /* time handling for point cache:
2789 * - simulation time is scaled by result of bsystem_time
2790 * - for offsetting time only time offset is taken into account, since
2791 * that's always the same and can't be animated. a time-offset which
2792 * varies over time is not simple to support.
2793 * - field and motion blur offsets are currently ignored, proper solution
2794 * is probably to interpolate results from two frames for that ..
2795 */
2796
2797 cache = pid->cache;
2798
2799 if (timescale) {
2800 time = BKE_scene_ctime_get(scene);
2801 nexttime = BKE_scene_frame_to_ctime(scene, scene->r.cfra + 1);
2802
2803 *timescale = std::max(nexttime - time, 0.0f);
2804 }
2805
2806 if (startframe && endframe) {
2807 *startframe = cache->startframe;
2808 *endframe = cache->endframe;
2809 }
2810
2811 /* verify cached_frames array is up to date */
2812 if (cache->cached_frames) {
2813 if (cache->cached_frames_len != (cache->endframe - cache->startframe + 1)) {
2814 MEM_freeN(cache->cached_frames);
2815 cache->cached_frames = nullptr;
2816 cache->cached_frames_len = 0;
2817 }
2818 }
2819
2820 if (cache->cached_frames == nullptr && cache->endframe > cache->startframe) {
2821 uint sta = cache->startframe;
2822 uint end = cache->endframe;
2823
2824 cache->cached_frames_len = cache->endframe - cache->startframe + 1;
2825 cache->cached_frames = static_cast<char *>(
2826 MEM_callocN(sizeof(char) * cache->cached_frames_len, "cached frames array"));
2827
2828 if (pid->cache->flag & PTCACHE_DISK_CACHE) {
2829 /* mode is same as fopen's modes */
2830 DIR *dir;
2831 dirent *de;
2832 char path[MAX_PTCACHE_PATH];
2833 char filepath[MAX_PTCACHE_FILE];
2834 char ext[MAX_PTCACHE_FILE];
2835 uint len; /* store the length of the string */
2836
2837 ptcache_path(pid, path);
2838
2839 len = ptcache_filepath(pid, filepath, int(cfra), false, false); /* no path */
2840
2841 dir = opendir(path);
2842 if (dir == nullptr) {
2843 return;
2844 }
2845
2846 ptcache_filepath_ext_append(pid, ext, 0, false, 0);
2847
2848 while ((de = readdir(dir)) != nullptr) {
2849 if (strstr(de->d_name, ext)) { /* Do we have the right extension? */
2850 if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */
2851 /* read the number of the file */
2852 const int frame = ptcache_frame_from_filename(de->d_name, ext);
2853
2854 if ((frame != -1) && (frame >= sta && frame <= end)) {
2855 cache->cached_frames[frame - sta] = 1;
2856 }
2857 }
2858 }
2859 }
2860 closedir(dir);
2861 }
2862 else {
2863 PTCacheMem *pm = static_cast<PTCacheMem *>(pid->cache->mem_cache.first);
2864
2865 while (pm) {
2866 if (pm->frame >= sta && pm->frame <= end) {
2867 cache->cached_frames[pm->frame - sta] = 1;
2868 }
2869 pm = pm->next;
2870 }
2871 }
2872 }
2873}
2874int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
2875{
2876 PointCache *cache;
2877 int reset, clear, after;
2878
2879 if (!pid->cache) {
2880 return 0;
2881 }
2882
2883 cache = pid->cache;
2884 reset = 0;
2885 clear = 0;
2886 after = 0;
2887
2888 if (mode == PTCACHE_RESET_DEPSGRAPH) {
2889 if (!(cache->flag & PTCACHE_BAKED)) {
2890
2891 after = 1;
2892 }
2893
2894 cache->flag |= PTCACHE_OUTDATED;
2895 }
2896 else if (mode == PTCACHE_RESET_BAKED) {
2897 cache->flag |= PTCACHE_OUTDATED;
2898 }
2899 else if (mode == PTCACHE_RESET_OUTDATED) {
2900 reset = 1;
2901
2902 if (cache->flag & PTCACHE_OUTDATED && !(cache->flag & PTCACHE_BAKED)) {
2903 clear = 1;
2904 cache->flag &= ~PTCACHE_OUTDATED;
2905 }
2906 }
2907
2908 if (reset) {
2910 cache->flag &= ~PTCACHE_REDO_NEEDED;
2911
2912 if (pid->type == PTCACHE_TYPE_CLOTH) {
2913 cloth_free_modifier(static_cast<ClothModifierData *>(pid->calldata));
2914 }
2915 else if (pid->type == PTCACHE_TYPE_SOFTBODY) {
2916 sbFreeSimulation(static_cast<SoftBody *>(pid->calldata));
2917 }
2918 else if (pid->type == PTCACHE_TYPE_PARTICLES) {
2920 }
2921 else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT) {
2923 }
2924 }
2925 if (clear) {
2927 }
2928 else if (after) {
2929 BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, scene->r.cfra);
2930 }
2931
2932 return (reset || clear || after);
2933}
2934int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
2935{
2936 PTCacheID pid;
2937 int reset, skip;
2938
2939 reset = 0;
2940 skip = 0;
2941
2942 if (ob->soft) {
2943 BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
2944 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
2945 }
2946
2948 /* children or just redo can be calculated without resetting anything */
2949 if (psys->recalc & ID_RECALC_PSYS_REDO || psys->recalc & ID_RECALC_PSYS_CHILD) {
2950 skip = 1;
2951 /* Baked cloth hair has to be checked too, because we don't want to reset */
2952 /* particles or cloth in that case -jahka */
2953 }
2954 else if (psys->clmd) {
2955 BKE_ptcache_id_from_cloth(&pid, ob, psys->clmd);
2956 if (mode == PSYS_RESET_ALL ||
2957 !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED)))
2958 {
2959 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
2960 }
2961 else {
2962 skip = 1;
2963 }
2964 }
2965
2966 if (skip == 0 && psys->part) {
2967 BKE_ptcache_id_from_particles(&pid, ob, psys);
2968 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
2969 }
2970 }
2971
2973 if (md->type == eModifierType_Cloth) {
2975 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
2976 }
2977 if (md->type == eModifierType_DynamicPaint) {
2979 if (pmd->canvas) {
2980 DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(
2981 pmd->canvas->surfaces.first);
2982
2983 for (; surface; surface = surface->next) {
2984 BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
2985 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
2986 }
2987 }
2988 }
2989 if (md->type == eModifierType_Fluid) {
2991 FluidDomainSettings *fds = fmd->domain;
2992 if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fds &&
2994 {
2995 BKE_ptcache_id_from_smoke(&pid, ob, fmd);
2996 reset |= BKE_ptcache_id_reset(scene, &pid, mode);
2997 }
2998 }
2999 }
3000
3001 if (scene->rigidbody_world && (ob->rigidbody_object || ob->rigidbody_constraint)) {
3002 if (ob->rigidbody_object) {
3004 }
3005 BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world);
3006 /* only flag as outdated, resetting should happen on start frame */
3007 pid.cache->flag |= PTCACHE_OUTDATED;
3008 }
3009
3010 if (ob->type == OB_ARMATURE) {
3011 BIK_clear_cache(ob->pose);
3012 }
3013
3014 return reset;
3015}
3016
3017/* Point Cache handling */
3018
3020{
3021 PointCache *cache;
3022
3023 cache = static_cast<PointCache *>(MEM_callocN(sizeof(PointCache), "PointCache"));
3024 cache->startframe = 1;
3025 cache->endframe = 250;
3026 cache->step = 1;
3027 cache->index = -1;
3028
3029 BLI_addtail(ptcaches, cache);
3030
3031 return cache;
3032}
3033
3035{
3036 PTCacheMem *pm = static_cast<PTCacheMem *>(mem_cache->first);
3037
3038 if (pm) {
3039 for (; pm; pm = pm->next) {
3041 }
3042
3043 BLI_freelistN(mem_cache);
3044 }
3045}
3047{
3049 if (cache->edit && cache->free_edit) {
3050 cache->free_edit(cache->edit);
3051 }
3052 if (cache->cached_frames) {
3053 MEM_freeN(cache->cached_frames);
3054 }
3055 MEM_freeN(cache);
3056}
3058{
3059 while (PointCache *cache = static_cast<PointCache *>(BLI_pophead(ptcaches))) {
3060 BKE_ptcache_free(cache);
3061 }
3062}
3063
3064static PointCache *ptcache_copy(PointCache *cache, const bool copy_data)
3065{
3066 PointCache *ncache;
3067
3068 ncache = static_cast<PointCache *>(MEM_dupallocN(cache));
3069
3070 BLI_listbase_clear(&ncache->mem_cache);
3071
3072 if (copy_data == false) {
3073 ncache->cached_frames = nullptr;
3074 ncache->cached_frames_len = 0;
3075
3076 /* flag is a mix of user settings and simulator/baking state */
3078 ncache->simframe = 0;
3079 }
3080 else {
3081 LISTBASE_FOREACH (PTCacheMem *, pm, &cache->mem_cache) {
3082 PTCacheMem *pmn = static_cast<PTCacheMem *>(MEM_dupallocN(pm));
3083 int i;
3084
3085 for (i = 0; i < BPHYS_TOT_DATA; i++) {
3086 if (pmn->data[i]) {
3087 pmn->data[i] = MEM_dupallocN(pm->data[i]);
3088 }
3089 }
3090
3091 BLI_addtail(&ncache->mem_cache, pmn);
3092 }
3093
3094 if (ncache->cached_frames) {
3095 ncache->cached_frames = static_cast<char *>(MEM_dupallocN(cache->cached_frames));
3096 }
3097 }
3098
3099 /* hmm, should these be copied over instead? */
3100 ncache->edit = nullptr;
3101
3102 return ncache;
3103}
3104
3106 const ListBase *ptcaches_old,
3107 const int flag)
3108{
3109 PointCache *cache = static_cast<PointCache *>(ptcaches_old->first);
3110
3111 BLI_listbase_clear(ptcaches_new);
3112
3113 for (; cache; cache = cache->next) {
3114 BLI_addtail(ptcaches_new, ptcache_copy(cache, (flag & LIB_ID_COPY_CACHES) != 0));
3115 }
3116
3117 return static_cast<PointCache *>(ptcaches_new->first);
3118}
3119
3120/* Disabled this code; this is being called on scene_update_tagged, and that in turn gets called on
3121 * every user action changing stuff, and then it runs a complete bake??? (ton) */
3122
3123/* Baking */
3124
3125void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
3126{
3127 PTCacheBaker baker;
3128
3129 memset(&baker, 0, sizeof(baker));
3130 baker.bmain = bmain;
3131 baker.scene = scene;
3132 baker.view_layer = view_layer;
3133 baker.bake = false;
3134 baker.render = false;
3135 baker.anim_init = false;
3136 baker.quick_step = scene->physics_settings.quick_cache_step;
3137
3138 BKE_ptcache_bake(&baker);
3139}
3140
3141static void ptcache_dt_to_str(char *str, size_t str_maxncpy, double dtime)
3142{
3143 if (dtime > 60.0) {
3144 if (dtime > 3600.0) {
3146 str_maxncpy,
3147 "%ih %im %is",
3148 int(dtime / 3600),
3149 int(dtime / 60) % 60,
3150 int(dtime) % 60);
3151 }
3152 else {
3153 BLI_snprintf(str, str_maxncpy, "%im %is", int(dtime / 60) % 60, int(dtime) % 60);
3154 }
3155 }
3156 else {
3157 BLI_snprintf(str, str_maxncpy, "%is", int(dtime) % 60);
3158 }
3159}
3160
3162{
3163 Scene *scene = baker->scene;
3164 ViewLayer *view_layer = baker->view_layer;
3165 Depsgraph *depsgraph = baker->depsgraph;
3166 Scene *sce_iter; /* SETLOOPER macro only */
3167 Base *base;
3168 ListBase pidlist;
3169 PTCacheID *pid = &baker->pid;
3170 PointCache *cache = nullptr;
3171 float frameleno = scene->r.framelen;
3172 int cfrao = scene->r.cfra;
3173 int startframe = MAXFRAME, endframe = baker->anim_init ? scene->r.sfra : scene->r.cfra;
3174 int bake = baker->bake;
3175 int render = baker->render;
3176
3177 G.is_break = false;
3178
3179 /* set caches to baking mode and figure out start frame */
3180 if (pid->owner_id) {
3181 /* cache/bake a single object */
3182 cache = pid->cache;
3183 if ((cache->flag & PTCACHE_BAKED) == 0) {
3184 if (pid->type == PTCACHE_TYPE_PARTICLES) {
3185 ParticleSystem *psys = static_cast<ParticleSystem *>(pid->calldata);
3186
3187 /* a bit confusing, could make this work better in the UI */
3188 if (psys->part->type == PART_EMITTER) {
3190 static_cast<ParticleSystem *>(pid->calldata),
3191 &cache->startframe,
3192 &cache->endframe);
3193 }
3194 }
3195 else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES) {
3196 /* get all pids from the object and search for smoke low res */
3197 ListBase pidlist2;
3198 BLI_assert(GS(pid->owner_id->name) == ID_OB);
3199 BKE_ptcache_ids_from_object(&pidlist2, (Object *)pid->owner_id, scene, MAX_DUPLI_RECUR);
3200 LISTBASE_FOREACH (PTCacheID *, pid2, &pidlist2) {
3201 if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
3202 if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
3203 if (bake || pid2->cache->flag & PTCACHE_REDO_NEEDED) {
3205 }
3206 if (bake) {
3207 pid2->cache->flag |= PTCACHE_BAKING;
3208 pid2->cache->flag &= ~PTCACHE_BAKED;
3209 }
3210 }
3211 }
3212 }
3213 BLI_freelistN(&pidlist2);
3214 }
3215
3216 if (bake || cache->flag & PTCACHE_REDO_NEEDED) {
3218 }
3219
3220 startframe = std::max(cache->last_exact, cache->startframe);
3221
3222 if (bake) {
3223 endframe = cache->endframe;
3224 cache->flag |= PTCACHE_BAKING;
3225 }
3226 else {
3227 endframe = std::min(endframe, cache->endframe);
3228 }
3229
3230 cache->flag &= ~PTCACHE_BAKED;
3231 }
3232 }
3233 else {
3234 for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
3235 /* cache/bake everything in the scene */
3236 BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
3237
3238 for (pid = static_cast<PTCacheID *>(pidlist.first); pid; pid = pid->next) {
3239 cache = pid->cache;
3240 if ((cache->flag & PTCACHE_BAKED) == 0) {
3241 if (pid->type == PTCACHE_TYPE_PARTICLES) {
3242 ParticleSystem *psys = (ParticleSystem *)pid->calldata;
3243 /* skip hair & keyed particles */
3244 if (psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED) {
3245 continue;
3246 }
3247
3249 static_cast<ParticleSystem *>(pid->calldata),
3250 &cache->startframe,
3251 &cache->endframe);
3252 }
3253
3254 /* XXX: workaround for regression introduced in ee3fadd, needs looking into. */
3255 if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
3256 if ((cache->flag & PTCACHE_REDO_NEEDED ||
3257 (cache->flag & PTCACHE_SIMULATION_VALID) == 0) &&
3258 (render || bake))
3259 {
3261 }
3262 }
3263 else if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) {
3265 }
3266
3267 startframe = std::min(startframe, cache->startframe);
3268
3269 if (bake || render) {
3270 cache->flag |= PTCACHE_BAKING;
3271
3272 if (bake) {
3273 endframe = std::max(endframe, cache->endframe);
3274 }
3275 }
3276
3277 cache->flag &= ~PTCACHE_BAKED;
3278 }
3279 }
3280 BLI_freelistN(&pidlist);
3281 }
3282 }
3283
3284 scene->r.cfra = startframe;
3285 scene->r.framelen = 1.0;
3286
3287 /* bake */
3288
3289 bool use_timer = false;
3290 double stime, ptime, ctime, fetd;
3291 char run[32], cur[32], etd[32];
3292 int cancel = 0;
3293
3294 stime = ptime = BLI_time_now_seconds();
3295
3296 for (int fr = scene->r.cfra; fr <= endframe; fr += baker->quick_step, scene->r.cfra = fr) {
3298
3299 if (baker->update_progress) {
3300 float progress = (float(scene->r.cfra - startframe) / float(endframe - startframe));
3301 baker->update_progress(baker->bake_job, progress, &cancel);
3302 }
3303
3304 if (G.background) {
3305 printf("bake: frame %d :: %d\n", scene->r.cfra, endframe);
3306 }
3307 else {
3308 ctime = BLI_time_now_seconds();
3309
3310 fetd = (ctime - ptime) * (endframe - scene->r.cfra) / baker->quick_step;
3311
3312 if (use_timer || fetd > 60.0) {
3313 use_timer = true;
3314
3315 ptcache_dt_to_str(cur, sizeof(cur), ctime - ptime);
3316 ptcache_dt_to_str(run, sizeof(run), ctime - stime);
3317 ptcache_dt_to_str(etd, sizeof(etd), fetd);
3318
3319 printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s\r",
3320 run,
3321 scene->r.cfra - startframe + 1,
3322 endframe - startframe + 1,
3323 ctime - ptime,
3324 etd);
3325 }
3326
3327 ptime = ctime;
3328 }
3329
3330 /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
3331 if (cancel || G.is_break) {
3332 break;
3333 }
3334
3335 scene->r.cfra += 1;
3336 }
3337
3338 if (use_timer) {
3339 /* start with newline because of \r above */
3340 ptcache_dt_to_str(run, sizeof(run), BLI_time_now_seconds() - stime);
3341 printf("\nBake %s %s (%i frames simulated).\n",
3342 (cancel ? "canceled after" : "finished in"),
3343 run,
3344 scene->r.cfra - startframe);
3345 }
3346
3347 /* clear baking flag */
3348 if (pid && cache) {
3351 if (bake) {
3352 cache->flag |= PTCACHE_BAKED;
3353 /* write info file */
3354 if (cache->flag & PTCACHE_DISK_CACHE) {
3355 if (pid->type == PTCACHE_TYPE_PARTICLES) {
3356 /* Since writing this from outside the bake job, make sure the ParticleSystem and
3357 * PTCacheID is in a fully evaluated state. */
3358 PTCacheID pid_eval;
3359 Object *ob = reinterpret_cast<Object *>(pid->owner_id);
3361 ParticleSystem *psys = static_cast<ParticleSystem *>(pid->calldata);
3362 ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
3363 BKE_ptcache_id_from_particles(&pid_eval, ob_eval, psys_eval);
3364 BKE_ptcache_write(&pid_eval, 0);
3365 }
3366 else {
3367 BKE_ptcache_write(pid, 0);
3368 }
3369 }
3370 }
3371 }
3372 else {
3373 for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
3374 BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
3375
3376 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
3377 /* skip hair particles */
3378 if (pid->type == PTCACHE_TYPE_PARTICLES &&
3379 ((ParticleSystem *)pid->calldata)->part->type == PART_HAIR)
3380 {
3381 continue;
3382 }
3383
3384 cache = pid->cache;
3385
3386 if (baker->quick_step > 1) {
3387 cache->flag &= ~(PTCACHE_BAKING | PTCACHE_OUTDATED);
3388 }
3389 else {
3391 }
3392
3394
3395 if (bake) {
3396 cache->flag |= PTCACHE_BAKED;
3397 if (cache->flag & PTCACHE_DISK_CACHE) {
3398 if (pid->type == PTCACHE_TYPE_PARTICLES) {
3399 /* Since writing this from outside the bake job, make sure the ParticleSystem and
3400 * PTCacheID is in a fully evaluated state. */
3401 PTCacheID pid_eval;
3402 Object *ob = reinterpret_cast<Object *>(pid->owner_id);
3404 ParticleSystem *psys = static_cast<ParticleSystem *>(pid->calldata);
3405 ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
3406 BKE_ptcache_id_from_particles(&pid_eval, ob_eval, psys_eval);
3407 BKE_ptcache_write(&pid_eval, 0);
3408 }
3409 else {
3410 BKE_ptcache_write(pid, 0);
3411 }
3412 }
3413 }
3414 }
3415 BLI_freelistN(&pidlist);
3416 }
3417 }
3418
3419 scene->r.framelen = frameleno;
3420 scene->r.cfra = cfrao;
3421
3422 if (bake) { /* already on cfra unless baking */
3424 }
3425
3426 /* TODO: call redraw all windows somehow */
3427}
3428
3429/* Helpers */
3430
3432{
3433 PointCache *cache = pid->cache;
3434 PTCacheMem *pm = nullptr;
3435 int baked = cache->flag & PTCACHE_BAKED;
3436 int cfra, sfra = cache->startframe, efra = cache->endframe;
3437
3438 /* Remove possible bake flag to allow clear */
3439 cache->flag &= ~PTCACHE_BAKED;
3440
3441 /* PTCACHE_DISK_CACHE flag was cleared already */
3443
3444 /* restore possible bake flag */
3445 cache->flag |= baked;
3446
3447 for (cfra = sfra; cfra <= efra; cfra++) {
3448 pm = ptcache_disk_frame_to_mem(pid, cfra);
3449
3450 if (pm) {
3451 BLI_addtail(&pid->cache->mem_cache, pm);
3452 }
3453 }
3454}
3456{
3457 PointCache *cache = pid->cache;
3458 PTCacheMem *pm = static_cast<PTCacheMem *>(cache->mem_cache.first);
3459 int baked = cache->flag & PTCACHE_BAKED;
3460
3461 /* Remove possible bake flag to allow clear */
3462 cache->flag &= ~PTCACHE_BAKED;
3463
3464 /* PTCACHE_DISK_CACHE flag was set already */
3466
3467 /* restore possible bake flag */
3468 cache->flag |= baked;
3469
3470 for (; pm; pm = pm->next) {
3471 if (ptcache_mem_frame_to_disk(pid, pm) == 0) {
3472 cache->flag &= ~PTCACHE_DISK_CACHE;
3473 break;
3474 }
3475 }
3476
3477 /* write info file */
3478 if (cache->flag & PTCACHE_BAKED) {
3479 BKE_ptcache_write(pid, 0);
3480 }
3481}
3483{
3484 PointCache *cache = pid->cache;
3485 int last_exact = cache->last_exact;
3486 const char *blendfile_path = BKE_main_blendfile_path_from_global();
3487
3488 if (blendfile_path[0] == '\0') {
3489 cache->flag &= ~PTCACHE_DISK_CACHE;
3490 if (G.debug & G_DEBUG) {
3491 printf("File must be saved before using disk cache!\n");
3492 }
3493 return;
3494 }
3495
3496 if (cache->cached_frames) {
3497 MEM_freeN(cache->cached_frames);
3498 cache->cached_frames = nullptr;
3499 cache->cached_frames_len = 0;
3500 }
3501
3502 if (cache->flag & PTCACHE_DISK_CACHE) {
3504 }
3505 else {
3507 }
3508
3509 cache->flag ^= PTCACHE_DISK_CACHE;
3511 cache->flag ^= PTCACHE_DISK_CACHE;
3512
3513 cache->last_exact = last_exact;
3514
3515 BKE_ptcache_id_time(pid, nullptr, 0.0f, nullptr, nullptr, nullptr);
3516
3517 cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
3518
3519 if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
3520 if (cache->index) {
3522 cache->index = -1;
3523 }
3524 }
3525}
3526
3527void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const char *name_dst)
3528{
3529 char old_name[80];
3530 int len; /* store the length of the string */
3531 /* mode is same as fopen's modes */
3532 DIR *dir;
3533 dirent *de;
3534 char path[MAX_PTCACHE_PATH];
3535 char old_filepath[MAX_PTCACHE_FILE];
3536 char new_path_full[MAX_PTCACHE_FILE];
3537 char old_path_full[MAX_PTCACHE_FILE];
3538 char ext[MAX_PTCACHE_FILE];
3539
3540 /* If both names are the same, there is nothing to do. */
3541 if (STREQ(name_src, name_dst)) {
3542 return;
3543 }
3544
3545 /* save old name */
3546 STRNCPY(old_name, pid->cache->name);
3547
3548 /* get "from" filename */
3549 STRNCPY(pid->cache->name, name_src);
3550
3551 len = ptcache_filepath(pid, old_filepath, 0, false, false); /* no path */
3552
3553 ptcache_path(pid, path);
3554 dir = opendir(path);
3555 if (dir == nullptr) {
3556 STRNCPY(pid->cache->name, old_name);
3557 return;
3558 }
3559
3560 ptcache_filepath_ext_append(pid, ext, 0, false, 0);
3561
3562 /* put new name into cache */
3563 STRNCPY(pid->cache->name, name_dst);
3564
3565 while ((de = readdir(dir)) != nullptr) {
3566 if (strstr(de->d_name, ext)) { /* Do we have the right extension? */
3567 if (STREQLEN(old_filepath, de->d_name, len)) { /* Do we have the right prefix. */
3568 /* read the number of the file */
3569 const int frame = ptcache_frame_from_filename(de->d_name, ext);
3570
3571 if (frame != -1) {
3572 BLI_path_join(old_path_full, sizeof(old_path_full), path, de->d_name);
3573 ptcache_filepath(pid, new_path_full, frame, true, true);
3574 BLI_rename_overwrite(old_path_full, new_path_full);
3575 }
3576 }
3577 }
3578 }
3579 closedir(dir);
3580
3581 STRNCPY(pid->cache->name, old_name);
3582}
3583
3585{
3586 /* TODO: */
3587 PointCache *cache = pid->cache;
3588 int len; /* store the length of the string */
3589 int info = 0;
3590 int start = MAXFRAME;
3591 int end = -1;
3592
3593 /* mode is same as fopen's modes */
3594 DIR *dir;
3595 dirent *de;
3596 char path[MAX_PTCACHE_PATH];
3597 char filepath[MAX_PTCACHE_FILE];
3598 char ext[MAX_PTCACHE_PATH];
3599
3600 if (!cache) {
3601 return;
3602 }
3603
3604 ptcache_path(pid, path);
3605
3606 len = ptcache_filepath(pid, filepath, 1, false, false); /* no path */
3607
3608 dir = opendir(path);
3609 if (dir == nullptr) {
3610 return;
3611 }
3612
3613 const char *fext = ptcache_file_extension(pid);
3614
3615 if (cache->index >= 0) {
3616 SNPRINTF(ext, "_%02d%s", cache->index, fext);
3617 }
3618 else {
3619 STRNCPY(ext, fext);
3620 }
3621
3622 while ((de = readdir(dir)) != nullptr) {
3623 if (strstr(de->d_name, ext)) { /* Do we have the right extension? */
3624 if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */
3625 /* read the number of the file */
3626 const int frame = ptcache_frame_from_filename(de->d_name, ext);
3627
3628 if (frame != -1) {
3629 if (frame) {
3630 start = std::min(start, frame);
3631 end = std::max(end, frame);
3632 }
3633 else {
3634 info = 1;
3635 }
3636 }
3637 }
3638 }
3639 }
3640 closedir(dir);
3641
3642 if (start != MAXFRAME) {
3643 PTCacheFile *pf;
3644
3645 cache->startframe = start;
3646 cache->endframe = end;
3647 cache->totpoint = 0;
3648
3649 if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
3650 /* necessary info in every file */
3651 }
3652 /* read totpoint from info file (frame 0) */
3653 else if (info) {
3655
3656 if (pf) {
3658 if (pf->type == pid->type && pid->read_header(pf)) {
3659 cache->totpoint = pf->totpoint;
3660 cache->flag |= PTCACHE_READ_INFO;
3661 }
3662 else {
3663 cache->totpoint = 0;
3664 }
3665 }
3667 }
3668 }
3669 /* or from any old format cache file */
3670 else {
3671 float old_data[14];
3672 int elemsize = ptcache_old_elemsize(pid);
3674
3675 if (pf) {
3676 while (ptcache_file_read(pf, old_data, 1, elemsize)) {
3677 cache->totpoint++;
3678 }
3679
3681 }
3682 }
3685 }
3686
3687 /* make sure all new frames are loaded */
3688 if (cache->cached_frames) {
3689 MEM_freeN(cache->cached_frames);
3690 cache->cached_frames = nullptr;
3691 cache->cached_frames_len = 0;
3692 }
3693
3694 cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
3695}
3696
3698{
3699 PointCache *cache = pid->cache;
3700 int totframes = 0;
3701 char mem_info[sizeof(PointCache::info) / sizeof(*PointCache::info)];
3702
3703 cache->flag &= ~PTCACHE_FLAG_INFO_DIRTY;
3704
3705 if (cache->flag & PTCACHE_EXTERNAL) {
3706 int cfra = cache->startframe;
3707
3708 for (; cfra <= cache->endframe; cfra++) {
3709 if (BKE_ptcache_id_exist(pid, cfra)) {
3710 totframes++;
3711 }
3712 }
3713
3714 /* smoke doesn't use frame 0 as info frame so can't check based on totpoint */
3715 if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN && totframes) {
3716 SNPRINTF(cache->info, RPT_("%i frames found!"), totframes);
3717 }
3718 else if (totframes && cache->totpoint) {
3719 SNPRINTF(cache->info, RPT_("%i points found!"), cache->totpoint);
3720 }
3721 else {
3722 STRNCPY(cache->info, RPT_("No valid data to read!"));
3723 }
3724 return;
3725 }
3726
3727 if (cache->flag & PTCACHE_DISK_CACHE) {
3728 if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
3729 int totpoint = pid->totpoint(pid->calldata, 0);
3730
3731 if (cache->totpoint > totpoint) {
3732 SNPRINTF(mem_info, RPT_("%i cells + High Resolution cached"), totpoint);
3733 }
3734 else {
3735 SNPRINTF(mem_info, RPT_("%i cells cached"), totpoint);
3736 }
3737 }
3738 else {
3739 int cfra = cache->startframe;
3740
3741 for (; cfra <= cache->endframe; cfra++) {
3742 if (BKE_ptcache_id_exist(pid, cfra)) {
3743 totframes++;
3744 }
3745 }
3746
3747 SNPRINTF(mem_info, RPT_("%i frames on disk"), totframes);
3748 }
3749 }
3750 else {
3751 PTCacheMem *pm = static_cast<PTCacheMem *>(cache->mem_cache.first);
3752 char formatted_tot[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
3753 char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
3754 long long int bytes = 0.0f;
3755 int i;
3756
3757 for (; pm; pm = pm->next) {
3758 for (i = 0; i < BPHYS_TOT_DATA; i++) {
3759 bytes += MEM_allocN_len(pm->data[i]);
3760 }
3761
3762 LISTBASE_FOREACH (PTCacheExtra *, extra, &pm->extradata) {
3763 bytes += MEM_allocN_len(extra->data);
3764 bytes += sizeof(PTCacheExtra);
3765 }
3766
3767 bytes += sizeof(PTCacheMem);
3768
3769 totframes++;
3770 }
3771
3772 BLI_str_format_int_grouped(formatted_tot, totframes);
3773 BLI_str_format_byte_unit(formatted_mem, bytes, false);
3774
3775 SNPRINTF(mem_info, RPT_("%s frames in memory (%s)"), formatted_tot, formatted_mem);
3776 }
3777
3778 if (cache->flag & PTCACHE_OUTDATED) {
3779 SNPRINTF(cache->info, RPT_("%s, cache is outdated!"), mem_info);
3780 }
3781 else if (cache->flag & PTCACHE_FRAMES_SKIPPED) {
3782 SNPRINTF(cache->info, RPT_("%s, not exact since frame %i"), mem_info, cache->last_exact);
3783 }
3784 else {
3785 SNPRINTF(cache->info, "%s.", mem_info);
3786 }
3787}
3788
3789void BKE_ptcache_validate(PointCache *cache, int framenr)
3790{
3791 if (cache) {
3793 cache->simframe = framenr;
3794 }
3795}
3797{
3798 if (cache) {
3799 cache->flag &= ~PTCACHE_SIMULATION_VALID;
3800 cache->simframe = 0;
3801 cache->last_exact = std::min(cache->startframe, 0);
3802 }
3803}
3804
3806{
3807 LISTBASE_FOREACH (PointCache *, cache, ptcaches) {
3808 BLO_write_struct(writer, PointCache, cache);
3809
3810 if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
3811 LISTBASE_FOREACH (PTCacheMem *, pm, &cache->mem_cache) {
3812 BLO_write_struct(writer, PTCacheMem, pm);
3813
3814 for (int i = 0; i < BPHYS_TOT_DATA; i++) {
3815 if (pm->data[i] && pm->data_types & (1 << i)) {
3816 if (i == BPHYS_DATA_BOIDS) {
3817 BLO_write_struct_array(writer, BoidData, pm->totpoint, pm->data[i]);
3818 }
3819 else if (i == BPHYS_DATA_INDEX) { /* Only 'cache type' to use uint values. */
3821 writer, pm->totpoint, reinterpret_cast<uint32_t *>(pm->data[i]));
3822 }
3823 else { /* All other types of caches use (vectors of) floats. */
3824 /* data_size returns bytes. */
3825 const uint32_t items_num = pm->totpoint * (BKE_ptcache_data_size(i) / sizeof(float));
3826 BLO_write_float_array(writer, items_num, reinterpret_cast<float *>(pm->data[i]));
3827 }
3828 }
3829 }
3830
3831 LISTBASE_FOREACH (PTCacheExtra *, extra, &pm->extradata) {
3832 BLO_write_struct(writer, PTCacheExtra, extra);
3833 if (extra->type == BPHYS_EXTRA_FLUID_SPRINGS) {
3834 BLO_write_struct_array(writer, ParticleSpring, extra->totdata, extra->data);
3835 }
3836 else if (extra->type == BPHYS_EXTRA_CLOTH_ACCELERATION) {
3837 BLO_write_struct_array(writer, vec3f, extra->totdata, extra->data);
3838 }
3839 else if (extra->data) {
3841 }
3842 }
3843 }
3844 }
3845 }
3846}
3847
3849{
3850 for (int i = 0; i < BPHYS_TOT_DATA; i++) {
3851 if (i == BPHYS_DATA_BOIDS) {
3852 BLO_read_struct_array(reader, BoidData, pm->totpoint, &pm->data[i]);
3853 }
3854 else if (i == BPHYS_DATA_INDEX) { /* Only 'cache type' to use uint values. */
3855 BLO_read_uint32_array(reader, pm->totpoint, reinterpret_cast<uint32_t **>(&pm->data[i]));
3856 }
3857 else { /* All other types of caches use (vectors of) floats. */
3858 /* data_size returns bytes. */
3859 const uint32_t items_num = pm->totpoint * (BKE_ptcache_data_size(i) / sizeof(float));
3860 BLO_read_float_array(reader, items_num, reinterpret_cast<float **>(&pm->data[i]));
3861 }
3862 }
3863
3865
3866 LISTBASE_FOREACH (PTCacheExtra *, extra, &pm->extradata) {
3867 if (extra->type == BPHYS_EXTRA_FLUID_SPRINGS) {
3868 BLO_read_struct_array(reader, ParticleSpring, extra->totdata, &extra->data);
3869 }
3870 else if (extra->type == BPHYS_EXTRA_CLOTH_ACCELERATION) {
3871 BLO_read_struct_array(reader, vec3f, extra->totdata, &extra->data);
3872 }
3873 else if (extra->data) {
3874 extra->data = nullptr;
3875 }
3876 }
3877}
3878
3880{
3881 if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
3882 BLO_read_struct_list(reader, PTCacheMem, &cache->mem_cache);
3883 LISTBASE_FOREACH (PTCacheMem *, pm, &cache->mem_cache) {
3884 direct_link_pointcache_mem(reader, pm);
3885 }
3886 }
3887 else {
3889 }
3890
3891 cache->flag &= ~PTCACHE_SIMULATION_VALID;
3892 cache->simframe = 0;
3893 cache->edit = nullptr;
3894 cache->free_edit = nullptr;
3895 cache->cached_frames = nullptr;
3896 cache->cached_frames_len = 0;
3897}
3898
3900 ListBase *ptcaches,
3901 PointCache **ocache,
3902 int force_disk)
3903{
3904 if (ptcaches->first) {
3905 BLO_read_struct_list(reader, PointCache, ptcaches);
3906 LISTBASE_FOREACH (PointCache *, cache, ptcaches) {
3907 direct_link_pointcache(reader, cache);
3908 if (force_disk) {
3909 cache->flag |= PTCACHE_DISK_CACHE;
3910 cache->step = 1;
3911 }
3912 }
3913
3914 BLO_read_struct(reader, PointCache, ocache);
3915 }
3916 else if (*ocache) {
3917 /* old "single" caches need to be linked too */
3918 BLO_read_struct(reader, PointCache, ocache);
3919 direct_link_pointcache(reader, *ocache);
3920 if (force_disk) {
3921 (*ocache)->flag |= PTCACHE_DISK_CACHE;
3922 (*ocache)->step = 1;
3923 }
3924
3925 ptcaches->first = ptcaches->last = *ocache;
3926 }
3927}
void BIK_clear_cache(struct bPose *pose)
void cloth_free_modifier(ClothModifierData *clmd)
Definition cloth.cc:433
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
struct PaintPoint PaintPoint
struct PaintWavePoint PaintWavePoint
void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface)
@ G_DEBUG
@ LIB_ID_COPY_CACHES
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:837
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
General operations, lookup, etc. for blender objects.
int BKE_object_insert_ptcache(Object *ob)
void BKE_object_delete_ptcache(Object *ob, int index)
void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, bool velocity)
Definition particle.cc:1137
void psys_reset(struct ParticleSystem *psys, int mode)
#define PSYS_RESET_ALL
struct ParticleSystem * psys_eval_get(struct Depsgraph *depsgraph, struct Object *object, struct ParticleSystem *psys)
Definition particle.cc:664
#define PSYS_RESET_DEPSGRAPH
#define PTCACHE_TYPEFLAG_TYPEMASK
#define PTCACHE_FILE_READ
#define PTCACHE_TYPE_SMOKE_HIGHRES
#define PTCACHE_VEL_PER_SEC
#define PTCACHE_FILE_WRITE
#define PTCACHE_CLEAR_BEFORE
#define PTCACHE_CLEAR_AFTER
#define PTCACHE_EXT
#define PTCACHE_TYPE_CLOTH
#define PTCACHE_TYPE_DYNAMICPAINT
#define PTCACHE_CLEAR_ALL
#define PTCACHE_READ_INTERPOLATED
#define PTCACHE_TYPE_PARTICLES
#define PTCACHE_TYPEFLAG_FLAGMASK
#define PTCACHE_TYPE_SOFTBODY
@ PTCACHE_FILE_PTCACHE
#define PTCACHE_READ_OLD
#define PTCACHE_TYPEFLAG_COMPRESS
#define PTCACHE_FILE_UPDATE
#define PTCACHE_CLEAR_FRAME
#define PTCACHE_TYPE_SMOKE_DOMAIN
#define PTCACHE_RESET_OUTDATED
#define PTCACHE_PATH
#define PTCACHE_TYPE_RIGIDBODY
#define PTCACHE_RESET_DEPSGRAPH
#define PTCACHE_RESET_BAKED
#define PTCACHE_READ_EXACT
#define PTCACHE_TYPEFLAG_EXTRADATA
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2317
#define SETLOOPER_VIEW_LAYER(_sce_basis, _view_layer, _sce_iter, _base)
Definition BKE_scene.hh:44
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2647
float BKE_scene_frame_to_ctime(const Scene *scene, int frame)
Definition scene.cc:2322
void sbFreeSimulation(struct SoftBody *sb)
Definition softbody.cc:3193
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
int BLI_rename_overwrite(const char *from, const char *to) ATTR_NONNULL()
Definition fileops_c.cc:505
int BLI_fseek(FILE *stream, int64_t offset, int whence)
Definition storage.cc:188
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:251
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag)
void unit_qt(float q[4])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool bool BLI_path_extension_strip(char *path) ATTR_NONNULL(1)
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
size_t BLI_str_format_int_grouped(char dst[BLI_STR_FORMAT_INT32_GROUPED_SIZE], int num) ATTR_NONNULL(1)
Definition string.c:1168
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE
Definition BLI_string.h:28
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define BLI_STR_FORMAT_INT32_GROUPED_SIZE
Definition BLI_string.h:25
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE], long long int bytes, bool base_10) ATTR_NONNULL(1)
Definition string.c:1192
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char char size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define UNPACK4(a)
#define UNUSED_VARS(...)
#define STREQLEN(a, b, n)
#define ELEM(...)
#define STREQ(a, b)
Compatibility-like things for windows.
struct __dirstream DIR
struct dirent * readdir(DIR *dp)
int closedir(DIR *dp)
const char * dirname(char *path)
DIR * opendir(const char *path)
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4967
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
Definition readfile.cc:4957
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define RPT_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_PSYS_REDO
Definition DNA_ID.h:1048
@ ID_RECALC_PSYS_CHILD
Definition DNA_ID.h:1052
@ ID_OB
Object groups, one object can be in many groups at once.
@ MOD_DPAINT_SURFACE_T_WEIGHT
@ MOD_DPAINT_SURFACE_T_PAINT
@ MOD_DPAINT_SURFACE_T_DISPLACE
@ MOD_DPAINT_SURFACE_T_WAVE
@ MOD_DPAINT_SURFACE_F_IMAGESEQ
@ FLUID_DOMAIN_CACHE_REPLAY
@ MOD_FLUID_TYPE_DOMAIN
@ eModifierType_Cloth
@ eModifierType_Fluid
@ eModifierType_DynamicPaint
Object is a sort of wrapper for general info.
#define MAX_DUPLI_RECUR
@ OB_ARMATURE
@ OB_NEGX
@ OB_POSZ
@ PART_DIED
@ PART_ROTATIONS
@ PART_EMITTER
@ PART_FLUID
@ PART_HAIR
struct ParticleKey ParticleKey
@ PART_AVE_RAND
@ PART_ROT_VEL
struct ParticleSpring ParticleSpring
@ PART_PHYS_FLUID
@ PART_PHYS_KEYED
@ PART_PHYS_BOIDS
@ PART_PHYS_NO
@ SPH_VISCOELASTIC_SPRINGS
@ PSYS_HAIR_DYNAMICS
struct PTCacheMem PTCacheMem
@ PTCACHE_READ_INFO
@ PTCACHE_IGNORE_CLEAR
@ PTCACHE_EXTERNAL
@ PTCACHE_IGNORE_LIBPATH
@ PTCACHE_BAKED
@ PTCACHE_FRAMES_SKIPPED
@ PTCACHE_FLAG_INFO_DIRTY
@ PTCACHE_BAKING
@ PTCACHE_OUTDATED
@ PTCACHE_DISK_CACHE
@ PTCACHE_SIMULATION_VALID
@ PTCACHE_REDO_NEEDED
@ BPHYS_EXTRA_FLUID_SPRINGS
@ BPHYS_EXTRA_CLOTH_ACCELERATION
struct PTCacheExtra PTCacheExtra
@ BPHYS_DATA_XCONST
@ BPHYS_DATA_SIZE
@ BPHYS_DATA_DYNAMICPAINT
@ BPHYS_DATA_VELOCITY
@ BPHYS_DATA_LOCATION
@ BPHYS_DATA_BOIDS
@ BPHYS_DATA_INDEX
@ BPHYS_DATA_AVELOCITY
@ BPHYS_DATA_ROTATION
@ BPHYS_DATA_TIMES
#define BPHYS_TOT_DATA
@ PTCACHE_COMPRESS_LZMA
@ PTCACHE_COMPRESS_LZO
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
@ RBO_FLAG_NEEDS_RESHAPE
#define MAXFRAME
Read Guarded memory(de)allocation.
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static float frame_len(const Frame *frame)
Definition MOD_skin.cc:384
Rigid Body API for interfacing with external Physics Engines.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void reset()
clear internal cached data and reset random seed
#define printf
double time
const Depsgraph * depsgraph
DEGForeachIDComponentCallback callback
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define rot(x, k)
#define str(s)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
int count
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float2 floor(const float2 a)
#define G(x, y, z)
static void error(const char *str)
static void clear(Message &msg)
Definition msgfmt.cc:218
static int ptcache_rigidbody_totpoint(void *rb_v, int)
int BKE_ptcache_data_size(int data_type)
static int ptcache_file_write(PTCacheFile *pf, const void *f, uint tot, uint size)
#define PTCACHE_DATA_FROM(data, type, from)
Definition pointcache.cc:89
int BKE_ptcache_mem_index_find(PTCacheMem *pm, uint index)
static int ptcache_basic_header_read(PTCacheFile *pf)
static void ptcache_data_copy(void *from[], void *to[])
void BKE_ptcache_disk_to_mem(PTCacheID *pid)
void BKE_ptcache_mem_pointers_incr(void *cur[BPHYS_TOT_DATA])
static int ptcache_cloth_totpoint(void *cloth_v, int)
static int ptcache_softbody_totpoint(void *soft_v, int)
static PTCacheFile * ptcache_file_open(PTCacheID *pid, int mode, int cfra)
static int ptcache_particle_totwrite(void *psys_v, int cfra)
static int ptcache_file_compressed_write(PTCacheFile *pf, uchar *in, uint in_len, uchar *out, int mode)
static void ptcache_particle_interpolate(int index, void *psys_v, void **data, float cfra, float cfra1, float cfra2, const float *old_data)
static void ptcache_add_extra_data(PTCacheMem *pm, uint type, uint count, void *data)
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
void BKE_ptcache_invalidate(PointCache *cache)
void BKE_ptcache_load_external(PTCacheID *pid)
static void ptcache_file_close(PTCacheFile *pf)
static int ptcache_filepath(PTCacheID *pid, char filepath[MAX_PTCACHE_FILE], int cfra, const bool do_path, const bool do_ext)
static int ptcache_read(PTCacheID *pid, int cfra)
static int ptcache_dynamicpaint_totpoint(void *sd, int)
static void ptcache_cloth_extra_write(void *cloth_v, PTCacheMem *pm, int)
#define MAX_PTCACHE_PATH
void BKE_ptcache_mem_to_disk(PTCacheID *pid)
static const char * ptcache_file_extension(const PTCacheID *pid)
void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
static void ptcache_softbody_read(int index, void *soft_v, void **data, float, const float *old_data)
static int ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v)
static int ptcache_data_size[]
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw)
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
static void direct_link_pointcache_mem(BlendDataReader *reader, PTCacheMem *pm)
static void ptcache_data_alloc(PTCacheMem *pm)
static void ptcache_cloth_extra_read(void *cloth_v, PTCacheMem *pm, float)
void BKE_ptcache_foreach_object_cache(Object &ob, Scene &scene, bool duplis, PointCacheIdFn fn)
static int ptcache_write(PTCacheID *pid, int cfra, int overwrite)
void BKE_ptcache_update_info(PTCacheID *pid)
static int ptcache_mem_frame_to_disk(PTCacheID *pid, PTCacheMem *pm)
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint)
static int ptcache_cloth_write(int index, void *cloth_v, void **data, int)
#define MAX_PTCACHE_FILE
void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
static void direct_link_pointcache(BlendDataReader *reader, PointCache *cache)
static PTCacheMem * ptcache_disk_frame_to_mem(PTCacheID *pid, int cfra)
static int ptcache_particle_totpoint(void *psys_v, int)
static int ptcache_file_data_write(PTCacheFile *pf)
static void ptcache_file_pointers_init(PTCacheFile *pf)
bool BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
void BKE_ptcache_free_mem(ListBase *mem_cache)
void BKE_ptcache_free_list(ListBase *ptcaches)
static int ptcache_read_stream(PTCacheID *pid, int cfra)
static void ptcache_cloth_interpolate(int index, void *cloth_v, void **data, float cfra, float cfra1, float cfra2, const float *old_data)
void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int)
static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
static void ptcache_particle_extra_write(void *psys_v, PTCacheMem *pm, int)
void BKE_ptcache_mem_pointers_init(PTCacheMem *pm, void *cur[BPHYS_TOT_DATA])
PointCache * BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, const int flag)
static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
void BKE_ptcache_id_from_smoke(PTCacheID *pid, Object *ob, FluidModifierData *fmd)
void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
static bool foreach_object_ptcache(Scene *scene, Object *object, int duplis, PointCacheIdFn callback)
static int ptcache_extra_datasize[]
static size_t ptcache_filepath_ext_append(PTCacheID *pid, char filepath[MAX_PTCACHE_FILE], const size_t filepath_len, const bool use_frame_number, const int cfra)
static int ptcache_frame_from_filename(const char *filename, const char *ext)
void BKE_ptcache_blend_read_data(BlendDataReader *reader, ListBase *ptcaches, PointCache **ocache, int force_disk)
bool BKE_ptcache_object_has(Scene *scene, Object *ob, int duplis)
int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm, void *cur[BPHYS_TOT_DATA])
void BKE_ptcache_bake(PTCacheBaker *baker)
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
static int ptcache_file_compressed_read(PTCacheFile *pf, uchar *result, uint len)
static void ptcache_softbody_error(const ID *, void *, const char *)
void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
static void ptcache_cloth_read(int index, void *cloth_v, void **data, float, const float *old_data)
static void ptcache_particle_read(int index, void *psys_v, void **data, float cfra, const float *old_data)
static PointCache * ptcache_copy(PointCache *cache, const bool copy_data)
int BKE_ptcache_write(PTCacheID *pid, uint cfra)
static void ptcache_cloth_error(const ID *owner_id, void *cloth_v, const char *message)
static void ptcache_rigidbody_error(const ID *, void *, const char *)
void BKE_ptcache_free(PointCache *cache)
static int ptcache_old_elemsize(PTCacheID *pid)
static bool foreach_object_modifier_ptcache(Object *object, PointCacheIdFn callback)
void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const char *name_dst)
static CLG_LogRef LOG
static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
#define PTCACHE_DATA_TO(data, type, index, to)
Definition pointcache.cc:95
static void ptcache_rigidbody_interpolate(int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, const float *old_data)
#define LZO_OUT_LEN(size)
Definition pointcache.cc:83
static int ptcache_particle_write(int index, void *psys_v, void **data, int cfra)
static bool foreach_object_particle_ptcache(Object *object, PointCacheIdFn callback)
static void ptcache_particle_extra_read(void *psys_v, PTCacheMem *pm, float)
#define DPAINT_CACHE_VERSION
static void ptcache_dynamicpaint_error(const ID *, void *, const char *)
static int ptcache_file_header_begin_write(PTCacheFile *pf)
void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
static int ptcache_softbody_write(int index, void *soft_v, void **data, int)
static void ptcache_softbody_interpolate(int index, void *soft_v, void **data, float cfra, float cfra1, float cfra2, const float *old_data)
static void ptcache_find_frames_around(PTCacheID *pid, uint frame, int *r_fra1, int *r_fra2)
PointCache * BKE_ptcache_add(ListBase *ptcaches)
static void ptcache_mem_clear(PTCacheMem *pm)
static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
void BKE_ptcache_validate(PointCache *cache, int framenr)
static void ptcache_data_free(PTCacheMem *pm)
static int ptcache_file_header_begin_read(PTCacheFile *pf)
static void ptcache_extra_free(PTCacheMem *pm)
static void ptcache_rigidbody_read(int index, void *rb_v, void **data, float, const float *old_data)
static int ptcache_file_read(PTCacheFile *pf, void *f, uint tot, uint size)
int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
static void ptcache_dt_to_str(char *str, size_t str_maxncpy, double dtime)
static int ptcache_basic_header_write(PTCacheFile *pf)
static void ptcache_particle_error(const ID *, void *, const char *)
void BKE_ptcache_blend_write(BlendWriter *writer, ListBase *ptcaches)
static int ptcache_file_data_read(PTCacheFile *pf)
return ret
void RB_body_get_orientation(rbRigidBody *object, float v_out[4])
void RB_body_get_position(rbRigidBody *object, float v_out[3])
unsigned int uint32_t
Definition stdint.h:80
struct Object * object
float pos[3]
float vec[3]
struct BoidData data
struct ListBase ptcaches
struct ClothHairData * hairdata
struct Cloth * clothObject
struct PointCache * point_cache
float x[3]
Definition BKE_cloth.hh:96
float v[3]
Definition BKE_cloth.hh:94
float xconst[3]
Definition BKE_cloth.hh:95
unsigned int mvert_num
Definition BKE_cloth.hh:72
struct DynamicPaintCanvasSettings * canvas
struct PaintSurfaceData * data
struct ListBase ptcaches[2]
struct PointCache * point_cache[2]
struct FluidDomainSettings * domain
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:419
char name[66]
Definition DNA_ID.h:425
void * last
void * first
ListBase particlesystem
struct bPose * pose
ListBase modifiers
struct RigidBodyOb * rigidbody_object
struct SoftBody * soft
struct RigidBodyCon * rigidbody_constraint
struct PTCacheID pid
struct Scene * scene
struct Main * bmain
void(* update_progress)(void *data, float progress, int *cancel)
struct Depsgraph * depsgraph
struct ViewLayer * view_layer
unsigned int totdata
struct PTCacheExtra * next
struct PointCache ** cache_ptr
int(* write_stream)(PTCacheFile *pf, void *calldata)
int(* write_point)(int index, void *calldata, void **data, int cfra)
unsigned int data_types
struct ID * owner_id
unsigned int info_types
int(* write_header)(PTCacheFile *pf)
void(* read_point)(int index, void *calldata, void **data, float cfra, const float *old_data)
void * calldata
unsigned int type
void(* interpolate_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra, float cfra1, float cfra2)
unsigned int stack_index
struct ListBase * ptcaches
unsigned int flag
void(* read_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra)
void(* interpolate_point)(int index, void *calldata, void **data, float cfra, float cfra1, float cfra2, const float *old_data)
unsigned int default_step
int(* totpoint)(void *calldata, int cfra)
unsigned int file_type
int(* totwrite)(void *calldata, int cfra)
void(* write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra)
int(* read_stream)(PTCacheFile *pf, void *calldata)
unsigned int max_step
void(* error)(const struct ID *owner_id, void *calldata, const char *message)
struct PTCacheID * next
int(* read_header)(PTCacheFile *pf)
struct PointCache * cache
unsigned int data_types
unsigned int frame
struct ListBase extradata
struct PTCacheMem * next
struct PTCacheMem * prev
unsigned int totpoint
BoidParticle * boid
ParticleKey state
ParticleKey prev_state
struct SPHFluidSettings * fluid
ParticleSpring * fluid_springs
struct ListBase ptcaches
ParticleData * particles
ParticleSettings * part
struct PointCache * pointcache
struct PointCache * next
struct ListBase mem_cache
struct PTCacheEdit * edit
void(* free_edit)(struct PTCacheEdit *edit)
struct RigidBodyOb_Shared * shared
struct PointCache * pointcache
struct RigidBodyWorld_Shared * shared
struct Object ** objects
struct PointCache * pointcache
struct SoftBody_Shared * shared
struct BodyPoint * bpoint
char * d_name
void * BKE_tempdir_session
Definition stubs.c:38
static DynamicLibrary lib
uint8_t flag
Definition wm_window.cc:138