Animation: Move Snapping to Scene
Part of #91973 Moving the snapping code for the * Graph Editor * Action Editor * and NLA editor into the common system that lives on the scene. This includes the Magnet icon for turning snapping on and off. The old settings translate to the new in the following way: * `Frame Step` -> `Frame` * `Second Step` -> `Second` * `Nearest Frame` -> `Frame` + `Absolute Time Snap` * `Nearest Second` -> `Second` + `Absolute Time Snap` * `Nearest Marker` -> `Nearest Marker` Since this moves the location of the snapping settings from the editor to the scene, it changes the behavior. Previously each editor could have different snapping settings, where now they are all synced. Pull Request: https://projects.blender.org/blender/blender/pulls/109015
This commit is contained in:
parent
7365f0b094
commit
11fe57cab8
|
@ -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) {
|
||||
/* 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);
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
@ -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