diff --git a/src/libretro/config.cpp b/src/libretro/config.cpp index 76131a96..3f0c6967 100644 --- a/src/libretro/config.cpp +++ b/src/libretro/config.cpp @@ -71,7 +71,6 @@ namespace Config { static const char* const OPENGL_FILTERING = "melonds_opengl_filtering"; static const char* const RENDER_MODE = "melonds_render_mode"; static const char* const NUMBER_OF_SCREEN_LAYOUTS = "melonds_number_of_screen_layouts"; - [[deprecated("Use SCREEN_LAYOUTS instead")]] static const char* const SCREEN_LAYOUT = "melonds_screen_layout"; static const char* const SCREEN_LAYOUT1 = "melonds_screen_layout1"; static const char* const SCREEN_LAYOUT2 = "melonds_screen_layout2"; static const char* const SCREEN_LAYOUT3 = "melonds_screen_layout3"; @@ -102,7 +101,6 @@ namespace Config { static const char* const CONSOLE_MODE = "melonds_console_mode"; static const char* const BOOT_DIRECTLY = "melonds_boot_directly"; static const char* const SCREEN_GAP = "melonds_screen_gap"; - [[deprecated("Use SCREEN_LAYOUTS instead")]] static const char* const SWAPSCREEN_MODE = "melonds_swapscreen_mode"; static const char* const RANDOMIZE_MAC_ADDRESS = "melonds_randomize_mac_address"; static const char* const TOUCH_MODE = "melonds_touch_mode"; static const char* const MIC_INPUT_BUTTON = "melonds_mic_input_active"; @@ -332,9 +330,6 @@ namespace melonds::config { static std::array _screenLayouts; std::array ScreenLayouts() noexcept { return _screenLayouts; } - [[deprecated("Use ScreenLayouts instead")]] static melonds::ScreenLayout _screenLayout; - enum melonds::ScreenLayout ScreenLayout() noexcept { return _screenLayout; } - static unsigned _screenGap; unsigned ScreenGap() noexcept { return _screenGap; } @@ -345,9 +340,6 @@ namespace melonds::config { unsigned HybridRatio() noexcept { return 2; } #endif - [[deprecated("Use ScreenLayouts instead")]] static melonds::ScreenSwapMode _screenSwapMode; - melonds::ScreenSwapMode ScreenSwapMode() noexcept { return _screenSwapMode; } - static melonds::SmallScreenLayout _smallScreenLayout; melonds::SmallScreenLayout SmallScreenLayout() noexcept { return _smallScreenLayout; } @@ -469,20 +461,22 @@ void melonds::InitConfig(const optional& nds_info, const config::apply_screen_options(screenLayout); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) - if (melonds::opengl::UsingOpenGl() && openGlNeedsRefresh) { + if (melonds::opengl::UsingOpenGl() && (openGlNeedsRefresh || screenLayout.Dirty())) { // If we're using OpenGL and the settings changed, or the screen layout changed... melonds::opengl::RequestOpenGlRefresh(); } #endif + if (melonds::render::CurrentRenderer() == Renderer::None) { + screenLayout.Update(config::video::ConfiguredRenderer()); + } else { + screenLayout.Update(melonds::render::CurrentRenderer()); + } + update_option_visibility(); } -void melonds::UpdateConfig( - const std::optional& nds_info, - const std::optional& header, - ScreenLayoutData& screenLayout -) noexcept { +void melonds::UpdateConfig(ScreenLayoutData& screenLayout) noexcept { config::parse_audio_options(); bool openGlNeedsRefresh = config::parse_video_options(false); openGlNeedsRefresh |= config::parse_screen_options(); @@ -491,12 +485,18 @@ void melonds::UpdateConfig( config::apply_screen_options(screenLayout); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) - if (melonds::opengl::UsingOpenGl() && openGlNeedsRefresh) { + if (melonds::opengl::UsingOpenGl() && (openGlNeedsRefresh || screenLayout.Dirty())) { // If we're using OpenGL and the settings changed, or the screen layout changed... melonds::opengl::RequestOpenGlRefresh(); } #endif + if (melonds::render::CurrentRenderer() == Renderer::None) { + screenLayout.Update(config::video::ConfiguredRenderer()); + } else { + screenLayout.Update(melonds::render::CurrentRenderer()); + } + update_option_visibility(); } @@ -552,9 +552,17 @@ bool melonds::update_option_visibility() { // Show/hide Hybrid screen options bool oldShowHybridOptions = ShowHybridOptions; bool oldShowVerticalLayoutOptions = ShowVerticalLayoutOptions; - optional layout = ParseScreenLayout(get_variable(Keys::SCREEN_LAYOUT)); - ShowHybridOptions = !layout || *layout == ScreenLayout::HybridTop || *layout == ScreenLayout::HybridBottom; - ShowVerticalLayoutOptions = !layout || *layout == ScreenLayout::TopBottom || *layout == ScreenLayout::BottomTop; + bool anyHybridLayouts = false; + bool anyVerticalLayouts = false; + for (unsigned i = 0; i < config::screen::MAX_SCREEN_LAYOUTS; i++) { + optional parsedLayout = ParseScreenLayout(get_variable(Keys::SCREEN_LAYOUTS[i])); + + anyHybridLayouts |= !parsedLayout || *parsedLayout == ScreenLayout::HybridTop || *parsedLayout == ScreenLayout::HybridBottom; + anyVerticalLayouts |= !parsedLayout || *parsedLayout == ScreenLayout::TopBottom || *parsedLayout == ScreenLayout::BottomTop; + } + ShowHybridOptions = anyHybridLayouts; + ShowVerticalLayoutOptions = anyVerticalLayouts; + if (ShowHybridOptions != oldShowHybridOptions) { set_option_visible(Keys::HYBRID_SMALL_SCREEN, ShowHybridOptions); #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) @@ -896,17 +904,6 @@ static bool melonds::config::parse_screen_options() noexcept { bool needsOpenGlRefresh = false; - enum ScreenLayout oldScreenLayout = _screenLayout; - if (optional value = ParseScreenLayout(get_variable(Keys::SCREEN_LAYOUT))) { - _screenLayout = *value; - } else { - retro::warn("Failed to get value for %s; defaulting to %s", Keys::SCREEN_LAYOUT, Values::TOP_BOTTOM); - _screenLayout = ScreenLayout::TopBottom; - } - - if (oldScreenLayout != _screenLayout) - needsOpenGlRefresh = true; - if (const char* value = get_variable(Keys::SCREEN_GAP); !string_is_empty(value)) { _screenGap = std::stoi(value); // TODO: Handle errors } else { @@ -923,7 +920,6 @@ static bool melonds::config::parse_screen_options() noexcept { } #endif - enum SmallScreenLayout oldHybridSmallScreen = _smallScreenLayout; if (const char* value = get_variable(Keys::HYBRID_SMALL_SCREEN); !string_is_empty(value)) { if (string_is_equal(value, Values::TOP)) _smallScreenLayout = SmallScreenLayout::SmallScreenTop; @@ -936,12 +932,6 @@ static bool melonds::config::parse_screen_options() noexcept { _smallScreenLayout = SmallScreenLayout::SmallScreenDuplicate; } -#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) - if (_smallScreenLayout != oldHybridSmallScreen) { - needsOpenGlRefresh = true; - } -#endif - enum TouchMode oldTouchMode = _touchMode; if (const char* value = get_variable(Keys::TOUCH_MODE); !string_is_empty(value)) { if (string_is_equal(value, Values::MOUSE)) @@ -959,20 +949,12 @@ static bool melonds::config::parse_screen_options() noexcept { #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) if (_touchMode != oldTouchMode) { + // May need to refresh the screen if the touch mode changed, + // as we may need to start (or stop) drawing a cursor. needsOpenGlRefresh = true; } #endif - if (const char* value = get_variable(Keys::SWAPSCREEN_MODE); !string_is_empty(value)) { - if (string_is_equal(value, Values::TOGGLE)) - _screenSwapMode = ScreenSwapMode::Toggle; - else - _screenSwapMode = ScreenSwapMode::Hold; - } else { - retro::warn("Failed to get value for %s; defaulting to %s", Keys::SWAPSCREEN_MODE, Values::TOGGLE); - _screenSwapMode = ScreenSwapMode::Toggle; - } - if (optional value = ParseIntegerInRange(get_variable(Keys::NUMBER_OF_SCREEN_LAYOUTS), 1, MAX_SCREEN_LAYOUTS)) { _numberOfScreenLayouts = *value; } else { @@ -1269,15 +1251,10 @@ static void melonds::config::apply_save_options(const optional& heade } static void melonds::config::apply_screen_options(ScreenLayoutData& screenLayout) noexcept { - screenLayout.SetLayout(screen::ScreenLayout()); + screenLayout.SetLayouts(screen::ScreenLayouts(), screen::NumberOfScreenLayouts()); screenLayout.HybridSmallScreenLayout(screen::SmallScreenLayout()); screenLayout.ScreenGap(screen::ScreenGap()); screenLayout.HybridRatio(screen::HybridRatio()); - if (melonds::render::CurrentRenderer() == Renderer::None) { - screenLayout.Update(video::ConfiguredRenderer()); - } else { - screenLayout.Update(melonds::render::CurrentRenderer()); - } } struct retro_core_option_v2_category option_cats_us[] = { @@ -1675,43 +1652,6 @@ struct retro_core_option_v2_definition melonds::option_defs_us[] = { }, Config::Retro::Values::MOUSE }, - { - Config::Retro::Keys::SWAPSCREEN_MODE, - "Swap Screen Mode", - nullptr, - "Choose if the 'Swap screens' button should work on press or on hold.", - nullptr, - Config::Retro::Category::SCREEN, - { - {Config::Retro::Values::TOGGLE, "Toggle"}, - {Config::Retro::Values::HOLD, "Hold"}, - {nullptr, nullptr}, - }, - Config::Retro::Values::TOGGLE - }, - { - Config::Retro::Keys::SCREEN_LAYOUT, - "Screen Layout", - nullptr, - "Choose how many screens should be displayed and how they should be displayed.", - nullptr, - Config::Retro::Category::SCREEN, - { - {Config::Retro::Values::TOP_BOTTOM, "Top/Bottom"}, - {Config::Retro::Values::BOTTOM_TOP, "Bottom/Top"}, - {Config::Retro::Values::LEFT_RIGHT, "Left/Right"}, - {Config::Retro::Values::RIGHT_LEFT, "Right/Left"}, - {Config::Retro::Values::TOP, "Top Only"}, - {Config::Retro::Values::BOTTOM, "Bottom Only"}, - {Config::Retro::Values::HYBRID_TOP, "Hybrid (Focus Top)"}, - {Config::Retro::Values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, - {Config::Retro::Values::ROTATE_LEFT, "Rotated Left"}, - {Config::Retro::Values::ROTATE_RIGHT, "Rotated Right"}, - {Config::Retro::Values::UPSIDE_DOWN, "Upside Down"}, - {nullptr, nullptr}, - }, - Config::Retro::Values::TOP_BOTTOM - }, #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) { Config::Retro::Keys::HYBRID_RATIO, diff --git a/src/libretro/config.hpp b/src/libretro/config.hpp index 1a839e0a..88375457 100644 --- a/src/libretro/config.hpp +++ b/src/libretro/config.hpp @@ -38,11 +38,7 @@ namespace melonds { ); /// Called when settings have been updated mid-game - void UpdateConfig( - const std::optional& nds_info, - const std::optional& header, - ScreenLayoutData& screenLayout - ) noexcept; + void UpdateConfig(ScreenLayoutData& screenLayout) noexcept; bool update_option_visibility(); extern struct retro_core_options_v2 options_us; extern struct retro_core_option_v2_definition option_defs_us[]; @@ -226,10 +222,8 @@ namespace melonds { constexpr unsigned MAX_SCREEN_LAYOUTS = 8; // Chosen arbitrarily; if you need more, open a PR [[nodiscard]] unsigned NumberOfScreenLayouts() noexcept; [[nodiscard]] std::array ScreenLayouts() noexcept; - [[nodiscard]] [[deprecated("Use ScreenLayouts instead")]] ScreenLayout ScreenLayout() noexcept; [[nodiscard]] unsigned ScreenGap() noexcept; [[nodiscard]] unsigned HybridRatio() noexcept; - [[nodiscard]] [[deprecated("Use ScreenLayouts instead")]] ScreenSwapMode ScreenSwapMode() noexcept; [[nodiscard]] SmallScreenLayout SmallScreenLayout() noexcept; [[nodiscard]] TouchMode TouchMode() noexcept; } diff --git a/src/libretro/libretro.cpp b/src/libretro/libretro.cpp index 9bcd8a4f..50d131d3 100644 --- a/src/libretro/libretro.cpp +++ b/src/libretro/libretro.cpp @@ -58,7 +58,6 @@ using std::nullopt; namespace melonds { static InputState input_state; static ScreenLayoutData screenLayout; - static unsigned currentLayoutIndex = 0; static bool swap_screen_toggled = false; static bool mic_state_toggled = false; static bool deferred_initialization_pending = false; @@ -324,11 +323,9 @@ PUBLIC_SYMBOL void retro_run(void) { if (melonds::render::ReadyToRender()) { // If the global state needed for rendering is ready... if (melonds::input_state.CycleLayoutPressed()) { - unsigned numberOfScreenLayouts = config::screen::NumberOfScreenLayouts(); - auto screenLayouts = config::screen::ScreenLayouts(); - currentLayoutIndex = (currentLayoutIndex + 1) % numberOfScreenLayouts; + screenLayout.NextLayout(); + retro::debug("Switched to screen layout %d of %d", screenLayout.LayoutIndex() + 1, screenLayout.NumberOfLayouts()); - screenLayout.SetLayout(screenLayouts[currentLayoutIndex]); screenLayout.Update(render::CurrentRenderer()); melonds::opengl::RequestOpenGlRefresh(); } @@ -344,8 +341,7 @@ PUBLIC_SYMBOL void retro_run(void) { } if (bool updated = false; retro::environment(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) { - optional header = NDSCart::Cart ? std::make_optional(NDSCart::Cart->GetHeader()) : std::nullopt; - melonds::UpdateConfig(retro::content::get_loaded_nds_info(), header, screenLayout); + melonds::UpdateConfig(screenLayout); struct retro_system_av_info updated_av_info{}; retro_get_system_av_info(&updated_av_info); diff --git a/src/libretro/screenlayout.cpp b/src/libretro/screenlayout.cpp index adb14840..e3af456e 100644 --- a/src/libretro/screenlayout.cpp +++ b/src/libretro/screenlayout.cpp @@ -23,6 +23,8 @@ melonds::ScreenLayoutData::ScreenLayoutData() { this->buffer_ptr = nullptr; this->hybrid_ratio = 2; + this->_dirty = true; // Uninitialized + this->_numberOfLayouts = 1; } melonds::ScreenLayoutData::~ScreenLayoutData() { @@ -98,7 +100,7 @@ void melonds::ScreenLayoutData::CopyHybridScreen(const uint32_t* src, ScreenId s void melonds::ScreenLayoutData::draw_cursor(int32_t x, int32_t y) { auto *base_offset = (uint32_t *) buffer_ptr; - uint32_t scale = layout == ScreenLayout::HybridBottom ? hybrid_ratio : 1; + uint32_t scale = Layout() == ScreenLayout::HybridBottom ? hybrid_ratio : 1; float cursorSize = melonds::config::video::CursorSize(); uint32_t start_y = std::clamp(y - cursorSize, 0, screen_height) * scale; uint32_t end_y = std::clamp(y + cursorSize, 0, screen_height) * scale; @@ -234,7 +236,7 @@ void melonds::ScreenLayoutData::Update(melonds::Renderer renderer) noexcept { this->buffer_height = (this->screen_height * this->hybrid_ratio); this->buffer_stride = this->buffer_width * pixel_size; - if (layout == ScreenLayout::HybridTop) { + if (Layout() == ScreenLayout::HybridTop) { this->touch_offset_x = (this->screen_width * this->hybrid_ratio) + (this->hybrid_ratio / 2); this->touch_offset_y = (this->screen_height * (this->hybrid_ratio - 1)); } else { @@ -260,29 +262,6 @@ void melonds::ScreenLayoutData::Update(melonds::Renderer renderer) noexcept { memset(this->buffer_ptr, 0, new_size); } } -} - -melonds::ScreenLayout melonds::SwapLayout(ScreenLayout layout) noexcept { - switch (layout) { - case ScreenLayout::BottomOnly: - return ScreenLayout::TopOnly; - case ScreenLayout::TopOnly: - return ScreenLayout::BottomOnly; - case ScreenLayout::BottomTop: - return ScreenLayout::TopBottom; - case ScreenLayout::TopBottom: - return ScreenLayout::BottomTop; - case ScreenLayout::LeftRight: - return ScreenLayout::RightLeft; - case ScreenLayout::RightLeft: - return ScreenLayout::LeftRight; - case ScreenLayout::HybridTop: - return ScreenLayout::HybridBottom; - case ScreenLayout::HybridBottom: - return ScreenLayout::HybridTop; - default: - // No swap for other types - return layout; - } + _dirty = false; } \ No newline at end of file diff --git a/src/libretro/screenlayout.hpp b/src/libretro/screenlayout.hpp index 4949bb63..05b0de42 100644 --- a/src/libretro/screenlayout.hpp +++ b/src/libretro/screenlayout.hpp @@ -28,8 +28,6 @@ namespace melonds { /// The native height of the Nintendo DS screens, in pixels constexpr int VIDEO_HEIGHT = 192; - ScreenLayout SwapLayout(ScreenLayout layout) noexcept; - class ScreenLayoutData { public: ScreenLayoutData(); @@ -41,6 +39,8 @@ namespace melonds { void Update(Renderer renderer) noexcept; + bool Dirty() const noexcept { return _dirty; } + void* Buffer() noexcept { return buffer_ptr; } const void* Buffer() const noexcept { return buffer_ptr; } @@ -52,22 +52,50 @@ namespace melonds { unsigned ScreenWidth() const noexcept { return screen_width; } unsigned ScreenHeight() const noexcept { return screen_height; } - ScreenLayout Layout() const noexcept { return layout; } - void SetLayout(ScreenLayout _layout) noexcept { this->layout = _layout; } + unsigned LayoutIndex() const noexcept { return _layoutIndex; } + unsigned NumberOfLayouts() const noexcept { return _numberOfLayouts; } + ScreenLayout Layout() const noexcept { return _layouts[_layoutIndex]; } + void SetLayouts(const std::array& layouts, unsigned numberOfLayouts) noexcept { + ScreenLayout oldLayout = Layout(); + + if (_layoutIndex >= numberOfLayouts) { + _layoutIndex = numberOfLayouts - 1; + } + _layouts = layouts; + _numberOfLayouts = numberOfLayouts; + + if (oldLayout != Layout()) _dirty = true; + } - bool IsHybridLayout() const noexcept { return layout == ScreenLayout::HybridTop || layout == ScreenLayout::HybridBottom; } + void NextLayout() noexcept { + ScreenLayout oldLayout = Layout(); + _layoutIndex = (_layoutIndex + 1) % _numberOfLayouts; + + if (oldLayout != Layout()) _dirty = true; + } + + bool IsHybridLayout() const noexcept { return Layout() == ScreenLayout::HybridTop || Layout() == ScreenLayout::HybridBottom; } SmallScreenLayout HybridSmallScreenLayout() const noexcept { return hybrid_small_screen; } - void HybridSmallScreenLayout(SmallScreenLayout _layout) noexcept { hybrid_small_screen = _layout; } + void HybridSmallScreenLayout(SmallScreenLayout _layout) noexcept { + if (IsHybridLayout() && _layout != hybrid_small_screen) _dirty = true; + hybrid_small_screen = _layout; + } - bool TopScreenEnabled() const noexcept { return layout != ScreenLayout::BottomOnly; } - bool BottomScreenEnabled() const noexcept { return layout != ScreenLayout::TopOnly; } + bool TopScreenEnabled() const noexcept { return Layout() != ScreenLayout::BottomOnly; } + bool BottomScreenEnabled() const noexcept { return Layout() != ScreenLayout::TopOnly; } unsigned ScreenGap() const noexcept { return screen_gap_unscaled; } - void ScreenGap(unsigned _screen_gap) noexcept { screen_gap_unscaled = _screen_gap; } + void ScreenGap(unsigned _screen_gap) noexcept { + if (_screen_gap != screen_gap_unscaled) _dirty = true; + screen_gap_unscaled = _screen_gap; + } unsigned ScaledScreenGap() const noexcept { return screen_gap_unscaled * scale; } unsigned HybridRatio() const noexcept { return hybrid_ratio; } - void HybridRatio(unsigned _hybrid_ratio) noexcept { hybrid_ratio = _hybrid_ratio; } + void HybridRatio(unsigned _hybrid_ratio) noexcept { + if (IsHybridLayout() && _hybrid_ratio != hybrid_ratio) _dirty = true; + hybrid_ratio = _hybrid_ratio; + } unsigned TopScreenOffset() const noexcept { return top_screen_offset; } unsigned BottomScreenOffset() const noexcept { return bottom_screen_offset; } @@ -75,6 +103,7 @@ namespace melonds { unsigned TouchOffsetX() const noexcept { return touch_offset_x; } unsigned TouchOffsetY() const noexcept { return touch_offset_y; } private: + bool _dirty; bool direct_copy; unsigned pixel_size; @@ -93,13 +122,16 @@ namespace melonds { SmallScreenLayout hybrid_small_screen; unsigned hybrid_ratio; + unsigned _layoutIndex; + unsigned _numberOfLayouts; + std::array _layouts; + // TODO: Move the buffer to a separate class unsigned buffer_width; unsigned buffer_height; unsigned buffer_stride; size_t buffer_len; uint16_t *buffer_ptr; - ScreenLayout layout; }; } #endif //MELONDS_DS_SCREENLAYOUT_HPP