mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
gitadora: (arena model) single window mode + subscreen overlay (#486)
## Link to GitHub Issue, if one exists #477 ## Description of change This is a work in progress. What works: - [x] subscreen overlay shows the touch screen image (in windowed mode) - [x] touch works in the overlay - [x] only the main window is shown, other windows are not launched What doesn't: - [ ] game occasionally crashes when entering test menu? - [ ] full screen mode is not tested at all due to monitor requirements - [ ] need more polish (various options to control the behavior)
This commit is contained in:
@@ -554,6 +554,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
||||
overlay/windows/camera_control.cpp
|
||||
overlay/windows/card_manager.cpp
|
||||
overlay/windows/drs_dancefloor.cpp
|
||||
overlay/windows/gfdm_sub.cpp
|
||||
overlay/windows/screen_resize.cpp
|
||||
overlay/windows/sdvx_sub.cpp
|
||||
overlay/windows/config.cpp
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "cfg/configurator.h"
|
||||
#include "hooks/audio/mme.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "overlay/overlay.h"
|
||||
#include "util/cpuutils.h"
|
||||
#include "util/detour.h"
|
||||
@@ -19,8 +20,10 @@ namespace games::gitadora {
|
||||
// settings
|
||||
bool TWOCHANNEL = false;
|
||||
std::optional<unsigned int> CAB_TYPE = std::nullopt;
|
||||
bool ARENA_SINGLE_WINDOW = false;
|
||||
bool P1_LEFTY = false;
|
||||
bool P2_LEFTY = false;
|
||||
std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
||||
|
||||
/*
|
||||
* Prevent GitaDora from creating folders on F drive
|
||||
@@ -285,6 +288,13 @@ namespace games::gitadora {
|
||||
|
||||
// volume change prevention
|
||||
hooks::audio::mme::init(avs::game::DLL_INSTANCE);
|
||||
|
||||
// touch hook
|
||||
if (ARENA_SINGLE_WINDOW) {
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook("GITADORA", avs::game::DLL_INSTANCE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@ namespace games::gitadora {
|
||||
// settings
|
||||
extern bool TWOCHANNEL;
|
||||
extern std::optional<unsigned int> CAB_TYPE;
|
||||
extern bool ARENA_SINGLE_WINDOW;
|
||||
extern bool P1_LEFTY;
|
||||
extern bool P2_LEFTY;
|
||||
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
||||
|
||||
class GitaDoraGame : public games::Game {
|
||||
public:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "cfg/screen_resize.h"
|
||||
#include "games/gitadora/gitadora.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "games/sdvx/sdvx.h"
|
||||
#include "games/mfc/mfc.h"
|
||||
@@ -1170,9 +1171,15 @@ IDirect3DSurface9 *graphics_d3d9_ldj_get_sub_screen() {
|
||||
}
|
||||
|
||||
static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) {
|
||||
// iidx/sdvx
|
||||
int swapchain = 1;
|
||||
if (games::gitadora::is_arena_model()) {
|
||||
swapchain = 3;
|
||||
}
|
||||
|
||||
if (!ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE && SUB_SWAP_CHAIN == nullptr) {
|
||||
ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE = true;
|
||||
HRESULT hr = wrapped_device->GetSwapChain(1, &SUB_SWAP_CHAIN);
|
||||
HRESULT hr = wrapped_device->GetSwapChain(swapchain, &SUB_SWAP_CHAIN);
|
||||
if (FAILED(hr)) {
|
||||
log_warning(
|
||||
"graphics::d3d9",
|
||||
@@ -1383,7 +1390,9 @@ void graphics_d3d9_on_present(
|
||||
// for IIDX TDJ / SDVX UFC, handle subscreen
|
||||
const bool is_vm = games::sdvx::is_valkyrie_model();
|
||||
const bool is_tdj = avs::game::is_model("LDJ") && games::iidx::TDJ_MODE;
|
||||
if (is_vm || is_tdj) {
|
||||
const bool is_gfdm_arena =
|
||||
games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW;
|
||||
if (is_vm || is_tdj || is_gfdm_arena) {
|
||||
graphics_d3d9_ldj_on_present(wrapped_device);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mutex>
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "games/gitadora/gitadora.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "overlay/overlay.h"
|
||||
#include "util/flags_helper.h"
|
||||
@@ -249,8 +250,16 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::CreateAdditionalSwapChain(
|
||||
WRAP_VERBOSE;
|
||||
|
||||
HRESULT hr = pReal->CreateAdditionalSwapChain(pPresentationParameters, ppSwapChain);
|
||||
|
||||
bool create_swap_chain = false;
|
||||
if (avs::game::is_model({"LDJ", "KFC"})) {
|
||||
create_swap_chain = true;
|
||||
} else if (games::gitadora::is_arena_model() &&
|
||||
games::gitadora::ARENA_SINGLE_WINDOW &&
|
||||
pPresentationParameters->BackBufferWidth == 800) {
|
||||
create_swap_chain = true;
|
||||
}
|
||||
|
||||
if (create_swap_chain) {
|
||||
if (SUCCEEDED(hr) && !sub_swapchain) {
|
||||
sub_swapchain = new WrappedIDirect3DSwapChain9(this, *ppSwapChain);
|
||||
sub_swapchain->should_run_hooks = false;
|
||||
@@ -295,7 +304,17 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::GetSwapChain(
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
bool swap = false;
|
||||
if (iSwapChain == 1 && avs::game::is_model({"LDJ", "KFC"})) {
|
||||
swap = true;
|
||||
}
|
||||
if (games::gitadora::is_arena_model() &&
|
||||
games::gitadora::ARENA_SINGLE_WINDOW &&
|
||||
iSwapChain == 3) {
|
||||
swap = true;
|
||||
}
|
||||
|
||||
if (swap) {
|
||||
if (sub_swapchain) {
|
||||
sub_swapchain->AddRef();
|
||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(sub_swapchain);
|
||||
|
||||
@@ -98,6 +98,7 @@ static decltype(SetCursor) *SetCursor_orig = nullptr;
|
||||
static decltype(SetWindowLongA) *SetWindowLongA_orig = nullptr;
|
||||
static decltype(SetWindowLongW) *SetWindowLongW_orig = nullptr;
|
||||
static decltype(SetWindowPos) *SetWindowPos_orig = nullptr;
|
||||
static decltype(ShowWindow) *ShowWindow_orig = nullptr;
|
||||
|
||||
static void reset_window_hook(HWND hWnd) {
|
||||
overlay::destroy(hWnd);
|
||||
@@ -377,7 +378,7 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
||||
bool is_sdvx_sub_window = avs::game::is_model("KFC") && window_name.ends_with(" Sub Screen");
|
||||
bool is_gfdm_sub_window = games::gitadora::is_arena_model() && window_name.ends_with("SMALL");
|
||||
|
||||
// TDJ windowed mode with subscreen: hide maximize button
|
||||
// hide maximize button (prevent misaligned touches)
|
||||
if ((is_tdj_sub_window && GRAPHICS_IIDX_WSUB) || is_sdvx_sub_window || is_gfdm_sub_window) {
|
||||
dwStyle &= ~(WS_MAXIMIZEBOX);
|
||||
}
|
||||
@@ -385,7 +386,7 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
||||
if (is_gfdm_sub_window) {
|
||||
dwStyle &= ~(WS_SIZEBOX);
|
||||
}
|
||||
if ((is_tdj_sub_window || is_sdvx_sub_window || is_gfdm_sub_window) && GRAPHICS_WSUB_BORDERLESS) {
|
||||
if ((is_tdj_sub_window || is_sdvx_sub_window) && GRAPHICS_WSUB_BORDERLESS) {
|
||||
dwStyle &= ~(WS_OVERLAPPEDWINDOW);
|
||||
}
|
||||
|
||||
@@ -433,7 +434,8 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
||||
graphics_hook_subscreen_window(SDVX_SUBSCREEN_WINDOW);
|
||||
}
|
||||
|
||||
if (is_gfdm_sub_window) {
|
||||
// only hook touch window if multiple windows are allowed
|
||||
if (is_gfdm_sub_window && !games::gitadora::ARENA_SINGLE_WINDOW) {
|
||||
GFDM_SUBSCREEN_WINDOW = result;
|
||||
graphics_hook_subscreen_window(GFDM_SUBSCREEN_WINDOW);
|
||||
}
|
||||
@@ -682,6 +684,18 @@ static BOOL WINAPI SetWindowPos_hook(HWND hWnd, HWND hWndInsertAfter,
|
||||
return SetWindowPos_orig(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
|
||||
}
|
||||
|
||||
static BOOL WINAPI ShowWindow_hook(HWND hWnd, int nCmdShow) {
|
||||
if (games::gitadora::is_arena_model() &&
|
||||
games::gitadora::ARENA_SINGLE_WINDOW &&
|
||||
hWnd != GRAPHICS_WINDOW_MAIN) {
|
||||
log_info("graphics", "ShowWindow_hook - hiding sub window 0x{}", fmt::ptr(hWnd));
|
||||
return true;
|
||||
}
|
||||
|
||||
// call original
|
||||
return ShowWindow_orig(hWnd, nCmdShow);
|
||||
}
|
||||
|
||||
static ATOM WINAPI RegisterClassA_hook(const WNDCLASSA *lpWndClass) {
|
||||
|
||||
// check for null
|
||||
@@ -824,6 +838,7 @@ void graphics_init() {
|
||||
SetWindowLongA_orig = detour::iat_try("SetWindowLongA", SetWindowLongA_hook);
|
||||
SetWindowLongW_orig = detour::iat_try("SetWindowLongW", SetWindowLongW_hook);
|
||||
SetWindowPos_orig = detour::iat_try("SetWindowPos", SetWindowPos_hook);
|
||||
ShowWindow_orig = detour::iat_try("ShowWindow", ShowWindow_hook);
|
||||
|
||||
detour::iat_try("MessageBoxA", MessageBoxA_hook);
|
||||
detour::iat_try("MessageBoxExA", MessageBoxExA_hook);
|
||||
|
||||
@@ -589,9 +589,15 @@ int main_implementation(int argc, char *argv[]) {
|
||||
if (options[launcher::Options::GitaDoraCabinetType].is_active()) {
|
||||
games::gitadora::CAB_TYPE = options[launcher::Options::GitaDoraCabinetType].value_uint32();
|
||||
}
|
||||
if (options[launcher::Options::GitaDoraArenaSingleWindow].value_bool() && GRAPHICS_WINDOWED) {
|
||||
games::gitadora::ARENA_SINGLE_WINDOW = true;
|
||||
}
|
||||
if (options[launcher::Options::GitaDoraWailHold].is_active()) {
|
||||
socd::TILT_HOLD_MS = options[launcher::Options::GitaDoraWailHold].value_uint32();
|
||||
}
|
||||
if (options[launcher::Options::GitaDoraSubOverlaySize].is_active()) {
|
||||
games::gitadora::SUBSCREEN_OVERLAY_SIZE = options[launcher::Options::GitaDoraSubOverlaySize].value_text();
|
||||
}
|
||||
if (options[launcher::Options::LoadNostalgiaModule].value_bool()) {
|
||||
attach_nostalgia = true;
|
||||
}
|
||||
|
||||
@@ -978,6 +978,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.category = "Game Options",
|
||||
.elements = {{"1", "DX"}, {"2", "SD"}, {"3", "SD2 - white cab"}},
|
||||
},
|
||||
{
|
||||
// GitaDoraArenaSingleWindow
|
||||
.title = "GitaDora Arena Single Window (EXPERIMENTAL)",
|
||||
.name = "gdaonewindow",
|
||||
.desc = "For Arena Model, when combined with windowed mode, only show the main game window; enables subscreen overlay",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "GitaDora",
|
||||
.category = "Game Options",
|
||||
},
|
||||
{
|
||||
// GitaDoraLefty
|
||||
.title = "GitaDora Lefty Guitar (for Digital Wailing)",
|
||||
@@ -1011,6 +1020,20 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.game_name = "GitaDora",
|
||||
.category = "Game Options",
|
||||
},
|
||||
{
|
||||
// GitaDoraSubOverlaySize
|
||||
.title = "GitaDora Subscreen Overlay Size",
|
||||
.name = "gdsubsize",
|
||||
.desc = "Default size of the subscreen overlay. Default: medium",
|
||||
.type = OptionType::Enum,
|
||||
.game_name = "GitaDora",
|
||||
.category = "Overlay",
|
||||
.elements = {
|
||||
{"small", ""},
|
||||
{"medium", ""},
|
||||
{"large", ""}
|
||||
},
|
||||
},
|
||||
{
|
||||
.title = "Force Load Jubeat Module",
|
||||
.name = "jb",
|
||||
|
||||
@@ -100,8 +100,10 @@ namespace launcher {
|
||||
LoadGitaDoraModule,
|
||||
GitaDoraTwoChannelAudio,
|
||||
GitaDoraCabinetType,
|
||||
GitaDoraArenaSingleWindow,
|
||||
GitaDoraLefty,
|
||||
GitaDoraWailHold,
|
||||
GitaDoraSubOverlaySize,
|
||||
LoadJubeatModule,
|
||||
LoadReflecBeatModule,
|
||||
LoadShogikaiModule,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <thread>
|
||||
|
||||
#include "cfg/screen_resize.h"
|
||||
#include "games/gitadora/gitadora.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "overlay/overlay.h"
|
||||
@@ -390,7 +391,10 @@ namespace wintouchemu {
|
||||
} else if (avs::game::is_model("LDJ") && !GENERIC_SUB_WINDOW_FULLSIZE) {
|
||||
// overlay subscreen in IIDX
|
||||
// use mouse position as ImGui overlay will block the touch window
|
||||
log_info("wintouchemu", "use mouse cursor API for overlay subscreen");
|
||||
log_info("wintouchemu", "use mouse cursor API for ldj overlay subscreen");
|
||||
USE_MOUSE = true;
|
||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
||||
log_info("wintouchemu", "use mouse cursor API for gitadora overlay subscreen");
|
||||
USE_MOUSE = true;
|
||||
} else {
|
||||
// create touch window - create overlay if not yet existing at this point
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "windows/generic_sub.h"
|
||||
#include "windows/iidx_seg.h"
|
||||
#include "windows/iidx_sub.h"
|
||||
#include "windows/gfdm_sub.h"
|
||||
#include "windows/drs_dancefloor.h"
|
||||
#include "windows/iopanel.h"
|
||||
#include "windows/iopanel_ddr.h"
|
||||
@@ -410,7 +411,10 @@ void overlay::SpiceOverlay::init() {
|
||||
window_sub = new overlay::windows::DRSDanceFloorDisplay(this);
|
||||
} else if (avs::game::is_model("KFC")) {
|
||||
window_sub = new overlay::windows::SDVXSubScreen(this);
|
||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
||||
window_sub = new overlay::windows::GitaDoraSubScreen(this);
|
||||
}
|
||||
|
||||
if (window_sub) {
|
||||
this->window_add(window_sub);
|
||||
if (AUTO_SHOW_SUBSCREEN) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "misc/eamuse.h"
|
||||
#include "util/logging.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "games/gitadora/gitadora.h"
|
||||
|
||||
namespace overlay::windows {
|
||||
|
||||
@@ -69,6 +70,8 @@ namespace overlay::windows {
|
||||
sub = "Show Valkyrie Subscreen";
|
||||
} else if (avs::game::is_model("REC")) {
|
||||
sub = "Show DRS Dance Floor";
|
||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
||||
sub = "Show GITADORA Subscreen";
|
||||
}
|
||||
|
||||
build_button(this->overlay->window_sub, sub, size, NextItem::NEW_LINE, false);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "avs/game.h"
|
||||
#include "gfdm_sub.h"
|
||||
#include "games/gitadora/gitadora.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "touch/touch.h"
|
||||
|
||||
namespace overlay::windows {
|
||||
|
||||
GitaDoraSubScreen::GitaDoraSubScreen(SpiceOverlay *overlay) : GenericSubScreen(overlay) {
|
||||
this->title = "GITADORA Subscreen";
|
||||
|
||||
if (!games::gitadora::is_arena_model()) {
|
||||
this->disabled_message = "Requires Arena Model!";
|
||||
}
|
||||
|
||||
this->resize_callback = keep_10_by_16;
|
||||
|
||||
// medium size - perfect for "layout B" in GW Delta, though in drums it covers the pacemaker
|
||||
float size = 0.64f;
|
||||
if (games::gitadora::SUBSCREEN_OVERLAY_SIZE.has_value()) {
|
||||
if (games::gitadora::SUBSCREEN_OVERLAY_SIZE.value() == "large") {
|
||||
// enough to not cover the FPS overlay
|
||||
size = 0.88f;
|
||||
} else if (games::gitadora::SUBSCREEN_OVERLAY_SIZE.value() == "small") {
|
||||
size = 0.48f;
|
||||
}
|
||||
}
|
||||
|
||||
const float height = ImGui::GetIO().DisplaySize.y * size;
|
||||
const float width = height * 10 / 16;
|
||||
this->init_size = ImVec2(width, height + ImGui::GetFrameHeight());
|
||||
|
||||
// bottom right
|
||||
this->init_pos = ImVec2(
|
||||
ImGui::GetIO().DisplaySize.x - ImGui::GetFrameHeight() / 4 - this->init_size.x,
|
||||
ImGui::GetIO().DisplaySize.y - this->init_size.y - (ImGui::GetFrameHeight() / 4));
|
||||
}
|
||||
|
||||
void GitaDoraSubScreen::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {
|
||||
if (!this->get_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GRAPHICS_WINDOWED) {
|
||||
// Touch needs to be registered on global coords
|
||||
*x_out = SPICETOUCH_TOUCH_X + xy_in.x * SPICETOUCH_TOUCH_WIDTH;
|
||||
*y_out = SPICETOUCH_TOUCH_Y + xy_in.y * SPICETOUCH_TOUCH_HEIGHT;
|
||||
} else {
|
||||
// Fullscreen mode, scale to game coords
|
||||
*x_out = xy_in.x * ImGui::GetIO().DisplaySize.x;
|
||||
*y_out = xy_in.y * ImGui::GetIO().DisplaySize.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "overlay/window.h"
|
||||
#include "overlay/windows/generic_sub.h"
|
||||
|
||||
namespace overlay::windows {
|
||||
|
||||
class GitaDoraSubScreen : public GenericSubScreen {
|
||||
public:
|
||||
GitaDoraSubScreen(SpiceOverlay *overlay);
|
||||
|
||||
protected:
|
||||
void touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) override;
|
||||
|
||||
private:
|
||||
static void keep_10_by_16(ImGuiSizeCallbackData* data) {
|
||||
data->DesiredSize.y = (data->DesiredSize.x * 16.f / 10.f) + ImGui::GetFrameHeight();
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user