Spelling Cleanup
[blender.git] / source / blender / editors / physics / dynamicpaint_ops.c
index 8a4007745deb7439e1227e7ef4bf9bd54e43cc9a..7f5688338668d15ee4f2b56bdd92c6a4c5c840ef 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
 #include "DNA_dynamicpaint_types.h"
 #include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 
+#include "BKE_blender.h"
 #include "BKE_context.h"
 #include "BKE_deform.h"
 #include "BKE_depsgraph.h"
 #include "BKE_dynamicpaint.h"
+#include "BKE_global.h"
 #include "BKE_modifier.h"
+#include "BKE_report.h"
 
 #include "ED_mesh.h"
 #include "ED_screen.h"
+#include "ED_object.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
 #include "RNA_enum_types.h"
 
+#include "PIL_time.h"
+
 #include "WM_types.h"
 #include "WM_api.h"
 
-static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
-{
-       /* Bake dynamic paint */
-       if(!dynamicPaint_initBake(C, op)) {
-               return OPERATOR_CANCELLED;}
-
-       return OPERATOR_FINISHED;
-}
+#include "physics_intern.h" /* own include */
 
-void DPAINT_OT_bake(wmOperatorType *ot)
+static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       /* identifiers */
-       ot->name= "Dynamic Paint Bake";
-       ot->description= "Bake dynamic paint image sequence surface";
-       ot->idname= "DPAINT_OT_bake";
-       
-       /* api callbacks */
-       ot->exec= dynamicpaint_bake_exec;
-       ot->poll= ED_operator_object_active_editable;
-}
-
-static int surface_slot_add_exec(bContext *C, wmOperator *op)
-{
-       DynamicPaintModifierData *pmd = 0;
-       Object *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       DynamicPaintModifierData *pmd = NULL;
+       Object *cObject = ED_object_context(C);
+       DynamicPaintCanvasSettings *canvas;
        DynamicPaintSurface *surface;
 
        /* Make sure we're dealing with a canvas */
        pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
-       if (!pmd) return OPERATOR_CANCELLED;
-       if (!pmd->canvas) return OPERATOR_CANCELLED;
+       if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
 
-       surface = dynamicPaint_createNewSurface(pmd->canvas, CTX_data_scene(C));
+       canvas = pmd->canvas;
+       surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C));
 
        if (!surface) return OPERATOR_CANCELLED;
 
        /* set preview for this surface only and set active */
-       pmd->canvas->active_sur = 0;
+       canvas->active_sur = 0;
        for(surface=surface->prev; surface; surface=surface->prev) {
                                surface->flags &= ~MOD_DPAINT_PREVIEW;
-                               pmd->canvas->active_sur++;
+                               canvas->active_sur++;
        }
 
        return OPERATOR_FINISHED;
@@ -101,31 +97,32 @@ void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-static int surface_slot_remove_exec(bContext *C, wmOperator *op)
+static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       DynamicPaintModifierData *pmd = 0;
-       Object *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       DynamicPaintModifierData *pmd = NULL;
+       Object *cObject = ED_object_context(C);
+       DynamicPaintCanvasSettings *canvas;
        DynamicPaintSurface *surface;
        int id=0;
 
        /* Make sure we're dealing with a canvas */
        pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
-       if (!pmd) return OPERATOR_CANCELLED;
-       if (!pmd->canvas) return OPERATOR_CANCELLED;
+       if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
 
-       surface = pmd->canvas->surfaces.first;
+       canvas = pmd->canvas;
+       surface = canvas->surfaces.first;
 
        /* find active surface and remove it */
        for(; surface; surface=surface->next) {
-               if(id == pmd->canvas->active_sur) {
-                               pmd->canvas->active_sur -= 1;
+               if(id == canvas->active_sur) {
+                               canvas->active_sur -= 1;
                                dynamicPaint_freeSurface(surface);
                                break;
                        }
                id++;
        }
 
-       dynamicPaint_resetPreview(pmd->canvas);
+       dynamicPaint_resetPreview(canvas);
        DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, cObject);
 
@@ -151,7 +148,7 @@ void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
 static int type_toggle_exec(bContext *C, wmOperator *op)
 {
 
-       Object *cObject = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       Object *cObject = ED_object_context(C);
        Scene *scene = CTX_data_scene(C);
        DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
        int type= RNA_enum_get(op->ptr, "type");
@@ -171,7 +168,7 @@ static int type_toggle_exec(bContext *C, wmOperator *op)
                        return OPERATOR_CANCELLED;
        }
        
-       /* update dependancy */
+       /* update dependency */
        DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, cObject);
        DAG_scene_sort(CTX_data_main(C), scene);
