Compare commits
4 Commits
temp-cpp-g
...
temp-angav
Author | SHA1 | Date | |
---|---|---|---|
efb558fc8b | |||
dfc187d411 | |||
de27f054af | |||
bd66965f31 |
@@ -97,6 +97,8 @@ class TIME_HT_header(Header):
|
||||
row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
|
||||
row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT')
|
||||
|
||||
layout.prop(toolsettings, "use_keyframe_cycle_aware", text="", toggle=True)
|
||||
|
||||
|
||||
class TIME_MT_editor_menus(Menu):
|
||||
bl_idname = "TIME_MT_editor_menus"
|
||||
|
@@ -269,6 +269,14 @@ bool BKE_fcurve_is_protected(struct FCurve *fcu);
|
||||
/* The curve is an infinite cycle via Cycles modifier */
|
||||
bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
|
||||
|
||||
typedef enum eFCU_Cycle_Type {
|
||||
FCU_CYCLE_NONE = 0,
|
||||
FCU_CYCLE_PERFECT,
|
||||
FCU_CYCLE_OFFSET
|
||||
} eFCU_Cycle_Type;
|
||||
|
||||
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
|
||||
|
||||
/* -------- Curve Sanity -------- */
|
||||
|
||||
void calchandles_fcurve(struct FCurve *fcu);
|
||||
@@ -278,6 +286,14 @@ short test_time_fcurve(struct FCurve *fcu);
|
||||
|
||||
void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]);
|
||||
|
||||
/* Adjust bezier handles as bezt is being inserted between prev and next.
|
||||
* - pdelta: outputs Y difference between bezt and old curve value at its X position.
|
||||
*/
|
||||
bool BKE_bezt_subdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, float *pdelta);
|
||||
|
||||
/* Try to revert prev & next handle adjustment performed by subdivide_handles. */
|
||||
bool BKE_bezt_unsubdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next);
|
||||
|
||||
/* -------- Evaluation -------- */
|
||||
|
||||
/* evaluate fcurve */
|
||||
|
@@ -883,24 +883,37 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
|
||||
*/
|
||||
|
||||
/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
|
||||
bool BKE_fcurve_is_cyclic(FCurve *fcu)
|
||||
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
|
||||
{
|
||||
FModifier *fcm = fcu->modifiers.first;
|
||||
|
||||
if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES)
|
||||
return false;
|
||||
return FCU_CYCLE_NONE;
|
||||
|
||||
if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED))
|
||||
return false;
|
||||
return FCU_CYCLE_NONE;
|
||||
|
||||
if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE))
|
||||
return false;
|
||||
return FCU_CYCLE_NONE;
|
||||
|
||||
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 (data && data->after_cycles == 0 && data->before_cycles == 0)
|
||||
{
|
||||
if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC)
|
||||
return FCU_CYCLE_PERFECT;
|
||||
|
||||
if (ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
|
||||
ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET))
|
||||
return FCU_CYCLE_OFFSET;
|
||||
}
|
||||
|
||||
return FCU_CYCLE_NONE;
|
||||
}
|
||||
|
||||
bool BKE_fcurve_is_cyclic(FCurve *fcu)
|
||||
{
|
||||
return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
|
||||
}
|
||||
|
||||
/* Shifts 'in' by the difference in coordinates between 'to' and 'from', using 'out' as the output buffer.
|
||||
@@ -2076,17 +2089,12 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2])
|
||||
}
|
||||
}
|
||||
|
||||
/* find root ('zero') */
|
||||
static int findzero(float x, float q0, float q1, float q2, float q3, float *o)
|
||||
/* find roots of cubic equation */
|
||||
static int solve_cubic(float c0, float c1, float c2, float c3, float *o)
|
||||
{
|
||||
double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
|
||||
double a, b, c, p, q, d, t, phi;
|
||||
int nr = 0;
|
||||
|
||||
c0 = q0 - x;
|
||||
c1 = 3.0f * (q1 - q0);
|
||||
c2 = 3.0f * (q0 - 2.0f * q1 + q2);
|
||||
c3 = q3 - q0 + 3.0f * (q1 - q2);
|
||||
|
||||
if (c3 != 0.0) {
|
||||
a = c2 / c3;
|
||||
b = c1 / c3;
|
||||
@@ -2171,6 +2179,19 @@ static int findzero(float x, float q0, float q1, float q2, float q3, float *o)
|
||||
}
|
||||
}
|
||||
|
||||
/* find root ('zero') */
|
||||
static int findzero(float x, float q0, float q1, float q2, float q3, float *o)
|
||||
{
|
||||
double c0, c1, c2, c3;
|
||||
|
||||
c0 = q0 - x;
|
||||
c1 = 3.0f * (q1 - q0);
|
||||
c2 = 3.0f * (q0 - 2.0f * q1 + q2);
|
||||
c3 = q3 - q0 + 3.0f * (q1 - q2);
|
||||
|
||||
return solve_cubic(c0, c1, c2, c3, o);
|
||||
}
|
||||
|
||||
static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
|
||||
{
|
||||
float t, c0, c1, c2, c3;
|
||||
@@ -2205,6 +2226,104 @@ static void berekenx(float *f, float *o, int b)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* recompute handles to neatly subdivide the prev-next range at bezt */
|
||||
bool BKE_bezt_subdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, float *pdelta)
|
||||
{
|
||||
float *P0 = prev->vec[1], *P1 = prev->vec[2], *P2 = next->vec[0], *P3 = next->vec[1];
|
||||
float *ML = bezt->vec[0], *MM = bezt->vec[1], *MR = bezt->vec[2];
|
||||
|
||||
if (MM[0] <= P0[0] || MM[0] >= P3[0])
|
||||
return false;
|
||||
|
||||
/* find bezier parameter */
|
||||
correct_bezpart(P0, P1, P2, P3);
|
||||
|
||||
float keys[4];
|
||||
|
||||
if (!findzero(MM[0], P0[0], P1[0], P2[0], P3[0], keys))
|
||||
return false;
|
||||
|
||||
float t = keys[0];
|
||||
|
||||
if (t <= 0.0f || t >= 1.0f)
|
||||
return false;
|
||||
|
||||
/* de-Casteljau split */
|
||||
float M1[3][2], M2[2][2], M3[2], D[2];
|
||||
|
||||
interp_v2_v2v2(M1[0], P0, P1, t);
|
||||
interp_v2_v2v2(M1[1], P1, P2, t);
|
||||
interp_v2_v2v2(M1[2], P2, P3, t);
|
||||
interp_v2_v2v2(M2[0], M1[0], M1[1], t);
|
||||
interp_v2_v2v2(M2[1], M1[1], M1[2], t);
|
||||
interp_v2_v2v2(M3, M2[0], M2[1], t);
|
||||
|
||||
/* overwrite the handles */
|
||||
copy_v2_v2(P1, M1[0]);
|
||||
copy_v2_v2(P2, M1[2]);
|
||||
|
||||
sub_v2_v2v2(D, MM, M3);
|
||||
add_v2_v2v2(ML, M2[0], D);
|
||||
add_v2_v2v2(MR, M2[1], D);
|
||||
|
||||
*pdelta = D[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
/* try to restore handles before deletion of bezt */
|
||||
bool BKE_bezt_unsubdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next)
|
||||
{
|
||||
float *P0 = prev->vec[1], *P1 = prev->vec[2], *P2 = next->vec[0], *P3 = next->vec[1];
|
||||
float *ML = bezt->vec[0], *MM = bezt->vec[1], *MR = bezt->vec[2];
|
||||
|
||||
if (MM[0] <= P0[0] || MM[0] >= P3[0])
|
||||
return false;
|
||||
|
||||
/* Solve equation to undo P1 & P2 rescaling, assuming basically that
|
||||
* prev and next were adjusted by BKE_bezt_subdivide_handles before.
|
||||
* The equation tries to find t that was used at that time.
|
||||
*/
|
||||
correct_bezpart(P0, P1, ML, MM);
|
||||
correct_bezpart(MM, MR, P2, P3);
|
||||
|
||||
float c0, c1, c2, c3, keys[4];
|
||||
|
||||
c0 = 3.0f * P1[0] - 2.0f * P0[0] - MM[0];
|
||||
c1 = 6.0f * (P0[0] - P1[0]);
|
||||
c2 = 3.0f * (P1[0] + P2[0]) - 6.0f * P0[0];
|
||||
c3 = 2.0f * (P0[0] - P3[0]);
|
||||
|
||||
float t, tx = (MM[0] - P0[0]) / (P3[0] - P0[0]);
|
||||
|
||||
int n = solve_cubic(c0, c1, c2, c3, keys);
|
||||
|
||||
if (n < 1) {
|
||||
/* if the equation failed, just use the X coordinate ratio */
|
||||
t = tx;
|
||||
}
|
||||
else {
|
||||
/* find the best solution given by the equation */
|
||||
t = keys[0];
|
||||
|
||||
for (int i = 1; i < n; i++)
|
||||
if (fabsf(keys[i] - tx) < fabsf(t - tx))
|
||||
t = keys[i];
|
||||
}
|
||||
|
||||
if (t <= 0.0f || t >= 1.0f)
|
||||
return false;
|
||||
|
||||
/* rescale handles */
|
||||
float tmp[2];
|
||||
|
||||
sub_v2_v2v2(tmp, P1, P0);
|
||||
madd_v2_v2v2fl(P1, P0, tmp, 1.0f / t);
|
||||
|
||||
sub_v2_v2v2(tmp, P2, P3);
|
||||
madd_v2_v2v2fl(P2, P3, tmp, 1.0f / (1.0f - t));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------- */
|
||||
|
||||
|
@@ -99,6 +99,29 @@ static short compare_ak_bezt(void *node, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static eKeyframeInterpolationDrawOpts bezt_interpolation_type(BezTriple *bezt)
|
||||
{
|
||||
switch (bezt->ipo)
|
||||
{
|
||||
case BEZT_IPO_CONST:
|
||||
return KEYFRAME_IPOTYPE_CONST;
|
||||
case BEZT_IPO_LIN:
|
||||
return KEYFRAME_IPOTYPE_LINEAR;
|
||||
case BEZT_IPO_BEZ:
|
||||
if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM)
|
||||
return KEYFRAME_IPOTYPE_BEZ_AUTO_CLAMP;
|
||||
else if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO))
|
||||
return KEYFRAME_IPOTYPE_BEZ_AUTO;
|
||||
else if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT)
|
||||
return KEYFRAME_IPOTYPE_BEZ_VECTOR;
|
||||
else
|
||||
return KEYFRAME_IPOTYPE_BEZ_MANUAL;
|
||||
|
||||
default:
|
||||
return KEYFRAME_IPOTYPE_EASING;
|
||||
}
|
||||
}
|
||||
|
||||
/* New node callback used for building ActKeyColumns from BezTriples */
|
||||
static DLRBT_Node *nalloc_ak_bezt(void *data)
|
||||
{
|
||||
@@ -109,6 +132,7 @@ static DLRBT_Node *nalloc_ak_bezt(void *data)
|
||||
ak->cfra = bezt->vec[1][0];
|
||||
ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
|
||||
ak->key_type = BEZKEYTYPE(bezt);
|
||||
ak->ipo_type = bezt_interpolation_type(bezt);
|
||||
|
||||
/* set 'modified', since this is used to identify long keyframes */
|
||||
ak->modified = 1;
|
||||
@@ -129,6 +153,8 @@ static void nupdate_ak_bezt(void *node, void *data)
|
||||
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
|
||||
if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME)
|
||||
ak->key_type = BEZT_KEYTYPE_KEYFRAME;
|
||||
|
||||
ak->ipo_type = MAX2(ak->ipo_type, bezt_interpolation_type(bezt));
|
||||
}
|
||||
|
||||
/* ......... */
|
||||
@@ -471,8 +497,99 @@ static const float _unit_diamond_shape[4][2] = {
|
||||
{-1.0f, 0.0f} /* mid-left */
|
||||
};
|
||||
|
||||
static const float _unit_mini_diamond_shape[4][2] = {
|
||||
{0.0f, 0.1f}, /* top vert */
|
||||
{0.1f, 0.0f}, /* mid-right */
|
||||
{0.0f, -0.1f}, /* bottom vert */
|
||||
{-0.1f, 0.0f} /* mid-left */
|
||||
};
|
||||
|
||||
static const float _unit_ipo_top_left[2] = {-0.5f, 0.5f};
|
||||
static const float _unit_ipo_top_right[2] = {0.5f, 0.5f};
|
||||
static const float _unit_ipo_bottom_left[2] = {-0.5f, -0.5f};
|
||||
static const float _unit_ipo_bottom_right[2] = {0.5f, -0.5f};
|
||||
static const float _unit_ipo_middle[2] = {0.0f, 0.0f};
|
||||
|
||||
static void draw_ipo_type(short ipo_type)
|
||||
{
|
||||
static GLuint ipo_disps[10] = { 0 };
|
||||
|
||||
if (ipo_type == KEYFRAME_IPOTYPE_NONE || ipo_type == KEYFRAME_IPOTYPE_BEZ_AUTO_CLAMP)
|
||||
return;
|
||||
|
||||
if (ipo_disps[ipo_type] == 0) {
|
||||
ipo_disps[ipo_type] = glGenLists(1);
|
||||
glNewList(ipo_disps[ipo_type], GL_COMPILE);
|
||||
|
||||
switch (ipo_type) {
|
||||
case KEYFRAME_IPOTYPE_CONST: // <|>
|
||||
glBegin(GL_LINES);
|
||||
glVertex2fv(_unit_diamond_shape[0]);
|
||||
glVertex2fv(_unit_diamond_shape[2]);
|
||||
glEnd();
|
||||
break;
|
||||
|
||||
case KEYFRAME_IPOTYPE_LINEAR: // <->
|
||||
glBegin(GL_LINES);
|
||||
glVertex2fv(_unit_diamond_shape[1]);
|
||||
glVertex2fv(_unit_diamond_shape[3]);
|
||||
glEnd();
|
||||
break;
|
||||
|
||||
case KEYFRAME_IPOTYPE_EASING: // <+>
|
||||
glBegin(GL_LINES);
|
||||
glVertex2fv(_unit_diamond_shape[0]);
|
||||
glVertex2fv(_unit_diamond_shape[2]);
|
||||
glVertex2fv(_unit_diamond_shape[1]);
|
||||
glVertex2fv(_unit_diamond_shape[3]);
|
||||
glEnd();
|
||||
break;
|
||||
|
||||
case KEYFRAME_IPOTYPE_BEZ_AUTO: // <.>
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2fv(_unit_mini_diamond_shape[0]);
|
||||
glVertex2fv(_unit_mini_diamond_shape[1]);
|
||||
glVertex2fv(_unit_mini_diamond_shape[2]);
|
||||
glVertex2fv(_unit_mini_diamond_shape[3]);
|
||||
glEnd();
|
||||
break;
|
||||
|
||||
/*case KEYFRAME_IPOTYPE_BEZ_AUTO: // </>
|
||||
glBegin(GL_LINES);
|
||||
glVertex2fv(_unit_ipo_bottom_left);
|
||||
glVertex2fv(_unit_ipo_top_right);
|
||||
glEnd();
|
||||
break;*/
|
||||
|
||||
case KEYFRAME_IPOTYPE_BEZ_VECTOR: // <v>
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex2fv(_unit_ipo_top_left);
|
||||
glVertex2fv(_unit_ipo_middle);
|
||||
glVertex2fv(_unit_ipo_top_right);
|
||||
glEnd();
|
||||
break;
|
||||
|
||||
case KEYFRAME_IPOTYPE_BEZ_MANUAL: // <X>
|
||||
glBegin(GL_LINES);
|
||||
glVertex2fv(_unit_ipo_top_left);
|
||||
glVertex2fv(_unit_ipo_bottom_right);
|
||||
glVertex2fv(_unit_ipo_bottom_left);
|
||||
glVertex2fv(_unit_ipo_top_right);
|
||||
glEnd();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
glEndList();
|
||||
}
|
||||
|
||||
glCallList(ipo_disps[ipo_type]);
|
||||
}
|
||||
|
||||
/* draw a simple diamond shape with OpenGL */
|
||||
void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha)
|
||||
void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha, short ipo_type)
|
||||
{
|
||||
static GLuint displist1 = 0;
|
||||
static GLuint displist2 = 0;
|
||||
@@ -599,6 +716,8 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
|
||||
border_col[3] *= alpha;
|
||||
glColor4fv(border_col);
|
||||
|
||||
draw_ipo_type(ipo_type);
|
||||
|
||||
glCallList(displist1);
|
||||
}
|
||||
|
||||
@@ -682,7 +801,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
|
||||
/* draw using OpenGL - uglier but faster */
|
||||
/* NOTE1: a previous version of this didn't work nice for some intel cards
|
||||
* NOTE2: if we wanted to go back to icons, these are icon = (ak->sel & SELECT) ? ICON_SPACE2 : ICON_SPACE3; */
|
||||
draw_keyframe_shape(ak->cfra, ypos, xscale, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha);
|
||||
draw_keyframe_shape(ak->cfra, ypos, xscale, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha, ak->ipo_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -71,6 +71,18 @@
|
||||
|
||||
/* **************************************************** */
|
||||
|
||||
static void unsubdivide_nonauto_handles(BezTriple *bezt, BezTriple *prev, BezTriple *next)
|
||||
{
|
||||
if (prev->ipo != BEZT_IPO_BEZ || bezt->ipo != BEZT_IPO_BEZ)
|
||||
return;
|
||||
|
||||
if (ELEM(prev->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT) &&
|
||||
ELEM(next->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT))
|
||||
return;
|
||||
|
||||
BKE_bezt_unsubdivide_handles(bezt, prev, next);
|
||||
}
|
||||
|
||||
/* Only delete the nominated keyframe from provided F-Curve.
|
||||
* Not recommended to be used many times successively. For that
|
||||
* there is delete_fcurve_keys().
|
||||
@@ -90,6 +102,10 @@ void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
|
||||
else if (index < 0)
|
||||
index += fcu->totvert;
|
||||
|
||||
/* resize surrounding non-auto bezier handles */
|
||||
if (do_recalc && index > 0 && index < fcu->totvert - 1)
|
||||
unsubdivide_nonauto_handles(&fcu->bezt[index], &fcu->bezt[index - 1], &fcu->bezt[index + 1]);
|
||||
|
||||
/* Delete this keyframe */
|
||||
memmove(&fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
|
||||
fcu->totvert--;
|
||||
@@ -105,8 +121,19 @@ void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
|
||||
calchandles_fcurve(fcu);
|
||||
}
|
||||
|
||||
/* Checks if all keys are selected in an fcurve */
|
||||
static bool check_if_all_keys_sel(struct FCurve *fcu)
|
||||
{
|
||||
for (int i = 0; i < fcu->totvert; i++)
|
||||
{
|
||||
if (!(fcu->bezt[i].f2 & SELECT))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Delete selected keyframes in given F-Curve */
|
||||
bool delete_fcurve_keys(FCurve *fcu)
|
||||
bool delete_fcurve_keys(FCurve *fcu, bool resize_handles)
|
||||
{
|
||||
int i;
|
||||
bool changed = false;
|
||||
@@ -114,9 +141,19 @@ bool delete_fcurve_keys(FCurve *fcu)
|
||||
if (fcu->bezt == NULL) /* ignore baked curves */
|
||||
return false;
|
||||
|
||||
/* Clear if everything is selected */
|
||||
if (check_if_all_keys_sel(fcu)) {
|
||||
clear_fcurve_keys(fcu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Delete selected BezTriples */
|
||||
for (i = 0; i < fcu->totvert; i++) {
|
||||
if (fcu->bezt[i].f2 & SELECT) {
|
||||
/* resize surrounding non-auto bezier handles */
|
||||
if (resize_handles && i > 0 && i < fcu->totvert - 1)
|
||||
unsubdivide_nonauto_handles(&fcu->bezt[i], &fcu->bezt[i-1], &fcu->bezt[i+1]);
|
||||
|
||||
memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
|
||||
fcu->totvert--;
|
||||
i--;
|
||||
@@ -860,7 +897,7 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
|
||||
}
|
||||
|
||||
/* remove frames in the range */
|
||||
delete_fcurve_keys(fcu);
|
||||
delete_fcurve_keys(fcu, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -112,6 +112,10 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode)
|
||||
/* keyframing mode - only replace existing keyframes */
|
||||
if (IS_AUTOKEY_MODE(scene, EDITKEYS))
|
||||
flag |= INSERTKEY_REPLACE;
|
||||
|
||||
/* cycle-aware keyframe insertion - preserve cycle period and flow */
|
||||
if (IS_AUTOKEY_FLAG(scene, CYCLEAWARE))
|
||||
flag |= INSERTKEY_CYCLE_AWARE;
|
||||
}
|
||||
|
||||
return flag;
|
||||
@@ -293,8 +297,57 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin
|
||||
/* ************************************************** */
|
||||
/* KEYFRAME INSERTION */
|
||||
|
||||
static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py)
|
||||
{
|
||||
if (fcu->totvert < 2 || !fcu->bezt)
|
||||
return FCU_CYCLE_NONE;
|
||||
|
||||
eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu);
|
||||
if (!type)
|
||||
return FCU_CYCLE_NONE;
|
||||
|
||||
BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert-1];
|
||||
float start = first->vec[1][0], end = last->vec[1][0];
|
||||
if (start >= end)
|
||||
return FCU_CYCLE_NONE;
|
||||
|
||||
if (*px < start || *px > end) {
|
||||
float period = end - start;
|
||||
float step = floorf((*px - start) / period);
|
||||
*px -= step * period;
|
||||
|
||||
if (type == FCU_CYCLE_OFFSET) {
|
||||
/* nasty check to handle the case when the modes are different better */
|
||||
FMod_Cycles *data = (FMod_Cycles *)((FModifier*)fcu->modifiers.first)->data;
|
||||
|
||||
if ((step >= 0 ? data->after_mode : data->before_mode) == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
|
||||
*py -= step * (last->vec[1][1] - first->vec[1][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* -------------- BezTriple Insertion -------------------- */
|
||||
|
||||
static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
|
||||
{
|
||||
/* just change the values when replacing, so as to not overwrite handles */
|
||||
float dy = bezt->vec[1][1] - dst->vec[1][1];
|
||||
|
||||
/* just apply delta value change to the handle values */
|
||||
dst->vec[0][1] += dy;
|
||||
dst->vec[1][1] += dy;
|
||||
dst->vec[2][1] += dy;
|
||||
|
||||
dst->f1 = bezt->f1;
|
||||
dst->f2 = bezt->f2;
|
||||
dst->f3 = bezt->f3;
|
||||
|
||||
/* TODO: perform some other operations? */
|
||||
}
|
||||
|
||||
/* This function adds a given BezTriple to an F-Curve. It will allocate
|
||||
* memory for the array if needed, and will insert the BezTriple into a
|
||||
* suitable place in chronological order.
|
||||
@@ -319,20 +372,13 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
|
||||
fcu->bezt[i] = *bezt;
|
||||
}
|
||||
else {
|
||||
/* just change the values when replacing, so as to not overwrite handles */
|
||||
BezTriple *dst = (fcu->bezt + i);
|
||||
float dy = bezt->vec[1][1] - dst->vec[1][1];
|
||||
|
||||
/* just apply delta value change to the handle values */
|
||||
dst->vec[0][1] += dy;
|
||||
dst->vec[1][1] += dy;
|
||||
dst->vec[2][1] += dy;
|
||||
|
||||
dst->f1 = bezt->f1;
|
||||
dst->f2 = bezt->f2;
|
||||
dst->f3 = bezt->f3;
|
||||
|
||||
/* TODO: perform some other operations? */
|
||||
replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
|
||||
}
|
||||
|
||||
/* if replacing an end point of a cyclic curve without offset, modify the other end too. */
|
||||
if ((flag & INSERTKEY_CYCLE_AWARE) && (i == 0 || i == fcu->totvert-1) &&
|
||||
(BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT)) {
|
||||
replace_bezt_keyframe_ypos(&fcu->bezt[(fcu->totvert-1) - i], bezt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -384,6 +430,47 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
|
||||
return i;
|
||||
}
|
||||
|
||||
/* This checks whether it is necessary to apply bezier subdivision due to involvement of non-auto handles.
|
||||
* - bezt: key being inserted
|
||||
* - prev, next: old keys surrounding the location
|
||||
*/
|
||||
static void subdivide_nonauto_handles(FCurve *fcu, BezTriple *bezt, BezTriple *prev, BezTriple *next)
|
||||
{
|
||||
if (prev->ipo != BEZT_IPO_BEZ || bezt->ipo != BEZT_IPO_BEZ)
|
||||
return;
|
||||
|
||||
/* don't change vector handles, or completely auto regions */
|
||||
bool bezt_auto = BEZT_IS_AUTOH(bezt) || (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT);
|
||||
bool prev_auto = BEZT_IS_AUTOH(prev) || (prev->h2 == HD_VECT);
|
||||
bool next_auto = BEZT_IS_AUTOH(next) || (next->h1 == HD_VECT);
|
||||
|
||||
if (bezt_auto && prev_auto && next_auto)
|
||||
return;
|
||||
|
||||
/* subdivide the curve */
|
||||
float delta;
|
||||
|
||||
if (!BKE_bezt_subdivide_handles(bezt, prev, next, &delta))
|
||||
return;
|
||||
|
||||
/* decide when to force auto to manual */
|
||||
if (BEZT_IS_AUTOH(bezt) && fabsf(delta) < 0.001f) {
|
||||
bool auto_works_well = false;
|
||||
|
||||
if (fcu->auto_smoothing == FCURVE_SMOOTH_CONT_ACCEL) {
|
||||
float hx = bezt->vec[1][0] - bezt->vec[0][0];
|
||||
float dx = bezt->vec[1][0] - prev->vec[1][0];
|
||||
|
||||
/* this mode always uses 1/3 of key distance for handle x size */
|
||||
auto_works_well = fabsf(hx - dx/3.0f) < 0.001f;
|
||||
}
|
||||
|
||||
if (!auto_works_well || !(prev_auto || next_auto)) {
|
||||
bezt->h1 = bezt->h2 = HD_ALIGN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is a wrapper for insert_bezt_fcurve_internal(), and should be used when
|
||||
* adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
|
||||
@@ -456,13 +543,6 @@ int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType ke
|
||||
*/
|
||||
if (a < 0) return -1;
|
||||
|
||||
/* don't recalculate handles if fast is set
|
||||
* - this is a hack to make importers faster
|
||||
* - we may calculate twice (due to autohandle needing to be calculated twice)
|
||||
*/
|
||||
if ((flag & INSERTKEY_FAST) == 0)
|
||||
calchandles_fcurve(fcu);
|
||||
|
||||
/* set handletype and interpolation */
|
||||
if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) {
|
||||
BezTriple *bezt = (fcu->bezt + a);
|
||||
@@ -476,15 +556,17 @@ int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType ke
|
||||
bezt->ipo = (bezt - 1)->ipo;
|
||||
else if (a < fcu->totvert - 1)
|
||||
bezt->ipo = (bezt + 1)->ipo;
|
||||
|
||||
if ((a > 0) && (a < fcu->totvert - 1) && (flag & INSERTKEY_OVERWRITE_FULL) == 0)
|
||||
subdivide_nonauto_handles(fcu, bezt, bezt - 1, bezt + 1);
|
||||
}
|
||||
|
||||
/* don't recalculate handles if fast is set
|
||||
* - this is a hack to make importers faster
|
||||
* - we may calculate twice (due to autohandle needing to be calculated twice)
|
||||
*/
|
||||
if ((flag & INSERTKEY_FAST) == 0)
|
||||
calchandles_fcurve(fcu);
|
||||
}
|
||||
|
||||
/* don't recalculate handles if fast is set
|
||||
* - this is a hack to make importers faster
|
||||
*/
|
||||
if ((flag & INSERTKEY_FAST) == 0)
|
||||
calchandles_fcurve(fcu);
|
||||
|
||||
/* return the index at which the keyframe was added */
|
||||
return a;
|
||||
@@ -960,6 +1042,14 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
|
||||
curval = setting_get_rna_value(&ptr, prop, fcu->array_index);
|
||||
}
|
||||
|
||||
/* adjust coordinates for cycle aware insertion */
|
||||
if (flag & INSERTKEY_CYCLE_AWARE) {
|
||||
if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) {
|
||||
/* inhibit action from insert_vert_fcurve unless it's a perfect cycle */
|
||||
flag &= ~INSERTKEY_CYCLE_AWARE;
|
||||
}
|
||||
}
|
||||
|
||||
/* only insert keyframes where they are needed */
|
||||
if (flag & INSERTKEY_NEEDED) {
|
||||
short insert_mode;
|
||||
|
@@ -923,7 +923,8 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
|
||||
/* Determine which keying flags apply based on the override flags */
|
||||
static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags)
|
||||
{
|
||||
short result = 0;
|
||||
/* Pass through all flags by default (i.e. even not explicitly listed ones). */
|
||||
short result = base_flags;
|
||||
|
||||
/* The logic for whether a keying flag applies is as follows:
|
||||
* - If the flag in question is set in "overrides", that means that the
|
||||
@@ -933,12 +934,10 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov
|
||||
*/
|
||||
#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \
|
||||
if (overrides & kflag) { \
|
||||
result &= ~kflag; \
|
||||
result |= (own_flags & kflag); \
|
||||
} \
|
||||
else { \
|
||||
result |= (base_flags & kflag); \
|
||||
}
|
||||
|
||||
|
||||
/* Apply the flags one by one...
|
||||
* (See rna_def_common_keying_flags() for the supported flags)
|
||||
*/
|
||||
|
@@ -61,6 +61,7 @@ typedef struct ActKeyColumn {
|
||||
|
||||
/* keyframe info */
|
||||
char key_type; /* eBezTripe_KeyframeType */
|
||||
char ipo_type; /* eKeyframeInterpolationDrawOpts */
|
||||
short sel;
|
||||
float cfra;
|
||||
|
||||
@@ -108,8 +109,22 @@ typedef enum eKeyframeShapeDrawOpts {
|
||||
KEYFRAME_SHAPE_BOTH
|
||||
} eKeyframeShapeDrawOpts;
|
||||
|
||||
/* interpolation type */
|
||||
typedef enum eKeyframeInterpolationDrawOpts {
|
||||
/* don't draw */
|
||||
KEYFRAME_IPOTYPE_NONE = 0,
|
||||
/* various marks */
|
||||
KEYFRAME_IPOTYPE_CONST,
|
||||
KEYFRAME_IPOTYPE_LINEAR,
|
||||
KEYFRAME_IPOTYPE_EASING,
|
||||
KEYFRAME_IPOTYPE_BEZ_AUTO_CLAMP,
|
||||
KEYFRAME_IPOTYPE_BEZ_AUTO,
|
||||
KEYFRAME_IPOTYPE_BEZ_VECTOR,
|
||||
KEYFRAME_IPOTYPE_BEZ_MANUAL,
|
||||
} eKeyframeInterpolationDrawOpts;
|
||||
|
||||
/* draw simple diamond-shape keyframe (with OpenGL) */
|
||||
void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha);
|
||||
void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha, short ipo_type);
|
||||
|
||||
/* ******************************* Methods ****************************** */
|
||||
|
||||
|
@@ -282,7 +282,7 @@ bool keyframe_region_circle_test(
|
||||
/* Destructive Editing API (keyframes_general.c) */
|
||||
|
||||
void delete_fcurve_key(struct FCurve *fcu, int index, bool do_recalc);
|
||||
bool delete_fcurve_keys(struct FCurve *fcu);
|
||||
bool delete_fcurve_keys(struct FCurve *fcu, bool resize_handles);
|
||||
void clear_fcurve_keys(struct FCurve *fcu);
|
||||
void duplicate_fcurve_keys(struct FCurve *fcu);
|
||||
|
||||
|
@@ -256,7 +256,7 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha,
|
||||
* - yscale: 0.3 * h (found out experimentally... dunno why!)
|
||||
* - sel: true (so that "keyframe" state shows the iconic yellow icon)
|
||||
*/
|
||||
draw_keyframe_shape(xco, yco, 1.0f, 0.3f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha);
|
||||
draw_keyframe_shape(xco, yco, 1.0f, 0.3f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha, KEYFRAME_IPOTYPE_NONE);
|
||||
|
||||
UI_Theme_Restore(&theme_state);
|
||||
}
|
||||
|
@@ -688,6 +688,9 @@ static void insert_action_keys(bAnimContext *ac, short mode)
|
||||
/* init keyframing flag */
|
||||
flag = ANIM_get_keyframing_flags(scene, 1);
|
||||
|
||||
/* ignore cycle aware setting in action editor for now */
|
||||
flag &= ~INSERTKEY_CYCLE_AWARE;
|
||||
|
||||
/* insert keyframes */
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
||||
@@ -906,7 +909,7 @@ static bool delete_action_keys(bAnimContext *ac)
|
||||
AnimData *adt = ale->adt;
|
||||
|
||||
/* delete selected keyframes only */
|
||||
changed = delete_fcurve_keys(fcu);
|
||||
changed = delete_fcurve_keys(fcu, true);
|
||||
|
||||
/* Only delete curve too if it won't be doing anything anymore */
|
||||
if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) {
|
||||
|
@@ -550,6 +550,9 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
|
||||
|
||||
/* init keyframing flag */
|
||||
flag = ANIM_get_keyframing_flags(scene, 1);
|
||||
|
||||
/* ignore cycle aware setting in graph editor for now */
|
||||
flag &= ~INSERTKEY_CYCLE_AWARE;
|
||||
|
||||
/* insert keyframes */
|
||||
if (mode & GRAPHKEYS_INSERTKEY_CURSOR) {
|
||||
@@ -1014,7 +1017,7 @@ static bool delete_graph_keys(bAnimContext *ac)
|
||||
bool changed;
|
||||
|
||||
/* delete selected keyframes only */
|
||||
changed = delete_fcurve_keys(fcu);
|
||||
changed = delete_fcurve_keys(fcu, true);
|
||||
|
||||
if (changed) {
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
|
@@ -139,7 +139,7 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d,
|
||||
* - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction
|
||||
*/
|
||||
for (ak = keys.first; ak; ak = ak->next)
|
||||
draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f);
|
||||
draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f, KEYFRAME_IPOTYPE_NONE);
|
||||
|
||||
/* free icons */
|
||||
BLI_dlrbTree_free(&keys);
|
||||
|
@@ -852,6 +852,7 @@ typedef enum eInsertKeyFlags {
|
||||
* Used by copy/paste code. */
|
||||
INSERTKEY_OVERWRITE_FULL = (1<<7),
|
||||
INSERTKEY_DRIVER = (1<<8), /* for driver FCurves, use driver's "input" value - for easier corrective driver setup */
|
||||
INSERTKEY_CYCLE_AWARE = (1<<9), /* for cyclic FCurves, adjust key timing to preserve the cycle period and flow */
|
||||
} eInsertKeyFlags;
|
||||
|
||||
/* ************************************************ */
|
||||
|
@@ -744,6 +744,7 @@ typedef enum eAutokey_Flag {
|
||||
/* toolsettings->autokey_flag */
|
||||
AUTOKEY_FLAG_ONLYKEYINGSET = (1 << 6),
|
||||
AUTOKEY_FLAG_NOWARNING = (1 << 7),
|
||||
AUTOKEY_FLAG_CYCLEAWARE = (1 << 8),
|
||||
ANIMRECORD_FLAG_WITHNLA = (1 << 10),
|
||||
} eAutokey_Flag;
|
||||
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_fcurve.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
@@ -394,6 +395,13 @@ static void rna_FCurve_RnaPath_set(PointerRNA *ptr, const char *value)
|
||||
fcu->rna_path = NULL;
|
||||
}
|
||||
|
||||
static int rna_FCurve_is_cyclic_get(PointerRNA *ptr)
|
||||
{
|
||||
FCurve *fcu = (FCurve *)ptr->data;
|
||||
|
||||
return BKE_fcurve_is_cyclic(fcu);
|
||||
}
|
||||
|
||||
static void rna_FCurve_group_set(PointerRNA *ptr, PointerRNA value)
|
||||
{
|
||||
ID *pid = (ID *)ptr->id.data;
|
||||
@@ -1986,6 +1994,12 @@ static void rna_def_fcurve(BlenderRNA *brna)
|
||||
"when evaluating");
|
||||
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "is_cyclic", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_FCurve_is_cyclic_get", NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Is Cyclic",
|
||||
"True when the curve is a simple infinite cycle because of the Cycles modifier");
|
||||
|
||||
/* Collections */
|
||||
prop = RNA_def_property(srna, "sampled_points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "fpt", "totvert");
|
||||
|
@@ -2843,7 +2843,13 @@ static void rna_def_tool_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Auto Keyframe Insert Keying Set",
|
||||
"Automatic keyframe insertion using active Keying Set only");
|
||||
RNA_def_property_ui_icon(prop, ICON_KEYINGSET, 0);
|
||||
|
||||
|
||||
prop = RNA_def_property(srna, "use_keyframe_cycle_aware", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_CYCLEAWARE);
|
||||
RNA_def_property_ui_text(prop, "Cycle-Aware Keying",
|
||||
"Keyframe insertion takes care to preserve Cyclic F-Curve period and continuity");
|
||||
RNA_def_property_ui_icon(prop, ICON_PROP_CON, 0);
|
||||
|
||||
/* Keyframing */
|
||||
prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "keyframe_type");
|
||||
|
Reference in New Issue
Block a user