svn merge ^/trunk/blender -r41998:42009
[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 #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 = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
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 *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
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(cObject, 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(&cObject->id, OB_RECALC_DATA);
127         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, cObject);
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 = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
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 dependancy */
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 = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
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 failture.
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, win->screen, 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         {
296                 float progress = (frame - surface->start_frame) / (float)frames * 100;
297                 surface->current_frame = frame;
298
299                 /* If user requested stop (esc), quit baking    */
300                 if (blender_test_break()) return 0;
301
302                 /* Update progress bar cursor */
303                 WM_timecursor(win, (int)progress);
304
305                 /* calculate a frame */
306                 scene->r.cfra = (int)frame;
307                 ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
308                 if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0;
309
310                 /*
311                 *       Save output images
312                 */
313                 {
314                         char filename[FILE_MAX];
315
316                         /* primary output layer */
317                         if (surface->flags & MOD_DPAINT_OUT1) {
318                                 /* set filepath */
319                                 BLI_join_dirfile(filename, sizeof(filename), surface->image_output_path, surface->output_name);
320                                 BLI_path_frame(filename, frame, 4);
321
322                                 /* save image */
323                                 dynamicPaint_outputSurfaceImage(surface, filename, 0);
324                         }
325                         /* secondary output */
326                         if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
327                                 /* set filepath */
328                                 BLI_join_dirfile(filename, sizeof(filename), surface->image_output_path, surface->output_name2);
329                                 BLI_path_frame(filename, frame, 4);
330
331                                 /* save image */
332                                 dynamicPaint_outputSurfaceImage(surface, filename, 1);
333                         }
334                 }
335         }
336         return 1;
337 }
338
339
340 /*
341  * Bake Dynamic Paint image sequence surface
342  */
343 static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
344 {
345         DynamicPaintModifierData *pmd = NULL;
346         DynamicPaintCanvasSettings *canvas;
347         Object *ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
348         int status = 0;
349         double timer = PIL_check_seconds_timer();
350         char result_str[80];
351         DynamicPaintSurface *surface;
352
353         /*
354         *       Get modifier data
355         */
356         pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
357         if (!pmd) {
358                 BKE_report(op->reports, RPT_ERROR, "Bake Failed: No Dynamic Paint modifier found.");
359                 return 0;
360         }
361
362         /* Make sure we're dealing with a canvas */
363         canvas = pmd->canvas;
364         if (!canvas) {
365                 BKE_report(op->reports, RPT_ERROR, "Bake Failed: Invalid Canvas.");
366                 return 0;
367         }
368         surface = get_activeSurface(canvas);
369
370         /* Set state to baking and init surface */
371         canvas->error[0] = '\0';
372         canvas->flags |= MOD_DPAINT_BAKING;
373         G.afbreek= 0;   /* reset blender_test_break*/
374
375         /*  Bake Dynamic Paint  */
376         status = dynamicPaint_bakeImageSequence(C, surface, ob);
377         /* Clear bake */
378         canvas->flags &= ~MOD_DPAINT_BAKING;
379         WM_cursor_restore(CTX_wm_window(C));
380         dynamicPaint_freeSurfaceData(surface);
381
382         /* Bake was successful:
383         *  Report for ended bake and how long it took */
384         if (status) {
385                 /* Format time string   */
386                 char time_str[30];
387                 double time = PIL_check_seconds_timer() - timer;
388                 BLI_timestr(time, time_str);
389
390                 /* Show bake info */
391                 BLI_snprintf(result_str, sizeof(result_str), "Bake Complete! (%s)", time_str);
392                 BKE_report(op->reports, RPT_INFO, result_str);
393         }
394         else {
395                 if (strlen(canvas->error)) { /* If an error occured */
396                         BLI_snprintf(result_str, sizeof(result_str), "Bake Failed: %s", canvas->error);
397                         BKE_report(op->reports, RPT_ERROR, result_str);
398                 }
399                 else {  /* User cancelled the bake */
400                         BLI_strncpy(result_str, "Baking Cancelled!", sizeof(result_str));
401                         BKE_report(op->reports, RPT_WARNING, result_str);
402                 }
403         }
404
405         return status;
406 }
407
408 static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
409 {
410         /* Bake dynamic paint */
411         if(!dynamicPaint_initBake(C, op)) {
412                 return OPERATOR_CANCELLED;}
413
414         return OPERATOR_FINISHED;
415 }
416
417 void DPAINT_OT_bake(wmOperatorType *ot)
418 {
419         /* identifiers */
420         ot->name= "Dynamic Paint Bake";
421         ot->description= "Bake dynamic paint image sequence surface";
422         ot->idname= "DPAINT_OT_bake";
423         
424         /* api callbacks */
425         ot->exec= dynamicpaint_bake_exec;
426         ot->poll= ED_operator_object_active_editable;
427 }