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