[Bf-blender-cvs] [0d814a2e491] smooth-fcurves: Make auto handle placement aware of cyclic extrapolation.

Alexander Gavrilov noreply at git.blender.org
Sun Aug 20 16:10:25 CEST 2017


Commit: 0d814a2e49197d50c1945ab994928a06b7bc3b78
Author: Alexander Gavrilov
Date:   Sat Aug 19 11:32:37 2017 +0300
Branches: smooth-fcurves
https://developer.blender.org/rB0d814a2e49197d50c1945ab994928a06b7bc3b78

Make auto handle placement aware of cyclic extrapolation.

Cyclic extrapolation is implemented as an f-curve modifier, so this
technically violates abstraction separation and is something of a hack.
However without such behavior achieving smooth looping with cyclic
extrapolation is extremely cumbersome.

The new behavior is applied when the first modifier is Cyclic
extrapolation in Repeat or Repeat with Offset mode without
using influence, repeat count or range restrictions.

This change in behavior means that curve handles have to be updated
when the modifier is added, removed or its options change. Due to the
way code is structured, it seems it requires a helper link to the
containing curve from the modifier object.

Reviewers: aligorith

Differential Revision: https://developer.blender.org/D2783

===================================================================

M	source/blender/blenkernel/BKE_fcurve.h
M	source/blender/blenkernel/intern/fcurve.c
M	source/blender/blenkernel/intern/fmodifier.c
M	source/blender/blenkernel/intern/ipo.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/editors/animation/drivers.c
M	source/blender/editors/animation/fmodifier_ui.c
M	source/blender/editors/include/ED_anim_api.h
M	source/blender/editors/object/object_constraint.c
M	source/blender/editors/object/object_relations.c
M	source/blender/editors/space_action/action_edit.c
M	source/blender/editors/space_graph/graph_edit.c
M	source/blender/editors/space_nla/nla_edit.c
M	source/blender/makesdna/DNA_anim_types.h
M	source/blender/makesdna/DNA_curve_types.h
M	source/blender/makesrna/intern/rna_fcurve.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index b38f1299763..2c52d40ed44 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -188,7 +188,7 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(const int type);
 
 /* ---------------------- */
 
-struct FModifier *add_fmodifier(ListBase *modifiers, int type);
+struct FModifier *add_fmodifier(ListBase *modifiers, int type, struct FCurve *owner_fcu);
 struct FModifier *copy_fmodifier(const struct FModifier *src);
 void copy_fmodifiers(ListBase *dst, const ListBase *src);
 bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index db6c533ab57..1eed8c7c204 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -882,6 +882,44 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
  * that the handles are correctly 
  */
 
+/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
+static bool detect_cycle_modifier(FCurve *fcu)
+{
+	FModifier *fcm = fcu->modifiers.first;
+
+	if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES)
+		return false;
+
+	if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED))
+		return false;
+
+	if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE))
+		return false;
+
+	FMod_Cycles *data = (FMod_Cycles*)fcm->data;
+
+	return data && data->after_cycles == 0 && data->before_cycles == 0 &&
+	    ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
+	    ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET);
+}
+
+/* If cyclic, set out by shifting in by the difference in position between from and to. */
+static BezTriple *cycle_offset_triple(bool cycle, BezTriple *out, const BezTriple *in, const BezTriple *from, const BezTriple *to)
+{
+	if (!cycle)
+		return NULL;
+
+	memcpy(out, in, sizeof(BezTriple));
+
+	float delta[3];
+	sub_v3_v3v3(delta, to->vec[1], from->vec[1]);
+
+	for (int i = 0; i < 3; i++)
+		add_v3_v3(out->vec[i], delta);
+
+	return out;
+}
+
 /* This function recalculates the handles of an F-Curve 
  * If the BezTriples have been rearranged, sort them first before using this.
  */
@@ -897,10 +935,16 @@ void calchandles_fcurve(FCurve *fcu)
 	 */
 	if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/) 
 		return;
-	
+
+	/* if the first modifier is Cycles, smooth the curve through the cycle */
+	BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert-1];
+	BezTriple tmp;
+
+	bool cycle = detect_cycle_modifier(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last);
+
 	/* get initial pointers */
 	bezt = fcu->bezt;
-	prev = NULL;
+	prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert-2], last, first);
 	next = (bezt + 1);
 	
 	/* loop over all beztriples, adjusting handles */
@@ -913,7 +957,7 @@ void calchandles_fcurve(FCurve *fcu)
 		BKE_nurb_handle_calc(bezt, prev, next, true);
 		
 		/* for automatic ease in and out */
