Blender  V3.3
physics_pointcache.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2007 by Janne Karhu. All rights reserved. */
3 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "BLI_blenlib.h"
14 #include "BLI_utildefines.h"
15 
16 #include "DNA_scene_types.h"
17 
18 #include "BKE_context.h"
19 #include "BKE_global.h"
20 #include "BKE_layer.h"
21 #include "BKE_pointcache.h"
22 
23 #include "DEG_depsgraph.h"
24 
25 #include "ED_particle.h"
26 
27 #include "WM_api.h"
28 #include "WM_types.h"
29 
30 #include "RNA_access.h"
31 #include "RNA_define.h"
32 #include "RNA_prototypes.h"
33 
34 #include "physics_intern.h"
35 
37 {
38  return CTX_data_scene(C) != NULL;
39 }
40 
41 static bool ptcache_poll(bContext *C)
42 {
43  PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
44 
45  ID *id = ptr.owner_id;
46  PointCache *point_cache = ptr.data;
47 
48  if (id == NULL || point_cache == NULL) {
49  return false;
50  }
51 
52  if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
54  "Library override data-blocks only support Disk Cache storage");
55  return false;
56  }
57 
58  if (ID_IS_LINKED(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
59  CTX_wm_operator_poll_msg_set(C, "Linked data-blocks do not allow editing caches");
60  return false;
61  }
62 
63  return true;
64 }
65 
67 {
68  PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
69 
70  ID *id = ptr.owner_id;
71  PointCache *point_cache = ptr.data;
72 
73  if (id == NULL || point_cache == NULL) {
74  return false;
75  }
76 
79  C, "Linked or library override data-blocks do not allow adding or removing caches");
80  return false;
81  }
82 
83  return true;
84 }
85 
86 typedef struct PointCacheJob {
88  void *owner;
89  short *stop, *do_update;
90  float *progress;
91 
94 
95 static void ptcache_job_free(void *customdata)
96 {
97  PointCacheJob *job = customdata;
98  MEM_freeN(job->baker);
99  MEM_freeN(job);
100 }
101 
102 static int ptcache_job_break(void *customdata)
103 {
104  PointCacheJob *job = customdata;
105 
106  if (G.is_break) {
107  return 1;
108  }
109 
110  if (job->stop && *(job->stop)) {
111  return 1;
112  }
113 
114  return 0;
115 }
116 
117 static void ptcache_job_update(void *customdata, float progress, int *cancel)
118 {
119  PointCacheJob *job = customdata;
120 
121  if (ptcache_job_break(job)) {
122  *cancel = 1;
123  }
124 
125  *(job->do_update) = true;
126  *(job->progress) = progress;
127 }
128 
129 static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress)
130 {
131  PointCacheJob *job = customdata;
132 
133  job->stop = stop;
134  job->do_update = do_update;
135  job->progress = progress;
136 
137  G.is_break = false;
138 
139  /* XXX annoying hack: needed to prevent data corruption when changing
140  * scene frame in separate threads
141  */
142  WM_set_locked_interface(job->wm, true);
143 
144  BKE_ptcache_bake(job->baker);
145 
146  *do_update = true;
147  *stop = 0;
148 }
149 
150 static void ptcache_job_endjob(void *customdata)
151 {
152  PointCacheJob *job = customdata;
153  Scene *scene = job->baker->scene;
154 
155  WM_set_locked_interface(job->wm, false);
156 
159 }
160 
161 static void ptcache_free_bake(PointCache *cache)
162 {
163  if (cache->edit) {
164  if (!cache->edit->edited || 1) { // XXX okee("Lose changes done in particle mode?")) {
165  PE_free_ptcache_edit(cache->edit);
166  cache->edit = NULL;
167  cache->flag &= ~PTCACHE_BAKED;
168  }
169  }
170  else {
171  cache->flag &= ~PTCACHE_BAKED;
172  }
173 }
174 
176 {
177  PTCacheBaker *baker = MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker");
178 
179  baker->bmain = CTX_data_main(C);
180  baker->scene = CTX_data_scene(C);
181  baker->view_layer = CTX_data_view_layer(C);
182  /* Depsgraph is used to sweep the frame range and evaluate scene at different times. */
184  baker->bake = RNA_boolean_get(op->ptr, "bake");
185  baker->render = 0;
186  baker->anim_init = 0;
187  baker->quick_step = 1;
188 
189  if (!all) {
190  PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
191  Object *ob = (Object *)ptr.owner_id;
192  PointCache *cache = 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 
210 static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
211 {
212  bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
213 
214  PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
215  job->wm = CTX_wm_manager(C);
216  job->baker = ptcache_baker_create(C, op, all);
217  job->baker->bake_job = job;
219 
220  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
221  CTX_wm_window(C),
222  CTX_data_scene(C),
223  "Point Cache",
226 
230 
232 
233  WM_jobs_start(CTX_wm_manager(C), wm_job);
234 
236 
237  /* we must run modal until the bake job is done, otherwise the undo push
238  * happens before the job ends, which can lead to race conditions between
239  * the baking and file writing code */
240  return OPERATOR_RUNNING_MODAL;
241 }
242 
243 static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
244 {
245  Scene *scene = (Scene *)op->customdata;
246 
247  /* no running blender, remove handler and pass through */
250  }
251 
252  return OPERATOR_PASS_THROUGH;
253 }
254 
256 {
258  Scene *scene = (Scene *)op->customdata;
259 
260  /* kill on cancel, because job is using op->reports */
262 }
263 
265 {
267  PTCacheID *pid;
268  ListBase pidlist;
269 
272 
273  for (pid = pidlist.first; pid; pid = pid->next) {
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", 1, "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 = 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 = 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 */
358  ot->poll = ptcache_poll;
359 
360  /* flags */
362 
363  RNA_def_boolean(ot->srna, "bake", 0, "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 */
374  ot->poll = ptcache_poll;
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 */
388  ot->poll = ptcache_poll;
389 
390  /* flags */
392 }
393 
395 {
397  PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
398  Object *ob = (Object *)ptr.owner_id;
399  PointCache *cache = 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);
418  Object *ob = (Object *)ptr.owner_id;
419  PointCache *cache = 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);
425  BKE_ptcache_free(pid.cache);
426  *(pid.cache_ptr) = 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)
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
Definition: context.c:473
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis)
Definition: pointcache.c:1250
void BKE_ptcache_bake(struct PTCacheBaker *baker)
Definition: pointcache.c:3156
struct PointCache * BKE_ptcache_add(struct ListBase *ptcaches)
Definition: pointcache.c:3014
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache)
Definition: pointcache.c:1092
void BKE_ptcache_free(struct PointCache *cache)
Definition: pointcache.c:3041
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
#define UNUSED(x)
#define STREQ(a, b)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_POINT_CACHE
Definition: DNA_ID.h:822
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition: DNA_ID.h:581
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define MAX_DUPLI_RECUR
@ PTCACHE_BAKED
@ PTCACHE_DISK_CACHE
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void PE_free_ptcache_edit(struct PTCacheEdit *edit)
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_TYPE_POINTCACHE
Definition: WM_api.h:1364
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_SCENE
Definition: WM_types.h:328
#define ND_FRAME
Definition: WM_types.h:382
#define ND_POINTCACHE
Definition: WM_types.h:415
#define NC_OBJECT
Definition: WM_types.h:329
__forceinline bool all(const avxb &b)
Definition: avxb.h:201
Scene scene
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
static void ptcache_bake_cancel(bContext *C, wmOperator *op)
struct PointCacheJob PointCacheJob
static void ptcache_job_free(void *customdata)
static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op))
static int ptcache_add_new_exec(bContext *C, wmOperator *UNUSED(op))
static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static void ptcache_free_bake(PointCache *cache)
static bool ptcache_add_remove_poll(bContext *C)
static int ptcache_job_break(void *customdata)
static bool ptcache_bake_all_poll(bContext *C)
static int ptcache_bake_exec(bContext *C, wmOperator *op)
static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
void PTCACHE_OT_bake(wmOperatorType *ot)
void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
static int ptcache_remove_exec(bContext *C, wmOperator *UNUSED(op))
static bool ptcache_poll(bContext *C)
void PTCACHE_OT_add(wmOperatorType *ot)
static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
static PTCacheBaker * ptcache_baker_create(bContext *C, wmOperator *op, bool all)
static void ptcache_job_endjob(void *customdata)
static int ptcache_bake_from_cache_exec(bContext *C, wmOperator *UNUSED(op))
void PTCACHE_OT_remove(wmOperatorType *ot)
void PTCACHE_OT_bake_from_cache(wmOperatorType *ot)
void PTCACHE_OT_bake_all(wmOperatorType *ot)
static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress)
void PTCACHE_OT_free_bake(wmOperatorType *ot)
static void ptcache_job_update(void *customdata, float progress, int *cancel)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
Definition: DNA_ID.h:368
void * first
Definition: DNA_listBase.h:31
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 ID * owner_id
struct PTCacheID * next
struct PointCache * cache
PTCacheBaker * baker
wmWindowManager * wm
struct PTCacheEdit * edit
void * data
Definition: RNA_types.h:38
struct ID * owner_id
Definition: RNA_types.h:36
Definition: wm_jobs.c:57
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct wmOperatorType * type
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
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.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:437
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:572
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184