diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c index 5f2b51aecfb..f8d3020bcea 100644 --- a/release/datafiles/userdef/userdef_default_theme.c +++ b/release/datafiles/userdef/userdef_default_theme.c @@ -312,6 +312,7 @@ const bTheme U_theme_default = { .anim = { .playhead = RGBA(0x4772b3ff), .preview_range = RGBA(0xa14d0066), + .scene_strip_range = RGBA(0x00000080), .channels = RGBA(0x194e8080), .channels_sub = RGBA(0x0f2c4d80), .channel_group = RGBA(0x1a332d37), diff --git a/scripts/startup/bl_ui/space_dopesheet.py b/scripts/startup/bl_ui/space_dopesheet.py index 5fcb64b08f8..fde484bdeb0 100644 --- a/scripts/startup/bl_ui/space_dopesheet.py +++ b/scripts/startup/bl_ui/space_dopesheet.py @@ -283,6 +283,13 @@ class DOPESHEET_HT_editor_buttons: icon_only=True, panel="DOPESHEET_PT_proportional_edit", ) + overlays = st.overlays + + row = layout.row(align=True) + row.prop(overlays, "show_overlays", text="", icon='OVERLAY') + sub = row.row(align=True) + sub.popover(panel="DOPESHEET_PT_overlay", text="") + sub.active = overlays.show_overlays @classmethod def _draw_action_selector(cls, context, layout): @@ -1014,6 +1021,33 @@ class DOPESHEET_PT_ShapeKey(Panel): draw_shape_key_properties(context, self.layout) +class DOPESHEET_PT_overlay(Panel): + bl_space_type = 'DOPESHEET_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Overlays" + bl_ui_units_x = 13 + + def draw(self, _context): + pass + + +class DOPESHEET_PT_dopesheet_overlay(Panel): + bl_space_type = 'DOPESHEET_EDITOR' + bl_region_type = 'HEADER' + bl_parent_id = "DOPESHEET_PT_overlay" + bl_label = "Dope Sheet Overlays" + + def draw(self, context): + st = context.space_data + overlay_settings = st.overlays + layout = self.layout + + layout.active = overlay_settings.show_overlays + row = layout.row() + row.active = context.workspace.use_scene_time_sync + row.prop(overlay_settings, "show_scene_strip_range") + + classes = ( DOPESHEET_HT_header, DOPESHEET_HT_playback_controls, @@ -1045,6 +1079,9 @@ classes = ( DOPESHEET_PT_grease_pencil_layer_relations, DOPESHEET_PT_grease_pencil_layer_display, DOPESHEET_PT_ShapeKey, + + DOPESHEET_PT_overlay, + DOPESHEET_PT_dopesheet_overlay, ) if __name__ == "__main__": # only for live edit. diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 5d25ef62e12..bb1e5a1304a 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 103 +#define BLENDER_FILE_SUBVERSION 104 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_500.cc b/source/blender/blenloader/intern/versioning_500.cc index defbaa193c7..d224209511f 100644 --- a/source/blender/blenloader/intern/versioning_500.cc +++ b/source/blender/blenloader/intern/versioning_500.cc @@ -3918,6 +3918,23 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 104)) { + /* Dope Sheet Editor: toggle overlays on. */ + if (!DNA_struct_exists(fd->filesdna, "SpaceActionOverlays")) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) { + if (space->spacetype == SPACE_ACTION) { + SpaceAction *space_action = (SpaceAction *)space; + space_action->overlays.flag |= ADS_OVERLAY_SHOW_OVERLAYS; + space_action->overlays.flag |= ADS_SHOW_SCENE_STRIP_FRAME_RANGE; + } + } + } + } + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index 8b04d298c1c..9bdc36095df 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -386,6 +386,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) btheme->tui.wcol_curve.roundness = U_theme_default.tui.wcol_curve.roundness; } + if (!USER_VERSION_ATLEAST(500, 104)) { + FROM_DEFAULT_V4_UCHAR(common.anim.scene_strip_range); + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a USER_VERSION_ATLEAST check. diff --git a/source/blender/editors/animation/anim_draw.cc b/source/blender/editors/animation/anim_draw.cc index 3522f19ea07..5cf72f71021 100644 --- a/source/blender/editors/animation/anim_draw.cc +++ b/source/blender/editors/animation/anim_draw.cc @@ -12,8 +12,10 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" +#include "DNA_workspace_types.h" #include "BLI_listbase.h" #include "BLI_math_rotation.h" @@ -31,6 +33,7 @@ #include "ED_anim_api.hh" #include "ED_keyframes_edit.hh" #include "ED_keyframes_keylist.hh" +#include "ED_sequencer.hh" #include "RNA_access.hh" #include "RNA_path.hh" @@ -41,6 +44,8 @@ #include "GPU_immediate.hh" #include "GPU_state.hh" +#include "SEQ_time.hh" + /* *************************************************** */ /* CURRENT FRAME DRAWING */ @@ -103,6 +108,57 @@ void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width } } +void ANIM_draw_scene_strip_range(const bContext *C, View2D *v2d) +{ + using namespace blender; + SpaceAction *space_action = CTX_wm_space_action(C); + if (!space_action || (space_action->overlays.flag & ADS_OVERLAY_SHOW_OVERLAYS) == 0 || + (space_action->overlays.flag & ADS_SHOW_SCENE_STRIP_FRAME_RANGE) == 0) + { + return; + } + WorkSpace *workspace = CTX_wm_workspace(C); + if (!workspace) { + return; + } + if ((workspace->flags & WORKSPACE_SYNC_SCENE_TIME) == 0) { + return; + } + const Scene *sequencer_scene = workspace->sequencer_scene; + if (!sequencer_scene) { + return; + } + const Strip *scene_strip = blender::ed::vse::get_scene_strip_for_time_sync(sequencer_scene); + if (!scene_strip) { + return; + } + GPU_blend(GPU_BLEND_ALPHA); + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_ANIM_SCENE_STRIP_RANGE, -25, -30); + + /* ..._handle are frames in "sequencer logic", meaning that on the right_handle point in time, + * the strip is not visible any more. The last visible frame of the strip is actually on + * (right_handle-1), hence the -1 when computing the end_frame. */ + const float left_handle = seq::time_left_handle_frame_get(sequencer_scene, scene_strip); + const float right_handle = seq::time_right_handle_frame_get(sequencer_scene, scene_strip); + const float start_frame = seq::give_frame_index(sequencer_scene, scene_strip, left_handle) + + scene_strip->scene->r.sfra; + const float end_frame = seq::give_frame_index(sequencer_scene, scene_strip, right_handle - 1) + + scene_strip->scene->r.sfra; + + BLI_assert(start_frame < end_frame); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, start_frame, v2d->cur.ymax); + immRectf(pos, end_frame, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + + immUnbindProgram(); + + GPU_blend(GPU_BLEND_NONE); +} + /* *************************************************** */ /* SCENE FRAME RANGE */ diff --git a/source/blender/editors/include/ED_anim_api.hh b/source/blender/editors/include/ED_anim_api.hh index 334101c7519..fbbaaa86705 100644 --- a/source/blender/editors/include/ED_anim_api.hh +++ b/source/blender/editors/include/ED_anim_api.hh @@ -881,6 +881,11 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag); */ void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width); +/** + * Draw range of the current sequencer scene strip when using scene time syncing. + */ +void ANIM_draw_scene_strip_range(const bContext *C, View2D *v2d); + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/include/ED_sequencer.hh b/source/blender/editors/include/ED_sequencer.hh index 016756764ef..93d2ad70311 100644 --- a/source/blender/editors/include/ED_sequencer.hh +++ b/source/blender/editors/include/ED_sequencer.hh @@ -82,6 +82,11 @@ bool can_select_handle(const Scene *scene, const Strip *strip, const View2D *v2d bool handle_is_selected(const Strip *strip, eStripHandle handle); bool is_scene_time_sync_needed(const bContext &C); +/** + * Returns the scene strip (if any) that should be used for the scene synchronization feature. + * This is the top-most visible scene strip at the current time of the \a sequencer_scene. + */ +const Strip *get_scene_strip_for_time_sync(const Scene *sequence_scene); void sync_active_scene_and_time_with_scene_strip(bContext &C); } // namespace blender::ed::vse diff --git a/source/blender/editors/include/UI_resources.hh b/source/blender/editors/include/UI_resources.hh index 8313e08cf90..e05fe37c625 100644 --- a/source/blender/editors/include/UI_resources.hh +++ b/source/blender/editors/include/UI_resources.hh @@ -287,9 +287,10 @@ enum ThemeColorID { TH_SKIN_ROOT, - TH_ANIM_ACTIVE, /* active action */ - TH_ANIM_INACTIVE, /* no active action */ - TH_ANIM_PREVIEW_RANGE, /* preview range overlay */ + TH_ANIM_ACTIVE, /* active action */ + TH_ANIM_INACTIVE, /* no active action */ + TH_ANIM_PREVIEW_RANGE, /* preview range overlay */ + TH_ANIM_SCENE_STRIP_RANGE, /* scene strip range overlay */ TH_ICON_SCENE, TH_ICON_COLLECTION, diff --git a/source/blender/editors/interface/resources.cc b/source/blender/editors/interface/resources.cc index e28ad2e05aa..ae6fca018fd 100644 --- a/source/blender/editors/interface/resources.cc +++ b/source/blender/editors/interface/resources.cc @@ -915,6 +915,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_ANIM_PREVIEW_RANGE: cp = btheme->common.anim.preview_range; break; + case TH_ANIM_SCENE_STRIP_RANGE: + cp = btheme->common.anim.scene_strip_range; + break; case TH_NLA_TWEAK: cp = ts->nla_tweaking; diff --git a/source/blender/editors/space_action/space_action.cc b/source/blender/editors/space_action/space_action.cc index 05339c72b28..4964a1c3dbe 100644 --- a/source/blender/editors/space_action/space_action.cc +++ b/source/blender/editors/space_action/space_action.cc @@ -72,6 +72,8 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene) TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT | TIME_CACHE_RIGIDBODY | TIME_CACHE_SIMULATION_NODES; + saction->overlays.flag |= (ADS_OVERLAY_SHOW_OVERLAYS | ADS_SHOW_SCENE_STRIP_FRAME_RANGE); + /* header */ region = BKE_area_region_new(); @@ -263,6 +265,8 @@ static void action_main_region_draw(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); ANIM_draw_previewrange(scene, v2d, 0); + ANIM_draw_scene_strip_range(C, v2d); + /* callback */ UI_view2d_view_ortho(v2d); ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.cc b/source/blender/editors/space_sequencer/sequencer_edit.cc index 3f1e33fa0d7..87359294263 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.cc +++ b/source/blender/editors/space_sequencer/sequencer_edit.cc @@ -361,27 +361,17 @@ static Scene *get_sequencer_scene_for_time_sync(const bContext &C) return nullptr; } -void sync_active_scene_and_time_with_scene_strip(bContext &C) +const Strip *get_scene_strip_for_time_sync(const Scene *sequencer_scene) { using namespace blender; - Scene *sequence_scene = get_sequencer_scene_for_time_sync(C); - if (!sequence_scene) { - return; - } - - wmWindow *win = CTX_wm_window(&C); - Scene *active_scene = WM_window_get_active_scene(win); - ViewLayer *view_layer = WM_window_get_active_view_layer(win); - Object *prev_obact = BKE_view_layer_active_object_get(view_layer); - - Editing *ed = seq::editing_get(sequence_scene); + const Editing *ed = seq::editing_get(sequencer_scene); if (!ed) { - return; + return nullptr; } ListBase *seqbase = seq::active_seqbase_get(ed); const ListBase *channels = seq::channels_displayed_get(ed); VectorSet query_strips = seq::query_strips_recursive_at_frame( - sequence_scene, seqbase, sequence_scene->r.cfra); + sequencer_scene, seqbase, sequencer_scene->r.cfra); /* Ignore effect strips, sound strips and muted strips. */ query_strips.remove_if([&](const Strip *strip) { return strip->is_effect() || strip->type == STRIP_TYPE_SOUND_RAM || @@ -393,20 +383,35 @@ void sync_active_scene_and_time_with_scene_strip(bContext &C) return a->channel > b->channel; }); /* Get the top-most scene strip. */ - const Strip *scene_strip = [&]() -> const Strip * { - for (const Strip *strip : strips) { - if (strip->type == STRIP_TYPE_SCENE) { - return strip; - } + for (const Strip *strip : strips) { + if (strip->type == STRIP_TYPE_SCENE) { + return strip; } - return nullptr; - }(); + } + return nullptr; +} + +void sync_active_scene_and_time_with_scene_strip(bContext &C) +{ + using namespace blender; + Scene *sequencer_scene = get_sequencer_scene_for_time_sync(C); + if (!sequencer_scene) { + return; + } + + wmWindow *win = CTX_wm_window(&C); + const Strip *scene_strip = get_scene_strip_for_time_sync(sequencer_scene); if (!scene_strip || !scene_strip->scene) { /* No scene strip with scene found. Switch to pinned scene. */ Main *bmain = CTX_data_main(&C); - WM_window_set_active_scene(bmain, &C, win, sequence_scene); + WM_window_set_active_scene(bmain, &C, win, sequencer_scene); return; } + + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Object *prev_obact = BKE_view_layer_active_object_get(view_layer); + + Scene *active_scene = WM_window_get_active_scene(win); if (active_scene != scene_strip->scene) { /* Sync active scene in window. */ Main *bmain = CTX_data_main(&C); @@ -440,7 +445,7 @@ void sync_active_scene_and_time_with_scene_strip(bContext &C) /* Compute the scene time based on the scene strip. */ const float frame_index = seq::give_frame_index( - sequence_scene, scene_strip, sequence_scene->r.cfra) + + sequencer_scene, scene_strip, sequencer_scene->r.cfra) + active_scene->r.sfra; if (active_scene->r.flag & SCER_SHOW_SUBFRAME) { active_scene->r.cfra = int(frame_index); diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index ec5fd02649c..2a4c98ef996 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -995,6 +995,17 @@ typedef struct SpaceAction_Runtime { char _pad0[7]; } SpaceAction_Runtime; +typedef enum SpaceActionOverlays_Flag { + ADS_OVERLAY_SHOW_OVERLAYS = (1 << 0), + ADS_SHOW_SCENE_STRIP_FRAME_RANGE = (1 << 1) +} SpaceActionOverlays_Flag; + +typedef struct SpaceActionOverlays { + /** #SpaceActionOverlays_Flag */ + int flag; + char _pad0[4]; +} SpaceActionOverlays; + /* Action Editor Space. This is defined here instead of in DNA_space_types.h */ typedef struct SpaceAction { struct SpaceLink *next, *prev; @@ -1028,6 +1039,8 @@ typedef struct SpaceAction { char cache_display; char _pad1[6]; + SpaceActionOverlays overlays; + SpaceAction_Runtime runtime; } SpaceAction; diff --git a/source/blender/makesdna/DNA_theme_types.h b/source/blender/makesdna/DNA_theme_types.h index 5a9cd31c986..8e911dd6da6 100644 --- a/source/blender/makesdna/DNA_theme_types.h +++ b/source/blender/makesdna/DNA_theme_types.h @@ -151,6 +151,9 @@ typedef struct ThemeCommonAnim { keyframe_jitter_selected[4], keyframe_moving_hold_selected[4], keyframe_generated_selected[4]; unsigned char long_key[4], long_key_selected[4]; + + unsigned char scene_strip_range[4]; + char _pad0[4]; } ThemeCommonAnim; typedef struct ThemeCommonCurves { diff --git a/source/blender/makesrna/intern/rna_space.cc b/source/blender/makesrna/intern/rna_space.cc index 73cfb8530f7..868c447d67e 100644 --- a/source/blender/makesrna/intern/rna_space.cc +++ b/source/blender/makesrna/intern/rna_space.cc @@ -2542,6 +2542,20 @@ static void rna_SpaceSequenceEditor_zoom_percentage_set(PointerRNA *ptr, const f ED_region_tag_redraw(region); } +static PointerRNA rna_SpaceDopeSheet_overlay_get(PointerRNA *ptr) +{ + return RNA_pointer_create_with_parent(*ptr, &RNA_SpaceDopeSheetOverlay, ptr->data); +} + +static std::optional rna_SpaceDopeSheetOverlay_path(const PointerRNA *ptr) +{ + std::optional editor_path = BKE_screen_path_from_screen_to_space(ptr); + if (!editor_path) { + return std::nullopt; + } + return editor_path.value() + ".overlays"; +} + /* Space Node Editor */ static PointerRNA rna_SpaceNode_overlay_get(PointerRNA *ptr) { @@ -6717,6 +6731,32 @@ static void rna_def_space_text(BlenderRNA *brna) RNA_api_space_text(srna); } +static void rna_def_space_dopesheet_overlays(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SpaceDopeSheetOverlay", nullptr); + RNA_def_struct_sdna(srna, "SpaceAction"); + RNA_def_struct_nested(brna, srna, "SpaceDopeSheetEditor"); + RNA_def_struct_path_func(srna, "rna_SpaceDopeSheetOverlay_path"); + RNA_def_struct_ui_text(srna, "Overlay Settings", ""); + + prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "overlays.flag", ADS_OVERLAY_SHOW_OVERLAYS); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, nullptr); + + prop = RNA_def_property(srna, "show_scene_strip_range", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "overlays.flag", ADS_SHOW_SCENE_STRIP_FRAME_RANGE); + RNA_def_property_ui_text(prop, + "Show Scene Strip Range", + "When using scene time synchronization in the sequence editor, display " + "the range of the current scene strip"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, nullptr); +} + static void rna_def_space_dopesheet(BlenderRNA *brna) { StructRNA *srna; @@ -6854,6 +6894,15 @@ static void rna_def_space_dopesheet(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, nullptr, "cache_display", TIME_CACHE_RIGIDBODY); RNA_def_property_ui_text(prop, "Rigid Body", "Show the active object's Rigid Body cache"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, nullptr); + + prop = RNA_def_property(srna, "overlays", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "SpaceDopeSheetOverlay"); + RNA_def_property_pointer_funcs( + prop, "rna_SpaceDopeSheet_overlay_get", nullptr, nullptr, nullptr); + RNA_def_property_ui_text(prop, "Overlay Settings", "Settings for display of overlays"); + + rna_def_space_dopesheet_overlays(brna); } static void rna_def_space_graph(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index 2ebd31d0519..e4c0c4f01b0 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -2382,6 +2382,12 @@ static void rna_def_userdef_theme_common_anim(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "scene_strip_range", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, nullptr, "scene_strip_range"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scene Strip Range", "Color of scene strip range overlay"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + /* Channel properties */ prop = RNA_def_property(srna, "channels", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 4);