From a43359eb88e898c8e1960564705bf80104b60295 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 7 Aug 2025 15:54:58 +0200 Subject: [PATCH] Anim: Store pose bone visibility flag on pose bone This PR adds a flag to the pose bone that determines its visibility. Doing so allows to hide a pose bone and * don't affect other instances of the same armature * save the visibility even if the rig is linked The visibility of the bone in object mode is now also determined by the pose bone whereas before it was the `Bone`. **This breaks backwards compatibility** on the Python API since the visibility property, on the `Bone` behaves differently now as it hides the edit bone instead of the pose bone. In order to remove all active uses of `BONE_HIDDEN_P` the changes in `armature_skinning.cc` are required. Part of #138482 Pull Request: https://projects.blender.org/blender/blender/pulls/139167 --- scripts/startup/bl_ui/properties_data_bone.py | 13 +-- source/blender/animrig/ANIM_armature.hh | 11 ++- source/blender/animrig/CMakeLists.txt | 1 + source/blender/animrig/intern/armature.cc | 41 +++++++++ source/blender/blenkernel/BKE_armature.hh | 4 +- .../blenloader/intern/versioning_500.cc | 16 ++++ .../draw/engines/overlay/overlay_armature.cc | 6 +- .../editors/armature/armature_skinning.cc | 83 +++++++++++-------- source/blender/editors/armature/pose_edit.cc | 70 ++++++---------- .../blender/editors/armature/pose_select.cc | 4 +- .../blender/editors/object/object_select.cc | 2 +- .../editors/space_outliner/outliner_draw.cc | 24 ++++-- .../editors/space_outliner/outliner_select.cc | 2 +- .../editors/space_outliner/outliner_tools.cc | 4 +- source/blender/makesdna/DNA_action_types.h | 1 + .../blender/makesrna/intern/rna_armature.cc | 15 +--- source/blender/makesrna/intern/rna_pose.cc | 16 ++++ 17 files changed, 200 insertions(+), 113 deletions(-) create mode 100644 source/blender/animrig/intern/armature.cc diff --git a/scripts/startup/bl_ui/properties_data_bone.py b/scripts/startup/bl_ui/properties_data_bone.py index 247ffd59a0c..2d5a6223bed 100644 --- a/scripts/startup/bl_ui/properties_data_bone.py +++ b/scripts/startup/bl_ui/properties_data_bone.py @@ -323,17 +323,18 @@ class BONE_PT_display(BoneButtonsPanel, Panel): bone = context.bone col = layout.column() - col.prop(bone, "hide", text="Hide", toggle=False) + # Figure out the pose bone. + ob = context.object + pose_bone = ob and ob.pose.bones[bone.name] hide_select_sub = col.column() - hide_select_sub.active = not bone.hide + if pose_bone: + col.prop(pose_bone, "hide", text="Hide", toggle=False) + hide_select_sub.active = not pose_bone.hide hide_select_sub.prop(bone, "hide_select", invert_checkbox=True) col.prop(bone, "display_type", text="Display As") - # Figure out the pose bone. - ob = context.object - if not ob: + if not pose_bone: return - pose_bone = ob.pose.bones[bone.name] # Allow the layout to use the space normally occupied by the 'set a key' diamond. layout.use_property_decorate = False diff --git a/source/blender/animrig/ANIM_armature.hh b/source/blender/animrig/ANIM_armature.hh index 931926f43ac..95f0486c128 100644 --- a/source/blender/animrig/ANIM_armature.hh +++ b/source/blender/animrig/ANIM_armature.hh @@ -27,7 +27,8 @@ inline bool bone_is_visible(const bArmature *armature, const Bone *bone) inline bool bone_is_visible_pchan(const bArmature *armature, const bPoseChannel *pchan) { - return bone_is_visible(armature, pchan->bone); + const bool bone_itself_visible = (pchan->drawflag & PCHAN_DRAW_HIDDEN) == 0; + return bone_itself_visible && ANIM_bone_in_visible_collection(armature, pchan->bone); } inline bool bone_is_visible_editbone(const bArmature *armature, const EditBone *ebone) @@ -55,4 +56,12 @@ inline bool bone_is_selected(const bArmature *armature, const EditBone *ebone) return (ebone->flag & BONE_SELECTED) && bone_is_visible_editbone(armature, ebone); } +/** + * Iterates all descendents of the given pose bone including the bone itself. Iterates breadth + * first. + */ +void pose_bone_descendent_iterator(bPose &pose, + bPoseChannel &pose_bone, + FunctionRef callback); + } // namespace blender::animrig diff --git a/source/blender/animrig/CMakeLists.txt b/source/blender/animrig/CMakeLists.txt index afcc1fec204..3bfec81eaf1 100644 --- a/source/blender/animrig/CMakeLists.txt +++ b/source/blender/animrig/CMakeLists.txt @@ -24,6 +24,7 @@ set(SRC intern/action_selection.cc intern/anim_rna.cc intern/animdata.cc + intern/armature.cc intern/bone_collections.cc intern/bonecolor.cc intern/driver.cc diff --git a/source/blender/animrig/intern/armature.cc b/source/blender/animrig/intern/armature.cc new file mode 100644 index 00000000000..f3183700d19 --- /dev/null +++ b/source/blender/animrig/intern/armature.cc @@ -0,0 +1,41 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup animrig + */ + +#include + +#include "ANIM_armature.hh" +#include "BKE_action.hh" +#include "BLI_listbase.h" + +namespace blender::animrig { + +void pose_bone_descendent_iterator(bPose &pose, + bPoseChannel &pose_bone, + FunctionRef callback) +{ + /* Needed for fast name lookups. */ + BKE_pose_channels_hash_ensure(&pose); + + std::deque to_visit = {&pose_bone}; + while (!to_visit.empty()) { + bPoseChannel *descendant = to_visit.front(); + to_visit.pop_front(); + callback(*descendant); + LISTBASE_FOREACH (Bone *, child_bone, &descendant->bone->childbase) { + bPoseChannel *child_pose_bone = BKE_pose_channel_find_name(&pose, child_bone->name); + if (!child_pose_bone) { + /* Can happen if the pose is not rebuilt. */ + BLI_assert_unreachable(); + continue; + } + to_visit.push_back(child_pose_bone); + } + } +}; + +} // namespace blender::animrig diff --git a/source/blender/blenkernel/BKE_armature.hh b/source/blender/blenkernel/BKE_armature.hh index d2cfe707d06..3af21bc30aa 100644 --- a/source/blender/blenkernel/BKE_armature.hh +++ b/source/blender/blenkernel/BKE_armature.hh @@ -576,7 +576,7 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, for (bPoseChannel *_pchan = (bPoseChannel *)(_ob)->pose->chanbase.first; _pchan; \ _pchan = _pchan->next) \ { \ - if (blender::animrig::bone_is_visible(((bArmature *)(_ob)->data), (_pchan)->bone) && \ + if (blender::animrig::bone_is_visible_pchan(((bArmature *)(_ob)->data), _pchan) && \ ((_pchan)->bone->flag & BONE_SELECTED)) \ { #define FOREACH_PCHAN_SELECTED_IN_OBJECT_END \ @@ -588,7 +588,7 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, for (bPoseChannel *_pchan = (bPoseChannel *)(_ob)->pose->chanbase.first; _pchan; \ _pchan = _pchan->next) \ { \ - if (blender::animrig::bone_is_visible(((bArmature *)(_ob)->data), (_pchan)->bone)) { + if (blender::animrig::bone_is_visible_pchan(((bArmature *)(_ob)->data), _pchan)) { #define FOREACH_PCHAN_VISIBLE_IN_OBJECT_END \ } \ } \ diff --git a/source/blender/blenloader/intern/versioning_500.cc b/source/blender/blenloader/intern/versioning_500.cc index 3fa41f2b61f..f2d2f285d4b 100644 --- a/source/blender/blenloader/intern/versioning_500.cc +++ b/source/blender/blenloader/intern/versioning_500.cc @@ -1585,6 +1585,22 @@ void do_versions_after_linking_500(FileData *fd, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 54)) { + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + if (object->type != OB_ARMATURE) { + continue; + } + LISTBASE_FOREACH (bPoseChannel *, pose_bone, &object->pose->chanbase) { + if (pose_bone->bone->flag & BONE_HIDDEN_P) { + pose_bone->drawflag |= PCHAN_DRAW_HIDDEN; + } + else { + pose_bone->drawflag &= ~PCHAN_DRAW_HIDDEN; + } + } + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/draw/engines/overlay/overlay_armature.cc b/source/blender/draw/engines/overlay/overlay_armature.cc index 9ff37650da3..df8bd474172 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.cc +++ b/source/blender/draw/engines/overlay/overlay_armature.cc @@ -2022,11 +2022,11 @@ void Armatures::draw_armature_pose(Armatures::DrawContext *ctx) for (bPoseChannel *pchan = static_cast(ob->pose->chanbase.first); pchan; pchan = pchan->next, index += 0x10000) { - Bone *bone = pchan->bone; - if (!blender::animrig::bone_is_visible(&arm, bone)) { + if (!blender::animrig::bone_is_visible_pchan(&arm, pchan)) { continue; } + Bone *bone = pchan->bone; const bool draw_dofs = !is_pose_select && ctx->show_relations && (ctx->draw_mode == ARM_DRAW_MODE_POSE) && (bone->flag & BONE_SELECTED) && @@ -2042,7 +2042,7 @@ void Armatures::draw_armature_pose(Armatures::DrawContext *ctx) } eBone_Flag boneflag = eBone_Flag(bone->flag); - if (bone->parent && !blender::animrig::bone_is_visible(&arm, bone->parent)) { + if (pchan->parent && !blender::animrig::bone_is_visible_pchan(&arm, pchan->parent)) { /* Avoid drawing connection line to hidden parent. */ boneflag &= ~BONE_CONNECTED; } diff --git a/source/blender/editors/armature/armature_skinning.cc b/source/blender/editors/armature/armature_skinning.cc index c906f935ae6..4392fefbabe 100644 --- a/source/blender/editors/armature/armature_skinning.cc +++ b/source/blender/editors/armature/armature_skinning.cc @@ -76,11 +76,14 @@ static int bone_skinnable_cb(Object * /*ob*/, Bone *bone, void *datap) bool is_weight_paint; } *data = static_cast(datap); - if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) { + bPoseChannel *pose_bone = BKE_pose_channel_find_name(data->armob->pose, bone->name); + if (!pose_bone) { + return 0; + } + + if (!(data->is_weight_paint) || !(pose_bone->drawflag & PCHAN_DRAW_HIDDEN)) { if (!(bone->flag & BONE_NO_DEFORM)) { - if (data->heat && data->armob->pose && - BKE_pose_channel_find_name(data->armob->pose, bone->name)) - { + if (data->heat && data->armob->pose && pose_bone) { segments = bone->segments; } else { @@ -149,43 +152,49 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) int heat; bool is_weight_paint; } *data = static_cast(datap); + + if (bone->flag & BONE_NO_DEFORM) { + return 0; + } + bArmature *arm = static_cast(data->armob->data); + const bPoseChannel *pose_bone = BKE_pose_channel_find_name(data->armob->pose, bone->name); + if (!pose_bone) { + return 0; + } - if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) { - if (!(bone->flag & BONE_NO_DEFORM)) { - if (data->heat && data->armob->pose && - BKE_pose_channel_find_name(data->armob->pose, bone->name)) - { - segments = bone->segments; - } - else { - segments = 1; - } + if (data->is_weight_paint && (pose_bone->drawflag & PCHAN_DRAW_HIDDEN)) { + return 0; + } - if (!data->is_weight_paint || - (ANIM_bone_in_visible_collection(arm, bone) && (bone->flag & BONE_SELECTED))) - { - if (!(defgroup = BKE_object_defgroup_find_name(ob, bone->name))) { - defgroup = BKE_object_defgroup_add_name(ob, bone->name); - } - else if (defgroup->flag & DG_LOCK_WEIGHT) { - /* In case vgroup already exists and is locked, do not modify it here. See #43814. */ - defgroup = nullptr; - } - } + if (data->heat) { + segments = bone->segments; + } + else { + segments = 1; + } - if (data->list != nullptr) { - hgroup = (bDeformGroup ***)&data->list; - - for (a = 0; a < segments; a++) { - **hgroup = defgroup; - (*hgroup)++; - } - } - return segments; + if (!data->is_weight_paint || + (ANIM_bone_in_visible_collection(arm, bone) && (bone->flag & BONE_SELECTED))) + { + if (!(defgroup = BKE_object_defgroup_find_name(ob, bone->name))) { + defgroup = BKE_object_defgroup_add_name(ob, bone->name); + } + else if (defgroup->flag & DG_LOCK_WEIGHT) { + /* In case vgroup already exists and is locked, do not modify it here. See #43814. */ + defgroup = nullptr; } } - return 0; + + if (data->list != nullptr) { + hgroup = (bDeformGroup ***)&data->list; + + for (a = 0; a < segments; a++) { + **hgroup = defgroup; + (*hgroup)++; + } + } + return segments; } static void envelope_bone_weighting(Object *ob, @@ -305,6 +314,10 @@ static void add_verts_to_dgroups(ReportList *reports, looper_data.list = nullptr; looper_data.is_weight_paint = wpmode; + if (!par->pose) { + BKE_pose_rebuild(nullptr, par, arm, false); + } + BKE_pose_channels_hash_ensure(par->pose); /* count the number of skinnable bones */ numbones = bone_looper( ob, static_cast(arm->bonebase.first), &looper_data, bone_skinnable_cb); diff --git a/source/blender/editors/armature/pose_edit.cc b/source/blender/editors/armature/pose_edit.cc index 68b4b2e86ea..e74cc50f419 100644 --- a/source/blender/editors/armature/pose_edit.cc +++ b/source/blender/editors/armature/pose_edit.cc @@ -663,22 +663,6 @@ void POSE_OT_rotation_mode_set(wmOperatorType *ot) /* ********************************************** */ /* Show/Hide Bones */ -static int hide_pose_bone_fn(Object *ob, Bone *bone, void *ptr) -{ - bArmature *arm = static_cast(ob->data); - const bool hide_select = bool(POINTER_AS_INT(ptr)); - int count = 0; - if (ANIM_bone_in_visible_collection(arm, bone)) { - 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; - count += 1; - } - } - return count; -} - /* active object is armature in posemode, poll checked */ static wmOperatorStatus pose_hide_exec(bContext *C, wmOperator *op) { @@ -688,15 +672,22 @@ static wmOperatorStatus pose_hide_exec(bContext *C, wmOperator *op) bool changed_multi = false; const int hide_select = !RNA_boolean_get(op->ptr, "unselected"); - void *hide_select_p = POINTER_FROM_INT(hide_select); for (Object *ob_iter : objects) { + bool changed = false; bArmature *arm = static_cast(ob_iter->data); + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) { + if (!ANIM_bone_in_visible_collection(arm, pchan->bone)) { + continue; + } + if (((pchan->bone->flag & BONE_SELECTED) != 0) != hide_select) { + continue; + } + pchan->drawflag |= PCHAN_DRAW_HIDDEN; + pchan->bone->flag &= ~BONE_SELECTED; + changed = true; + } - bool changed = bone_looper(ob_iter, - static_cast(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); @@ -725,25 +716,6 @@ void POSE_OT_hide(wmOperatorType *ot) RNA_def_boolean(ot->srna, "unselected", false, "Unselected", ""); } -static int show_pose_bone_cb(Object *ob, Bone *bone, void *data) -{ - const bool select = POINTER_AS_INT(data); - - bArmature *arm = static_cast(ob->data); - int count = 0; - if (ANIM_bone_in_visible_collection(arm, bone)) { - 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 count; -} - /* active object is armature in posemode, poll checked */ static wmOperatorStatus pose_reveal_exec(bContext *C, wmOperator *op) { @@ -752,13 +724,25 @@ static wmOperatorStatus pose_reveal_exec(bContext *C, wmOperator *op) Vector objects = BKE_object_pose_array_get_unique(scene, view_layer, CTX_wm_view3d(C)); bool changed_multi = false; const bool select = RNA_boolean_get(op->ptr, "select"); - void *select_p = POINTER_FROM_INT(select); for (Object *ob_iter : objects) { bArmature *arm = static_cast(ob_iter->data); - bool changed = bone_looper( - ob_iter, static_cast(arm->bonebase.first), select_p, show_pose_bone_cb); + bool changed = false; + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) { + if (!ANIM_bone_in_visible_collection(arm, pchan->bone)) { + continue; + } + if ((pchan->drawflag & PCHAN_DRAW_HIDDEN) == 0) { + continue; + } + if (!(pchan->bone->flag & BONE_UNSELECTABLE)) { + SET_FLAG_FROM_TEST(pchan->bone->flag, select, BONE_SELECTED); + } + pchan->drawflag &= ~PCHAN_DRAW_HIDDEN; + changed = true; + } + if (changed) { changed_multi = true; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter); diff --git a/source/blender/editors/armature/pose_select.cc b/source/blender/editors/armature/pose_select.cc index 87e169a19ad..39d69b35e10 100644 --- a/source/blender/editors/armature/pose_select.cc +++ b/source/blender/editors/armature/pose_select.cc @@ -624,7 +624,9 @@ static wmOperatorStatus pose_select_parent_exec(bContext *C, wmOperator * /*op*/ pchan = CTX_data_active_pose_bone(C); if (pchan) { parent = pchan->parent; - if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { + if ((parent) && !(parent->drawflag & PCHAN_DRAW_HIDDEN) && + !(parent->bone->flag & BONE_UNSELECTABLE)) + { parent->bone->flag |= BONE_SELECTED; arm->act_bone = parent->bone; } diff --git a/source/blender/editors/object/object_select.cc b/source/blender/editors/object/object_select.cc index d0fc907c324..be0e33791b1 100644 --- a/source/blender/editors/object/object_select.cc +++ b/source/blender/editors/object/object_select.cc @@ -326,7 +326,7 @@ bool jump_to_bone(bContext *C, Object *ob, const char *bone_name, const bool rev if (pchan != nullptr) { if (reveal_hidden) { /* Unhide the bone. */ - pchan->bone->flag &= ~BONE_HIDDEN_P; + pchan->drawflag &= ~PCHAN_DRAW_HIDDEN; ANIM_armature_bonecoll_show_from_pchan(arm, pchan); } diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index da78b7412be..2b59bb2457b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -29,6 +29,7 @@ #include "BLT_translation.hh" +#include "BKE_action.hh" #include "BKE_armature.hh" #include "BKE_context.hh" #include "BKE_curve.hh" @@ -49,6 +50,7 @@ #include "BKE_report.hh" #include "BKE_scene.hh" +#include "ANIM_armature.hh" #include "ANIM_bone_collections.hh" #include "ANIM_keyframing.hh" @@ -177,12 +179,20 @@ static void restrictbutton_r_lay_fn(bContext *C, void *poin, void * /*poin2*/) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin); } -static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void * /*poin2*/) +static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *poin2) { - Bone *bone = (Bone *)poin; - + const Object *ob = (Object *)poin; + bPoseChannel *pchan = (bPoseChannel *)poin2; if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); + blender::animrig::pose_bone_descendent_iterator( + *ob->pose, *pchan, [&](bPoseChannel &descendent) { + if (pchan->drawflag & PCHAN_DRAW_HIDDEN) { + descendent.drawflag |= PCHAN_DRAW_HIDDEN; + } + else { + descendent.drawflag &= ~PCHAN_DRAW_HIDDEN; + } + }); } } @@ -1135,7 +1145,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute"); - props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide"); + props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_PoseBone, "hide"); props.initialized = true; } @@ -1401,7 +1411,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Object *ob = (Object *)tselem->id; bArmature *arm = static_cast(ob->data); - PointerRNA ptr = RNA_pointer_create_discrete(&arm->id, &RNA_Bone, bone); + PointerRNA ptr = RNA_pointer_create_discrete(&arm->id, &RNA_PoseBone, pchan); if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) { bt = uiDefIconButR_prop(block, @@ -1419,7 +1429,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, TIP_("Restrict visibility in the 3D View\n" " \u2022 Shift to set children")); - UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, nullptr); + UI_but_func_set(bt, restrictbutton_bone_visibility_fn, ob, pchan); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index f3f0e950436..e7d183e0962 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -577,7 +577,7 @@ static void tree_element_posechannel_activate(bContext *C, pchan->bone->flag &= ~BONE_SELECTED; } else { - if (blender::animrig::bone_is_visible(arm, pchan->bone)) { + if (blender::animrig::bone_is_visible_pchan(arm, pchan)) { pchan->bone->flag |= BONE_SELECTED; } arm->act_bone = pchan->bone; diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index cf0b527d035..1abd6c7665a 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -2096,11 +2096,11 @@ static void pchan_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, voi pchan->bone->flag &= ~BONE_SELECTED; } else if (event == OL_DOP_HIDE) { - pchan->bone->flag |= BONE_HIDDEN_P; + pchan->drawflag |= PCHAN_DRAW_HIDDEN; pchan->bone->flag &= ~BONE_SELECTED; } else if (event == OL_DOP_UNHIDE) { - pchan->bone->flag &= ~BONE_HIDDEN_P; + pchan->drawflag &= ~PCHAN_DRAW_HIDDEN; } } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index cc42928e80d..06f3b085df5 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -504,6 +504,7 @@ typedef enum ePchan_IkFlag { /* PoseChannel->drawflag */ typedef enum ePchan_DrawFlag { PCHAN_DRAW_NO_CUSTOM_BONE_SIZE = (1 << 0), + PCHAN_DRAW_HIDDEN = (1 << 1), } ePchan_DrawFlag; /* NOTE: It doesn't take custom_scale_xyz into account. */ diff --git a/source/blender/makesrna/intern/rna_armature.cc b/source/blender/makesrna/intern/rna_armature.cc index dcf1758a7b9..03e97438212 100644 --- a/source/blender/makesrna/intern/rna_armature.cc +++ b/source/blender/makesrna/intern/rna_armature.cc @@ -720,11 +720,9 @@ static void rna_Bone_hide_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA { bArmature *arm = (bArmature *)ptr->owner_id; Bone *bone = (Bone *)ptr->data; - - if (bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE)) { + if (bone->flag & (BONE_HIDDEN_A | BONE_UNSELECTABLE)) { bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } - WM_main_add_notifier(NC_OBJECT | ND_POSE, arm); DEG_id_tag_update(&arm->id, ID_RECALC_SYNC_TO_EVAL); } @@ -1778,16 +1776,11 @@ static void rna_def_bone(BlenderRNA *brna) RNA_define_lib_overridable(true); - /* XXX should we define this in PoseChannel wrapping code instead? - * But PoseChannels directly get some of their flags from here... */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_HIDDEN_P); - RNA_def_property_ui_text( - prop, - "Hide", - "Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes)"); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_HIDDEN_A); + RNA_def_property_ui_text(prop, "Hide", "Bone is not visible when it is in Edit Mode"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); - RNA_def_property_update(prop, 0, "rna_Bone_hide_update"); + RNA_def_property_update(prop, 0, "rna_EditBone_hide_update"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_SELECTED); diff --git a/source/blender/makesrna/intern/rna_pose.cc b/source/blender/makesrna/intern/rna_pose.cc index 53b32e208b1..4af602e375f 100644 --- a/source/blender/makesrna/intern/rna_pose.cc +++ b/source/blender/makesrna/intern/rna_pose.cc @@ -95,6 +95,14 @@ static void rna_Pose_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr WM_main_add_notifier(NC_OBJECT | ND_POSE, ptr->owner_id); } +static void rna_PoseBone_visibility_update(Main * /* bmain */, + Scene * /* scene */, + PointerRNA *ptr) +{ + DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_OBJECT | ND_POSE, ptr->owner_id); +} + static void rna_Pose_dependency_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr) { DEG_relations_tag_update(bmain); @@ -1169,6 +1177,14 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop, "Scale to Bone Length", "Scale the custom object by the bone length"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); + + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_boolean_sdna(prop, nullptr, "drawflag", PCHAN_DRAW_HIDDEN); + RNA_def_property_ui_text(prop, "Hide", "Bone is not visible except for Edit Mode"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); + RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_PoseBone_visibility_update"); + prop = RNA_def_property(srna, "custom_shape_transform", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, nullptr, "custom_tx"); RNA_def_property_struct_type(prop, "PoseBone");