Blender V4.3
dynamicpaint_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstdio>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_blenlib.h"
16#include "BLI_string.h"
17#include "BLI_time.h"
18#include "BLI_utildefines.h"
19
20#include "BLT_translation.hh"
21
23#include "DNA_modifier_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26
27#include "BKE_attribute.hh"
28#include "BKE_context.hh"
29#include "BKE_deform.hh"
30#include "BKE_dynamicpaint.h"
31#include "BKE_global.hh"
32#include "BKE_main.hh"
33#include "BKE_modifier.hh"
34#include "BKE_object_deform.h"
35#include "BKE_report.hh"
36#include "BKE_screen.hh"
37
38#include "DEG_depsgraph.hh"
41
42#include "ED_mesh.hh"
43#include "ED_object.hh"
44#include "ED_screen.hh"
45
46#include "RNA_access.hh"
47#include "RNA_define.hh"
48#include "RNA_enum_types.hh"
49
50#include "WM_api.hh"
51#include "WM_types.hh"
52
53#include "physics_intern.hh" /* own include */
54
56{
57 DynamicPaintModifierData *pmd = nullptr;
60 DynamicPaintSurface *surface;
61
62 /* Make sure we're dealing with a canvas */
64 if (!pmd || !pmd->canvas) {
65 return OPERATOR_CANCELLED;
66 }
67
68 canvas = pmd->canvas;
70
71 if (!surface) {
72 return OPERATOR_CANCELLED;
73 }
74
75 canvas->active_sur = 0;
76 for (surface = surface->prev; surface; surface = surface->prev) {
77 canvas->active_sur++;
78 }
79
80 return OPERATOR_FINISHED;
81}
82
84{
85 /* identifiers */
86 ot->name = "Add Surface Slot";
87 ot->idname = "DPAINT_OT_surface_slot_add";
88 ot->description = "Add a new Dynamic Paint surface slot";
89
90 /* api callbacks */
93
94 /* flags */
96}
97
99{
100 DynamicPaintModifierData *pmd = nullptr;
103 DynamicPaintSurface *surface;
104 int id = 0;
105
106 /* Make sure we're dealing with a canvas */
108 if (!pmd || !pmd->canvas) {
109 return OPERATOR_CANCELLED;
110 }
111
112 canvas = pmd->canvas;
113 surface = static_cast<DynamicPaintSurface *>(canvas->surfaces.first);
114
115 /* find active surface and remove it */
116 for (; surface; surface = surface->next) {
117 if (id == canvas->active_sur) {
118 canvas->active_sur -= 1;
119 dynamicPaint_freeSurface(pmd, surface);
120 break;
121 }
122 id++;
123 }
124
127
128 return OPERATOR_FINISHED;
129}
130
132{
133 /* identifiers */
134 ot->name = "Remove Surface Slot";
135 ot->idname = "DPAINT_OT_surface_slot_remove";
136 ot->description = "Remove the selected surface slot";
137
138 /* api callbacks */
141
142 /* flags */
144}
145
147{
148
150 Scene *scene = CTX_data_scene(C);
153 int type = RNA_enum_get(op->ptr, "type");
154
155 if (!pmd) {
156 return OPERATOR_CANCELLED;
157 }
158
159 /* if type is already enabled, toggle it off */
160 if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) {
162 }
163 else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) {
165 }
166 /* else create a new type */
167 else {
168 if (!dynamicPaint_createType(pmd, type, scene)) {
169 return OPERATOR_CANCELLED;
170 }
171 }
172
173 /* update dependency */
177
178 return OPERATOR_FINISHED;
179}
180
182{
183 PropertyRNA *prop;
184
185 /* identifiers */
186 ot->name = "Toggle Type Active";
187 ot->idname = "DPAINT_OT_type_toggle";
188 ot->description = "Toggle whether given type is active or not";
189
190 /* api callbacks */
193
194 /* flags */
196
197 /* properties */
198 prop = RNA_def_enum(ot->srna,
199 "type",
202 "Type",
203 "");
205 ot->prop = prop;
206}
207
209{
211 DynamicPaintSurface *surface;
214 int output = RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
215
216 if (!pmd || !pmd->canvas) {
217 return OPERATOR_CANCELLED;
218 }
219 surface = get_activeSurface(pmd->canvas);
220
221 /* if type is already enabled, toggle it off */
222 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
223 bool exists = dynamicPaint_outputLayerExists(surface, ob, output);
224 const char *name;
225
226 if (output == 0) {
227 name = surface->output_name;
228 }
229 else {
230 name = surface->output_name2;
231 }
232
233 /* Vertex Color Layer */
234 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
235 if (!exists) {
236 ED_mesh_color_add(static_cast<Mesh *>(ob->data), name, true, true, op->reports);
237 }
238 else {
239 AttributeOwner owner = AttributeOwner::from_id(static_cast<ID *>(ob->data));
240 BKE_attribute_remove(owner, name, nullptr);
241 }
242 }
243 /* Vertex Weight Layer */
244 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
245 if (!exists) {
248 }
249 else {
250 bDeformGroup *defgroup = BKE_object_defgroup_find_name(ob, name);
251 if (defgroup) {
252 BKE_object_defgroup_remove(ob, defgroup);
254 }
255 }
256 }
257 }
258
259 return OPERATOR_FINISHED;
260}
261
263{
264 static const EnumPropertyItem prop_output_toggle_types[] = {
265 {0, "A", 0, "Output A", ""},
266 {1, "B", 0, "Output B", ""},
267 {0, nullptr, 0, nullptr, nullptr},
268 };
269
270 /* identifiers */
271 ot->name = "Toggle Output Layer";
272 ot->idname = "DPAINT_OT_output_toggle";
273 ot->description = "Add or remove Dynamic Paint output data layer";
274
275 /* api callbacks */
278
279 /* flags */
281
282 /* properties */
283 ot->prop = RNA_def_enum(ot->srna, "output", prop_output_toggle_types, 0, "Output Toggle", "");
284}
285
286/***************************** Image Sequence Baking ******************************/
287
305
306static void dpaint_bake_free(void *customdata)
307{
308 DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(customdata);
309 MEM_freeN(job);
310}
311
312static void dpaint_bake_endjob(void *customdata)
313{
314 DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(customdata);
315 DynamicPaintCanvasSettings *canvas = job->canvas;
316
317 canvas->flags &= ~MOD_DPAINT_BAKING;
318
320
321 G.is_rendering = false;
323
324 WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
325
326 /* Bake was successful:
327 * Report for ended bake and how long it took */
328 if (job->success) {
329 /* Show bake info */
331 RPT_INFO, "DynamicPaint: Bake complete! (%.2f)", BLI_time_now_seconds() - job->start);
332 }
333 else {
334 if (strlen(canvas->error)) { /* If an error occurred */
335 WM_reportf(RPT_ERROR, "DynamicPaint: Bake failed: %s", canvas->error);
336 }
337 else { /* User canceled the bake */
338 WM_report(RPT_WARNING, "Baking canceled!");
339 }
340 }
341}
342
343/*
344 * Do actual bake operation. Loop through to-be-baked frames.
345 * Returns 0 on failure.
346 */
348{
349 DynamicPaintSurface *surface = job->surface;
350 Object *cObject = job->ob;
351 DynamicPaintCanvasSettings *canvas = surface->canvas;
352 Scene *input_scene = DEG_get_input_scene(job->depsgraph);
353 Scene *scene = job->scene;
354 int frame = 1, orig_frame;
355 int frames;
356
357 frames = surface->end_frame - surface->start_frame + 1;
358 if (frames <= 0) {
359 STRNCPY(canvas->error, N_("No frames to bake"));
360 return;
361 }
362
363 /* Show progress bar. */
364 *(job->do_update) = true;
365
366 /* Set frame to start point (also initializes modifier data). */
367 frame = surface->start_frame;
368 orig_frame = input_scene->r.cfra;
369 input_scene->r.cfra = int(frame);
371
372 /* Init surface */
373 if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) {
374 job->success = 0;
375 return;
376 }
377
378 /* Loop through selected frames */
379 for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
380 /* The first 10% are for createUVSurface... */
381 const float progress = 0.1f + 0.9f * (frame - surface->start_frame) / float(frames);
382 surface->current_frame = frame;
383
384 /* If user requested stop, quit baking */
385 if (G.is_break) {
386 job->success = 0;
387 return;
388 }
389
390 /* Update progress bar */
391 *(job->do_update) = true;
392 *(job->progress) = progress;
393
394 /* calculate a frame */
395 input_scene->r.cfra = int(frame);
397 if (!dynamicPaint_calculateFrame(surface, job->depsgraph, scene, cObject, frame)) {
398 job->success = 0;
399 return;
400 }
401
402 /*
403 * Save output images
404 */
405 {
406 char filepath[FILE_MAX];
407
408 /* primary output layer */
409 if (surface->flags & MOD_DPAINT_OUT1) {
410 /* set filepath */
412 filepath, sizeof(filepath), surface->image_output_path, surface->output_name);
413 BLI_path_frame(filepath, sizeof(filepath), frame, 4);
414
415 /* save image */
416 dynamicPaint_outputSurfaceImage(surface, filepath, 0);
417 }
418 /* secondary output */
419 if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
420 /* set filepath */
422 filepath, sizeof(filepath), surface->image_output_path, surface->output_name2);
423 BLI_path_frame(filepath, sizeof(filepath), frame, 4);
424
425 /* save image */
426 dynamicPaint_outputSurfaceImage(surface, filepath, 1);
427 }
428 }
429 }
430
431 input_scene->r.cfra = orig_frame;
433}
434
435static void dpaint_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
436{
437 DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(customdata);
438
439 job->stop = &worker_status->stop;
440 job->do_update = &worker_status->do_update;
441 job->progress = &worker_status->progress;
443 job->success = 1;
444
445 G.is_break = false;
446
447 /* XXX annoying hack: needed to prevent data corruption when changing
448 * scene frame in separate threads
449 */
450 G.is_rendering = true;
452
454
455 worker_status->do_update = true;
456 worker_status->stop = false;
457}
458
459/*
460 * Bake Dynamic Paint image sequence surface
461 */
463{
466 Object *object_eval = DEG_get_evaluated_object(depsgraph, ob_);
468
469 DynamicPaintSurface *surface;
470
471 /*
472 * Get modifier data
473 */
475 object_eval, eModifierType_DynamicPaint);
476 if (pmd == nullptr) {
477 BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
478 return OPERATOR_CANCELLED;
479 }
480
481 /* Make sure we're dealing with a canvas */
482 DynamicPaintCanvasSettings *canvas = pmd->canvas;
483 if (canvas == nullptr) {
484 BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
485 return OPERATOR_CANCELLED;
486 }
487 surface = get_activeSurface(canvas);
488
489 /* Set state to baking and init surface */
490 canvas->error[0] = '\0';
491 canvas->flags |= MOD_DPAINT_BAKING;
492
493 DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(
494 MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob"));
495 job->bmain = CTX_data_main(C);
496 job->scene = scene_eval;
497 job->depsgraph = depsgraph;
498 job->ob = object_eval;
499 job->canvas = canvas;
500 job->surface = surface;
501
502 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
503 CTX_wm_window(C),
505 "Dynamic Paint Bake",
508
512
514
515 /* Bake Dynamic Paint */
516 WM_jobs_start(CTX_wm_manager(C), wm_job);
517
518 return OPERATOR_FINISHED;
519}
520
522{
523 /* identifiers */
524 ot->name = "Dynamic Paint Bake";
525 ot->description = "Bake dynamic paint image sequence surface";
526 ot->idname = "DPAINT_OT_bake";
527
528 /* api callbacks */
531}
bool BKE_attribute_remove(AttributeOwner &owner, const char *name, struct ReportList *reports)
Definition attribute.cc:501
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
support for deformation groups and hooks.
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:520
struct DynamicPaintSurface * get_activeSurface(struct DynamicPaintCanvasSettings *canvas)
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, struct Object *ob, int output)
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, const char *filepath, short output_layer)
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd)
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, bool *do_update)
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
struct DynamicPaintSurface * dynamicPaint_createNewSurface(struct DynamicPaintCanvasSettings *canvas, struct Scene *scene)
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *cObject, int frame)
void dynamicPaint_freeSurfaceData(struct DynamicPaintSurface *surface)
void dynamicPaint_freeSurface(const struct DynamicPaintModifierData *pmd, struct DynamicPaintSurface *surface)
#define G_MAIN
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
Functions for dealing with objects and deform verts, used by painting and tools.
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup)
struct bDeformGroup * BKE_object_defgroup_add_name(struct Object *ob, const char *name)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_spacedata_draw_locks(bool set)
Definition screen.cc:405
#define FILE_MAX
#define BLI_path_join(...)
bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) ATTR_NONNULL(1)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define BLT_I18NCONTEXT_ID_SIMULATION
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
Scene * DEG_get_input_scene(const Depsgraph *graph)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ MOD_DPAINT_OUT2
@ MOD_DPAINT_OUT1
@ MOD_DPAINT_SURFACE_T_WEIGHT
@ MOD_DPAINT_SURFACE_T_PAINT
@ MOD_DPAINT_BAKING
@ MOD_DPAINT_SURFACE_F_VERTEX
@ MOD_DYNAMICPAINT_TYPE_BRUSH
@ MOD_DYNAMICPAINT_TYPE_CANVAS
@ eModifierType_DynamicPaint
Object is a sort of wrapper for general info.
int ED_mesh_color_add(Mesh *mesh, const char *name, bool active_set, bool do_init, ReportList *reports)
Definition mesh_data.cc:381
bool ED_operator_object_active_local_editable(bContext *C)
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
Read Guarded memory(de)allocation.
@ WM_JOB_TYPE_DPAINT_BAKE
Definition WM_api.hh:1595
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_MODIFIER
Definition WM_types.hh:429
#define NC_OBJECT
Definition WM_types.hh:346
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
const Depsgraph * depsgraph
static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
static int type_toggle_exec(bContext *C, wmOperator *op)
void DPAINT_OT_type_toggle(wmOperatorType *ot)
void DPAINT_OT_output_toggle(wmOperatorType *ot)
static void dpaint_bake_endjob(void *customdata)
static int output_toggle_exec(bContext *C, wmOperator *op)
static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
static void dpaint_bake_free(void *customdata)
static void dpaint_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
static int surface_slot_remove_exec(bContext *C, wmOperator *)
void DPAINT_OT_bake(wmOperatorType *ot)
static int surface_slot_add_exec(bContext *C, wmOperator *)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define G(x, y, z)
Object * context_object(const bContext *C)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
const EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[]
DynamicPaintCanvasSettings * canvas
DynamicPaintSurface * surface
struct DynamicPaintCanvasSettings * canvas
struct DynamicPaintBrushSettings * brush
Definition DNA_ID.h:413
void * first
struct RenderData r
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(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
#define N_(msgid)
void WM_report(eReportType type, const char *message)
void WM_reportf(eReportType type, const char *format,...)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
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
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
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336