@@ -186,7 +183,7 @@ void DPAINT_OT_type_toggle(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Toggle Type Active";
        ot->idname= "DPAINT_OT_type_toggle";
-       ot->description = "Toggles whether given type is active or not";
+       ot->description = "Toggle whether given type is active or not";
        
        /* api callbacks */
        ot->exec= type_toggle_exec;
@@ -202,45 +199,42 @@ void DPAINT_OT_type_toggle(wmOperatorType *ot)
 
 static int output_toggle_exec(bContext *C, wmOperator *op)
 {
-
-       Object *ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       Object *ob = ED_object_context(C);
        Scene *scene = CTX_data_scene(C);
+       DynamicPaintSurface *surface;
        DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
-       int index= RNA_int_get(op->ptr, "index");
-
-       if (!pmd) return OPERATOR_CANCELLED;
+       int output= RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
 
+       if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
+       surface = get_activeSurface(pmd->canvas);
 
        /* if type is already enabled, toggle it off */
-       if (pmd->canvas) {
-                       DynamicPaintSurface *surface = get_activeSurface(pmd->canvas);
-
-                       if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
-                               int exists = dynamicPaint_outputLayerExists(surface, ob, index);
-                               char *name;
-                               
-                               if (index == 0)
-                                       name = surface->output_name;
-                               else if (index == 1)
-                                       name = surface->output_name2;
-
-                               /* Vertex Color Layer */
-                               if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-                                       if (!exists)
-                                               ED_mesh_color_add(C, scene, ob, ob->data, name, 1);
-                                       else 
-                                               ED_mesh_color_remove_named(C, ob, ob->data, name);
-                               }
-                               /* Vertex Weight Layer */
-                               else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
-                                       if (!exists)
-                                               ED_vgroup_add_name(ob, name);
-                                       else {
-                                               bDeformGroup *defgroup = defgroup_find_name(ob, name);
-                                               if (defgroup) ED_vgroup_delete(ob, defgroup);
-                                       }
-                               }
+       if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+               int exists = dynamicPaint_outputLayerExists(surface, ob, output);
+               const char *name;
+               
+               if (output == 0)
+                       name = surface->output_name;
+               else
+                       name = surface->output_name2;
+
+               /* Vertex Color Layer */
+               if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+                       if (!exists)
+                               ED_mesh_color_add(C, scene, ob, ob->data, name, 1);
+                       else 
+                               ED_mesh_color_remove_named(C, ob, ob->data, name);
+               }
+               /* Vertex Weight Layer */
+               else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+                       if (!exists) {
+                               ED_vgroup_add_name(ob, name);
+                       }
+                       else {
+                               bDeformGroup *defgroup = defgroup_find_name(ob, name);
+                               if (defgroup) ED_vgroup_delete(ob, defgroup);
                        }
+               }
        }
 
        return OPERATOR_FINISHED;
