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