Blender V4.3
physics_pointcache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 by Janne Karhu. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdlib>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_utildefines.h"
15
16#include "BKE_context.hh"
17#include "BKE_global.hh"
18#include "BKE_layer.hh"
19#include "BKE_pointcache.h"
20
21#include "DEG_depsgraph.hh"
22
23#include "ED_particle.hh"
24
25#include "WM_api.hh"
26#include "WM_types.hh"
27
28#include "RNA_access.hh"
29#include "RNA_define.hh"
30#include "RNA_prototypes.hh"
31
32#include "physics_intern.hh"
33
35{
36 return CTX_data_scene(C) != nullptr;
37}
38
39static bool ptcache_poll(bContext *C)
40{
41 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
42
43 ID *id = ptr.owner_id;
44 PointCache *point_cache = static_cast<PointCache *>(ptr.data);
45
46 if (id == nullptr || point_cache == nullptr) {
47 return false;
48 }
49
50 if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
52 "Library override data-blocks only support Disk Cache storage");
53 return false;
54 }
55
56 if (!ID_IS_EDITABLE(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
57 CTX_wm_operator_poll_msg_set(C, "Linked data-blocks do not allow editing caches");
58 return false;
59 }
60
61 return true;
62}
63
65{
66 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
67
68 ID *id = ptr.owner_id;
69 PointCache *point_cache = static_cast<PointCache *>(ptr.data);
70
71 if (id == nullptr || point_cache == nullptr) {
72 return false;
73 }
74
77 C, "Linked or library override data-blocks do not allow adding or removing caches");
78 return false;
79 }
80
81 return true;
82}
83
92
93static void ptcache_job_free(void *customdata)
94{
95 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
96 MEM_freeN(job->baker);
97 MEM_freeN(job);
98}
99
100static int ptcache_job_break(void *customdata)
101{
102 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
103
104 if (G.is_break) {
105 return 1;
106 }
107
108 if (job->stop && *(job->stop)) {
109 return 1;
110 }
111
112 return 0;
113}
114
115static void ptcache_job_update(void *customdata, float progress, int *cancel)
116{
117 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
118
119 if (ptcache_job_break(job)) {
120 *cancel = 1;
121 }
122
123 *(job->do_update) = true;
124 *(job->progress) = progress;
125}
126
127static void ptcache_job_startjob(void *customdata, wmJobWorkerStatus *worker_status)
128{
129 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
130
131 job->stop = &worker_status->stop;
132 job->do_update = &worker_status->do_update;
133 job->progress = &worker_status->progress;
134
135 G.is_break = false;
136
137 /* XXX annoying hack: needed to prevent data corruption when changing
138 * scene frame in separate threads
139 */
140 WM_set_locked_interface(job->wm, true);
141
143
144 worker_status->do_update = true;
145 worker_status->stop = false;
146}
147
148static void ptcache_job_endjob(void *customdata)
149{
150 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
151 Scene *scene = job->baker->scene;
152
153 WM_set_locked_interface(job->wm, false);
154
157}
158
159static void ptcache_free_bake(PointCache *cache)
160{
161 if (cache->edit) {
162 if (!cache->edit->edited || true) { // XXX okee("Lose changes done in particle mode?")) {
164 cache->edit = nullptr;
165 cache->flag &= ~PTCACHE_BAKED;
166 }
167 }
168 else {
169 cache->flag &= ~PTCACHE_BAKED;
170 }
171}
172
174{
175 PTCacheBaker *baker = static_cast<PTCacheBaker *>(
176 MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker"));
177
178 baker->bmain = CTX_data_main(C);
179 baker->scene = CTX_data_scene(C);
181 /* Depsgraph is used to sweep the frame range and evaluate scene at different times. */
183 baker->bake = RNA_boolean_get(op->ptr, "bake");
184 baker->render = false;
185 baker->anim_init = false;
186 baker->quick_step = 1;
187
188 if (!all) {
189 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
190 ID *id = ptr.owner_id;
191 Object *ob = (GS(id->name) == ID_OB) ? (Object *)id : nullptr;
192 PointCache *cache = static_cast<PointCache *>(ptr.data);
193 baker->pid = BKE_ptcache_id_find(ob, baker->scene, cache);
194 }
195
196 return baker;
197}
198
200{
201 bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
202
203 PTCacheBaker *baker = ptcache_baker_create(C, op, all);
204 BKE_ptcache_bake(baker);
205 MEM_freeN(baker);
206
207 return OPERATOR_FINISHED;
208}
209
210static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
211{
212 bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
213
214 PointCacheJob *job = static_cast<PointCacheJob *>(
215 MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob"));
216 job->wm = CTX_wm_manager(C);
217 job->baker = ptcache_baker_create(C, op, all);
218 job->baker->bake_job = job;
220
221 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
222 CTX_wm_window(C),
224 "Point Cache",
227
231
233
234 WM_jobs_start(CTX_wm_manager(C), wm_job);
235
237
238 /* we must run modal until the bake job is done, otherwise the undo push
239 * happens before the job ends, which can lead to race conditions between
240 * the baking and file writing code */
242}
243
244static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent * /*event*/)
245{
246 Scene *scene = (Scene *)op->customdata;
247
248 /* no running blender, remove handler and pass through */
251 }
252
254}
255
257{
259 Scene *scene = (Scene *)op->customdata;
260
261 /* kill on cancel, because job is using op->reports */
263}
264
266{
267 Scene *scene = CTX_data_scene(C);
268 ListBase pidlist;
269
270 FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
271 BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
272
273 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
274 ptcache_free_bake(pid->cache);
275 }
276
277 BLI_freelistN(&pidlist);
278
280 }
282
284
285 return OPERATOR_FINISHED;
286}
287
289{
290 /* identifiers */
291 ot->name = "Bake All Physics";
292 ot->description = "Bake all physics";
293 ot->idname = "PTCACHE_OT_bake_all";
294
295 /* api callbacks */
301
302 /* flags */
304
305 RNA_def_boolean(ot->srna, "bake", true, "Bake", "");
306}
308{
309 /* identifiers */
310 ot->name = "Delete All Physics Bakes";
311 ot->idname = "PTCACHE_OT_free_bake_all";
312 ot->description = "Delete all baked caches of all objects in the current scene";
313
314 /* api callbacks */
317
318 /* flags */
320}
321
323{
324 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
325 PointCache *cache = static_cast<PointCache *>(ptr.data);
326 Object *ob = (Object *)ptr.owner_id;
327
328 ptcache_free_bake(cache);
329
331
332 return OPERATOR_FINISHED;
333}
335{
336 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
337 PointCache *cache = static_cast<PointCache *>(ptr.data);
338 Object *ob = (Object *)ptr.owner_id;
339
340 cache->flag |= PTCACHE_BAKED;
341
343
344 return OPERATOR_FINISHED;
345}
347{
348 /* identifiers */
349 ot->name = "Bake Physics";
350 ot->description = "Bake physics";
351 ot->idname = "PTCACHE_OT_bake";
352
353 /* api callbacks */
359
360 /* flags */
362
363 RNA_def_boolean(ot->srna, "bake", false, "Bake", "");
364}
366{
367 /* identifiers */
368 ot->name = "Delete Physics Bake";
369 ot->description = "Delete physics bake";
370 ot->idname = "PTCACHE_OT_free_bake";
371
372 /* api callbacks */
375
376 /* flags */
378}
380{
381 /* identifiers */
382 ot->name = "Bake from Cache";
383 ot->description = "Bake from cache";
384 ot->idname = "PTCACHE_OT_bake_from_cache";
385
386 /* api callbacks */
389
390 /* flags */
392}
393
395{
396 Scene *scene = CTX_data_scene(C);
397 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
398 Object *ob = (Object *)ptr.owner_id;
399 PointCache *cache = static_cast<PointCache *>(ptr.data);
400 PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
401
402 if (pid.cache) {
403 PointCache *cache_new = BKE_ptcache_add(pid.ptcaches);
404 cache_new->step = pid.default_step;
405 *(pid.cache_ptr) = cache_new;
406
410 }
411
412 return OPERATOR_FINISHED;
413}
415{
416 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
417 Scene *scene = CTX_data_scene(C);
418 Object *ob = (Object *)ptr.owner_id;
419 PointCache *cache = static_cast<PointCache *>(ptr.data);
420 PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
421
422 /* don't delete last cache */
423 if (pid.cache && pid.ptcaches->first != pid.ptcaches->last) {
424 BLI_remlink(pid.ptcaches, pid.cache);
426 *(pid.cache_ptr) = static_cast<PointCache *>(pid.ptcaches->first);
427
430 }
431
432 return OPERATOR_FINISHED;
433}
435{
436 /* identifiers */
437 ot->name = "Add New Cache";
438 ot->description = "Add new cache";
439 ot->idname = "PTCACHE_OT_add";
440
441 /* api callbacks */
444
445 /* flags */
447}
449{
450 /* identifiers */
451 ot->name = "Delete Current Cache";
452 ot->description = "Delete current cache";
453 ot->idname = "PTCACHE_OT_remove";
454
455 /* api callbacks */
458
459 /* flags */
461}
#define FOREACH_SCENE_OBJECT_END
#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis)
void BKE_ptcache_bake(struct PTCacheBaker *baker)
struct PointCache * BKE_ptcache_add(struct ListBase *ptcaches)
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache)
void BKE_ptcache_free(struct PointCache *cache)
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
#define STREQ(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_POINT_CACHE
Definition DNA_ID.h:1072
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_OB
#define MAX_DUPLI_RECUR
@ PTCACHE_BAKED
@ PTCACHE_DISK_CACHE
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void PE_free_ptcache_edit(PTCacheEdit *edit)
Read Guarded memory(de)allocation.
@ WM_JOB_TYPE_POINTCACHE
Definition WM_api.hh:1594
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_SCENE
Definition WM_types.hh:345
#define ND_FRAME
Definition WM_types.hh:401
#define ND_POINTCACHE
Definition WM_types.hh:433
#define NC_OBJECT
Definition WM_types.hh:346
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
static void ptcache_bake_cancel(bContext *C, wmOperator *op)
static int ptcache_bake_from_cache_exec(bContext *C, wmOperator *)
static void ptcache_job_free(void *customdata)
static int ptcache_free_bake_all_exec(bContext *C, wmOperator *)
static void ptcache_free_bake(PointCache *cache)
static bool ptcache_add_remove_poll(bContext *C)
static int ptcache_job_break(void *customdata)
static int ptcache_free_bake_exec(bContext *C, wmOperator *)
static bool ptcache_bake_all_poll(bContext *C)
static int ptcache_bake_exec(bContext *C, wmOperator *op)
void PTCACHE_OT_bake(wmOperatorType *ot)
void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
static PTCacheBaker * ptcache_baker_create(bContext *C, wmOperator *op, bool all)
static bool ptcache_poll(bContext *C)
static int ptcache_add_new_exec(bContext *C, wmOperator *)
void PTCACHE_OT_add(wmOperatorType *ot)
static void ptcache_job_endjob(void *customdata)
static int ptcache_remove_exec(bContext *C, wmOperator *)
void PTCACHE_OT_remove(wmOperatorType *ot)
void PTCACHE_OT_bake_from_cache(wmOperatorType *ot)
void PTCACHE_OT_bake_all(wmOperatorType *ot)
void PTCACHE_OT_free_bake(wmOperatorType *ot)
static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *)
static void ptcache_job_update(void *customdata, float progress, int *cancel)
static void ptcache_job_startjob(void *customdata, wmJobWorkerStatus *worker_status)
static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
Definition DNA_ID.h:413
void * last
void * first
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
struct PointCache ** cache_ptr
struct ID * owner_id
struct ListBase * ptcaches
unsigned int default_step
struct PointCache * cache
PTCacheBaker * baker
wmWindowManager * wm
struct PTCacheEdit * edit
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:597
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:189
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:364
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336