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
diff options
context:
space:
mode:
-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;