|
|
|
|
@@ -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
|
|
|
|
|
* \{ */
|
|
|
|
|
@@ -992,7 +942,7 @@ static void draw_bone_update_disp_matrix_default(UnifiedBonePtr bone)
|
|
|
|
|
float(*disp_tail_mat)[4] = bone.disp_tail_mat();
|
|
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
if (bone.is_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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
if (bone.is_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
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
/** 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,
|
|
|
|
|
const bPoseChannel *pchan,
|
|
|
|
|
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,
|
|
|
|
|
const ArmatureBoneDrawStrategy &draw_strategy,
|
|
|
|
|
const UnifiedBonePtr bone,
|
|
|
|
|
const eBone_Flag boneflag)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
|
|
|
|
|
const EditBone *ebone = bone.as_editbone();
|
|
|
|
|
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(
|
|
|
|
|
ctx, ebone->head, ebone->parent->head, ebone->parent->tail);
|
|
|
|
|
}
|
|
|
|
|
@@ -1511,7 +1799,7 @@ static void draw_bone_relations(const Armatures::DrawContext *ctx,
|
|
|
|
|
else {
|
|
|
|
|
const bPoseChannel *pchan = bone.as_posebone();
|
|
|
|
|
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(
|
|
|
|
|
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
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
Object *ob = ctx->ob;
|
|
|
|
|
@@ -2029,9 +1890,7 @@ void Armatures::draw_armature_edit(Armatures::DrawContext *ctx)
|
|
|
|
|
|
|
|
|
|
edbo_compute_bbone_child(&arm);
|
|
|
|
|
|
|
|
|
|
/* Determine drawing strategy. */
|
|
|
|
|
const ArmatureBoneDrawStrategy &draw_strat = strategy_for_armature_drawtype(
|
|
|
|
|
eArmature_Drawtype(arm.drawtype));
|
|
|
|
|
const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
|
|
|
|
|
|
|
|
|
|
for (eBone = static_cast<EditBone *>(arm.edbo->first),
|
|
|
|
|
/* Note: Selection Next handles the object id merging later. */
|
|
|
|
|
@@ -2064,11 +1923,14 @@ void Armatures::draw_armature_edit(Armatures::DrawContext *ctx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_select) {
|
|
|
|
|
draw_bone_relations(ctx, draw_strat, bone, boneflag);
|
|
|
|
|
draw_bone_relations(ctx, bone, boneflag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
draw_strat.update_display_matrix(bone);
|
|
|
|
|
draw_strat.draw_bone(ctx, bone, boneflag, select_id);
|
|
|
|
|
const eArmature_Drawtype drawtype = eBone->drawtype == ARM_BONE_DEFAULT ?
|
|
|
|
|
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 (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(
|
|
|
|
|
eArmature_Drawtype(arm.drawtype));
|
|
|
|
|
const ArmatureBoneDrawStrategyCustomShape draw_strat_custom;
|
|
|
|
|
const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
|
|
|
|
|
|
|
|
|
|
for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); pchan;
|
|
|
|
|
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 ArmatureBoneDrawStrategy &draw_strat = use_custom_shape ? draw_strat_custom :
|
|
|
|
|
draw_strat_normal;
|
|
|
|
|
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);
|
|
|
|
|
draw_strat.draw_bone(ctx, bone_ptr, boneflag, select_id);
|
|
|
|
|
const eArmature_Drawtype drawtype = bone->drawtype == ARM_BONE_DEFAULT ?
|
|
|
|
|
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. */
|
|
|
|
|
if (is_pose_select) {
|
|
|
|
|
|