Multi-Objects: pose slide operators
* POSE_OT_breakdown * POSE_OT_relax * POSE_OT_push * POSE_OT_propagate Note: I could not test relax because of T57313. Note 2: I believe those are the last armature related operators to be ported - \o/
This commit is contained in:
parent
8e3a680ebe
commit
3c61efcf20
Notes:
blender-bot
2023-02-14 06:47:29 +01:00
Referenced by issue #54650, Multi-Object-Mode: Pose Tools
|
@ -147,6 +147,8 @@ void POSE_OT_bone_layers(struct wmOperatorType *ot);
|
|||
typedef struct tPChanFCurveLink {
|
||||
struct tPChanFCurveLink *next, *prev;
|
||||
|
||||
struct Object *ob; /* Object this Pose Channel belongs to. */
|
||||
|
||||
ListBase fcurves; /* F-Curves for this PoseChannel (wrapped with LinkData) */
|
||||
struct bPoseChannel *pchan; /* Pose Channel which data is attached to */
|
||||
|
||||
|
@ -170,12 +172,13 @@ typedef struct tPChanFCurveLink {
|
|||
|
||||
/* ----------- */
|
||||
|
||||
void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks, struct Object *ob, struct bAction *act);
|
||||
struct Object *poseAnim_object_get(struct Object *ob_);
|
||||
void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks);
|
||||
void poseAnim_mapping_free(ListBase *pfLinks);
|
||||
|
||||
void poseAnim_mapping_refresh(struct bContext *C, struct Scene *scene, struct Object *ob);
|
||||
void poseAnim_mapping_reset(ListBase *pfLinks);
|
||||
void poseAnim_mapping_autoKeyframe(struct bContext *C, struct Scene *scene, struct Object *ob, ListBase *pfLinks, float cframe);
|
||||
void poseAnim_mapping_autoKeyframe(struct bContext *C, struct Scene *scene, ListBase *pfLinks, float cframe);
|
||||
|
||||
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "BKE_nla.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -89,10 +90,9 @@ typedef struct tPoseSlideOp {
|
|||
Scene *scene; /* current scene */
|
||||
ScrArea *sa; /* area that we're operating in (needed for modal()) */
|
||||
ARegion *ar; /* region that we're operating in (needed for modal()) */
|
||||
Object *ob; /* active object that Pose Info comes from */
|
||||
bArmature *arm; /* armature for pose */
|
||||
uint objects_len; /* len of the PoseSlideObject array. */
|
||||
|
||||
ListBase pfLinks; /* links between posechannels and f-curves */
|
||||
ListBase pfLinks; /* links between posechannels and f-curves for all the pose objects. */
|
||||
DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */
|
||||
|
||||
int cframe; /* current frame number - global time */
|
||||
|
@ -100,9 +100,6 @@ typedef struct tPoseSlideOp {
|
|||
int prevFrame; /* frame before current frame (blend-from) - global time */
|
||||
int nextFrame; /* frame after current frame (blend-to) - global time */
|
||||
|
||||
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) */
|
||||
|
||||
short mode; /* sliding mode (ePoseSlide_Modes) */
|
||||
short flag; /* unused for now, but can later get used for storing runtime settings.... */
|
||||
|
||||
|
@ -112,8 +109,17 @@ typedef struct tPoseSlideOp {
|
|||
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
|
||||
|
||||
NumInput num; /* numeric input */
|
||||
|
||||
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;
|
||||
} tPoseSlideObject;
|
||||
|
||||
/* Pose Sliding Modes */
|
||||
typedef enum ePoseSlide_Modes {
|
||||
POSESLIDE_PUSH = 0, /* exaggerate the pose... */
|
||||
|
@ -167,18 +173,15 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
|
|||
/* ------------------------------------ */
|
||||
|
||||
/* operator init */
|
||||
static int pose_slide_init(bContext *C, wmOperator *op, short mode)
|
||||
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
|
||||
{
|
||||
tPoseSlideOp *pso;
|
||||
bAction *act = NULL;
|
||||
|
||||
/* init slide-op data */
|
||||
pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
|
||||
|
||||
/* get info from context */
|
||||
pso->scene = CTX_data_scene(C);
|
||||
pso->ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
|
||||
pso->arm = (pso->ob) ? pso->ob->data : NULL;
|
||||
pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
|
||||
pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
|
||||
|
||||
|
@ -194,25 +197,38 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
|
|||
pso->channels = RNA_enum_get(op->ptr, "channels");
|
||||
pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
|
||||
|
||||
/* ensure validity of the settings from the context */
|
||||
if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
|
||||
return 0;
|
||||
|
||||
act = pso->ob->adt->action;
|
||||
|
||||
/* apply NLA mapping corrections so the frame lookups work */
|
||||
pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
|
||||
pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
|
||||
|
||||
/* 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, pso->ob, act);
|
||||
* and set the relevant transform flags...
|
||||
*/
|
||||
poseAnim_mapping_get(C, &pso->pfLinks);
|
||||
|
||||
/* set depsgraph flags */
|
||||
/* make sure the lock is set OK, unlock can be accidentally saved? */
|
||||
pso->ob->pose->flag |= POSE_LOCKED;
|
||||
pso->ob->pose->flag &= ~POSE_DO_UNLOCK;
|
||||
Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(CTX_data_view_layer(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).
|
||||
|
@ -242,6 +258,10 @@ static void pose_slide_exit(wmOperator *op)
|
|||
/* 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);
|
||||
}
|
||||
|
||||
/* free data itself */
|
||||
MEM_freeN(pso);
|
||||
}
|
||||
|
@ -256,21 +276,50 @@ static void pose_slide_exit(wmOperator *op)
|
|||
static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
|
||||
{
|
||||
/* wrapper around the generic version, allowing us to add some custom stuff later still */
|
||||
poseAnim_mapping_refresh(C, pso->scene, pso->ob);
|
||||
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 frme in the tPChanFCurveLink. */
|
||||
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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* helper for apply() - perform sliding for some value */
|
||||
static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, 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, pso->prevFrameF);
|
||||
sVal = evaluate_fcurve(fcu, prevFrameF);
|
||||
/* next/end */
|
||||
eVal = evaluate_fcurve(fcu, pso->nextFrameF);
|
||||
eVal = evaluate_fcurve(fcu, nextFrameF);
|
||||
|
||||
/* if both values are equal, don't do anything */
|
||||
if (IS_EQF(sVal, eVal)) {
|
||||
|
@ -364,7 +413,7 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
|
|||
((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, &vec[fcu->array_index]);
|
||||
pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,14 +462,14 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, con
|
|||
case PROP_FLOAT:
|
||||
{
|
||||
float tval = RNA_property_float_get(&ptr, prop);
|
||||
pose_slide_apply_val(pso, fcu, &tval);
|
||||
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, &tval);
|
||||
pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
|
||||
RNA_property_int_set(&ptr, prop, (int)tval);
|
||||
break;
|
||||
}
|
||||
|
@ -429,7 +478,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, con
|
|||
case PROP_BOOLEAN:
|
||||
{
|
||||
float tval = (float)RNA_property_boolean_get(&ptr, prop);
|
||||
pose_slide_apply_val(pso, fcu, &tval);
|
||||
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;
|
||||
}
|
||||
|
@ -459,6 +508,12 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
|
|||
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");
|
||||
|
@ -492,15 +547,15 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
|
|||
float quat_prev[4], quat_next[4];
|
||||
|
||||
/* get 2 quats */
|
||||
quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrameF);
|
||||
quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrameF);
|
||||
quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrameF);
|
||||
quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrameF);
|
||||
quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
|
||||
quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
|
||||
quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF);
|
||||
quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF);
|
||||
|
||||
quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrameF);
|
||||
quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrameF);
|
||||
quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrameF);
|
||||
quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrameF);
|
||||
quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF);
|
||||
quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF);
|
||||
quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF);
|
||||
quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF);
|
||||
|
||||
/* perform blending */
|
||||
if (pso->mode == POSESLIDE_BREAKDOWN) {
|
||||
|
@ -553,9 +608,21 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
|
|||
pso->prevFrame--;
|
||||
pso->nextFrame++;
|
||||
|
||||
/* apply NLA mapping corrections so the frame lookups work */
|
||||
pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
|
||||
pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
|
||||
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,
|
||||
ob_data->prevFrameF,
|
||||
NLATIME_CONVERT_UNMAP);
|
||||
ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
|
||||
ob_data->nextFrameF,
|
||||
NLATIME_CONVERT_UNMAP);
|
||||
}
|
||||
}
|
||||
|
||||
/* for each link, handle each set of transforms */
|
||||
|
@ -613,7 +680,7 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
|
|||
static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
|
||||
{
|
||||
/* wrapper around the generic call */
|
||||
poseAnim_mapping_autoKeyframe(C, pso->scene, pso->ob, &pso->pfLinks, (float)pso->cframe);
|
||||
poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
|
||||
}
|
||||
|
||||
/* reset changes made to current pose */
|
||||
|
@ -712,7 +779,6 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
|
|||
static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
|
||||
{
|
||||
tPChanFCurveLink *pfl;
|
||||
AnimData *adt = pso->ob->adt;
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
|
||||
/* for each link, add all its keyframes to the search tree */
|
||||
|
@ -722,7 +788,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
|
|||
/* do this for each F-Curve */
|
||||
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
|
||||
FCurve *fcu = (FCurve *)ld->data;
|
||||
fcurve_to_keylist(adt, fcu, &pso->keys);
|
||||
fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,8 +824,17 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
|
|||
}
|
||||
|
||||
/* apply NLA mapping corrections so the frame lookups work */
|
||||
pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
|
||||
pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
|
||||
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,
|
||||
ob_data->prevFrameF,
|
||||
NLATIME_CONVERT_UNMAP);
|
||||
ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
|
||||
ob_data->nextFrameF,
|
||||
NLATIME_CONVERT_UNMAP);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
|
||||
|
@ -1260,10 +1335,11 @@ typedef union tPosePropagate_ModeData {
|
|||
* if this happens to be a major issue, scrap this, and just make this happen
|
||||
* independently per F-Curve
|
||||
*/
|
||||
static float pose_propagate_get_boneHoldEndFrame(Object *ob, tPChanFCurveLink *pfl, float startFrame)
|
||||
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;
|
||||
|
@ -1489,8 +1565,7 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
|
|||
static int pose_propagate_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
|
||||
bAction *act = (ob && ob->adt) ? ob->adt->action : NULL;
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
ListBase pflinks = {NULL, NULL};
|
||||
tPChanFCurveLink *pfl;
|
||||
|
@ -1498,19 +1573,16 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
|
|||
tPosePropagate_ModeData modeData;
|
||||
const int mode = RNA_enum_get(op->ptr, "mode");
|
||||
|
||||
/* sanity checks */
|
||||
if (ob == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No object to propagate poses for");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (act == NULL) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* isolate F-Curves related to the selected bones */
|
||||
poseAnim_mapping_get(C, &pflinks, ob, act);
|
||||
|
||||
/* mode-specific data preprocessing (requiring no access to curves) */
|
||||
if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
|
||||
/* get a list of selected markers */
|
||||
|
@ -1530,12 +1602,13 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
|
|||
/* 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(ob, pfl, (float)CFRA);
|
||||
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, ob, (FCurve *)ld->data, (float)CFRA, modeData);
|
||||
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
|
||||
pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
|
||||
}
|
||||
}
|
||||
|
||||
/* free temp data */
|
||||
|
@ -1545,7 +1618,9 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
|
|||
BLI_freelistN(&modeData.sel_markers);
|
||||
|
||||
/* updates + notifiers */
|
||||
poseAnim_mapping_refresh(C, scene, ob);
|
||||
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob) {
|
||||
poseAnim_mapping_refresh(C, scene, ob);
|
||||
} FOREACH_OBJECT_IN_MODE_END;
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
|
@ -81,6 +83,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
|
|||
tPChanFCurveLink *pfl = MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
|
||||
PointerRNA ptr;
|
||||
|
||||
pfl->ob = ob;
|
||||
pfl->fcurves = curves;
|
||||
pfl->pchan = pchan;
|
||||
|
||||
|
@ -127,16 +130,48 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a valid pose armature for this object, else returns NULL.
|
||||
**/
|
||||
Object *poseAnim_object_get(Object *ob_)
|
||||
{
|
||||
Object *ob = BKE_object_pose_armature_get(ob_);
|
||||
if (!ELEM(NULL,
|
||||
ob,
|
||||
ob->data,
|
||||
ob->adt,
|
||||
ob->adt->action))
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get sets of F-Curves providing transforms for the bones in the Pose */
|
||||
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *act)
|
||||
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
|
||||
{
|
||||
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
|
||||
* and set the relevant transform flags...
|
||||
*/
|
||||
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
|
||||
Object *prev_ob, *ob_pose_armature;
|
||||
|
||||
prev_ob = NULL;
|
||||
ob_pose_armature = NULL;
|
||||
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
|
||||
{
|
||||
fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
|
||||
if (ob != prev_ob) {
|
||||
prev_ob = ob;
|
||||
ob_pose_armature = poseAnim_object_get(ob);
|
||||
}
|
||||
|
||||
if (ob_pose_armature == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fcurves_to_pchan_links_get(pfLinks,
|
||||
ob_pose_armature,
|
||||
ob_pose_armature->adt->action,
|
||||
pchan);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
|
@ -144,12 +179,25 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a
|
|||
* i.e. if nothing selected, do whole pose
|
||||
*/
|
||||
if (BLI_listbase_is_empty(pfLinks)) {
|
||||
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
|
||||
prev_ob = NULL;
|
||||
ob_pose_armature = NULL;
|
||||
CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
|
||||
{
|
||||
fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
|
||||
if (ob != prev_ob) {
|
||||
prev_ob = ob;
|
||||
ob_pose_armature = poseAnim_object_get(ob);
|
||||
}
|
||||
|
||||
if (ob_pose_armature == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fcurves_to_pchan_links_get(pfLinks,
|
||||
ob_pose_armature,
|
||||
ob_pose_armature->adt->action,
|
||||
pchan);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,42 +284,71 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
|
|||
}
|
||||
|
||||
/* perform autokeyframing after changes were made + confirmed */
|
||||
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
|
||||
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
|
||||
{
|
||||
/* insert keyframes as necessary if autokeyframing */
|
||||
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
|
||||
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
|
||||
ListBase dsources = {NULL, NULL};
|
||||
tPChanFCurveLink *pfl;
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
bool skip = true;
|
||||
|
||||
/* iterate over each pose-channel affected, tagging bones to be keyed */
|
||||
/* XXX: here we already have the information about what transforms exist, though
|
||||
* it might be easier to just overwrite all using normal mechanisms
|
||||
*/
|
||||
for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
|
||||
bPoseChannel *pchan = pfl->pchan;
|
||||
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob) {
|
||||
ob->id.tag &= ~LIB_TAG_DOIT;
|
||||
ob = poseAnim_object_get(ob);
|
||||
|
||||
/* add datasource override for the PoseChannel, to be used later */
|
||||
ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan);
|
||||
|
||||
/* clear any unkeyed tags */
|
||||
if (pchan->bone)
|
||||
pchan->bone->flag &= ~BONE_UNKEYED;
|
||||
/* Ensure validity of the settings from the context. */
|
||||
if (ob == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* insert keyframes for all relevant bones in one go */
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
|
||||
BLI_freelistN(&dsources);
|
||||
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
|
||||
ob->id.tag |= LIB_TAG_DOIT;
|
||||
skip = false;
|
||||
}
|
||||
} FOREACH_OBJECT_IN_MODE_END;
|
||||
|
||||
/* do the bone paths
|
||||
* - only do this if keyframes should have been added
|
||||
* - do not calculate unless there are paths already to update...
|
||||
*/
|
||||
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
|
||||
//ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
|
||||
ED_pose_recalculate_paths(C, scene, ob, false);
|
||||
if (skip) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* insert keyframes as necessary if autokeyframing */
|
||||
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
|
||||
ListBase dsources = {NULL, NULL};
|
||||
tPChanFCurveLink *pfl;
|
||||
|
||||
/* iterate over each pose-channel affected, tagging bones to be keyed */
|
||||
/* XXX: here we already have the information about what transforms exist, though
|
||||
* it might be easier to just overwrite all using normal mechanisms
|
||||
*/
|
||||
for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
|
||||
bPoseChannel *pchan = pfl->pchan;
|
||||
|
||||
if ((pfl->ob->id.tag & LIB_TAG_DOIT) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* add datasource override for the PoseChannel, to be used later */
|
||||
ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan);
|
||||
|
||||
/* clear any unkeyed tags */
|
||||
if (pchan->bone) {
|
||||
pchan->bone->flag &= ~BONE_UNKEYED;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert keyframes for all relevant bones in one go */
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
|
||||
BLI_freelistN(&dsources);
|
||||
|
||||
/* do the bone paths
|
||||
* - only do this if keyframes should have been added
|
||||
* - do not calculate unless there are paths already to update...
|
||||
*/
|
||||
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob) {
|
||||
if (ob->id.tag & LIB_TAG_DOIT) {
|
||||
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
|
||||
//ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
|
||||
ED_pose_recalculate_paths(C, scene, ob, false);
|
||||
}
|
||||
}
|
||||
} FOREACH_OBJECT_IN_MODE_END;
|
||||
}
|
||||
|
||||
/* ------------------------- */
|
||||
|
|
Loading…
Reference in New Issue