-		if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
+		if (BEZT_IS_AUTOH(bezt) && !cycle) {
 			/* only do this on first or last beztriple */
 			if ((a == 0) || (a == fcu->totvert - 1)) {
 				/* set both handles to have same horizontal value as keyframe */
@@ -925,7 +969,8 @@ void calchandles_fcurve(FCurve *fcu)
 		
 		/* advance pointers for next iteration */
 		prev = bezt;
-		if (a == 1) next = NULL;
+		if (a == 1)
+			next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
 		else next++;
 		bezt++;
 	}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index f1732ee7a9a..98a3c4bacb5 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1077,7 +1077,7 @@ const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
 /* API --------------------------- */
 
 /* Add a new F-Curve Modifier to the given F-Curve of a certain type */
-FModifier *add_fmodifier(ListBase *modifiers, int type)
+FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
 {
 	const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
 	FModifier *fcm;
@@ -1098,6 +1098,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type)
 	fcm = MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
 	fcm->type = type;
 	fcm->flag = FMODIFIER_FLAG_EXPANDED;
+	fcm->curve = owner_fcu;
 	fcm->influence = 1.0f;
 	BLI_addtail(modifiers, fcm);
 	
@@ -1129,6 +1130,7 @@ FModifier *copy_fmodifier(const FModifier *src)
 	/* copy the base data, clearing the links */
 	dst = MEM_dupallocN(src);
 	dst->next = dst->prev = NULL;
+	dst->curve = NULL;
 	
 	/* make a new copy of the F-Modifier's data */
 	dst->data = MEM_dupallocN(src->data);
@@ -1157,6 +1159,7 @@ void copy_fmodifiers(ListBase *dst, const ListBase *src)
 		
 		/* make a new copy of the F-Modifier's data */
 		fcm->data = MEM_dupallocN(fcm->data);
+		fcm->curve = NULL;
 		
 		/* only do specific constraints if required */
 		if (fmi && fmi->copy_data)
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index f3a85dcee2b..90247441631 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1192,7 +1192,7 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i
 			/* Add a new FModifier (Cyclic) instead of setting extend value 
 			 * as that's the new equivalent of that option.
 			 */
-			FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
+			FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
 			FMod_Cycles *data = (FMod_Cycles *)fcm->data;
 			
 			/* if 'offset' one is in use, set appropriate settings */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 31964373716..248da6a9f55 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2389,11 +2389,13 @@ static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbas
 
 /* Data Linking ----------------------------- */
 
-static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list)
+static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list, FCurve *curve)
 {
 	FModifier *fcm;
 	
 	for (fcm = list->first; fcm; fcm = fcm->next) {
+		fcm->curve = curve;
+
 		/* data for specific modifiers */
 		switch (fcm->type) {
 			case FMODIFIER_TYPE_PYTHON:
@@ -2435,19 +2437,20 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list)
 		}
 		
 		/* modifiers */
-		lib_link_fmodifiers(fd, id, &fcu->modifiers);
+		lib_link_fmodifiers(fd, id, &fcu->modifiers, fcu);
 	}
 }
 
 
 /* NOTE: this assumes that link_list has already been called on the list */
-static void direct_link_fmodifiers(FileData *fd, ListBase *list)
+static void direct_link_fmodifiers(FileData *fd, ListBase *list, FCurve *curve)
 {
 	FModifier *fcm;
 	
 	for (fcm = list->first; fcm; fcm = fcm->next) {
 		/* relink general data */
 		fcm->data  = newdataadr(fd, fcm->data);
+		fcm->curve = curve;
 		
 		/* do relinking of data for specific types */
 		switch (fcm->type) {
@@ -2537,7 +2540,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
 		
 		/* modifiers */
 		link_list(fd, &fcu->modifiers);
-		direct_link_fmodifiers(fd, &fcu->modifiers);
+		direct_link_fmodifiers(fd, &fcu->modifiers, fcu);
 	}
 }
 
@@ -2642,7 +2645,7 @@ static void direct_link_nladata_strips(FileData *fd, ListBase *list)
 		
 		/* strip's F-Modifiers */
 		link_list(fd, &strip->modifiers);
-		direct_link_fmodifiers(fd, &strip->modifiers);
+		direct_link_fmodifiers(fd, &strip->modifiers, NULL);
 	}
 }
 
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 21c25f829b1..d2aade8446d 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -122,7 +122,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
 				 * Create FModifier so that old scripts won't break
 				 * for now before 2.7 series -- (September 4, 2013)
 				 */
-				add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
+				add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu);
 			}
 			else {
 				/* add 2 keyframes so that user has something to work with 
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 6bb73416fec..ed21f2342e4 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -90,7 +90,9 @@ static void delete_fmodifier_cb(bContext *C, void *fmods_v, void *fcm_v)
 {
 	ListBase *modifiers = (ListBase *)fmods_v;
 	FModifier *fcm = (FModifier *)fcm_v;
-	
+
+	FCurve *update_fcu = fcm->type == FMODIFIER_TYPE_CYCLES ? fcm->curve : NULL;
+
 	/* remove the given F-Modifier from the active modifier-stack */
 	remove_fmodifier(modifiers, fcm);
 
@@ -99,6 +101,9 @@ static void delete_fmodifier_cb(bContext *C, void *fmods_v, void *fcm_v)
 	/* send notifiers */
 	// XXX for now, this is the only way to get updates in all the right places... but would be nice to have a special one in this case 
 	WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+	if (update_fcu)
+		calchandles_fcurve(update_fcu);
 }
 
 /* --------------- */
@@ -736,7 +741,7 @@ bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
 /* 'Paste' the F-Modifier(s) from the buffer to the specified list 
  *	- replace: free all the existing modifiers to leave only the pasted ones 
  */
-bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace)
+bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
 {
 	FModifier *fcm;
 	bool ok = false;
@@ -753,6 +758,8 @@ bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bo

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list