Animation: Paste Keys in Graph Editor with value offset #104512
|
@ -20,12 +20,14 @@
|
|||
#include "DNA_anim_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
@ -1074,7 +1076,7 @@ static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt)
|
|||
|
||||
/* helper for paste_animedit_keys() - performs the actual pasting */
|
||||
static void paste_animedit_keys_fcurve(
|
||||
FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
|
||||
FCurve *fcu, tAnimCopybufItem *aci, float offset[2], const eKeyMergeMode merge_mode, bool flip)
|
||||
{
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
|
@ -1101,12 +1103,12 @@ static void paste_animedit_keys_fcurve(
|
|||
float f_max;
|
||||
|
||||
if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) {
|
||||
f_min = aci->bezt[0].vec[1][0] + offset;
|
||||
f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset;
|
||||
f_min = aci->bezt[0].vec[1][0] + offset[0];
|
||||
f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset[0];
|
||||
}
|
||||
else { /* Entire Range */
|
||||
f_min = animcopy_firstframe + offset;
|
||||
f_max = animcopy_lastframe + offset;
|
||||
f_min = animcopy_firstframe + offset[0];
|
||||
f_max = animcopy_lastframe + offset[0];
|
||||
}
|
||||
|
||||
/* remove keys in range */
|
||||
|
@ -1132,9 +1134,9 @@ static void paste_animedit_keys_fcurve(
|
|||
do_curve_mirror_flippping(aci, bezt);
|
||||
}
|
||||
|
||||
bezt->vec[0][0] += offset;
|
||||
bezt->vec[1][0] += offset;
|
||||
bezt->vec[2][0] += offset;
|
||||
add_v2_v2(bezt->vec[0], offset);
|
||||
add_v2_v2(bezt->vec[1], offset);
|
||||
add_v2_v2(bezt->vec[2], offset);
|
||||
|
||||
/* insert the keyframe
|
||||
* NOTE: we do not want to inherit handles from existing keyframes in this case!
|
||||
|
@ -1143,9 +1145,9 @@ static void paste_animedit_keys_fcurve(
|
|||
insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
|
||||
|
||||
/* un-apply offset from src beztriple after copying */
|
||||
bezt->vec[0][0] -= offset;
|
||||
bezt->vec[1][0] -= offset;
|
||||
bezt->vec[2][0] -= offset;
|
||||
sub_v2_v2(bezt->vec[0], offset);
|
||||
sub_v2_v2(bezt->vec[1], offset);
|
||||
sub_v2_v2(bezt->vec[2], offset);
|
||||
|
||||
if (flip) {
|
||||
do_curve_mirror_flippping(aci, bezt);
|
||||
|
@ -1172,6 +1174,34 @@ const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_keyframe_paste_offset_value[] = {
|
||||
{KEYFRAME_PASTE_VALUE_OFFSET_LEFT_KEY,
|
||||
"LEFT_KEY",
|
||||
0,
|
||||
"Left Key",
|
||||
"Paste keys with the first key matching the key left of the cursor"},
|
||||
{KEYFRAME_PASTE_VALUE_OFFSET_RIGHT_KEY,
|
||||
"RIGHT_KEY",
|
||||
0,
|
||||
"Right Key",
|
||||
"Paste keys with the last key matching the key right of the cursor"},
|
||||
{KEYFRAME_PASTE_VALUE_OFFSET_CFRA,
|
||||
"CURRENT_FRAME",
|
||||
0,
|
||||
"Current Frame Value",
|
||||
"Paste keys relative to the value of the curve under the cursor"},
|
||||
{KEYFRAME_PASTE_VALUE_OFFSET_CURSOR,
|
||||
"CURSOR_VALUE",
|
||||
0,
|
||||
"Cursor Value",
|
||||
"Paste keys relative to the Y-Position of the cursor"},
|
||||
{KEYFRAME_PASTE_VALUE_OFFSET_NONE,
|
||||
"NONE",
|
||||
0,
|
||||
"No Offset",
|
||||
"Paste keys with the same value as they were copied"},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
|
||||
{KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
|
||||
{KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
|
||||
|
@ -1188,9 +1218,56 @@ const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static float paste_get_y_offset(bAnimContext *ac,
|
||||
tAnimCopybufItem *aci,
|
||||
bAnimListElem *ale,
|
||||
const eKeyPasteValueOffset value_offset_mode)
|
||||
{
|
||||
FCurve *fcu = (FCurve *)ale->data;
|
||||
const float cfra = BKE_scene_frame_get(ac->scene);
|
||||
|
||||
switch (value_offset_mode) {
|
||||
case KEYFRAME_PASTE_VALUE_OFFSET_CURSOR: {
|
||||
SpaceGraph *sipo = (SpaceGraph *)ac->sl;
|
||||
const float offset = sipo->cursorVal - aci->bezt[0].vec[1][1];
|
||||
return offset;
|
||||
}
|
||||
dr.sybren marked this conversation as resolved
|
||||
|
||||
case KEYFRAME_PASTE_VALUE_OFFSET_CFRA: {
|
||||
const float cfra_y = evaluate_fcurve(fcu, cfra);
|
||||
const float offset = cfra_y - aci->bezt[0].vec[1][1];
|
||||
return offset;
|
||||
}
|
||||
|
||||
case KEYFRAME_PASTE_VALUE_OFFSET_LEFT_KEY: {
|
||||
bool replace;
|
||||
const int fcu_index = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, cfra, fcu->totvert, &replace);
|
||||
BezTriple left_key = fcu->bezt[max_ii(fcu_index - 1, 0)];
|
||||
const float offset = left_key.vec[1][1] - aci->bezt[0].vec[1][1];
|
||||
return offset;
|
||||
}
|
||||
|
||||
case KEYFRAME_PASTE_VALUE_OFFSET_RIGHT_KEY: {
|
||||
bool replace;
|
||||
const int fcu_index = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, cfra, fcu->totvert, &replace);
|
||||
BezTriple right_key = fcu->bezt[min_ii(fcu_index, fcu->totvert - 1)];
|
||||
const float offset = right_key.vec[1][1] - aci->bezt[aci->totvert - 1].vec[1][1];
|
||||
return offset;
|
||||
}
|
||||
|
||||
case KEYFRAME_PASTE_VALUE_OFFSET_NONE:
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
You can remove the You can remove the `default:`, that way the compiler can complain when a new value was added to the enum, but not handled here.
|
||||
break;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
eKeyPasteError paste_animedit_keys(bAnimContext *ac,
|
||||
ListBase *anim_data,
|
||||
const eKeyPasteOffset offset_mode,
|
||||
const eKeyPasteValueOffset value_offset_mode,
|
||||
const eKeyMergeMode merge_mode,
|
||||
bool flip)
|
||||
{
|
||||
|
@ -1201,7 +1278,7 @@ eKeyPasteError paste_animedit_keys(bAnimContext *ac,
|
|||
const bool from_single = BLI_listbase_is_single(&animcopybuf);
|
||||
const bool to_simple = BLI_listbase_is_single(anim_data);
|
||||
|
||||
float offset = 0.0f;
|
||||
float offset[2];
|
||||
int pass;
|
||||
|
||||
/* check if buffer is empty */
|
||||
|
@ -1216,16 +1293,16 @@ eKeyPasteError paste_animedit_keys(bAnimContext *ac,
|
|||
/* methods of offset */
|
||||
switch (offset_mode) {
|
||||
case KEYFRAME_PASTE_OFFSET_CFRA_START:
|
||||
offset = (float)(scene->r.cfra - animcopy_firstframe);
|
||||
offset[0] = (float)(scene->r.cfra - animcopy_firstframe);
|
||||
break;
|
||||
case KEYFRAME_PASTE_OFFSET_CFRA_END:
|
||||
offset = (float)(scene->r.cfra - animcopy_lastframe);
|
||||
offset[0] = (float)(scene->r.cfra - animcopy_lastframe);
|
||||
break;
|
||||
case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
|
||||
offset = (float)(scene->r.cfra - animcopy_cfra);
|
||||
offset[0] = (float)(scene->r.cfra - animcopy_cfra);
|
||||
break;
|
||||
case KEYFRAME_PASTE_OFFSET_NONE:
|
||||
offset = 0.0f;
|
||||
offset[0] = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1238,6 +1315,7 @@ eKeyPasteError paste_animedit_keys(bAnimContext *ac,
|
|||
fcu = (FCurve *)ale->data; /* destination F-Curve */
|
||||
aci = animcopybuf.first;
|
||||
|
||||
offset[1] = paste_get_y_offset(ac, aci, ale, value_offset_mode);
|
||||
paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
}
|
||||
|
@ -1282,6 +1360,7 @@ eKeyPasteError paste_animedit_keys(bAnimContext *ac,
|
|||
if (aci) {
|
||||
totmatch++;
|
||||
|
||||
offset[1] = paste_get_y_offset(ac, aci, ale, value_offset_mode);
|
||||
if (adt) {
|
||||
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
|
||||
paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
|
||||
|
|
|
@ -218,6 +218,19 @@ typedef enum eKeyPasteOffset {
|
|||
KEYFRAME_PASTE_OFFSET_NONE,
|
||||
} eKeyPasteOffset;
|
||||
|
||||
typedef enum eKeyPasteValueOffset {
|
||||
/* Paste keys with the first key matching the key left of the cursor. */
|
||||
KEYFRAME_PASTE_VALUE_OFFSET_LEFT_KEY,
|
||||
/* Paste keys with the last key matching the key right of the cursor. */
|
||||
KEYFRAME_PASTE_VALUE_OFFSET_RIGHT_KEY,
|
||||
/* Paste keys relative to the value of the curve under the cursor. */
|
||||
KEYFRAME_PASTE_VALUE_OFFSET_CFRA,
|
||||
/* Paste values relative to the cursor position. */
|
||||
KEYFRAME_PASTE_VALUE_OFFSET_CURSOR,
|
||||
/* Paste keys with the exact copied value. */
|
||||
KEYFRAME_PASTE_VALUE_OFFSET_NONE,
|
||||
} eKeyPasteValueOffset;
|
||||
|
||||
typedef enum eKeyMergeMode {
|
||||
/* overlay existing with new keys */
|
||||
KEYFRAME_PASTE_MERGE_MIX,
|
||||
|
@ -427,6 +440,7 @@ short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
|
|||
eKeyPasteError paste_animedit_keys(struct bAnimContext *ac,
|
||||
ListBase *anim_data,
|
||||
eKeyPasteOffset offset_mode,
|
||||
eKeyPasteValueOffset value_offset_mode,
|
||||
eKeyMergeMode merge_mode,
|
||||
bool flip);
|
||||
|
||||
|
|
|
@ -533,8 +533,9 @@ static eKeyPasteError paste_action_keys(bAnimContext *ac,
|
|||
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
||||
}
|
||||
|
||||
/* paste keyframes */
|
||||
const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
|
||||
/* Value offset is always None because the user cannot see the effect of it. */
|
||||
const eKeyPasteError ok = paste_animedit_keys(
|
||||
ac, &anim_data, offset_mode, KEYFRAME_PASTE_VALUE_OFFSET_NONE, merge_mode, flip);
|
||||
|
||||
/* clean up */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
|
|
|
@ -475,6 +475,7 @@ static short copy_graph_keys(bAnimContext *ac)
|
|||
|
||||
static eKeyPasteError paste_graph_keys(bAnimContext *ac,
|
||||
const eKeyPasteOffset offset_mode,
|
||||
const eKeyPasteValueOffset value_offset_mode,
|
||||
const eKeyMergeMode merge_mode,
|
||||
bool flip)
|
||||
{
|
||||
|
@ -495,7 +496,8 @@ static eKeyPasteError paste_graph_keys(bAnimContext *ac,
|
|||
}
|
||||
|
||||
/* Paste keyframes. */
|
||||
const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
|
||||
const eKeyPasteError ok = paste_animedit_keys(
|
||||
ac, &anim_data, offset_mode, value_offset_mode, merge_mode, flip);
|
||||
|
||||
/* Clean up. */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
|
@ -544,6 +546,7 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
|
|||
bAnimContext ac;
|
||||
|
||||
const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
|
||||
const eKeyPasteValueOffset value_offset_mode = RNA_enum_get(op->ptr, "value_offset");
|
||||
const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
|
||||
const bool flipped = RNA_boolean_get(op->ptr, "flipped");
|
||||
|
||||
|
@ -555,7 +558,8 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
|
|||
/* Ac.reports by default will be the global reports list, which won't show warnings. */
|
||||
ac.reports = op->reports;
|
||||
|
||||
const eKeyPasteError kf_empty = paste_graph_keys(&ac, offset_mode, merge_mode, flipped);
|
||||
const eKeyPasteError kf_empty = paste_graph_keys(
|
||||
&ac, offset_mode, value_offset_mode, merge_mode, flipped);
|
||||
switch (kf_empty) {
|
||||
case KEYFRAME_PASTE_OK:
|
||||
break;
|
||||
|
@ -614,8 +618,14 @@ void GRAPH_OT_paste(wmOperatorType *ot)
|
|||
"offset",
|
||||
rna_enum_keyframe_paste_offset_items,
|
||||
KEYFRAME_PASTE_OFFSET_CFRA_START,
|
||||
"Offset",
|
||||
"Frame Offset",
|
||||
"Paste time offset of keys");
|
||||
RNA_def_enum(ot->srna,
|
||||
"value_offset",
|
||||
rna_enum_keyframe_paste_offset_value,
|
||||
KEYFRAME_PASTE_VALUE_OFFSET_NONE,
|
||||
"Value Offset",
|
||||
"Paste keys with a value offset");
|
||||
RNA_def_enum(ot->srna,
|
||||
"merge",
|
||||
rna_enum_keyframe_paste_merge_items,
|
||||
|
|
|
@ -242,6 +242,7 @@ DEF_ENUM(rna_enum_particle_edit_hair_brush_items)
|
|||
DEF_ENUM(rna_enum_particle_edit_disconnected_hair_brush_items)
|
||||
|
||||
DEF_ENUM(rna_enum_keyframe_paste_offset_items)
|
||||
DEF_ENUM(rna_enum_keyframe_paste_offset_value)
|
||||
DEF_ENUM(rna_enum_keyframe_paste_merge_items)
|
||||
|
||||
DEF_ENUM(rna_enum_transform_pivot_items_full)
|
||||
|
|
Loading…
Reference in New Issue
Instead of having a variable
offset
, and having to track how it's changed in the code below, IMO it's better to just replace thiswith
With this change, you don't even need the top-level variable
float offset
any more. If you want to keep a variable between the calculation and thereturn
(can aid in debugging the code), use aconst float offset = ...
constant scoped to thecase
statement instead. Or justreturn sipo->cursorVal - aci->bezt[0].vec[1][1];
if you don't need the extra variable.