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