Files
spice2x-r3d/src/spice2x/overlay/windows/sdvx_sub.cpp
T
bicarus-devandGitHub 45a52cff90 sdvx: landscape mode (#277)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Add `SDVX Landscape Mode` option, allowing you to play SDVX in landscape
monitor orientation, with black borders on left and right - similar to
how EAC does it. This is meant to be an alternative to what people do
today, which is launching in windowed mode.

By default, with just `-sdvxlandscape` enabled, EG will launch at
1920x1080 (transposed from the original 1080x1920 resolution).

It is possible to combine with `-forceres` to launch at higher
resolutions. At some point though, when rendering at large resolutions
past 1440p, at some point scaling may break due to #276.

Disabled on 32-bit SDVX since dx9 `CreateDeviceEx` call is required;
`CreateDevice` won't work. For the same reason this isn't being made a
generic option for museca/rb/etc. In theory you can supply
`-sdvxlandscape` to games like IIDX and play landscape games in portrait
mode, although again, scaling my break due to #276.

Also, add new options (bottomleft/right) for subscreen overlay position
so that they don't overlap with the main screen in landscape mode.

## Compiling
🙂

## Testing
Tested a couple versions of VW and EG.
2025-03-26 20:21:05 -07:00

93 lines
3.7 KiB
C++

#undef CINTERFACE
#include "avs/game.h"
#include "sdvx_sub.h"
#include "games/sdvx/sdvx.h"
#include "hooks/graphics/graphics.h"
namespace overlay::windows {
SDVXSubScreen::SDVXSubScreen(SpiceOverlay *overlay) : GenericSubScreen(overlay) {
this->title = "SDVX Sub Screen";
bool isValkyrieCabinetMode = avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H';
if (!isValkyrieCabinetMode) {
this->disabled_message = "Valkyrie Model mode is not enabled!";
} else if (GRAPHICS_WINDOWED) {
if (GRAPHICS_PREVENT_SECONDARY_WINDOW) {
this->disabled_message = "Subscreen has been disabled by the user (-sdvxnosub).";
} else {
this->disabled_message = "Overlay unavailable in windowed mode! Use the second window instead.";
}
}
const auto padding = ImGui::GetFrameHeight() / 2;
switch (games::sdvx::OVERLAY_POS) {
case games::sdvx::SDVX_OVERLAY_BOTTOM_LEFT:
case games::sdvx::SDVX_OVERLAY_BOTTOM_RIGHT:
this->init_size.x = (ImGui::GetIO().DisplaySize.x - (ImGui::GetIO().DisplaySize.y * 9 / 16)) / 2 - padding;
this->init_size.y = (this->init_size.x * 9 / 16) + ImGui::GetFrameHeight();
break;
case games::sdvx::SDVX_OVERLAY_TOP:
case games::sdvx::SDVX_OVERLAY_BOTTOM:
case games::sdvx::SDVX_OVERLAY_MIDDLE:
default:
this->init_size = ImVec2(ImGui::GetIO().DisplaySize.x - (padding * 2), 0.f);
this->init_size.y = (this->init_size.x * 9 / 16) + ImGui::GetFrameHeight();
if (GRAPHICS_FS_FORCE_LANDSCAPE) {
this->init_size.x /= 2;
this->init_size.y /= 2;
}
break;
}
this->init_pos = ImVec2(ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2, 0);
switch (games::sdvx::OVERLAY_POS) {
case games::sdvx::SDVX_OVERLAY_BOTTOM_LEFT:
this->init_pos.x = 0;
this->init_pos.y = ImGui::GetIO().DisplaySize.y - this->init_size.y;
break;
case games::sdvx::SDVX_OVERLAY_BOTTOM_RIGHT:
this->init_pos.x = ImGui::GetIO().DisplaySize.x - this->init_size.x;
this->init_pos.y = ImGui::GetIO().DisplaySize.y - this->init_size.y;
break;
case games::sdvx::SDVX_OVERLAY_TOP:
this->init_pos.y = padding;
break;
case games::sdvx::SDVX_OVERLAY_BOTTOM:
this->init_pos.y = ImGui::GetIO().DisplaySize.y - this->init_size.y - padding;
break;
case games::sdvx::SDVX_OVERLAY_MIDDLE:
default:
this->init_pos.y = (ImGui::GetIO().DisplaySize.y / 2) - (this->init_size.y / 2);
break;
}
}
void SDVXSubScreen::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {
if (!this->get_active()) {
return;
}
// SDVX Valkyrie cab needs math to make things work
// what the game expects from touch screen:
// [1080, 0 1920, 1080]
// [0, 0 0, 1920]
// actual cursor position given by x_in (on the overlay, normalized):
// [0, 0 1, 0]
// [0, 1 1, 1]
// Basically, the game operates on rotated coordinates, but on top of that,
// it needs to be adjusted so they match up with the subscreen overlay.
// so the math is:
// Xin(0, 1) => Yout(0, 1920)
// Yin(0, 1) => Xout(1080, 0)
*x_out = ImGui::GetIO().DisplaySize.x * (1.f - xy_in.y);
*y_out = ImGui::GetIO().DisplaySize.y * xy_in.x;
}
}