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