@@ -248,12 +242,16 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
 
 void DPAINT_OT_output_toggle(wmOperatorType *ot)
 {
-       PropertyRNA *prop;
+       static EnumPropertyItem prop_output_toggle_types[] = {
+               {0, "A", 0, "Output A", ""},
+               {1, "B", 0, "Output B", ""},
+               {0, NULL, 0, NULL, NULL}
+       };
 
        /* identifiers */
        ot->name= "Toggle Output Layer";
        ot->idname= "DPAINT_OT_output_toggle";
-       ot->description = "Adds or removes Dynamic Paint output data layer.";
+       ot->description = "Add or remove Dynamic Paint output data layer";
        
        /* api callbacks */
        ot->exec= output_toggle_exec;
@@ -263,6 +261,167 @@ void DPAINT_OT_output_toggle(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       prop= RNA_def_int(ot->srna, "index", 0, 0, 1, "Index", "", 0, 1);
-       ot->prop= prop;
+       ot->prop= RNA_def_enum(ot->srna, "output", prop_output_toggle_types, 0, "Output Toggle", "");
+}
+
+
+/***************************** Image Sequence Baking ******************************/
+
+/*
+*      Do actual bake operation. Loop through to-be-baked frames.
+*      Returns 0 on failture.
+*/
+static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surface, Object *cObject)
+{
+       DynamicPaintCanvasSettings *canvas = surface->canvas;
+       Scene *scene= CTX_data_scene(C);
+       wmWindow *win = CTX_wm_window(C);
+       int frame = 1;
+       int frames;
+
+       frames = surface->end_frame - surface->start_frame + 1;
+       if (frames <= 0) {BLI_strncpy(canvas->error, "No frames to bake.", sizeof(canvas->error)); return 0;}
+
+       /* Set frame to start point (also inits modifier data) */
+       frame = surface->start_frame;
+       scene->r.cfra = (int)frame;
+       ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
+
+       /* Init surface */
+       if (!dynamicPaint_createUVSurface(surface)) return 0;
+
+       /* Loop through selected frames */
+       for (frame=surface->start_frame; frame<=surface->end_frame; frame++)
+       {
+               float progress = (frame - surface->start_frame) / (float)frames * 100;
+               surface->current_frame = frame;
+
+               /* If user requested stop (esc), quit baking    */
+               if (blender_test_break()) return 0;
+
+               /* Update progress bar cursor */
+               WM_timecursor(win, (int)progress);
+
+               /* calculate a frame */
+               scene->r.cfra = (int)frame;
+               ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
+               if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0;
+
+               /*
+               *       Save output images
+               */
+               {
+                       char filename[FILE_MAX];
+
+                       /* primary output layer */
+                       if (surface->flags & MOD_DPAINT_OUT1) {
+                               /* set filepath */
+                               BLI_join_dirfile(filename, sizeof(filename), surface->image_output_path, surface->output_name);
+                               BLI_path_frame(filename, frame, 4);
+
+                               /* save image */
+                               dynamicPaint_outputSurfaceImage(surface, filename, 0);
+                       }
+                       /* secondary output */
+                       if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+                               /* set filepath */
+                               BLI_join_dirfile(filename, sizeof(filename), surface->image_output_path, surface->output_name2);
+                               BLI_path_frame(filename, frame, 4);
+
+                               /* save image */
+                               dynamicPaint_outputSurfaceImage(surface, filename, 1);
+                       }
+               }
+       }
+       return 1;
+}
+
+
+/*
+ * Bake Dynamic Paint image sequence surface
+ */
+static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
+{
+       DynamicPaintModifierData *pmd = NULL;
+       DynamicPaintCanvasSettings *canvas;
+       Object *ob = ED_object_context(C);
+       int status = 0;
+       double timer = PIL_check_seconds_timer();
+       char result_str[80];
+       DynamicPaintSurface *surface;
+
+       /*
+       *       Get modifier data
+       */
+       pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
+       if (!pmd) {
+               BKE_report(op->reports, RPT_ERROR, "Bake Failed: No Dynamic Paint modifier found.");
+               return 0;
+       }
+
+       /* Make sure we're dealing with a canvas */
+       canvas = pmd->canvas;
+       if (!canvas) {
+               BKE_report(op->reports, RPT_ERROR, "Bake Failed: Invalid Canvas.");
+               return 0;
+       }
+       surface = get_activeSurface(canvas);
+
+       /* Set state to baking and init surface */
+       canvas->error[0] = '\0';
+       canvas->flags |= MOD_DPAINT_BAKING;
+       G.afbreek= 0;   /* reset blender_test_break*/
+
+       /*  Bake Dynamic Paint  */
+       status = dynamicPaint_bakeImageSequence(C, surface, ob);
+       /* Clear bake */
+       canvas->flags &= ~MOD_DPAINT_BAKING;
+       WM_cursor_restore(CTX_wm_window(C));
+       dynamicPaint_freeSurfaceData(surface);
+
+       /* Bake was successful:
+       *  Report for ended bake and how long it took */
+       if (status) {
+               /* Format time string   */
+               char time_str[30];
+               double time = PIL_check_seconds_timer() - timer;
+               BLI_timestr(time, time_str);
+
+               /* Show bake info */
+               BLI_snprintf(result_str, sizeof(result_str), "Bake Complete! (%s)", time_str);
+               BKE_report(op->reports, RPT_INFO, result_str);
+       }
+       else {
+               if (strlen(canvas->error)) { /* If an error occured */
+                       BLI_snprintf(result_str, sizeof(result_str), "Bake Failed: %s", canvas->error);
+                       BKE_report(op->reports, RPT_ERROR, result_str);
+               }
+               else {  /* User cancelled the bake */
+                       BLI_strncpy(result_str, "Baking Cancelled!", sizeof(result_str));
+                       BKE_report(op->reports, RPT_WARNING, result_str);
+               }
+       }
+
+       return status;
+}
+
+static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
+{
+       /* Bake dynamic paint */
+       if(!dynamicPaint_initBake(C, op)) {
+               return OPERATOR_CANCELLED;}
+
+       return OPERATOR_FINISHED;
+}
+
+void DPAINT_OT_bake(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Dynamic Paint Bake";
+       ot->description= "Bake dynamic paint image sequence surface";
+       ot->idname= "DPAINT_OT_bake";
+       
+       /* api callbacks */
+       ot->exec= dynamicpaint_bake_exec;
+       ot->poll= ED_operator_object_active_editable;
 }