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:
Diffstat (limited to 'source/blender/editors/armature/pose_slide.c')
-rw-r--r--source/blender/editors/armature/pose_slide.c2827
1 files changed, 1457 insertions, 1370 deletions
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 90de331b3e0..cb9cfa64181 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -81,102 +81,104 @@
/* Temporary data shared between these operators */
typedef struct tPoseSlideOp {
- /** current scene */
- Scene *scene;
- /** area that we're operating in (needed for modal()) */
- ScrArea *sa;
- /** region that we're operating in (needed for modal()) */
- ARegion *ar;
- /** len of the PoseSlideObject array. */
- uint objects_len;
-
- /** links between posechannels and f-curves for all the pose objects. */
- ListBase pfLinks;
- /** binary tree for quicker searching for keyframes (when applicable) */
- DLRBT_Tree keys;
-
- /** current frame number - global time */
- int cframe;
-
- /** frame before current frame (blend-from) - global time */
- int prevFrame;
- /** frame after current frame (blend-to) - global time */
- int nextFrame;
-
- /** sliding mode (ePoseSlide_Modes) */
- short mode;
- /** unused for now, but can later get used for storing runtime settings.... */
- short flag;
-
- /** which transforms/channels are affected (ePoseSlide_Channels) */
- short channels;
- /** axis-limits for transforms (ePoseSlide_AxisLock) */
- short axislock;
-
- /** 0-1 value for determining the influence of whatever is relevant */
- float percentage;
-
- /** numeric input */
- NumInput num;
-
- struct tPoseSlideObject *ob_data_array;
+ /** current scene */
+ Scene *scene;
+ /** area that we're operating in (needed for modal()) */
+ ScrArea *sa;
+ /** region that we're operating in (needed for modal()) */
+ ARegion *ar;
+ /** len of the PoseSlideObject array. */
+ uint objects_len;
+
+ /** links between posechannels and f-curves for all the pose objects. */
+ ListBase pfLinks;
+ /** binary tree for quicker searching for keyframes (when applicable) */
+ DLRBT_Tree keys;
+
+ /** current frame number - global time */
+ int cframe;
+
+ /** frame before current frame (blend-from) - global time */
+ int prevFrame;
+ /** frame after current frame (blend-to) - global time */
+ int nextFrame;
+
+ /** sliding mode (ePoseSlide_Modes) */
+ short mode;
+ /** unused for now, but can later get used for storing runtime settings.... */
+ short flag;
+
+ /** which transforms/channels are affected (ePoseSlide_Channels) */
+ short channels;
+ /** axis-limits for transforms (ePoseSlide_AxisLock) */
+ short axislock;
+
+ /** 0-1 value for determining the influence of whatever is relevant */
+ float percentage;
+
+ /** numeric input */
+ NumInput num;
+
+ struct tPoseSlideObject *ob_data_array;
} tPoseSlideOp;
typedef struct tPoseSlideObject {
- Object *ob; /* active object that Pose Info comes from */
- float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
- float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
- bool valid;
+ Object *ob; /* active object that Pose Info comes from */
+ float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
+ float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
+ bool valid;
} tPoseSlideObject;
/* Pose Sliding Modes */
typedef enum ePoseSlide_Modes {
- POSESLIDE_PUSH = 0, /* exaggerate the pose... */
- POSESLIDE_RELAX, /* soften the pose... */
- POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
+ POSESLIDE_PUSH = 0, /* exaggerate the pose... */
+ POSESLIDE_RELAX, /* soften the pose... */
+ POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
} ePoseSlide_Modes;
-
/* Transforms/Channels to Affect */
typedef enum ePoseSlide_Channels {
- PS_TFM_ALL = 0, /* All transforms and properties */
+ PS_TFM_ALL = 0, /* All transforms and properties */
- PS_TFM_LOC, /* Loc/Rot/Scale */
- PS_TFM_ROT,
- PS_TFM_SIZE,
+ PS_TFM_LOC, /* Loc/Rot/Scale */
+ PS_TFM_ROT,
+ PS_TFM_SIZE,
- PS_TFM_BBONE_SHAPE, /* Bendy Bones */
+ PS_TFM_BBONE_SHAPE, /* Bendy Bones */
- PS_TFM_PROPS, /* Custom Properties */
+ PS_TFM_PROPS, /* Custom Properties */
} ePoseSlide_Channels;
/* Property enum for ePoseSlide_Channels */
static const EnumPropertyItem prop_channels_types[] = {
- {PS_TFM_ALL, "ALL", 0, "All Properties",
- "All properties, including transforms, bendy bone shape, and custom properties"},
- {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
- {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
- {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
- {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
- {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
- {0, NULL, 0, NULL, NULL},
+ {PS_TFM_ALL,
+ "ALL",
+ 0,
+ "All Properties",
+ "All properties, including transforms, bendy bone shape, and custom properties"},
+ {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
+ {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
+ {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
+ {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
+ {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
+ {0, NULL, 0, NULL, NULL},
};
/* Axis Locks */
typedef enum ePoseSlide_AxisLock {
- PS_LOCK_X = (1 << 0),
- PS_LOCK_Y = (1 << 1),
- PS_LOCK_Z = (1 << 2),
+ PS_LOCK_X = (1 << 0),
+ PS_LOCK_Y = (1 << 1),
+ PS_LOCK_Z = (1 << 2),
} ePoseSlide_AxisLock;
/* Property enum for ePoseSlide_AxisLock */
static const EnumPropertyItem prop_axis_lock_types[] = {
- {0, "FREE", 0, "Free", "All axes are affected"},
- {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
- {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
- {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
- /* TODO: Combinations? */
- {0, NULL, 0, NULL, NULL},
+ {0, "FREE", 0, "Free", "All axes are affected"},
+ {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
+ {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
+ {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
+ /* TODO: Combinations? */
+ {0, NULL, 0, NULL, NULL},
};
/* ------------------------------------ */
@@ -184,99 +186,100 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
/* operator init */
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
- tPoseSlideOp *pso;
-
- /* init slide-op data */
- pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
-
- /* get info from context */
- pso->scene = CTX_data_scene(C);
- pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
- pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
-
- pso->cframe = pso->scene->r.cfra;
- pso->mode = mode;
-
- /* set range info from property values - these may get overridden for the invoke() */
- pso->percentage = RNA_float_get(op->ptr, "percentage");
- pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
- pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
-
- /* get the set of properties/axes that can be operated on */
- pso->channels = RNA_enum_get(op->ptr, "channels");
- pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
-
- /* for each Pose-Channel which gets affected, get the F-Curves for that channel
- * and set the relevant transform flags... */
- poseAnim_mapping_get(C, &pso->pfLinks);
-
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(CTX_data_view_layer(C),
- CTX_wm_view3d(C),
- &pso->objects_len,
- OB_MODE_POSE);
- pso->ob_data_array = MEM_callocN(pso->objects_len * sizeof(tPoseSlideObject), "pose slide objects data");
-
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- Object *ob_iter = poseAnim_object_get(objects[ob_index]);
-
- /* Ensure validity of the settings from the context. */
- if (ob_iter == NULL) {
- continue;
- }
-
- ob_data->ob = ob_iter;
- ob_data->valid = true;
-
- /* apply NLA mapping corrections so the frame lookups work */
- ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
- ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
-
- /* set depsgraph flags */
- /* make sure the lock is set OK, unlock can be accidentally saved? */
- ob_data->ob->pose->flag |= POSE_LOCKED;
- ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
- }
- MEM_freeN(objects);
-
- /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
- * to the caller of this (usually only invoke() will do it, to make things more efficient).
- */
- BLI_dlrbTree_init(&pso->keys);
-
- /* initialise numeric input */
- initNumInput(&pso->num);
- pso->num.idx_max = 0; /* one axis */
- pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
- pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
-
- /* return status is whether we've got all the data we were requested to get */
- return 1;
+ tPoseSlideOp *pso;
+
+ /* init slide-op data */
+ pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
+
+ /* get info from context */
+ pso->scene = CTX_data_scene(C);
+ pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
+ pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
+
+ pso->cframe = pso->scene->r.cfra;
+ pso->mode = mode;
+
+ /* set range info from property values - these may get overridden for the invoke() */
+ pso->percentage = RNA_float_get(op->ptr, "percentage");
+ pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
+ pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
+
+ /* get the set of properties/axes that can be operated on */
+ pso->channels = RNA_enum_get(op->ptr, "channels");
+ pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
+
+ /* for each Pose-Channel which gets affected, get the F-Curves for that channel
+ * and set the relevant transform flags... */
+ poseAnim_mapping_get(C, &pso->pfLinks);
+
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
+ CTX_data_view_layer(C), CTX_wm_view3d(C), &pso->objects_len, OB_MODE_POSE);
+ pso->ob_data_array = MEM_callocN(pso->objects_len * sizeof(tPoseSlideObject),
+ "pose slide objects data");
+
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ Object *ob_iter = poseAnim_object_get(objects[ob_index]);
+
+ /* Ensure validity of the settings from the context. */
+ if (ob_iter == NULL) {
+ continue;
+ }
+
+ ob_data->ob = ob_iter;
+ ob_data->valid = true;
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+
+ /* set depsgraph flags */
+ /* make sure the lock is set OK, unlock can be accidentally saved? */
+ ob_data->ob->pose->flag |= POSE_LOCKED;
+ ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
+ }
+ MEM_freeN(objects);
+
+ /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
+ * to the caller of this (usually only invoke() will do it, to make things more efficient).
+ */
+ BLI_dlrbTree_init(&pso->keys);
+
+ /* initialise numeric input */
+ initNumInput(&pso->num);
+ pso->num.idx_max = 0; /* one axis */
+ pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
+ pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
+
+ /* return status is whether we've got all the data we were requested to get */
+ return 1;
}
/* exiting the operator - free data */
static void pose_slide_exit(wmOperator *op)
{
- tPoseSlideOp *pso = op->customdata;
+ tPoseSlideOp *pso = op->customdata;
- /* if data exists, clear its data and exit */
- if (pso) {
- /* free the temp pchan links and their data */
- poseAnim_mapping_free(&pso->pfLinks);
+ /* if data exists, clear its data and exit */
+ if (pso) {
+ /* free the temp pchan links and their data */
+ poseAnim_mapping_free(&pso->pfLinks);
- /* free RB-BST for keyframes (if it contained data) */
- BLI_dlrbTree_free(&pso->keys);
+ /* free RB-BST for keyframes (if it contained data) */
+ BLI_dlrbTree_free(&pso->keys);
- if (pso->ob_data_array != NULL) {
- MEM_freeN(pso->ob_data_array);
- }
+ if (pso->ob_data_array != NULL) {
+ MEM_freeN(pso->ob_data_array);
+ }
- /* free data itself */
- MEM_freeN(pso);
- }
+ /* free data itself */
+ MEM_freeN(pso);
+ }
- /* cleanup */
- op->customdata = NULL;
+ /* cleanup */
+ op->customdata = NULL;
}
/* ------------------------------------ */
@@ -284,438 +287,437 @@ static void pose_slide_exit(wmOperator *op)
/* helper for apply() / reset() - refresh the data */
static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
{
- /* wrapper around the generic version, allowing us to add some custom stuff later still */
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- if (ob_data->valid) {
- poseAnim_mapping_refresh(C, pso->scene, ob_data->ob);
- }
- }
+ /* wrapper around the generic version, allowing us to add some custom stuff later still */
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ if (ob_data->valid) {
+ poseAnim_mapping_refresh(C, pso->scene, ob_data->ob);
+ }
+ }
}
/**
* Although this lookup is not ideal, we won't be dealing with a lot of objects at a given time.
* But if it comes to that we can instead store prev/next frame in the #tPChanFCurveLink.
*/
-static bool pose_frame_range_from_object_get(tPoseSlideOp *pso, Object *ob, float *prevFrameF, float *nextFrameF)
+static bool pose_frame_range_from_object_get(tPoseSlideOp *pso,
+ Object *ob,
+ float *prevFrameF,
+ float *nextFrameF)
{
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- Object *ob_iter = ob_data->ob;
-
- if (ob_iter == ob) {
- *prevFrameF = ob_data->prevFrameF;
- *nextFrameF = ob_data->nextFrameF;
- return true;
- }
- }
- *prevFrameF = *nextFrameF = 0.0f;
- return false;
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ Object *ob_iter = ob_data->ob;
+
+ if (ob_iter == ob) {
+ *prevFrameF = ob_data->prevFrameF;
+ *nextFrameF = ob_data->nextFrameF;
+ return true;
+ }
+ }
+ *prevFrameF = *nextFrameF = 0.0f;
+ return false;
}
/* helper for apply() - perform sliding for some value */
-static void pose_slide_apply_val(
- tPoseSlideOp *pso,
- FCurve *fcu,
- Object *ob,
- float *val)
+static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, float *val)
{
- float prevFrameF, nextFrameF;
- float cframe = (float)pso->cframe;
- float sVal, eVal;
- float w1, w2;
-
- pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
-
- /* get keyframe values for endpoint poses to blend with */
- /* previous/start */
- sVal = evaluate_fcurve(fcu, prevFrameF);
- /* next/end */
- eVal = evaluate_fcurve(fcu, nextFrameF);
-
- /* if both values are equal, don't do anything */
- if (IS_EQF(sVal, eVal)) {
- (*val) = sVal;
- return;
- }
-
- /* calculate the relative weights of the endpoints */
- if (pso->mode == POSESLIDE_BREAKDOWN) {
- /* get weights from the percentage control */
- w1 = pso->percentage; /* this must come second */
- w2 = 1.0f - w1; /* this must come first */
- }
- else {
- /* - these weights are derived from the relative distance of these
- * poses from the current frame
- * - they then get normalized so that they only sum up to 1
- */
- float wtot;
-
- w1 = cframe - (float)pso->prevFrame;
- w2 = (float)pso->nextFrame - cframe;
-
- wtot = w1 + w2;
- w1 = (w1 / wtot);
- w2 = (w2 / wtot);
- }
-
- /* depending on the mode, calculate the new value
- * - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
- * since multiplication in another order would decrease the value the current frame is closer to
- */
- switch (pso->mode) {
- case POSESLIDE_PUSH: /* make the current pose more pronounced */
- {
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be larger than denominator to 'expand' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f;
- }
- break;
- }
- case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
- {
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be smaller than denominator to 'relax' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f;
- }
- break;
- }
- case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
- {
- /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
- /* TODO: make this use some kind of spline interpolation instead? */
- (*val) = ((sVal * w2) + (eVal * w1));
- break;
- }
- }
+ float prevFrameF, nextFrameF;
+ float cframe = (float)pso->cframe;
+ float sVal, eVal;
+ float w1, w2;
+
+ pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
+
+ /* get keyframe values for endpoint poses to blend with */
+ /* previous/start */
+ sVal = evaluate_fcurve(fcu, prevFrameF);
+ /* next/end */
+ eVal = evaluate_fcurve(fcu, nextFrameF);
+
+ /* if both values are equal, don't do anything */
+ if (IS_EQF(sVal, eVal)) {
+ (*val) = sVal;
+ return;
+ }
+
+ /* calculate the relative weights of the endpoints */
+ if (pso->mode == POSESLIDE_BREAKDOWN) {
+ /* get weights from the percentage control */
+ w1 = pso->percentage; /* this must come second */
+ w2 = 1.0f - w1; /* this must come first */
+ }
+ else {
+ /* - these weights are derived from the relative distance of these
+ * poses from the current frame
+ * - they then get normalized so that they only sum up to 1
+ */
+ float wtot;
+
+ w1 = cframe - (float)pso->prevFrame;
+ w2 = (float)pso->nextFrame - cframe;
+
+ wtot = w1 + w2;
+ w1 = (w1 / wtot);
+ w2 = (w2 / wtot);
+ }
+
+ /* depending on the mode, calculate the new value
+ * - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
+ * since multiplication in another order would decrease the value the current frame is closer to
+ */
+ switch (pso->mode) {
+ case POSESLIDE_PUSH: /* make the current pose more pronounced */
+ {
+ /* perform a weighted average here, favoring the middle pose
+ * - numerator should be larger than denominator to 'expand' the result
+ * - perform this weighting a number of times given by the percentage...
+ */
+ /* TODO: maybe a sensitivity ctrl on top of this is needed */
+ int iters = (int)ceil(10.0f * pso->percentage);
+
+ while (iters-- > 0) {
+ (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f;
+ }
+ break;
+ }
+ case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
+ {
+ /* perform a weighted average here, favoring the middle pose
+ * - numerator should be smaller than denominator to 'relax' the result
+ * - perform this weighting a number of times given by the percentage...
+ */
+ /* TODO: maybe a sensitivity ctrl on top of this is needed */
+ int iters = (int)ceil(10.0f * pso->percentage);
+
+ while (iters-- > 0) {
+ (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f;
+ }
+ break;
+ }
+ case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
+ {
+ /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
+ /* TODO: make this use some kind of spline interpolation instead? */
+ (*val) = ((sVal * w2) + (eVal * w1));
+ break;
+ }
+ }
}
/* helper for apply() - perform sliding for some 3-element vector */
-static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], const char propName[])
+static void pose_slide_apply_vec3(tPoseSlideOp *pso,
+ tPChanFCurveLink *pfl,
+ float vec[3],
+ const char propName[])
{
- LinkData *ld = NULL;
- char *path = NULL;
-
- /* get the path to use... */
- path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
-
- /* using this path, find each matching F-Curve for the variables we're interested in */
- while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
- FCurve *fcu = (FCurve *)ld->data;
- const int idx = fcu->array_index;
- const int lock = pso->axislock;
-
- /* check if this F-Curve is ok given the current axis locks */
- BLI_assert(fcu->array_index < 3);
-
- if ((lock == 0) ||
- ((lock & PS_LOCK_X) && (idx == 0)) ||
- ((lock & PS_LOCK_Y) && (idx == 1)) ||
- ((lock & PS_LOCK_Z) && (idx == 2)))
- {
- /* just work on these channels one by one... there's no interaction between values */
- pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
- }
- }
-
- /* free the temp path we got */
- MEM_freeN(path);
+ LinkData *ld = NULL;
+ char *path = NULL;
+
+ /* get the path to use... */
+ path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
+
+ /* using this path, find each matching F-Curve for the variables we're interested in */
+ while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
+ FCurve *fcu = (FCurve *)ld->data;
+ const int idx = fcu->array_index;
+ const int lock = pso->axislock;
+
+ /* check if this F-Curve is ok given the current axis locks */
+ BLI_assert(fcu->array_index < 3);
+
+ if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
+ ((lock & PS_LOCK_Z) && (idx == 2))) {
+ /* just work on these channels one by one... there's no interaction between values */
+ pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
+ }
+ }
+
+ /* free the temp path we got */
+ MEM_freeN(path);
}
/* helper for apply() - perform sliding for custom properties or bbone properties */
-static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[])
+static void pose_slide_apply_props(tPoseSlideOp *pso,
+ tPChanFCurveLink *pfl,
+ const char prop_prefix[])
{
- PointerRNA ptr = {{NULL}};
- LinkData *ld;
- int len = strlen(pfl->pchan_path);
-
- /* setup pointer RNA for resolving paths */
- RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
-
- /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
- * so just check for opening pair after the end of the path
- * - bbone properties are similar, but they always start with a prefix "bbone_*",
- * so a similar method should work here for those too
- */
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
- const char *bPtr, *pPtr;
-
- if (fcu->rna_path == NULL)
- continue;
-
- /* do we have a match?
- * - bPtr is the RNA Path with the standard part chopped off
- * - pPtr is the chunk of the path which is left over
- */
- bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
- pPtr = strstr(bPtr, prop_prefix);
-
- if (pPtr) {
- /* use RNA to try and get a handle on this property, then, assuming that it is just
- * numerical, try and grab the value as a float for temp editing before setting back
- */
- PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
-
- if (prop) {
- switch (RNA_property_type(prop)) {
- /* continuous values that can be smoothly interpolated... */
- case PROP_FLOAT:
- {
- float tval = RNA_property_float_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
- RNA_property_float_set(&ptr, prop, tval);
- break;
- }
- case PROP_INT:
- {
- float tval = (float)RNA_property_int_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
- RNA_property_int_set(&ptr, prop, (int)tval);
- break;
- }
-
- /* values which can only take discrete values */
- case PROP_BOOLEAN:
- {
- float tval = (float)RNA_property_boolean_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
- RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
- break;
- }
- case PROP_ENUM:
- {
- /* don't handle this case - these don't usually represent interchangeable
- * set of values which should be interpolated between
- */
- break;
- }
-
- default:
- /* cannot handle */
- //printf("Cannot Pose Slide non-numerical property\n");
- break;
- }
- }
- }
- }
+ PointerRNA ptr = {{NULL}};
+ LinkData *ld;
+ int len = strlen(pfl->pchan_path);
+
+ /* setup pointer RNA for resolving paths */
+ RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
+
+ /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
+ * so just check for opening pair after the end of the path
+ * - bbone properties are similar, but they always start with a prefix "bbone_*",
+ * so a similar method should work here for those too
+ */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ const char *bPtr, *pPtr;
+
+ if (fcu->rna_path == NULL)
+ continue;
+
+ /* do we have a match?
+ * - bPtr is the RNA Path with the standard part chopped off
+ * - pPtr is the chunk of the path which is left over
+ */
+ bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
+ pPtr = strstr(bPtr, prop_prefix);
+
+ if (pPtr) {
+ /* use RNA to try and get a handle on this property, then, assuming that it is just
+ * numerical, try and grab the value as a float for temp editing before setting back
+ */
+ PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
+
+ if (prop) {
+ switch (RNA_property_type(prop)) {
+ /* continuous values that can be smoothly interpolated... */
+ case PROP_FLOAT: {
+ float tval = RNA_property_float_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
+ RNA_property_float_set(&ptr, prop, tval);
+ break;
+ }
+ case PROP_INT: {
+ float tval = (float)RNA_property_int_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
+ RNA_property_int_set(&ptr, prop, (int)tval);
+ break;
+ }
+
+ /* values which can only take discrete values */
+ case PROP_BOOLEAN: {
+ float tval = (float)RNA_property_boolean_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
+ RNA_property_boolean_set(
+ &ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
+ break;
+ }
+ case PROP_ENUM: {
+ /* don't handle this case - these don't usually represent interchangeable
+ * set of values which should be interpolated between
+ */
+ break;
+ }
+
+ default:
+ /* cannot handle */
+ //printf("Cannot Pose Slide non-numerical property\n");
+ break;
+ }
+ }
+ }
+ }
}
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
{
- FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
- bPoseChannel *pchan = pfl->pchan;
- LinkData *ld = NULL;
- char *path = NULL;
- float cframe;
- float prevFrameF, nextFrameF;
-
- if (!pose_frame_range_from_object_get(pso, pfl->ob, &prevFrameF, &nextFrameF)) {
- BLI_assert(!"Invalid pfl data");
- return;
- }
-
- /* get the path to use - this should be quaternion rotations only (needs care) */
- path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
-
- /* get the current frame number */
- cframe = (float)pso->cframe;
-
- /* using this path, find each matching F-Curve for the variables we're interested in */
- while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
- FCurve *fcu = (FCurve *)ld->data;
-
- /* assign this F-Curve to one of the relevant pointers... */
- switch (fcu->array_index) {
- case 3: /* z */
- fcu_z = fcu;
- break;
- case 2: /* y */
- fcu_y = fcu;
- break;
- case 1: /* x */
- fcu_x = fcu;
- break;
- case 0: /* w */
- fcu_w = fcu;
- break;
- }
- }
-
- /* only if all channels exist, proceed */
- if (fcu_w && fcu_x && fcu_y && fcu_z) {
- float quat_prev[4], quat_prev_orig[4];
- float quat_next[4], quat_next_orig[4];
- float quat_curr[4], quat_curr_orig[4];
- float quat_final[4];
-
- copy_qt_qt(quat_curr_orig, pchan->quat);
-
- /* get 2 quats */
- quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
- quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
- quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
- quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
-
- quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
- quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
- quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
- quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
-
- normalize_qt_qt(quat_prev, quat_prev_orig);
- normalize_qt_qt(quat_next, quat_next_orig);
- normalize_qt_qt(quat_curr, quat_curr_orig);
-
- /* perform blending */
- if (pso->mode == POSESLIDE_BREAKDOWN) {
- /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
- }
- else if (pso->mode == POSESLIDE_PUSH) {
- float quat_diff[4];
-
- /* calculate the delta transform from the previous to the current */
- /* TODO: investigate ways to favour one transform more? */
- sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
-
- /* increase the original by the delta transform, by an amount determined by percentage */
- add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
-
- normalize_qt(quat_final);
- }
- else {
- BLI_assert(pso->mode == POSESLIDE_RELAX);
- float quat_interp[4], quat_final_prev[4];
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- copy_qt_qt(quat_final, quat_curr);
-
- /* perform this blending several times until a satisfactory result is reached */
- while (iters-- > 0) {
- /* calculate the interpolation between the endpoints */
- interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
-
- normalize_qt_qt(quat_final_prev, quat_final);
-
- /* tricky interpolations - blending between original and new */
- interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
- }
- }
-
- /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
- quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
- }
-
- /* free the path now */
- MEM_freeN(path);
+ FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
+ bPoseChannel *pchan = pfl->pchan;
+ LinkData *ld = NULL;
+ char *path = NULL;
+ float cframe;
+ float prevFrameF, nextFrameF;
+
+ if (!pose_frame_range_from_object_get(pso, pfl->ob, &prevFrameF, &nextFrameF)) {
+ BLI_assert(!"Invalid pfl data");
+ return;
+ }
+
+ /* get the path to use - this should be quaternion rotations only (needs care) */
+ path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
+
+ /* get the current frame number */
+ cframe = (float)pso->cframe;
+
+ /* using this path, find each matching F-Curve for the variables we're interested in */
+ while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
+ FCurve *fcu = (FCurve *)ld->data;
+
+ /* assign this F-Curve to one of the relevant pointers... */
+ switch (fcu->array_index) {
+ case 3: /* z */
+ fcu_z = fcu;
+ break;
+ case 2: /* y */
+ fcu_y = fcu;
+ break;
+ case 1: /* x */
+ fcu_x = fcu;
+ break;
+ case 0: /* w */
+ fcu_w = fcu;
+ break;
+ }
+ }
+
+ /* only if all channels exist, proceed */
+ if (fcu_w && fcu_x && fcu_y && fcu_z) {
+ float quat_prev[4], quat_prev_orig[4];
+ float quat_next[4], quat_next_orig[4];
+ float quat_curr[4], quat_curr_orig[4];
+ float quat_final[4];
+
+ copy_qt_qt(quat_curr_orig, pchan->quat);
+
+ /* get 2 quats */
+ quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
+
+ quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
+
+ normalize_qt_qt(quat_prev, quat_prev_orig);
+ normalize_qt_qt(quat_next, quat_next_orig);
+ normalize_qt_qt(quat_curr, quat_curr_orig);
+
+ /* perform blending */
+ if (pso->mode == POSESLIDE_BREAKDOWN) {
+ /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
+ }
+ else if (pso->mode == POSESLIDE_PUSH) {
+ float quat_diff[4];
+
+ /* calculate the delta transform from the previous to the current */
+ /* TODO: investigate ways to favour one transform more? */
+ sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
+
+ /* increase the original by the delta transform, by an amount determined by percentage */
+ add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
+
+ normalize_qt(quat_final);
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ float quat_interp[4], quat_final_prev[4];
+ /* TODO: maybe a sensitivity ctrl on top of this is needed */
+ int iters = (int)ceil(10.0f * pso->percentage);
+
+ copy_qt_qt(quat_final, quat_curr);
+
+ /* perform this blending several times until a satisfactory result is reached */
+ while (iters-- > 0) {
+ /* calculate the interpolation between the endpoints */
+ interp_qt_qtqt(quat_interp,
+ quat_prev,
+ quat_next,
+ (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
+
+ normalize_qt_qt(quat_final_prev, quat_final);
+
+ /* tricky interpolations - blending between original and new */
+ interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
+ }
+ }
+
+ /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
+ quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
+ }
+
+ /* free the path now */
+ MEM_freeN(path);
}
/* apply() - perform the pose sliding based on weighting various poses */
static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
{
- tPChanFCurveLink *pfl;
-
- /* sanitise the frame ranges */
- if (pso->prevFrame == pso->nextFrame) {
- /* move out one step either side */
- pso->prevFrame--;
- pso->nextFrame++;
-
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
-
- if (!ob_data->valid) {
- continue;
- }
-
- /* apply NLA mapping corrections so the frame lookups work */
- ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->prevFrame,
- NLATIME_CONVERT_UNMAP);
- ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->nextFrame,
- NLATIME_CONVERT_UNMAP);
- }
- }
-
- /* for each link, handle each set of transforms */
- for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
- /* valid transforms for each PoseChannel should have been noted already
- * - sliding the pose should be a straightforward exercise for location+rotation,
- * but rotations get more complicated since we may want to use quaternion blending
- * for quaternions instead...
- */
- bPoseChannel *pchan = pfl->pchan;
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
- /* calculate these for the 'location' vector, and use location curves */
- pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
- /* calculate these for the 'scale' vector, and use scale curves */
- pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
- /* everything depends on the rotation mode */
- if (pchan->rotmode > 0) {
- /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
- pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* TODO: need to figure out how to do this! */
- }
- else {
- /* quaternions - use quaternion blending */
- pose_slide_apply_quat(pso, pfl);
- }
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
- /* bbone properties - they all start a "bbone_" prefix */
- pose_slide_apply_props(pso, pfl, "bbone_");
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
- /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
- * (e.g. the facial rigs used in Sintel)
- */
- pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
- }
- }
-
- /* depsgraph updates + redraws */
- pose_slide_refresh(C, pso);
+ tPChanFCurveLink *pfl;
+
+ /* sanitise the frame ranges */
+ if (pso->prevFrame == pso->nextFrame) {
+ /* move out one step either side */
+ pso->prevFrame--;
+ pso->nextFrame++;
+
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+
+ if (!ob_data->valid) {
+ continue;
+ }
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ }
+ }
+
+ /* for each link, handle each set of transforms */
+ for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
+ /* valid transforms for each PoseChannel should have been noted already
+ * - sliding the pose should be a straightforward exercise for location+rotation,
+ * but rotations get more complicated since we may want to use quaternion blending
+ * for quaternions instead...
+ */
+ bPoseChannel *pchan = pfl->pchan;
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
+ /* calculate these for the 'location' vector, and use location curves */
+ pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
+ /* calculate these for the 'scale' vector, and use scale curves */
+ pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
+ /* everything depends on the rotation mode */
+ if (pchan->rotmode > 0) {
+ /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
+ pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* TODO: need to figure out how to do this! */
+ }
+ else {
+ /* quaternions - use quaternion blending */
+ pose_slide_apply_quat(pso, pfl);
+ }
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
+ /* bbone properties - they all start a "bbone_" prefix */
+ pose_slide_apply_props(pso, pfl, "bbone_");
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
+ /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
+ * (e.g. the facial rigs used in Sintel)
+ */
+ pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
+ }
+ }
+
+ /* depsgraph updates + redraws */
+ pose_slide_refresh(C, pso);
}
/* perform auto-key-framing after changes were made + confirmed */
static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
{
- /* wrapper around the generic call */
- poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
+ /* wrapper around the generic call */
+ poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
}
/* reset changes made to current pose */
static void pose_slide_reset(tPoseSlideOp *pso)
{
- /* wrapper around the generic call, so that custom stuff can be added later */
- poseAnim_mapping_reset(&pso->pfLinks);
+ /* wrapper around the generic call, so that custom stuff can be added later */
+ poseAnim_mapping_reset(&pso->pfLinks);
}
/* ------------------------------------ */
@@ -724,425 +726,472 @@ static void pose_slide_reset(tPoseSlideOp *pso)
// TODO: Include hints about locks here...
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[UI_MAX_DRAW_STR];
- char limits_str[UI_MAX_DRAW_STR];
- char axis_str[50];
- char mode_str[32];
-
- switch (pso->mode) {
- case POSESLIDE_PUSH:
- strcpy(mode_str, "Push Pose");
- break;
- case POSESLIDE_RELAX:
- strcpy(mode_str, "Relax Pose");
- break;
- case POSESLIDE_BREAKDOWN:
- strcpy(mode_str, "Breakdown");
- break;
-
- default:
- /* unknown */
- strcpy(mode_str, "Sliding-Tool");
- break;
- }
-
- switch (pso->axislock) {
- case PS_LOCK_X:
- BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
- break;
- case PS_LOCK_Y:
- BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
- break;
- case PS_LOCK_Z:
- BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
- break;
-
- default:
- if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
- BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
- }
- else {
- axis_str[0] = '\0';
- }
- break;
- }
-
- switch (pso->channels) {
- case PS_TFM_LOC:
- BLI_snprintf(limits_str, sizeof(limits_str), "[G]/R/S/B/C - Location only (G to clear) | %s", axis_str);
- break;
- case PS_TFM_ROT:
- BLI_snprintf(limits_str, sizeof(limits_str), "G/[R]/S/B/C - Rotation only (R to clear) | %s", axis_str);
- break;
- case PS_TFM_SIZE:
- BLI_snprintf(limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
- break;
- case PS_TFM_BBONE_SHAPE:
- BLI_strncpy(limits_str, "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s", sizeof(limits_str));
- break;
- case PS_TFM_PROPS:
- BLI_strncpy(limits_str, "G/R/S/B/[C] - Custom Properties only (C to clear) | %s", sizeof(limits_str));
- break;
- default:
- BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
- break;
- }
-
- if (hasNumInput(&pso->num)) {
- Scene *scene = pso->scene;
- char str_offs[NUM_STR_REP_LEN];
-
- outputNumInput(&pso->num, str_offs, &scene->unit);
-
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %% | %s", mode_str, (int)(pso->percentage * 100.0f), limits_str);
- }
-
- ED_area_status_text(pso->sa, status_str);
+ char status_str[UI_MAX_DRAW_STR];
+ char limits_str[UI_MAX_DRAW_STR];
+ char axis_str[50];
+ char mode_str[32];
+
+ switch (pso->mode) {
+ case POSESLIDE_PUSH:
+ strcpy(mode_str, "Push Pose");
+ break;
+ case POSESLIDE_RELAX:
+ strcpy(mode_str, "Relax Pose");
+ break;
+ case POSESLIDE_BREAKDOWN:
+ strcpy(mode_str, "Breakdown");
+ break;
+
+ default:
+ /* unknown */
+ strcpy(mode_str, "Sliding-Tool");
+ break;
+ }
+
+ switch (pso->axislock) {
+ case PS_LOCK_X:
+ BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Y:
+ BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Z:
+ BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
+ break;
+
+ default:
+ if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
+ BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
+ }
+ else {
+ axis_str[0] = '\0';
+ }
+ break;
+ }
+
+ switch (pso->channels) {
+ case PS_TFM_LOC:
+ BLI_snprintf(limits_str,
+ sizeof(limits_str),
+ "[G]/R/S/B/C - Location only (G to clear) | %s",
+ axis_str);
+ break;
+ case PS_TFM_ROT:
+ BLI_snprintf(limits_str,
+ sizeof(limits_str),
+ "G/[R]/S/B/C - Rotation only (R to clear) | %s",
+ axis_str);
+ break;
+ case PS_TFM_SIZE:
+ BLI_snprintf(
+ limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
+ break;
+ case PS_TFM_BBONE_SHAPE:
+ BLI_strncpy(limits_str,
+ "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s",
+ sizeof(limits_str));
+ break;
+ case PS_TFM_PROPS:
+ BLI_strncpy(limits_str,
+ "G/R/S/B/[C] - Custom Properties only (C to clear) | %s",
+ sizeof(limits_str));
+ break;
+ default:
+ BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
+ break;
+ }
+
+ if (hasNumInput(&pso->num)) {
+ Scene *scene = pso->scene;
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&pso->num, str_offs, &scene->unit);
+
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
+ }
+ else {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s: %d %% | %s",
+ mode_str,
+ (int)(pso->percentage * 100.0f),
+ limits_str);
+ }
+
+ ED_area_status_text(pso->sa, status_str);
}
/* common code for invoke() methods */
static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
- tPChanFCurveLink *pfl;
- wmWindow *win = CTX_wm_window(C);
-
- /* for each link, add all its keyframes to the search tree */
- for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
- LinkData *ld;
-
- /* do this for each F-Curve */
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
- }
- }
-
- /* cancel if no keyframes found... */
- if (pso->keys.root) {
- ActKeyColumn *ak;
- float cframe = (float)pso->cframe;
-
- /* firstly, check if the current frame is a keyframe... */
- ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
-
- if (ak == NULL) {
- /* current frame is not a keyframe, so search */
- ActKeyColumn *pk = (ActKeyColumn *)BLI_dlrbTree_search_prev(&pso->keys, compare_ak_cfraPtr, &cframe);
- ActKeyColumn *nk = (ActKeyColumn *)BLI_dlrbTree_search_next(&pso->keys, compare_ak_cfraPtr, &cframe);
-
- /* new set the frames */
- /* prev frame */
- pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
- RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
- /* next frame */
- pso->nextFrame = (nk) ? (nk->cfra) : (pso->cframe + 1);
- RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
- }
- else {
- /* current frame itself is a keyframe, so just take keyframes on either side */
- /* prev frame */
- pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
- RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
- /* next frame */
- pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
- RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
- }
-
- /* apply NLA mapping corrections so the frame lookups work */
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- if (ob_data->valid) {
- ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->prevFrame,
- NLATIME_CONVERT_UNMAP);
- ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->nextFrame,
- NLATIME_CONVERT_UNMAP);
- }
- }
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
-
- /* initial apply for operator... */
- /* TODO: need to calculate percentage for initial round too... */
- pose_slide_apply(C, pso);
-
- /* depsgraph updates + redraws */
- pose_slide_refresh(C, pso);
-
- /* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
-
- /* header print */
- pose_slide_draw_status(pso);
-
- /* add a modal handler for this operator */
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ tPChanFCurveLink *pfl;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* for each link, add all its keyframes to the search tree */
+ for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
+ LinkData *ld;
+
+ /* do this for each F-Curve */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
+ }
+ }
+
+ /* cancel if no keyframes found... */
+ if (pso->keys.root) {
+ ActKeyColumn *ak;
+ float cframe = (float)pso->cframe;
+
+ /* firstly, check if the current frame is a keyframe... */
+ ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
+
+ if (ak == NULL) {
+ /* current frame is not a keyframe, so search */
+ ActKeyColumn *pk = (ActKeyColumn *)BLI_dlrbTree_search_prev(
+ &pso->keys, compare_ak_cfraPtr, &cframe);
+ ActKeyColumn *nk = (ActKeyColumn *)BLI_dlrbTree_search_next(
+ &pso->keys, compare_ak_cfraPtr, &cframe);
+
+ /* new set the frames */
+ /* prev frame */
+ pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
+ RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
+ /* next frame */
+ pso->nextFrame = (nk) ? (nk->cfra) : (pso->cframe + 1);
+ RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
+ }
+ else {
+ /* current frame itself is a keyframe, so just take keyframes on either side */
+ /* prev frame */
+ pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
+ RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
+ /* next frame */
+ pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
+ RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
+ }
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ if (ob_data->valid) {
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ }
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* initial apply for operator... */
+ /* TODO: need to calculate percentage for initial round too... */
+ pose_slide_apply(C, pso);
+
+ /* depsgraph updates + redraws */
+ pose_slide_refresh(C, pso);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+
+ /* header print */
+ pose_slide_draw_status(pso);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
/* calculate percentage based on position of mouse (we only use x-axis for now.
* since this is more convenient for users to do), and store new percentage value
*/
-static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event)
+static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso,
+ wmOperator *op,
+ const wmEvent *event)
{
- pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
}
/* handle an event to toggle channels mode */
-static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_Channels channel)
+static void pose_slide_toggle_channels_mode(wmOperator *op,
+ tPoseSlideOp *pso,
+ ePoseSlide_Channels channel)
{
- /* Turn channel on or off? */
- if (pso->channels == channel) {
- /* Already limiting to transform only, so pressing this again turns it off */
- pso->channels = PS_TFM_ALL;
- }
- else {
- /* Only this set of channels */
- pso->channels = channel;
- }
- RNA_enum_set(op->ptr, "channels", pso->channels);
-
-
- /* Reset axis limits too for good measure */
- pso->axislock = 0;
- RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+ /* Turn channel on or off? */
+ if (pso->channels == channel) {
+ /* Already limiting to transform only, so pressing this again turns it off */
+ pso->channels = PS_TFM_ALL;
+ }
+ else {
+ /* Only this set of channels */
+ pso->channels = channel;
+ }
+ RNA_enum_set(op->ptr, "channels", pso->channels);
+
+ /* Reset axis limits too for good measure */
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
}
/* handle an event to toggle axis locks - returns whether any change in state is needed */
-static bool pose_slide_toggle_axis_locks(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_AxisLock axis)
+static bool pose_slide_toggle_axis_locks(wmOperator *op,
+ tPoseSlideOp *pso,
+ ePoseSlide_AxisLock axis)
{
- /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
- pso->axislock = 0;
- RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
- return false;
- }
-
- /* Turn on or off? */
- if (pso->axislock == axis) {
- /* Already limiting on this axis, so turn off */
- pso->axislock = 0;
- }
- else {
- /* Only this axis */
- pso->axislock = axis;
- }
- RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
-
- /* Setting changed, so pose update is needed */
- return true;
+ /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+ return false;
+ }
+
+ /* Turn on or off? */
+ if (pso->axislock == axis) {
+ /* Already limiting on this axis, so turn off */
+ pso->axislock = 0;
+ }
+ else {
+ /* Only this axis */
+ pso->axislock = axis;
+ }
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+
+ /* Setting changed, so pose update is needed */
+ return true;
}
/* common code for modal() */
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso = op->customdata;
- wmWindow *win = CTX_wm_window(C);
- bool do_pose_update = false;
-
- const bool has_numinput = hasNumInput(&pso->num);
-
- switch (event->type) {
- case LEFTMOUSE: /* confirm */
- case RETKEY:
- case PADENTER:
- {
- /* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
- WM_cursor_modal_restore(win);
-
- /* insert keyframes as required... */
- pose_slide_autoKeyframe(C, pso);
- pose_slide_exit(op);
-
- /* done! */
- return OPERATOR_FINISHED;
- }
-
- case ESCKEY: /* cancel */
- case RIGHTMOUSE:
- {
- /* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
- WM_cursor_modal_restore(win);
-
- /* reset transforms back to original state */
- pose_slide_reset(pso);
-
- /* depsgraph updates + redraws */
- pose_slide_refresh(C, pso);
-
- /* clean up temp data */
- pose_slide_exit(op);
-
- /* canceled! */
- return OPERATOR_CANCELLED;
- }
-
- /* Percentage Chane... */
- case MOUSEMOVE: /* calculate new position */
- {
- /* only handle mousemove if not doing numinput */
- if (has_numinput == false) {
- /* update percentage based on position of mouse */
- pose_slide_mouse_update_percentage(pso, op, event);
-
- /* update pose to reflect the new values (see below) */
- do_pose_update = true;
- }
- break;
- }
- default:
- {
- if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
- float value;
-
- /* Grab percentage from numeric input, and store this new value for redo
- * NOTE: users see ints, while internally we use a 0-1 float
- */
- value = pso->percentage * 100.0f;
- applyNumInput(&pso->num, &value);
-
- pso->percentage = value / 100.0f;
- CLAMP(pso->percentage, 0.0f, 1.0f);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
-
- /* Update pose to reflect the new values (see below) */
- do_pose_update = true;
- break;
- }
- else if (event->val == KM_PRESS) {
- switch (event->type) {
- /* Transform Channel Limits */
- /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
- case GKEY: /* Location */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
- do_pose_update = true;
- break;
- }
- case RKEY: /* Rotation */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
- do_pose_update = true;
- break;
- }
- case SKEY: /* Scale */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
- do_pose_update = true;
- break;
- }
- case BKEY: /* Bendy Bones */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
- do_pose_update = true;
- break;
- }
- case CKEY: /* Custom Properties */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
- do_pose_update = true;
- break;
- }
-
-
- /* Axis Locks */
- /* XXX: Hardcoded... */
- case XKEY:
- {
- if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
- do_pose_update = true;
- }
- break;
- }
- case YKEY:
- {
- if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
- do_pose_update = true;
- }
- break;
- }
- case ZKEY:
- {
- if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
- do_pose_update = true;
- }
- break;
- }
-
-
- default: /* Some other unhandled key... */
- break;
- }
- }
- else {
- /* unhandled event - maybe it was some view manip? */
- /* allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
- }
- }
-
-
- /* perform pose updates - in response to some user action (e.g. pressing a key or moving the mouse) */
- if (do_pose_update) {
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
- }
-
- /* still running... */
- return OPERATOR_RUNNING_MODAL;
+ tPoseSlideOp *pso = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bool do_pose_update = false;
+
+ const bool has_numinput = hasNumInput(&pso->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ case PADENTER: {
+ /* return to normal cursor and header status */
+ ED_area_status_text(pso->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ pose_slide_autoKeyframe(C, pso);
+ pose_slide_exit(op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE: {
+ /* return to normal cursor and header status */
+ ED_area_status_text(pso->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* reset transforms back to original state */
+ pose_slide_reset(pso);
+
+ /* depsgraph updates + redraws */
+ pose_slide_refresh(C, pso);
+
+ /* clean up temp data */
+ pose_slide_exit(op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Percentage Chane... */
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update percentage based on position of mouse */
+ pose_slide_mouse_update_percentage(pso, op, event);
+
+ /* update pose to reflect the new values (see below) */
+ do_pose_update = true;
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
+ float value;
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float
+ */
+ value = pso->percentage * 100.0f;
+ applyNumInput(&pso->num, &value);
+
+ pso->percentage = value / 100.0f;
+ CLAMP(pso->percentage, 0.0f, 1.0f);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+
+ /* Update pose to reflect the new values (see below) */
+ do_pose_update = true;
+ break;
+ }
+ else if (event->val == KM_PRESS) {
+ switch (event->type) {
+ /* Transform Channel Limits */
+ /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
+ case GKEY: /* Location */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
+ do_pose_update = true;
+ break;
+ }
+ case RKEY: /* Rotation */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
+ do_pose_update = true;
+ break;
+ }
+ case SKEY: /* Scale */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
+ do_pose_update = true;
+ break;
+ }
+ case BKEY: /* Bendy Bones */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
+ do_pose_update = true;
+ break;
+ }
+ case CKEY: /* Custom Properties */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
+ do_pose_update = true;
+ break;
+ }
+
+ /* Axis Locks */
+ /* XXX: Hardcoded... */
+ case XKEY: {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case YKEY: {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case ZKEY: {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+
+ default: /* Some other unhandled key... */
+ break;
+ }
+ }
+ else {
+ /* unhandled event - maybe it was some view manip? */
+ /* allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ /* perform pose updates - in response to some user action (e.g. pressing a key or moving the mouse) */
+ if (do_pose_update) {
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
}
/* common code for cancel() */
static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op)
{
- /* cleanup and done */
- pose_slide_exit(op);
+ /* cleanup and done */
+ pose_slide_exit(op);
}
/* common code for exec() methods */
static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
- /* settings should have been set up ok for applying, so just apply! */
- pose_slide_apply(C, pso);
+ /* settings should have been set up ok for applying, so just apply! */
+ pose_slide_apply(C, pso);
- /* insert keyframes if needed */
- pose_slide_autoKeyframe(C, pso);
+ /* insert keyframes if needed */
+ pose_slide_autoKeyframe(C, pso);
- /* cleanup and done */
- pose_slide_exit(op);
+ /* cleanup and done */
+ pose_slide_exit(op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
/* common code for defining RNA properties */
/* TODO: Skip save on these? */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
- RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for which keyframe is favored more", 0.3, 0.7);
-
- RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame", 0, 50);
- RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame", 0, 50);
-
- RNA_def_enum(ot->srna, "channels", prop_channels_types, PS_TFM_ALL, "Channels", "Set of properties that are affected");
- RNA_def_enum(ot->srna, "axis_lock", prop_axis_lock_types, 0, "Axis Lock", "Transform axis to restrict effects to");
+ RNA_def_float_percentage(ot->srna,
+ "percentage",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Percentage",
+ "Weighting factor for which keyframe is favored more",
+ 0.3,
+ 0.7);
+
+ RNA_def_int(ot->srna,
+ "prev_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Previous Keyframe",
+ "Frame number of keyframe immediately before the current frame",
+ 0,
+ 50);
+ RNA_def_int(ot->srna,
+ "next_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Next Keyframe",
+ "Frame number of keyframe immediately after the current frame",
+ 0,
+ 50);
+
+ RNA_def_enum(ot->srna,
+ "channels",
+ prop_channels_types,
+ PS_TFM_ALL,
+ "Channels",
+ "Set of properties that are affected");
+ RNA_def_enum(ot->srna,
+ "axis_lock",
+ prop_axis_lock_types,
+ 0,
+ "Axis Lock",
+ "Transform axis to restrict effects to");
}
/* ------------------------------------ */
@@ -1150,59 +1199,59 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
/* invoke() - for 'push' mode */
static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
+ tPoseSlideOp *pso;
- /* initialize data */
- if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
+ /* initialize data */
+ if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
- /* initialise percentage so that it won't pop on first mouse move */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
- /* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ /* do common setup work */
+ return pose_slide_invoke_common(C, op, pso);
}
/* exec() - for push */
static int pose_slide_push_exec(bContext *C, wmOperator *op)
{
- tPoseSlideOp *pso;
-
- /* initialize data (from RNA-props) */
- if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
-
- /* do common exec work */
- return pose_slide_exec_common(C, op, pso);
+ tPoseSlideOp *pso;
+
+ /* initialize data (from RNA-props) */
+ if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
+
+ /* do common exec work */
+ return pose_slide_exec_common(C, op, pso);
}
void POSE_OT_push(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Push Pose";
- ot->idname = "POSE_OT_push";
- ot->description = "Exaggerate the current pose";
-
- /* callbacks */
- ot->exec = pose_slide_push_exec;
- ot->invoke = pose_slide_push_invoke;
- ot->modal = pose_slide_modal;
- ot->cancel = pose_slide_cancel;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* Properties */
- pose_slide_opdef_properties(ot);
+ /* identifiers */
+ ot->name = "Push Pose";
+ ot->idname = "POSE_OT_push";
+ ot->description = "Exaggerate the current pose";
+
+ /* callbacks */
+ ot->exec = pose_slide_push_exec;
+ ot->invoke = pose_slide_push_invoke;
+ ot->modal = pose_slide_modal;
+ ot->cancel = pose_slide_cancel;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* Properties */
+ pose_slide_opdef_properties(ot);
}
/* ........................ */
@@ -1210,59 +1259,59 @@ void POSE_OT_push(wmOperatorType *ot)
/* invoke() - for 'relax' mode */
static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
+ tPoseSlideOp *pso;
- /* initialize data */
- if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
+ /* initialize data */
+ if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
- /* initialise percentage so that it won't pop on first mouse move */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
- /* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ /* do common setup work */
+ return pose_slide_invoke_common(C, op, pso);
}
/* exec() - for relax */
static int pose_slide_relax_exec(bContext *C, wmOperator *op)
{
- tPoseSlideOp *pso;
-
- /* initialize data (from RNA-props) */
- if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
-
- /* do common exec work */
- return pose_slide_exec_common(C, op, pso);
+ tPoseSlideOp *pso;
+
+ /* initialize data (from RNA-props) */
+ if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
+
+ /* do common exec work */
+ return pose_slide_exec_common(C, op, pso);
}
void POSE_OT_relax(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Relax Pose";
- ot->idname = "POSE_OT_relax";
- ot->description = "Make the current pose more similar to its surrounding ones";
-
- /* callbacks */
- ot->exec = pose_slide_relax_exec;
- ot->invoke = pose_slide_relax_invoke;
- ot->modal = pose_slide_modal;
- ot->cancel = pose_slide_cancel;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* Properties */
- pose_slide_opdef_properties(ot);
+ /* identifiers */
+ ot->name = "Relax Pose";
+ ot->idname = "POSE_OT_relax";
+ ot->description = "Make the current pose more similar to its surrounding ones";
+
+ /* callbacks */
+ ot->exec = pose_slide_relax_exec;
+ ot->invoke = pose_slide_relax_invoke;
+ ot->modal = pose_slide_modal;
+ ot->cancel = pose_slide_cancel;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* Properties */
+ pose_slide_opdef_properties(ot);
}
/* ........................ */
@@ -1270,59 +1319,59 @@ void POSE_OT_relax(wmOperatorType *ot)
/* invoke() - for 'breakdown' mode */
static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
+ tPoseSlideOp *pso;
- /* initialize data */
- if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
+ /* initialize data */
+ if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
- /* initialise percentage so that it won't pop on first mouse move */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
- /* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ /* do common setup work */
+ return pose_slide_invoke_common(C, op, pso);
}
/* exec() - for breakdown */
static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
{
- tPoseSlideOp *pso;
-
- /* initialize data (from RNA-props) */
- if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
-
- /* do common exec work */
- return pose_slide_exec_common(C, op, pso);
+ tPoseSlideOp *pso;
+
+ /* initialize data (from RNA-props) */
+ if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
+
+ /* do common exec work */
+ return pose_slide_exec_common(C, op, pso);
}
void POSE_OT_breakdown(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Pose Breakdowner";
- ot->idname = "POSE_OT_breakdown";
- ot->description = "Create a suitable breakdown pose on the current frame";
-
- /* callbacks */
- ot->exec = pose_slide_breakdown_exec;
- ot->invoke = pose_slide_breakdown_invoke;
- ot->modal = pose_slide_modal;
- ot->cancel = pose_slide_cancel;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* Properties */
- pose_slide_opdef_properties(ot);
+ /* identifiers */
+ ot->name = "Pose Breakdowner";
+ ot->idname = "POSE_OT_breakdown";
+ ot->description = "Create a suitable breakdown pose on the current frame";
+
+ /* callbacks */
+ ot->exec = pose_slide_breakdown_exec;
+ ot->invoke = pose_slide_breakdown_invoke;
+ ot->modal = pose_slide_modal;
+ ot->cancel = pose_slide_cancel;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* Properties */
+ pose_slide_opdef_properties(ot);
}
/* **************************************************** */
@@ -1330,30 +1379,30 @@ void POSE_OT_breakdown(wmOperatorType *ot)
/* "termination conditions" - i.e. when we stop */
typedef enum ePosePropagate_Termination {
- /* stop after the current hold ends */
- POSE_PROPAGATE_SMART_HOLDS = 0,
- /* only do on the last keyframe */
- POSE_PROPAGATE_LAST_KEY,
- /* stop after the next keyframe */
- POSE_PROPAGATE_NEXT_KEY,
- /* stop after the specified frame */
- POSE_PROPAGATE_BEFORE_FRAME,
- /* stop when we run out of keyframes */
- POSE_PROPAGATE_BEFORE_END,
-
- /* only do on keyframes that are selected */
- POSE_PROPAGATE_SELECTED_KEYS,
- /* only do on the frames where markers are selected */
- POSE_PROPAGATE_SELECTED_MARKERS,
+ /* stop after the current hold ends */
+ POSE_PROPAGATE_SMART_HOLDS = 0,
+ /* only do on the last keyframe */
+ POSE_PROPAGATE_LAST_KEY,
+ /* stop after the next keyframe */
+ POSE_PROPAGATE_NEXT_KEY,
+ /* stop after the specified frame */
+ POSE_PROPAGATE_BEFORE_FRAME,
+ /* stop when we run out of keyframes */
+ POSE_PROPAGATE_BEFORE_END,
+
+ /* only do on keyframes that are selected */
+ POSE_PROPAGATE_SELECTED_KEYS,
+ /* only do on the frames where markers are selected */
+ POSE_PROPAGATE_SELECTED_MARKERS,
} ePosePropagate_Termination;
/* termination data needed for some modes - assumes only one of these entries will be needed at a time */
typedef union tPosePropagate_ModeData {
- /* smart holds + before frame: frame number to stop on */
- float end_frame;
+ /* smart holds + before frame: frame number to stop on */
+ float end_frame;
- /* selected markers: listbase for CfraElem's marking these frames */
- ListBase sel_markers;
+ /* selected markers: listbase for CfraElem's marking these frames */
+ ListBase sel_markers;
} tPosePropagate_ModeData;
/* --------------------------------- */
@@ -1365,333 +1414,371 @@ typedef union tPosePropagate_ModeData {
*/
static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float startFrame)
{
- DLRBT_Tree keys;
-
- Object *ob = pfl->ob;
- AnimData *adt = ob->adt;
- LinkData *ld;
- float endFrame = startFrame;
-
- /* set up optimized data-structures for searching for relevant keyframes + holds */
- BLI_dlrbTree_init(&keys);
-
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(adt, fcu, &keys, 0);
- }
-
- /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
- * - the best case would be one that starts on the frame itself
- */
- ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &startFrame);
-
- /* There are only two cases for no-exact match:
- * 1) the current frame is just before another key but not on a key itself
- * 2) the current frame is on a key, but that key doesn't link to the next
- *
- * If we've got the first case, then we can search for another block,
- * otherwise forget it, as we'd be overwriting some valid data.
- */
- if (ab == NULL) {
- /* we've got case 1, so try the one after */
- ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
-
- if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* try the block before this frame then as last resort */
- ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
- }
- }
-
- /* whatever happens, stop searching now... */
- if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* restrict range to just the frame itself
- * i.e. everything is in motion, so no holds to safely overwrite
- */
- ab = NULL;
- }
-
- /* check if we can go any further than we've already gone */
- if (ab) {
- /* go to next if it is also valid and meets "extension" criteria */
- while (ab->next) {
- ActKeyColumn *abn = ab->next;
-
- /* must be valid */
- if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- break;
- }
- /* should have the same number of curves */
- if (ab->totblock != abn->totblock) {
- break;
- }
-
- /* we can extend the bounds to the end of this "next" block now */
- ab = abn;
- }
-
- /* end frame can now take the value of the end of the block */
- endFrame = ab->next->cfra;
- }
-
- /* free temp memory */
- BLI_dlrbTree_free(&keys);
-
- /* return the end frame we've found */
- return endFrame;
+ DLRBT_Tree keys;
+
+ Object *ob = pfl->ob;
+ AnimData *adt = ob->adt;
+ LinkData *ld;
+ float endFrame = startFrame;
+
+ /* set up optimized data-structures for searching for relevant keyframes + holds */
+ BLI_dlrbTree_init(&keys);
+
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ fcurve_to_keylist(adt, fcu, &keys, 0);
+ }
+
+ /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
+ * - the best case would be one that starts on the frame itself
+ */
+ ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(
+ &keys, compare_ak_cfraPtr, &startFrame);
+
+ /* There are only two cases for no-exact match:
+ * 1) the current frame is just before another key but not on a key itself
+ * 2) the current frame is on a key, but that key doesn't link to the next
+ *
+ * If we've got the first case, then we can search for another block,
+ * otherwise forget it, as we'd be overwriting some valid data.
+ */
+ if (ab == NULL) {
+ /* we've got case 1, so try the one after */
+ ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
+
+ if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* try the block before this frame then as last resort */
+ ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
+ }
+ }
+
+ /* whatever happens, stop searching now... */
+ if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* restrict range to just the frame itself
+ * i.e. everything is in motion, so no holds to safely overwrite
+ */
+ ab = NULL;
+ }
+
+ /* check if we can go any further than we've already gone */
+ if (ab) {
+ /* go to next if it is also valid and meets "extension" criteria */
+ while (ab->next) {
+ ActKeyColumn *abn = ab->next;
+
+ /* must be valid */
+ if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ break;
+ }
+ /* should have the same number of curves */
+ if (ab->totblock != abn->totblock) {
+ break;
+ }
+
+ /* we can extend the bounds to the end of this "next" block now */
+ ab = abn;
+ }
+
+ /* end frame can now take the value of the end of the block */
+ endFrame = ab->next->cfra;
+ }
+
+ /* free temp memory */
+ BLI_dlrbTree_free(&keys);
+
+ /* return the end frame we've found */
+ return endFrame;
}
/* get reference value from F-Curve using RNA */
static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value)
{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
- bool found = false;
-
- /* base pointer is always the object -> id_ptr */
- RNA_id_pointer_create(&ob->id, &id_ptr);
-
- /* resolve the property... */
- if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
- if (RNA_property_array_check(prop)) {
- /* array */
- if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
- found = true;
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- *value = (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index);
- break;
- case PROP_INT:
- *value = (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index);
- break;
- case PROP_FLOAT:
- *value = RNA_property_float_get_index(&ptr, prop, fcu->array_index);
- break;
- default:
- found = false;
- break;
- }
- }
- }
- else {
- /* not an array */
- found = true;
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- *value = (float)RNA_property_boolean_get(&ptr, prop);
- break;
- case PROP_INT:
- *value = (float)RNA_property_int_get(&ptr, prop);
- break;
- case PROP_ENUM:
- *value = (float)RNA_property_enum_get(&ptr, prop);
- break;
- case PROP_FLOAT:
- *value = RNA_property_float_get(&ptr, prop);
- break;
- default:
- found = false;
- break;
- }
- }
- }
-
- return found;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ bool found = false;
+
+ /* base pointer is always the object -> id_ptr */
+ RNA_id_pointer_create(&ob->id, &id_ptr);
+
+ /* resolve the property... */
+ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
+ if (RNA_property_array_check(prop)) {
+ /* array */
+ if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
+ found = true;
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ *value = (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index);
+ break;
+ case PROP_INT:
+ *value = (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index);
+ break;
+ case PROP_FLOAT:
+ *value = RNA_property_float_get_index(&ptr, prop, fcu->array_index);
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ }
+ else {
+ /* not an array */
+ found = true;
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ *value = (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ *value = (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ *value = (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ *value = RNA_property_float_get(&ptr, prop);
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ }
+
+ return found;
}
/* propagate just works along each F-Curve in turn */
-static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
- float startFrame, tPosePropagate_ModeData modeData)
+static void pose_propagate_fcurve(
+ wmOperator *op, Object *ob, FCurve *fcu, float startFrame, tPosePropagate_ModeData modeData)
{
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- BezTriple *bezt;
- float refVal = 0.0f;
- bool keyExists;
- int i, match;
- short first = 1;
-
- /* skip if no keyframes to edit */
- if ((fcu->bezt == NULL) || (fcu->totvert < 2))
- return;
-
- /* find the reference value from bones directly, which means that the user
- * doesn't need to firstly keyframe the pose (though this doesn't mean that
- * they can't either)
- */
- if (!pose_propagate_get_refVal(ob, fcu, &refVal))
- return;
-
- /* find the first keyframe to start propagating from
- * - if there's a keyframe on the current frame, we probably want to save this value there too
- * since it may be as of yet unkeyed
- * - if starting before the starting frame, don't touch the key, as it may have had some valid
- * values
- * - if only doing selected keyframes, start from the first one
- */
- if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
- match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
-
- if (fcu->bezt[match].vec[1][0] < startFrame)
- i = match + 1;
- else
- i = match;
- }
- else {
- /* selected - start from first keyframe */
- i = 0;
- }
-
- for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
- /* additional termination conditions based on the operator 'mode' property go here... */
- if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
- /* stop if keyframe is outside the accepted range */
- if (bezt->vec[1][0] > modeData.end_frame)
- break;
- }
- else if (mode == POSE_PROPAGATE_NEXT_KEY) {
- /* stop after the first keyframe has been processed */
- if (first == 0)
- break;
- }
- else if (mode == POSE_PROPAGATE_LAST_KEY) {
- /* only affect this frame if it will be the last one */
- if (i != (fcu->totvert - 1))
- continue;
- }
- else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
- /* only allow if there's a marker on this frame */
- CfraElem *ce = NULL;
-
- /* stop on matching marker if there is one */
- for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
- if (ce->cfra == round_fl_to_int(bezt->vec[1][0]))
- break;
- }
-
- /* skip this keyframe if no marker */
- if (ce == NULL)
- continue;
- }
- else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
- /* only allow if this keyframe is already selected - skip otherwise */
- if (BEZT_ISSEL_ANY(bezt) == 0)
- continue;
- }
-
- /* just flatten handles, since values will now be the same either side... */
- /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
- bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
-
- /* select keyframe to indicate that it's been changed */
- bezt->f2 |= SELECT;
- first = 0;
- }
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ BezTriple *bezt;
+ float refVal = 0.0f;
+ bool keyExists;
+ int i, match;
+ short first = 1;
+
+ /* skip if no keyframes to edit */
+ if ((fcu->bezt == NULL) || (fcu->totvert < 2))
+ return;
+
+ /* find the reference value from bones directly, which means that the user
+ * doesn't need to firstly keyframe the pose (though this doesn't mean that
+ * they can't either)
+ */
+ if (!pose_propagate_get_refVal(ob, fcu, &refVal))
+ return;
+
+ /* find the first keyframe to start propagating from
+ * - if there's a keyframe on the current frame, we probably want to save this value there too
+ * since it may be as of yet unkeyed
+ * - if starting before the starting frame, don't touch the key, as it may have had some valid
+ * values
+ * - if only doing selected keyframes, start from the first one
+ */
+ if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
+ match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
+
+ if (fcu->bezt[match].vec[1][0] < startFrame)
+ i = match + 1;
+ else
+ i = match;
+ }
+ else {
+ /* selected - start from first keyframe */
+ i = 0;
+ }
+
+ for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
+ /* additional termination conditions based on the operator 'mode' property go here... */
+ if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
+ /* stop if keyframe is outside the accepted range */
+ if (bezt->vec[1][0] > modeData.end_frame)
+ break;
+ }
+ else if (mode == POSE_PROPAGATE_NEXT_KEY) {
+ /* stop after the first keyframe has been processed */
+ if (first == 0)
+ break;
+ }
+ else if (mode == POSE_PROPAGATE_LAST_KEY) {
+ /* only affect this frame if it will be the last one */
+ if (i != (fcu->totvert - 1))
+ continue;
+ }
+ else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
+ /* only allow if there's a marker on this frame */
+ CfraElem *ce = NULL;
+
+ /* stop on matching marker if there is one */
+ for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
+ if (ce->cfra == round_fl_to_int(bezt->vec[1][0]))
+ break;
+ }
+
+ /* skip this keyframe if no marker */
+ if (ce == NULL)
+ continue;
+ }
+ else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
+ /* only allow if this keyframe is already selected - skip otherwise */
+ if (BEZT_ISSEL_ANY(bezt) == 0)
+ continue;
+ }
+
+ /* just flatten handles, since values will now be the same either side... */
+ /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
+ bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
+
+ /* select keyframe to indicate that it's been changed */
+ bezt->f2 |= SELECT;
+ first = 0;
+ }
}
/* --------------------------------- */
static int pose_propagate_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- ListBase pflinks = {NULL, NULL};
- tPChanFCurveLink *pfl;
-
- tPosePropagate_ModeData modeData;
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* isolate F-Curves related to the selected bones */
- poseAnim_mapping_get(C, &pflinks);
-
- if (BLI_listbase_is_empty(&pflinks)) {
- /* There is a change the reason the list is empty is that there is no valid object to propagate poses for.
- * This is very unlikely though, so we focus on the most likely issue. */
- BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
- return OPERATOR_CANCELLED;
- }
-
- /* mode-specific data preprocessing (requiring no access to curves) */
- if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
- /* get a list of selected markers */
- ED_markers_make_cfra_list(&scene->markers, &modeData.sel_markers, SELECT);
- }
- else {
- /* assume everything else wants endFrame */
- modeData.end_frame = RNA_float_get(op->ptr, "end_frame");
- }
-
- /* for each bone, perform the copying required */
- for (pfl = pflinks.first; pfl; pfl = pfl->next) {
- LinkData *ld;
-
- /* mode-specific data preprocessing (requiring access to all curves) */
- if (mode == POSE_PROPAGATE_SMART_HOLDS) {
- /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
- * from the keyframe that occurs after the current frame
- */
- modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
- }
-
- /* go through propagating pose to keyframes, curve by curve */
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
- }
- }
-
- /* free temp data */
- poseAnim_mapping_free(&pflinks);
-
- if (mode == POSE_PROPAGATE_SELECTED_MARKERS)
- BLI_freelistN(&modeData.sel_markers);
-
- /* updates + notifiers */
- FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
- poseAnim_mapping_refresh(C, scene, ob);
- } FOREACH_OBJECT_IN_MODE_END;
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ ListBase pflinks = {NULL, NULL};
+ tPChanFCurveLink *pfl;
+
+ tPosePropagate_ModeData modeData;
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* isolate F-Curves related to the selected bones */
+ poseAnim_mapping_get(C, &pflinks);
+
+ if (BLI_listbase_is_empty(&pflinks)) {
+ /* There is a change the reason the list is empty is that there is no valid object to propagate poses for.
+ * This is very unlikely though, so we focus on the most likely issue. */
+ BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* mode-specific data preprocessing (requiring no access to curves) */
+ if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
+ /* get a list of selected markers */
+ ED_markers_make_cfra_list(&scene->markers, &modeData.sel_markers, SELECT);
+ }
+ else {
+ /* assume everything else wants endFrame */
+ modeData.end_frame = RNA_float_get(op->ptr, "end_frame");
+ }
+
+ /* for each bone, perform the copying required */
+ for (pfl = pflinks.first; pfl; pfl = pfl->next) {
+ LinkData *ld;
+
+ /* mode-specific data preprocessing (requiring access to all curves) */
+ if (mode == POSE_PROPAGATE_SMART_HOLDS) {
+ /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
+ * from the keyframe that occurs after the current frame
+ */
+ modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
+ }
+
+ /* go through propagating pose to keyframes, curve by curve */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
+ }
+ }
+
+ /* free temp data */
+ poseAnim_mapping_free(&pflinks);
+
+ if (mode == POSE_PROPAGATE_SELECTED_MARKERS)
+ BLI_freelistN(&modeData.sel_markers);
+
+ /* updates + notifiers */
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ poseAnim_mapping_refresh(C, scene, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return OPERATOR_FINISHED;
}
/* --------------------------------- */
void POSE_OT_propagate(wmOperatorType *ot)
{
- static const EnumPropertyItem terminate_items[] = {
- {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held",
- "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
- {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe",
- "Propagate pose to first keyframe following the current frame only"},
- {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe",
- "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
- {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame",
- "Propagate pose to all keyframes between current frame and 'Frame' property"},
- {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe",
- "Propagate pose to all keyframes from current frame until no more are found"},
- {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes",
- "Propagate pose to all selected keyframes"},
- {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers",
- "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Propagate Pose";
- ot->idname = "POSE_OT_propagate";
- ot->description = "Copy selected aspects of the current pose to subsequent poses already keyframed";
-
- /* callbacks */
- ot->exec = pose_propagate_exec;
- ot->poll = ED_operator_posemode; /* XXX: needs selected bones! */
-
- /* flag */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- /* TODO: add "fade out" control for tapering off amount of propagation as time goes by? */
- ot->prop = RNA_def_enum(ot->srna, "mode", terminate_items, POSE_PROPAGATE_SMART_HOLDS, "Terminate Mode", "Method used to determine when to stop propagating pose to keyframes");
- RNA_def_float(ot->srna, "end_frame", 250.0, FLT_MIN, FLT_MAX, "End Frame", "Frame to stop propagating frames to (for 'Before Frame' mode)", 1.0, 250.0);
+ static const EnumPropertyItem terminate_items[] = {
+ {POSE_PROPAGATE_SMART_HOLDS,
+ "WHILE_HELD",
+ 0,
+ "While Held",
+ "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
+ {POSE_PROPAGATE_NEXT_KEY,
+ "NEXT_KEY",
+ 0,
+ "To Next Keyframe",
+ "Propagate pose to first keyframe following the current frame only"},
+ {POSE_PROPAGATE_LAST_KEY,
+ "LAST_KEY",
+ 0,
+ "To Last Keyframe",
+ "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
+ {POSE_PROPAGATE_BEFORE_FRAME,
+ "BEFORE_FRAME",
+ 0,
+ "Before Frame",
+ "Propagate pose to all keyframes between current frame and 'Frame' property"},
+ {POSE_PROPAGATE_BEFORE_END,
+ "BEFORE_END",
+ 0,
+ "Before Last Keyframe",
+ "Propagate pose to all keyframes from current frame until no more are found"},
+ {POSE_PROPAGATE_SELECTED_KEYS,
+ "SELECTED_KEYS",
+ 0,
+ "On Selected Keyframes",
+ "Propagate pose to all selected keyframes"},
+ {POSE_PROPAGATE_SELECTED_MARKERS,
+ "SELECTED_MARKERS",
+ 0,
+ "On Selected Markers",
+ "Propagate pose to all keyframes occurring on frames with Scene Markers after the current "
+ "frame"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Propagate Pose";
+ ot->idname = "POSE_OT_propagate";
+ ot->description =
+ "Copy selected aspects of the current pose to subsequent poses already keyframed";
+
+ /* callbacks */
+ ot->exec = pose_propagate_exec;
+ ot->poll = ED_operator_posemode; /* XXX: needs selected bones! */
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ /* TODO: add "fade out" control for tapering off amount of propagation as time goes by? */
+ ot->prop = RNA_def_enum(ot->srna,
+ "mode",
+ terminate_items,
+ POSE_PROPAGATE_SMART_HOLDS,
+ "Terminate Mode",
+ "Method used to determine when to stop propagating pose to keyframes");
+ RNA_def_float(ot->srna,
+ "end_frame",
+ 250.0,
+ FLT_MIN,
+ FLT_MAX,
+ "End Frame",
+ "Frame to stop propagating frames to (for 'Before Frame' mode)",
+ 1.0,
+ 250.0);
}
/* **************************************************** */