DPAINT_OT_output_toggle operator was using an index option for what was really a...
[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
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48 #include "RNA_enum_types.h"
49
50 /* Platform independend time    */
51 #include "PIL_time.h"
52
53 #include "WM_types.h"
54 #include "WM_api.h"
55
56 static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
57 {
58         DynamicPaintModifierData *pmd = 0;
59         Object *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
60         DynamicPaintCanvasSettings *canvas;
61         DynamicPaintSurface *surface;
62
63         /* Make sure we're dealing with a canvas */
64         pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
65         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
66
67         canvas = pmd->canvas;
68         surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C));
69
70         if (!surface) return OPERATOR_CANCELLED;
71
72         /* set preview for this surface only and set active */
73         canvas->active_sur = 0;
74         for(surface=surface->prev; surface; surface=surface->prev) {
75                                 surface->flags &= ~MOD_DPAINT_PREVIEW;
76                                 canvas->active_sur++;
77         }
78
79         return OPERATOR_FINISHED;
80 }
81
82 /* add surface slot */
83 void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
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 */
91         ot->exec= surface_slot_add_exec;
92         ot->poll= ED_operator_object_active_editable;
93
94         /* flags */
95         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
96 }
97
98 static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
99 {
100         DynamicPaintModifierData *pmd = 0;
101         Object *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
102         DynamicPaintCanvasSettings *canvas;
103         DynamicPaintSurface *surface;
104         int id=0;
105
106         /* Make sure we're dealing with a canvas */
107         pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
108         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
109
110         canvas = pmd->canvas;
111         surface = canvas->surfaces.first;
112
113         /* find active surface and remove it */
114         for(; surface; surface=surface->next) {
115                 if(id == canvas->active_sur) {
116                                 canvas->active_sur -= 1;
117                                 dynamicPaint_freeSurface(surface);
118                                 break;
119                         }
120                 id++;
121         }
122
123         dynamicPaint_resetPreview(canvas);
124         DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
125         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, cObject);
126
127         return OPERATOR_FINISHED;
128 }
129
130 /* remove surface slot */
131 void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
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 */
139         ot->exec= surface_slot_remove_exec;
140         ot->poll= ED_operator_object_active_editable;
141
142         /* flags */
143         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
144 }
145
146 static int type_toggle_exec(bContext *C, wmOperator *op)
147 {
148
149         Object *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
150         Scene *scene = CTX_data_scene(C);
151         DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
152         int type= RNA_enum_get(op->ptr, "type");
153
154         if (!pmd) return OPERATOR_CANCELLED;
155
156         /* if type is already enabled, toggle it off */
157         if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) {
158                         dynamicPaint_freeCanvas(pmd);
159         }
160         else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) {
161                         dynamicPaint_freeBrush(pmd);
162         }
163         /* else create a new type */
164         else {
165                 if (!dynamicPaint_createType(pmd, type, scene))
166                         return OPERATOR_CANCELLED;
167         }
168         
169         /* update dependancy */
170         DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
171         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, cObject);
172         DAG_scene_sort(CTX_data_main(C), scene);
173
174         return OPERATOR_FINISHED;
175 }
176
177 void DPAINT_OT_type_toggle(wmOperatorType *ot)
178 {
179         PropertyRNA *prop;
180
181         /* identifiers */
182         ot->name= "Toggle Type Active";
183         ot->idname= "DPAINT_OT_type_toggle";
184         ot->description = "Toggles whether given type is active or not";
185         
186         /* api callbacks */
187         ot->exec= type_toggle_exec;
188         ot->poll= ED_operator_object_active_editable;
189         
190         /* flags */
191         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
192         
193         /* properties */
194         prop= RNA_def_enum(ot->srna, "type", prop_dynamicpaint_type_items, MOD_DYNAMICPAINT_TYPE_CANVAS, "Type", "");
195         ot->prop= prop;
196 }
197
198 static int output_toggle_exec(bContext *C, wmOperator *op)
199 {
200         Object *ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
201         Scene *scene = CTX_data_scene(C);
202         DynamicPaintSurface *surface;
203         DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
204         int output= RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
205
206         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
207         surface = get_activeSurface(pmd->canvas);
208
209         /* if type is already enabled, toggle it off */
210         if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
211                 int exists = dynamicPaint_outputLayerExists(surface, ob, output);
212                 const char *name;
213                 
214                 if (output == 0)
215                         name = surface->output_name;
216                 else
217                         name = surface->output_name2;
218
219                 /* Vertex Color Layer */
220                 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
221                         if (!exists)
222                                 ED_mesh_color_add(C, scene, ob, ob->data, name, 1);
223                         else 
224                                 ED_mesh_color_remove_named(C, ob, ob->data, name);
225                 }
226                 /* Vertex Weight Layer */
227                 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
228                         if (!exists) {
229                                 ED_vgroup_add_name(ob, name);
230                         }
231                         else {
232                                 bDeformGroup *defgroup = defgroup_find_name(ob, name);
233                                 if (defgroup) ED_vgroup_delete(ob, defgroup);
234                         }
235                 }
236         }
237
238         return OPERATOR_FINISHED;
239 }
240
241 void DPAINT_OT_output_toggle(wmOperatorType *ot)
242 {
243         static EnumPropertyItem prop_output_toggle_types[] = {
244                 {0, "A", 0, "Output A", ""},
245                 {1, "B", 0, "Output B", ""},
246                 {0, NULL, 0, NULL, NULL}
247         };
248
249         /* identifiers */
250         ot->name= "Toggle Output Layer";
251         ot->idname= "DPAINT_OT_output_toggle";
252         ot->description = "Adds or removes Dynamic Paint output data layer";
253         
254         /* api callbacks */
255         ot->exec= output_toggle_exec;
256         ot->poll= ED_operator_object_active_editable;
257         
258         /* flags */
259         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
260         
261         /* properties */
262         ot->prop= RNA_def_enum(ot->srna, "output", prop_output_toggle_types, 0, "Output Toggle", "");
263 }
264
265
266 /***************************** Image Sequence Baking ******************************/
267
268 /*
269 *       Do actual bake operation. Loop through to-be-baked frames.
270 *       Returns 0 on failture.
271 */
272 static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surface, Object *cObject)
273 {
274         DynamicPaintCanvasSettings *canvas = surface->canvas;
275         Scene *scene= CTX_data_scene(C);
276         wmWindow *win = CTX_wm_window(C);
277         int frame = 1;
278         int frames;
279
280         frames = surface->end_frame - surface->start_frame + 1;
281         if (frames <= 0) {BLI_strncpy(canvas->error, "No frames to bake.", sizeof(canvas->error)); return 0;}
282
283         /* Set frame to start point (also inits modifier data) */
284         frame = surface->start_frame;
285         scene->r.cfra = (int)frame;
286         ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
287
288         /* Init surface */
289         if (!dynamicPaint_createUVSurface(surface)) return 0;
290
291         /* Loop through selected frames */
292         for (frame=surface->start_frame; frame<=surface->end_frame; frame++)
293         {
294                 float progress = (frame - surface->start_frame) / (float)frames * 100;
295                 surface->current_frame = frame;
296
297                 /* If user requested stop (esc), quit baking    */
298                 if (blender_test_break()) return 0;
299
300                 /* Update progress bar cursor */
301                 WM_timecursor(win, (int)progress);
302
303                 /* calculate a frame */
304                 scene->r.cfra = (int)frame;
305                 ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
306                 if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0;
307
308                 /*
309                 *       Save output images
310                 */
311                 {
312                         char filename[FILE_MAX];
313                         /* make sure output path has ending slash */
314                         BLI_add_slash(surface->image_output_path);
315
316                         /* primary output layer */
317                         if (surface->flags & MOD_DPAINT_OUT1) {
318                                 /* set filepath */
319                                 BLI_snprintf(filename, sizeof(filename), "%s%s", surface->image_output_path, surface->output_name);
320                                 BLI_path_frame(filename, frame, 4);
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_snprintf(filename, sizeof(filename), "%s%s", surface->image_output_path, surface->output_name2);
328                                 BLI_path_frame(filename, frame, 4);
329                                 /* save image */
330                                 dynamicPaint_outputSurfaceImage(surface, filename, 1);
331                         }
332                 }
333         }
334         return 1;
335 }
336
337
338 /*
339 *       Bake Dynamic Paint image sequence surface
340 */
341 int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
342 {
343         DynamicPaintModifierData *pmd = NULL;
344         DynamicPaintCanvasSettings *canvas;
345         Object *ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
346         int status = 0;
347         double timer = PIL_check_seconds_timer();
348         char result_str[80];
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.afbreek= 0;   /* 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                 BLI_snprintf(result_str, sizeof(result_str), "Bake Complete! (%s)", time_str);
390                 BKE_report(op->reports, RPT_INFO, result_str);
391         }
392         else {
393                 if (strlen(canvas->error)) { /* If an error occured */
394                         BLI_snprintf(result_str, sizeof(result_str), "Bake Failed: %s", canvas->error);
395                         BKE_report(op->reports, RPT_ERROR, result_str);
396                 }
397                 else {  /* User cancelled the bake */
398                         BLI_strncpy(result_str, "Baking Cancelled!", sizeof(result_str));
399                         BKE_report(op->reports, RPT_WARNING, result_str);
400                 }
401         }
402
403         return status;
404 }
405
406 static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
407 {
408         /* Bake dynamic paint */
409         if(!dynamicPaint_initBake(C, op)) {
410                 return OPERATOR_CANCELLED;}
411
412         return OPERATOR_FINISHED;
413 }
414
415 void DPAINT_OT_bake(wmOperatorType *ot)
416 {
417         /* identifiers */
418         ot->name= "Dynamic Paint Bake";
419         ot->description= "Bake dynamic paint image sequence surface";
420         ot->idname= "DPAINT_OT_bake";
421         
422         /* api callbacks */
423         ot->exec= dynamicpaint_bake_exec;
424         ot->poll= ED_operator_object_active_editable;
425 }