Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2018-08-07 21:08:16 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2018-10-04 19:55:44 +0300
commit65f77ccea1645f8c66fc171377641b08b62010e0 (patch)
tree8ff90e2385cadcbe7e50a4de0ffd062fea182668 /source
parent61a24c799b2882c22a43591138a113d7f09be0ed (diff)
Fix T56268: display the correct rest shape for B-Bones in Edit Mode.
The rest shape of B-Bones is actually affected by custom handles or the default connected parent/child mechanism. Ignoring these effects thus leads to the edit mode shape being different from the actual rest pose. This splits the b_bone_spline_setup function that is used to compute the correct rest and pose shape from pose channels into two parts, and applies the data structure independent half to edit mode. In order to access the custom handle settings in Edit Mode, they are moved to Bone and EditBone, while the bPoseChannel fields are downgraded in status to a cache for performance. Also, instead of flags, introduce an enum to specify the handle operation modes, so that new ones could be added later. Reviewers: aligorith, brecht Differential Revision: https://developer.blender.org/D3588
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_armature.h25
-rw-r--r--source/blender/blenkernel/intern/armature.c289
-rw-r--r--source/blender/draw/intern/draw_armature.c148
-rw-r--r--source/blender/editors/include/ED_armature.h2
4 files changed, 297 insertions, 167 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 44120d182b7..abcf1388c55 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -140,11 +140,34 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
+typedef struct BBoneSplineParameters {
+ int segments;
+ float length;
+
+ /* Non-uniform scale correction. */
+ bool do_scale;
+ float scale[3];
+
+ /* Handle control bone data. */
+ bool use_prev, prev_bbone;
+ bool use_next, next_bbone;
+
+ float prev_h[3], next_h[3];
+ float prev_mat[4][4], next_mat[4][4];
+
+ /* Control values. */
+ float ease1, ease2;
+ float roll1, roll2;
+ float scaleIn, scaleOut;
+ float curveInX, curveInY, curveOutX, curveOutY;
+} BBoneSplineParameters;
+
void BKE_pchan_get_bbone_handles(struct bPoseChannel *pchan, struct bPoseChannel **r_prev, struct bPoseChannel **r_next);
-void equalize_bbone_bezier(float *data, int desired);
void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
+int BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]);
+
/* like EBONE_VISIBLE */
#define PBONE_VISIBLE(arm, bone) ( \
CHECK_TYPE_INLINE(arm, bArmature *), \
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 61472068399..5ffb38414a8 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -393,7 +393,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-void equalize_bbone_bezier(float *data, int desired)
+static void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -460,59 +460,63 @@ void BKE_pchan_get_bbone_handles(bPoseChannel *pchan, bPoseChannel **r_prev, bPo
}
}
-/* returns pointer to static array, filled with desired amount of bone->segments elements */
-/* this calculation is done within unit bone space */
+/* Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space. */
void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV])
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
- float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
- float data[MAX_BBONE_SUBDIV + 1][4], *fp;
- int a;
- bool do_scale = false;
+ BBoneSplineParameters param;
+ float imat[4][4], posemat[4][4];
- length = bone->length;
+ memset(&param, 0, sizeof(param));
+
+ param.segments = bone->segments;
+ param.length = bone->length;
if (!rest) {
- /* check if we need to take non-uniform bone scaling into account */
+ float scale[3];
+
+ /* Check if we need to take non-uniform bone scaling into account. */
mat4_to_size(scale, pchan->pose_mat);
if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) {
- size_to_mat4(scalemat, scale);
- invert_m4_m4(iscalemat, scalemat);
-
- length *= scale[1];
- do_scale = 1;
+ param.do_scale = true;
+ copy_v3_v3(param.scale, scale);
}
}
BKE_pchan_get_bbone_handles(pchan, &prev, &next);
- /* find the handle points, since this is inside bone space, the
+ /* Find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
* last point = (0, length, 0) */
if (rest) {
invert_m4_m4(imat, pchan->bone->arm_mat);
}
- else if (do_scale) {
+ else if (param.do_scale) {
copy_m4_m4(posemat, pchan->pose_mat);
normalize_m4(posemat);
invert_m4_m4(imat, posemat);
}
- else
+ else {
invert_m4_m4(imat, pchan->pose_mat);
+ }
if (prev) {
- float difmat[4][4], result[3][3], imat3[3][3];
+ float h1[3];
+ bool done = false;
- /* transform previous point inside this bone space */
- if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE)
- {
- /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ param.use_prev = true;
+ param.prev_bbone = (prev->bone->segments > 1);
+
+ /* Transform previous point inside this bone space. */
+ if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head. */
if (rest) {
- /* in restpose, arm_head == pose_head */
- h1[0] = h1[1] = h1[2] = 0.0f;
+ /* In restpose, arm_head == pose_head */
+ zero_v3(param.prev_h);
+ done = true;
}
else {
float delta[3];
@@ -521,16 +525,125 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
else {
- /* Use bone head as absolute position */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ /* Use bone head as absolute position. */
+ copy_v3_v3(h1, rest ? prev->bone->arm_head : prev->pose_head);
+ }
+
+ if (!done) {
+ mul_v3_m4v3(param.prev_h, imat, h1);
+ }
+
+ if (!param.prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ mul_m4_m4m4(param.prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
+ }
+ }
+
+ if (next) {
+ float h2[3];
+ bool done = false;
+
+ param.use_next = true;
+ param.next_bbone = (next->bone->segments > 1);
+
+ /* Transform next point inside this bone space. */
+ if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail. */
+ if (rest) {
+ /* In restpose, arm_tail == pose_tail */
+ copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+ done = true;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else {
+ /* Use bone tail as absolute position. */
+ copy_v3_v3(h2, rest ? next->bone->arm_tail : next->pose_tail);
+ }
+
+ if (!done) {
+ mul_v3_m4v3(param.next_h, imat, h2);
}
- mul_m4_v3(imat, h1);
- if (prev->bone->segments > 1) {
- /* if previous bone is B-bone too, use average handle direction */
+ /* Find the next roll to interpolate as well. */
+ mul_m4_m4m4(param.next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ param.ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
+ param.ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
+
+ param.roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ param.roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone) {
+ param.roll1 += prev->bone->roll2;
+ }
+
+ if (!rest) {
+ param.roll1 += prev->roll2;
+ }
+ }
+ }
+
+ param.scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ param.scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+
+ /* Extra curve x / y */
+ param.curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f);
+ param.curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f);
+
+ param.curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f);
+ param.curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f);
+ }
+
+ bone->segments = BKE_compute_b_bone_spline(&param, result_array);
+}
+
+/* Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space. */
+int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ float scalemat[4][4], iscalemat[4][4];
+ float result[3][3], mat3[3][3], imat3[3][3];
+ float h1[3], roll1, h2[3], roll2;
+ float data[MAX_BBONE_SUBDIV + 1][4], *fp;
+ int a;
+
+ float length = param->length;
+
+ if (param->do_scale) {
+ size_to_mat4(scalemat, param->scale);
+ invert_m4_m4(iscalemat, scalemat);
+
+ length *= param->scale[1];
+ }
+
+ if (param->use_prev) {
+ copy_v3_v3(h1, param->prev_h);
+
+ if (param->prev_bbone) {
+ /* If previous bone is B-bone too, use average handle direction. */
h1[1] -= length;
roll1 = 0.0f;
}
@@ -538,13 +651,9 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
normalize_v3(h1);
negate_v3(h1);
- if (prev->bone->segments == 1) {
- /* find the previous roll to interpolate */
- if (rest)
- mul_m4_m4m4(difmat, imat, prev->bone->arm_mat);
- else
- mul_m4_m4m4(difmat, imat, prev->pose_mat);
- copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */
+ if (!param->prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ copy_m3_m4(result, param->prev_mat); /* the desired rotation at beginning of next bone */
vec_roll_to_mat3(h1, 0.0f, mat3); /* the result of vec_roll without roll */
@@ -558,47 +667,22 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
roll1 = 0.0f;
}
- if (next) {
- float difmat[4][4], result[3][3], imat3[3][3];
- /* transform next point inside this bone space */
- if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE)
- {
- /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
- if (rest) {
- /* in restpose, arm_tail == pose_tail */
- h2[0] = h2[1] = h2[2] = 0.0f;
- }
- else {
- float delta[3];
- sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
- add_v3_v3v3(h2, pchan->pose_tail, delta);
- }
- }
- else {
- /* Use bone tail as absolute position */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
- }
- mul_m4_v3(imat, h2);
+ if (param->use_next) {
+ copy_v3_v3(h2, param->next_h);
- /* if next bone is B-bone too, use average handle direction */
- if (next->bone->segments > 1) {
+ /* If next bone is B-bone too, use average handle direction. */
+ if (param->next_bbone) {
/* pass */
}
else {
h2[1] -= length;
}
+
normalize_v3(h2);
- /* find the next roll to interpolate as well */
- if (rest)
- mul_m4_m4m4(difmat, imat, next->bone->arm_mat);
- else
- mul_m4_m4m4(difmat, imat, next->pose_mat);
- copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */
+ /* Find the next roll to interpolate as well. */
+ copy_m3_m4(result, param->next_mat); /* the desired rotation at beginning of next bone */
vec_roll_to_mat3(h2, 0.0f, mat3); /* the result of vec_roll without roll */
@@ -606,7 +690,6 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
mul_m3_m3m3(mat3, imat3, result); /* the matrix transforming vec_roll to desired roll */
roll2 = atan2f(mat3[2][0], mat3[2][2]);
-
}
else {
h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
@@ -616,10 +699,8 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
- const float combined_ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
- const float combined_ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
- const float hlength1 = combined_ease1 * circle_factor;
- const float hlength2 = combined_ease2 * circle_factor;
+ const float hlength1 = param->ease1 * circle_factor;
+ const float hlength2 = param->ease2 * circle_factor;
/* and only now negate h2 */
mul_v3_fl(h1, hlength1);
@@ -641,67 +722,56 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
* end up animating
*/
{
- /* add extra rolls */
- roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
- roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
-
- if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
- if (prev) {
- if (prev->bone)
- roll1 += prev->bone->roll2;
-
- if (!rest)
- roll1 += prev->roll2;
- }
- }
+ /* Add extra rolls. */
+ roll1 += param->roll1;
+ roll2 += param->roll2;
- /* extra curve x / y */
+ /* Extra curve x / y */
/* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
* when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
* in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
*/
- const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
- const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+ const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f;
+ const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
- h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
- h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+ h1[0] += param->curveInX * xscale_correction;
+ h1[2] += param->curveInY * yscale_correction;
- h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
- h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ h2[0] += param->curveOutX * xscale_correction;
+ h2[2] += param->curveOutY * yscale_correction;
}
- /* make curve */
- if (bone->segments > MAX_BBONE_SUBDIV)
- bone->segments = MAX_BBONE_SUBDIV;
+ /* Make curve. */
+ CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV);
BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], param->segments); /* note: does stride 4! */
- /* make transformation matrices for the segments for drawing */
- for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
+ /* Make transformation matrices for the segments for drawing. */
+ for (a = 0, fp = data[0]; a < param->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
- if (do_scale) {
- /* correct for scaling when this matrix is used in scaled space */
+ if (param->do_scale) {
+ /* Correct for scaling when this matrix is used in scaled space. */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
/* BBone scale... */
{
- const int num_segments = bone->segments;
+ const int num_segments = param->segments;
- const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleIn = param->scaleIn;
const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
- const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleOut = param->scaleOut;
const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
const float scalefac = scaleFactorIn * scaleFactorOut;
@@ -717,8 +787,9 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
/*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
}
-
}
+
+ return param->segments;
}
/* ************ Armature Deform ******************* */
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index 777775cf8ca..e0ce5751956 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -918,80 +918,113 @@ static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
}
-/* XXX Direct copy from drawarmature.c... This is ugly! */
-/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
- *
- * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight"
- * position here anyway), and that we can simply apply the bbone settings to get the desired effect...
- */
-static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
+/* compute connected child pointer for B-Bone drawing */
+static void edbo_compute_bbone_child(bArmature *arm)
{
- float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f;
- float mat3[3][3];
- float data[MAX_BBONE_SUBDIV + 1][4], *fp;
- int a;
-
- length = ebone->length;
+ EditBone *eBone;
- hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
- hlength2 = ebone->ease2 * length * 0.390464f;
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ eBone->bbone_child = NULL;
+ }
- /* find the handle points, since this is inside bone space, the
- * first point = (0, 0, 0)
- * last point = (0, length, 0)
- *
- * we also just apply all the "extra effects", since they're the whole reason we're doing this...
- */
- h1[0] = ebone->curveInX;
- h1[1] = hlength1;
- h1[2] = ebone->curveInY;
- roll1 = ebone->roll1;
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->bbone_child = eBone;
+ }
+ }
+}
- h2[0] = ebone->curveOutX;
- h2[1] = -hlength2;
- h2[2] = ebone->curveOutY;
- roll2 = ebone->roll2;
+/* A version of b_bone_spline_setup() for previewing editmode curve settings. */
+static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
+{
+ BBoneSplineParameters param;
+ EditBone *prev, *next;
+ float imat[4][4], bonemat[4][4];
- /* make curve */
- if (ebone->segments > MAX_BBONE_SUBDIV)
- ebone->segments = MAX_BBONE_SUBDIV;
+ memset(&param, 0, sizeof(param));
- BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
- BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ param.segments = ebone->segments;
+ param.length = ebone->length;
- equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */
+ /* Get "next" and "prev" bones - these are used for handle calculations. */
+ if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (ebone->flag & BONE_CONNECTED) {
+ prev = ebone->parent;
+ }
+ else {
+ prev = NULL;
+ }
+ }
+ else {
+ prev = ebone->bbone_prev;
+ }
- /* make transformation matrices for the segments for drawing */
- for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) {
- sub_v3_v3v3(h1, fp + 4, fp);
- vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
+ if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ next = ebone->bbone_child;
+ }
+ else {
+ next = ebone->bbone_next;
+ }
- copy_m4_m3(result_array[a], mat3);
- copy_v3_v3(result_array[a][3], fp);
+ /* compute handles from connected bones */
+ if (prev || next) {
+ ED_armature_ebone_to_mat4(ebone, imat);
+ invert_m4(imat);
- /* "extra" scale facs... */
- {
- const int num_segments = ebone->segments;
+ if (prev) {
+ param.use_prev = true;
+ param.prev_bbone = (prev->segments > 1);
- const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
- const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+ if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ zero_v3(param.prev_h);
+ }
+ else {
+ mul_v3_m4v3(param.prev_h, imat, prev->head);
+ }
- const float scalefac = scaleFactorIn * scaleFactorOut;
- float bscalemat[4][4], bscale[3];
+ if (!param.prev_bbone) {
+ ED_armature_ebone_to_mat4(prev, bonemat);
+ mul_m4_m4m4(param.prev_mat, imat, bonemat);
+ }
+ }
- bscale[0] = scalefac;
- bscale[1] = 1.0f;
- bscale[2] = scalefac;
+ if (next) {
+ param.use_next = true;
+ param.next_bbone = (next->segments > 1);
- size_to_mat4(bscalemat, bscale);
+ if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+ }
+ else {
+ mul_v3_m4v3(param.next_h, imat, next->tail);
+ }
- /* Note: don't multiply by inverse scale mat here,
- * as it causes problems with scaling shearing and breaking segment chains */
- mul_m4_series(result_array[a], result_array[a], bscalemat);
+ ED_armature_ebone_to_mat4(next, bonemat);
+ mul_m4_m4m4(param.next_mat, imat, bonemat);
}
}
+
+ param.ease1 = ebone->ease1;
+ param.ease2 = ebone->ease2;
+ param.roll1 = ebone->roll1;
+ param.roll2 = ebone->roll2;
+
+ if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
+ param.roll1 += prev->roll2;
+ }
+
+ param.scaleIn = ebone->scaleIn;
+ param.scaleOut = ebone->scaleOut;
+
+ param.curveInX = ebone->curveInX;
+ param.curveInY = ebone->curveInY;
+
+ param.curveOutX = ebone->curveOutX;
+ param.curveOutY = ebone->curveOutY;
+
+ ebone->segments = BKE_compute_b_bone_spline(&param, (Mat4*)result_array);
}
static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan)
@@ -1624,6 +1657,7 @@ static void draw_armature_edit(Object *ob)
const bool is_select = DRW_state_is_select();
update_color(ob, NULL);
+ edbo_compute_bbone_child(arm);
const bool show_text = DRW_state_show_text();
const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 9347d2037b0..7bade53cdf4 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -101,6 +101,8 @@ typedef struct EditBone {
/* 32 == MAX_BBONE_SUBDIV */
float disp_bbone_mat[32][4][4]; /* in Armature space, rest pos matrix */
+ struct EditBone *bbone_child; /* connected child temporary during drawing */
+
/* Used to store temporary data */
union {
struct EditBone *ebone;