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/animation/keyframes_general.c')
-rw-r--r--source/blender/editors/animation/keyframes_general.c1678
1 files changed, 853 insertions, 825 deletions
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index c9e672a111d..945327ed78b 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -21,7 +21,6 @@
* \ingroup edanimation
*/
-
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -37,7 +36,6 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
@@ -71,68 +69,68 @@
*/
void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
{
- /* sanity check */
- if (fcu == NULL)
- return;
-
- /* verify the index:
- * 1) cannot be greater than the number of available keyframes
- * 2) negative indices are for specifying a value from the end of the array
- */
- if (abs(index) >= fcu->totvert)
- return;
- else if (index < 0)
- index += fcu->totvert;
-
- /* Delete this keyframe */
- memmove(&fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
- fcu->totvert--;
-
- if (fcu->totvert == 0) {
- if (fcu->bezt)
- MEM_freeN(fcu->bezt);
- fcu->bezt = NULL;
- }
-
- /* recalc handles - only if it won't cause problems */
- if (do_recalc)
- calchandles_fcurve(fcu);
+ /* sanity check */
+ if (fcu == NULL)
+ return;
+
+ /* verify the index:
+ * 1) cannot be greater than the number of available keyframes
+ * 2) negative indices are for specifying a value from the end of the array
+ */
+ if (abs(index) >= fcu->totvert)
+ return;
+ else if (index < 0)
+ index += fcu->totvert;
+
+ /* Delete this keyframe */
+ memmove(
+ &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
+ fcu->totvert--;
+
+ if (fcu->totvert == 0) {
+ if (fcu->bezt)
+ MEM_freeN(fcu->bezt);
+ fcu->bezt = NULL;
+ }
+
+ /* recalc handles - only if it won't cause problems */
+ if (do_recalc)
+ calchandles_fcurve(fcu);
}
/* Delete selected keyframes in given F-Curve */
bool delete_fcurve_keys(FCurve *fcu)
{
- int i;
- bool changed = false;
-
- if (fcu->bezt == NULL) /* ignore baked curves */
- return false;
-
- /* Delete selected BezTriples */
- for (i = 0; i < fcu->totvert; i++) {
- if (fcu->bezt[i].f2 & SELECT) {
- memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
- fcu->totvert--;
- i--;
- changed = true;
- }
- }
-
- /* Free the array of BezTriples if there are not keyframes */
- if (fcu->totvert == 0)
- clear_fcurve_keys(fcu);
-
- return changed;
+ int i;
+ bool changed = false;
+
+ if (fcu->bezt == NULL) /* ignore baked curves */
+ return false;
+
+ /* Delete selected BezTriples */
+ for (i = 0; i < fcu->totvert; i++) {
+ if (fcu->bezt[i].f2 & SELECT) {
+ memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
+ fcu->totvert--;
+ i--;
+ changed = true;
+ }
+ }
+
+ /* Free the array of BezTriples if there are not keyframes */
+ if (fcu->totvert == 0)
+ clear_fcurve_keys(fcu);
+
+ return changed;
}
-
void clear_fcurve_keys(FCurve *fcu)
{
- if (fcu->bezt)
- MEM_freeN(fcu->bezt);
- fcu->bezt = NULL;
+ if (fcu->bezt)
+ MEM_freeN(fcu->bezt);
+ fcu->bezt = NULL;
- fcu->totvert = 0;
+ fcu->totvert = 0;
}
/* ---------------- */
@@ -140,36 +138,36 @@ void clear_fcurve_keys(FCurve *fcu)
/* duplicate selected keyframes for the given F-Curve */
void duplicate_fcurve_keys(FCurve *fcu)
{
- BezTriple *newbezt;
- int i;
-
- /* this can only work when there is an F-Curve, and also when there are some BezTriples */
- if (ELEM(NULL, fcu, fcu->bezt))
- return;
-
- for (i = 0; i < fcu->totvert; i++) {
- /* If a key is selected */
- if (fcu->bezt[i].f2 & SELECT) {
- /* Expand the list */
- newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert + 1), "beztriple");
-
- memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i + 1));
- memcpy(newbezt + i + 1, fcu->bezt + i, sizeof(BezTriple));
- memcpy(newbezt + i + 2, fcu->bezt + i + 1, sizeof(BezTriple) * (fcu->totvert - (i + 1)));
- fcu->totvert++;
-
- /* reassign pointers... (free old, and add new) */
- MEM_freeN(fcu->bezt);
- fcu->bezt = newbezt;
-
- /* Unselect the current key */
- BEZT_DESEL_ALL(&fcu->bezt[i]);
- i++;
-
- /* Select the copied key */
- BEZT_SEL_ALL(&fcu->bezt[i]);
- }
- }
+ BezTriple *newbezt;
+ int i;
+
+ /* this can only work when there is an F-Curve, and also when there are some BezTriples */
+ if (ELEM(NULL, fcu, fcu->bezt))
+ return;
+
+ for (i = 0; i < fcu->totvert; i++) {
+ /* If a key is selected */
+ if (fcu->bezt[i].f2 & SELECT) {
+ /* Expand the list */
+ newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert + 1), "beztriple");
+
+ memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i + 1));
+ memcpy(newbezt + i + 1, fcu->bezt + i, sizeof(BezTriple));
+ memcpy(newbezt + i + 2, fcu->bezt + i + 1, sizeof(BezTriple) * (fcu->totvert - (i + 1)));
+ fcu->totvert++;
+
+ /* reassign pointers... (free old, and add new) */
+ MEM_freeN(fcu->bezt);
+ fcu->bezt = newbezt;
+
+ /* Unselect the current key */
+ BEZT_DESEL_ALL(&fcu->bezt[i]);
+ i++;
+
+ /* Select the copied key */
+ BEZT_SEL_ALL(&fcu->bezt[i]);
+ }
+ }
}
/* **************************************************** */
@@ -180,327 +178,325 @@ void duplicate_fcurve_keys(FCurve *fcu)
*/
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
- FCurve *fcu = (FCurve *)ale->key_data;
- BezTriple *old_bezts, *bezt, *beztn;
- BezTriple *lastb;
- int totCount, i;
-
- /* check if any points */
- if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
- (!cleardefault && fcu->totvert == 1))
- {
- return;
- }
-
- /* make a copy of the old BezTriples, and clear F-Curve */
- old_bezts = fcu->bezt;
- totCount = fcu->totvert;
- fcu->bezt = NULL;
- fcu->totvert = 0;
-
- /* now insert first keyframe, as it should be ok */
- bezt = old_bezts;
- insert_bezt_fcurve(fcu, bezt, 0);
- if (!(bezt->f2 & SELECT)) {
- lastb = fcu->bezt;
- lastb->f1 = lastb->f2 = lastb->f3 = 0;
- }
-
- /* Loop through BezTriples, comparing them. Skip any that do
- * not fit the criteria for "ok" points.
- */
- for (i = 1; i < totCount; i++) {
- float prev[2], cur[2], next[2];
-
- /* get BezTriples and their values */
- if (i < (totCount - 1)) {
- beztn = (old_bezts + (i + 1));
- next[0] = beztn->vec[1][0]; next[1] = beztn->vec[1][1];
- }
- else {
- beztn = NULL;
- next[0] = next[1] = 0.0f;
- }
- lastb = (fcu->bezt + (fcu->totvert - 1));
- bezt = (old_bezts + i);
-
- /* get references for quicker access */
- prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
- cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
-
- if (!(bezt->f2 & SELECT)) {
- insert_bezt_fcurve(fcu, bezt, 0);
- lastb = (fcu->bezt + (fcu->totvert - 1));
- lastb->f1 = lastb->f2 = lastb->f3 = 0;
- continue;
- }
-
- /* check if current bezt occurs at same time as last ok */
- if (IS_EQT(cur[0], prev[0], thresh)) {
- /* If there is a next beztriple, and if occurs at the same time, only insert
- * if there is a considerable distance between the points, and also if the
- * current is further away than the next one is to the previous.
- */
- if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
- (IS_EQT(next[1], prev[1], thresh) == 0))
- {
- /* only add if current is further away from previous */
- if (cur[1] > next[1]) {
- if (IS_EQT(cur[1], prev[1], thresh) == 0) {
- /* add new keyframe */
- insert_bezt_fcurve(fcu, bezt, 0);
- }
- }
- }
- else {
- /* only add if values are a considerable distance apart */
- if (IS_EQT(cur[1], prev[1], thresh) == 0) {
- /* add new keyframe */
- insert_bezt_fcurve(fcu, bezt, 0);
- }
- }
- }
- else {
- /* checks required are dependent on whether this is last keyframe or not */
- if (beztn) {
- /* does current have same value as previous and next? */
- if (IS_EQT(cur[1], prev[1], thresh) == 0) {
- /* add new keyframe */
- insert_bezt_fcurve(fcu, bezt, 0);
- }
- else if (IS_EQT(cur[1], next[1], thresh) == 0) {
- /* add new keyframe */
- insert_bezt_fcurve(fcu, bezt, 0);
- }
- }
- else {
- /* add if value doesn't equal that of previous */
- if (IS_EQT(cur[1], prev[1], thresh) == 0) {
- /* add new keyframe */
- insert_bezt_fcurve(fcu, bezt, 0);
- }
- }
- }
- }
-
- /* now free the memory used by the old BezTriples */
- if (old_bezts)
- MEM_freeN(old_bezts);
-
- /* final step, if there is just one key in fcurve, check if it's
- * the default value and if is, remove fcurve completely. */
- if (cleardefault && fcu->totvert == 1) {
- float default_value = 0.0f;
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
- RNA_id_pointer_create(ale->id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
- if (RNA_property_type(prop) == PROP_FLOAT)
- default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
- }
-
- if (fcu->bezt->vec[1][1] == default_value) {
- clear_fcurve_keys(fcu);
-
- /* check if curve is really unused and if it is, return signal for deletion */
- if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
- (fcu->driver == NULL))
- {
- AnimData *adt = ale->adt;
- ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
- ale->key_data = NULL;
- }
- }
- }
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *old_bezts, *bezt, *beztn;
+ BezTriple *lastb;
+ int totCount, i;
+
+ /* check if any points */
+ if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
+ (!cleardefault && fcu->totvert == 1)) {
+ return;
+ }
+
+ /* make a copy of the old BezTriples, and clear F-Curve */
+ old_bezts = fcu->bezt;
+ totCount = fcu->totvert;
+ fcu->bezt = NULL;
+ fcu->totvert = 0;
+
+ /* now insert first keyframe, as it should be ok */
+ bezt = old_bezts;
+ insert_bezt_fcurve(fcu, bezt, 0);
+ if (!(bezt->f2 & SELECT)) {
+ lastb = fcu->bezt;
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ }
+
+ /* Loop through BezTriples, comparing them. Skip any that do
+ * not fit the criteria for "ok" points.
+ */
+ for (i = 1; i < totCount; i++) {
+ float prev[2], cur[2], next[2];
+
+ /* get BezTriples and their values */
+ if (i < (totCount - 1)) {
+ beztn = (old_bezts + (i + 1));
+ next[0] = beztn->vec[1][0];
+ next[1] = beztn->vec[1][1];
+ }
+ else {
+ beztn = NULL;
+ next[0] = next[1] = 0.0f;
+ }
+ lastb = (fcu->bezt + (fcu->totvert - 1));
+ bezt = (old_bezts + i);
+
+ /* get references for quicker access */
+ prev[0] = lastb->vec[1][0];
+ prev[1] = lastb->vec[1][1];
+ cur[0] = bezt->vec[1][0];
+ cur[1] = bezt->vec[1][1];
+
+ if (!(bezt->f2 & SELECT)) {
+ insert_bezt_fcurve(fcu, bezt, 0);
+ lastb = (fcu->bezt + (fcu->totvert - 1));
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ continue;
+ }
+
+ /* check if current bezt occurs at same time as last ok */
+ if (IS_EQT(cur[0], prev[0], thresh)) {
+ /* If there is a next beztriple, and if occurs at the same time, only insert
+ * if there is a considerable distance between the points, and also if the
+ * current is further away than the next one is to the previous.
+ */
+ if (beztn && (IS_EQT(cur[0], next[0], thresh)) && (IS_EQT(next[1], prev[1], thresh) == 0)) {
+ /* only add if current is further away from previous */
+ if (cur[1] > next[1]) {
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
+ }
+ }
+ }
+ else {
+ /* only add if values are a considerable distance apart */
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
+ }
+ }
+ }
+ else {
+ /* checks required are dependent on whether this is last keyframe or not */
+ if (beztn) {
+ /* does current have same value as previous and next? */
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
+ }
+ else if (IS_EQT(cur[1], next[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
+ }
+ }
+ else {
+ /* add if value doesn't equal that of previous */
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
+ }
+ }
+ }
+ }
+
+ /* now free the memory used by the old BezTriples */
+ if (old_bezts)
+ MEM_freeN(old_bezts);
+
+ /* final step, if there is just one key in fcurve, check if it's
+ * the default value and if is, remove fcurve completely. */
+ if (cleardefault && fcu->totvert == 1) {
+ float default_value = 0.0f;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ RNA_id_pointer_create(ale->id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
+ if (RNA_property_type(prop) == PROP_FLOAT)
+ default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
+ }
+
+ if (fcu->bezt->vec[1][1] == default_value) {
+ clear_fcurve_keys(fcu);
+
+ /* check if curve is really unused and if it is, return signal for deletion */
+ if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
+ (fcu->driver == NULL)) {
+ AnimData *adt = ale->adt;
+ ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
+ ale->key_data = NULL;
+ }
+ }
+ }
}
/* ---------------- */
/* temp struct used for smooth_fcurve */
typedef struct tSmooth_Bezt {
- float *h1, *h2, *h3; /* bezt->vec[0,1,2][1] */
- float y1, y2, y3; /* averaged before/new/after y-values */
+ float *h1, *h2, *h3; /* bezt->vec[0,1,2][1] */
+ float y1, y2, y3; /* averaged before/new/after y-values */
} tSmooth_Bezt;
/* Use a weighted moving-means method to reduce intensity of fluctuations */
// TODO: introduce scaling factor for weighting falloff
void smooth_fcurve(FCurve *fcu)
{
- BezTriple *bezt;
- int i, x, totSel = 0;
-
- if (fcu->bezt == NULL) {
- return;
- }
-
- /* first loop through - count how many verts are selected */
- bezt = fcu->bezt;
- for (i = 0; i < fcu->totvert; i++, bezt++) {
- if (BEZT_ISSEL_ANY(bezt))
- totSel++;
- }
-
- /* if any points were selected, allocate tSmooth_Bezt points to work on */
- if (totSel >= 3) {
- tSmooth_Bezt *tarray, *tsb;
-
- /* allocate memory in one go */
- tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
-
- /* populate tarray with data of selected points */
- bezt = fcu->bezt;
- for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
- if (BEZT_ISSEL_ANY(bezt)) {
- /* tsb simply needs pointer to vec, and index */
- tsb->h1 = &bezt->vec[0][1];
- tsb->h2 = &bezt->vec[1][1];
- tsb->h3 = &bezt->vec[2][1];
-
- /* advance to the next tsb to populate */
- if (x < totSel - 1)
- tsb++;
- else
- break;
- }
- }
-
- /* calculate the new smoothed F-Curve's with weighted averages:
- * - this is done with two passes to avoid progressive corruption errors
- * - uses 5 points for each operation (which stores in the relevant handles)
- * - previous: w/a ratio = 3:5:2:1:1
- * - next: w/a ratio = 1:1:2:5:3
- */
-
- /* round 1: calculate smoothing deltas and new values */
- tsb = tarray;
- for (i = 0; i < totSel; i++, tsb++) {
- /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */
- if (ELEM(i, 0, (totSel - 1)) == 0) {
- const tSmooth_Bezt *tP1 = tsb - 1;
- const tSmooth_Bezt *tP2 = (i - 2 > 0) ? (tsb - 2) : (NULL);
- const tSmooth_Bezt *tN1 = tsb + 1;
- const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL);
-
- const float p1 = *tP1->h2;
- const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
- const float c1 = *tsb->h2;
- const float n1 = *tN1->h2;
- const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
-
- /* calculate previous and next, then new position by averaging these */
- tsb->y1 = (3 * p2 + 5 * p1 + 2 * c1 + n1 + n2) / 12;
- tsb->y3 = (p2 + p1 + 2 * c1 + 5 * n1 + 3 * n2) / 12;
-
- tsb->y2 = (tsb->y1 + tsb->y3) / 2;
- }
- }
-
- /* round 2: apply new values */
- tsb = tarray;
- for (i = 0; i < totSel; i++, tsb++) {
- /* don't touch end points, as their values weren't touched above */
- if (ELEM(i, 0, (totSel - 1)) == 0) {
- /* y2 takes the average of the 2 points */
- *tsb->h2 = tsb->y2;
-
- /* handles are weighted between their original values and the averaged values */
- *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f);
- *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f);
- }
- }
-
- /* free memory required for tarray */
- MEM_freeN(tarray);
- }
-
- /* recalculate handles */
- calchandles_fcurve(fcu);
+ BezTriple *bezt;
+ int i, x, totSel = 0;
+
+ if (fcu->bezt == NULL) {
+ return;
+ }
+
+ /* first loop through - count how many verts are selected */
+ bezt = fcu->bezt;
+ for (i = 0; i < fcu->totvert; i++, bezt++) {
+ if (BEZT_ISSEL_ANY(bezt))
+ totSel++;
+ }
+
+ /* if any points were selected, allocate tSmooth_Bezt points to work on */
+ if (totSel >= 3) {
+ tSmooth_Bezt *tarray, *tsb;
+
+ /* allocate memory in one go */
+ tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
+
+ /* populate tarray with data of selected points */
+ bezt = fcu->bezt;
+ for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
+ if (BEZT_ISSEL_ANY(bezt)) {
+ /* tsb simply needs pointer to vec, and index */
+ tsb->h1 = &bezt->vec[0][1];
+ tsb->h2 = &bezt->vec[1][1];
+ tsb->h3 = &bezt->vec[2][1];
+
+ /* advance to the next tsb to populate */
+ if (x < totSel - 1)
+ tsb++;
+ else
+ break;
+ }
+ }
+
+ /* calculate the new smoothed F-Curve's with weighted averages:
+ * - this is done with two passes to avoid progressive corruption errors
+ * - uses 5 points for each operation (which stores in the relevant handles)
+ * - previous: w/a ratio = 3:5:2:1:1
+ * - next: w/a ratio = 1:1:2:5:3
+ */
+
+ /* round 1: calculate smoothing deltas and new values */
+ tsb = tarray;
+ for (i = 0; i < totSel; i++, tsb++) {
+ /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */
+ if (ELEM(i, 0, (totSel - 1)) == 0) {
+ const tSmooth_Bezt *tP1 = tsb - 1;
+ const tSmooth_Bezt *tP2 = (i - 2 > 0) ? (tsb - 2) : (NULL);
+ const tSmooth_Bezt *tN1 = tsb + 1;
+ const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL);
+
+ const float p1 = *tP1->h2;
+ const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
+ const float c1 = *tsb->h2;
+ const float n1 = *tN1->h2;
+ const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
+
+ /* calculate previous and next, then new position by averaging these */
+ tsb->y1 = (3 * p2 + 5 * p1 + 2 * c1 + n1 + n2) / 12;
+ tsb->y3 = (p2 + p1 + 2 * c1 + 5 * n1 + 3 * n2) / 12;
+
+ tsb->y2 = (tsb->y1 + tsb->y3) / 2;
+ }
+ }
+
+ /* round 2: apply new values */
+ tsb = tarray;
+ for (i = 0; i < totSel; i++, tsb++) {
+ /* don't touch end points, as their values weren't touched above */
+ if (ELEM(i, 0, (totSel - 1)) == 0) {
+ /* y2 takes the average of the 2 points */
+ *tsb->h2 = tsb->y2;
+
+ /* handles are weighted between their original values and the averaged values */
+ *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f);
+ *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f);
+ }
+ }
+
+ /* free memory required for tarray */
+ MEM_freeN(tarray);
+ }
+
+ /* recalculate handles */
+ calchandles_fcurve(fcu);
}
/* ---------------- */
/* little cache for values... */
typedef struct TempFrameValCache {
- float frame, val;
+ float frame, val;
} TempFrameValCache;
-
/* Evaluates the curves between each selected keyframe on each frame, and keys the value */
void sample_fcurve(FCurve *fcu)
{
- BezTriple *bezt, *start = NULL, *end = NULL;
- TempFrameValCache *value_cache, *fp;
- int sfra, range;
- int i, n;
-
- if (fcu->bezt == NULL) /* ignore baked */
- return;
-
- /* find selected keyframes... once pair has been found, add keyframes */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- /* check if selected, and which end this is */
- if (BEZT_ISSEL_ANY(bezt)) {
- if (start) {
- /* If next bezt is also selected, don't start sampling yet,
- * but instead wait for that one to reconsider, to avoid
- * changing the curve when sampling consecutive segments
- * (T53229)
- */
- if (i < fcu->totvert - 1) {
- BezTriple *next = &fcu->bezt[i + 1];
- if (BEZT_ISSEL_ANY(next)) {
- continue;
- }
- }
-
- /* set end */
- end = bezt;
-
- /* cache values then add keyframes using these values, as adding
- * keyframes while sampling will affect the outcome...
- * - only start sampling+adding from index=1, so that we don't overwrite original keyframe
- */
- range = (int)(ceil(end->vec[1][0] - start->vec[1][0]));
- sfra = (int)(floor(start->vec[1][0]));
-
- if (range) {
- value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache");
-
- /* sample values */
- for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
- fp->frame = (float)(sfra + n);
- fp->val = evaluate_fcurve(fcu, fp->frame);
- }
-
- /* add keyframes with these, tagging as 'breakdowns' */
- for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
- insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1);
- }
-
- /* free temp cache */
- MEM_freeN(value_cache);
-
- /* as we added keyframes, we need to compensate so that bezt is at the right place */
- bezt = fcu->bezt + i + range - 1;
- i += (range - 1);
- }
-
- /* the current selection island has ended, so start again from scratch */
- start = NULL;
- end = NULL;
- }
- else {
- /* just set start keyframe */
- start = bezt;
- end = NULL;
- }
- }
- }
-
- /* recalculate channel's handles? */
- calchandles_fcurve(fcu);
+ BezTriple *bezt, *start = NULL, *end = NULL;
+ TempFrameValCache *value_cache, *fp;
+ int sfra, range;
+ int i, n;
+
+ if (fcu->bezt == NULL) /* ignore baked */
+ return;
+
+ /* find selected keyframes... once pair has been found, add keyframes */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ /* check if selected, and which end this is */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ if (start) {
+ /* If next bezt is also selected, don't start sampling yet,
+ * but instead wait for that one to reconsider, to avoid
+ * changing the curve when sampling consecutive segments
+ * (T53229)
+ */
+ if (i < fcu->totvert - 1) {
+ BezTriple *next = &fcu->bezt[i + 1];
+ if (BEZT_ISSEL_ANY(next)) {
+ continue;
+ }
+ }
+
+ /* set end */
+ end = bezt;
+
+ /* cache values then add keyframes using these values, as adding
+ * keyframes while sampling will affect the outcome...
+ * - only start sampling+adding from index=1, so that we don't overwrite original keyframe
+ */
+ range = (int)(ceil(end->vec[1][0] - start->vec[1][0]));
+ sfra = (int)(floor(start->vec[1][0]));
+
+ if (range) {
+ value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache");
+
+ /* sample values */
+ for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
+ fp->frame = (float)(sfra + n);
+ fp->val = evaluate_fcurve(fcu, fp->frame);
+ }
+
+ /* add keyframes with these, tagging as 'breakdowns' */
+ for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
+ insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1);
+ }
+
+ /* free temp cache */
+ MEM_freeN(value_cache);
+
+ /* as we added keyframes, we need to compensate so that bezt is at the right place */
+ bezt = fcu->bezt + i + range - 1;
+ i += (range - 1);
+ }
+
+ /* the current selection island has ended, so start again from scratch */
+ start = NULL;
+ end = NULL;
+ }
+ else {
+ /* just set start keyframe */
+ start = bezt;
+ end = NULL;
+ }
+ }
+ }
+
+ /* recalculate channel's handles? */
+ calchandles_fcurve(fcu);
}
/* **************************************************** */
@@ -520,46 +516,45 @@ static float animcopy_cfra = 0.0;
/* datatype for use in copy/paste buffer */
typedef struct tAnimCopybufItem {
- struct tAnimCopybufItem *next, *prev;
+ struct tAnimCopybufItem *next, *prev;
- ID *id; /* ID which owns the curve */
- bActionGroup *grp; /* Action Group */
- char *rna_path; /* RNA-Path */
- int array_index; /* array index */
+ ID *id; /* ID which owns the curve */
+ bActionGroup *grp; /* Action Group */
+ char *rna_path; /* RNA-Path */
+ int array_index; /* array index */
- int totvert; /* number of keyframes stored for this channel */
- BezTriple *bezt; /* keyframes in buffer */
+ int totvert; /* number of keyframes stored for this channel */
+ BezTriple *bezt; /* keyframes in buffer */
- short id_type; /* Result of GS(id->name)*/
- bool is_bone; /* special flag for armature bones */
+ short id_type; /* Result of GS(id->name)*/
+ bool is_bone; /* special flag for armature bones */
} tAnimCopybufItem;
-
/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_fcurves_copybuf_free(void)
{
- tAnimCopybufItem *aci, *acn;
+ tAnimCopybufItem *aci, *acn;
- /* free each buffer element */
- for (aci = animcopybuf.first; aci; aci = acn) {
- acn = aci->next;
+ /* free each buffer element */
+ for (aci = animcopybuf.first; aci; aci = acn) {
+ acn = aci->next;
- /* free keyframes */
- if (aci->bezt)
- MEM_freeN(aci->bezt);
+ /* free keyframes */
+ if (aci->bezt)
+ MEM_freeN(aci->bezt);
- /* free RNA-path */
- if (aci->rna_path)
- MEM_freeN(aci->rna_path);
+ /* free RNA-path */
+ if (aci->rna_path)
+ MEM_freeN(aci->rna_path);
- /* free ourself */
- BLI_freelinkN(&animcopybuf, aci);
- }
+ /* free ourself */
+ BLI_freelinkN(&animcopybuf, aci);
+ }
- /* restore initial state */
- BLI_listbase_clear(&animcopybuf);
- animcopy_firstframe = 999999999.0f;
- animcopy_lastframe = -999999999.0f;
+ /* restore initial state */
+ BLI_listbase_clear(&animcopybuf);
+ animcopy_firstframe = 999999999.0f;
+ animcopy_lastframe = -999999999.0f;
}
/* ------------------- */
@@ -567,468 +562,501 @@ void ANIM_fcurves_copybuf_free(void)
/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
{
- bAnimListElem *ale;
- Scene *scene = ac->scene;
-
- /* clear buffer first */
- ANIM_fcurves_copybuf_free();
-
- /* assume that each of these is an F-Curve */
- for (ale = anim_data->first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
- tAnimCopybufItem *aci;
- BezTriple *bezt, *nbezt, *newbuf;
- int i;
-
- /* firstly, check if F-Curve has any selected keyframes
- * - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
- * - this check should also eliminate any problems associated with using sample-data
- */
- if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
- continue;
-
- /* init copybuf item info */
- aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
- aci->id = ale->id;
- aci->id_type = GS(ale->id->name);
- aci->grp = fcu->grp;
- aci->rna_path = MEM_dupallocN(fcu->rna_path);
- aci->array_index = fcu->array_index;
-
- /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo.
- * storing the relevant information here helps avoiding crashes if we undo-repaste */
- if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
- Object *ob = (Object *)aci->id;
- bPoseChannel *pchan;
- char *bone_name;
-
- bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
- pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- if (pchan) {
- aci->is_bone = true;
- }
- if (bone_name) MEM_freeN(bone_name);
- }
-
- BLI_addtail(&animcopybuf, aci);
-
- /* add selected keyframes to buffer */
- /* TODO: currently, we resize array every time we add a new vert -
- * this works ok as long as it is assumed only a few keys are copied */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (BEZT_ISSEL_ANY(bezt)) {
- /* add to buffer */
- newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
-
- /* assume that since we are just re-sizing the array, just copy all existing data across */
- if (aci->bezt)
- memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert));
-
- /* copy current beztriple across too */
- nbezt = &newbuf[aci->totvert];
- *nbezt = *bezt;
-
- /* ensure copy buffer is selected so pasted keys are selected */
- BEZT_SEL_ALL(nbezt);
-
- /* free old array and set the new */
- if (aci->bezt) MEM_freeN(aci->bezt);
- aci->bezt = newbuf;
- aci->totvert++;
-
- /* check if this is the earliest frame encountered so far */
- if (bezt->vec[1][0] < animcopy_firstframe)
- animcopy_firstframe = bezt->vec[1][0];
- if (bezt->vec[1][0] > animcopy_lastframe)
- animcopy_lastframe = bezt->vec[1][0];
- }
- }
-
- }
-
- /* check if anything ended up in the buffer */
- if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
- return -1;
-
- /* in case 'relative' paste method is used */
- animcopy_cfra = CFRA;
-
- /* everything went fine */
- return 0;
+ bAnimListElem *ale;
+ Scene *scene = ac->scene;
+
+ /* clear buffer first */
+ ANIM_fcurves_copybuf_free();
+
+ /* assume that each of these is an F-Curve */
+ for (ale = anim_data->first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ tAnimCopybufItem *aci;
+ BezTriple *bezt, *nbezt, *newbuf;
+ int i;
+
+ /* firstly, check if F-Curve has any selected keyframes
+ * - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
+ * - this check should also eliminate any problems associated with using sample-data
+ */
+ if (ANIM_fcurve_keyframes_loop(
+ NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
+ continue;
+
+ /* init copybuf item info */
+ aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
+ aci->id = ale->id;
+ aci->id_type = GS(ale->id->name);
+ aci->grp = fcu->grp;
+ aci->rna_path = MEM_dupallocN(fcu->rna_path);
+ aci->array_index = fcu->array_index;
+
+ /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo.
+ * storing the relevant information here helps avoiding crashes if we undo-repaste */
+ if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
+ Object *ob = (Object *)aci->id;
+ bPoseChannel *pchan;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan) {
+ aci->is_bone = true;
+ }
+ if (bone_name)
+ MEM_freeN(bone_name);
+ }
+
+ BLI_addtail(&animcopybuf, aci);
+
+ /* add selected keyframes to buffer */
+ /* TODO: currently, we resize array every time we add a new vert -
+ * this works ok as long as it is assumed only a few keys are copied */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (BEZT_ISSEL_ANY(bezt)) {
+ /* add to buffer */
+ newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
+
+ /* assume that since we are just re-sizing the array, just copy all existing data across */
+ if (aci->bezt)
+ memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert));
+
+ /* copy current beztriple across too */
+ nbezt = &newbuf[aci->totvert];
+ *nbezt = *bezt;
+
+ /* ensure copy buffer is selected so pasted keys are selected */
+ BEZT_SEL_ALL(nbezt);
+
+ /* free old array and set the new */
+ if (aci->bezt)
+ MEM_freeN(aci->bezt);
+ aci->bezt = newbuf;
+ aci->totvert++;
+
+ /* check if this is the earliest frame encountered so far */
+ if (bezt->vec[1][0] < animcopy_firstframe)
+ animcopy_firstframe = bezt->vec[1][0];
+ if (bezt->vec[1][0] > animcopy_lastframe)
+ animcopy_lastframe = bezt->vec[1][0];
+ }
+ }
+ }
+
+ /* check if anything ended up in the buffer */
+ if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
+ return -1;
+
+ /* in case 'relative' paste method is used */
+ animcopy_cfra = CFRA;
+
+ /* everything went fine */
+ return 0;
}
static void flip_names(tAnimCopybufItem *aci, char **name)
{
- if (aci->is_bone) {
- char *str_start;
- if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
- /* ninja coding, try to change the name */
- char bname_new[MAX_VGROUP_NAME];
- char *str_iter, *str_end;
- int length, prefix_l, postfix_l;
-
- str_start += 12;
- prefix_l = str_start - aci->rna_path;
-
- str_end = strchr(str_start, '\"');
-
- length = str_end - str_start;
- postfix_l = strlen(str_end);
-
- /* more ninja stuff, temporary substitute with NULL terminator */
- str_start[length] = 0;
- BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
- str_start[length] = '\"';
-
- str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
-
- BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
- str_iter += prefix_l;
- BLI_strncpy(str_iter, bname_new, length + 1);
- str_iter += length;
- BLI_strncpy(str_iter, str_end, postfix_l + 1);
- str_iter[postfix_l] = '\0';
- }
- }
+ if (aci->is_bone) {
+ char *str_start;
+ if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
+ /* ninja coding, try to change the name */
+ char bname_new[MAX_VGROUP_NAME];
+ char *str_iter, *str_end;
+ int length, prefix_l, postfix_l;
+
+ str_start += 12;
+ prefix_l = str_start - aci->rna_path;
+
+ str_end = strchr(str_start, '\"');
+
+ length = str_end - str_start;
+ postfix_l = strlen(str_end);
+
+ /* more ninja stuff, temporary substitute with NULL terminator */
+ str_start[length] = 0;
+ BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
+ str_start[length] = '\"';
+
+ str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1),
+ "flipped_path");
+
+ BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
+ str_iter += prefix_l;
+ BLI_strncpy(str_iter, bname_new, length + 1);
+ str_iter += length;
+ BLI_strncpy(str_iter, str_end, postfix_l + 1);
+ str_iter[postfix_l] = '\0';
+ }
+ }
}
/* ------------------- */
/* most strict method: exact matches only */
-static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple, bool flip)
+static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu,
+ const short from_single,
+ const short to_simple,
+ bool flip)
{
- tAnimCopybufItem *aci;
-
- for (aci = animcopybuf.first; aci; aci = aci->next) {
- if (to_simple || (aci->rna_path && fcu->rna_path)) {
- if (!to_simple && flip && aci->is_bone && fcu->rna_path) {
- if ((from_single) || (aci->array_index == fcu->array_index)) {
- char *name = NULL;
- flip_names(aci, &name);
- if (STREQ(name, fcu->rna_path)) {
- MEM_freeN(name);
- break;
- }
- MEM_freeN(name);
- }
- }
- else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) {
- if ((from_single) || (aci->array_index == fcu->array_index)) {
- break;
- }
- }
- }
- }
-
- return aci;
+ tAnimCopybufItem *aci;
+
+ for (aci = animcopybuf.first; aci; aci = aci->next) {
+ if (to_simple || (aci->rna_path && fcu->rna_path)) {
+ if (!to_simple && flip && aci->is_bone && fcu->rna_path) {
+ if ((from_single) || (aci->array_index == fcu->array_index)) {
+ char *name = NULL;
+ flip_names(aci, &name);
+ if (STREQ(name, fcu->rna_path)) {
+ MEM_freeN(name);
+ break;
+ }
+ MEM_freeN(name);
+ }
+ }
+ else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) {
+ if ((from_single) || (aci->array_index == fcu->array_index)) {
+ break;
+ }
+ }
+ }
+ }
+
+ return aci;
}
/* medium match strictness: path match only (i.e. ignore ID) */
-static tAnimCopybufItem *pastebuf_match_path_property(
- Main *bmain, FCurve *fcu, const short from_single, const short UNUSED(to_simple))
+static tAnimCopybufItem *pastebuf_match_path_property(Main *bmain,
+ FCurve *fcu,
+ const short from_single,
+ const short UNUSED(to_simple))
{
- tAnimCopybufItem *aci;
-
- for (aci = animcopybuf.first; aci; aci = aci->next) {
- /* check that paths exist */
- if (aci->rna_path && fcu->rna_path) {
- /* find the property of the fcurve and compare against the end of the tAnimCopybufItem
- * more involved since it needs to do path lookups.
- * This is not 100% reliable since the user could be editing the curves on a path that wont
- * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
- * this should work out ok.
- */
- if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) {
- /* pedantic but the ID could have been removed, and beats crashing! */
- printf("paste_animedit_keys: error ID has been removed!\n");
- }
- else {
- PointerRNA id_ptr, rptr;
- PropertyRNA *prop;
-
- RNA_id_pointer_create(aci->id, &id_ptr);
-
- if (RNA_path_resolve_property(&id_ptr, aci->rna_path, &rptr, &prop)) {
- const char *identifier = RNA_property_identifier(prop);
- int len_id = strlen(identifier);
- int len_path = strlen(fcu->rna_path);
- if (len_id <= len_path) {
- /* note, paths which end with "] will fail with this test - Animated ID Props */
- if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) {
- if ((from_single) || (aci->array_index == fcu->array_index))
- break;
- }
- }
- }
- else {
- printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path);
- }
- }
- }
- }
-
- return aci;
+ tAnimCopybufItem *aci;
+
+ for (aci = animcopybuf.first; aci; aci = aci->next) {
+ /* check that paths exist */
+ if (aci->rna_path && fcu->rna_path) {
+ /* find the property of the fcurve and compare against the end of the tAnimCopybufItem
+ * more involved since it needs to do path lookups.
+ * This is not 100% reliable since the user could be editing the curves on a path that wont
+ * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
+ * this should work out ok.
+ */
+ if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) {
+ /* pedantic but the ID could have been removed, and beats crashing! */
+ printf("paste_animedit_keys: error ID has been removed!\n");
+ }
+ else {
+ PointerRNA id_ptr, rptr;
+ PropertyRNA *prop;
+
+ RNA_id_pointer_create(aci->id, &id_ptr);
+
+ if (RNA_path_resolve_property(&id_ptr, aci->rna_path, &rptr, &prop)) {
+ const char *identifier = RNA_property_identifier(prop);
+ int len_id = strlen(identifier);
+ int len_path = strlen(fcu->rna_path);
+ if (len_id <= len_path) {
+ /* note, paths which end with "] will fail with this test - Animated ID Props */
+ if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) {
+ if ((from_single) || (aci->array_index == fcu->array_index))
+ break;
+ }
+ }
+ }
+ else {
+ printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n",
+ aci->id->name,
+ aci->rna_path);
+ }
+ }
+ }
+ }
+
+ return aci;
}
/* least strict matching heuristic: indices only */
-static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
+static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu,
+ const short from_single,
+ const short UNUSED(to_simple))
{
- tAnimCopybufItem *aci;
+ tAnimCopybufItem *aci;
- for (aci = animcopybuf.first; aci; aci = aci->next) {
- /* check that paths exist */
- if ((from_single) || (aci->array_index == fcu->array_index)) {
- break;
- }
- }
+ for (aci = animcopybuf.first; aci; aci = aci->next) {
+ /* check that paths exist */
+ if ((from_single) || (aci->array_index == fcu->array_index)) {
+ break;
+ }
+ }
- return aci;
+ return aci;
}
/* ................ */
static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt)
{
- if (aci->is_bone) {
- const size_t slength = strlen(aci->rna_path);
- bool flip = false;
- if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0)
- flip = true;
- else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) && ELEM(aci->array_index, 2, 3))
- flip = true;
- else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) && ELEM(aci->array_index, 1, 2))
- flip = true;
- else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) && ELEM(aci->array_index, 2, 3))
- flip = true;
-
- if (flip) {
- bezt->vec[0][1] = -bezt->vec[0][1];
- bezt->vec[1][1] = -bezt->vec[1][1];
- bezt->vec[2][1] = -bezt->vec[2][1];
- }
- }
+ if (aci->is_bone) {
+ const size_t slength = strlen(aci->rna_path);
+ bool flip = false;
+ if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0)
+ flip = true;
+ else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) &&
+ ELEM(aci->array_index, 2, 3))
+ flip = true;
+ else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) &&
+ ELEM(aci->array_index, 1, 2))
+ flip = true;
+ else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) &&
+ ELEM(aci->array_index, 2, 3))
+ flip = true;
+
+ if (flip) {
+ bezt->vec[0][1] = -bezt->vec[0][1];
+ bezt->vec[1][1] = -bezt->vec[1][1];
+ bezt->vec[2][1] = -bezt->vec[2][1];
+ }
+ }
}
/* helper for paste_animedit_keys() - performs the actual pasting */
-static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
+static void paste_animedit_keys_fcurve(
+ FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
{
- BezTriple *bezt;
- int i;
-
- /* First de-select existing FCurve's keyframes */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- BEZT_DESEL_ALL(bezt);
- }
-
- /* mix mode with existing data */
- switch (merge_mode) {
- case KEYFRAME_PASTE_MERGE_MIX:
- /* do-nothing */
- break;
-
- case KEYFRAME_PASTE_MERGE_OVER:
- /* remove all keys */
- clear_fcurve_keys(fcu);
- break;
-
- case KEYFRAME_PASTE_MERGE_OVER_RANGE:
- case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL:
- {
- float f_min;
- float f_max;
-
- if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) {
- f_min = aci->bezt[0].vec[1][0] + offset;
- f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset;
- }
- else { /* Entire Range */
- f_min = animcopy_firstframe + offset;
- f_max = animcopy_lastframe + offset;
- }
-
- /* remove keys in range */
- if (f_min < f_max) {
- /* select verts in range for removal */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
- bezt->f2 |= SELECT;
- }
- }
-
- /* remove frames in the range */
- delete_fcurve_keys(fcu);
- }
- break;
- }
- }
-
- /* just start pasting, with the first keyframe on the current frame, and so on */
- for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) {
- /* temporarily apply offset to src beztriple while copying */
- if (flip)
- do_curve_mirror_flippping(aci, bezt);
-
- bezt->vec[0][0] += offset;
- bezt->vec[1][0] += offset;
- bezt->vec[2][0] += offset;
-
- /* insert the keyframe
- * NOTE: we do not want to inherit handles from existing keyframes in this case!
- */
-
- insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
-
- /* un-apply offset from src beztriple after copying */
- bezt->vec[0][0] -= offset;
- bezt->vec[1][0] -= offset;
- bezt->vec[2][0] -= offset;
-
- if (flip)
- do_curve_mirror_flippping(aci, bezt);
- }
-
- /* recalculate F-Curve's handles? */
- calchandles_fcurve(fcu);
+ BezTriple *bezt;
+ int i;
+
+ /* First de-select existing FCurve's keyframes */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ BEZT_DESEL_ALL(bezt);
+ }
+
+ /* mix mode with existing data */
+ switch (merge_mode) {
+ case KEYFRAME_PASTE_MERGE_MIX:
+ /* do-nothing */
+ break;
+
+ case KEYFRAME_PASTE_MERGE_OVER:
+ /* remove all keys */
+ clear_fcurve_keys(fcu);
+ break;
+
+ case KEYFRAME_PASTE_MERGE_OVER_RANGE:
+ case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL: {
+ float f_min;
+ float f_max;
+
+ if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) {
+ f_min = aci->bezt[0].vec[1][0] + offset;
+ f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset;
+ }
+ else { /* Entire Range */
+ f_min = animcopy_firstframe + offset;
+ f_max = animcopy_lastframe + offset;
+ }
+
+ /* remove keys in range */
+ if (f_min < f_max) {
+ /* select verts in range for removal */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
+ bezt->f2 |= SELECT;
+ }
+ }
+
+ /* remove frames in the range */
+ delete_fcurve_keys(fcu);
+ }
+ break;
+ }
+ }
+
+ /* just start pasting, with the first keyframe on the current frame, and so on */
+ for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) {
+ /* temporarily apply offset to src beztriple while copying */
+ if (flip)
+ do_curve_mirror_flippping(aci, bezt);
+
+ bezt->vec[0][0] += offset;
+ bezt->vec[1][0] += offset;
+ bezt->vec[2][0] += offset;
+
+ /* insert the keyframe
+ * NOTE: we do not want to inherit handles from existing keyframes in this case!
+ */
+
+ insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
+
+ /* un-apply offset from src beztriple after copying */
+ bezt->vec[0][0] -= offset;
+ bezt->vec[1][0] -= offset;
+ bezt->vec[2][0] -= offset;
+
+ if (flip)
+ do_curve_mirror_flippping(aci, bezt);
+ }
+
+ /* recalculate F-Curve's handles? */
+ calchandles_fcurve(fcu);
}
/* ------------------- */
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
- {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"},
- {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
- {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"},
- {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
- {0, NULL, 0, NULL, NULL},
+ {KEYFRAME_PASTE_OFFSET_CFRA_START,
+ "START",
+ 0,
+ "Frame Start",
+ "Paste keys starting at current frame"},
+ {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
+ {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE,
+ "RELATIVE",
+ 0,
+ "Frame Relative",
+ "Paste keys relative to the current frame when copying"},
+ {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
+ {0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
- {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
- {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
- {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"},
- {KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL, "OVER_RANGE_ALL", 0, "Overwrite Entire Range", "Overwrite keys in pasted range, using the range of all copied keys"},
- {0, NULL, 0, NULL, NULL},
+ {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
+ {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
+ {KEYFRAME_PASTE_MERGE_OVER_RANGE,
+ "OVER_RANGE",
+ 0,
+ "Overwrite Range",
+ "Overwrite keys in pasted range"},
+ {KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL,
+ "OVER_RANGE_ALL",
+ 0,
+ "Overwrite Entire Range",
+ "Overwrite keys in pasted range, using the range of all copied keys"},
+ {0, NULL, 0, NULL, NULL},
};
-
/**
* This function pastes data from the keyframes copy/paste buffer
*
* \return Status code is whether the method FAILED to do anything
*/
-short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
- const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
+short paste_animedit_keys(bAnimContext *ac,
+ ListBase *anim_data,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
- bAnimListElem *ale;
-
- const Scene *scene = (ac->scene);
-
- const bool from_single = BLI_listbase_is_single(&animcopybuf);
- const bool to_simple = BLI_listbase_is_single(anim_data);
-
- float offset = 0.0f;
- int pass;
-
- /* check if buffer is empty */
- if (BLI_listbase_is_empty(&animcopybuf)) {
- BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
- return -1;
- }
-
- if (BLI_listbase_is_empty(anim_data)) {
- BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
- return -1;
- }
-
- /* methods of offset */
- switch (offset_mode) {
- case KEYFRAME_PASTE_OFFSET_CFRA_START:
- offset = (float)(CFRA - animcopy_firstframe);
- break;
- case KEYFRAME_PASTE_OFFSET_CFRA_END:
- offset = (float)(CFRA - animcopy_lastframe);
- break;
- case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
- offset = (float)(CFRA - animcopy_cfra);
- break;
- case KEYFRAME_PASTE_OFFSET_NONE:
- offset = 0.0f;
- break;
- }
-
- if (from_single && to_simple) {
- /* 1:1 match, no tricky checking, just paste */
- FCurve *fcu;
- tAnimCopybufItem *aci;
-
- ale = anim_data->first;
- fcu = (FCurve *)ale->data; /* destination F-Curve */
- aci = animcopybuf.first;
-
- paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
- ale->update |= ANIM_UPDATE_DEFAULT;
- }
- else {
- /* from selected channels
- * This "passes" system aims to try to find "matching" channels to paste keyframes
- * into with increasingly loose matching heuristics. The process finishes when at least
- * one F-Curve has been pasted into.
- */
- for (pass = 0; pass < 3; pass++) {
- unsigned int totmatch = 0;
-
- for (ale = anim_data->first; ale; ale = ale->next) {
- /* find buffer item to paste from
- * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group
- * - if names do matter, only check if id-type is ok for now (group check is not that important)
- * - most importantly, rna-paths should match (array indices are unimportant for now)
- */
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */
- tAnimCopybufItem *aci = NULL;
-
- switch (pass) {
- case 0:
- /* most strict, must be exact path match data_path & index */
- aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip);
- break;
-
- case 1:
- /* less strict, just compare property names */
- aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple);
- break;
-
- case 2:
- /* Comparing properties gave no results, so just do index comparisons */
- aci = pastebuf_match_index_only(fcu, from_single, to_simple);
- break;
- }
-
- /* copy the relevant data from the matching buffer curve */
- if (aci) {
- totmatch++;
-
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
- }
- else {
- paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
- }
- }
-
- ale->update |= ANIM_UPDATE_DEFAULT;
- }
-
- /* don't continue if some fcurves were pasted */
- if (totmatch)
- break;
- }
- }
-
- ANIM_animdata_update(ac, anim_data);
-
- return 0;
+ bAnimListElem *ale;
+
+ const Scene *scene = (ac->scene);
+
+ const bool from_single = BLI_listbase_is_single(&animcopybuf);
+ const bool to_simple = BLI_listbase_is_single(anim_data);
+
+ float offset = 0.0f;
+ int pass;
+
+ /* check if buffer is empty */
+ if (BLI_listbase_is_empty(&animcopybuf)) {
+ BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
+ return -1;
+ }
+
+ if (BLI_listbase_is_empty(anim_data)) {
+ BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
+ return -1;
+ }
+
+ /* methods of offset */
+ switch (offset_mode) {
+ case KEYFRAME_PASTE_OFFSET_CFRA_START:
+ offset = (float)(CFRA - animcopy_firstframe);
+ break;
+ case KEYFRAME_PASTE_OFFSET_CFRA_END:
+ offset = (float)(CFRA - animcopy_lastframe);
+ break;
+ case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
+ offset = (float)(CFRA - animcopy_cfra);
+ break;
+ case KEYFRAME_PASTE_OFFSET_NONE:
+ offset = 0.0f;
+ break;
+ }
+
+ if (from_single && to_simple) {
+ /* 1:1 match, no tricky checking, just paste */
+ FCurve *fcu;
+ tAnimCopybufItem *aci;
+
+ ale = anim_data->first;
+ fcu = (FCurve *)ale->data; /* destination F-Curve */
+ aci = animcopybuf.first;
+
+ paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+ else {
+ /* from selected channels
+ * This "passes" system aims to try to find "matching" channels to paste keyframes
+ * into with increasingly loose matching heuristics. The process finishes when at least
+ * one F-Curve has been pasted into.
+ */
+ for (pass = 0; pass < 3; pass++) {
+ unsigned int totmatch = 0;
+
+ for (ale = anim_data->first; ale; ale = ale->next) {
+ /* find buffer item to paste from
+ * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group
+ * - if names do matter, only check if id-type is ok for now (group check is not that important)
+ * - most importantly, rna-paths should match (array indices are unimportant for now)
+ */
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */
+ tAnimCopybufItem *aci = NULL;
+
+ switch (pass) {
+ case 0:
+ /* most strict, must be exact path match data_path & index */
+ aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip);
+ break;
+
+ case 1:
+ /* less strict, just compare property names */
+ aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple);
+ break;
+
+ case 2:
+ /* Comparing properties gave no results, so just do index comparisons */
+ aci = pastebuf_match_index_only(fcu, from_single, to_simple);
+ break;
+ }
+
+ /* copy the relevant data from the matching buffer curve */
+ if (aci) {
+ totmatch++;
+
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
+ paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
+ }
+ else {
+ paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
+ }
+ }
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ /* don't continue if some fcurves were pasted */
+ if (totmatch)
+ break;
+ }
+ }
+
+ ANIM_animdata_update(ac, anim_data);
+
+ return 0;
}
/* **************************************************** */