Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / armature / pose_edit.c
index da328ee..fa99274 100644 (file)
@@ -31,6 +31,8 @@
  *  \ingroup edarmature
  */
 
+#include "MEM_guardedalloc.h"
+
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
 
+#include "BKE_action.h"
 #include "BKE_anim.h"
 #include "BKE_armature.h"
 #include "BKE_context.h"
 #include "BKE_deform.h"
-#include "BKE_depsgraph.h"
 #include "BKE_object.h"
 #include "BKE_report.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -58,6 +63,7 @@
 #include "ED_keyframing.h"
 #include "ED_screen.h"
 #include "ED_object.h"
+#include "ED_view3d.h"
 
 #include "UI_interface.h"
 
@@ -81,7 +87,7 @@ Object *ED_pose_object_from_context(bContext *C)
 }
 
 /* This function is used to process the necessary updates for */
-bool ED_object_posemode_enter_ex(Object *ob)
+bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob)
 {
        BLI_assert(!ID_IS_LINKED(ob));
        bool ok = false;
@@ -90,6 +96,8 @@ bool ED_object_posemode_enter_ex(Object *ob)
                case OB_ARMATURE:
                        ob->restore_mode = ob->mode;
                        ob->mode |= OB_MODE_POSE;
+                       /* Inform all CoW versions that we changed the mode. */
+                       DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE);
                        ok = true;
 
                        break;
@@ -106,26 +114,31 @@ bool ED_object_posemode_enter(bContext *C, Object *ob)
                BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
                return false;
        }
-       bool ok = ED_object_posemode_enter_ex(ob);
+       struct Main *bmain = CTX_data_main(C);
+       bool ok = ED_object_posemode_enter_ex(bmain, ob);
        if (ok) {
                WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
        }
        return ok;
 }
 
-bool ED_object_posemode_exit_ex(Object *ob)
+bool ED_object_posemode_exit_ex(struct Main *bmain, Object *ob)
 {
        bool ok = false;
        if (ob) {
                ob->restore_mode = ob->mode;
                ob->mode &= ~OB_MODE_POSE;
+
+               /* Inform all CoW versions that we changed the mode. */
+               DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE);
                ok = true;
        }
        return ok;
 }
 bool ED_object_posemode_exit(bContext *C, Object *ob)
 {
-       bool ok = ED_object_posemode_exit_ex(ob);
+       struct Main *bmain = CTX_data_main(C);
+       bool ok = ED_object_posemode_exit_ex(bmain, ob);
        if (ok) {
                WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
        }
@@ -167,8 +180,10 @@ static bool pose_has_protected_selected(Object *ob, short warn)
  *
  * To be called from various tools that do incremental updates
  */
-void ED_pose_recalculate_paths(Scene *scene, Object *ob)
+void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
 {
+       struct Main *bmain = CTX_data_main(C);
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
        ListBase targets = {NULL, NULL};
 
        /* set flag to force recalc, then grab the relevant bones to target */
@@ -176,8 +191,11 @@ void ED_pose_recalculate_paths(Scene *scene, Object *ob)
        animviz_get_object_motionpaths(ob, &targets);
 
        /* recalculate paths, then free */
-       animviz_calc_motionpaths(scene, &targets);
+       animviz_calc_motionpaths(depsgraph, bmain, scene, &targets);
        BLI_freelistN(&targets);
+
+       /* tag armature object for copy on write - so paths will draw/redraw */
+       DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
 }
 
 
@@ -239,7 +257,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
 
        /* calculate the bones that now have motionpaths... */
        /* TODO: only make for the selected bones? */
-       ED_pose_recalculate_paths(scene, ob);
+       ED_pose_recalculate_paths(C, scene, ob);
 
        /* notifiers for updates */
        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -295,7 +313,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
 
        /* calculate the bones that now have motionpaths... */
        /* TODO: only make for the selected bones? */
-       ED_pose_recalculate_paths(scene, ob);
+       ED_pose_recalculate_paths(C, scene, ob);
 
        /* notifiers for updates */
        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -593,7 +611,7 @@ static void pose_copy_menu(Scene *scene)
                        BKE_pose_tag_recalc(bmain, ob->pose);
        }
 
-       DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
+       DEG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
 
        BIF_undo_push("Copy Pose Attributes");
 
@@ -604,34 +622,31 @@ static void pose_copy_menu(Scene *scene)
 
 static int pose_flip_names_exec(bContext *C, wmOperator *op)
 {
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-       bArmature *arm;
-
-       /* paranoia checks */
-       if (ELEM(NULL, ob, ob->pose))
-               return OPERATOR_CANCELLED;
-
+       ViewLayer *view_layer = CTX_data_view_layer(C);
        const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
 
-       arm = ob->data;
-
-       ListBase bones_names = {NULL};
-
-       CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+       FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob)
        {
-               BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
-       }
-       CTX_DATA_END;
+               bArmature *arm = ob->data;
+               ListBase bones_names = {NULL};
 
