Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / physics / dynamicpaint_ops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup edphys
19  */
20
21 #include <math.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_blenlib.h"
28 #include "BLI_string.h"
29 #include "BLI_utildefines.h"
30
31 #include "BLT_translation.h"
32
33 #include "DNA_dynamicpaint_types.h"
34 #include "DNA_modifier_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "BKE_context.h"
39 #include "BKE_deform.h"
40 #include "BKE_object_deform.h"
41 #include "BKE_dynamicpaint.h"
42 #include "BKE_global.h"
43 #include "BKE_main.h"
44 #include "BKE_modifier.h"
45 #include "BKE_report.h"
46 #include "BKE_screen.h"
47
48 #include "DEG_depsgraph.h"
49 #include "DEG_depsgraph_build.h"
50
51 #include "ED_mesh.h"
52 #include "ED_screen.h"
53 #include "ED_object.h"
54
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57 #include "RNA_enum_types.h"
58
59 #include "PIL_time.h"
60
61 #include "WM_types.h"
62 #include "WM_api.h"
63
64 #include "physics_intern.h" /* own include */
65
66 static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
67 {
68   DynamicPaintModifierData *pmd = NULL;
69   Object *cObject = ED_object_context(C);
70   DynamicPaintCanvasSettings *canvas;
71   DynamicPaintSurface *surface;
72
73   /* Make sure we're dealing with a canvas */
74   pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
75   if (!pmd || !pmd->canvas) {
76     return OPERATOR_CANCELLED;
77   }
78
79   canvas = pmd->canvas;
80   surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C));
81
82   if (!surface) {
83     return OPERATOR_CANCELLED;
84   }
85
86   /* set preview for this surface only and set active */
87   canvas->active_sur = 0;
88   for (surface = surface->prev; surface; surface = surface->prev) {
89     surface->flags &= ~MOD_DPAINT_PREVIEW;
90     canvas->active_sur++;
91   }
92
93   return OPERATOR_FINISHED;
94 }
95
96 /* add surface slot */
97 void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
98 {
99   /* identifiers */
100   ot->name = "Add Surface Slot";
101   ot->idname = "DPAINT_OT_surface_slot_add";
102   ot->description = "Add a new Dynamic Paint surface slot";
103
104   /* api callbacks */
105   ot->exec = surface_slot_add_exec;
106   ot->poll = ED_operator_object_active_editable;
107
108   /* flags */
109   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
110 }
111
112 static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
113 {
114   DynamicPaintModifierData *pmd = NULL;
115   Object *obj_ctx = ED_object_context(C);
116   DynamicPaintCanvasSettings *canvas;
117   DynamicPaintSurface *surface;
118   int id = 0;
119
120   /* Make sure we're dealing with a canvas */
121   pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint);
122   if (!pmd || !pmd->canvas) {
123     return OPERATOR_CANCELLED;
124   }
125
126   canvas = pmd->canvas;
127   surface = canvas->surfaces.first;
128
129   /* find active surface and remove it */
130   for (; surface; surface = surface->next) {
131     if (id == canvas->active_sur) {
132       canvas->active_sur -= 1;
133       dynamicPaint_freeSurface(pmd, surface);
134       break;
135     }
136     id++;
137   }
138
139   dynamicPaint_resetPreview(canvas);
140   DEG_id_tag_update(&obj_ctx->id, ID_RECALC_GEOMETRY);
141   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obj_ctx);
142
143   return OPERATOR_FINISHED;
144 }
145
146 /* remove surface slot */
147 void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
148 {
149   /* identifiers */
150   ot->name = "Remove Surface Slot";
151   ot->idname = "DPAINT_OT_surface_slot_remove";
152   ot->description = "Remove the selected surface slot";
153
154   /* api callbacks */
155   ot->exec = surface_slot_remove_exec;
156   ot->poll = ED_operator_object_active_editable;
157
158   /* flags */
159   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
160 }
161
162 static int type_toggle_exec(bContext *C, wmOperator *op)
163 {
164
165   Object *cObject = ED_object_context(C);
166   Scene *scene = CTX_data_scene(C);
167   DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
168       cObject, eModifierType_DynamicPaint);
169   int type = RNA_enum_get(op->ptr, "type");
170
171   if (!pmd) {
172     return OPERATOR_CANCELLED;
173   }
174
175   /* if type is already enabled, toggle it off */
176   if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) {
177     dynamicPaint_freeCanvas(pmd);
178   }
179   else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) {
180     dynamicPaint_freeBrush(pmd);
181   }
182   /* else create a new type */
183   else {
184     if (!dynamicPaint_createType(pmd, type, scene)) {
185       return OPERATOR_CANCELLED;
186     }
187   }
188
189   /* update dependency */
190   DEG_id_tag_update(&cObject->id, ID_RECALC_GEOMETRY);
191   DEG_relations_tag_update(CTX_data_main(C));
192   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, cObject);
193
194   return OPERATOR_FINISHED;
195 }
196
197 void DPAINT_OT_type_toggle(wmOperatorType *ot)
198 {
199   PropertyRNA *prop;
200
201   /* identifiers */
202   ot->name = "Toggle Type Active";
203   ot->idname = "DPAINT_OT_type_toggle";
204   ot->description = "Toggle whether given type is active or not";
205
206   /* api callbacks */
207   ot->exec = type_toggle_exec;
208   ot->poll = ED_operator_object_active_editable;
209
210   /* flags */
211   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
212
213   /* properties */
214   prop = RNA_def_enum(ot->srna,
215                       "type",
216                       rna_enum_prop_dynamicpaint_type_items,
217                       MOD_DYNAMICPAINT_TYPE_CANVAS,
218                       "Type",
219                       "");
220   ot->prop = prop;
221 }
222
223 static int output_toggle_exec(bContext *C, wmOperator *op)
224 {
225   Object *ob = ED_object_context(C);
226   DynamicPaintSurface *surface;
227   DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
228       ob, eModifierType_DynamicPaint);
229   int output = RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
230
231   if (!pmd || !pmd->canvas) {
232     return OPERATOR_CANCELLED;
233   }
234   surface = get_activeSurface(pmd->canvas);
235
236   /* if type is already enabled, toggle it off */
237   if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
238     int exists = dynamicPaint_outputLayerExists(surface, ob, output);
239     const char *name;
240
241     if (output == 0) {
242       name = surface->output_name;
243     }
244     else {
245       name = surface->output_name2;
246     }
247
248     /* Vertex Color Layer */
249     if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
250       if (!exists) {
251         ED_mesh_color_add(ob->data, name, true, true);
252       }
253       else {
254         ED_mesh_color_remove_named(ob->data, name);
255       }
256     }
257     /* Vertex Weight Layer */
258     else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
259       if (!exists) {
260         BKE_object_defgroup_add_name(ob, name);
261       }
262       else {
263         bDeformGroup *defgroup = defgroup_find_name(ob, name);
264         if (defgroup) {
265           BKE_object_defgroup_remove(ob, defgroup);
266         }
267       }
268     }
269   }
270
271   return OPERATOR_FINISHED;
272 }
273
274 void DPAINT_OT_output_toggle(wmOperatorType *ot)
275 {
276   static const EnumPropertyItem prop_output_toggle_types[] = {
277       {0, "A", 0, "Output A", ""},
278       {1, "B", 0, "Output B", ""},
279       {0, NULL, 0, NULL, NULL},
280   };
281
282   /* identifiers */
283   ot->name = "Toggle Output Layer";
284   ot->idname = "DPAINT_OT_output_toggle";
285   ot->description = "Add or remove Dynamic Paint output data layer";
286
287   /* api callbacks */
288   ot->exec = output_toggle_exec;
289   ot->poll = ED_operator_object_active_editable;
290
291   /* flags */
292   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
293
294   /* properties */
295   ot->prop = RNA_def_enum(ot->srna, "output", prop_output_toggle_types, 0, "Output Toggle", "");
296 }
297
298 /***************************** Image Sequence Baking ******************************/
299
300 typedef struct DynamicPaintBakeJob {
301   /* from wmJob */
302   void *owner;
303   short *stop, *do_update;
304   float *progress;
305
306   struct Main *bmain;
307   Scene *scene;
308   Depsgraph *depsgraph;
309   Object *ob;
310
311   DynamicPaintSurface *surface;
312   DynamicPaintCanvasSettings *canvas;
313
314   int success;
315   double start;
316 } DynamicPaintBakeJob;
317
318 static void dpaint_bake_free(void *customdata)
319 {
320   DynamicPaintBakeJob *job = customdata;
321   MEM_freeN(job);
322 }
323
324 static void dpaint_bake_endjob(void *customdata)
325 {
326   DynamicPaintBakeJob *job = customdata;
327   DynamicPaintCanvasSettings *canvas = job->canvas;
328
329   canvas->flags &= ~MOD_DPAINT_BAKING;
330
331   dynamicPaint_freeSurfaceData(job->surface);
332
333   G.is_rendering = false;
334   BKE_spacedata_draw_locks(false);
335
336   WM_set_locked_interface(G_MAIN->wm.first, false);
337
338   /* Bake was successful:
339    * Report for ended bake and how long it took */
340   if (job->success) {
341     /* Show bake info */
342     WM_reportf(
343         RPT_INFO, "DynamicPaint: Bake complete! (%.2f)", PIL_check_seconds_timer() - job->start);
344   }
345   else {
346     if (strlen(canvas->error)) { /* If an error occurred */
347       WM_reportf(RPT_ERROR, "DynamicPaint: Bake failed: %s", canvas->error);
348     }
349     else { /* User canceled the bake */
350       WM_report(RPT_WARNING, "Baking canceled!");
351     }
352   }
353 }
354
355 /*
356  * Do actual bake operation. Loop through to-be-baked frames.
357  * Returns 0 on failure.
358  */
359 static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
360 {
361   DynamicPaintSurface *surface = job->surface;
362   Object *cObject = job->ob;
363   DynamicPaintCanvasSettings *canvas = surface->canvas;
364   Scene *scene = job->scene;
365   int frame = 1, orig_frame;
366   int frames;
367
368   frames = surface->end_frame - surface->start_frame + 1;
369   if (frames <= 0) {
370     BLI_strncpy(canvas->error, N_("No frames to bake"), sizeof(canvas->error));
371     return;
372   }
373
374   /* Show progress bar. */
375   *(job->do_update) = true;
376
377   /* Set frame to start point (also inits modifier data) */
378   frame = surface->start_frame;
379   orig_frame = scene->r.cfra;
380   scene->r.cfra = (int)frame;
381   ED_update_for_newframe(job->bmain, job->depsgraph);
382
383   /* Init surface */
384   if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) {
385     job->success = 0;
386     return;
387   }
388
389   /* Loop through selected frames */
390   for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
391     /* The first 10% are for createUVSurface... */
392     const float progress = 0.1f + 0.9f * (frame - surface->start_frame) / (float)frames;
393     surface->current_frame = frame;
394
395     /* If user requested stop, quit baking */
396     if (G.is_break) {
397       job->success = 0;
398       return;
399     }
400
401     /* Update progress bar */
402     *(job->do_update) = true;
403     *(job->progress) = progress;
404
405     /* calculate a frame */
406     scene->r.cfra = (int)frame;
407     ED_update_for_newframe(job->bmain, job->depsgraph);
408     if (!dynamicPaint_calculateFrame(surface, job->depsgraph, scene, cObject, frame)) {
409       job->success = 0;
410       return;
411     }
412
413     /*
414      * Save output images
415      */
416     {
417       char filename[FILE_MAX];
418
419       /* primary output layer */
420       if (surface->flags & MOD_DPAINT_OUT1) {
421         /* set filepath */
422         BLI_join_dirfile(
423             filename, sizeof(filename), surface->image_output_path, surface->output_name);
424         BLI_path_frame(filename, frame, 4);
425
426         /* save image */
427         dynamicPaint_outputSurfaceImage(surface, filename, 0);
428       }
429       /* secondary output */
430       if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
431         /* set filepath */
432         BLI_join_dirfile(
433             filename, sizeof(filename), surface->image_output_path, surface->output_name2);
434         BLI_path_frame(filename, frame, 4);
435
436         /* save image */
437         dynamicPaint_outputSurfaceImage(surface, filename, 1);
438       }
439     }
440   }
441
442   scene->r.cfra = orig_frame;
443 }
444
445 static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
446 {
447   DynamicPaintBakeJob *job = customdata;
448
449   job->stop = stop;
450   job->do_update = do_update;
451   job->progress = progress;
452   job->start = PIL_check_seconds_timer();
453   job->success = 1;
454
455   G.is_break = false; /* reset BKE_blender_test_break*/
456
457   /* XXX annoying hack: needed to prevent data corruption when changing
458    * scene frame in separate threads
459    */
460   G.is_rendering = true;
461   BKE_spacedata_draw_locks(true);
462
463   dynamicPaint_bakeImageSequence(job);
464
465   *do_update = true;
466   *stop = 0;
467 }
468
469 /*
470  * Bake Dynamic Paint image sequence surface
471  */
472 static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
473 {
474   DynamicPaintModifierData *pmd = NULL;
475   DynamicPaintCanvasSettings *canvas;
476   Object *ob = ED_object_context(C);
477   Scene *scene = CTX_data_scene(C);
478
479   DynamicPaintSurface *surface;
480
481   /*
482    * Get modifier data
483    */
484   pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
485   if (!pmd) {
486     BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
487     return OPERATOR_CANCELLED;
488   }
489
490   /* Make sure we're dealing with a canvas */
491   canvas = pmd->canvas;
492   if (!canvas) {
493     BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
494     return OPERATOR_CANCELLED;
495   }
496   surface = get_activeSurface(canvas);
497
498   /* Set state to baking and init surface */
499   canvas->error[0] = '\0';
500   canvas->flags |= MOD_DPAINT_BAKING;
501
502   DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob");
503   job->bmain = CTX_data_main(C);
504   job->scene = scene;
505   job->depsgraph = CTX_data_depsgraph(C);
506   job->ob = ob;
507   job->canvas = canvas;
508   job->surface = surface;
509
510   wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
511                               CTX_wm_window(C),
512                               scene,
513                               "Dynamic Paint Bake",
514                               WM_JOB_PROGRESS,
515                               WM_JOB_TYPE_DPAINT_BAKE);
516
517   WM_jobs_customdata_set(wm_job, job, dpaint_bake_free);
518   WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
519   WM_jobs_callbacks(wm_job, dpaint_bake_startjob, NULL, NULL, dpaint_bake_endjob);
520
521   WM_set_locked_interface(CTX_wm_manager(C), true);
522
523   /* Bake Dynamic Paint */
524   WM_jobs_start(CTX_wm_manager(C), wm_job);
525
526   return OPERATOR_FINISHED;
527 }
528
529 void DPAINT_OT_bake(wmOperatorType *ot)
530 {
531   /* identifiers */
532   ot->name = "Dynamic Paint Bake";
533   ot->description = "Bake dynamic paint image sequence surface";
534   ot->idname = "DPAINT_OT_bake";
535
536   /* api callbacks */
537   ot->exec = dynamicpaint_bake_exec;
538   ot->poll = ED_operator_object_active_editable;
539 }