467ad5c6ff9d50d139ef5482119451a74585a825
[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 #include <math.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "BLI_blenlib.h"
26 #include "BLI_string.h"
27 #include "BLI_utildefines.h"
28
29 #include "DNA_dynamicpaint_types.h"
30 #include "DNA_modifier_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_scene_types.h"
33
34 #include "BKE_blender.h"
35 #include "BKE_context.h"
36 #include "BKE_deform.h"
37 #include "BKE_depsgraph.h"
38 #include "BKE_dynamicpaint.h"
39 #include "BKE_global.h"
40 #include "BKE_modifier.h"
41 #include "BKE_report.h"
42
43 #include "ED_mesh.h"
44 #include "ED_screen.h"
45 #include "ED_object.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49 #include "RNA_enum_types.h"
50
51 #include "PIL_time.h"
52
53 #include "WM_types.h"
54 #include "WM_api.h"
55
56 #include "physics_intern.h" /* own include */
57
58 static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
59 {
60         DynamicPaintModifierData *pmd = NULL;
61         Object *cObject = ED_object_context(C);
62         DynamicPaintCanvasSettings *canvas;
63         DynamicPaintSurface *surface;
64
65         /* Make sure we're dealing with a canvas */
66         pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
67         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
68
69         canvas = pmd->canvas;
70         surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C));
71
72         if (!surface) return OPERATOR_CANCELLED;
73
74         /* set preview for this surface only and set active */
75         canvas->active_sur = 0;
76         for (surface = surface->prev; surface; surface = surface->prev) {
77                 surface->flags &= ~MOD_DPAINT_PREVIEW;
78                 canvas->active_sur++;
79         }
80
81         return OPERATOR_FINISHED;
82 }
83
84 /* add surface slot */
85 void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
86 {
87         /* identifiers */
88         ot->name = "Add Surface Slot";
89         ot->idname = "DPAINT_OT_surface_slot_add";
90         ot->description = "Add a new Dynamic Paint surface slot";
91         
92         /* api callbacks */
93         ot->exec = surface_slot_add_exec;
94         ot->poll = ED_operator_object_active_editable;
95
96         /* flags */
97         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
98 }
99
100 static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
101 {
102         DynamicPaintModifierData *pmd = NULL;
103         Object *obj_ctx = ED_object_context(C);
104         DynamicPaintCanvasSettings *canvas;
105         DynamicPaintSurface *surface;
106         int id = 0;
107
108         /* Make sure we're dealing with a canvas */
109         pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint);
110         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
111
112         canvas = pmd->canvas;
113         surface = 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(surface);
120                                 break;
121                         }
122                 id++;
123         }
124
125         dynamicPaint_resetPreview(canvas);
126         DAG_id_tag_update(&obj_ctx->id, OB_RECALC_DATA);
127         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obj_ctx);
128
129         return OPERATOR_FINISHED;
130 }
131
132 /* remove surface slot */
133 void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
134 {
135         /* identifiers */
136         ot->name = "Remove Surface Slot";
137         ot->idname = "DPAINT_OT_surface_slot_remove";
138         ot->description = "Remove the selected surface slot";
139         
140         /* api callbacks */
141         ot->exec = surface_slot_remove_exec;
142         ot->poll = ED_operator_object_active_editable;
143
144         /* flags */
145         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
146 }
147
148 static int type_toggle_exec(bContext *C, wmOperator *op)
149 {
150
151         Object *cObject = ED_object_context(C);
152         Scene *scene = CTX_data_scene(C);
153         DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
154         int type = RNA_enum_get(op->ptr, "type");
155
156         if (!pmd) return OPERATOR_CANCELLED;
157
158         /* if type is already enabled, toggle it off */
159         if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) {
160                         dynamicPaint_freeCanvas(pmd);
161         }
162         else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) {
163                         dynamicPaint_freeBrush(pmd);
164         }
165         /* else create a new type */
166         else {
167                 if (!dynamicPaint_createType(pmd, type, scene))
168                         return OPERATOR_CANCELLED;
169         }
170         
171         /* update dependency */
172         DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
173         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, cObject);
174         DAG_scene_sort(CTX_data_main(C), scene);
175
176         return OPERATOR_FINISHED;
177 }
178
179 void DPAINT_OT_type_toggle(wmOperatorType *ot)
180 {
181         PropertyRNA *prop;
182
183         /* identifiers */
184         ot->name = "Toggle Type Active";
185         ot->idname = "DPAINT_OT_type_toggle";
186         ot->description = "Toggle whether given type is active or not";
187         
188         /* api callbacks */
189         ot->exec = type_toggle_exec;
190         ot->poll = ED_operator_object_active_editable;
191         
192         /* flags */
193         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
194         
195         /* properties */
196         prop = RNA_def_enum(ot->srna, "type", prop_dynamicpaint_type_items, MOD_DYNAMICPAINT_TYPE_CANVAS, "Type", "");
197         ot->prop = prop;
198 }
199
200 static int output_toggle_exec(bContext *C, wmOperator *op)
201 {
202         Object *ob = ED_object_context(C);
203         Scene *scene = CTX_data_scene(C);
204         DynamicPaintSurface *surface;
205         DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
206         int output = RNA_enum_get(op->ptr, "output");  /* currently only 1/0 */
207
208         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
209         surface = get_activeSurface(pmd->canvas);
210
211         /* if type is already enabled, toggle it off */
212         if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
213                 int exists = dynamicPaint_outputLayerExists(surface, ob, output);
214                 const char *name;
215                 
216                 if (output == 0)
217                         name = surface->output_name;
218                 else
219                         name = surface->output_name2;
220
221                 /* Vertex Color Layer */
222                 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
223                         if (!exists)
224                                 ED_mesh_color_add(C, scene, ob, ob->data, name, 1);
225                         else 
226                                 ED_mesh_color_remove_named(C, ob, ob->data, name);
227                 }
228                 /* Vertex Weight Layer */
229                 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
230                         if (!exists) {
231                                 ED_vgroup_add_name(ob, name);
232                         }
233                         else {
234                                 bDeformGroup *defgroup = defgroup_find_name(ob, name);
235                                 if (defgroup) ED_vgroup_delete(ob, defgroup);
236                         }
237                 }
238         }
239
240         return OPERATOR_FINISHED;
241 }
242
243 void DPAINT_OT_output_toggle(wmOperatorType *ot)
244 {
245         static EnumPropertyItem prop_output_toggle_types[] = {
246                 {0, "A", 0, "Output A", ""},
247                 {1, "B", 0, "Output B", ""},
248                 {0, NULL, 0, NULL, NULL}
249         };
250
251         /* identifiers */
252         ot->name = "Toggle Output Layer";
253         ot->idname = "DPAINT_OT_output_toggle";
254         ot->description = "Add or remove Dynamic Paint output data layer";
255         
256         /* api callbacks */
257         ot->exec = output_toggle_exec;
258         ot->poll = ED_operator_object_active_editable;
259         
260         /* flags */
261         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
262         
263         /* properties */
264         ot->prop = RNA_def_enum(ot->srna, "output", prop_output_toggle_types, 0, "Output Toggle", "");
265 }
266
267
268 /***************************** Image Sequence Baking ******************************/
269
270 /*
271  * Do actual bake operation. Loop through to-be-baked frames.
272  * Returns 0 on failure.
273  */
274 static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surface, Object *cObject)
275 {
276         DynamicPaintCanvasSettings *canvas = surface->canvas;
277         Scene *scene = CTX_data_scene(C);
278         wmWindow *win = CTX_wm_window(C);
279         int frame = 1;
280         int frames;
281
282         frames = surface->end_frame - surface->start_frame + 1;
283         if (frames <= 0) {BLI_strncpy(canvas->error, "No frames to bake.", sizeof(canvas->error)); return 0;}
284
285         /* Set frame to start point (also inits modifier data) */
286         frame = surface->start_frame;
287         scene->r.cfra = (int)frame;
288         ED_update_for_newframe(CTX_data_main(C), scene, 1);
289
290         /* Init surface */
291         if (!dynamicPaint_createUVSurface(surface)) return 0;
292
293         /* Loop through selected frames */
294         for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
295                 float progress = (frame - surface->start_frame) / (float)frames * 100;
296                 surface->current_frame = frame;
297
298                 /* If user requested stop (esc), quit baking    */
299                 if (blender_test_break()) return 0;
300
301                 /* Update progress bar cursor */
302                 WM_cursor_time(win, (int)progress);
303
304                 /* calculate a frame */
305                 scene->r.cfra = (int)frame;
306                 ED_update_for_newframe(CTX_data_main(C), scene, 1);
307                 if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0;
308
309                 /*
310                  * Save output images
311                  */
312                 {
313                         char filename[FILE_MAX];
314
315                         /* primary output layer */
316                         if (surface->flags & MOD_DPAINT_OUT1) {
317                                 /* set filepath */
318                                 BLI_join_dirfile(filename, sizeof(filename), surface->image_output_path, surface->output_name);
319                                 BLI_path_frame(filename, frame, 4);
320
321                                 /* save image */
322                                 dynamicPaint_outputSurfaceImage(surface, filename, 0);
323                         }
324                         /* secondary output */
325                         if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
326                                 /* set filepath */
327                                 BLI_join_dirfile(filename, sizeof(filename), surface->image_output_path, surface->output_name2);
328                                 BLI_path_frame(filename, frame, 4);
329
330                                 /* save image */
331                                 dynamicPaint_outputSurfaceImage(surface, filename, 1);
332                         }
333                 }
334         }
335         return 1;
336 }
337
338
339 /*
340  * Bake Dynamic Paint image sequence surface
341  */
342 static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
343 {
344         DynamicPaintModifierData *pmd = NULL;
345         DynamicPaintCanvasSettings *canvas;
346         Object *ob = ED_object_context(C);
347         int status = 0;
348         double timer = PIL_check_seconds_timer();
349         DynamicPaintSurface *surface;
350
351         /*
352          * Get modifier data
353          */
354         pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
355         if (!pmd) {
356                 BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
357                 return 0;
358         }
359
360         /* Make sure we're dealing with a canvas */
361         canvas = pmd->canvas;
362         if (!canvas) {
363                 BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
364                 return 0;
365         }
366         surface = get_activeSurface(canvas);
367
368         /* Set state to baking and init surface */
369         canvas->error[0] = '\0';
370         canvas->flags |= MOD_DPAINT_BAKING;
371         G.is_break = FALSE;  /* reset blender_test_break*/
372
373         /*  Bake Dynamic Paint  */
374         status = dynamicPaint_bakeImageSequence(C, surface, ob);
375         /* Clear bake */
376         canvas->flags &= ~MOD_DPAINT_BAKING;
377         WM_cursor_restore(CTX_wm_window(C));
378         dynamicPaint_freeSurfaceData(surface);
379
380         /* Bake was successful:
381          *  Report for ended bake and how long it took */
382         if (status) {
383                 /* Format time string */
384                 char time_str[30];
385                 double time = PIL_check_seconds_timer() - timer;
386                 BLI_timestr(time, time_str);
387
388                 /* Show bake info */
389                 BKE_reportf(op->reports, RPT_INFO, "Bake complete! (%s)", time_str);
390         }
391         else {
392                 if (strlen(canvas->error)) { /* If an error occurred */
393                         BKE_reportf(op->reports, RPT_ERROR, "Bake failed: %s", canvas->error);
394                 }
395                 else { /* User canceled the bake */
396                         BKE_report(op->reports, RPT_WARNING, "Baking canceled!");
397                 }
398         }
399
400         return status;
401 }
402
403 static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
404 {
405         /* Bake dynamic paint */
406         if (!dynamicPaint_initBake(C, op)) {
407                 return OPERATOR_CANCELLED;}
408
409         return OPERATOR_FINISHED;
410 }
411
412 void DPAINT_OT_bake(wmOperatorType *ot)
413 {
414         /* identifiers */
415         ot->name = "Dynamic Paint Bake";
416         ot->description = "Bake dynamic paint image sequence surface";
417         ot->idname = "DPAINT_OT_bake";
418         
419         /* api callbacks */
420         ot->exec = dynamicpaint_bake_exec;
421         ot->poll = ED_operator_object_active_editable;
422 }