-       ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers);
+               FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
+               {
+                       BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
+               }
+               FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
 
-       BLI_freelistN(&bones_names);
+               ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers);
 
-       /* since we renamed stuff... */
-       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               BLI_freelistN(&bones_names);
 
-       /* note, notifier might evolve */
-       WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+               /* since we renamed stuff... */
+               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+               /* note, notifier might evolve */
+               WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+       }
+       FOREACH_OBJECT_IN_MODE_END;
 
        return OPERATOR_FINISHED;
 }
@@ -679,7 +694,7 @@ static int pose_autoside_names_exec(bContext *C, wmOperator *op)
        CTX_DATA_END;
 
        /* since we renamed stuff... */
-       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 
        /* note, notifier might evolve */
        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -728,7 +743,7 @@ static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
        CTX_DATA_END;
 
        /* notifiers and updates */
-       DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+       DEG_id_tag_update((ID *)ob, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
 
        return OPERATOR_FINISHED;
@@ -808,6 +823,7 @@ static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
 
        /* note, notifier might evolve */
        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
 
        /* done */
        return OPERATOR_FINISHED;
@@ -875,6 +891,7 @@ static int armature_layers_exec(bContext *C, wmOperator *op)
 
        /* note, notifier might evolve */
        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
 
        return OPERATOR_FINISHED;
 }
@@ -903,7 +920,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot)
 /* Present a popup to get the layers that should be used */
 static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+       int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
 
        /* get layers that are active already */
        CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
@@ -949,6 +966,7 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op)
 
        /* note, notifier might evolve */
        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+       DEG_id_tag_update((ID *)ob->data, DEG_TAG_COPY_ON_WRITE);
 
        return OPERATOR_FINISHED;
 }
@@ -1004,7 +1022,6 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
 static int armature_bone_layers_exec(bContext *C, wmOperator *op)
 {
        Object *ob = CTX_data_edit_object(C);
-       bArmature *arm = (ob) ? ob->data : NULL;
        PointerRNA ptr;
        int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
 
@@ -1012,7 +1029,7 @@ static int armature_bone_layers_exec(bContext *C, wmOperator *op)
        RNA_boolean_get_array(op->ptr, "layers", layers);
 
        /* set layers of pchans based on the values set in the operator props */
-       CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+       CTX_DATA_BEGIN_WITH_ID (C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
        {
                /* get pointer for pchan, and write flags this way */
                RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
@@ -1048,55 +1065,54 @@ void ARMATURE_OT_bone_layers(wmOperatorType *ot)
 /* ********************************************** */
 /* Show/Hide Bones */
 
-static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+static int hide_pose_bone_fn(Object *ob, Bone *bone, void *ptr)
 {
        bArmature *arm = ob->data;
-
+       const bool hide_select = (bool)GET_INT_FROM_POINTER(ptr);
+       int count = 0;
        if (arm->layer & bone->layer) {
-               if (bone->flag & BONE_SELECTED) {
+               if (((bone->flag & BONE_SELECTED) != 0) == hide_select) {
                        bone->flag |= BONE_HIDDEN_P;
+                       /* only needed when 'hide_select' is true, but harmless. */
                        bone->flag &= ~BONE_SELECTED;
-                       if (arm->act_bone == bone)
-                               arm->act_bone = NULL;
-               }
-       }
-       return 0;
-}
-
-static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
-       bArmature *arm = ob->data;
-
-       if (arm->layer & bone->layer) {
-               /* hrm... typo here? */
-               if ((bone->flag & BONE_SELECTED) == 0) {
-                       bone->flag |= BONE_HIDDEN_P;
-                       if (arm->act_bone == bone)
+                       if (arm->act_bone == bone) {
                                arm->act_bone = NULL;
+                       }
+                       count += 1;
                }
        }
-       return 0;
+       return count;
 }
 
 /* active object is armature in posemode, poll checked */
 static int pose_hide_exec(bContext *C, wmOperator *op)
 {
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-       bArmature *arm = ob->data;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       uint objects_len;
+       Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len);
+       bool changed_multi = false;
 
-       if (ob->proxy != NULL) {
-               BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
-       }
+       const int hide_select = !RNA_boolean_get(op->ptr, "unselected");
+       void     *hide_select_p = SET_INT_IN_POINTER(hide_select);
 
-       if (RNA_boolean_get(op->ptr, "unselected"))
-               bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
-       else
-               bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb);
+       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+               Object *ob_iter = objects[ob_index];
+               bArmature *arm = ob_iter->data;
 
-       /* note, notifier might evolve */
-       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+               if (ob_iter->proxy != NULL) {
+                       BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
+               }
 
-       return OPERATOR_FINISHED;
+               bool changed = bone_looper(ob_iter, arm->bonebase.first, hide_select_p, hide_pose_bone_fn) != 0;
+               if (changed) {
+                       changed_multi = true;
+                       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
+                       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+               }
+       }
+       MEM_freeN(objects);
+
+       return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 }
 
 void POSE_OT_hide(wmOperatorType *ot)
