Anim: move bone colors from bone groups to individual bones
Move control over the color of bones from bone groups to the bones themselves. Instead of using bone groups (which are defined on the pose, and thus owned by the object), the color is stored on: - the bone (`struct Bone`, or RNA `armature.bones['bone_name'].color`) - a possible override on the pose bone (`struct bPoseChannel`, or RNA `ob.pose.bones['bone_name'].color`). When the pose bone is set to its default color, the color is determined by the armature bone. In armature edit mode, the armature bone colors are always used, as then the pose data is unavailable. Versioning code converts bone group colors to bone colors. If the Armature has a single user, the group color is stored on the bones directly. If it has multiple users, the group colors will be stored on the pose bones instead. The bone group color is not removed from DNA for forward compatibility, that is, to avoid immediate dataloss when saving a 3.6 file with 4.0. This is part of the replacement of bone groups & armature layers with bone collections. See the design task at #108941. Pull request: https://projects.blender.org/blender/blender/pulls/109976
This commit is contained in:
committed by
Nathan Vegdahl
parent
c9621a002d
commit
042c5347f4
@@ -101,11 +101,6 @@ class DATA_UL_bone_groups(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, _icon, _active_data, _active_propname, _index):
|
||||
layout.prop(item, "name", text="", emboss=False, icon='GROUP_BONE')
|
||||
|
||||
if item.is_custom_color_set or item.color_set == 'DEFAULT':
|
||||
layout.prop(item, "color_set", icon_only=True, icon='COLOR')
|
||||
else:
|
||||
layout.prop(item, "color_set", icon_only=True)
|
||||
|
||||
|
||||
class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
|
||||
bl_label = "Bone Groups"
|
||||
@@ -148,21 +143,6 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
|
||||
col.operator("pose.group_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("pose.group_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
if group.is_custom_color_set:
|
||||
col = layout.column()
|
||||
split = col.split(factor=0.4)
|
||||
|
||||
col = split.column()
|
||||
row = col.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Custom Colors")
|
||||
|
||||
col = split.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.prop(group.colors, "normal", text="")
|
||||
row.prop(group.colors, "select", text="")
|
||||
row.prop(group.colors, "active", text="")
|
||||
|
||||
row = layout.row()
|
||||
|
||||
sub = row.row(align=True)
|
||||
|
||||
@@ -258,7 +258,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.bone
|
||||
return context.bone or context.edit_bone
|
||||
|
||||
def draw(self, context):
|
||||
# note. this works ok in edit-mode but isn't
|
||||
@@ -266,13 +266,55 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
bone = context.bone
|
||||
if bone is None:
|
||||
bone = context.edit_bone
|
||||
if context.bone is None:
|
||||
self.draw_edit_bone(context, layout)
|
||||
else:
|
||||
self.draw_bone(context, layout)
|
||||
|
||||
if bone:
|
||||
col = layout.column()
|
||||
col.prop(bone, "hide", text="Hide", toggle=False)
|
||||
def draw_bone(self, context, layout):
|
||||
bone = context.bone
|
||||
|
||||
col = layout.column()
|
||||
col.prop(bone, "hide", text="Hide", toggle=False)
|
||||
|
||||
# Figure out the pose bone.
|
||||
ob = context.object
|
||||
if not ob:
|
||||
return
|
||||
pose_bone = ob.pose.bones[bone.name]
|
||||
|
||||
layout.prop(bone.color, 'palette', text='Edit Bone Color')
|
||||
self.draw_bone_color_ui(layout, bone.color)
|
||||
layout.prop(pose_bone.color, 'palette', text='Pose Bone Color')
|
||||
self.draw_bone_color_ui(layout, pose_bone.color)
|
||||
|
||||
def draw_edit_bone(self, context, layout):
|
||||
bone = context.edit_bone
|
||||
if bone is None:
|
||||
return
|
||||
|
||||
col = layout.column()
|
||||
col.prop(bone, "hide", text="Hide", toggle=False)
|
||||
layout.prop(bone.color, 'palette', text='Edit Bone Color')
|
||||
self.draw_bone_color_ui(layout, bone.color)
|
||||
|
||||
def draw_bone_color_ui(self, layout, bone_color):
|
||||
if not bone_color.is_custom:
|
||||
return
|
||||
|
||||
layout.use_property_split = False
|
||||
split = layout.split(factor=0.4)
|
||||
|
||||
col = split.column()
|
||||
row = col.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Custom Colors")
|
||||
|
||||
col = split.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.prop(bone_color.custom, "normal", text="")
|
||||
row.prop(bone_color.custom, "select", text="")
|
||||
row.prop(bone_color.custom, "active", text="")
|
||||
|
||||
|
||||
class BONE_PT_display_custom_shape(BoneButtonsPanel, Panel):
|
||||
|
||||
56
source/blender/animrig/ANIM_armature_iter.hh
Normal file
56
source/blender/animrig/ANIM_armature_iter.hh
Normal file
@@ -0,0 +1,56 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup animrig
|
||||
*
|
||||
* \brief Iterators for armatures.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This is a C++ header.
|
||||
#endif
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
|
||||
namespace blender::animrig {
|
||||
/**
|
||||
* Call `callback(bone)` for each bone in the list of bones.
|
||||
*
|
||||
* Bones are visited in depth-first order.
|
||||
*
|
||||
* TODO: extend the callback with a `bool` return value to indicate whether the
|
||||
* loop should continue or stop.
|
||||
*/
|
||||
template<typename CB>
|
||||
static void ANIM_armature_foreach_bone(ListBase /* Bone */ *bones, CB callback)
|
||||
{
|
||||
for (Bone *bone : blender::ListBaseWrapper<Bone>(bones)) {
|
||||
callback(bone);
|
||||
ANIM_armature_foreach_bone(&bone->childbase, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `callback(bone)` for each bone in the list of bones.
|
||||
*
|
||||
* Bones are visited in depth-first order.
|
||||
*
|
||||
* TODO: extend the callback with a `bool` return value to indicate whether the
|
||||
* loop should continue or stop.
|
||||
*/
|
||||
template<typename CB>
|
||||
static void ANIM_armature_foreach_bone(const ListBase /* Bone */ *bones, CB callback)
|
||||
{
|
||||
for (const Bone *bone : blender::ConstListBaseWrapper<Bone>(bones)) {
|
||||
callback(bone);
|
||||
ANIM_armature_foreach_bone(&bone->childbase, callback);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace blender::animrig
|
||||
33
source/blender/animrig/ANIM_bonecolor.hh
Normal file
33
source/blender/animrig/ANIM_bonecolor.hh
Normal file
@@ -0,0 +1,33 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup animrig
|
||||
*
|
||||
* \brief C++ part of the BoneColor DNA struct.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This is a C++ header.
|
||||
#endif
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
||||
struct ThemeWireColor;
|
||||
|
||||
namespace blender::animrig {
|
||||
|
||||
/** C++ wrapper for the DNA BoneColor struct. */
|
||||
class BoneColor : public ::BoneColor {
|
||||
public:
|
||||
BoneColor();
|
||||
BoneColor(const BoneColor &other);
|
||||
~BoneColor();
|
||||
|
||||
const ThemeWireColor *effective_color() const;
|
||||
};
|
||||
|
||||
}; // namespace blender::animrig
|
||||
@@ -7,6 +7,7 @@ set(INC
|
||||
intern
|
||||
|
||||
../blenkernel
|
||||
../editors/include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
@@ -14,8 +15,10 @@ set(INC_SYS
|
||||
|
||||
set(SRC
|
||||
intern/bone_collections.cc
|
||||
intern/bonecolor.cc
|
||||
|
||||
ANIM_bone_collections.h
|
||||
ANIM_bonecolor.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
||||
42
source/blender/animrig/intern/bonecolor.cc
Normal file
42
source/blender/animrig/intern/bonecolor.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup animrig
|
||||
*/
|
||||
|
||||
#include "ANIM_bonecolor.hh"
|
||||
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace blender::animrig {
|
||||
|
||||
BoneColor::BoneColor()
|
||||
{
|
||||
this->palette_index = 0;
|
||||
}
|
||||
BoneColor::BoneColor(const BoneColor &other)
|
||||
{
|
||||
this->palette_index = other.palette_index;
|
||||
std::memcpy(&this->custom, &other.custom, sizeof(this->custom));
|
||||
}
|
||||
BoneColor::~BoneColor() {}
|
||||
|
||||
const ThemeWireColor *BoneColor::effective_color() const
|
||||
{
|
||||
const int8_t color_index = this->palette_index;
|
||||
if (color_index == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if (color_index < 0) {
|
||||
return &this->custom;
|
||||
}
|
||||
|
||||
const bTheme *btheme = UI_GetTheme();
|
||||
return &btheme->tarm[(color_index - 1)];
|
||||
}
|
||||
|
||||
}; // namespace blender::animrig
|
||||
@@ -24,6 +24,7 @@ struct bArmature;
|
||||
|
||||
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */
|
||||
struct AnimationEvalContext;
|
||||
struct BoneColor;
|
||||
struct FCurve;
|
||||
struct ID;
|
||||
struct Main;
|
||||
@@ -125,6 +126,19 @@ void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, sho
|
||||
*/
|
||||
void action_group_colors_sync(struct bActionGroup *grp, const struct bActionGroup *ref_grp);
|
||||
|
||||
/**
|
||||
* Set colors used on this action group.
|
||||
*/
|
||||
void action_group_colors_set(struct bActionGroup *grp, const struct BoneColor *color);
|
||||
|
||||
/**
|
||||
* Set colors used on this action group, using the color of the pose bone.
|
||||
*
|
||||
* If `pchan->color` is set to a non-default color, that is used. Otherwise the
|
||||
* armature bone color is used.
|
||||
*/
|
||||
void action_group_colors_set_from_posebone(bActionGroup *grp, const bPoseChannel *pchan);
|
||||
|
||||
/**
|
||||
* Add a new action group with the given name to the action>
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -101,6 +103,8 @@ typedef struct EditBone {
|
||||
/** connected child temporary during drawing */
|
||||
struct EditBone *bbone_child;
|
||||
|
||||
BoneColor color; /* MUST be named the same as in bPoseChannel and Bone structs. */
|
||||
|
||||
/* Used to store temporary data */
|
||||
union {
|
||||
struct EditBone *ebone;
|
||||
|
||||
@@ -261,6 +261,21 @@ PointerRNA CTX_data_pointer_get_type_silent(const bContext *C,
|
||||
const char *member,
|
||||
StructRNA *type);
|
||||
ListBase CTX_data_collection_get(const bContext *C, const char *member);
|
||||
|
||||
/**
|
||||
* For each pointer in collection_pointers, remap it to point to `ptr->propname`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* lb = CTX_data_collection_get(C, "selected_pose_bones"); // lb contains pose bones.
|
||||
* CTX_data_collection_remap_property(lb, "color"); // lb now contains bone colors.
|
||||
*
|
||||
* NOTE: this alters the items contained in the given listbase.
|
||||
* It does not change the listbase itself.
|
||||
*/
|
||||
void CTX_data_collection_remap_property(ListBase /*CollectionPointerLink*/ collection_pointers,
|
||||
const char *propname);
|
||||
|
||||
/**
|
||||
* \param C: Context.
|
||||
* \param use_store: Use 'C->wm.store'.
|
||||
|
||||
@@ -534,6 +534,7 @@ set(SRC
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::animrig
|
||||
bf_asset_system
|
||||
bf_blenfont
|
||||
PRIVATE bf::blenlib
|
||||
|
||||
@@ -62,6 +62,9 @@
|
||||
|
||||
#include "BLO_read_write.hh"
|
||||
|
||||
#include "ANIM_bone_collections.h"
|
||||
#include "ANIM_bonecolor.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"bke.action"};
|
||||
@@ -367,6 +370,32 @@ void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
|
||||
}
|
||||
}
|
||||
|
||||
void action_group_colors_set_from_posebone(bActionGroup *grp, const bPoseChannel *pchan)
|
||||
{
|
||||
if (pchan->color.palette_index == 0) {
|
||||
action_group_colors_set(grp, &pchan->bone->color);
|
||||
}
|
||||
else {
|
||||
action_group_colors_set(grp, &pchan->color);
|
||||
}
|
||||
}
|
||||
|
||||
void action_group_colors_set(bActionGroup *grp, const BoneColor *color)
|
||||
{
|
||||
const blender::animrig::BoneColor &bone_color = color->wrap();
|
||||
|
||||
grp->customCol = bone_color.palette_index;
|
||||
|
||||
const ThemeWireColor *effective_color = bone_color.effective_color();
|
||||
if (effective_color) {
|
||||
/* The drawing code assumes that grp->cs always contains the effective
|
||||
* color. This is why the effective color is always written to it, and why
|
||||
* the above action_group_colors_sync() function exists: it needs to update
|
||||
* grp->cs in case the theme changes. */
|
||||
memcpy(&grp->cs, effective_color, sizeof(grp->cs));
|
||||
}
|
||||
}
|
||||
|
||||
bActionGroup *action_groups_add_new(bAction *act, const char name[])
|
||||
{
|
||||
bActionGroup *agrp;
|
||||
|
||||
@@ -500,6 +500,16 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member)
|
||||
return list;
|
||||
}
|
||||
|
||||
void CTX_data_collection_remap_property(ListBase /*CollectionPointerLink*/ collection_pointers,
|
||||
const char *propname)
|
||||
{
|
||||
LISTBASE_FOREACH (CollectionPointerLink *, link, &collection_pointers) {
|
||||
PointerRNA original_ptr = link->ptr;
|
||||
PointerRNA remapped_ptr = RNA_pointer_get(&original_ptr, propname);
|
||||
link->ptr = remapped_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
int /*eContextResult*/ CTX_data_get(const bContext *C,
|
||||
const char *member,
|
||||
PointerRNA *r_ptr,
|
||||
|
||||
@@ -60,6 +60,7 @@ set(SRC
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::animrig
|
||||
bf_blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::dna
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
@@ -64,6 +65,49 @@ static void version_composite_nodetree_null_id(bNodeTree *ntree, Scene *scene)
|
||||
}
|
||||
}
|
||||
|
||||
/* Move bonegroup color to the individual bones. */
|
||||
static void version_bonegroup_migrate_color(Main *bmain)
|
||||
{
|
||||
using PoseSet = blender::Set<bPose *>;
|
||||
blender::Map<bArmature *, PoseSet> armature_poses;
|
||||
|
||||
/* Gather a mapping from armature to the poses that use it. */
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
|
||||
if (ob->type != OB_ARMATURE || !ob->pose) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
|
||||
BLI_assert_msg(GS(arm->id.name) == ID_AR,
|
||||
"Expected ARMATURE object to have an Armature as data");
|
||||
PoseSet &pose_set = armature_poses.lookup_or_add_default(arm);
|
||||
pose_set.add(ob->pose);
|
||||
}
|
||||
|
||||
/* Move colors from the pose's bonegroup to either the armature bones or the
|
||||
* pose bones, depending on how many poses use the Armature. */
|
||||
for (const PoseSet &pose_set : armature_poses.values()) {
|
||||
/* If the Armature is shared, the bone group colors might be different, and thus they have to
|
||||
* be stored on the pose bones. If the Armature is NOT shared, the bone colors can be stored
|
||||
* directly on the Armature bones. */
|
||||
const bool store_on_armature = pose_set.size() == 1;
|
||||
|
||||
for (bPose *pose : pose_set) {
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
|
||||
const bActionGroup *bgrp = (const bActionGroup *)BLI_findlink(&pose->agroups,
|
||||
(pchan->agrp_index - 1));
|
||||
if (!bgrp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BoneColor &bone_color = store_on_armature ? pchan->bone->color : pchan->color;
|
||||
bone_color.palette_index = bgrp->customCol;
|
||||
memcpy(&bone_color.custom, &bgrp->cs, sizeof(bone_color.custom));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
||||
{
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 9)) {
|
||||
@@ -135,6 +179,10 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "BoneColor", "color")) {
|
||||
version_bonegroup_migrate_color(bmain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "ANIM_bone_collections.h"
|
||||
#include "ANIM_bonecolor.hh"
|
||||
|
||||
#include "UI_resources.hh"
|
||||
|
||||
@@ -121,6 +122,11 @@ class UnifiedBonePtr {
|
||||
UnifiedBonePtr(EditBone *eBone) : eBone_(eBone), is_editbone_(true) {}
|
||||
UnifiedBonePtr(bPoseChannel *pchan) : pchan_(pchan), is_editbone_(false) {}
|
||||
|
||||
const char *name() const
|
||||
{
|
||||
return is_editbone_ ? eBone_->name : pchan_->name;
|
||||
}
|
||||
|
||||
const EditBone *as_editbone() const
|
||||
{
|
||||
BLI_assert_msg(is_editbone_,
|
||||
@@ -218,6 +224,20 @@ class UnifiedBonePtr {
|
||||
{
|
||||
return is_editbone_ ? eBone_->rad_tail : pchan_->bone->rad_tail;
|
||||
}
|
||||
|
||||
const blender::animrig::BoneColor &effective_bonecolor() const
|
||||
{
|
||||
if (is_editbone_) {
|
||||
return eBone_->color.wrap();
|
||||
}
|
||||
|
||||
if (pchan_->color.palette_index == 0) {
|
||||
/* If the pchan has the 'default' color, treat it as a signal to use the underlying bone
|
||||
* color. */
|
||||
return pchan_->bone->color.wrap();
|
||||
}
|
||||
return pchan_->color.wrap();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1075,46 +1095,18 @@ static void drw_shgroup_bone_ik_spline_lines(const ArmatureDrawContext *ctx,
|
||||
* \{ */
|
||||
|
||||
/* This function sets the color-set for coloring a certain bone */
|
||||
static void set_pchan_colorset(ArmatureDrawContext *ctx, Object *ob, bPoseChannel *pchan)
|
||||
static void set_ctx_bcolor(ArmatureDrawContext *ctx, const UnifiedBonePtr bone)
|
||||
{
|
||||
bPose *pose = (ob) ? ob->pose : nullptr;
|
||||
bArmature *arm = (ob) ? static_cast<bArmature *>(ob->data) : nullptr;
|
||||
bActionGroup *grp = nullptr;
|
||||
short color_index = 0;
|
||||
bArmature *arm = static_cast<bArmature *>(ctx->ob->data);
|
||||
|
||||
/* sanity check */
|
||||
if (ELEM(nullptr, ob, arm, pose, pchan)) {
|
||||
if ((arm->flag & ARM_COL_CUSTOM) == 0) {
|
||||
/* Only set a custom color if that's enabled on this armature. */
|
||||
ctx->bcolor = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
/* only try to set custom color if enabled for armature */
|
||||
if (arm->flag & ARM_COL_CUSTOM) {
|
||||
/* currently, a bone can only use a custom color set if its group (if it has one),
|
||||
* has been set to use one
|
||||
*/
|
||||
if (pchan->agrp_index) {
|
||||
grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
|
||||
if (grp) {
|
||||
color_index = grp->customCol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* bcolor is a pointer to the color set to use. If nullptr, then the default
|
||||
* color set (based on the theme colors for 3d-view) is used.
|
||||
*/
|
||||
if (color_index > 0) {
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
ctx->bcolor = &btheme->tarm[(color_index - 1)];
|
||||
}
|
||||
else if (color_index == -1) {
|
||||
/* use the group's own custom color set (grp is always != nullptr here) */
|
||||
ctx->bcolor = &grp->cs;
|
||||
}
|
||||
else {
|
||||
ctx->bcolor = nullptr;
|
||||
}
|
||||
const blender::animrig::BoneColor &bone_color = bone.effective_bonecolor();
|
||||
ctx->bcolor = bone_color.effective_color();
|
||||
}
|
||||
|
||||
/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
|
||||
@@ -1253,18 +1245,14 @@ static const float *get_bone_solid_color(const ArmatureDrawContext *ctx, const e
|
||||
return G_draw.block.color_bone_solid;
|
||||
}
|
||||
|
||||
if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
|
||||
static float disp_color[4];
|
||||
get_pchan_color_solid(ctx->bcolor, disp_color);
|
||||
static float disp_color[4];
|
||||
get_pchan_color_solid(ctx->bcolor, disp_color);
|
||||
|
||||
if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
|
||||
bone_locked_color_shade(disp_color);
|
||||
}
|
||||
|
||||
return disp_color;
|
||||
if (ctx->draw_mode == ARM_DRAW_MODE_POSE && (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
|
||||
bone_locked_color_shade(disp_color);
|
||||
}
|
||||
|
||||
return G_draw.block.color_bone_solid;
|
||||
return disp_color;
|
||||
}
|
||||
|
||||
static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext *ctx,
|
||||
@@ -1643,13 +1631,12 @@ static void draw_axes(const ArmatureDrawContext *ctx,
|
||||
static void draw_points(const ArmatureDrawContext *ctx,
|
||||
const UnifiedBonePtr bone,
|
||||
const eBone_Flag boneflag,
|
||||
const float col_solid[4],
|
||||
const int select_id)
|
||||
{
|
||||
float col_solid_root[4], col_solid_tail[4], col_wire_root[4], col_wire_tail[4];
|
||||
float col_wire_root[4], col_wire_tail[4];
|
||||
float col_hint_root[4], col_hint_tail[4];
|
||||
|
||||
copy_v4_v4(col_solid_root, G_draw.block.color_bone_solid);
|
||||
copy_v4_v4(col_solid_tail, G_draw.block.color_bone_solid);
|
||||
copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : &G_draw.block.color_vertex.x);
|
||||
copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : &G_draw.block.color_vertex.x);
|
||||
|
||||
@@ -1669,16 +1656,19 @@ static void draw_points(const ArmatureDrawContext *ctx,
|
||||
}
|
||||
}
|
||||
else if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
|
||||
const float *solid_color = get_bone_solid_color(ctx, boneflag);
|
||||
const float *wire_color = get_bone_wire_color(ctx, boneflag);
|
||||
copy_v4_v4(col_wire_tail, wire_color);
|
||||
copy_v4_v4(col_wire_root, wire_color);
|
||||
copy_v4_v4(col_solid_tail, solid_color);
|
||||
copy_v4_v4(col_solid_root, solid_color);
|
||||
}
|
||||
|
||||
bone_hint_color_shade(col_hint_root, (ctx->const_color) ? col_solid_root : col_wire_root);
|
||||
bone_hint_color_shade(col_hint_tail, (ctx->const_color) ? col_solid_tail : col_wire_tail);
|
||||
const float *hint_color_shade_root = (ctx->const_color) ?
|
||||
(const float *)G_draw.block.color_bone_solid :
|
||||
col_wire_root;
|
||||
const float *hint_color_shade_tail = (ctx->const_color) ?
|
||||
(const float *)G_draw.block.color_bone_solid :
|
||||
col_wire_tail;
|
||||
bone_hint_color_shade(col_hint_root, hint_color_shade_root);
|
||||
bone_hint_color_shade(col_hint_tail, hint_color_shade_tail);
|
||||
|
||||
/* Draw root point if we are not connected to our parent */
|
||||
|
||||
@@ -1690,14 +1680,14 @@ static void draw_points(const ArmatureDrawContext *ctx,
|
||||
if (is_envelope_draw) {
|
||||
drw_shgroup_bone_envelope(ctx,
|
||||
bone.disp_mat(),
|
||||
col_solid_root,
|
||||
col_solid,
|
||||
col_hint_root,
|
||||
col_wire_root,
|
||||
&bone.rad_head(),
|
||||
&envelope_ignore);
|
||||
}
|
||||
else {
|
||||
drw_shgroup_bone_point(ctx, bone.disp_mat(), col_solid_root, col_hint_root, col_wire_root);
|
||||
drw_shgroup_bone_point(ctx, bone.disp_mat(), col_solid, col_hint_root, col_wire_root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1709,15 +1699,14 @@ static void draw_points(const ArmatureDrawContext *ctx,
|
||||
if (is_envelope_draw) {
|
||||
drw_shgroup_bone_envelope(ctx,
|
||||
bone.disp_mat(),
|
||||
col_solid_tail,
|
||||
col_solid,
|
||||
col_hint_tail,
|
||||
col_wire_tail,
|
||||
&envelope_ignore,
|
||||
&bone.rad_tail());
|
||||
}
|
||||
else {
|
||||
drw_shgroup_bone_point(
|
||||
ctx, bone.disp_tail_mat(), col_solid_tail, col_hint_tail, col_wire_tail);
|
||||
drw_shgroup_bone_point(ctx, bone.disp_tail_mat(), col_solid, col_hint_tail, col_wire_tail);
|
||||
}
|
||||
|
||||
if (select_id != -1) {
|
||||
@@ -2179,7 +2168,7 @@ class ArmatureBoneDrawStrategyOcta : public ArmatureBoneDrawStrategy {
|
||||
DRW_select_load_id(-1);
|
||||
}
|
||||
|
||||
draw_points(ctx, bone, boneflag, select_id);
|
||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2343,7 +2332,7 @@ class ArmatureBoneDrawStrategyBBone : public ArmatureBoneDrawStrategy {
|
||||
}
|
||||
|
||||
if (bone.is_editbone()) {
|
||||
draw_points(ctx, bone, boneflag, select_id);
|
||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2424,7 +2413,7 @@ class ArmatureBoneDrawStrategyEnvelope : public ArmatureBoneDrawStrategy {
|
||||
DRW_select_load_id(-1);
|
||||
}
|
||||
|
||||
draw_points(ctx, bone, boneflag, select_id);
|
||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2485,7 +2474,8 @@ class ArmatureBoneDrawStrategyWire : public ArmatureBoneDrawStrategy {
|
||||
}
|
||||
|
||||
if (bone.is_editbone()) {
|
||||
draw_points(ctx, bone, boneflag, select_id);
|
||||
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2538,7 +2528,7 @@ static ArmatureBoneDrawStrategy &strategy_for_armature_drawtype(const eArmature_
|
||||
/** \name Main Draw Loops
|
||||
* \{ */
|
||||
|
||||
static void draw_armature_edit(const ArmatureDrawContext *ctx)
|
||||
static void draw_armature_edit(ArmatureDrawContext *ctx)
|
||||
{
|
||||
Object *ob = ctx->ob;
|
||||
EditBone *eBone;
|
||||
@@ -2563,10 +2553,7 @@ static void draw_armature_edit(const ArmatureDrawContext *ctx)
|
||||
eBone;
|
||||
eBone = eBone->next, index += 0x10000)
|
||||
{
|
||||
if (!ANIM_bonecoll_is_visible_editbone(arm, eBone)) {
|
||||
continue;
|
||||
}
|
||||
if (eBone->flag & BONE_HIDDEN_A) {
|
||||
if (!EBONE_VISIBLE(arm, eBone)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2586,6 +2573,10 @@ static void draw_armature_edit(const ArmatureDrawContext *ctx)
|
||||
boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
|
||||
|
||||
UnifiedBonePtr bone = eBone;
|
||||
if (!ctx->const_color) {
|
||||
set_ctx_bcolor(ctx, bone);
|
||||
}
|
||||
|
||||
if (!is_select) {
|
||||
draw_bone_relations(ctx, draw_strat, bone, boneflag);
|
||||
}
|
||||
@@ -2689,11 +2680,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
|
||||
pchan = pchan->next, index += 0x10000)
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0;
|
||||
if (!bone_visible) {
|
||||
continue;
|
||||
}
|
||||
if ((bone->layer & arm->layer) == 0) {
|
||||
if (!ANIM_bone_is_visible(arm, bone)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2706,8 +2693,9 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
|
||||
|
||||
pchan_draw_data_init(pchan);
|
||||
|
||||
UnifiedBonePtr bone_ptr = pchan;
|
||||
if (!ctx->const_color) {
|
||||
set_pchan_colorset(ctx, ob, pchan);
|
||||
set_ctx_bcolor(ctx, bone_ptr);
|
||||
}
|
||||
|
||||
eBone_Flag boneflag = eBone_Flag(bone->flag);
|
||||
@@ -2726,8 +2714,6 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
|
||||
const bool use_custom_shape = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM);
|
||||
const ArmatureBoneDrawStrategy &draw_strat = use_custom_shape ? draw_strat_custom :
|
||||
draw_strat_normal;
|
||||
UnifiedBonePtr bone_ptr = pchan;
|
||||
|
||||
if (!is_pose_select) {
|
||||
draw_bone_relations(ctx, draw_strat, bone_ptr, boneflag);
|
||||
}
|
||||
|
||||
@@ -140,8 +140,6 @@ static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGro
|
||||
bArmature *arm = static_cast<bArmature *>(ob->data);
|
||||
|
||||
if (pchan) {
|
||||
bActionGroup *bgrp;
|
||||
|
||||
/* if one matches, sync the selection status */
|
||||
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
|
||||
agrp->flag |= AGRP_SELECTED;
|
||||
@@ -167,12 +165,8 @@ static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGro
|
||||
agrp->flag &= ~AGRP_ACTIVE;
|
||||
}
|
||||
|
||||
/* sync group colors */
|
||||
bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1));
|
||||
if (bgrp) {
|
||||
agrp->customCol = bgrp->customCol;
|
||||
action_group_colors_sync(agrp, bgrp);
|
||||
}
|
||||
/* sync bone color */
|
||||
action_group_colors_set_from_posebone(agrp, pchan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,17 +221,8 @@ FCurve *ED_action_fcurve_ensure(Main *bmain,
|
||||
|
||||
/* sync bone group colors if applicable */
|
||||
if (ptr && (ptr->type == &RNA_PoseBone)) {
|
||||
Object *ob = (Object *)ptr->owner_id;
|
||||
bPoseChannel *pchan = static_cast<bPoseChannel *>(ptr->data);
|
||||
bPose *pose = ob->pose;
|
||||
bActionGroup *grp;
|
||||
|
||||
/* find bone group (if present), and use the color from that */
|
||||
grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
|
||||
if (grp) {
|
||||
agrp->customCol = grp->customCol;
|
||||
action_group_colors_sync(agrp, grp);
|
||||
}
|
||||
action_group_colors_set_from_posebone(agrp, pchan);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -517,6 +517,8 @@ static EditBone *make_boneList_recursive(ListBase *edbo,
|
||||
eBone->bbone_prev_flag = curBone->bbone_prev_flag;
|
||||
eBone->bbone_next_flag = curBone->bbone_next_flag;
|
||||
|
||||
eBone->color = curBone->color;
|
||||
|
||||
if (curBone->prop) {
|
||||
eBone->prop = IDP_CopyProperty(curBone->prop);
|
||||
}
|
||||
@@ -728,6 +730,8 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
|
||||
newBone->bbone_prev_flag = eBone->bbone_prev_flag;
|
||||
newBone->bbone_next_flag = eBone->bbone_next_flag;
|
||||
|
||||
newBone->color = eBone->color;
|
||||
|
||||
if (eBone->prop) {
|
||||
newBone->prop = IDP_CopyProperty(eBone->prop);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_override.hh"
|
||||
@@ -1131,6 +1132,44 @@ bool UI_context_copy_to_selected_list(bContext *C,
|
||||
else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
|
||||
ui_context_selected_bones_via_pose(C, r_lb);
|
||||
}
|
||||
else if (RNA_struct_is_a(ptr->type, &RNA_BoneColor)) {
|
||||
/* Get the things that own the bone color (bones, pose bones, or edit bones). */
|
||||
ListBase list_of_things = {}; /* First this will be bones, then gets remapped to colors. */
|
||||
switch (GS(ptr->owner_id->name)) {
|
||||
case ID_OB:
|
||||
list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
|
||||
break;
|
||||
case ID_AR: {
|
||||
/* Armature-owned bones can be accessed from both edit mode and pose mode.
|
||||
* - Edit mode: visit selected edit bones.
|
||||
* - Pose mode: visit the armature bones of selected pose bones.
|
||||
*/
|
||||
const bArmature *arm = reinterpret_cast<bArmature *>(ptr->owner_id);
|
||||
if (arm->edbo) {
|
||||
list_of_things = CTX_data_collection_get(C, "selected_editable_bones");
|
||||
}
|
||||
else {
|
||||
list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
|
||||
CTX_data_collection_remap_property(list_of_things, "bone");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("BoneColor is unexpectedly owned by %s '%s'\n",
|
||||
BKE_idtype_idcode_to_name(GS(ptr->owner_id->name)),
|
||||
ptr->owner_id->name + 2);
|
||||
BLI_assert(!"expected BoneColor to be owned by the Armature (bone & edit bone) or the Object (pose bone)");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remap from some bone to its color, to ensure the items of r_lb are of
|
||||
* type ptr->type. Since all three structs `bPoseChan`, `Bone`, and
|
||||
* `EditBone` have the same name for their embedded `BoneColor` struct, this
|
||||
* code is suitable for all of them. */
|
||||
CTX_data_collection_remap_property(list_of_things, "color");
|
||||
|
||||
*r_lb = list_of_things;
|
||||
}
|
||||
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
|
||||
/* Special case when we do this for 'Sequence.lock'.
|
||||
* (if the sequence is locked, it won't be in "selected_editable_sequences"). */
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_session_uuid_types.h"
|
||||
#include "DNA_userdef_types.h" /* ThemeWireColor */
|
||||
@@ -352,6 +353,8 @@ typedef struct bPoseChannel {
|
||||
/** Points to an original pose channel. */
|
||||
struct bPoseChannel *orig_pchan;
|
||||
|
||||
BoneColor color; /* MUST be named the same as in Bone and EditBone structs. */
|
||||
|
||||
/** Runtime data (keep last). */
|
||||
struct bPoseChannel_Runtime runtime;
|
||||
} bPoseChannel;
|
||||
|
||||
@@ -11,10 +11,15 @@
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_defs.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace blender::animrig {
|
||||
class BoneColor;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -28,6 +33,22 @@ struct AnimData;
|
||||
* 4) World Space; Object matrix applied to Pose or Armature space
|
||||
*/
|
||||
|
||||
typedef struct BoneColor {
|
||||
/**
|
||||
* Index of color palette to use when drawing bones.
|
||||
* 0=default, >0 = predefined in theme, -1=custom color in #custom.
|
||||
*
|
||||
* For the predefined ones, see #rna_enum_color_sets_items in rna_armature.c.
|
||||
*/
|
||||
int8_t palette_index;
|
||||
uint8_t _pad0[7];
|
||||
ThemeWireColor custom;
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::BoneColor &wrap();
|
||||
const blender::animrig::BoneColor &wrap() const;
|
||||
#endif
|
||||
} BoneColor;
|
||||
|
||||
typedef struct Bone {
|
||||
/** Next/previous elements within this list. */
|
||||
struct Bone *next, *prev;
|
||||
@@ -50,8 +71,11 @@ typedef struct Bone {
|
||||
|
||||
int flag;
|
||||
|
||||
char _pad1[4];
|
||||
BoneColor color; /* MUST be named the same as in bPoseChannel and EditBone structs. */
|
||||
|
||||
char inherit_scale_mode;
|
||||
char _pad[7];
|
||||
char _pad[3];
|
||||
|
||||
float arm_head[3];
|
||||
/** Head/tail in Armature Space (rest pose). */
|
||||
@@ -319,5 +343,14 @@ typedef enum eBone_BBoneHandleFlag {
|
||||
#define MAXBONENAME 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
inline blender::animrig::BoneColor &BoneColor::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::BoneColor *>(this);
|
||||
}
|
||||
inline const blender::animrig::BoneColor &BoneColor::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::BoneColor *>(this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -484,6 +484,7 @@ set(SRC
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::animrig
|
||||
PRIVATE bf::dna
|
||||
bf_editor_space_api
|
||||
|
||||
|
||||
@@ -25,6 +25,36 @@
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
/* Bone Collection Color Sets */
|
||||
const EnumPropertyItem rna_enum_color_palettes_items[] = {
|
||||
{0, "DEFAULT", 0, "Default Colors", ""},
|
||||
{1, "THEME01", ICON_COLORSET_01_VEC, "01 - Theme Color Set", ""},
|
||||
{2, "THEME02", ICON_COLORSET_02_VEC, "02 - Theme Color Set", ""},
|
||||
{3, "THEME03", ICON_COLORSET_03_VEC, "03 - Theme Color Set", ""},
|
||||
{4, "THEME04", ICON_COLORSET_04_VEC, "04 - Theme Color Set", ""},
|
||||
{5, "THEME05", ICON_COLORSET_05_VEC, "05 - Theme Color Set", ""},
|
||||
{6, "THEME06", ICON_COLORSET_06_VEC, "06 - Theme Color Set", ""},
|
||||
{7, "THEME07", ICON_COLORSET_07_VEC, "07 - Theme Color Set", ""},
|
||||
{8, "THEME08", ICON_COLORSET_08_VEC, "08 - Theme Color Set", ""},
|
||||
{9, "THEME09", ICON_COLORSET_09_VEC, "09 - Theme Color Set", ""},
|
||||
{10, "THEME10", ICON_COLORSET_10_VEC, "10 - Theme Color Set", ""},
|
||||
{11, "THEME11", ICON_COLORSET_11_VEC, "11 - Theme Color Set", ""},
|
||||
{12, "THEME12", ICON_COLORSET_12_VEC, "12 - Theme Color Set", ""},
|
||||
{13, "THEME13", ICON_COLORSET_13_VEC, "13 - Theme Color Set", ""},
|
||||
{14, "THEME14", ICON_COLORSET_14_VEC, "14 - Theme Color Set", ""},
|
||||
{15, "THEME15", ICON_COLORSET_15_VEC, "15 - Theme Color Set", ""},
|
||||
{16, "THEME16", ICON_COLORSET_16_VEC, "16 - Theme Color Set", ""},
|
||||
{17, "THEME17", ICON_COLORSET_17_VEC, "17 - Theme Color Set", ""},
|
||||
{18, "THEME18", ICON_COLORSET_18_VEC, "18 - Theme Color Set", ""},
|
||||
{19, "THEME19", ICON_COLORSET_19_VEC, "19 - Theme Color Set", ""},
|
||||
{20, "THEME20", ICON_COLORSET_20_VEC, "20 - Theme Color Set", ""},
|
||||
{-1, "CUSTOM", 0, "Custom Color Set", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
#ifdef RNA_RUNTIME
|
||||
constexpr int COLOR_SETS_MAX_THEMED_INDEX = 20;
|
||||
#endif
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "BLI_math_vector.h"
|
||||
@@ -41,6 +71,10 @@
|
||||
# include "DEG_depsgraph.h"
|
||||
# include "DEG_depsgraph_build.h"
|
||||
|
||||
# ifndef NDEBUG
|
||||
# include "ANIM_armature_iter.hh"
|
||||
# endif
|
||||
|
||||
static void rna_Armature_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
ID *id = ptr->owner_id;
|
||||
@@ -155,6 +189,144 @@ static void rna_Armature_update_layers(Main * /*bmain*/, Scene * /*scene*/, Poin
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, arm);
|
||||
}
|
||||
|
||||
static char *rna_BoneColor_path_posebone(const PointerRNA *ptr)
|
||||
{
|
||||
/* Find the bPoseChan that owns this BoneColor. */
|
||||
const uint8_t *bcolor_ptr = static_cast<const uint8_t *>(ptr->data);
|
||||
const uint8_t *bone_ptr = bcolor_ptr - offsetof(bPoseChannel, color);
|
||||
const bPoseChannel *bone = reinterpret_cast<const bPoseChannel *>(bone_ptr);
|
||||
|
||||
# ifndef NDEBUG
|
||||
/* Sanity check that the above pointer magic actually worked. */
|
||||
BLI_assert(GS(ptr->owner_id->name) == ID_OB);
|
||||
const Object *ob = reinterpret_cast<const Object *>(ptr->owner_id);
|
||||
bool found = false;
|
||||
LISTBASE_FOREACH (bPoseChannel *, checkBone, &ob->pose->chanbase) {
|
||||
if (&checkBone->color == ptr->data) {
|
||||
BLI_assert_msg(checkBone == bone,
|
||||
"pointer magic to find the pose bone failed (found the wrong bone)");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLI_assert_msg(found, "pointer magic to find the pose bone failed (did not find the bone)");
|
||||
# endif
|
||||
|
||||
char name_esc[sizeof(bone->name) * 2];
|
||||
BLI_str_escape(name_esc, bone->name, sizeof(name_esc));
|
||||
return BLI_sprintfN("pose.bones[\"%s\"].color", name_esc);
|
||||
}
|
||||
|
||||
static char *rna_BoneColor_path_bone(const PointerRNA *ptr)
|
||||
{
|
||||
/* Find the Bone that owns this BoneColor. */
|
||||
const uint8_t *bcolor_ptr = static_cast<const uint8_t *>(ptr->data);
|
||||
const uint8_t *bone_ptr = bcolor_ptr - offsetof(Bone, color);
|
||||
const Bone *bone = reinterpret_cast<const Bone *>(bone_ptr);
|
||||
|
||||
# ifndef NDEBUG
|
||||
/* Sanity check that the above pointer magic actually worked. */
|
||||
BLI_assert(GS(ptr->owner_id->name) == ID_AR);
|
||||
const bArmature *arm = reinterpret_cast<const bArmature *>(ptr->owner_id);
|
||||
|
||||
bool found = false;
|
||||
blender::animrig::ANIM_armature_foreach_bone(&arm->bonebase, [&](const Bone *checkBone) {
|
||||
if (&checkBone->color == ptr->data) {
|
||||
BLI_assert_msg(checkBone == bone,
|
||||
"pointer magic to find the pose bone failed (found the wrong bone)");
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
BLI_assert_msg(found, "pointer magic to find the pose bone failed (did not find the bone)");
|
||||
# endif
|
||||
|
||||
char name_esc[sizeof(bone->name) * 2];
|
||||
BLI_str_escape(name_esc, bone->name, sizeof(name_esc));
|
||||
return BLI_sprintfN("bones[\"%s\"].color", name_esc);
|
||||
}
|
||||
|
||||
static char *rna_BoneColor_path_editbone(const PointerRNA *ptr)
|
||||
{
|
||||
/* Find the Bone that owns this BoneColor. */
|
||||
const uint8_t *bcolor_ptr = static_cast<const uint8_t *>(ptr->data);
|
||||
const uint8_t *bone_ptr = bcolor_ptr - offsetof(EditBone, color);
|
||||
const EditBone *bone = reinterpret_cast<const EditBone *>(bone_ptr);
|
||||
|
||||
# ifndef NDEBUG
|
||||
/* Sanity check that the above pointer magic actually worked. */
|
||||
BLI_assert(GS(ptr->owner_id->name) == ID_AR);
|
||||
const bArmature *arm = reinterpret_cast<const bArmature *>(ptr->owner_id);
|
||||
|
||||
bool found = false;
|
||||
LISTBASE_FOREACH (const EditBone *, checkBone, arm->edbo) {
|
||||
if (&checkBone->color == ptr->data) {
|
||||
BLI_assert_msg(checkBone == bone,
|
||||
"pointer magic to find the pose bone failed (found the wrong bone)");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLI_assert_msg(found, "pointer magic to find the pose bone failed (did not find the bone)");
|
||||
# endif
|
||||
|
||||
char name_esc[sizeof(bone->name) * 2];
|
||||
BLI_str_escape(name_esc, bone->name, sizeof(name_esc));
|
||||
return BLI_sprintfN("bones[\"%s\"].color", name_esc);
|
||||
}
|
||||
|
||||
static char *rna_BoneColor_path(const PointerRNA *ptr)
|
||||
{
|
||||
const ID *owner = ptr->owner_id;
|
||||
BLI_assert_msg(owner, "expecting all bone colors to have an owner");
|
||||
|
||||
switch (GS(owner->name)) {
|
||||
case ID_OB:
|
||||
return rna_BoneColor_path_posebone(ptr);
|
||||
case ID_AR: {
|
||||
const bArmature *arm = reinterpret_cast<const bArmature *>(owner);
|
||||
if (arm->edbo == nullptr) {
|
||||
return rna_BoneColor_path_bone(ptr);
|
||||
}
|
||||
return rna_BoneColor_path_editbone(ptr);
|
||||
}
|
||||
default:
|
||||
BLI_assert_msg(false, "expected object or armature");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void rna_BoneColor_palette_index_set(PointerRNA *ptr, const int new_palette_index)
|
||||
{
|
||||
if (new_palette_index < -1 || new_palette_index > COLOR_SETS_MAX_THEMED_INDEX) {
|
||||
BKE_reportf(nullptr, RPT_ERROR, "Invalid color palette index: %d", new_palette_index);
|
||||
return;
|
||||
}
|
||||
|
||||
BoneColor *bcolor = static_cast<BoneColor *>(ptr->data);
|
||||
bcolor->palette_index = new_palette_index;
|
||||
|
||||
ID *id = ptr->owner_id;
|
||||
DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
}
|
||||
|
||||
bool rna_BoneColor_is_custom_get(PointerRNA *ptr)
|
||||
{
|
||||
BoneColor *bcolor = static_cast<BoneColor *>(ptr->data);
|
||||
return bcolor->palette_index < 0;
|
||||
}
|
||||
|
||||
static void rna_BoneColor_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
/* Ugly hack to trigger the setting of the SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC flag on the
|
||||
* animation editors, which in turn calls ANIM_sync_animchannels_to_data(C) with the right
|
||||
* context.
|
||||
*
|
||||
* Without this, changes to the bone colors are not reflected on the bActionGroup colors.
|
||||
*/
|
||||
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ptr->data);
|
||||
}
|
||||
|
||||
static void rna_Armature_redraw_data(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
ID *id = ptr->owner_id;
|
||||
@@ -574,6 +746,12 @@ static void rna_Bone_bbone_next_set(PointerRNA *ptr, PointerRNA value, ReportLis
|
||||
}
|
||||
}
|
||||
|
||||
static PointerRNA rna_EditBone_color_get(PointerRNA *ptr)
|
||||
{
|
||||
EditBone *data = (EditBone *)(ptr->data);
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_BoneColor, &data->color);
|
||||
}
|
||||
|
||||
static void rna_Armature_editbone_transform_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
bArmature *arm = (bArmature *)ptr->owner_id;
|
||||
@@ -676,6 +854,41 @@ static void rna_Armature_relation_line_position_set(PointerRNA *ptr, const int v
|
||||
|
||||
#else
|
||||
|
||||
static void rna_def_bonecolor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "BoneColor", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "BoneColor", "Theme color or custom color of a bone");
|
||||
RNA_def_struct_ui_icon(srna, ICON_BONE_DATA);
|
||||
RNA_def_struct_path_func(srna, "rna_BoneColor_path");
|
||||
|
||||
prop = RNA_def_property(srna, "palette", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "palette_index");
|
||||
RNA_def_property_enum_items(prop, rna_enum_color_palettes_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_BoneColor_palette_index_set", NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Color Set", "Color palette to use");
|
||||
RNA_def_property_update(prop, 0, "rna_BoneColor_update");
|
||||
|
||||
prop = RNA_def_property(srna, "is_custom", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_BoneColor_is_custom_get", NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Use Custom Color",
|
||||
"A color palette is user-defined, instead of using a theme-defined one");
|
||||
|
||||
prop = RNA_def_property(srna, "custom", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_struct_type(prop, "ThemeBoneColorSet");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Custom", "The custom bone colors, used when palette is 'CUSTOM'");
|
||||
RNA_def_property_update(prop, 0, "rna_BoneColor_update");
|
||||
}
|
||||
|
||||
void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editbone)
|
||||
{
|
||||
/* NOTE: The pose-mode values get applied over the top of the edit-mode ones. */
|
||||
@@ -873,6 +1086,13 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
|
||||
|
||||
RNA_define_lib_overridable(true);
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoneColor");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
if (editbone) {
|
||||
RNA_def_property_pointer_funcs(prop, "rna_EditBone_color_get", nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
/* flags */
|
||||
prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "layer", 1);
|
||||
@@ -1634,6 +1854,7 @@ static void rna_def_armature(BlenderRNA *brna)
|
||||
|
||||
void RNA_def_armature(BlenderRNA *brna)
|
||||
{
|
||||
rna_def_bonecolor(brna);
|
||||
rna_def_armature(brna);
|
||||
rna_def_bone(brna);
|
||||
rna_def_edit_bone(brna);
|
||||
|
||||
@@ -1407,6 +1407,10 @@ static void rna_def_pose_channel(BlenderRNA *brna)
|
||||
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoneColor");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
||||
/* transform locks */
|
||||
prop = RNA_def_property(srna, "lock_location", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "protectflag", OB_LOCK_LOCX);
|
||||
|
||||
Reference in New Issue
Block a user