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