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