svn merge -r41723:41751 ^/trunk/blender
[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
201         Object *ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
202         Scene *scene = CTX_data_scene(C);
203         DynamicPaintSurface *surface;
204         DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
205         int index= RNA_int_get(op->ptr, "index");
206
207         if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
208         surface = get_activeSurface(pmd->canvas);
209
210         /* if type is already enabled, toggle it off */
211         if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
212                 int exists = dynamicPaint_outputLayerExists(surface, ob, index);
213                 char *name;
214                 
215                 if (index == 0)
216                         name = surface->output_name;
217                 else if (index == 1)
218                         name = surface->output_name2;
219
220                 /* Vertex Color Layer */
221                 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
222                         if (!exists)
223                                 ED_mesh_color_add(C, scene, ob, ob->data, name, 1);
224                         else 
225                                 ED_mesh_color_remove_named(C, ob, ob->data, name);
226                 }
227                 /* Vertex Weight Layer */
228                 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
229                         if (!exists)
230                                 ED_vgroup_add_name(ob, name);
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         PropertyRNA *prop;
244
245         /* identifiers */
246         ot->name= "Toggle Output Layer";
247         ot->idname= "DPAINT_OT_output_toggle";
248         ot->description = "Adds or removes Dynamic Paint output data layer";
249         
250         /* api callbacks */
251         ot->exec= output_toggle_exec;
252         ot->poll= ED_operator_object_active_editable;
253         
254         /* flags */
255         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
256         
257         /* properties */
258         prop= RNA_def_int(ot->srna, "index", 0, 0, 1, "Index", "", 0, 1);
259         ot->prop= prop;
260 }
261
262
263 /***************************** Image Sequence Baking ******************************/
264
265 /*
266 *       Do actual bake operation. Loop through to-be-baked frames.
267 *       Returns 0 on failture.
268 */
269 static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surface, Object *cObject)
270 {
271         DynamicPaintCanvasSettings *canvas = surface->canvas;
272         Scene *scene= CTX_data_scene(C);
273         wmWindow *win = CTX_wm_window(C);
274         int frame = 1;
275         int frames;
276
277         frames = surface->end_frame - surface->start_frame + 1;
278         if (frames <= 0) {BLI_strncpy(canvas->error, "No frames to bake.", sizeof(canvas->error)); return 0;}
279
280         /* Set frame to start point (also inits modifier data) */
281         frame = surface->start_frame;
282         scene->r.cfra = (int)frame;
283         ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
284
285         /* Init surface */
286         if (!dynamicPaint_createUVSurface(surface)) return 0;
287
288         /* Loop through selected frames */
289         for (frame=surface->start_frame; frame<=surface->end_frame; frame++)
290         {
291                 float progress = (frame - surface->start_frame) / (float)frames * 100;
292                 surface->current_frame = frame;
293
294                 /* If user requested stop (esc), quit baking    */
295                 if (blender_test_break()) return 0;
296
297                 /* Update progress bar cursor */
298                 WM_timecursor(win, (int)progress);
299
300                 /* calculate a frame */
301                 scene->r.cfra = (int)frame;
302                 ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
303                 if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0;
304
305                 /*
306                 *       Save output images
307                 */
308                 {
309                         char filename[FILE_MAX];
310                         /* make sure output path has ending slash */
311                         BLI_add_slash(surface->image_output_path);
312
313                         /* primary output layer */
314                         if (surface->flags & MOD_DPAINT_OUT1) {
315                                 /* set filepath */
316                                 BLI_snprintf(filename, sizeof(filename), "%s%s", surface->image_output_path, surface->output_name);
317                                 BLI_path_frame(filename, frame, 4);
318                                 /* save image */
319                                 dynamicPaint_outputSurfaceImage(surface, filename, 0);
320                         }
321                         /* secondary output */
322                         if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
323                                 /* set filepath */
324                                 BLI_snprintf(filename, sizeof(filename), "%s%s", surface->image_output_path, surface->output_name2);
325                                 BLI_path_frame(filename, frame, 4);
326                                 /* save image */
327                                 dynamicPaint_outputSurfaceImage(surface, filename, 1);
328                         }
329                 }
330         }
331         return 1;
332 }
333
334
335 /*
336 *       Bake Dynamic Paint image sequence surface
337 */
338 int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
339 {
340         DynamicPaintModifierData *pmd = NULL;
341         DynamicPaintCanvasSettings *canvas;
342         Object *ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
343         int status = 0;
344         double timer = PIL_check_seconds_timer();
345         char result_str[80];
346         DynamicPaintSurface *surface;
347
348         /*
349         *       Get modifier data
350         */
351         pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
352         if (!pmd) {
353                 BKE_report(op->reports, RPT_ERROR, "Bake Failed: No Dynamic Paint modifier found.");
354                 return 0;
355         }
356
357         /* Make sure we're dealing with a canvas */
358         canvas = pmd->canvas;
359         if (!canvas) {
360                 BKE_report(op->reports, RPT_ERROR, "Bake Failed: Invalid Canvas.");
361                 return 0;
362         }
363         surface = get_activeSurface(canvas);
364
365         /* Set state to baking and init surface */
366         canvas->error[0] = '\0';
367         canvas->flags |= MOD_DPAINT_BAKING;
368         G.afbreek= 0;   /* reset blender_test_break*/
369
370         /*  Bake Dynamic Paint  */
371         status = dynamicPaint_bakeImageSequence(C, surface, ob);
372         /* Clear bake */
373         canvas->flags &= ~MOD_DPAINT_BAKING;
374         WM_cursor_restore(CTX_wm_window(C));
375         dynamicPaint_freeSurfaceData(surface);
376
377         /* Bake was successful:
378         *  Report for ended bake and how long it took */
379         if (status) {
380                 /* Format time string   */
381                 char time_str[30];
382                 double time = PIL_check_seconds_timer() - timer;
383                 BLI_timestr(time, time_str);
384
385                 /* Show bake info */
386                 BLI_snprintf(result_str, sizeof(result_str), "Bake Complete! (%s)", time_str);
387                 BKE_report(op->reports, RPT_INFO, result_str);
388         }
389         else {
390                 if (strlen(canvas->error)) { /* If an error occured */
391                         BLI_snprintf(result_str, sizeof(result_str), "Bake Failed: %s", canvas->error);
392                         BKE_report(op->reports, RPT_ERROR, result_str);
393                 }
394                 else {  /* User cancelled the bake */
395                         BLI_strncpy(result_str, "Baking Cancelled!", sizeof(result_str));
396                         BKE_report(op->reports, RPT_WARNING, result_str);
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 }