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/transform/transform_conversions.c')
-rw-r--r--source/blender/editors/transform/transform_conversions.c136
1 files changed, 96 insertions, 40 deletions
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 96970fa8a0f..9c3ed801381 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -3497,67 +3497,123 @@ static void posttrans_mask_clean(Mask *mask)
}
}
+/* Time + Average value */
+typedef struct tRetainedKeyframe {
+ struct tRetainedKeyframe *next, *prev;
+ float frame; /* frame to cluster around */
+ float val; /* average value */
+
+ size_t tot_count; /* number of keyframes that have been averaged */
+ size_t del_count; /* number of keyframes of this sort that have been deleted so far */
+} tRetainedKeyframe;
+
/* Called during special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
*/
static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
{
- float *selcache; /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */
- int len, index, i; /* number of frames in cache, item index */
-
- /* allocate memory for the cache */
- // TODO: investigate using BezTriple columns instead?
- if (fcu->totvert == 0 || fcu->bezt == NULL)
+ /* NOTE: We assume that all keys are sorted */
+ ListBase retained_keys = {NULL, NULL};
+ const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) == 0);
+
+ /* sanity checks */
+ if ((fcu->totvert == 0) || (fcu->bezt == NULL))
return;
- selcache = MEM_callocN(sizeof(float) * fcu->totvert, "FCurveSelFrameNums");
- len = 0;
- index = 0;
-
- /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting
- * as there is no guarantee what order the keyframes are exactly, even though
- * they have been sorted by time.
+
+ /* 1) Identify selected keyframes, and average the values on those
+ * in case there are collisions due to multiple keys getting scaled
+ * to all end up on the same frame
*/
-
- /* Loop 1: find selected keyframes */
- for (i = 0; i < fcu->totvert; i++) {
+ for (int i = 0; i < fcu->totvert; i++) {
BezTriple *bezt = &fcu->bezt[i];
if (BEZT_ISSEL_ANY(bezt)) {
- selcache[index] = bezt->vec[1][0];
- index++;
- len++;
+ bool found = false;
+
+ /* If there's another selected frame here, merge it */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
+ rk->val += bezt->vec[1][1];
+ rk->tot_count++;
+
+ found = true;
+ break;
+ }
+ else if (rk->frame < bezt->vec[1][0]) {
+ /* Terminate early if have passed the supposed insertion point? */
+ break;
+ }
+ }
+
+ /* If nothing found yet, create a new one */
+ if (found == false) {
+ tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe");
+
+ rk->frame = bezt->vec[1][0];
+ rk->val = bezt->vec[1][1];
+ rk->tot_count = 1;
+
+ BLI_addtail(&retained_keys, rk);
+ }
}
}
-
- /* Loop 2: delete unselected keyframes on the same frames
- * (if any keyframes were found, or the whole curve wasn't affected)
+
+ if (BLI_listbase_is_empty(&retained_keys)) {
+ /* This may happen if none of the points were selected... */
+ if (G.debug & G_DEBUG) {
+ printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
+ }
+ return;
+ }
+ else {
+ /* Compute the average values for each retained keyframe */
+ for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ rk->val = rk->val / (float)rk->tot_count;
+ }
+ }
+
+ /* 2) Delete all keyframes duplicating the "retained keys" found above
+ * - Most of these will be unselected keyframes
+ * - Some will be selected keyframes though. For those, we only keep the last one
+ * (or else everything is gone), and replace its value with the averaged value.
*/
- if ((len) && (len != fcu->totvert)) {
- for (i = fcu->totvert - 1; i >= 0; i--) {
- BezTriple *bezt = &fcu->bezt[i];
-
- if (BEZT_ISSEL_ANY(bezt) == 0) {
- /* check beztriple should be removed according to cache */
- for (index = 0; index < len; index++) {
- if (IS_EQF(bezt->vec[1][0], selcache[index])) {
- delete_fcurve_key(fcu, i, 0);
- break;
+ for (int i = fcu->totvert - 1; i >= 0; i--) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ /* Is this a candidate for deletion? */
+ /* TODO: Replace loop with an O(1) lookup instead */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
+ /* Delete this keyframe, unless it's the last selected one on this frame,
+ * in which case, we'll update its value instead
+ */
+ if (BEZT_ISSEL_ANY(bezt) && (rk->del_count == rk->tot_count - 1)) {
+ /* Update keyframe */
+ if (can_average_points) {
+ /* TODO: update handles too? */
+ bezt->vec[1][1] = rk->val;
}
- else if (bezt->vec[1][0] < selcache[index])
- break;
}
+ else {
+ /* Delete keyframe */
+ delete_fcurve_key(fcu, i, 0);
+ }
+
+ /* Stop searching for matching RK's */
+ rk->del_count++;
+ break;
}
}
-
- testhandles_fcurve(fcu, use_handle);
}
-
- /* free cache */
- MEM_freeN(selcache);
+
+ /* 3) Recalculate handles */
+ testhandles_fcurve(fcu, use_handle);
+
+ /* cleanup */
+ BLI_freelistN(&retained_keys);
}
-
/* Called by special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
* remake_action_ipos should have already been called