@@ -1122,32 +1138,44 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *data)
        const bool select = GET_INT_FROM_POINTER(data);
 
        bArmature *arm = ob->data;
-
+       int count = 0;
        if (arm->layer & bone->layer) {
                if (bone->flag & BONE_HIDDEN_P) {
                        if (!(bone->flag & BONE_UNSELECTABLE)) {
                                SET_FLAG_FROM_TEST(bone->flag, select, BONE_SELECTED);
                        }
                        bone->flag &= ~BONE_HIDDEN_P;
+                       count += 1;
                }
        }
 
-       return 0;
+       return count;
 }
 
 /* active object is armature in posemode, poll checked */
 static int pose_reveal_exec(bContext *C, wmOperator *op)
 {
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-       bArmature *arm = ob->data;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       uint objects_len;
+       Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len);
+       bool changed_multi = false;
        const bool select = RNA_boolean_get(op->ptr, "select");
+       void *select_p = SET_INT_IN_POINTER(select);
 
-       bone_looper(ob, arm->bonebase.first, SET_INT_IN_POINTER(select), show_pose_bone_cb);
+       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+               Object *ob_iter = objects[ob_index];
+               bArmature *arm = ob_iter->data;
 
-       /* note, notifier might evolve */
-       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+               bool changed = bone_looper(ob_iter, arm->bonebase.first, select_p, show_pose_bone_cb);
+               if (changed) {
+                       changed_multi = true;
+                       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
+                       DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+               }
+       }
+       MEM_freeN(objects);
 
-       return OPERATOR_FINISHED;
+       return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 }
 
 void POSE_OT_reveal(wmOperatorType *ot)
@@ -1173,27 +1201,34 @@ void POSE_OT_reveal(wmOperatorType *ot)
 static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Scene *scene = CTX_data_scene(C);
-       Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
        KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
 
-       /* loop through all selected pchans, flipping and keying (as needed) */
-       CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
-       {
-               /* only if bone is using quaternion rotation */
-               if (pchan->rotmode == ROT_MODE_QUAT) {
-                       /* quaternions have 720 degree range */
-                       negate_v4(pchan->quat);
+       bool changed_multi = false;
 
-                       ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
-               }
-       }
-       CTX_DATA_END;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) {
+               bool changed = false;
+               /* loop through all selected pchans, flipping and keying (as needed) */
+               FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
+                       /* only if bone is using quaternion rotation */
+                       if (pchan->rotmode == ROT_MODE_QUAT) {
+                               changed = true;
+                               /* quaternions have 720 degree range */
+                               negate_v4(pchan->quat);
 
-       /* notifiers and updates */
-       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+                               ED_autokeyframe_pchan(C, scene, ob_iter, pchan, ks);
+                       }
+               } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
 
-       return OPERATOR_FINISHED;
+               if (changed) {
+                       changed_multi = true;
+                       /* notifiers and updates */
+                       DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+                       WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
+               }
+       } FOREACH_OBJECT_IN_MODE_END;
+
+       return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 }
 
 void POSE_OT_quaternions_flip(wmOperatorType *ot)
@@ -1211,3 +1246,34 @@ void POSE_OT_quaternions_flip(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/* -------------------------------------------------------------------- */
+/** \name Toggle Bone selection Overlay Operator
+ * \{ */
+
+static int toggle_bone_selection_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       View3D *v3d = CTX_wm_view3d(C);
+       v3d->overlay.flag ^= V3D_OVERLAY_BONE_SELECTION;
+       ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
+       WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+       return OPERATOR_FINISHED;
+}
+
+static int pose_select_linked_poll(bContext *C)
+{
+       return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
+}
+
+void POSE_OT_toggle_bone_selection_overlay(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Toggle Bone Selection Overlay";
+       ot->description = "Toggle bone selection overlay of the viewport";
+       ot->idname = "POSE_OT_toggle_bone_selection_overlay";
+
+       /* api callbacks */
+       ot->exec = toggle_bone_selection_exec;
+       ot->poll = pose_select_linked_poll;
+}
+
+/** \} */