Blender V5.0
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
8
9#include <cstdlib>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_listbase.h"
15#include "BLI_utildefines.h"
16
17#include "BKE_context.hh"
18#include "BKE_duplilist.hh"
19#include "BKE_global.hh"
20#include "BKE_layer.hh"
21#include "BKE_library.hh"
22#include "BKE_pointcache.h"
23
24#include "DEG_depsgraph.hh"
25
26#include "ED_particle.hh"
27
28#include "WM_api.hh"
29#include "WM_types.hh"
30
31#include "RNA_access.hh"
32#include "RNA_define.hh"
33#include "RNA_prototypes.hh"
34
35#include "physics_intern.hh"
36
38{
39 return CTX_data_scene(C) != nullptr;
40}
41
42static bool ptcache_poll(bContext *C)
43{
44 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
45
46 ID *id = ptr.owner_id;
47 PointCache *point_cache = static_cast<PointCache *>(ptr.data);
48
49 if (id == nullptr || point_cache == nullptr) {
50 return false;
51 }
52
53 if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
55 "Library override data-blocks only support Disk Cache storage");
56 return false;
57 }
58
59 if (!ID_IS_EDITABLE(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
60 CTX_wm_operator_poll_msg_set(C, "Linked data-blocks do not allow editing caches");
61 return false;
62 }
63
64 return true;
65}
66
68{
69 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
70
71 ID *id = ptr.owner_id;
72 PointCache *point_cache = static_cast<PointCache *>(ptr.data);
73
74 if (id == nullptr || point_cache == nullptr) {
75 return false;
76 }
77
80 C, "Linked or library override data-blocks do not allow adding or removing caches");
81 return false;
82 }
83
84 return true;
85}
86
95
96static void ptcache_job_free(void *customdata)
97{
98 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
99 MEM_freeN(job->baker);
100 MEM_freeN(job);
101}
102
103static int ptcache_job_break(void *customdata)
104{
105 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
106
107 if (G.is_break) {
108 return 1;
109 }
110
111 if (job->stop && *(job->stop)) {
112 return 1;
113 }
114
115 return 0;
116}
117
118static void ptcache_job_update(void *customdata, float progress, int *cancel)
119{
120 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
121
122 if (ptcache_job_break(job)) {
123 *cancel = 1;
124 }
125
126 *(job->do_update) = true;
127 *(job->progress) = progress;
128}
129
130static void ptcache_job_startjob(void *customdata, wmJobWorkerStatus *worker_status)
131{
132 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
133
134 job->stop = &worker_status->stop;
135 job->do_update = &worker_status->do_update;
136 job->progress = &worker_status->progress;
137
138 G.is_break = false;
139
140 /* XXX annoying hack: needed to prevent data corruption when changing
141 * scene frame in separate threads
142 */
143 WM_locked_interface_set(job->wm, true);
144
146
147 worker_status->do_update = true;
148 worker_status->stop = false;
149}
150
151static void ptcache_job_endjob(void *customdata)
152{
153 PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
154 Scene *scene = job->baker->scene;
155
156 WM_locked_interface_set(job->wm, false);
157
160}
161
162static void ptcache_free_bake(PointCache *cache)
163{
164 if (cache->edit) {
165 if (!cache->edit->edited || true) { // XXX okee("Lose changes done in particle mode?")) {
167 cache->edit = nullptr;
168 cache->flag &= ~PTCACHE_BAKED;
169 }
170 }
171 else {
172 cache->flag &= ~PTCACHE_BAKED;
173 }
174}
175
177{
178 PTCacheBaker *baker = MEM_callocN<PTCacheBaker>("PTCacheBaker");
179
180 baker->bmain = CTX_data_main(C);
181 baker->scene = CTX_data_scene(C);
183 /* Depsgraph is used to sweep the frame range and evaluate scene at different times. */
185 baker->bake = RNA_boolean_get(op->ptr, "bake");
186 baker->render = false;
187 baker->anim_init = false;
188 baker->quick_step = 1;
189
190 if (!all) {
191 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
192 ID *id = ptr.owner_id;
193 Object *ob = (GS(id->name) == ID_OB) ? (Object *)id : nullptr;
194 PointCache *cache = static_cast<PointCache *>(ptr.data);
195 baker->pid = BKE_ptcache_id_find(ob, baker->scene, cache);
196 }
197
198 return baker;
199}
200
202{
203 bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
204
205 PTCacheBaker *baker = ptcache_baker_create(C, op, all);
206 BKE_ptcache_bake(baker);
207 MEM_freeN(baker);
208
209 return OPERATOR_FINISHED;
210}
211
213{
214 bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
215
216 PointCacheJob *job = MEM_mallocN<PointCacheJob>("PointCacheJob");
217 job->wm = CTX_wm_manager(C);
218 job->baker = ptcache_baker_create(C, op, all);
219 job->baker->bake_job = job;
221
225 "Baking point cache...",
228
232
234
236
238
239 /* we must run modal until the bake job is done, otherwise the undo push
240 * happens before the job ends, which can lead to race conditions between
241 * the baking and file writing code */
243}
244
246{
247 Scene *scene = (Scene *)op->customdata;
248
249 /* no running blender, remove handler and pass through */
252 }
253
255}
256
258{
260 Scene *scene = (Scene *)op->customdata;
261
262 /* kill on cancel, because job is using op->reports */
264}
265
267{
268 Scene *scene = CTX_data_scene(C);
269 ListBase pidlist;
270
271 FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
272 BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
273
274 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
275 ptcache_free_bake(pid->cache);
276 }
277
278 BLI_freelistN(&pidlist);
279
281 }
283
285
286 return OPERATOR_FINISHED;
287}
288
290{
291 /* identifiers */
292 ot->name = "Bake All Physics";
293 ot->description = "Bake all physics";
294 ot->idname = "PTCACHE_OT_bake_all";
295
296 /* API callbacks. */
297 ot->exec = ptcache_bake_exec;
298 ot->invoke = ptcache_bake_invoke;
299 ot->modal = ptcache_bake_modal;
300 ot->cancel = ptcache_bake_cancel;
302
303 /* flags */
305
306 RNA_def_boolean(ot->srna, "bake", true, "Bake", "");
307}
309{
310 /* identifiers */
311 ot->name = "Delete All Physics Bakes";
312 ot->idname = "PTCACHE_OT_free_bake_all";
313 ot->description = "Delete all baked caches of all objects in the current scene";
314
315 /* API callbacks. */
318
319 /* flags */
321}
322
324{
325 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
326 PointCache *cache = static_cast<PointCache *>(ptr.data);
327 Object *ob = (Object *)ptr.owner_id;
328
329 ptcache_free_bake(cache);
330
332
333 return OPERATOR_FINISHED;
334}
336{
337 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
338 PointCache *cache = static_cast<PointCache *>(ptr.data);
339 Object *ob = (Object *)ptr.owner_id;
340
341 cache->flag |= PTCACHE_BAKED;
342
344
345 return OPERATOR_FINISHED;
346}
348{
349 /* identifiers */
350 ot->name = "Bake Physics";
351 ot->description = "Bake physics";
352 ot->idname = "PTCACHE_OT_bake";
353
354 /* API callbacks. */
355 ot->exec = ptcache_bake_exec;
356 ot->invoke = ptcache_bake_invoke;
357 ot->modal = ptcache_bake_modal;
358 ot->cancel = ptcache_bake_cancel;
359 ot->poll = ptcache_poll;
360
361 /* flags */
363
364 RNA_def_boolean(ot->srna, "bake", false, "Bake", "");
365}
367{
368 /* identifiers */
369 ot->name = "Delete Physics Bake";
370 ot->description = "Delete physics bake";
371 ot->idname = "PTCACHE_OT_free_bake";
372
373 /* API callbacks. */
375 ot->poll = ptcache_poll;
376
377 /* flags */
379}
381{
382 /* identifiers */
383 ot->name = "Bake from Cache";
384 ot->description = "Bake from cache";
385 ot->idname = "PTCACHE_OT_bake_from_cache";
386
387 /* API callbacks. */
389 ot->poll = ptcache_poll;
390
391 /* flags */
393}
394
396{
397 Scene *scene = CTX_data_scene(C);
398 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
399 Object *ob = (Object *)ptr.owner_id;
400 PointCache *cache = static_cast<PointCache *>(ptr.data);
401 PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
402
403 if (pid.cache) {
404 PointCache *cache_new = BKE_ptcache_add(pid.ptcaches);
405 cache_new->step = pid.default_step;
406 *(pid.cache_ptr) = cache_new;
407
411 }
412
413 return OPERATOR_FINISHED;
414}
416{
417 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
418 Scene *scene = CTX_data_scene(C);
419 Object *ob = (Object *)ptr.owner_id;
420 PointCache *cache = static_cast<PointCache *>(ptr.data);
421 PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
422
423 /* don't delete last cache */
424 if (pid.cache && pid.ptcaches->first != pid.ptcaches->last) {
425 BLI_remlink(pid.ptcaches, pid.cache);
427 *(pid.cache_ptr) = static_cast<PointCache *>(pid.ptcaches->first);
428
431 }
432
433 return OPERATOR_FINISHED;
434}
436{
437 /* identifiers */
438 ot->name = "Add New Cache";
439 ot->description = "Add new cache";
440 ot->idname = "PTCACHE_OT_add";
441
442 /* API callbacks. */
443 ot->exec = ptcache_add_new_exec;
445
446 /* flags */
448}
450{
451 /* identifiers */
452 ot->name = "Delete Current Cache";
453 ot->description = "Delete current cache";
454 ot->idname = "PTCACHE_OT_remove";
455
456 /* API callbacks. */
457 ot->exec = ptcache_remove_exec;
459
460 /* flags */
462}
#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)
constexpr int MAX_DUPLI_RECUR
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(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
#define STREQ(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_POINT_CACHE
Definition DNA_ID.h:1105
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:723
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ ID_OB
@ PTCACHE_BAKED
@ PTCACHE_DISK_CACHE
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void PE_free_ptcache_edit(PTCacheEdit *edit)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ WM_JOB_TYPE_POINTCACHE
Definition WM_api.hh:1794
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_FRAME
Definition WM_types.hh:434
#define ND_POINTCACHE
Definition WM_types.hh:466
#define NC_OBJECT
Definition WM_types.hh:379
#define GS(x)
bool all(VecOp< bool, D >) RET
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
static void ptcache_bake_cancel(bContext *C, wmOperator *op)
static void ptcache_job_free(void *customdata)
static wmOperatorStatus ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void ptcache_free_bake(PointCache *cache)
static bool ptcache_add_remove_poll(bContext *C)
static wmOperatorStatus ptcache_bake_from_cache_exec(bContext *C, wmOperator *)
static int ptcache_job_break(void *customdata)
static wmOperatorStatus ptcache_add_new_exec(bContext *C, wmOperator *)
static bool ptcache_bake_all_poll(bContext *C)
static wmOperatorStatus ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *)
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 wmOperatorStatus ptcache_free_bake_exec(bContext *C, wmOperator *)
void PTCACHE_OT_add(wmOperatorType *ot)
static wmOperatorStatus ptcache_free_bake_all_exec(bContext *C, wmOperator *)
static wmOperatorStatus ptcache_bake_exec(bContext *C, wmOperator *op)
static void ptcache_job_endjob(void *customdata)
static wmOperatorStatus 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 void ptcache_job_update(void *customdata, float progress, int *cancel)
static void ptcache_job_startjob(void *customdata, wmJobWorkerStatus *worker_status)
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:414
char name[258]
Definition DNA_ID.h:432
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
const char * idname
Definition WM_types.hh:1035
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_locked_interface_set(wmWindowManager *wm, bool lock)
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)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:623
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:211
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:388
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:247
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360