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.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 34cc143f3a9..7b18ee09df8 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -3512,11 +3512,130 @@ 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)
{
+ /* NOTE: We assume that all keys are sorted */
+ ListBase retained_keys = {NULL, NULL};
+ tRetainedKeyframe *last_rk = NULL;
+
+ /* sanity checks */
+ if ((fcu->totvert == 0) || (fcu->bezt == NULL))
+ return;
+ printf("cleaning fcurve = '%s' (%p)\n", fcu->rna_path, fcu);
+
+ /* 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
+ */
+ for (int i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ if (BEZT_ISSEL_ANY(bezt)) {
+ 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->val) / ((float)rk->tot_count);
+ rk->tot_count++;
+
+ found = true;
+ break;
+ }
+ else if (rk->frame < bezt->vec[1][0]) {
+ /* XXX: terminate early if have passed the supposed insertion point? */
+ printf(" %f: rk %f (@ %p) is earlier (last = %p)\n", bezt->vec[1][0], rk->frame, rk, retained_keys.last);
+ }
+ }
+
+ /* 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);
+ }
+ }
+ }
+
+ if (BLI_listbase_is_empty(&retained_keys)) {
+ /* This may happen if none of the points were selected... */
+ printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
+ return;
+ }
+ else {
+ // XXX: Debug - Print out all the retained keys so we can check if they're in order!
+ int rk_index = 0;
+ for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ printf(" %d: f = %f, v = %f (n = %d)\n", rk_index, rk->frame, rk->val, rk->tot_count);
+ rk_index++;
+ }
+
+ /* "last_rk" is the last one we need to search (assuming everything is sorted) */
+ last_rk = retained_keys.last;
+ }
+
+ /* 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.
+ */
+ 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
+ // TODO: update last_rk on each deletion
+ for (tRetainedKeyframe *rk = last_rk; 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 */
+ // XXX: update handles too...
+ bezt->vec[1][1] = rk->val;
+
+ /* Adjust last_rk, since we don't need to use this one anymore */
+ last_rk = rk->prev;
+ }
+ else {
+ /* Delete keyframe */
+ delete_fcurve_key(fcu, i, 0);
+ }
+
+ /* Stop searching for matching RK's */
+ rk->del_count++;
+ break;
+ }
+ else if (rk->frame < bezt->vec[1][0]) {
+ /* Terminate search early - There shouldn't be anything */
+ }
+ }
+ }
+
+ /* cleanup */
+ BLI_freelistN(&retained_keys);
+}
+
+static void UNUSED_FUNCTION(posttrans_fcurve_clean__OLD)(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 */