Refactor: move code related to fcurve keyframe insertion
No functional changes. Move the functions `insert_vert_fcurve` and `insert_bezt_fcurve` from `ED_keyframing.hh` / `keyframing.cc` to `ANIM_fcurve.hh` / `fcurve.cc` in animrig Pull Request: https://projects.blender.org/blender/blender/pulls/114570
This commit is contained in:
committed by
Christoph Lendenfeld
parent
160111c318
commit
69a3c5c7fc
@@ -8,6 +8,7 @@
|
||||
* \brief Functions to modify FCurves.
|
||||
*/
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
struct AnimData;
|
||||
struct FCurve;
|
||||
|
||||
@@ -18,4 +19,36 @@ namespace blender::animrig {
|
||||
*/
|
||||
bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra);
|
||||
|
||||
/**
|
||||
* \brief Lesser Key-framing API call.
|
||||
*
|
||||
* Use this when validation of necessary animation data isn't necessary as it already
|
||||
* exists, and there is a #BezTriple that can be directly copied into the array.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \note any recalculate of the F-Curve that needs to be done will need to be done by the caller.
|
||||
*/
|
||||
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag);
|
||||
|
||||
/**
|
||||
* \brief Main Key-framing API call.
|
||||
*
|
||||
* Use this when validation of necessary animation data isn't necessary as it
|
||||
* already exists. It will insert a keyframe using the current value being keyframed.
|
||||
* Returns the index at which a keyframe was added (or -1 if failed).
|
||||
*
|
||||
* This function is a wrapper for #insert_bezt_fcurve(), and should be used when
|
||||
* adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
|
||||
* It returns the index at which the keyframe was added.
|
||||
*
|
||||
* \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
|
||||
* \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added
|
||||
* and/or whether updates get done.
|
||||
*/
|
||||
int insert_vert_fcurve(
|
||||
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag);
|
||||
|
||||
} // namespace blender::animrig
|
||||
|
||||
@@ -6,10 +6,14 @@
|
||||
* \ingroup animrig
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <string.h>
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "DNA_anim_types.h"
|
||||
#include "ED_anim_api.hh"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace blender::animrig {
|
||||
|
||||
@@ -33,4 +37,270 @@ bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
/* KEYFRAME INSERTION */
|
||||
|
||||
/* -------------- BezTriple Insertion -------------------- */
|
||||
|
||||
/* Change the Y position of a keyframe to match the input, adjusting handles. */
|
||||
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? */
|
||||
}
|
||||
|
||||
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* are there already keyframes? */
|
||||
if (fcu->bezt) {
|
||||
bool replace;
|
||||
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
|
||||
|
||||
/* replace an existing keyframe? */
|
||||
if (replace) {
|
||||
/* sanity check: 'i' may in rare cases exceed arraylen */
|
||||
if ((i >= 0) && (i < fcu->totvert)) {
|
||||
if (flag & INSERTKEY_OVERWRITE_FULL) {
|
||||
fcu->bezt[i] = *bezt;
|
||||
}
|
||||
else {
|
||||
replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
|
||||
}
|
||||
|
||||
if (flag & INSERTKEY_CYCLE_AWARE) {
|
||||
/* If replacing an end point of a cyclic curve without offset,
|
||||
* modify the other end too. */
|
||||
if (ELEM(i, 0, fcu->totvert - 1) && BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT)
|
||||
{
|
||||
replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Keyframing modes allow not replacing the keyframe. */
|
||||
else if ((flag & INSERTKEY_REPLACE) == 0) {
|
||||
/* insert new - if we're not restricted to replacing keyframes only */
|
||||
BezTriple *newb = static_cast<BezTriple *>(
|
||||
MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple"));
|
||||
|
||||
/* Add the beztriples that should occur before the beztriple to be pasted
|
||||
* (originally in fcu). */
|
||||
if (i > 0) {
|
||||
memcpy(newb, fcu->bezt, i * sizeof(BezTriple));
|
||||
}
|
||||
|
||||
/* add beztriple to paste at index i */
|
||||
*(newb + i) = *bezt;
|
||||
|
||||
/* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */
|
||||
if (i < fcu->totvert) {
|
||||
memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple));
|
||||
}
|
||||
|
||||
/* replace (+ free) old with new, only if necessary to do so */
|
||||
MEM_freeN(fcu->bezt);
|
||||
fcu->bezt = newb;
|
||||
|
||||
fcu->totvert++;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* no keyframes already, but can only add if...
|
||||
* 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know
|
||||
* 2) there are no samples on the curve
|
||||
* NOTE: maybe we may want to allow this later when doing samples -> bezt conversions,
|
||||
* but for now, having both is asking for trouble
|
||||
*/
|
||||
else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == nullptr)) {
|
||||
/* create new keyframes array */
|
||||
fcu->bezt = static_cast<BezTriple *>(MEM_callocN(sizeof(BezTriple), "beztriple"));
|
||||
*(fcu->bezt) = *bezt;
|
||||
fcu->totvert = 1;
|
||||
}
|
||||
/* cannot add anything */
|
||||
else {
|
||||
/* return error code -1 to prevent any misunderstandings */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we need to return the index, so that some tools which do post-processing can
|
||||
* detect where we added the BezTriple in the array
|
||||
*/
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the FCurve to allow insertion of `bezt` without modifying the curve shape.
|
||||
*
|
||||
* Checks whether it is necessary to apply Bezier subdivision due to involvement of non-auto
|
||||
* handles. If necessary, changes `bezt` handles from Auto to Aligned.
|
||||
*
|
||||
* \param bezt: key being inserted
|
||||
* \param prev: keyframe before that key
|
||||
* \param next: keyframe after that key
|
||||
*/
|
||||
static void subdivide_nonauto_handles(const 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. */
|
||||
const bool bezt_auto = BEZT_IS_AUTOH(bezt) || (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT);
|
||||
const bool prev_auto = BEZT_IS_AUTOH(prev) || (prev->h2 == HD_VECT);
|
||||
const 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_fcurve_bezt_subdivide_handles(bezt, prev, next, &delta)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decide when to force auto to manual. */
|
||||
if (!BEZT_IS_AUTOH(bezt)) {
|
||||
return;
|
||||
}
|
||||
if ((prev_auto || next_auto) && fcu->auto_smoothing == FCURVE_SMOOTH_CONT_ACCEL) {
|
||||
const float hx = bezt->vec[1][0] - bezt->vec[0][0];
|
||||
const float dx = bezt->vec[1][0] - prev->vec[1][0];
|
||||
|
||||
/* This mode always uses 1/3 of key distance for handle x size. */
|
||||
const bool auto_works_well = fabsf(hx - dx / 3.0f) < 0.001f;
|
||||
if (auto_works_well) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off auto mode. */
|
||||
bezt->h1 = bezt->h2 = HD_ALIGN;
|
||||
}
|
||||
|
||||
int insert_vert_fcurve(
|
||||
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
|
||||
{
|
||||
BezTriple beztr = {{{0}}};
|
||||
uint oldTot = fcu->totvert;
|
||||
int a;
|
||||
|
||||
/* set all three points, for nicer start position
|
||||
* NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok...
|
||||
*/
|
||||
beztr.vec[0][0] = x - 1.0f;
|
||||
beztr.vec[0][1] = y;
|
||||
beztr.vec[1][0] = x;
|
||||
beztr.vec[1][1] = y;
|
||||
beztr.vec[2][0] = x + 1.0f;
|
||||
beztr.vec[2][1] = y;
|
||||
beztr.f1 = beztr.f2 = beztr.f3 = SELECT;
|
||||
|
||||
/* set default handle types and interpolation mode */
|
||||
if (flag & INSERTKEY_NO_USERPREF) {
|
||||
/* for Py-API, we want scripts to have predictable behavior,
|
||||
* hence the option to not depend on the userpref defaults
|
||||
*/
|
||||
beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
|
||||
beztr.ipo = BEZT_IPO_BEZ;
|
||||
}
|
||||
else {
|
||||
/* For UI usage - defaults should come from the user-preferences and/or tool-settings. */
|
||||
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
|
||||
|
||||
/* use default interpolation mode, with exceptions for int/discrete values */
|
||||
beztr.ipo = U.ipo_new;
|
||||
}
|
||||
|
||||
/* interpolation type used is constrained by the type of values the curve can take */
|
||||
if (fcu->flag & FCURVE_DISCRETE_VALUES) {
|
||||
beztr.ipo = BEZT_IPO_CONST;
|
||||
}
|
||||
else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) {
|
||||
beztr.ipo = BEZT_IPO_LIN;
|
||||
}
|
||||
|
||||
/* set keyframe type value (supplied), which should come from the scene settings in most cases */
|
||||
BEZKEYTYPE(&beztr) = keyframe_type;
|
||||
|
||||
/* set default values for "easing" interpolation mode settings
|
||||
* NOTE: Even if these modes aren't currently used, if users switch
|
||||
* to these later, we want these to work in a sane way out of
|
||||
* the box.
|
||||
*/
|
||||
|
||||
/* "back" easing - this value used to be used when overshoot=0, but that
|
||||
* introduced discontinuities in how the param worked. */
|
||||
beztr.back = 1.70158f;
|
||||
|
||||
/* "elastic" easing - values here were hand-optimized for a default duration of
|
||||
* ~10 frames (typical mograph motion length) */
|
||||
beztr.amplitude = 0.8f;
|
||||
beztr.period = 4.1f;
|
||||
|
||||
/* add temp beztriple to keyframes */
|
||||
a = insert_bezt_fcurve(fcu, &beztr, flag);
|
||||
BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[a]);
|
||||
|
||||
/* what if 'a' is a negative index?
|
||||
* for now, just exit to prevent any segfaults
|
||||
*/
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set handle-type and interpolation. */
|
||||
if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) {
|
||||
BezTriple *bezt = (fcu->bezt + a);
|
||||
|
||||
/* Set interpolation from previous (if available),
|
||||
* but only if we didn't just replace some keyframe:
|
||||
* - Replacement is indicated by no-change in number of verts.
|
||||
* - When replacing, the user may have specified some interpolation that should be kept.
|
||||
*/
|
||||
if (fcu->totvert > oldTot) {
|
||||
if (a > 0) {
|
||||
bezt->ipo = (bezt - 1)->ipo;
|
||||
}
|
||||
else if (a < fcu->totvert - 1) {
|
||||
bezt->ipo = (bezt + 1)->ipo;
|
||||
}
|
||||
|
||||
if (0 < a && 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 auto-handle needing to be calculated twice)
|
||||
*/
|
||||
if ((flag & INSERTKEY_FAST) == 0) {
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
}
|
||||
|
||||
/* return the index at which the keyframe was added */
|
||||
return a;
|
||||
}
|
||||
|
||||
} // namespace blender::animrig
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
#include "RNA_path.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include "anim_intern.h"
|
||||
|
||||
/* ************************************************** */
|
||||
@@ -122,9 +124,9 @@ FCurve *alloc_driver_fcurve(const char rna_path[],
|
||||
* - These are configured to 0,0 and 1,1 to give a 1-1 mapping
|
||||
* which can be easily tweaked from there.
|
||||
*/
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
|
||||
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "ED_keyframes_edit.hh"
|
||||
#include "ED_keyframing.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
/* This file contains code for various keyframe-editing tools which are 'destructive'
|
||||
* (i.e. they will modify the order of the keyframes, and change the size of the array).
|
||||
* While some of these tools may eventually be moved out into blenkernel, for now, it is
|
||||
@@ -117,7 +119,7 @@ void clean_fcurve(bAnimContext *ac,
|
||||
|
||||
/* now insert first keyframe, as it should be ok */
|
||||
bezt = old_bezts;
|
||||
insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
if (!(bezt->f2 & SELECT)) {
|
||||
lastb = fcu->bezt;
|
||||
lastb->f1 = lastb->f2 = lastb->f3 = 0;
|
||||
@@ -149,7 +151,7 @@ void clean_fcurve(bAnimContext *ac,
|
||||
cur[1] = bezt->vec[1][1];
|
||||
|
||||
if (only_selected_keys && !(bezt->f2 & SELECT)) {
|
||||
insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
lastb = (fcu->bezt + (fcu->totvert - 1));
|
||||
lastb->f1 = lastb->f2 = lastb->f3 = 0;
|
||||
continue;
|
||||
@@ -166,7 +168,7 @@ void clean_fcurve(bAnimContext *ac,
|
||||
if (cur[1] > next[1]) {
|
||||
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
|
||||
/* add new keyframe */
|
||||
insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +176,7 @@ void clean_fcurve(bAnimContext *ac,
|
||||
/* 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, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,18 +186,18 @@ void clean_fcurve(bAnimContext *ac,
|
||||
/* 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, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
}
|
||||
else if (IS_EQT(cur[1], next[1], thresh) == 0) {
|
||||
/* add new keyframe */
|
||||
insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(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, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1077,7 +1079,7 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
|
||||
BezTriple *bezt = (old_bezts + i);
|
||||
bezt->f2 &= ~BEZT_FLAG_IGNORE_TAG;
|
||||
if ((bezt->f2 & BEZT_FLAG_TEMP_TAG) == 0) {
|
||||
insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, eInsertKeyFlags(0));
|
||||
}
|
||||
}
|
||||
/* now free the memory used by the old BezTriples */
|
||||
@@ -1270,7 +1272,7 @@ void bake_fcurve_segments(FCurve *fcu)
|
||||
|
||||
/* add keyframes with these, tagging as 'breakdowns' */
|
||||
for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, eInsertKeyFlags(1));
|
||||
}
|
||||
|
||||
@@ -1712,7 +1714,7 @@ static void paste_animedit_keys_fcurve(
|
||||
* NOTE: we do not want to inherit handles from existing keyframes in this case!
|
||||
*/
|
||||
|
||||
insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
|
||||
blender::animrig::insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
|
||||
|
||||
/* un-apply offset from src beztriple after copying */
|
||||
sub_v2_v2(bezt->vec[0], offset);
|
||||
|
||||
@@ -212,271 +212,6 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
/* KEYFRAME INSERTION */
|
||||
|
||||
/* -------------- BezTriple Insertion -------------------- */
|
||||
|
||||
/* Change the Y position of a keyframe to match the input, adjusting handles. */
|
||||
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? */
|
||||
}
|
||||
|
||||
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* are there already keyframes? */
|
||||
if (fcu->bezt) {
|
||||
bool replace;
|
||||
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
|
||||
|
||||
/* replace an existing keyframe? */
|
||||
if (replace) {
|
||||
/* sanity check: 'i' may in rare cases exceed arraylen */
|
||||
if ((i >= 0) && (i < fcu->totvert)) {
|
||||
if (flag & INSERTKEY_OVERWRITE_FULL) {
|
||||
fcu->bezt[i] = *bezt;
|
||||
}
|
||||
else {
|
||||
replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
|
||||
}
|
||||
|
||||
if (flag & INSERTKEY_CYCLE_AWARE) {
|
||||
/* If replacing an end point of a cyclic curve without offset,
|
||||
* modify the other end too. */
|
||||
if (ELEM(i, 0, fcu->totvert - 1) && BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT)
|
||||
{
|
||||
replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Keyframing modes allow not replacing the keyframe. */
|
||||
else if ((flag & INSERTKEY_REPLACE) == 0) {
|
||||
/* insert new - if we're not restricted to replacing keyframes only */
|
||||
BezTriple *newb = static_cast<BezTriple *>(
|
||||
MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple"));
|
||||
|
||||
/* Add the beztriples that should occur before the beztriple to be pasted
|
||||
* (originally in fcu). */
|
||||
if (i > 0) {
|
||||
memcpy(newb, fcu->bezt, i * sizeof(BezTriple));
|
||||
}
|
||||
|
||||
/* add beztriple to paste at index i */
|
||||
*(newb + i) = *bezt;
|
||||
|
||||
/* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */
|
||||
if (i < fcu->totvert) {
|
||||
memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple));
|
||||
}
|
||||
|
||||
/* replace (+ free) old with new, only if necessary to do so */
|
||||
MEM_freeN(fcu->bezt);
|
||||
fcu->bezt = newb;
|
||||
|
||||
fcu->totvert++;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* no keyframes already, but can only add if...
|
||||
* 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know
|
||||
* 2) there are no samples on the curve
|
||||
* NOTE: maybe we may want to allow this later when doing samples -> bezt conversions,
|
||||
* but for now, having both is asking for trouble
|
||||
*/
|
||||
else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == nullptr)) {
|
||||
/* create new keyframes array */
|
||||
fcu->bezt = static_cast<BezTriple *>(MEM_callocN(sizeof(BezTriple), "beztriple"));
|
||||
*(fcu->bezt) = *bezt;
|
||||
fcu->totvert = 1;
|
||||
}
|
||||
/* cannot add anything */
|
||||
else {
|
||||
/* return error code -1 to prevent any misunderstandings */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we need to return the index, so that some tools which do post-processing can
|
||||
* detect where we added the BezTriple in the array
|
||||
*/
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the FCurve to allow insertion of `bezt` without modifying the curve shape.
|
||||
*
|
||||
* Checks whether it is necessary to apply Bezier subdivision due to involvement of non-auto
|
||||
* handles. If necessary, changes `bezt` handles from Auto to Aligned.
|
||||
*
|
||||
* \param bezt: key being inserted
|
||||
* \param prev: keyframe before that key
|
||||
* \param next: keyframe after that key
|
||||
*/
|
||||
static void subdivide_nonauto_handles(const 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. */
|
||||
const bool bezt_auto = BEZT_IS_AUTOH(bezt) || (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT);
|
||||
const bool prev_auto = BEZT_IS_AUTOH(prev) || (prev->h2 == HD_VECT);
|
||||
const 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_fcurve_bezt_subdivide_handles(bezt, prev, next, &delta)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decide when to force auto to manual. */
|
||||
if (!BEZT_IS_AUTOH(bezt)) {
|
||||
return;
|
||||
}
|
||||
if ((prev_auto || next_auto) && fcu->auto_smoothing == FCURVE_SMOOTH_CONT_ACCEL) {
|
||||
const float hx = bezt->vec[1][0] - bezt->vec[0][0];
|
||||
const float dx = bezt->vec[1][0] - prev->vec[1][0];
|
||||
|
||||
/* This mode always uses 1/3 of key distance for handle x size. */
|
||||
const bool auto_works_well = fabsf(hx - dx / 3.0f) < 0.001f;
|
||||
if (auto_works_well) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off auto mode. */
|
||||
bezt->h1 = bezt->h2 = HD_ALIGN;
|
||||
}
|
||||
|
||||
int insert_vert_fcurve(
|
||||
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
|
||||
{
|
||||
BezTriple beztr = {{{0}}};
|
||||
uint oldTot = fcu->totvert;
|
||||
int a;
|
||||
|
||||
/* set all three points, for nicer start position
|
||||
* NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok...
|
||||
*/
|
||||
beztr.vec[0][0] = x - 1.0f;
|
||||
beztr.vec[0][1] = y;
|
||||
beztr.vec[1][0] = x;
|
||||
beztr.vec[1][1] = y;
|
||||
beztr.vec[2][0] = x + 1.0f;
|
||||
beztr.vec[2][1] = y;
|
||||
beztr.f1 = beztr.f2 = beztr.f3 = SELECT;
|
||||
|
||||
/* set default handle types and interpolation mode */
|
||||
if (flag & INSERTKEY_NO_USERPREF) {
|
||||
/* for Py-API, we want scripts to have predictable behavior,
|
||||
* hence the option to not depend on the userpref defaults
|
||||
*/
|
||||
beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
|
||||
beztr.ipo = BEZT_IPO_BEZ;
|
||||
}
|
||||
else {
|
||||
/* For UI usage - defaults should come from the user-preferences and/or tool-settings. */
|
||||
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
|
||||
|
||||
/* use default interpolation mode, with exceptions for int/discrete values */
|
||||
beztr.ipo = U.ipo_new;
|
||||
}
|
||||
|
||||
/* interpolation type used is constrained by the type of values the curve can take */
|
||||
if (fcu->flag & FCURVE_DISCRETE_VALUES) {
|
||||
beztr.ipo = BEZT_IPO_CONST;
|
||||
}
|
||||
else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) {
|
||||
beztr.ipo = BEZT_IPO_LIN;
|
||||
}
|
||||
|
||||
/* set keyframe type value (supplied), which should come from the scene settings in most cases */
|
||||
BEZKEYTYPE(&beztr) = keyframe_type;
|
||||
|
||||
/* set default values for "easing" interpolation mode settings
|
||||
* NOTE: Even if these modes aren't currently used, if users switch
|
||||
* to these later, we want these to work in a sane way out of
|
||||
* the box.
|
||||
*/
|
||||
|
||||
/* "back" easing - this value used to be used when overshoot=0, but that
|
||||
* introduced discontinuities in how the param worked. */
|
||||
beztr.back = 1.70158f;
|
||||
|
||||
/* "elastic" easing - values here were hand-optimized for a default duration of
|
||||
* ~10 frames (typical mograph motion length) */
|
||||
beztr.amplitude = 0.8f;
|
||||
beztr.period = 4.1f;
|
||||
|
||||
/* add temp beztriple to keyframes */
|
||||
a = insert_bezt_fcurve(fcu, &beztr, flag);
|
||||
BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[a]);
|
||||
|
||||
/* what if 'a' is a negative index?
|
||||
* for now, just exit to prevent any segfaults
|
||||
*/
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set handle-type and interpolation. */
|
||||
if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) {
|
||||
BezTriple *bezt = (fcu->bezt + a);
|
||||
|
||||
/* Set interpolation from previous (if available),
|
||||
* but only if we didn't just replace some keyframe:
|
||||
* - Replacement is indicated by no-change in number of verts.
|
||||
* - When replacing, the user may have specified some interpolation that should be kept.
|
||||
*/
|
||||
if (fcu->totvert > oldTot) {
|
||||
if (a > 0) {
|
||||
bezt->ipo = (bezt - 1)->ipo;
|
||||
}
|
||||
else if (a < fcu->totvert - 1) {
|
||||
bezt->ipo = (bezt + 1)->ipo;
|
||||
}
|
||||
|
||||
if (0 < a && 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 auto-handle needing to be calculated twice)
|
||||
*/
|
||||
if ((flag & INSERTKEY_FAST) == 0) {
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
}
|
||||
|
||||
/* return the index at which the keyframe was added */
|
||||
return a;
|
||||
}
|
||||
|
||||
/* ------------------------- Insert Key API ------------------------- */
|
||||
|
||||
void ED_keyframes_add(FCurve *fcu, int num_keys_to_add)
|
||||
|
||||
@@ -67,13 +67,14 @@
|
||||
#include "ED_armature.hh"
|
||||
#include "ED_keyframes_edit.hh"
|
||||
#include "ED_keyframes_keylist.hh"
|
||||
#include "ED_keyframing.hh"
|
||||
#include "ED_markers.hh"
|
||||
#include "ED_numinput.hh"
|
||||
#include "ED_screen.hh"
|
||||
#include "ED_space_api.hh"
|
||||
#include "ED_util.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_immediate_util.h"
|
||||
#include "GPU_matrix.h"
|
||||
@@ -1740,7 +1741,7 @@ static void propagate_curve_values(ListBase /*tPChanFCurveLink*/ *pflinks,
|
||||
FCurve *fcu = (FCurve *)ld->data;
|
||||
const float current_fcu_value = evaluate_fcurve(fcu, source_frame);
|
||||
LISTBASE_FOREACH (FrameLink *, target_frame, target_frames) {
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, target_frame->frame, current_fcu_value, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,38 +67,6 @@ void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop);
|
||||
|
||||
/* -------- */
|
||||
|
||||
/**
|
||||
* \brief Lesser Key-framing API call.
|
||||
*
|
||||
* Use this when validation of necessary animation data isn't necessary as it already
|
||||
* exists, and there is a #BezTriple that can be directly copied into the array.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \note any recalculate of the F-Curve that needs to be done will need to be done by the caller.
|
||||
*/
|
||||
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag);
|
||||
|
||||
/**
|
||||
* \brief Main Key-framing API call.
|
||||
*
|
||||
* Use this when validation of necessary animation data isn't necessary as it
|
||||
* already exists. It will insert a keyframe using the current value being keyframed.
|
||||
* Returns the index at which a keyframe was added (or -1 if failed).
|
||||
*
|
||||
* This function is a wrapper for #insert_bezt_fcurve(), and should be used when
|
||||
* adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
|
||||
* It returns the index at which the keyframe was added.
|
||||
*
|
||||
* \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
|
||||
* \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added
|
||||
* and/or whether updates get done.
|
||||
*/
|
||||
int insert_vert_fcurve(
|
||||
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag);
|
||||
|
||||
/**
|
||||
* Add the given number of keyframes to the FCurve. Their coordinates are
|
||||
* uninitialized, so the curve should not be used without further attention.
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include "UI_view2d.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
#include "ANIM_keyframing.hh"
|
||||
#include "ED_anim_api.hh"
|
||||
#include "ED_gpencil_legacy.hh"
|
||||
@@ -859,7 +860,7 @@ static void insert_fcurve_key(bAnimContext *ac,
|
||||
}
|
||||
|
||||
const float curval = evaluate_fcurve(fcu, cfra);
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, cfra, curval, eBezTriple_KeyframeType(ts->keyframe_type), eInsertKeyFlags(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_view2d.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
#include "ANIM_keyframing.hh"
|
||||
#include "ED_anim_api.hh"
|
||||
#include "ED_keyframes_edit.hh"
|
||||
@@ -179,7 +180,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
|
||||
}
|
||||
|
||||
/* Insert keyframe directly into the F-Curve. */
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, x, y, eBezTriple_KeyframeType(ts->keyframe_type), eInsertKeyFlags(0));
|
||||
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
@@ -228,7 +229,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
|
||||
}
|
||||
|
||||
const float curval = evaluate_fcurve_only_curve(fcu, cfra);
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, cfra, curval, eBezTriple_KeyframeType(ts->keyframe_type), eInsertKeyFlags(0));
|
||||
}
|
||||
|
||||
@@ -345,7 +346,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
|
||||
val = val * scale - offset;
|
||||
|
||||
/* Insert keyframe on the specified frame + value. */
|
||||
insert_vert_fcurve(
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, frame, val, eBezTriple_KeyframeType(ts->keyframe_type), eInsertKeyFlags(0));
|
||||
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "ED_keyframing.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_string.h"
|
||||
@@ -65,7 +67,7 @@ void AnimationImporter::add_bezt(FCurve *fcu,
|
||||
bez.ipo = ipo; /* use default interpolation mode here... */
|
||||
bez.f1 = bez.f2 = bez.f3 = SELECT;
|
||||
bez.h1 = bez.h2 = HD_AUTO;
|
||||
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
blender::animrig::insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
}
|
||||
|
||||
@@ -132,7 +134,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
|
||||
#endif
|
||||
bez.f1 = bez.f2 = bez.f3 = SELECT;
|
||||
|
||||
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
blender::animrig::insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
}
|
||||
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
|
||||
@@ -103,7 +103,7 @@ void BCAnimationCurve::create_bezt(float frame, float output)
|
||||
bez.ipo = U.ipo_new; /* use default interpolation mode here... */
|
||||
bez.f1 = bez.f2 = bez.f3 = SELECT;
|
||||
bez.h1 = bez.h2 = HD_AUTO;
|
||||
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
blender::animrig::insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
}
|
||||
|
||||
@@ -315,7 +315,8 @@ void BCAnimationCurve::clean_handles()
|
||||
BezTriple *bezt = &old_bezts[i];
|
||||
float x = bezt->vec[1][0];
|
||||
float y = bezt->vec[1][1];
|
||||
insert_vert_fcurve(fcurve, x, y, (eBezTriple_KeyframeType)BEZKEYTYPE(bezt), INSERTKEY_NOFLAGS);
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcurve, x, y, (eBezTriple_KeyframeType)BEZKEYTYPE(bezt), INSERTKEY_NOFLAGS);
|
||||
BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
|
||||
lastb->f1 = lastb->f2 = lastb->f3 = 0;
|
||||
}
|
||||
@@ -380,7 +381,8 @@ void BCAnimationCurve::add_value(const float val, const int frame_index)
|
||||
{
|
||||
FCurve *fcu = get_edit_fcurve();
|
||||
fcu->auto_smoothing = U.auto_smoothing_new;
|
||||
insert_vert_fcurve(fcu, frame_index, val, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS);
|
||||
blender::animrig::insert_vert_fcurve(
|
||||
fcu, frame_index, val, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS);
|
||||
|
||||
if (fcu->totvert == 1) {
|
||||
init_range(val);
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
|
||||
#include "ED_anim_api.hh"
|
||||
#include "ED_keyframes_edit.hh"
|
||||
#include "ED_keyframing.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
typedef float(TangentPoint)[2];
|
||||
|
||||
|
||||
@@ -186,6 +186,7 @@ set(LIB
|
||||
bf_blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::dna
|
||||
PRIVATE bf::animrig
|
||||
bf_imbuf
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
bf_io_common
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "ED_keyframing.hh"
|
||||
#include "ED_mesh.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#include <iostream>
|
||||
@@ -93,7 +95,7 @@ void add_bezt(FCurve *fcu,
|
||||
bez.ipo = ipo; /* use default interpolation mode here... */
|
||||
bez.f1 = bez.f2 = bez.f3 = SELECT;
|
||||
bez.h1 = bez.h2 = HD_AUTO;
|
||||
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
blender::animrig::insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#include "ED_keyframes_edit.hh"
|
||||
#include "ED_keyframing.hh"
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
# include "ANIM_fcurve.hh"
|
||||
#endif
|
||||
|
||||
const EnumPropertyItem rna_enum_fmodifier_type_items[] = {
|
||||
{FMODIFIER_TYPE_NULL, "nullptr", 0, "Invalid", ""},
|
||||
{FMODIFIER_TYPE_GENERATOR,
|
||||
@@ -1051,11 +1055,11 @@ static void rna_FModifierStepped_frame_end_set(PointerRNA *ptr, float value)
|
||||
static BezTriple *rna_FKeyframe_points_insert(
|
||||
ID *id, FCurve *fcu, Main *bmain, float frame, float value, int keyframe_type, int flag)
|
||||
{
|
||||
int index = insert_vert_fcurve(fcu,
|
||||
frame,
|
||||
value,
|
||||
eBezTriple_KeyframeType(keyframe_type),
|
||||
eInsertKeyFlags(flag) | INSERTKEY_NO_USERPREF);
|
||||
int index = blender::animrig::insert_vert_fcurve(fcu,
|
||||
frame,
|
||||
value,
|
||||
eBezTriple_KeyframeType(keyframe_type),
|
||||
eInsertKeyFlags(flag) | INSERTKEY_NO_USERPREF);
|
||||
|
||||
if ((fcu->bezt) && (index >= 0)) {
|
||||
rna_tag_animation_update(bmain, id);
|
||||
|
||||
Reference in New Issue
Block a user