diff --git a/src/spice2x/CMakeLists.txt b/src/spice2x/CMakeLists.txt index 02e4d42..e50cea1 100644 --- a/src/spice2x/CMakeLists.txt +++ b/src/spice2x/CMakeLists.txt @@ -583,6 +583,7 @@ set(SOURCE_FILES ${SOURCE_FILES} overlay/windows/log.cpp overlay/windows/midi.cpp overlay/windows/patch_manager.cpp + overlay/windows/popn_sub.cpp overlay/windows/wnd_manager.cpp # rawinput diff --git a/src/spice2x/games/popn/popn.cpp b/src/spice2x/games/popn/popn.cpp index b90830d..19f3b71 100644 --- a/src/spice2x/games/popn/popn.cpp +++ b/src/spice2x/games/popn/popn.cpp @@ -3,6 +3,7 @@ #include "bi3a_hook.h" #include #include +#include "hooks/graphics/graphics.h" #include "rawinput/rawinput.h" #include "util/detour.h" #include "util/fileutils.h" @@ -17,11 +18,15 @@ #include "misc/eamuse.h" #include "util/sysutils.h" #include "io.h" +#include "util/deferlog.h" +#include "misc/wintouchemu.h" namespace games::popn { + bool SHOW_PIKA_MONITOR_WARNING = false; + #if SPICE64 && !SPICE_XP - + static decltype(DisplayConfigGetDeviceInfo) *DisplayConfigGetDeviceInfo_orig = nullptr; static @@ -406,6 +411,29 @@ namespace games::popn { #endif #if SPICE64 && !SPICE_XP + if (!GRAPHICS_WINDOWED && D3D9_ADAPTER.has_value()) { + SHOW_PIKA_MONITOR_WARNING = true; + log_warning( + "popn", + "\n\n" + "!!! using -dxmainadapter option is NOT recommended due to known !!!\n" + "!!! compatibility issues with the game !!!\n" + "!!! !!!\n" + "!!! * game may launch in wrong resolution or refresh rate !!!\n" + "!!! * touch / mouse input may stop working in subscreen / overlay !!!\n" + "!!! !!!\n" + "!!! recommendation is to use the Change Main Monitor (-mainmonitor) !!!\n" + "!!! option instead of -dxmainadapter !!!\n\n" + ); + + deferredlogs::defer_error_messages({ + "-dxmainadapter option is NOT recommended due to known compatibility ", + " issues with the game!", + " * game may launch in wrong resolution or refresh rate", + " * touch / mouse input may stop working in subscreen / overlay", + " use Change Main Monitor (-mainmonitor) option instead" + }); + } // monitor hook DisplayConfigGetDeviceInfo_orig = @@ -445,6 +473,10 @@ namespace games::popn { // 00000100 0000000B 00000001 (button 9) // set third column to 0 and it will work with BIO2 + wintouchemu::FORCE = true; + wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true; + wintouchemu::hook_title_ends("", "Main Screen", avs::game::DLL_INSTANCE); + #endif } diff --git a/src/spice2x/games/popn/popn.h b/src/spice2x/games/popn/popn.h index 9944442..e11918e 100644 --- a/src/spice2x/games/popn/popn.h +++ b/src/spice2x/games/popn/popn.h @@ -6,9 +6,17 @@ namespace games::popn { static inline bool is_pikapika_model() { + +#if SPICE64 return (avs::game::is_model("M39") && avs::game::SPEC[0] == 'D'); +#else + return false; +#endif + } + extern bool SHOW_PIKA_MONITOR_WARNING; + class POPNGame : public games::Game { public: POPNGame(); diff --git a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp index 23e3246..30883d5 100644 --- a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp +++ b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp @@ -661,7 +661,7 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::GetDeviceCaps(UINT Adapter, D3DDEVT } // in windowed mode, LDJ will always launch two windows, no special handling needed here } else if (avs::game::is_model("KFC")) { - if (GRAPHICS_WINDOWED & GRAPHICS_PREVENT_SECONDARY_WINDOW) { + if (GRAPHICS_WINDOWED && GRAPHICS_PREVENT_SECONDARY_WINDOW) { // user wants windowed mode but does not want subscreen at all pCaps->NumberOfAdaptersInGroup = 1; } else { @@ -1206,7 +1206,10 @@ static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) { if (SUB_SWAP_CHAIN != nullptr) { wintouchemu::update(); - if (GRAPHICS_WINDOWED || SUBSCREEN_FORCE_REDRAW) { + // newer versions of exceed gear needs SUBSCREEN_FORCE_REDRAW + // (when enabled on older versions of EG, you end up with graphical glitches on the subscreen + // early versions of popn HC needs this as well, otherwise the subscreen doesn't update at all + if (GRAPHICS_WINDOWED || SUBSCREEN_FORCE_REDRAW || games::popn::is_pikapika_model()) { SUB_SWAP_CHAIN->Present(nullptr, nullptr, nullptr, nullptr, 0); } } diff --git a/src/spice2x/hooks/graphics/graphics.cpp b/src/spice2x/hooks/graphics/graphics.cpp index 08c430c..57a50b9 100644 --- a/src/spice2x/hooks/graphics/graphics.cpp +++ b/src/spice2x/hooks/graphics/graphics.cpp @@ -16,6 +16,7 @@ #include "games/ddr/ddr.h" #include "games/gitadora/gitadora.h" #include "games/iidx/iidx.h" +#include "games/popn/popn.h" #include "hooks/graphics/backends/d3d9/d3d9_backend.h" #include "launcher/shutdown.h" #include "overlay/overlay.h" @@ -401,7 +402,9 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC if (is_popn_sub_window) { POPN_SUBSCREEN_WINDOW = result; - graphics_hook_subscreen_window(POPN_SUBSCREEN_WINDOW); + if (!GRAPHICS_PREVENT_SECONDARY_WINDOW) { + graphics_hook_subscreen_window(POPN_SUBSCREEN_WINDOW); + } } disable_touch_indicators(result); @@ -671,6 +674,13 @@ static BOOL WINAPI ShowWindow_hook(HWND hWnd, int nCmdShow) { return true; } + if (games::popn::is_pikapika_model() && + GRAPHICS_PREVENT_SECONDARY_WINDOW && + hWnd == POPN_SUBSCREEN_WINDOW) { + log_info("graphics", "ShowWindow_hook - hiding sub window {}", fmt::ptr(hWnd)); + return true; + } + // call original return ShowWindow_orig(hWnd, nCmdShow); } diff --git a/src/spice2x/launcher/launcher.cpp b/src/spice2x/launcher/launcher.cpp index dc23eb0..3eccc51 100644 --- a/src/spice2x/launcher/launcher.cpp +++ b/src/spice2x/launcher/launcher.cpp @@ -590,6 +590,10 @@ int main_implementation(int argc, char *argv[]) { if (options[launcher::Options::PopnMusicForceSDMode].value_bool()) { avs::ea3::PCB_TYPE = 0; } + if (options[launcher::Options::PopnNoSub].value_bool()) { + GRAPHICS_FORCE_SINGLE_ADAPTER = true; + GRAPHICS_PREVENT_SECONDARY_WINDOW = true; + } if (options[launcher::Options::LoadMetalGearArcadeModule].value_bool()) { attach_mga = true; } diff --git a/src/spice2x/launcher/options.cpp b/src/spice2x/launcher/options.cpp index bc932ce..172952b 100644 --- a/src/spice2x/launcher/options.cpp +++ b/src/spice2x/launcher/options.cpp @@ -988,6 +988,15 @@ static const std::vector OPTION_DEFINITIONS = { .game_name = "Pop'n Music", .category = "Game Options", }, + { + // PopnNoSub + .title = "Pop'n Music PikaPika Subscreen Disable", + .name = "popnnosub", + .desc = "Prevents PikaPika model subscreen from launching a separate window.", + .type = OptionType::Bool, + .game_name = "Pop'n Music", + .category = "Game Options", + }, { .title = "Force Load HELLO! Pop'n Music Module", .name = "hpm", diff --git a/src/spice2x/launcher/options.h b/src/spice2x/launcher/options.h index c2bec62..92e6388 100644 --- a/src/spice2x/launcher/options.h +++ b/src/spice2x/launcher/options.h @@ -99,6 +99,7 @@ namespace launcher { LoadPopnMusicModule, PopnMusicForceHDMode, PopnMusicForceSDMode, + PopnNoSub, LoadHelloPopnMusicModule, LoadGitaDoraModule, GitaDoraTwoChannelAudio, diff --git a/src/spice2x/misc/wintouchemu.cpp b/src/spice2x/misc/wintouchemu.cpp index cb3ba5b..944584d 100644 --- a/src/spice2x/misc/wintouchemu.cpp +++ b/src/spice2x/misc/wintouchemu.cpp @@ -12,6 +12,7 @@ #include "cfg/screen_resize.h" #include "games/gitadora/gitadora.h" #include "games/iidx/iidx.h" +#include "games/popn/popn.h" #include "hooks/graphics/graphics.h" #include "overlay/overlay.h" #include "overlay/windows/generic_sub.h" @@ -405,6 +406,10 @@ namespace wintouchemu { // use mouse position as ImGui overlay will block the touch window log_info("wintouchemu", "use mouse cursor API for ldj overlay subscreen"); USE_MOUSE = true; + } else if (games::popn::is_pikapika_model()) { + // same as iidx case above + log_info("wintouchemu", "use mouse cursor API for popn 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; diff --git a/src/spice2x/overlay/overlay.cpp b/src/spice2x/overlay/overlay.cpp index a6a934f..2b7c309 100644 --- a/src/spice2x/overlay/overlay.cpp +++ b/src/spice2x/overlay/overlay.cpp @@ -5,6 +5,7 @@ #include "games/io.h" #include "games/gitadora/gitadora.h" #include "games/iidx/iidx.h" +#include "games/popn/popn.h" #include "hooks/graphics/graphics.h" #include "misc/eamuse.h" #include "touch/touch.h" @@ -35,6 +36,7 @@ #include "windows/iopanel_ddr.h" #include "windows/iopanel_gfdm.h" #include "windows/iopanel_iidx.h" +#include "windows/popn_sub.h" #include "windows/sdvx_sub.h" #include "windows/keypad.h" #include "windows/log.h" @@ -415,6 +417,8 @@ void overlay::SpiceOverlay::init() { 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); + } else if (games::popn::is_pikapika_model()) { + window_sub = new overlay::windows::PopnSubScreen(this); } if (window_sub) { diff --git a/src/spice2x/overlay/windows/exitprompt.cpp b/src/spice2x/overlay/windows/exitprompt.cpp index 38d6a16..8b36e72 100644 --- a/src/spice2x/overlay/windows/exitprompt.cpp +++ b/src/spice2x/overlay/windows/exitprompt.cpp @@ -4,6 +4,7 @@ #include "util/logging.h" #include "games/iidx/iidx.h" #include "games/gitadora/gitadora.h" +#include "games/popn/popn.h" namespace overlay::windows { @@ -72,6 +73,8 @@ namespace overlay::windows { sub = "Show DRS Dance Floor"; } else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) { sub = "Show GITADORA Subscreen"; + } else if (games::popn::is_pikapika_model()) { + sub = "Show Pop'n Subscreen"; } build_button(this->overlay->window_sub, sub, size, NextItem::NEW_LINE, false); diff --git a/src/spice2x/overlay/windows/popn_sub.cpp b/src/spice2x/overlay/windows/popn_sub.cpp new file mode 100644 index 0000000..8bfaea7 --- /dev/null +++ b/src/spice2x/overlay/windows/popn_sub.cpp @@ -0,0 +1,53 @@ +#undef CINTERFACE + +#include "avs/game.h" +#include "popn_sub.h" +#include "games/popn/popn.h" +#include "hooks/graphics/graphics.h" +#include "touch/touch.h" + +namespace overlay::windows { + + PopnSubScreen::PopnSubScreen(SpiceOverlay *overlay) : GenericSubScreen(overlay) { + this->title = "Pop'n Subscreen"; + + if (!games::popn::is_pikapika_model()) { + this->disabled_message = "Game did not launch as Pikapika Pop-kun (invalid )!"; + } else if (games::popn::SHOW_PIKA_MONITOR_WARNING) { + this->disabled_message = "Subscreen overlay is not compatible with -dxmainadapter option, use -mainmonitor instead"; + } else if (GRAPHICS_WINDOWED && !GRAPHICS_PREVENT_SECONDARY_WINDOW) { + this->disabled_message = "Subscren overlay was not enabled in spicecfg. Use the second window (ALT+TAB)."; + } + + this->resize_callback = keep_16_by_10; + float size = 0.5f; + this->init_size = ImVec2( + ImGui::GetIO().DisplaySize.x * size, + (ImGui::GetIO().DisplaySize.x * size * 10 / 16) + ImGui::GetFrameHeight()); + + this->size_max = ImVec2( + ImGui::GetIO().DisplaySize.x - ImGui::GetFrameHeight() * 2, + ImGui::GetIO().DisplaySize.y - ImGui::GetFrameHeight() * 2); + + // middle / bottom + this->init_pos = ImVec2( + ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2, + ImGui::GetIO().DisplaySize.y - this->init_size.y - (ImGui::GetFrameHeight() / 2)); + } + + void PopnSubScreen::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; + } + } +} diff --git a/src/spice2x/overlay/windows/popn_sub.h b/src/spice2x/overlay/windows/popn_sub.h new file mode 100644 index 0000000..2e0726f --- /dev/null +++ b/src/spice2x/overlay/windows/popn_sub.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "overlay/window.h" +#include "overlay/windows/generic_sub.h" + +namespace overlay::windows { + + class PopnSubScreen : public GenericSubScreen { + public: + PopnSubScreen(SpiceOverlay *overlay); + + protected: + void touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) override; + + private: + static void keep_16_by_10(ImGuiSizeCallbackData* data) { + data->DesiredSize.y = (data->DesiredSize.x * 10.f / 16.f) + ImGui::GetFrameHeight(); + } + }; +}