Animation: Move Snapping to Scene #109015
|
@ -277,7 +277,14 @@ class DOPESHEET_HT_editor_buttons:
|
|||
|
||||
# Grease Pencil mode doesn't need snapping, as it's frame-aligned only
|
||||
if st.mode != 'GPENCIL':
|
||||
layout.prop(st, "auto_snap", text="")
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_snap_anim", text="")
|
||||
sub = row.row(align=True)
|
||||
sub.popover(
|
||||
panel="DOPESHEET_PT_snapping",
|
||||
icon='NONE',
|
||||
text="Modes",
|
||||
)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_proportional_action", text="", icon_only=True)
|
||||
|
@ -292,6 +299,21 @@ class DOPESHEET_HT_editor_buttons:
|
|||
)
|
||||
|
||||
|
||||
class DOPESHEET_PT_snapping(Panel):
|
||||
bl_space_type = 'DOPESHEET_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Snapping"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.label(text="Snap To")
|
||||
tool_settings = context.tool_settings
|
||||
col.prop(tool_settings, "snap_anim_element", expand=True)
|
||||
if tool_settings.snap_anim_element not in ('MARKER', ):
|
||||
col.prop(tool_settings, "use_snap_time_absolute")
|
||||
|
||||
|
||||
class DOPESHEET_PT_proportional_edit(Panel):
|
||||
bl_space_type = 'DOPESHEET_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
|
@ -872,6 +894,7 @@ classes = (
|
|||
DOPESHEET_PT_gpencil_layer_relations,
|
||||
DOPESHEET_PT_gpencil_layer_display,
|
||||
DOPESHEET_PT_custom_props_action,
|
||||
DOPESHEET_PT_snapping
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
|
|
@ -49,7 +49,14 @@ class GRAPH_HT_header(Header):
|
|||
|
||||
layout.prop(st, "pivot_point", icon_only=True)
|
||||
|
||||
layout.prop(st, "auto_snap", text="")
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_snap_anim", text="")
|
||||
sub = row.row(align=True)
|
||||
sub.popover(
|
||||
panel="GRAPH_PT_snapping",
|
||||
icon='NONE',
|
||||
text="Modes",
|
||||
)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_proportional_fcurve", text="", icon_only=True)
|
||||
|
@ -94,6 +101,20 @@ class GRAPH_PT_filters(DopesheetFilterPopoverBase, Panel):
|
|||
layout.separator()
|
||||
DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
|
||||
|
||||
class GRAPH_PT_snapping(Panel):
|
||||
bl_space_type = 'GRAPH_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Snapping"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.label(text="Snap To")
|
||||
tool_settings = context.tool_settings
|
||||
col.prop(tool_settings, "snap_anim_element", expand=True)
|
||||
if tool_settings.snap_anim_element not in ('MARKER', ):
|
||||
col.prop(tool_settings, "use_snap_time_absolute")
|
||||
|
||||
|
||||
class GRAPH_MT_editor_menus(Menu):
|
||||
bl_idname = "GRAPH_MT_editor_menus"
|
||||
|
@ -527,6 +548,7 @@ classes = (
|
|||
GRAPH_MT_snap_pie,
|
||||
GRAPH_MT_view_pie,
|
||||
GRAPH_PT_filters,
|
||||
GRAPH_PT_snapping,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
|
|
@ -33,7 +33,30 @@ class NLA_HT_header(Header):
|
|||
icon='FILTER',
|
||||
)
|
||||
|
||||
layout.prop(st, "auto_snap", text="")
|
||||
row = layout.row(align=True)
|
||||
tool_settings = context.tool_settings
|
||||
row.prop(tool_settings, "use_snap_anim", text="")
|
||||
sub = row.row(align=True)
|
||||
sub.popover(
|
||||
panel="NLA_PT_snapping",
|
||||
icon='NONE',
|
||||
text="Modes",
|
||||
)
|
||||
|
||||
|
||||
class NLA_PT_snapping(Panel):
|
||||
bl_space_type = 'NLA_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Snapping"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.label(text="Snap To")
|
||||
tool_settings = context.tool_settings
|
||||
col.prop(tool_settings, "snap_anim_element", expand=True)
|
||||
if tool_settings.snap_anim_element not in ('MARKER', ):
|
||||
col.prop(tool_settings, "use_snap_time_absolute")
|
||||
|
||||
|
||||
class NLA_PT_filters(DopesheetFilterPopoverBase, Panel):
|
||||
|
@ -350,6 +373,7 @@ classes = (
|
|||
NLA_MT_channel_context_menu,
|
||||
NLA_PT_filters,
|
||||
NLA_PT_action,
|
||||
NLA_PT_snapping,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
|
|
@ -969,6 +969,11 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
scene->eevee.gi_irradiance_pool_size = 16;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
scene->toolsettings->snap_flag_anim |= SCE_SNAP;
|
||||
scene->toolsettings->snap_anim_mode |= SCE_SNAP_TO_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 20)) {
|
||||
|
|
|
@ -62,7 +62,6 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
|
|||
saction = MEM_cnew<SpaceAction>("initaction");
|
||||
saction->spacetype = SPACE_ACTION;
|
||||
|
||||
saction->autosnap = SACTSNAP_FRAME;
|
||||
saction->mode = SACTCONT_DOPESHEET;
|
||||
saction->mode_prev = SACTCONT_DOPESHEET;
|
||||
saction->flag = SACTION_SHOW_INTERPOLATION | SACTION_SHOW_MARKERS;
|
||||
|
|
|
@ -62,8 +62,6 @@ static SpaceLink *graph_create(const ScrArea * /*area*/, const Scene *scene)
|
|||
sipo = static_cast<SpaceGraph *>(MEM_callocN(sizeof(SpaceGraph), "init graphedit"));
|
||||
sipo->spacetype = SPACE_GRAPH;
|
||||
|
||||
sipo->autosnap = SACTSNAP_FRAME;
|
||||
|
||||
/* allocate DopeSheet data for Graph Editor */
|
||||
sipo->ads = static_cast<bDopeSheet *>(MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"));
|
||||
sipo->ads->source = (ID *)scene;
|
||||
|
|
|
@ -57,7 +57,6 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene)
|
|||
snla->ads->source = (ID *)(scene);
|
||||
|
||||
/* set auto-snapping settings */
|
||||
snla->autosnap = SACTSNAP_FRAME;
|
||||
snla->flag = SNLA_SHOW_MARKERS;
|
||||
|
||||
/* header */
|
||||
|
|
|
@ -820,6 +820,20 @@ static void flushTransIntFrameActionData(TransInfo *t)
|
|||
}
|
||||
}
|
||||
|
||||
static void invert_snap(eSnapMode &snap_mode)
|
||||
|
||||
{
|
||||
/* Make snapping work like before 4.0 where pressing CTRL will switch between snapping to seconds
|
||||
* and frames. */
|
||||
if (snap_mode & SCE_SNAP_TO_FRAME) {
|
||||
snap_mode &= ~SCE_SNAP_TO_FRAME;
|
||||
snap_mode |= SCE_SNAP_TO_SECOND;
|
||||
}
|
||||
else if (snap_mode & SCE_SNAP_TO_SECOND) {
|
||||
snap_mode &= ~SCE_SNAP_TO_SECOND;
|
||||
snap_mode |= SCE_SNAP_TO_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
static void recalcData_actedit(TransInfo *t)
|
||||
{
|
||||
ViewLayer *view_layer = t->view_layer;
|
||||
|
@ -853,13 +867,17 @@ static void recalcData_actedit(TransInfo *t)
|
|||
|
||||
/* Flush 2d vector. */
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
const short autosnap = getAnimEdit_SnapMode(t);
|
||||
eSnapMode snap_mode = t->tsnap.mode;
|
||||
if (t->modifiers & MOD_SNAP_INVERT) {
|
||||
invert_snap(snap_mode);
|
||||
}
|
||||
|
||||
TransData *td;
|
||||
TransData2D *td2d;
|
||||
int i = 0;
|
||||
for (td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
|
||||
if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
|
||||
transform_snap_anim_flush_data(t, td, eAnimEdit_AutoSnap(autosnap), td->loc);
|
||||
if ((t->tsnap.flag & SCE_SNAP) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
|
||||
transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
|
||||
}
|
||||
|
||||
/* Constrain Y. */
|
||||
|
|
|
@ -644,6 +644,18 @@ static bool fcu_test_selected(FCurve *fcu)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void invert_snap(eSnapMode &snap_mode)
|
||||
{
|
||||
if (snap_mode & SCE_SNAP_TO_FRAME) {
|
||||
snap_mode &= ~SCE_SNAP_TO_FRAME;
|
||||
snap_mode |= SCE_SNAP_TO_SECOND;
|
||||
}
|
||||
else if (snap_mode & SCE_SNAP_TO_SECOND) {
|
||||
snap_mode &= ~SCE_SNAP_TO_SECOND;
|
||||
snap_mode |= SCE_SNAP_TO_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is called on recalc_data to apply the transforms applied
|
||||
* to the transdata on to the actual keyframe data
|
||||
*/
|
||||
|
@ -654,9 +666,13 @@ static void flushTransGraphData(TransInfo *t)
|
|||
TransDataGraph *tdg;
|
||||
int a;
|
||||
|
||||
const short autosnap = getAnimEdit_SnapMode(t);
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
eSnapMode snap_mode = t->tsnap.mode;
|
||||
|
||||
if (t->modifiers & MOD_SNAP_INVERT) {
|
||||
invert_snap(snap_mode);
|
||||
}
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
/* flush to 2d vector from internally used 3d vector */
|
||||
for (a = 0,
|
||||
td = tc->data,
|
||||
|
@ -675,8 +691,8 @@ static void flushTransGraphData(TransInfo *t)
|
|||
* - Only apply to keyframes (but never to handles).
|
||||
* - Don't do this when canceling, or else these changes won't go away.
|
||||
*/
|
||||
if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
|
||||
transform_snap_anim_flush_data(t, td, eAnimEdit_AutoSnap(autosnap), td->loc);
|
||||
if ((t->tsnap.flag & SCE_SNAP) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
|
||||
transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
|
||||
}
|
||||
|
||||
/* we need to unapply the nla-mapping from the time in some situations */
|
||||
|
|
|
@ -629,6 +629,18 @@ static void createTransNlaData(bContext *C, TransInfo *t)
|
|||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void invert_snap(eSnapMode &snap_mode)
|
||||
{
|
||||
if (snap_mode & SCE_SNAP_TO_FRAME) {
|
||||
snap_mode &= ~SCE_SNAP_TO_FRAME;
|
||||
snap_mode |= SCE_SNAP_TO_SECOND;
|
||||
}
|
||||
else if (snap_mode & SCE_SNAP_TO_SECOND) {
|
||||
snap_mode &= ~SCE_SNAP_TO_SECOND;
|
||||
snap_mode |= SCE_SNAP_TO_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
static void recalcData_nla(TransInfo *t)
|
||||
{
|
||||
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
|
||||
|
@ -639,11 +651,14 @@ static void recalcData_nla(TransInfo *t)
|
|||
* NOTE: only do this when transform is still running, or we can't restore
|
||||
*/
|
||||
if (t->state != TRANS_CANCEL) {
|
||||
const short autosnap = getAnimEdit_SnapMode(t);
|
||||
if (autosnap != SACTSNAP_OFF) {
|
||||
if (t->tsnap.flag & SCE_SNAP) {
|
||||
eSnapMode snap_mode = t->tsnap.mode;
|
||||
if (t->modifiers & MOD_SNAP_INVERT) {
|
||||
invert_snap(snap_mode);
|
||||
}
|
||||
TransData *td = tc->data;
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
transform_snap_anim_flush_data(t, td, eAnimEdit_AutoSnap(autosnap), td->loc);
|
||||
transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,30 +43,26 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
|
|||
outputNumInput(&(t->num), tvec, &t->scene->unit);
|
||||
}
|
||||
else {
|
||||
const short autosnap = getAnimEdit_SnapMode(t);
|
||||
eSnapMode snap_mode = t->tsnap.mode;
|
||||
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
|
||||
float val = ival + t->values_final[0];
|
||||
|
||||
snapFrameTransform(t, eAnimEdit_AutoSnap(autosnap), ival, val, &val);
|
||||
snapFrameTransform(t, snap_mode, ival, val, &val);
|
||||
float delta_x = val - ival;
|
||||
|
||||
if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) {
|
||||
if (snap_mode == SCE_SNAP_TO_SECOND) {
|
||||
nathanvegdahl marked this conversation as resolved
Outdated
Nathan Vegdahl
commented
Probably this can just be Probably this can just be `snap_mode == SCE_SNAP_TO_SECOND` now.
|
||||
/* Convert to seconds. */
|
||||
const Scene *scene = t->scene;
|
||||
const double secf = FPS;
|
||||
delta_x /= secf;
|
||||
val /= secf;
|
||||
delta_x /= FPS;
|
||||
val /= FPS;
|
||||
}
|
||||
|
||||
if (autosnap == SACTSNAP_FRAME) {
|
||||
if (snap_mode == SCE_SNAP_TO_FRAME) {
|
||||
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val);
|
||||
}
|
||||
else if (autosnap == SACTSNAP_SECOND) {
|
||||
else if (snap_mode == SCE_SNAP_TO_SECOND) {
|
||||
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val);
|
||||
}
|
||||
else if (autosnap == SACTSNAP_TSTEP) {
|
||||
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x);
|
||||
}
|
||||
|
|
|
@ -212,10 +212,10 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
|
|||
/* WORKAROUND:
|
||||
* Special case where snapping is done in #recalData.
|
||||
* Update the header based on the #center_local. */
|
||||
const short autosnap = getAnimEdit_SnapMode(t);
|
||||
eSnapMode autosnap = t->tsnap.mode;
|
||||
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0];
|
||||
float val = ival + dvec[0];
|
||||
snapFrameTransform(t, eAnimEdit_AutoSnap(autosnap), ival, val, &val);
|
||||
snapFrameTransform(t, autosnap, ival, val, &val);
|
||||
dvec[0] = val - ival;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,10 @@ bool validSnap(const TransInfo *t)
|
|||
|
||||
void transform_snap_flag_from_modifiers_set(TransInfo *t)
|
||||
{
|
||||
if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) {
|
||||
/* Those spacetypes define their own invert behaviour instead of toggling it on/off. */
|
||||
return;
|
||||
}
|
||||
SET_FLAG_FROM_TEST(t->tsnap.flag,
|
||||
(((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) ||
|
||||
((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT)),
|
||||
|
@ -151,7 +155,7 @@ bool transformModeUseSnap(const TransInfo *t)
|
|||
if (t->mode == TFM_RESIZE) {
|
||||
return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_SCALE) != 0;
|
||||
}
|
||||
if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE, TFM_SEQ_SLIDE)) {
|
||||
if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -164,11 +168,6 @@ static bool doForceIncrementSnap(const TransInfo *t)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
|
||||
/* No incremental snapping. */
|
||||
return false;
|
||||
}
|
||||
|
||||
return !transformModeUseSnap(t);
|
||||
}
|
||||
|
||||
|
@ -632,9 +631,7 @@ static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
|
|||
case SPACE_GRAPH:
|
||||
case SPACE_ACTION:
|
||||
case SPACE_NLA:
|
||||
/* These editors have their own "Auto-Snap" activation option.
|
||||
* See #getAnimEdit_SnapMode. */
|
||||
return eSnapFlag(0);
|
||||
return eSnapFlag(ts->snap_flag_anim);
|
||||
}
|
||||
/* #SPACE_EMPTY.
|
||||
* It can happen when the operator is called via a handle in `bpy.app.handlers`. */
|
||||
|
@ -680,9 +677,8 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t)
|
|||
return snap_mode;
|
||||
}
|
||||
|
||||
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
|
||||
/* No incremental snapping. */
|
||||
return eSnapMode(0);
|
||||
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_GRAPH)) {
|
||||
return eSnapMode(ts->snap_anim_mode);
|
||||
}
|
||||
|
||||
return SCE_SNAP_TO_INCREMENT;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define SNAP_MIN_DISTANCE 30
|
||||
|
||||
/* For enum. */
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
bool peelObjectsTransform(TransInfo *t,
|
||||
|
@ -73,25 +74,14 @@ void transform_snap_sequencer_data_free(TransSeqSnapData *data);
|
|||
bool transform_snap_sequencer_calc(TransInfo *t);
|
||||
void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
|
||||
|
||||
/* `transform_snap_animation.cc` */
|
||||
|
||||
/**
|
||||
* This function returns the snapping 'mode' for Animation Editors only.
|
||||
* We cannot use the standard snapping due to NLA-strip scaling complexities.
|
||||
*
|
||||
* TODO: these modifier checks should be accessible from the key-map.
|
||||
*/
|
||||
short getAnimEdit_SnapMode(TransInfo *t);
|
||||
void snapFrameTransform(TransInfo *t,
|
||||
eAnimEdit_AutoSnap autosnap,
|
||||
float val_initial,
|
||||
float val_final,
|
||||
float *r_val_final);
|
||||
/* transform_snap_animation.cc */
|
||||
void snapFrameTransform(
|
||||
TransInfo *t, eSnapMode autosnap, float val_initial, float val_final, float *r_val_final);
|
||||
nathanvegdahl marked this conversation as resolved
Nathan Vegdahl
commented
Would it be worth taking the time to switch from Would it be worth taking the time to switch from `r_val_final` to just returning the value? (`transform_snap_anim_flush_data()` is also like this.) Maybe not—maybe better as a separate clean up PR.
|
||||
/**
|
||||
* This function is used by Animation Editor specific transform functions to do
|
||||
* the Snap Keyframe to Nearest Frame/Marker
|
||||
*/
|
||||
void transform_snap_anim_flush_data(TransInfo *t,
|
||||
TransData *td,
|
||||
eAnimEdit_AutoSnap autosnap,
|
||||
eSnapMode autosnap,
|
||||
float *r_val_final);
|
||||
|
|
|
@ -21,96 +21,59 @@
|
|||
/** \name Snapping in Anim Editors
|
||||
* \{ */
|
||||
|
||||
short getAnimEdit_SnapMode(TransInfo *t)
|
||||
{
|
||||
short autosnap = SACTSNAP_OFF;
|
||||
|
||||
if (t->spacetype == SPACE_ACTION) {
|
||||
SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
|
||||
|
||||
if (saction) {
|
||||
autosnap = saction->autosnap;
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_GRAPH) {
|
||||
if ((t->mode == TFM_TRANSLATION) && transform_snap_is_active(t)) {
|
||||
return autosnap;
|
||||
}
|
||||
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
|
||||
if (sipo) {
|
||||
autosnap = sipo->autosnap;
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_NLA) {
|
||||
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
|
||||
|
||||
if (snla) {
|
||||
autosnap = snla->autosnap;
|
||||
}
|
||||
}
|
||||
else {
|
||||
autosnap = SACTSNAP_OFF;
|
||||
}
|
||||
|
||||
/* toggle autosnap on/off
|
||||
* - when toggling on, prefer nearest frame over 1.0 frame increments
|
||||
*/
|
||||
if (t->modifiers & MOD_SNAP_INVERT) {
|
||||
if (autosnap) {
|
||||
autosnap = SACTSNAP_OFF;
|
||||
}
|
||||
else {
|
||||
autosnap = SACTSNAP_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
return autosnap;
|
||||
}
|
||||
|
||||
void snapFrameTransform(TransInfo *t,
|
||||
const eAnimEdit_AutoSnap autosnap,
|
||||
const eSnapMode snap_mode,
|
||||
const float val_initial,
|
||||
const float val_final,
|
||||
float *r_val_final)
|
||||
{
|
||||
float deltax = val_final - val_initial;
|
||||
switch (autosnap) {
|
||||
case SACTSNAP_FRAME:
|
||||
*r_val_final = floorf(val_final + 0.5f);
|
||||
break;
|
||||
case SACTSNAP_MARKER:
|
||||
/* Snap to nearest marker. */
|
||||
/* TODO: need some more careful checks for where data comes from. */
|
||||
*r_val_final = float(ED_markers_find_nearest_marker_time(&t->scene->markers, val_final));
|
||||
break;
|
||||
case SACTSNAP_SECOND:
|
||||
case SACTSNAP_TSTEP: {
|
||||
const Scene *scene = t->scene;
|
||||
const double secf = FPS;
|
||||
if (autosnap == SACTSNAP_SECOND) {
|
||||
*r_val_final = floorf((val_final / secf) + 0.5) * secf;
|
||||
/* This is needed for the FPS macro. */
|
||||
const Scene *scene = t->scene;
|
||||
const eSnapFlag snap_flag = t->tsnap.flag;
|
||||
|
||||
switch (snap_mode) {
|
||||
case SCE_SNAP_TO_FRAME: {
|
||||
if (snap_flag & SCE_SNAP_ABS_TIME_STEP) {
|
||||
*r_val_final = floorf(val_final + 0.5f);
|
||||
}
|
||||
else {
|
||||
deltax = float(floor((deltax / secf) + 0.5) * secf);
|
||||
deltax = floorf(deltax + 0.5f);
|
||||
*r_val_final = val_initial + deltax;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SACTSNAP_STEP:
|
||||
deltax = floorf(deltax + 0.5f);
|
||||
*r_val_final = val_initial + deltax;
|
||||
case SCE_SNAP_TO_SECOND: {
|
||||
if (snap_flag & SCE_SNAP_ABS_TIME_STEP) {
|
||||
*r_val_final = floorf((val_final / FPS) + 0.5) * FPS;
|
||||
}
|
||||
else {
|
||||
deltax = float(floor((deltax / FPS) + 0.5) * FPS);
|
||||
*r_val_final = val_initial + deltax;
|
||||
}
|
||||
break;
|
||||
case SACTSNAP_OFF:
|
||||
}
|
||||
case SCE_SNAP_TO_MARKERS: {
|
||||
/* Snap to nearest marker. */
|
||||
/* TODO: need some more careful checks for where data comes from. */
|
||||
const float nearest_marker_time = float(
|
||||
ED_markers_find_nearest_marker_time(&t->scene->markers, val_final));
|
||||
*r_val_final = nearest_marker_time;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
*r_val_final = val_final;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transform_snap_anim_flush_data(TransInfo *t,
|
||||
TransData *td,
|
||||
const eAnimEdit_AutoSnap autosnap,
|
||||
const eSnapMode snap_mode,
|
||||
float *r_val_final)
|
||||
{
|
||||
BLI_assert(autosnap != SACTSNAP_OFF);
|
||||
BLI_assert(t->tsnap.flag);
|
||||
|
||||
float val = td->loc[0];
|
||||
float ival = td->iloc[0];
|
||||
|
@ -123,7 +86,7 @@ void transform_snap_anim_flush_data(TransInfo *t,
|
|||
ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
|
||||
}
|
||||
|
||||
snapFrameTransform(t, autosnap, ival, val, &val);
|
||||
snapFrameTransform(t, snap_mode, ival, val, &val);
|
||||
|
||||
/* Convert frame out of nla-action time. */
|
||||
if (adt) {
|
||||
|
|
|
@ -853,8 +853,8 @@ typedef struct SpaceAction {
|
|||
char mode;
|
||||
/* Storage for sub-space types. */
|
||||
char mode_prev;
|
||||
/** Automatic keyframe snapping mode. */
|
||||
char autosnap;
|
||||
/* Snapping now lives on the Scene. */
|
||||
char autosnap DNA_DEPRECATED;
|
||||
/** (eTimeline_Cache_Flag). */
|
||||
char cache_display;
|
||||
char _pad1[6];
|
||||
|
@ -917,10 +917,8 @@ typedef enum eAnimEdit_Context {
|
|||
SACTCONT_TIMELINE = 6,
|
||||
} eAnimEdit_Context;
|
||||
|
||||
/* SpaceAction AutoSnap Settings (also used by other Animation Editors) */
|
||||
/* Old snapping enum that is only needed because of the versioning code. */
|
||||
typedef enum eAnimEdit_AutoSnap {
|
||||
/* no auto-snap */
|
||||
SACTSNAP_OFF = 0,
|
||||
/* snap to 1.0 frame/second intervals */
|
||||
SACTSNAP_STEP = 1,
|
||||
/* snap to actual frames/seconds (nla-action time) */
|
||||
|
@ -931,7 +929,7 @@ typedef enum eAnimEdit_AutoSnap {
|
|||
SACTSNAP_SECOND = 4,
|
||||
/* snap to 1.0 second increments */
|
||||
SACTSNAP_TSTEP = 5,
|
||||
} eAnimEdit_AutoSnap;
|
||||
} eAnimEdit_AutoSnap DNA_DEPRECATED;
|
||||
|
||||
/* SAction->cache_display */
|
||||
typedef enum eTimeline_Cache_Flag {
|
||||
|
|
|
@ -365,7 +365,9 @@
|
|||
.snap_mode = SCE_SNAP_TO_INCREMENT, \
|
||||
.snap_node_mode = SCE_SNAP_TO_GRID, \
|
||||
.snap_uv_mode = SCE_SNAP_TO_INCREMENT, \
|
||||
.snap_anim_mode = SCE_SNAP_TO_FRAME, \
|
||||
.snap_flag = SCE_SNAP_TO_INCLUDE_EDITED | SCE_SNAP_TO_INCLUDE_NONEDITED, \
|
||||
.snap_flag_anim = SCE_SNAP, \
|
||||
.snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE, \
|
||||
.snap_face_nearest_steps = 1, \
|
||||
\
|
||||
|
|
|
@ -1639,11 +1639,14 @@ typedef struct ToolSettings {
|
|||
short snap_mode;
|
||||
char snap_node_mode;
|
||||
char snap_uv_mode;
|
||||
short snap_anim_mode;
|
||||
/** Generic flags (per space-type), #eSnapFlag. */
|
||||
short snap_flag;
|
||||
short snap_flag_node;
|
||||
short snap_flag_seq;
|
||||
short snap_flag_anim;
|
||||
short snap_uv_flag;
|
||||
char _pad[4];
|
||||
/** Default snap source, #eSnapSourceOP. */
|
||||
/**
|
||||
* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
|
||||
|
@ -2324,6 +2327,8 @@ typedef enum eSnapFlag {
|
|||
/** Was `SCE_SNAP_NO_SELF`, but self should be active. */
|
||||
SCE_SNAP_NOT_TO_ACTIVE = (1 << 4),
|
||||
SCE_SNAP_ABS_GRID = (1 << 5),
|
||||
/* Same value with different name to make it easier to understand in time based code. */
|
||||
SCE_SNAP_ABS_TIME_STEP = (1 << 5),
|
||||
SCE_SNAP_BACKFACE_CULLING = (1 << 6),
|
||||
SCE_SNAP_KEEP_ON_SAME_OBJECT = (1 << 7),
|
||||
/** see #eSnapTargetOP */
|
||||
|
@ -2383,11 +2388,17 @@ typedef enum eSnapMode {
|
|||
/** For snap individual elements. */
|
||||
SCE_SNAP_INDIVIDUAL_NEAREST = (1 << 8),
|
||||
SCE_SNAP_INDIVIDUAL_PROJECT = (1 << 9),
|
||||
|
||||
/** #ToolSettings::snap_anim_mode */
|
||||
SCE_SNAP_TO_FRAME = (1 << 10),
|
||||
SCE_SNAP_TO_SECOND = (1 << 11),
|
||||
SCE_SNAP_TO_MARKERS = (1 << 12),
|
||||
} eSnapMode;
|
||||
|
||||
/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
|
||||
/* TODO: move this macro to a more general place. */
|
||||
#ifdef ENUM_OPERATORS
|
||||
ENUM_OPERATORS(eSnapMode, SCE_SNAP_INDIVIDUAL_PROJECT)
|
||||
ENUM_OPERATORS(eSnapMode, SCE_SNAP_TO_MARKERS)
|
||||
#endif
|
||||
|
||||
#define SCE_SNAP_TO_VERTEX (SCE_SNAP_TO_POINT | SCE_SNAP_TO_EDGE_ENDPOINT)
|
||||
|
|
|
@ -470,11 +470,8 @@ typedef struct SpaceGraph {
|
|||
|
||||
/** Mode for the Graph editor (eGraphEdit_Mode). */
|
||||
short mode;
|
||||
/**
|
||||
* Time-transform auto-snapping settings for Graph editor
|
||||
* (eAnimEdit_AutoSnap in DNA_action_types.h).
|
||||
*/
|
||||
short autosnap;
|
||||
/* Snapping now lives on the Scene. */
|
||||
short autosnap DNA_DEPRECATED;
|
||||
/** Settings for Graph editor (eGraphEdit_Flag). */
|
||||
int flag;
|
||||
|
||||
Sybren A. Stüvel
commented
👍 for pointing to the new location. :+1: for pointing to the new location.
|
||||
|
@ -560,8 +557,8 @@ typedef struct SpaceNla {
|
|||
char _pad0[6];
|
||||
/* End 'SpaceLink' header. */
|
||||
|
||||
/** This uses the same settings as autosnap for Action Editor. */
|
||||
short autosnap;
|
||||
/* Snapping now lives on the Scene. */
|
||||
short autosnap DNA_DEPRECATED;
|
||||
short flag;
|
||||
char _pad[4];
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ DEF_ENUM(rna_enum_proportional_falloff_curve_only_items)
|
|||
DEF_ENUM(rna_enum_snap_source_items)
|
||||
DEF_ENUM(rna_enum_snap_element_items)
|
||||
DEF_ENUM(rna_enum_snap_node_element_items)
|
||||
DEF_ENUM(rna_enum_snap_animation_element_items)
|
||||
DEF_ENUM(rna_enum_curve_fit_method_items)
|
||||
DEF_ENUM(rna_enum_mesh_select_mode_items)
|
||||
DEF_ENUM(rna_enum_mesh_select_mode_uv_items)
|
||||
|
|
|
@ -201,6 +201,13 @@ const EnumPropertyItem rna_enum_snap_node_element_items[] = {
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_snap_animation_element_items[] = {
|
||||
{SCE_SNAP_TO_FRAME, "FRAME", 0, "Frame", "Snap to frame"},
|
||||
{SCE_SNAP_TO_SECOND, "SECOND", 0, "Second", "Snap to seconds"},
|
||||
{SCE_SNAP_TO_MARKERS, "MARKER", 0, "Nearest Marker", "Snap to nearest marker"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
#ifndef RNA_RUNTIME
|
||||
static const EnumPropertyItem snap_uv_element_items[] = {
|
||||
{SCE_SNAP_TO_INCREMENT,
|
||||
|
@ -3449,6 +3456,24 @@ static void rna_def_tool_settings(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Snap Node Element", "Type of element to snap to");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr); /* header redraw */
|
||||
|
||||
prop = RNA_def_property(srna, "use_snap_anim", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag_anim", SCE_SNAP);
|
||||
RNA_def_property_ui_text(prop, "Snap", "Enable snapping when transforming keyframes");
|
||||
RNA_def_property_ui_icon(prop, ICON_SNAP_OFF, 1);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
|
||||
|
||||
prop = RNA_def_property(srna, "use_snap_time_absolute", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "snap_flag_anim", SCE_SNAP_ABS_TIME_STEP);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Absolute Time Snap", "Absolute time alignment while translating");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr); /* header redraw */
|
||||
|
||||
prop = RNA_def_property(srna, "snap_anim_element", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, nullptr, "snap_anim_mode");
|
||||
RNA_def_property_enum_items(prop, rna_enum_snap_animation_element_items);
|
||||
RNA_def_property_ui_text(prop, "Snap Anim Element", "Type of element to snap to");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr); /* header redraw */
|
||||
|
||||
/* image editor uses own set of snap modes */
|
||||
prop = RNA_def_property(srna, "snap_uv_element", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, nullptr, "snap_uv_mode");
|
||||
|
|
|
@ -392,21 +392,6 @@ static const EnumPropertyItem display_channels_items[] = {
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
#ifndef RNA_RUNTIME
|
||||
static const EnumPropertyItem autosnap_items[] = {
|
||||
{SACTSNAP_OFF, "NONE", 0, "No Auto-Snap", ""},
|
||||
/* {-1, "", 0, "", ""}, */
|
||||
{SACTSNAP_STEP, "STEP", 0, "Frame Step", "Snap to 1.0 frame intervals"},
|
||||
{SACTSNAP_TSTEP, "TIME_STEP", 0, "Second Step", "Snap to 1.0 second intervals"},
|
||||
/* {-1, "", 0, "", ""}, */
|
||||
{SACTSNAP_FRAME, "FRAME", 0, "Nearest Frame", "Snap to actual frames (nla-action time)"},
|
||||
{SACTSNAP_SECOND, "SECOND", 0, "Nearest Second", "Snap to actual seconds (nla-action time)"},
|
||||
/* {-1, "", 0, "", ""}, */
|
||||
{SACTSNAP_MARKER, "MARKER", 0, "Nearest Marker", "Snap to nearest marker"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
#endif
|
||||
|
||||
const EnumPropertyItem rna_enum_shading_type_items[] = {
|
||||
{OB_WIRE, "WIREFRAME", ICON_SHADING_WIRE, "Wireframe", "Display the object as wire edges"},
|
||||
{OB_SOLID, "SOLID", ICON_SHADING_SOLID, "Solid", "Display in solid mode"},
|
||||
|
@ -6283,14 +6268,6 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
|
|||
RNA_def_property_pointer_sdna(prop, nullptr, "ads");
|
||||
RNA_def_property_ui_text(prop, "Dope Sheet", "Settings for filtering animation data");
|
||||
|
||||
/* autosnap */
|
||||
prop = RNA_def_property(srna, "auto_snap", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "autosnap");
|
||||
RNA_def_property_enum_items(prop, autosnap_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Auto Snap", "Automatic time snapping settings for transformations");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, nullptr);
|
||||
|
||||
/* displaying cache status */
|
||||
prop = RNA_def_property(srna, "show_cache", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "cache_display", TIME_CACHE_DISPLAY);
|
||||
|
@ -6452,14 +6429,6 @@ static void rna_def_space_graph(BlenderRNA *brna)
|
|||
RNA_def_property_pointer_sdna(prop, nullptr, "ads");
|
||||
RNA_def_property_ui_text(prop, "Dope Sheet", "Settings for filtering animation data");
|
||||
|
||||
/* Auto-snap. */
|
||||
prop = RNA_def_property(srna, "auto_snap", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "autosnap");
|
||||
RNA_def_property_enum_items(prop, autosnap_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Auto Snap", "Automatic time snapping settings for transformations");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, nullptr);
|
||||
|
||||
/* Read-only state info. */
|
||||
prop = RNA_def_property(srna, "has_ghost_curves", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_SpaceGraphEditor_has_ghost_curves_get", nullptr);
|
||||
|
@ -6539,14 +6508,6 @@ static void rna_def_space_nla(BlenderRNA *brna)
|
|||
RNA_def_property_struct_type(prop, "DopeSheet");
|
||||
RNA_def_property_pointer_sdna(prop, nullptr, "ads");
|
||||
RNA_def_property_ui_text(prop, "Dope Sheet", "Settings for filtering animation data");
|
||||
|
||||
/* autosnap */
|
||||
prop = RNA_def_property(srna, "auto_snap", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "autosnap");
|
||||
RNA_def_property_enum_items(prop, autosnap_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Auto Snap", "Automatic time snapping settings for transformations");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, nullptr);
|
||||
}
|
||||
|
||||
static void rna_def_console_line(BlenderRNA *brna)
|
||||
|
|
Loading…
Reference in New Issue
Add a comment that explains what this 'inversion' is for. I had to read about the "CTRL key to switch between seconds & frames" behaviour of 3.6 that you put in the PR description to know this was a thing (so 👍 for putting it there), and I think it'll be helpful for future devs (including future us) if this info is actually in the source.