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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_action.h8
-rw-r--r--source/blender/blenkernel/intern/action.c29
-rw-r--r--source/blender/editors/armature/armature_intern.h13
-rw-r--r--source/blender/editors/armature/poseSlide.c200
-rw-r--r--source/blender/editors/armature/poseUtils.c67
5 files changed, 196 insertions, 121 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 59da97d8b09..698f0f0fecf 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -82,9 +82,15 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ROT = (1<<1),
/* scaling */
ACT_TRANS_SCALE = (1<<2),
+
+ /* strictly not a transform, but custom properties are also
+ * quite often used in modern rigs
+ */
+ ACT_TRANS_PROP = (1<<3),
/* all flags */
- ACT_TRANS_ALL = (ACT_TRANS_LOC|ACT_TRANS_ROT|ACT_TRANS_SCALE),
+ ACT_TRANS_ONLY = (ACT_TRANS_LOC|ACT_TRANS_ROT|ACT_TRANS_SCALE),
+ ACT_TRANS_ALL = (ACT_TRANS_ONLY|ACT_TRANS_PROP)
} eAction_TransformFlags;
/* Return flags indicating which transforms the given object/posechannel has
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 1c0091cff74..4c5b7f5fcaf 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -973,6 +973,11 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
bPtr= strstr(fcu->rna_path, basePath);
if (bPtr) {
+ /* we must add len(basePath) bytes to the match so that we are at the end of the
+ * base path so that we don't get false positives with these strings in the names
+ */
+ bPtr += strlen(basePath);
+
/* step 2: check for some property with transforms
* - to speed things up, only check for the ones not yet found
* unless we're getting the curves too
@@ -981,8 +986,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
* - once a match has been found, the curve cannot possibly be any other one
*/
if ((curves) || (flags & ACT_TRANS_LOC) == 0) {
- pPtr= strstr(fcu->rna_path, "location");
- if ((pPtr) && (pPtr >= bPtr)) {
+ pPtr= strstr(bPtr, "location");
+ if (pPtr) {
flags |= ACT_TRANS_LOC;
if (curves)
@@ -992,8 +997,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
}
if ((curves) || (flags & ACT_TRANS_SCALE) == 0) {
- pPtr= strstr(fcu->rna_path, "scale");
- if ((pPtr) && (pPtr >= bPtr)) {
+ pPtr= strstr(bPtr, "scale");
+ if (pPtr) {
flags |= ACT_TRANS_SCALE;
if (curves)
@@ -1003,8 +1008,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
}
if ((curves) || (flags & ACT_TRANS_ROT) == 0) {
- pPtr= strstr(fcu->rna_path, "rotation");
- if ((pPtr) && (pPtr >= bPtr)) {
+ pPtr= strstr(bPtr, "rotation");
+ if (pPtr) {
flags |= ACT_TRANS_ROT;
if (curves)
@@ -1012,6 +1017,18 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
continue;
}
}
+
+ if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
+ /* custom properties only */
+ pPtr= strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
+ if (pPtr) {
+ flags |= ACT_TRANS_PROP;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
}
}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 5110f04aa6b..b72cf75d9c7 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -150,16 +150,19 @@ void SKETCH_OT_select(struct wmOperatorType *ot);
typedef struct tPChanFCurveLink {
struct tPChanFCurveLink *next, *prev;
- ListBase fcurves; /* F-Curves for this PoseChannel (wrapped with LinkData) */
- struct bPoseChannel *pchan; /* Pose Channel which data is attached to */
+ ListBase fcurves; /* F-Curves for this PoseChannel (wrapped with LinkData) */
+ struct bPoseChannel *pchan; /* Pose Channel which data is attached to */
- char *pchan_path; /* RNA Path to this Pose Channel (needs to be freed when we're done) */
+ char *pchan_path; /* RNA Path to this Pose Channel (needs to be freed when we're done) */
- // TODO: need to include axis-angle here at some stage
- float oldloc[3]; /* transform values at start of operator (to be restored before each modal step) */
+ float oldloc[3]; /* transform values at start of operator (to be restored before each modal step) */
float oldrot[3];
float oldscale[3];
float oldquat[4];
+ float oldangle;
+ float oldaxis[3];
+
+ struct IDProperty *oldprops; /* copy of custom properties at start of operator (to be restored before each modal step) */
} tPChanFCurveLink;
/* ----------- */
diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c
index d3d430f4331..302f23f7028 100644
--- a/source/blender/editors/armature/poseSlide.c
+++ b/source/blender/editors/armature/poseSlide.c
@@ -192,102 +192,146 @@ static void pose_slide_refresh (bContext *C, tPoseSlideOp *pso)
poseAnim_mapping_refresh(C, pso->scene, pso->ob);
}
+/* helper for apply() - perform sliding for some value */
+static void pose_slider_apply_val (tPoseSlideOp *pso, FCurve *fcu, float *val)
+{
+ float cframe = (float)pso->cframe;
+ float sVal, eVal;
+ float w1, w2;
+
+ /* get keyframe values for endpoint poses to blend with */
+ /* previous/start */
+ sVal= evaluate_fcurve(fcu, (float)pso->prevFrame);
+ /* next/end */
+ eVal= evaluate_fcurve(fcu, (float)pso->nextFrame);
+
+ /* 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 normalised 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, favouring the middle pose
+ * - numerator should be larger than denominator to 'expand' the result
+ * - perform this weighting a number of times given by the percentage...
+ */
+ int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
+
+ 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, favouring the middle pose
+ * - numerator should be smaller than denominator to 'relax' the result
+ * - perform this weighting a number of times given by the percentage...
+ */
+ int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
+
+ 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;
- float cframe;
/* get the path to use... */
path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
- /* 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;
- float sVal, eVal;
- float w1, w2;
- int ch;
- /* get keyframe values for endpoint poses to blend with */
- /* previous/start */
- sVal= evaluate_fcurve(fcu, (float)pso->prevFrame);
- /* next/end */
- eVal= evaluate_fcurve(fcu, (float)pso->nextFrame);
+ /* just work on these channels one by one... there's no interaction between values */
+ pose_slider_apply_val(pso, fcu, &vec[fcu->array_index]);
+ }
+
+ /* free the temp path we got */
+ MEM_freeN(path);
+}
+
+/* helper for apply() - perform sliding for custom properties */
+static void pose_slide_apply_props (tPoseSlideOp *pso, tPChanFCurveLink *pfl)
+{
+ 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
+ */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ char *bPtr, *pPtr;
+
+ if (fcu->rna_path == NULL)
+ continue;
- /* get channel index */
- ch= fcu->array_index;
+ /* 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, "[\""); /* dummy " for texteditor bugs */
- /* 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 normalised so that they only sum up to 1
+ 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
*/
- float wtot;
-
- w1 = cframe - (float)pso->prevFrame;
- w2 = (float)pso->nextFrame - cframe;
+ PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
- 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, favouring the middle pose
- * - numerator should be larger than denominator to 'expand' the result
- * - perform this weighting a number of times given by the percentage...
- */
- int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
+ if (prop) {
+ float tval = RNA_property_float_get(&ptr, prop);
- while (iters-- > 0) {
- vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f;
- }
- }
- break;
-
- case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
- {
- /* perform a weighted average here, favouring the middle pose
- * - numerator should be smaller than denominator to 'relax' the result
- * - perform this weighting a number of times given by the percentage...
- */
- int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed
-
- while (iters-- > 0) {
- vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f;
- }
- }
- break;
+ pose_slider_apply_val(pso, fcu, &tval);
- 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?
- vec[ch]= ((sVal * w2) + (eVal * w1));
+ RNA_property_float_set(&ptr, prop, tval);
}
- break;
}
-
}
-
- /* free the temp path we got */
- MEM_freeN(path);
}
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
@@ -426,6 +470,11 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
pose_slide_apply_quat(pso, pfl);
}
}
+
+ if (pfl->oldprops) {
+ /* not strictly a transform, but contributes to the pose produced in many rigs */
+ pose_slide_apply_props(pso, pfl);
+ }
}
/* depsgraph updates + redraws */
@@ -502,6 +551,7 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *
}
else {
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between.");
+ pose_slide_exit(op);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/armature/poseUtils.c b/source/blender/editors/armature/poseUtils.c
index f95f8836d71..bae44eb6d5b 100644
--- a/source/blender/editors/armature/poseUtils.c
+++ b/source/blender/editors/armature/poseUtils.c
@@ -53,6 +53,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_depsgraph.h"
+#include "BKE_idprop.h"
#include "BKE_context.h"
@@ -112,11 +113,16 @@ static void fcurves_to_pchan_links_get (ListBase *pfLinks, Object *ob, bAction *
pchan->flag |= POSE_SIZE;
/* store current transforms */
- // TODO: store axis-angle too?
VECCOPY(pfl->oldloc, pchan->loc);
VECCOPY(pfl->oldrot, pchan->eul);
VECCOPY(pfl->oldscale, pchan->size);
QUATCOPY(pfl->oldquat, pchan->quat);
+ VECCOPY(pfl->oldaxis, pchan->rotAxis);
+ pfl->oldangle = pchan->rotAngle;
+
+ /* make copy of custom properties */
+ if (transFlags & ACT_TRANS_PROP)
+ pfl->oldprops = IDP_CopyProperty(pchan->prop);
}
}
@@ -144,6 +150,12 @@ void poseAnim_mapping_free (ListBase *pfLinks)
for (pfl= pfLinks->first; pfl; pfl= pfln) {
pfln= pfl->next;
+ /* free custom properties */
+ if (pfl->oldprops) {
+ IDP_FreeProperty(pfl->oldprops);
+ MEM_freeN(pfl->oldprops);
+ }
+
/* free list of F-Curve reference links */
BLI_freelistN(&pfl->fcurves);
@@ -185,59 +197,46 @@ void poseAnim_mapping_reset (ListBase *pfLinks)
bPoseChannel *pchan= pfl->pchan;
/* just copy all the values over regardless of whether they changed or not */
- // TODO; include axis-angle here too?
VECCOPY(pchan->loc, pfl->oldloc);
VECCOPY(pchan->eul, pfl->oldrot);
VECCOPY(pchan->size, pfl->oldscale);
QUATCOPY(pchan->quat, pfl->oldquat);
+ VECCOPY(pchan->rotAxis, pfl->oldaxis);
+ pchan->rotAngle = pfl->oldangle;
+
+ /* just overwrite values of properties from the stored copies (there should be some) */
+ if (pfl->oldprops)
+ IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
}
}
/* perform autokeyframing after changes were made + confirmed */
void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
{
- static short keyingsets_need_init = 1;
- static KeyingSet *ks_loc = NULL;
- static KeyingSet *ks_rot = NULL;
- static KeyingSet *ks_scale = NULL;
-
- /* get keyingsets the first time this is run?
- * NOTE: it should be safe to store these static, since they're currently builtin ones
- * but maybe later this may change, in which case this code needs to be revised!
- */
- if (keyingsets_need_init) {
- ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location");
- ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
- ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scaling");
-
- keyingsets_need_init = 0;
- }
-
/* insert keyframes as necessary if autokeyframing */
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, "Whole Character");
+ ListBase dsources = {NULL, NULL};
tPChanFCurveLink *pfl;
- /* iterate over each pose-channel affected, applying the changes */
+ /* 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) {
- ListBase dsources = {NULL, NULL};
bPoseChannel *pchan= pfl->pchan;
- /* add datasource override for the PoseChannel so KeyingSet will do right thing */
+ /* add datasource override for the PoseChannel, to be used later */
ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan);
- /* insert keyframes
- * - these keyingsets here use dsources, since we need to specify exactly which keyframes get affected
- */
- if (pchan->flag & POSE_LOC)
- ANIM_apply_keyingset(C, &dsources, NULL, ks_loc, MODIFYKEY_MODE_INSERT, cframe);
- if (pchan->flag & POSE_ROT)
- ANIM_apply_keyingset(C, &dsources, NULL, ks_rot, MODIFYKEY_MODE_INSERT, cframe);
- if (pchan->flag & POSE_SIZE)
- ANIM_apply_keyingset(C, &dsources, NULL, ks_scale, MODIFYKEY_MODE_INSERT, cframe);
-
- /* free the temp info */
- BLI_freelistN(&dsources);
+ /* 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, (float)CFRA);
+ BLI_freelistN(&dsources);
}
}