diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2018-11-24 15:12:24 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2018-11-27 09:31:34 +0300 |
commit | a58f0eea4f1e9b04e519e123eb656009cf718f9e (patch) | |
tree | d3459d3c43d9602fe1f0c2e1678bb565601144d6 /source/blender | |
parent | fe65867c3dd99f33c1b2a8f509027021d43063bf (diff) |
RNA: expose access to B-Bone shape data from Python.
B-Bone shape is a non-trivial computation, so access to
the results would be useful for Python scripts working with
B-Bones, e.g. rig generation.
This exposes both final segment matrices, and the tangent
vectors computed from the custom handle bones.
Since the handle tangents use the axis+roll orientation math
of edit bones, add matrix conversion static methods to Bone.
Reviewers: campbellbarton
Differential Revision: https://developer.blender.org/D3983
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 124 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature_update.c | 11 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_armature_api.c | 53 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_pose_api.c | 71 |
5 files changed, 206 insertions, 55 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 1831e93cccb..0e356c1557f 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -165,9 +165,11 @@ typedef struct BBoneSplineParameters { } BBoneSplineParameters; void BKE_pchan_get_bbone_handles(struct bPoseChannel *pchan, struct bPoseChannel **r_prev, struct bPoseChannel **r_next); +void BKE_pchan_get_bbone_spline_parameters(struct bPoseChannel *pchan, const bool rest, struct BBoneSplineParameters *r_param); void b_bone_spline_setup(struct bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]); +void BKE_compute_b_bone_handles(const BBoneSplineParameters *param, float h1[3], float *r_roll1, float h2[3], float *r_roll2, bool ease, bool offsets); int BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]); void BKE_pchan_cache_bbone_segments(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 2004b66c1ef..9abd20679d8 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -462,20 +462,18 @@ void BKE_pchan_get_bbone_handles(bPoseChannel *pchan, bPoseChannel **r_prev, bPo } } -/* 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, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]) +/* Compute B-Bone spline parameters for the given channel. */ +void BKE_pchan_get_bbone_spline_parameters(struct bPoseChannel *pchan, const bool rest, struct BBoneSplineParameters *param) { bPoseChannel *next, *prev; Bone *bone = pchan->bone; - BBoneSplineParameters param; float imat[4][4], posemat[4][4]; float delta[3]; - memset(¶m, 0, sizeof(param)); + memset(param, 0, sizeof(*param)); - param.segments = bone->segments; - param.length = bone->length; + param->segments = bone->segments; + param->length = bone->length; if (!rest) { float scale[3]; @@ -484,8 +482,8 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array mat4_to_size(scale, pchan->pose_mat); if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) { - param.do_scale = true; - copy_v3_v3(param.scale, scale); + param->do_scale = true; + copy_v3_v3(param->scale, scale); } } @@ -497,7 +495,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array if (rest) { invert_m4_m4(imat, pchan->bone->arm_mat); } - else if (param.do_scale) { + else if (param->do_scale) { copy_m4_m4(posemat, pchan->pose_mat); normalize_m4(posemat); invert_m4_m4(imat, posemat); @@ -510,14 +508,14 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array float h1[3]; bool done = false; - param.use_prev = true; + param->use_prev = true; /* 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 */ - zero_v3(param.prev_h); + zero_v3(param->prev_h); done = true; } else { @@ -538,19 +536,19 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array } else { /* Apply special handling for smoothly joining B-Bone chains */ - param.prev_bbone = (prev->bone->segments > 1); + param->prev_bbone = (prev->bone->segments > 1); /* 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); + mul_v3_m4v3(param->prev_h, imat, h1); } - if (!param.prev_bbone) { + 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); + mul_m4_m4m4(param->prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat); } } @@ -558,14 +556,14 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array float h2[3]; bool done = false; - param.use_next = true; + param->use_next = true; /* 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_head == pose_head */ - copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0); + copy_v3_fl3(param->next_h, 0.0f, param->length, 0.0); done = true; } else { @@ -586,18 +584,18 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array } else { /* Apply special handling for smoothly joining B-Bone chains */ - param.next_bbone = (next->bone->segments > 1); + param->next_bbone = (next->bone->segments > 1); /* 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_v3_m4v3(param->next_h, imat, h2); } /* Find the next roll to interpolate as well. */ - mul_m4_m4m4(param.next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat); + mul_m4_m4m4(param->next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat); } /* Add effects from bbone properties over the top @@ -615,64 +613,65 @@ void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array * end up animating */ { - param.ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f); - param.ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f); + 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); + 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; + param->roll1 += prev->bone->roll2; } if (!rest) { - param.roll1 += prev->roll2; + param->roll1 += prev->roll2; } } } - param.scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f); - param.scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f); + 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->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); + 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(¶m, 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]) +void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]) { - float scalemat[4][4], iscalemat[4][4]; - float mat3[3][3]; - float h1[3], roll1, h2[3], roll2; - float data[MAX_BBONE_SUBDIV + 1][4], *fp; - int a; + BBoneSplineParameters param; + + BKE_pchan_get_bbone_spline_parameters(pchan, rest, ¶m); + pchan->bone->segments = BKE_compute_b_bone_spline(¶m, result_array); +} + +/* Computes the bezier handle vectors and rolls coming from custom handles. */ +void BKE_compute_b_bone_handles(const BBoneSplineParameters *param, float h1[3], float *r_roll1, float h2[3], float *r_roll2, bool ease, bool offsets) +{ + float mat3[3][3]; float length = param->length; if (param->do_scale) { - size_to_mat4(scalemat, param->scale); - invert_m4_m4(iscalemat, scalemat); - length *= param->scale[1]; } + *r_roll1 = *r_roll2 = 0.0f; + 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; } normalize_v3(h1); @@ -681,12 +680,11 @@ int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MA if (!param->prev_bbone) { /* Find the previous roll to interpolate. */ copy_m3_m4(mat3, param->prev_mat); - mat3_vec_to_roll(mat3, h1, &roll1); + mat3_vec_to_roll(mat3, h1, r_roll1); } } else { h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f; - roll1 = 0.0f; } if (param->use_next) { @@ -704,14 +702,13 @@ int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MA /* Find the next roll to interpolate as well. */ copy_m3_m4(mat3, param->next_mat); - mat3_vec_to_roll(mat3, h2, &roll2); + mat3_vec_to_roll(mat3, h2, r_roll2); } else { h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f; - roll2 = 0.0; } - { + if (ease) { const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f); const float hlength1 = param->ease1 * circle_factor; @@ -736,10 +733,10 @@ int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MA * - The "pchan" level offsets are the ones that animators actually * end up animating */ - { + if (offsets) { /* Add extra rolls. */ - roll1 += param->roll1; - roll2 += param->roll2; + *r_roll1 += param->roll1; + *r_roll2 += param->roll2; /* Extra curve x / y */ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches @@ -755,6 +752,27 @@ int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MA h2[0] += param->curveOutX * xscale_correction; h2[2] += param->curveOutY * yscale_correction; } +} + +/* 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 mat3[3][3]; + float h1[3], roll1, h2[3], roll2; + float data[MAX_BBONE_SUBDIV + 1][4], *fp; + float length = param->length; + int a; + + if (param->do_scale) { + size_to_mat4(scalemat, param->scale); + invert_m4_m4(iscalemat, scalemat); + + length *= param->scale[1]; + } + + BKE_compute_b_bone_handles(param, h1, &roll1, h2, &roll2, true, true); /* Make curve. */ CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV); diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index b917aae08de..f5519966ac2 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -715,17 +715,24 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]); copy_m4_m4(pchan_orig->constinv, pchan->constinv); BKE_pose_where_is_bone_tail(pchan_orig); + if (pchan->bone == NULL || pchan->bone->segments <= 1) { + BKE_pose_channel_free_bbone_cache(pchan_orig); + } } } void BKE_pose_eval_bbone_segments(struct Depsgraph *depsgraph, - struct Object *ob, - int pchan_index) + struct Object *ob, + int pchan_index) { bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan); if (pchan->bone != NULL && pchan->bone->segments > 1) { BKE_pchan_cache_bbone_segments(pchan); + bArmature *arm = (bArmature *)ob->data; + if (DEG_is_active(depsgraph) && arm->edbo == NULL) { + BKE_pchan_copy_bbone_segments_cache(pchan->orig_pchan, pchan); + } } } diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c index 222baf99afd..55caac973d8 100644 --- a/source/blender/makesrna/intern/rna_armature_api.c +++ b/source/blender/makesrna/intern/rna_armature_api.c @@ -42,6 +42,7 @@ #include <stddef.h> +#include "BLI_math_vector.h" #include "BKE_armature.h" static void rna_EditBone_align_roll(EditBone *ebo, float no[3]) @@ -56,6 +57,24 @@ static float rna_Bone_do_envelope(Bone *bone, float *vec) bone->rad_tail * scale, bone->dist * scale); } +static void rna_Bone_MatrixFromAxisRoll(float *axis, float roll, float *r_matrix) +{ + vec_roll_to_mat3(axis, roll, (float (*)[3])r_matrix); +} + +static void rna_Bone_AxisRollFromMatrix(float *matrix, float *axis_override, float *r_axis, float *r_roll) +{ + float mat[3][3]; + + normalize_m3_m3(mat, (float (*)[3])matrix); + + if (normalize_v3_v3(r_axis, axis_override) != 0.0f) { + mat3_vec_to_roll(mat, r_axis, r_roll); + } + else { + mat3_to_vec_roll(mat, r_axis, r_roll); + } +} #else void RNA_api_armature_edit_bone(StructRNA *srna) @@ -83,6 +102,40 @@ void RNA_api_bone(StructRNA *srna) /* return value */ parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); + + /* Conversions between Matrix and Axis + Roll representations. */ + func = RNA_def_function(srna, "MatrixFromAxisRoll", "rna_Bone_MatrixFromAxisRoll"); + RNA_def_function_ui_description(func, "Convert the axis + roll representation to a matrix"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_property(func, "axis", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(parm, 3); + RNA_def_property_ui_text(parm, "", "The main axis of the bone (tail - head)"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_property(func, "roll", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(parm, "", "The roll of the bone"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_property(func, "result_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_3x3); + RNA_def_property_ui_text(parm, "", "The resulting orientation matrix"); + RNA_def_function_output(func, parm); + + func = RNA_def_function(srna, "AxisRollFromMatrix", "rna_Bone_AxisRollFromMatrix"); + RNA_def_function_ui_description(func, "Convert a rotational matrix to the axis + roll representation"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_3x3); + RNA_def_property_ui_text(parm, "", "The orientation matrix of the bone"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_property(func, "axis", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_array(parm, 3); + RNA_def_property_ui_text(parm, "", "The optional override for the axis (finds closest approximation for the matrix)"); + parm = RNA_def_property(func, "result_axis", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(parm, 3); + RNA_def_property_ui_text(parm, "", "The main axis of the bone"); + RNA_def_function_output(func, parm); + parm = RNA_def_property(func, "result_roll", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(parm, "", "The roll of the bone"); + RNA_def_function_output(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index 04ecdd497f6..f4463e0f7d8 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -59,6 +59,45 @@ static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec) return distfactor_to_bone(vec, chan->pose_head, chan->pose_tail, bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale); } + +static void rna_PoseBone_bbone_segment_matrix(bPoseChannel *pchan, ReportList *reports, float mat_ret[16], int index, bool rest) +{ + if (!pchan->bone || pchan->bone->segments <= 1) { + BKE_reportf(reports, RPT_ERROR, "Bone '%s' is not a B-Bone!", pchan->name); + return; + } + if (pchan->runtime.bbone_segments != pchan->bone->segments) { + BKE_reportf(reports, RPT_ERROR, "Bone '%s' has out of date B-Bone segment data!", pchan->name); + return; + } + if (index < 0 || index >= pchan->runtime.bbone_segments) { + BKE_reportf(reports, RPT_ERROR, "Invalid index %d for B-Bone segments of '%s'!", index, pchan->name); + return; + } + + if (rest) { + copy_m4_m4((float (*)[4])mat_ret, pchan->runtime.bbone_rest_mats[index].mat); + } + else { + copy_m4_m4((float (*)[4])mat_ret, pchan->runtime.bbone_pose_mats[index].mat); + } +} + +static void rna_PoseBone_compute_bbone_handles( + bPoseChannel *pchan, ReportList *reports, + float ret_h1[3], float *ret_roll1, float ret_h2[3], float *ret_roll2, + bool rest, bool ease, bool offsets) +{ + if (!pchan->bone || pchan->bone->segments <= 1) { + BKE_reportf(reports, RPT_ERROR, "Bone '%s' is not a B-Bone!", pchan->name); + return; + } + + BBoneSplineParameters params; + + BKE_pchan_get_bbone_spline_parameters(pchan, rest, ¶ms); + BKE_compute_b_bone_handles(¶ms, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets); +} #else void RNA_api_pose(StructRNA *UNUSED(srna)) @@ -80,6 +119,38 @@ void RNA_api_pose_channel(StructRNA *srna) /* return value */ parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); + + /* B-Bone segment matrices */ + func = RNA_def_function(srna, "bbone_segment_matrix", "rna_PoseBone_bbone_segment_matrix"); + RNA_def_function_ui_description(func, "Retrieve the matrix of the B-Bone segment if available"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_property(func, "matrix_return", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The resulting matrix in bone local space"); + RNA_def_function_output(func, parm); + parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the segment", 0, 10000); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "rest", false, "", "Return the rest pose matrix"); + + /* B-Bone custom handle positions */ + func = RNA_def_function(srna, "compute_bbone_handles", "rna_PoseBone_compute_bbone_handles"); + RNA_def_function_ui_description(func, "Retrieve the vectors and rolls coming from B-Bone custom handles"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_property(func, "handle1", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(parm, 3); + RNA_def_property_ui_text(parm, "", "The direction vector of the start handle in bone local space"); + RNA_def_function_output(func, parm); + parm = RNA_def_float(func, "roll1", 0, -FLT_MAX, FLT_MAX, "", "Roll of the start handle", -FLT_MAX, FLT_MAX); + RNA_def_function_output(func, parm); + parm = RNA_def_property(func, "handle2", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(parm, 3); + RNA_def_property_ui_text(parm, "", "The direction vector of the end handle in bone local space"); + RNA_def_function_output(func, parm); + parm = RNA_def_float(func, "roll2", 0, -FLT_MAX, FLT_MAX, "", "Roll of the end handle", -FLT_MAX, FLT_MAX); + RNA_def_function_output(func, parm); + parm = RNA_def_boolean(func, "rest", false, "", "Return the rest pose state"); + parm = RNA_def_boolean(func, "ease", false, "", "Apply scale from ease values"); + parm = RNA_def_boolean(func, "offsets", false, "", "Apply roll and curve offsets from bone properties"); } |