Anim: support per-bone "Display As" overrides
Armature bone display mode (Octahedral, Stick, Envelope, B-Bone, Wire) could only be set on the whole armature. This adds ability to override the display mode per-bone (by default bones use the same display mode as the armature). Images in the PR. Pull Request: https://projects.blender.org/blender/blender/pulls/138445
This commit is contained in:
committed by
Aras Pranckevicius
parent
fcc6e022b1
commit
8bf73386f2
@@ -327,6 +327,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
|||||||
hide_select_sub = col.column()
|
hide_select_sub = col.column()
|
||||||
hide_select_sub.active = not bone.hide
|
hide_select_sub.active = not bone.hide
|
||||||
hide_select_sub.prop(bone, "hide_select", invert_checkbox=True)
|
hide_select_sub.prop(bone, "hide_select", invert_checkbox=True)
|
||||||
|
col.prop(bone, "display_type", text="Display As")
|
||||||
|
|
||||||
# Figure out the pose bone.
|
# Figure out the pose bone.
|
||||||
ob = context.object
|
ob = context.object
|
||||||
@@ -359,6 +360,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
|||||||
hide_select_sub = col.column()
|
hide_select_sub = col.column()
|
||||||
hide_select_sub.active = not bone.hide
|
hide_select_sub.active = not bone.hide
|
||||||
hide_select_sub.prop(bone, "hide_select", invert_checkbox=True)
|
hide_select_sub.prop(bone, "hide_select", invert_checkbox=True)
|
||||||
|
col.prop(bone, "display_type", text="Display As")
|
||||||
layout.prop(bone.color, "palette", text="Bone Color")
|
layout.prop(bone.color, "palette", text="Bone Color")
|
||||||
self.draw_bone_color_ui(layout, bone.color)
|
self.draw_bone_color_ui(layout, bone.color)
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ struct EditBone {
|
|||||||
*/
|
*/
|
||||||
int flag;
|
int flag;
|
||||||
int layer;
|
int layer;
|
||||||
|
int drawtype; /* eArmature_Drawtype */
|
||||||
char inherit_scale_mode;
|
char inherit_scale_mode;
|
||||||
|
|
||||||
/* Envelope distance & weight */
|
/* Envelope distance & weight */
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
/* Blender file format version. */
|
/* Blender file format version. */
|
||||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||||
#define BLENDER_FILE_SUBVERSION 71
|
#define BLENDER_FILE_SUBVERSION 72
|
||||||
|
|
||||||
/* Minimum Blender version that supports reading file written with the current
|
/* Minimum Blender version that supports reading file written with the current
|
||||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||||
|
|||||||
@@ -4339,6 +4339,15 @@ static void version_convert_sculpt_planar_brushes(Main *bmain)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void version_set_default_bone_drawtype(Main *bmain)
|
||||||
|
{
|
||||||
|
LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
|
||||||
|
blender::animrig::ANIM_armature_foreach_bone(
|
||||||
|
&arm->bonebase, [](Bone *bone) { bone->drawtype = ARM_BONE_DEFAULT; });
|
||||||
|
BLI_assert_msg(!arm->edbo, "Armatures should not be saved in edit mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
|
void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -5148,6 +5157,10 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
|
|||||||
FOREACH_NODETREE_END;
|
FOREACH_NODETREE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 72)) {
|
||||||
|
version_set_default_bone_drawtype(bmain);
|
||||||
|
}
|
||||||
|
|
||||||
/* Always run this versioning (keep at the bottom of the function). Meshes are written with the
|
/* Always run this versioning (keep at the bottom of the function). Meshes are written with the
|
||||||
* legacy format which always needs to be converted to the new format on file load. To be moved
|
* legacy format which always needs to be converted to the new format on file load. To be moved
|
||||||
* to a subversion check in 5.0. */
|
* to a subversion check in 5.0. */
|
||||||
|
|||||||
@@ -189,56 +189,6 @@ class UnifiedBonePtr {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Bone drawing strategy class.
|
|
||||||
*
|
|
||||||
* Depending on the armature display mode, a different subclass is used to
|
|
||||||
* manage drawing. These subclasses are defined further down in the file. This
|
|
||||||
* abstract class needs to be defined before any function that uses it, though.
|
|
||||||
*/
|
|
||||||
class ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
virtual void update_display_matrix(UnifiedBonePtr bone) const = 0;
|
|
||||||
|
|
||||||
virtual void draw_context_setup(Armatures::DrawContext *ctx,
|
|
||||||
const bool is_filled,
|
|
||||||
const bool do_envelope_dist) const = 0;
|
|
||||||
|
|
||||||
virtual void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const = 0;
|
|
||||||
|
|
||||||
/** Should the relationship line between this bone and its parent be drawn? */
|
|
||||||
virtual bool should_draw_relation_to_parent(const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag) const
|
|
||||||
{
|
|
||||||
const bool has_parent = bone.has_parent();
|
|
||||||
|
|
||||||
if (bone.is_editbone() && has_parent) {
|
|
||||||
/* Always draw for unconnected bones, regardless of selection,
|
|
||||||
* since riggers will want to know about the links between bones
|
|
||||||
*/
|
|
||||||
return (boneflag & BONE_CONNECTED) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bone.is_posebone() && has_parent) {
|
|
||||||
/* Only draw between unconnected bones. */
|
|
||||||
if (boneflag & BONE_CONNECTED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only draw if bone or its parent is selected - reduces viewport
|
|
||||||
* complexity with complex rigs */
|
|
||||||
const bPoseChannel *pchan = bone.as_posebone();
|
|
||||||
return (boneflag & BONE_SELECTED) ||
|
|
||||||
(pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Shading Groups
|
/** \name Shading Groups
|
||||||
* \{ */
|
* \{ */
|
||||||
@@ -992,7 +942,7 @@ static void draw_bone_update_disp_matrix_default(UnifiedBonePtr bone)
|
|||||||
float(*disp_tail_mat)[4] = bone.disp_tail_mat();
|
float(*disp_tail_mat)[4] = bone.disp_tail_mat();
|
||||||
|
|
||||||
/* TODO: This should be moved to depsgraph or armature refresh
|
/* TODO: This should be moved to depsgraph or armature refresh
|
||||||
* and not be tight to the draw pass creation.
|
* and not be tied to the draw pass creation.
|
||||||
* This would refresh armature without invalidating the draw cache */
|
* This would refresh armature without invalidating the draw cache */
|
||||||
if (bone.is_posebone()) {
|
if (bone.is_posebone()) {
|
||||||
bPoseChannel *pchan = bone.as_posebone();
|
bPoseChannel *pchan = bone.as_posebone();
|
||||||
@@ -1014,6 +964,38 @@ static void draw_bone_update_disp_matrix_default(UnifiedBonePtr bone)
|
|||||||
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
|
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void draw_bone_update_disp_matrix_custom_shape(UnifiedBonePtr bone)
|
||||||
|
{
|
||||||
|
float bone_scale[3];
|
||||||
|
float(*bone_mat)[4];
|
||||||
|
float(*disp_mat)[4];
|
||||||
|
float(*disp_tail_mat)[4];
|
||||||
|
float rot_mat[3][3];
|
||||||
|
|
||||||
|
/* Custom bone shapes are only supported in pose mode for now. */
|
||||||
|
bPoseChannel *pchan = bone.as_posebone();
|
||||||
|
|
||||||
|
/* TODO: This should be moved to depsgraph or armature refresh
|
||||||
|
* and not be tied to the draw pass creation.
|
||||||
|
* This would refresh armature without invalidating the draw cache. */
|
||||||
|
mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
|
||||||
|
bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
|
||||||
|
disp_mat = bone.disp_mat();
|
||||||
|
disp_tail_mat = pchan->disp_tail_mat;
|
||||||
|
|
||||||
|
eulO_to_mat3(rot_mat, pchan->custom_rotation_euler, ROT_MODE_XYZ);
|
||||||
|
|
||||||
|
copy_m4_m4(disp_mat, bone_mat);
|
||||||
|
translate_m4(disp_mat,
|
||||||
|
pchan->custom_translation[0],
|
||||||
|
pchan->custom_translation[1],
|
||||||
|
pchan->custom_translation[2]);
|
||||||
|
mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
|
||||||
|
rescale_m4(disp_mat, bone_scale);
|
||||||
|
copy_m4_m4(disp_tail_mat, disp_mat);
|
||||||
|
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
/* compute connected child pointer for B-Bone drawing */
|
/* compute connected child pointer for B-Bone drawing */
|
||||||
static void edbo_compute_bbone_child(bArmature *arm)
|
static void edbo_compute_bbone_child(bArmature *arm)
|
||||||
{
|
{
|
||||||
@@ -1153,7 +1135,7 @@ static void draw_bone_update_disp_matrix_bbone(UnifiedBonePtr bone)
|
|||||||
short bbone_segments;
|
short bbone_segments;
|
||||||
|
|
||||||
/* TODO: This should be moved to depsgraph or armature refresh
|
/* TODO: This should be moved to depsgraph or armature refresh
|
||||||
* and not be tight to the draw pass creation.
|
* and not be tied to the draw pass creation.
|
||||||
* This would refresh armature without invalidating the draw cache. */
|
* This would refresh armature without invalidating the draw cache. */
|
||||||
if (bone.is_posebone()) {
|
if (bone.is_posebone()) {
|
||||||
bPoseChannel *pchan = bone.as_posebone();
|
bPoseChannel *pchan = bone.as_posebone();
|
||||||
@@ -1334,6 +1316,285 @@ static void draw_points(const Armatures::DrawContext *ctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bone_draw_custom_shape(const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
const float *col_solid = get_bone_solid_color(ctx, boneflag);
|
||||||
|
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
||||||
|
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
||||||
|
const float(*disp_mat)[4] = bone.disp_mat();
|
||||||
|
|
||||||
|
/* TODO(fclem): Code after this scope should be removed when we remove the legacy code. */
|
||||||
|
auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
|
||||||
|
|
||||||
|
/* Custom bone shapes are only supported in pose mode for now. */
|
||||||
|
const bPoseChannel *pchan = bone.as_posebone();
|
||||||
|
Object *custom_shape_ob = pchan->custom;
|
||||||
|
|
||||||
|
if (custom_shape_ob->type == OB_EMPTY) {
|
||||||
|
if (custom_shape_ob->empty_drawtype != OB_EMPTY_IMAGE) {
|
||||||
|
drw_shgroup_bone_custom_empty(
|
||||||
|
ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (boneflag & (BONE_DRAWWIRE | BONE_DRAW_LOCKED_WEIGHT)) {
|
||||||
|
drw_shgroup_bone_custom_wire(
|
||||||
|
ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
drw_shgroup_bone_custom_solid(ctx,
|
||||||
|
disp_mat,
|
||||||
|
col_solid,
|
||||||
|
col_hint,
|
||||||
|
col_wire,
|
||||||
|
pchan->custom_shape_wire_width,
|
||||||
|
sel_id,
|
||||||
|
pchan->custom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bone_draw_octa(const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
||||||
|
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
||||||
|
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
||||||
|
|
||||||
|
auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
|
||||||
|
float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(bone.disp_mat());
|
||||||
|
|
||||||
|
if (ctx->is_filled) {
|
||||||
|
ctx->bone_buf->octahedral_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
|
||||||
|
}
|
||||||
|
if (col_wire[3] > 0.0f) {
|
||||||
|
ctx->bone_buf->octahedral_outline_buf.append({bone_mat, col_wire}, sel_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bone_draw_line(const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
const float *col_bone = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
||||||
|
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
||||||
|
const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
const float *col_head = no_display;
|
||||||
|
const float *col_tail = col_bone;
|
||||||
|
|
||||||
|
if (ctx->const_color != nullptr) {
|
||||||
|
col_wire = no_display; /* actually shrink the display. */
|
||||||
|
col_bone = col_head = col_tail = ctx->const_color;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const UniformData &theme = ctx->res->theme;
|
||||||
|
|
||||||
|
if (bone.is_editbone() && bone.flag() & BONE_TIPSEL) {
|
||||||
|
col_tail = &theme.colors.vert_select.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw root point if we are not connected to our parent. */
|
||||||
|
if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
|
||||||
|
|
||||||
|
if (bone.is_editbone()) {
|
||||||
|
col_head = (bone.flag() & BONE_ROOTSEL) ? &theme.colors.vert_select.x : col_bone;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
col_head = col_bone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select_id == -1) {
|
||||||
|
/* Not in bone selection mode (can still be object select mode), draw everything at once.
|
||||||
|
*/
|
||||||
|
drw_shgroup_bone_stick(
|
||||||
|
ctx, bone.disp_mat(), col_wire, col_bone, col_head, col_tail, select_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* In selection mode, draw bone, root and tip separately. */
|
||||||
|
drw_shgroup_bone_stick(ctx,
|
||||||
|
bone.disp_mat(),
|
||||||
|
col_wire,
|
||||||
|
col_bone,
|
||||||
|
no_display,
|
||||||
|
no_display,
|
||||||
|
select_id | BONESEL_BONE);
|
||||||
|
|
||||||
|
if (col_head[3] > 0.0f) {
|
||||||
|
drw_shgroup_bone_stick(ctx,
|
||||||
|
bone.disp_mat(),
|
||||||
|
col_wire,
|
||||||
|
no_display,
|
||||||
|
col_head,
|
||||||
|
no_display,
|
||||||
|
select_id | BONESEL_ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
drw_shgroup_bone_stick(
|
||||||
|
ctx, bone.disp_mat(), col_wire, no_display, no_display, col_tail, select_id | BONESEL_TIP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bone_draw_b_bone(const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
||||||
|
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
||||||
|
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
||||||
|
|
||||||
|
/* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
|
||||||
|
* This would require a deeper refactor. */
|
||||||
|
Span<Mat4> bbone_matrices;
|
||||||
|
if (bone.is_posebone()) {
|
||||||
|
bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
|
||||||
|
bone.as_posebone()->bone->segments};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
|
||||||
|
|
||||||
|
for (const Mat4 &in_bone_mat : bbone_matrices) {
|
||||||
|
float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(in_bone_mat.mat);
|
||||||
|
|
||||||
|
if (ctx->is_filled) {
|
||||||
|
ctx->bone_buf->bbones_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
|
||||||
|
}
|
||||||
|
if (col_wire[3] > 0.0f) {
|
||||||
|
ctx->bone_buf->bbones_outline_buf.append({bone_mat, col_wire}, sel_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
|
||||||
|
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bone_draw_envelope(const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
||||||
|
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
||||||
|
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
||||||
|
|
||||||
|
const float *rad_head, *rad_tail, *distance;
|
||||||
|
if (bone.is_editbone()) {
|
||||||
|
const EditBone *eBone = bone.as_editbone();
|
||||||
|
rad_tail = &eBone->rad_tail;
|
||||||
|
distance = &eBone->dist;
|
||||||
|
rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
|
||||||
|
&eBone->rad_head;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const bPoseChannel *pchan = bone.as_posebone();
|
||||||
|
rad_tail = &pchan->bone->rad_tail;
|
||||||
|
distance = &pchan->bone->dist;
|
||||||
|
rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
|
||||||
|
&pchan->bone->rad_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
|
||||||
|
((boneflag & BONE_SELECTED) ||
|
||||||
|
(bone.is_editbone() && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
|
||||||
|
{
|
||||||
|
drw_shgroup_bone_envelope_distance(ctx, bone.disp_mat(), rad_head, rad_tail, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
drw_shgroup_bone_envelope(ctx,
|
||||||
|
bone.disp_mat(),
|
||||||
|
col_solid,
|
||||||
|
col_hint,
|
||||||
|
col_wire,
|
||||||
|
rad_head,
|
||||||
|
rad_tail,
|
||||||
|
select_id | BONESEL_BONE);
|
||||||
|
|
||||||
|
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bone_draw_wire(const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
using namespace blender::math;
|
||||||
|
|
||||||
|
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
||||||
|
|
||||||
|
auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE) :
|
||||||
|
draw::select::SelectMap::select_invalid_id();
|
||||||
|
|
||||||
|
/* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
|
||||||
|
* This would require a deeper refactor. */
|
||||||
|
Span<Mat4> bbone_matrices;
|
||||||
|
if (bone.is_posebone()) {
|
||||||
|
bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
|
||||||
|
bone.as_posebone()->bone->segments};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Mat4 &in_bone_mat : bbone_matrices) {
|
||||||
|
float4x4 bmat = float4x4(in_bone_mat.mat);
|
||||||
|
float3 head = transform_point(ctx->ob->object_to_world(), bmat.location());
|
||||||
|
float3 tail = transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
|
||||||
|
|
||||||
|
ctx->bone_buf->wire_buf.append(head, tail, float4(col_wire), sel_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bone.is_editbone()) {
|
||||||
|
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
||||||
|
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bone_draw(const eArmature_Drawtype drawtype,
|
||||||
|
const bool use_custom_shape,
|
||||||
|
const Armatures::DrawContext *ctx,
|
||||||
|
const UnifiedBonePtr bone,
|
||||||
|
const eBone_Flag boneflag,
|
||||||
|
const int select_id)
|
||||||
|
{
|
||||||
|
if (use_custom_shape) {
|
||||||
|
bone_draw_custom_shape(ctx, bone, boneflag, select_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (drawtype) {
|
||||||
|
case ARM_OCTA:
|
||||||
|
bone_draw_octa(ctx, bone, boneflag, select_id);
|
||||||
|
break;
|
||||||
|
case ARM_LINE:
|
||||||
|
bone_draw_line(ctx, bone, boneflag, select_id);
|
||||||
|
break;
|
||||||
|
case ARM_B_BONE:
|
||||||
|
bone_draw_b_bone(ctx, bone, boneflag, select_id);
|
||||||
|
break;
|
||||||
|
case ARM_ENVELOPE:
|
||||||
|
bone_draw_envelope(ctx, bone, boneflag, select_id);
|
||||||
|
break;
|
||||||
|
case ARM_WIRE:
|
||||||
|
bone_draw_wire(ctx, bone, boneflag, select_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@@ -1401,6 +1662,34 @@ static void draw_bone_degrees_of_freedom(const Armatures::DrawContext *ctx,
|
|||||||
/** \name Draw Relationships
|
/** \name Draw Relationships
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
/** Should the relationship line between this bone and its parent be drawn? */
|
||||||
|
static bool should_draw_relation_to_parent(const UnifiedBonePtr bone, const eBone_Flag boneflag)
|
||||||
|
{
|
||||||
|
const bool has_parent = bone.has_parent();
|
||||||
|
|
||||||
|
if (bone.is_editbone() && has_parent) {
|
||||||
|
/* Always draw for unconnected bones, regardless of selection,
|
||||||
|
* since riggers will want to know about the links between bones
|
||||||
|
*/
|
||||||
|
return (boneflag & BONE_CONNECTED) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bone.is_posebone() && has_parent) {
|
||||||
|
/* Only draw between unconnected bones. */
|
||||||
|
if (boneflag & BONE_CONNECTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only draw if bone or its parent is selected - reduces viewport
|
||||||
|
* complexity with complex rigs */
|
||||||
|
const bPoseChannel *pchan = bone.as_posebone();
|
||||||
|
return (boneflag & BONE_SELECTED) ||
|
||||||
|
(pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void pchan_draw_ik_lines(const Armatures::DrawContext *ctx,
|
static void pchan_draw_ik_lines(const Armatures::DrawContext *ctx,
|
||||||
const bPoseChannel *pchan,
|
const bPoseChannel *pchan,
|
||||||
const bool only_temp)
|
const bool only_temp)
|
||||||
@@ -1495,14 +1784,13 @@ static void draw_bone_bone_relationship_line(const Armatures::DrawContext *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void draw_bone_relations(const Armatures::DrawContext *ctx,
|
static void draw_bone_relations(const Armatures::DrawContext *ctx,
|
||||||
const ArmatureBoneDrawStrategy &draw_strategy,
|
|
||||||
const UnifiedBonePtr bone,
|
const UnifiedBonePtr bone,
|
||||||
const eBone_Flag boneflag)
|
const eBone_Flag boneflag)
|
||||||
{
|
{
|
||||||
if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
|
if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
|
||||||
const EditBone *ebone = bone.as_editbone();
|
const EditBone *ebone = bone.as_editbone();
|
||||||
if (ebone->parent) {
|
if (ebone->parent) {
|
||||||
if (ctx->do_relations && draw_strategy.should_draw_relation_to_parent(bone, boneflag)) {
|
if (ctx->do_relations && should_draw_relation_to_parent(bone, boneflag)) {
|
||||||
draw_bone_bone_relationship_line(
|
draw_bone_bone_relationship_line(
|
||||||
ctx, ebone->head, ebone->parent->head, ebone->parent->tail);
|
ctx, ebone->head, ebone->parent->head, ebone->parent->tail);
|
||||||
}
|
}
|
||||||
@@ -1511,7 +1799,7 @@ static void draw_bone_relations(const Armatures::DrawContext *ctx,
|
|||||||
else {
|
else {
|
||||||
const bPoseChannel *pchan = bone.as_posebone();
|
const bPoseChannel *pchan = bone.as_posebone();
|
||||||
if (pchan->parent) {
|
if (pchan->parent) {
|
||||||
if (ctx->do_relations && draw_strategy.should_draw_relation_to_parent(bone, boneflag)) {
|
if (ctx->do_relations && should_draw_relation_to_parent(bone, boneflag)) {
|
||||||
draw_bone_bone_relationship_line(
|
draw_bone_bone_relationship_line(
|
||||||
ctx, pchan->pose_head, pchan->parent->pose_head, pchan->parent->pose_tail);
|
ctx, pchan->pose_head, pchan->parent->pose_head, pchan->parent->pose_tail);
|
||||||
}
|
}
|
||||||
@@ -1566,452 +1854,25 @@ static void draw_bone_name(const Armatures::DrawContext *ctx,
|
|||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Bone Drawing Strategies
|
|
||||||
*
|
|
||||||
* Bone drawing uses a strategy pattern for the different armature drawing modes.
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bone drawing strategy for unknown draw types.
|
|
||||||
* This doesn't do anything, except call the default matrix update function.
|
|
||||||
*/
|
|
||||||
class ArmatureBoneDrawStrategyEmpty : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
draw_bone_update_disp_matrix_default(bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext * /*ctx*/,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext * /*ctx*/,
|
|
||||||
const UnifiedBonePtr /*bone*/,
|
|
||||||
const eBone_Flag /*boneflag*/,
|
|
||||||
const int /*select_id*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Bone drawing strategy for custom bone shapes. */
|
|
||||||
class ArmatureBoneDrawStrategyCustomShape : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
float bone_scale[3];
|
|
||||||
float(*bone_mat)[4];
|
|
||||||
float(*disp_mat)[4];
|
|
||||||
float(*disp_tail_mat)[4];
|
|
||||||
float rot_mat[3][3];
|
|
||||||
|
|
||||||
/* Custom bone shapes are only supported in pose mode for now. */
|
|
||||||
bPoseChannel *pchan = bone.as_posebone();
|
|
||||||
|
|
||||||
/* TODO: This should be moved to depsgraph or armature refresh
|
|
||||||
* and not be tight to the draw pass creation.
|
|
||||||
* This would refresh armature without invalidating the draw cache. */
|
|
||||||
mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
|
|
||||||
bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
|
|
||||||
disp_mat = bone.disp_mat();
|
|
||||||
disp_tail_mat = pchan->disp_tail_mat;
|
|
||||||
|
|
||||||
eulO_to_mat3(rot_mat, pchan->custom_rotation_euler, ROT_MODE_XYZ);
|
|
||||||
|
|
||||||
copy_m4_m4(disp_mat, bone_mat);
|
|
||||||
translate_m4(disp_mat,
|
|
||||||
pchan->custom_translation[0],
|
|
||||||
pchan->custom_translation[1],
|
|
||||||
pchan->custom_translation[2]);
|
|
||||||
mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
|
|
||||||
rescale_m4(disp_mat, bone_scale);
|
|
||||||
copy_m4_m4(disp_tail_mat, disp_mat);
|
|
||||||
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext * /*ctx*/,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const override
|
|
||||||
{
|
|
||||||
const float *col_solid = get_bone_solid_color(ctx, boneflag);
|
|
||||||
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
|
||||||
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
|
||||||
const float(*disp_mat)[4] = bone.disp_mat();
|
|
||||||
|
|
||||||
/* TODO(fclem): Code after this scope should be removed when we remove the legacy code. */
|
|
||||||
auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
|
|
||||||
|
|
||||||
/* Custom bone shapes are only supported in pose mode for now. */
|
|
||||||
const bPoseChannel *pchan = bone.as_posebone();
|
|
||||||
Object *custom_shape_ob = pchan->custom;
|
|
||||||
|
|
||||||
if (custom_shape_ob->type == OB_EMPTY) {
|
|
||||||
if (custom_shape_ob->empty_drawtype != OB_EMPTY_IMAGE) {
|
|
||||||
drw_shgroup_bone_custom_empty(
|
|
||||||
ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (boneflag & (BONE_DRAWWIRE | BONE_DRAW_LOCKED_WEIGHT)) {
|
|
||||||
drw_shgroup_bone_custom_wire(
|
|
||||||
ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
drw_shgroup_bone_custom_solid(ctx,
|
|
||||||
disp_mat,
|
|
||||||
col_solid,
|
|
||||||
col_hint,
|
|
||||||
col_wire,
|
|
||||||
pchan->custom_shape_wire_width,
|
|
||||||
sel_id,
|
|
||||||
pchan->custom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Bone drawing strategy for ARM_OCTA. */
|
|
||||||
class ArmatureBoneDrawStrategyOcta : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
draw_bone_update_disp_matrix_default(bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext * /*ctx*/,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const override
|
|
||||||
{
|
|
||||||
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
|
||||||
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
|
||||||
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
|
||||||
|
|
||||||
auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
|
|
||||||
float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(bone.disp_mat());
|
|
||||||
|
|
||||||
if (ctx->is_filled) {
|
|
||||||
ctx->bone_buf->octahedral_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
|
|
||||||
}
|
|
||||||
if (col_wire[3] > 0.0f) {
|
|
||||||
ctx->bone_buf->octahedral_outline_buf.append({bone_mat, col_wire}, sel_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Bone drawing strategy for ARM_LINE. */
|
|
||||||
class ArmatureBoneDrawStrategyLine : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
draw_bone_update_disp_matrix_default(bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext * /*ctx*/,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const override
|
|
||||||
{
|
|
||||||
const float *col_bone = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
|
||||||
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
|
||||||
const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
const float *col_head = no_display;
|
|
||||||
const float *col_tail = col_bone;
|
|
||||||
|
|
||||||
if (ctx->const_color != nullptr) {
|
|
||||||
col_wire = no_display; /* actually shrink the display. */
|
|
||||||
col_bone = col_head = col_tail = ctx->const_color;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const UniformData &theme = ctx->res->theme;
|
|
||||||
|
|
||||||
if (bone.is_editbone() && bone.flag() & BONE_TIPSEL) {
|
|
||||||
col_tail = &theme.colors.vert_select.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Draw root point if we are not connected to our parent. */
|
|
||||||
if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
|
|
||||||
|
|
||||||
if (bone.is_editbone()) {
|
|
||||||
col_head = (bone.flag() & BONE_ROOTSEL) ? &theme.colors.vert_select.x : col_bone;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
col_head = col_bone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (select_id == -1) {
|
|
||||||
/* Not in bone selection mode (can still be object select mode), draw everything at once. */
|
|
||||||
drw_shgroup_bone_stick(
|
|
||||||
ctx, bone.disp_mat(), col_wire, col_bone, col_head, col_tail, select_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* In selection mode, draw bone, root and tip separately. */
|
|
||||||
drw_shgroup_bone_stick(ctx,
|
|
||||||
bone.disp_mat(),
|
|
||||||
col_wire,
|
|
||||||
col_bone,
|
|
||||||
no_display,
|
|
||||||
no_display,
|
|
||||||
select_id | BONESEL_BONE);
|
|
||||||
|
|
||||||
if (col_head[3] > 0.0f) {
|
|
||||||
drw_shgroup_bone_stick(ctx,
|
|
||||||
bone.disp_mat(),
|
|
||||||
col_wire,
|
|
||||||
no_display,
|
|
||||||
col_head,
|
|
||||||
no_display,
|
|
||||||
select_id | BONESEL_ROOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
drw_shgroup_bone_stick(ctx,
|
|
||||||
bone.disp_mat(),
|
|
||||||
col_wire,
|
|
||||||
no_display,
|
|
||||||
no_display,
|
|
||||||
col_tail,
|
|
||||||
select_id | BONESEL_TIP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Bone drawing strategy for ARM_B_BONE. */
|
|
||||||
class ArmatureBoneDrawStrategyBBone : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
draw_bone_update_disp_matrix_bbone(bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext * /*ctx*/,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const override
|
|
||||||
{
|
|
||||||
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
|
||||||
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
|
||||||
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
|
||||||
|
|
||||||
/* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
|
|
||||||
* This would require a deeper refactor. */
|
|
||||||
Span<Mat4> bbone_matrices;
|
|
||||||
if (bone.is_posebone()) {
|
|
||||||
bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
|
|
||||||
bone.as_posebone()->bone->segments};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
|
|
||||||
|
|
||||||
for (const Mat4 &in_bone_mat : bbone_matrices) {
|
|
||||||
float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(in_bone_mat.mat);
|
|
||||||
|
|
||||||
if (ctx->is_filled) {
|
|
||||||
ctx->bone_buf->bbones_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
|
|
||||||
}
|
|
||||||
if (col_wire[3] > 0.0f) {
|
|
||||||
ctx->bone_buf->bbones_outline_buf.append({bone_mat, col_wire}, sel_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
|
|
||||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Bone drawing strategy for ARM_ENVELOPE. */
|
|
||||||
class ArmatureBoneDrawStrategyEnvelope : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
draw_bone_update_disp_matrix_default(bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext * /*ctx*/,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const override
|
|
||||||
{
|
|
||||||
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
|
||||||
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
|
||||||
const float *col_hint = get_bone_hint_color(ctx, boneflag);
|
|
||||||
|
|
||||||
const float *rad_head, *rad_tail, *distance;
|
|
||||||
if (bone.is_editbone()) {
|
|
||||||
const EditBone *eBone = bone.as_editbone();
|
|
||||||
rad_tail = &eBone->rad_tail;
|
|
||||||
distance = &eBone->dist;
|
|
||||||
rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
|
|
||||||
&eBone->rad_head;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const bPoseChannel *pchan = bone.as_posebone();
|
|
||||||
rad_tail = &pchan->bone->rad_tail;
|
|
||||||
distance = &pchan->bone->dist;
|
|
||||||
rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
|
|
||||||
&pchan->bone->rad_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
|
|
||||||
((boneflag & BONE_SELECTED) ||
|
|
||||||
(bone.is_editbone() && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
|
|
||||||
{
|
|
||||||
drw_shgroup_bone_envelope_distance(ctx, bone.disp_mat(), rad_head, rad_tail, distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
drw_shgroup_bone_envelope(ctx,
|
|
||||||
bone.disp_mat(),
|
|
||||||
col_solid,
|
|
||||||
col_hint,
|
|
||||||
col_wire,
|
|
||||||
rad_head,
|
|
||||||
rad_tail,
|
|
||||||
select_id | BONESEL_BONE);
|
|
||||||
|
|
||||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Bone drawing strategy for ARM_WIRE. */
|
|
||||||
class ArmatureBoneDrawStrategyWire : public ArmatureBoneDrawStrategy {
|
|
||||||
public:
|
|
||||||
void update_display_matrix(UnifiedBonePtr bone) const override
|
|
||||||
{
|
|
||||||
draw_bone_update_disp_matrix_bbone(bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_context_setup(Armatures::DrawContext *ctx,
|
|
||||||
const bool /*is_filled*/,
|
|
||||||
const bool /*do_envelope_dist*/) const override
|
|
||||||
{
|
|
||||||
ctx->const_wire = 1.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_bone(const Armatures::DrawContext *ctx,
|
|
||||||
const UnifiedBonePtr bone,
|
|
||||||
const eBone_Flag boneflag,
|
|
||||||
const int select_id) const override
|
|
||||||
{
|
|
||||||
using namespace blender::math;
|
|
||||||
|
|
||||||
const float *col_wire = get_bone_wire_color(ctx, boneflag);
|
|
||||||
|
|
||||||
auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE) :
|
|
||||||
draw::select::SelectMap::select_invalid_id();
|
|
||||||
|
|
||||||
/* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
|
|
||||||
* This would require a deeper refactor. */
|
|
||||||
Span<Mat4> bbone_matrices;
|
|
||||||
if (bone.is_posebone()) {
|
|
||||||
bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
|
|
||||||
bone.as_posebone()->bone->segments};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const Mat4 &in_bone_mat : bbone_matrices) {
|
|
||||||
float4x4 bmat = float4x4(in_bone_mat.mat);
|
|
||||||
float3 head = transform_point(ctx->ob->object_to_world(), bmat.location());
|
|
||||||
float3 tail = transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
|
|
||||||
|
|
||||||
ctx->bone_buf->wire_buf.append(head, tail, float4(col_wire), sel_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bone.is_editbone()) {
|
|
||||||
const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
|
|
||||||
draw_points(ctx, bone, boneflag, col_solid, select_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
/**
|
|
||||||
* Armature drawing strategies.
|
|
||||||
*
|
|
||||||
* Declared statically here because they cost almost no memory (no fields in any
|
|
||||||
* of the structs, so just the virtual function table), and this makes it very
|
|
||||||
* simple to just pass references to them around.
|
|
||||||
*
|
|
||||||
* See the functions below.
|
|
||||||
*/
|
|
||||||
ArmatureBoneDrawStrategyOcta strat_octa;
|
|
||||||
ArmatureBoneDrawStrategyLine strat_line;
|
|
||||||
ArmatureBoneDrawStrategyBBone strat_b_bone;
|
|
||||||
ArmatureBoneDrawStrategyEnvelope strat_envelope;
|
|
||||||
ArmatureBoneDrawStrategyWire strat_wire;
|
|
||||||
ArmatureBoneDrawStrategyEmpty strat_empty;
|
|
||||||
}; // namespace
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the armature bone drawing strategy for the given draw type.
|
|
||||||
*
|
|
||||||
* Note that this does not consider custom bone shapes, as those can be set per bone.
|
|
||||||
* For those occasions just instance a `ArmatureBoneDrawStrategyCustomShape` and use that.
|
|
||||||
*/
|
|
||||||
static ArmatureBoneDrawStrategy &strategy_for_armature_drawtype(const eArmature_Drawtype drawtype)
|
|
||||||
{
|
|
||||||
switch (drawtype) {
|
|
||||||
case ARM_OCTA:
|
|
||||||
return strat_octa;
|
|
||||||
case ARM_LINE:
|
|
||||||
return strat_line;
|
|
||||||
case ARM_B_BONE:
|
|
||||||
return strat_b_bone;
|
|
||||||
case ARM_ENVELOPE:
|
|
||||||
return strat_envelope;
|
|
||||||
case ARM_WIRE:
|
|
||||||
return strat_wire;
|
|
||||||
}
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
return strat_empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Main Draw Loops
|
/** \name Main Draw Loops
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
static void bone_draw_update_display_matrix(const eArmature_Drawtype drawtype,
|
||||||
|
const bool use_custom_shape,
|
||||||
|
UnifiedBonePtr bone)
|
||||||
|
{
|
||||||
|
if (use_custom_shape) {
|
||||||
|
draw_bone_update_disp_matrix_custom_shape(bone);
|
||||||
|
}
|
||||||
|
else if (ELEM(drawtype, ARM_B_BONE, ARM_WIRE)) {
|
||||||
|
draw_bone_update_disp_matrix_bbone(bone);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
draw_bone_update_disp_matrix_default(bone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Armatures::draw_armature_edit(Armatures::DrawContext *ctx)
|
void Armatures::draw_armature_edit(Armatures::DrawContext *ctx)
|
||||||
{
|
{
|
||||||
Object *ob = ctx->ob;
|
Object *ob = ctx->ob;
|
||||||
@@ -2029,9 +1890,7 @@ void Armatures::draw_armature_edit(Armatures::DrawContext *ctx)
|
|||||||
|
|
||||||
edbo_compute_bbone_child(&arm);
|
edbo_compute_bbone_child(&arm);
|
||||||
|
|
||||||
/* Determine drawing strategy. */
|
const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
|
||||||
const ArmatureBoneDrawStrategy &draw_strat = strategy_for_armature_drawtype(
|
|
||||||
eArmature_Drawtype(arm.drawtype));
|
|
||||||
|
|
||||||
for (eBone = static_cast<EditBone *>(arm.edbo->first),
|
for (eBone = static_cast<EditBone *>(arm.edbo->first),
|
||||||
/* Note: Selection Next handles the object id merging later. */
|
/* Note: Selection Next handles the object id merging later. */
|
||||||
@@ -2064,11 +1923,14 @@ void Armatures::draw_armature_edit(Armatures::DrawContext *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is_select) {
|
if (!is_select) {
|
||||||
draw_bone_relations(ctx, draw_strat, bone, boneflag);
|
draw_bone_relations(ctx, bone, boneflag);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_strat.update_display_matrix(bone);
|
const eArmature_Drawtype drawtype = eBone->drawtype == ARM_BONE_DEFAULT ?
|
||||||
draw_strat.draw_bone(ctx, bone, boneflag, select_id);
|
arm_drawtype :
|
||||||
|
eArmature_Drawtype(eBone->drawtype);
|
||||||
|
bone_draw_update_display_matrix(drawtype, false, bone);
|
||||||
|
bone_draw(drawtype, false, ctx, bone, boneflag, select_id);
|
||||||
|
|
||||||
if (!is_select) {
|
if (!is_select) {
|
||||||
if (show_text && (arm.flag & ARM_DRAWNAMES)) {
|
if (show_text && (arm.flag & ARM_DRAWNAMES)) {
|
||||||
@@ -2156,9 +2018,7 @@ void Armatures::draw_armature_pose(Armatures::DrawContext *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArmatureBoneDrawStrategy &draw_strat_normal = strategy_for_armature_drawtype(
|
const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
|
||||||
eArmature_Drawtype(arm.drawtype));
|
|
||||||
const ArmatureBoneDrawStrategyCustomShape draw_strat_custom;
|
|
||||||
|
|
||||||
for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); pchan;
|
for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); pchan;
|
||||||
pchan = pchan->next, index += 0x10000)
|
pchan = pchan->next, index += 0x10000)
|
||||||
@@ -2196,14 +2056,15 @@ void Armatures::draw_armature_pose(Armatures::DrawContext *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool use_custom_shape = (pchan->custom) && !(arm.flag & ARM_NO_CUSTOM);
|
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;
|
|
||||||
if (!is_pose_select) {
|
if (!is_pose_select) {
|
||||||
draw_bone_relations(ctx, draw_strat, bone_ptr, boneflag);
|
draw_bone_relations(ctx, bone_ptr, boneflag);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_strat.update_display_matrix(bone_ptr);
|
const eArmature_Drawtype drawtype = bone->drawtype == ARM_BONE_DEFAULT ?
|
||||||
draw_strat.draw_bone(ctx, bone_ptr, boneflag, select_id);
|
arm_drawtype :
|
||||||
|
eArmature_Drawtype(bone->drawtype);
|
||||||
|
bone_draw_update_display_matrix(drawtype, use_custom_shape, bone_ptr);
|
||||||
|
bone_draw(drawtype, use_custom_shape, ctx, bone_ptr, boneflag, select_id);
|
||||||
|
|
||||||
/* Below this point nothing is used for selection queries. */
|
/* Below this point nothing is used for selection queries. */
|
||||||
if (is_pose_select) {
|
if (is_pose_select) {
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ EditBone *ED_armature_ebone_add(bArmature *arm, const char *name)
|
|||||||
BLI_addtail(arm->edbo, bone);
|
BLI_addtail(arm->edbo, bone);
|
||||||
|
|
||||||
bone->flag |= BONE_TIPSEL;
|
bone->flag |= BONE_TIPSEL;
|
||||||
|
bone->drawtype = ARM_BONE_DEFAULT;
|
||||||
bone->weight = 1.0f;
|
bone->weight = 1.0f;
|
||||||
bone->dist = 0.25f;
|
bone->dist = 0.25f;
|
||||||
bone->xwidth = 0.1f;
|
bone->xwidth = 0.1f;
|
||||||
@@ -1668,6 +1669,7 @@ static wmOperatorStatus armature_extrude_exec(bContext *C, wmOperator *op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
newbone->color = ebone->color;
|
newbone->color = ebone->color;
|
||||||
|
newbone->drawtype = ebone->drawtype;
|
||||||
|
|
||||||
newbone->weight = ebone->weight;
|
newbone->weight = ebone->weight;
|
||||||
newbone->dist = ebone->dist;
|
newbone->dist = ebone->dist;
|
||||||
|
|||||||
@@ -459,6 +459,7 @@ static EditBone *make_boneList_recursive(ListBase *edbo,
|
|||||||
STRNCPY(eBone->name, curBone->name);
|
STRNCPY(eBone->name, curBone->name);
|
||||||
eBone->flag = curBone->flag;
|
eBone->flag = curBone->flag;
|
||||||
eBone->inherit_scale_mode = curBone->inherit_scale_mode;
|
eBone->inherit_scale_mode = curBone->inherit_scale_mode;
|
||||||
|
eBone->drawtype = curBone->drawtype;
|
||||||
|
|
||||||
/* fix selection flags */
|
/* fix selection flags */
|
||||||
if (eBone->flag & BONE_SELECTED) {
|
if (eBone->flag & BONE_SELECTED) {
|
||||||
@@ -690,6 +691,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
|
|||||||
|
|
||||||
newBone->flag = eBone->flag;
|
newBone->flag = eBone->flag;
|
||||||
newBone->inherit_scale_mode = eBone->inherit_scale_mode;
|
newBone->inherit_scale_mode = eBone->inherit_scale_mode;
|
||||||
|
newBone->drawtype = eBone->drawtype;
|
||||||
|
|
||||||
if (eBone == arm->act_edbone) {
|
if (eBone == arm->act_edbone) {
|
||||||
/* Don't change active selection, this messes up separate which uses
|
/* Don't change active selection, this messes up separate which uses
|
||||||
|
|||||||
@@ -10,10 +10,6 @@
|
|||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name bArmature Struct
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
#define _DNA_DEFAULT_bArmature \
|
#define _DNA_DEFAULT_bArmature \
|
||||||
{ \
|
{ \
|
||||||
.deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE, \
|
.deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE, \
|
||||||
@@ -22,6 +18,9 @@
|
|||||||
.drawtype = ARM_OCTA, \
|
.drawtype = ARM_OCTA, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
#define _DNA_DEFAULT_Bone \
|
||||||
|
{ \
|
||||||
|
.drawtype = ARM_BONE_DEFAULT, \
|
||||||
|
}
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ typedef struct Bone {
|
|||||||
float bone_mat[3][3];
|
float bone_mat[3][3];
|
||||||
|
|
||||||
int flag;
|
int flag;
|
||||||
|
int8_t drawtype; /* eArmature_Drawtype */
|
||||||
char _pad1[4];
|
char _pad1[3];
|
||||||
BoneColor color; /* MUST be named the same as in bPoseChannel and EditBone structs. */
|
BoneColor color; /* MUST be named the same as in bPoseChannel and EditBone structs. */
|
||||||
|
|
||||||
char inherit_scale_mode;
|
char inherit_scale_mode;
|
||||||
@@ -188,7 +188,7 @@ typedef struct bArmature {
|
|||||||
char _pad0[3];
|
char _pad0[3];
|
||||||
|
|
||||||
int flag;
|
int flag;
|
||||||
int drawtype;
|
int drawtype; /* eArmature_Drawtype */
|
||||||
|
|
||||||
short deformflag;
|
short deformflag;
|
||||||
short pathflag;
|
short pathflag;
|
||||||
@@ -374,6 +374,7 @@ typedef enum eArmature_Flag {
|
|||||||
|
|
||||||
/* armature->drawtype */
|
/* armature->drawtype */
|
||||||
typedef enum eArmature_Drawtype {
|
typedef enum eArmature_Drawtype {
|
||||||
|
ARM_BONE_DEFAULT = -1, /* Use draw type from Armature (only used on Bones). */
|
||||||
ARM_OCTA = 0,
|
ARM_OCTA = 0,
|
||||||
ARM_LINE = 1,
|
ARM_LINE = 1,
|
||||||
ARM_B_BONE = 2,
|
ARM_B_BONE = 2,
|
||||||
|
|||||||
@@ -1363,6 +1363,32 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
|
|||||||
{0, nullptr, 0, nullptr, nullptr},
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const EnumPropertyItem prop_drawtype_items[] = {
|
||||||
|
{ARM_BONE_DEFAULT,
|
||||||
|
"USE_ARMATURE_SETTING",
|
||||||
|
0,
|
||||||
|
"Use Armature Setting",
|
||||||
|
"Use display mode from armature (default)"},
|
||||||
|
{ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Display bones as octahedral shape"},
|
||||||
|
{ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots"},
|
||||||
|
{ARM_B_BONE,
|
||||||
|
"BBONE",
|
||||||
|
0,
|
||||||
|
"B-Bone",
|
||||||
|
"Display bones as boxes, showing subdivision and B-Splines"},
|
||||||
|
{ARM_ENVELOPE,
|
||||||
|
"ENVELOPE",
|
||||||
|
0,
|
||||||
|
"Envelope",
|
||||||
|
"Display bones as extruded spheres, showing deformation influence volume"},
|
||||||
|
{ARM_WIRE,
|
||||||
|
"WIRE",
|
||||||
|
0,
|
||||||
|
"Wire",
|
||||||
|
"Display bones as thin wires, showing subdivision and B-Splines"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
/* strings */
|
/* strings */
|
||||||
@@ -1387,6 +1413,13 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
|
|||||||
RNA_def_property_pointer_funcs(prop, "rna_EditBone_color_get", nullptr, nullptr, nullptr);
|
RNA_def_property_pointer_funcs(prop, "rna_EditBone_color_get", nullptr, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_sdna(prop, nullptr, "drawtype");
|
||||||
|
RNA_def_property_enum_items(prop, prop_drawtype_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Display Type", "");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
|
||||||
|
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
prop = RNA_def_property(srna, "use_connect", PROP_BOOLEAN, PROP_NONE);
|
prop = RNA_def_property(srna, "use_connect", PROP_BOOLEAN, PROP_NONE);
|
||||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_CONNECTED);
|
RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_CONNECTED);
|
||||||
@@ -2144,6 +2177,7 @@ static void rna_def_armature(BlenderRNA *brna)
|
|||||||
"Display bones as thin wires, showing subdivision and B-Splines"},
|
"Display bones as thin wires, showing subdivision and B-Splines"},
|
||||||
{0, nullptr, 0, nullptr, nullptr},
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const EnumPropertyItem prop_pose_position_items[] = {
|
static const EnumPropertyItem prop_pose_position_items[] = {
|
||||||
{0, "POSE", 0, "Pose Position", "Show armature in posed state"},
|
{0, "POSE", 0, "Pose Position", "Show armature in posed state"},
|
||||||
{ARM_RESTPOS,
|
{ARM_RESTPOS,
|
||||||
|
|||||||
Reference in New Issue
Block a user