diff --git a/src/libretro/config/constants.hpp b/src/libretro/config/constants.hpp index 9e2f47d6..97f76603 100644 --- a/src/libretro/config/constants.hpp +++ b/src/libretro/config/constants.hpp @@ -202,6 +202,8 @@ namespace MelonDsDs::config { static constexpr const char *const ENGLISH = "en"; static constexpr const char *const EXISTING = "existing"; static constexpr const char *const FIRMWARE = "firmware"; + static constexpr const char *const FLIPPED_HYBRID_BOTTOM = "flipped-hybrid-bottom"; + static constexpr const char *const FLIPPED_HYBRID_TOP = "flipped-hybrid-top"; static constexpr const char *const FRENCH = "fr"; static constexpr const char *const GERMAN = "de"; static constexpr const char *const HOLD = "hold"; diff --git a/src/libretro/config/definitions/screen.hpp b/src/libretro/config/definitions/screen.hpp index 13fd29a0..1d0ab3da 100644 --- a/src/libretro/config/definitions/screen.hpp +++ b/src/libretro/config/definitions/screen.hpp @@ -302,6 +302,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -326,6 +328,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -350,6 +354,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -374,6 +380,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -398,6 +406,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -422,6 +432,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -446,6 +458,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, @@ -470,6 +484,8 @@ namespace MelonDsDs::config::definitions { {MelonDsDs::config::values::BOTTOM, "Bottom Only"}, {MelonDsDs::config::values::HYBRID_TOP, "Hybrid (Focus Top)"}, {MelonDsDs::config::values::HYBRID_BOTTOM, "Hybrid (Focus Bottom)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_TOP, "Flipped Hybrid (Focus Top)"}, + {MelonDsDs::config::values::FLIPPED_HYBRID_BOTTOM, "Flipped Hybrid (Focus Bottom)"}, {MelonDsDs::config::values::ROTATE_LEFT, "Rotated Left"}, {MelonDsDs::config::values::ROTATE_RIGHT, "Rotated Right"}, {MelonDsDs::config::values::UPSIDE_DOWN, "Upside Down"}, diff --git a/src/libretro/config/parse.hpp b/src/libretro/config/parse.hpp index a3a58ec6..2d9a8902 100644 --- a/src/libretro/config/parse.hpp +++ b/src/libretro/config/parse.hpp @@ -129,6 +129,8 @@ namespace MelonDsDs { if (value == config::values::BOTTOM) return ScreenLayout::BottomOnly; if (value == config::values::HYBRID_TOP) return ScreenLayout::HybridTop; if (value == config::values::HYBRID_BOTTOM) return ScreenLayout::HybridBottom; + if (value == config::values::FLIPPED_HYBRID_TOP) return ScreenLayout::FlippedHybridTop; + if (value == config::values::FLIPPED_HYBRID_BOTTOM) return ScreenLayout::FlippedHybridBottom; if (value == config::values::ROTATE_LEFT) return ScreenLayout::TurnLeft; if (value == config::values::ROTATE_RIGHT) return ScreenLayout::TurnRight; if (value == config::values::UPSIDE_DOWN) return ScreenLayout::UpsideDown; diff --git a/src/libretro/config/types.hpp b/src/libretro/config/types.hpp index 64551a20..bdfac2db 100644 --- a/src/libretro/config/types.hpp +++ b/src/libretro/config/types.hpp @@ -128,9 +128,11 @@ namespace MelonDsDs { BottomOnly = 5, HybridTop = 6, HybridBottom = 7, - TurnLeft = 8, - TurnRight = 9, - UpsideDown = 10, + FlippedHybridTop = 8, + FlippedHybridBottom = 9, + TurnLeft = 10, + TurnRight = 11, + UpsideDown = 12, }; enum class HybridSideScreenDisplay { diff --git a/src/libretro/format.cpp b/src/libretro/format.cpp index b244fa8d..217656e3 100644 --- a/src/libretro/format.cpp +++ b/src/libretro/format.cpp @@ -473,6 +473,12 @@ auto fmt::formatter::format(MelonDsDs::ScreenLayout lay case MelonDsDs::ScreenLayout::HybridBottom: name = "HybridBottom"; break; + case MelonDsDs::ScreenLayout::FlippedHybridTop: + name = "FlippedHybridTop"; + break; + case MelonDsDs::ScreenLayout::FlippedHybridBottom: + name = "FlippedHybridBottom"; + break; case MelonDsDs::ScreenLayout::TurnLeft: name = "TurnLeft"; break; diff --git a/src/libretro/input.cpp b/src/libretro/input.cpp index c5850571..1952f46f 100644 --- a/src/libretro/input.cpp +++ b/src/libretro/input.cpp @@ -254,6 +254,7 @@ glm::uvec2 MelonDsDs::InputState::ConsoleTouchCoordinates(const ScreenLayoutData switch (layout.Layout()) { case ScreenLayout::HybridBottom: + case ScreenLayout::FlippedHybridBottom: if (layout.HybridSmallScreenLayout() == HybridSideScreenDisplay::One) { // If the touch screen is only shown in the hybrid-screen position... clampedTouch = clamp(hybridTouchPosition, ivec2(0), NDS_SCREEN_SIZE - 1); diff --git a/src/libretro/render/opengl.cpp b/src/libretro/render/opengl.cpp index b1af7180..d717c1c8 100644 --- a/src/libretro/render/opengl.cpp +++ b/src/libretro/render/opengl.cpp @@ -93,6 +93,7 @@ constexpr array GetPositionIndexes(MelonDsDs::ScreenLayout layout) } break; case ScreenLayout::HybridTop: + case ScreenLayout::FlippedHybridTop: for (unsigned i = 0; i < VERTEXES_PER_SCREEN; ++i) { indexes[i] = hybridPositionIndexes[i]; indexes[i + VERTEXES_PER_SCREEN] = bottomPositionIndexes[i]; @@ -100,6 +101,7 @@ constexpr array GetPositionIndexes(MelonDsDs::ScreenLayout layout) } break; case ScreenLayout::HybridBottom: + case ScreenLayout::FlippedHybridBottom: for (unsigned i = 0; i < VERTEXES_PER_SCREEN; ++i) { indexes[i] = hybridPositionIndexes[i]; indexes[i + VERTEXES_PER_SCREEN] = topPositionIndexes[i]; @@ -118,6 +120,8 @@ constexpr unsigned GetVertexCount(ScreenLayout layout, MelonDsDs::HybridSideScre return 6; // 1 screen, 2 triangles case ScreenLayout::HybridTop: case ScreenLayout::HybridBottom: + case ScreenLayout::FlippedHybridTop: + case ScreenLayout::FlippedHybridBottom: if (hybridScreen == MelonDsDs::HybridSideScreenDisplay::Both) return 18; // 3 screens, 6 triangles [[fallthrough]]; @@ -566,6 +570,7 @@ void MelonDsDs::OpenGLRenderState::InitVertices(const ScreenLayoutData& screenLa } break; case ScreenLayout::HybridTop: + case ScreenLayout::FlippedHybridTop: for (unsigned i = 0; i < VERTEXES_PER_SCREEN; ++i) { // Hybrid screen screen_vertices[i] = { @@ -588,6 +593,7 @@ void MelonDsDs::OpenGLRenderState::InitVertices(const ScreenLayoutData& screenLa } break; case ScreenLayout::HybridBottom: + case ScreenLayout::FlippedHybridBottom: for (unsigned i = 0; i < VERTEXES_PER_SCREEN; ++i) { // Hybrid screen screen_vertices[i] = { diff --git a/src/libretro/render/software.cpp b/src/libretro/render/software.cpp index 26103dd7..2aa1324d 100644 --- a/src/libretro/render/software.cpp +++ b/src/libretro/render/software.cpp @@ -168,7 +168,7 @@ void MelonDsDs::SoftwareRenderState::CombineScreens( ScreenLayout layout = screenLayout.Layout(); if (IsHybridLayout(layout)) { - auto primaryBuffer = layout == ScreenLayout::HybridTop ? topBuffer : bottomBuffer; + auto primaryBuffer = layout == ScreenLayout::HybridTop || layout == ScreenLayout::FlippedHybridTop ? topBuffer : bottomBuffer; hybridScaler.Scale(hybridBuffer[0], primaryBuffer.data()); buffer.CopyRows( @@ -179,12 +179,12 @@ void MelonDsDs::SoftwareRenderState::CombineScreens( HybridSideScreenDisplay smallScreenLayout = screenLayout.HybridSmallScreenLayout(); - if (smallScreenLayout == HybridSideScreenDisplay::Both || layout == ScreenLayout::HybridBottom) { + if (smallScreenLayout == HybridSideScreenDisplay::Both || layout == ScreenLayout::HybridBottom || layout == ScreenLayout::FlippedHybridBottom) { // If we should display both screens, or if the bottom one is the primary... buffer.CopyRows(topBuffer.data(), screenLayout.GetTopScreenTranslation(), NDS_SCREEN_SIZE); } - if (smallScreenLayout == HybridSideScreenDisplay::Both || layout == ScreenLayout::HybridTop) { + if (smallScreenLayout == HybridSideScreenDisplay::Both || layout == ScreenLayout::HybridTop || layout == ScreenLayout::FlippedHybridTop) { // If we should display both screens, or if the top one is being focused... buffer.CopyRows(bottomBuffer.data(), screenLayout.GetBottomScreenTranslation(), NDS_SCREEN_SIZE); } diff --git a/src/libretro/screenlayout.cpp b/src/libretro/screenlayout.cpp index 245cc6c6..093fb414 100644 --- a/src/libretro/screenlayout.cpp +++ b/src/libretro/screenlayout.cpp @@ -108,6 +108,33 @@ constexpr mat3 HybridSoutheastMatrix(unsigned resolutionScale, unsigned hybridRa ); } +/// For the east flipped hybrid screen +constexpr mat3 FlippedHybridEastMatrix(unsigned resolutionScale, unsigned hybridRatio) noexcept { + using namespace MelonDsDs; + return math::ts( + vec2(resolutionScale * NDS_SCREEN_WIDTH, 0), + vec2(resolutionScale * hybridRatio) + ); +} + +/// For the northwest flipped hybrid screen +constexpr mat3 FlippedHybridNorthwestMatrix(unsigned resolutionScale, unsigned hybridRatio) noexcept { + using namespace MelonDsDs; + return math::ts( + vec2(0), + vec2(resolutionScale) + ); +} + +/// For the southwest flipped hybrid screen +constexpr mat3 FlippedHybridSouthwestMatrix(unsigned resolutionScale, unsigned hybridRatio) noexcept { + using namespace MelonDsDs; + return math::ts( + vec2(0, resolutionScale * NDS_SCREEN_HEIGHT * (hybridRatio - 1)), + vec2(resolutionScale) + ); +} + mat3 MelonDsDs::ScreenLayoutData::GetTopScreenMatrix(unsigned scale) const noexcept { ZoneScopedN(TracyFunction); switch (Layout()) { @@ -125,6 +152,9 @@ mat3 MelonDsDs::ScreenLayoutData::GetTopScreenMatrix(unsigned scale) const noexc case ScreenLayout::HybridTop: case ScreenLayout::HybridBottom: return HybridNortheastMatrix(scale, hybridRatio); + case ScreenLayout::FlippedHybridTop: + case ScreenLayout::FlippedHybridBottom: + return FlippedHybridNorthwestMatrix(scale, hybridRatio); default: return mat3(1); } @@ -147,6 +177,9 @@ mat3 MelonDsDs::ScreenLayoutData::GetBottomScreenMatrix(unsigned scale) const no case ScreenLayout::HybridTop: case ScreenLayout::HybridBottom: return HybridSoutheastMatrix(scale, hybridRatio); + case ScreenLayout::FlippedHybridTop: + case ScreenLayout::FlippedHybridBottom: + return FlippedHybridSouthwestMatrix(scale, hybridRatio); default: return mat3(1); } @@ -158,6 +191,9 @@ glm::mat3 MelonDsDs::ScreenLayoutData::GetHybridScreenMatrix(unsigned scale) con case ScreenLayout::HybridBottom: case ScreenLayout::HybridTop: return HybridWestMatrix(scale, hybridRatio); + case ScreenLayout::FlippedHybridBottom: + case ScreenLayout::FlippedHybridTop: + return FlippedHybridEastMatrix(scale, hybridRatio); default: return mat3(1); } diff --git a/src/libretro/screenlayout.hpp b/src/libretro/screenlayout.hpp index fbefb2a0..5d127709 100644 --- a/src/libretro/screenlayout.hpp +++ b/src/libretro/screenlayout.hpp @@ -77,6 +77,8 @@ namespace MelonDsDs { switch (layout) { case ScreenLayout::HybridTop: case ScreenLayout::HybridBottom: + case ScreenLayout::FlippedHybridTop: + case ScreenLayout::FlippedHybridBottom: return true; default: return false;