mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
gitadora: (arena model) booting fullscreen with one monitor (#696)
## Link to GitHub Issue or related Pull Request, if one exists #477 ## Description of change By default the game needs 4 monitors. With the new option to disable subscreens, you can now boot fullscreen with a single 4K monitor, with subscreen overlay enabled. Side monitors are not shown in the overlay; only the touch screen is emulated. ## Future work - [ ] custom resolution (-forceres) doesn't work properly (hooking ResetEx does allow the game to boot but will render incorrectly; probably needs hex edits) - [x] enable this automatically if the user has fewer than 4 monitors - [ ] ability to boot with a 4k main screen + small subscreen (with no side screens which do nothing gameplay wise), but this whole display emulation is a nightmare to work with & test thoroughly so it'll have to be in the future. ## Testing Checklist: - [x] fs on 1 monitor with option set - [x] fs on 2 monitor with option set - [x] windowed - default (4 windows, no overlay) - [x] windowed - with option set (1 window, overlay) - [x] fs with 4 monitors? - [x] check popn hc for regression
This commit is contained in:
@@ -13,6 +13,8 @@
|
|||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/sigscan.h"
|
#include "util/sigscan.h"
|
||||||
#include "util/socd_cleaner.h"
|
#include "util/socd_cleaner.h"
|
||||||
|
#include "util/sysutils.h"
|
||||||
|
#include "util/utils.h"
|
||||||
#include "hooks/setupapihook.h"
|
#include "hooks/setupapihook.h"
|
||||||
|
|
||||||
namespace games::gitadora {
|
namespace games::gitadora {
|
||||||
@@ -20,7 +22,6 @@ namespace games::gitadora {
|
|||||||
// settings
|
// settings
|
||||||
bool TWOCHANNEL = false;
|
bool TWOCHANNEL = false;
|
||||||
std::optional<unsigned int> CAB_TYPE = std::nullopt;
|
std::optional<unsigned int> CAB_TYPE = std::nullopt;
|
||||||
bool ARENA_SINGLE_WINDOW = false;
|
|
||||||
bool P1_LEFTY = false;
|
bool P1_LEFTY = false;
|
||||||
bool P2_LEFTY = false;
|
bool P2_LEFTY = false;
|
||||||
std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
||||||
@@ -223,8 +224,7 @@ namespace games::gitadora {
|
|||||||
|
|
||||||
// arena model launches a tiny window yet backbuffer at 4k, resulting in unusable overlay
|
// arena model launches a tiny window yet backbuffer at 4k, resulting in unusable overlay
|
||||||
// force scaling to make things usable
|
// force scaling to make things usable
|
||||||
if (!overlay::UI_SCALE_PERCENT.has_value() && is_arena_model() &&
|
if (!overlay::UI_SCALE_PERCENT.has_value() && is_arena_model() && !cfg::CONFIGURATOR_STANDALONE) {
|
||||||
GRAPHICS_WINDOWED && !cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
overlay::UI_SCALE_PERCENT = 250;
|
overlay::UI_SCALE_PERCENT = 250;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,9 +237,292 @@ namespace games::gitadora {
|
|||||||
} else {
|
} else {
|
||||||
log_info("gitadora", "guitar pick SOCD algorithm: legacy");
|
log_info("gitadora", "guitar pick SOCD algorithm: legacy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SPICE64 && !SPICE_XP
|
||||||
|
|
||||||
|
if (is_arena_model() && !GRAPHICS_WINDOWED && !GRAPHICS_FORCE_SINGLE_ADAPTER) {
|
||||||
|
const auto &monitors = sysutils::enumerate_monitors();
|
||||||
|
const size_t active_count = monitors.size();
|
||||||
|
log_info("gitadora", "arena model: detected {} active monitor(s)", active_count);
|
||||||
|
if (active_count < 4) {
|
||||||
|
log_info("gitadora", "arena model: enable single monitor mode due to insufficient monitors");
|
||||||
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
||||||
|
GRAPHICS_PREVENT_SECONDARY_WINDOW = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SPICE64 && !SPICE_XP
|
||||||
|
|
||||||
|
static decltype(GetDisplayConfigBufferSizes) *GetDisplayConfigBufferSizes_orig = nullptr;
|
||||||
|
static decltype(QueryDisplayConfig) *QueryDisplayConfig_orig = nullptr;
|
||||||
|
static decltype(DisplayConfigGetDeviceInfo) *DisplayConfigGetDeviceInfo_orig = nullptr;
|
||||||
|
|
||||||
|
// cached primary real monitor: its path + source/target mode entries.
|
||||||
|
// modeInfoIdx values on the path are renumbered to 0 / 1 so the cache is self-contained.
|
||||||
|
static DISPLAYCONFIG_PATH_INFO real_primary_path = {};
|
||||||
|
static DISPLAYCONFIG_MODE_INFO real_primary_modes[2] = {}; // [0]=source, [1]=target
|
||||||
|
|
||||||
|
// fake monitors appended after the real ones. the game classifies monitors
|
||||||
|
// by outputTechnology + connectorInstance:
|
||||||
|
// HDMI -> main 4k monitor (real primary)
|
||||||
|
// DP connInstance 0 -> left
|
||||||
|
// DP connInstance 1 -> right
|
||||||
|
// DP connInstance 2 -> small (sub/touch)
|
||||||
|
// ids are negated on the fake monitor headers so they can be distinguished
|
||||||
|
// from real ones in DisplayConfigGetDeviceInfo.
|
||||||
|
struct FakeMonitor {
|
||||||
|
LONG id;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int offset_x;
|
||||||
|
int offset_y;
|
||||||
|
UINT32 connector_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ORDERING MATTERS: the d3d9 wrapper (FAKE_SUBSCREEN_ADAPTER) hands out
|
||||||
|
// adapters as "\\.\DISPLAY_SPICE_FAKE_{N}" for N=1,2,3. The game maps each
|
||||||
|
// adapter to a swap chain role via its DisplayConfig connector instance,
|
||||||
|
// so the entries here must be listed in the same order the wrapper enumerates
|
||||||
|
// them: id=1 -> adapter 1 -> left, id=2 -> adapter 2 -> right, id=3 -> adapter 3 -> small.
|
||||||
|
static constexpr FakeMonitor FAKE_MONITORS[] = {
|
||||||
|
{ 1, 1080, 1920, -100000, -100000, 0 }, // left (DP connector instance 0)
|
||||||
|
{ 2, 1080, 1920, -200000, -200000, 1 }, // right (DP connector instance 1)
|
||||||
|
{ 3, 800, 1280, -300000, -300000, 2 }, // small (DP connector instance 2, touch)
|
||||||
|
};
|
||||||
|
static constexpr UINT32 FAKE_MONITOR_COUNT = static_cast<UINT32>(std::size(FAKE_MONITORS));
|
||||||
|
|
||||||
|
// call QueryDisplayConfig once, keep only the primary monitor's path and its
|
||||||
|
// two referenced modes (source + target). modeInfoIdx values are rewritten to
|
||||||
|
// 0 and 1 so the cache is self-consistent.
|
||||||
|
static void cache_primary_monitor_info() {
|
||||||
|
UINT32 path_count = 0;
|
||||||
|
UINT32 mode_count = 0;
|
||||||
|
if (GetDisplayConfigBufferSizes_orig(
|
||||||
|
QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) != ERROR_SUCCESS) {
|
||||||
|
log_fatal("gitadora", "cache_primary_monitor_info: GetDisplayConfigBufferSizes failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DISPLAYCONFIG_PATH_INFO> all_paths(path_count);
|
||||||
|
std::vector<DISPLAYCONFIG_MODE_INFO> all_modes(mode_count);
|
||||||
|
if (QueryDisplayConfig_orig(
|
||||||
|
QDC_ONLY_ACTIVE_PATHS,
|
||||||
|
&path_count, all_paths.data(),
|
||||||
|
&mode_count, all_modes.data(),
|
||||||
|
nullptr) != ERROR_SUCCESS) {
|
||||||
|
log_fatal("gitadora", "cache_primary_monitor_info: QueryDisplayConfig failed");
|
||||||
|
}
|
||||||
|
all_paths.resize(path_count);
|
||||||
|
all_modes.resize(mode_count);
|
||||||
|
|
||||||
|
// pick the primary monitor: source mode at (0, 0)
|
||||||
|
auto primary = std::find_if(all_paths.begin(), all_paths.end(),
|
||||||
|
[&](const auto &p) {
|
||||||
|
const auto idx = p.sourceInfo.modeInfoIdx;
|
||||||
|
return idx < all_modes.size() &&
|
||||||
|
all_modes[idx].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
|
||||||
|
all_modes[idx].sourceMode.position.x == 0 &&
|
||||||
|
all_modes[idx].sourceMode.position.y == 0;
|
||||||
|
});
|
||||||
|
if (primary == all_paths.end()) {
|
||||||
|
log_fatal("gitadora", "cache_primary_monitor_info: no primary monitor found");
|
||||||
|
}
|
||||||
|
|
||||||
|
real_primary_modes[0] = all_modes[primary->sourceInfo.modeInfoIdx];
|
||||||
|
real_primary_modes[1] = all_modes[primary->targetInfo.modeInfoIdx];
|
||||||
|
real_primary_path = *primary;
|
||||||
|
real_primary_path.sourceInfo.modeInfoIdx = 0;
|
||||||
|
real_primary_path.targetInfo.modeInfoIdx = 1;
|
||||||
|
|
||||||
|
log_info("gitadora", "cache_primary_monitor_info: cached primary monitor");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
LONG
|
||||||
|
WINAPI
|
||||||
|
GetDisplayConfigBufferSizes_hook(
|
||||||
|
UINT32 Flags,
|
||||||
|
UINT32 *pNumPathArrayElements,
|
||||||
|
UINT32 *pNumModeInfoArrayElements)
|
||||||
|
{
|
||||||
|
// populate cached primary real monitor on the first call
|
||||||
|
static std::once_flag populate_once;
|
||||||
|
std::call_once(populate_once, cache_primary_monitor_info);
|
||||||
|
|
||||||
|
// always report exactly 1 real + N fake monitors
|
||||||
|
*pNumPathArrayElements = 1 + FAKE_MONITOR_COUNT;
|
||||||
|
*pNumModeInfoArrayElements = 2 + FAKE_MONITOR_COUNT * 2;
|
||||||
|
|
||||||
|
log_info(
|
||||||
|
"gitadora",
|
||||||
|
"GetDisplayConfigBufferSizes: 1 real path + {} fake monitor(s)",
|
||||||
|
FAKE_MONITOR_COUNT);
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write fake monitor i into the caller's path/mode arrays. layout (single-monitor
|
||||||
|
// assumption): index 0 in both arrays holds the cached primary real monitor, so
|
||||||
|
// fake i occupies path slot (1 + i) and mode slots (2 + i*2) / (2 + i*2 + 1).
|
||||||
|
static void insert_fake_monitor(
|
||||||
|
DISPLAYCONFIG_PATH_INFO *paths,
|
||||||
|
DISPLAYCONFIG_MODE_INFO *modes,
|
||||||
|
UINT32 i)
|
||||||
|
{
|
||||||
|
const FakeMonitor &m = FAKE_MONITORS[i];
|
||||||
|
const UINT32 src_idx = 2 + i * 2;
|
||||||
|
const UINT32 tgt_idx = src_idx + 1;
|
||||||
|
const LUID adapter_id { .LowPart = static_cast<DWORD>(-m.id), .HighPart = -m.id };
|
||||||
|
const UINT32 uid = static_cast<UINT32>(-m.id);
|
||||||
|
|
||||||
|
paths[1 + i] = {
|
||||||
|
.sourceInfo = {
|
||||||
|
.adapterId = adapter_id,
|
||||||
|
.id = uid,
|
||||||
|
.modeInfoIdx = src_idx,
|
||||||
|
.statusFlags = DISPLAYCONFIG_SOURCE_IN_USE,
|
||||||
|
},
|
||||||
|
.targetInfo = {
|
||||||
|
.adapterId = adapter_id,
|
||||||
|
.id = uid,
|
||||||
|
.modeInfoIdx = tgt_idx,
|
||||||
|
.outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL,
|
||||||
|
.rotation = DISPLAYCONFIG_ROTATION_IDENTITY,
|
||||||
|
.scaling = DISPLAYCONFIG_SCALING_IDENTITY,
|
||||||
|
.refreshRate = { .Numerator = 60000, .Denominator = 1000 },
|
||||||
|
.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE,
|
||||||
|
.targetAvailable = TRUE,
|
||||||
|
.statusFlags = DISPLAYCONFIG_TARGET_IN_USE,
|
||||||
|
},
|
||||||
|
.flags = DISPLAYCONFIG_PATH_ACTIVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
modes[src_idx] = {
|
||||||
|
.infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE,
|
||||||
|
.id = uid,
|
||||||
|
.adapterId = adapter_id,
|
||||||
|
.sourceMode = {
|
||||||
|
.width = static_cast<UINT32>(m.width),
|
||||||
|
.height = static_cast<UINT32>(m.height),
|
||||||
|
.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP,
|
||||||
|
.position = { .x = m.offset_x, .y = m.offset_y },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
modes[tgt_idx] = {
|
||||||
|
.infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET,
|
||||||
|
.id = uid,
|
||||||
|
.adapterId = adapter_id,
|
||||||
|
.targetMode = {},
|
||||||
|
};
|
||||||
|
|
||||||
|
log_misc(
|
||||||
|
"gitadora",
|
||||||
|
"inserted fake monitor: id={}, width={}, height={}, offset_x={}, offset_y={}",
|
||||||
|
m.id, m.width, m.height, m.offset_x, m.offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
LONG
|
||||||
|
WINAPI
|
||||||
|
QueryDisplayConfig_hook(
|
||||||
|
UINT32 flags,
|
||||||
|
UINT32* numPathArrayElements,
|
||||||
|
DISPLAYCONFIG_PATH_INFO* pathArray,
|
||||||
|
UINT32* numModeInfoArrayElements,
|
||||||
|
DISPLAYCONFIG_MODE_INFO* modeInfoArray,
|
||||||
|
DISPLAYCONFIG_TOPOLOGY_ID* currentTopologyId)
|
||||||
|
{
|
||||||
|
// copy cached primary real monitor into caller buffers at index 0
|
||||||
|
pathArray[0] = real_primary_path;
|
||||||
|
modeInfoArray[0] = real_primary_modes[0];
|
||||||
|
modeInfoArray[1] = real_primary_modes[1];
|
||||||
|
*numPathArrayElements = 1 + FAKE_MONITOR_COUNT;
|
||||||
|
*numModeInfoArrayElements = 2 + FAKE_MONITOR_COUNT * 2;
|
||||||
|
if (currentTopologyId != nullptr) {
|
||||||
|
*currentTopologyId = DISPLAYCONFIG_TOPOLOGY_EXTEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_misc("gitadora", "QueryDisplayConfig returning fake monitor paths and modes");
|
||||||
|
|
||||||
|
// append fake monitors after the real one
|
||||||
|
for (UINT32 i = 0; i < FAKE_MONITOR_COUNT; i++) {
|
||||||
|
insert_fake_monitor(pathArray, modeInfoArray, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
LONG
|
||||||
|
WINAPI
|
||||||
|
DisplayConfigGetDeviceInfo_hook(DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket)
|
||||||
|
{
|
||||||
|
if (requestPacket == nullptr) {
|
||||||
|
return DisplayConfigGetDeviceInfo_orig(requestPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle fake monitors (negative id) directly without calling orig
|
||||||
|
const auto id = static_cast<int>(requestPacket->id);
|
||||||
|
if (id < 0) {
|
||||||
|
if (requestPacket->type == DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME) {
|
||||||
|
const auto sourceName = reinterpret_cast<DISPLAYCONFIG_SOURCE_DEVICE_NAME*>(requestPacket);
|
||||||
|
// name must match WrappedIDirect3D9::GetAdapterIdentifier
|
||||||
|
const std::string adapter_name = fmt::format("\\\\.\\DISPLAY_SPICE_FAKE_{}", -id);
|
||||||
|
wcscpy(sourceName->viewGdiDeviceName, s2ws(adapter_name).c_str());
|
||||||
|
log_misc("gitadora",
|
||||||
|
"DisplayConfigGetDeviceInfo: fake source id={} name={}", id, adapter_name);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
if (requestPacket->type == DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME) {
|
||||||
|
const auto targetName = reinterpret_cast<DISPLAYCONFIG_TARGET_DEVICE_NAME*>(requestPacket);
|
||||||
|
const LONG fake_id = -id;
|
||||||
|
UINT32 conn_inst = 0xff;
|
||||||
|
for (const auto& f : FAKE_MONITORS) {
|
||||||
|
if (f.id == fake_id) {
|
||||||
|
conn_inst = f.connector_instance;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetName->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL;
|
||||||
|
targetName->connectorInstance = conn_inst;
|
||||||
|
wcscpy(targetName->monitorFriendlyDeviceName, L"Spice Fake Monitor");
|
||||||
|
wcscpy(targetName->monitorDevicePath, L"\\\\?\\SpiceFakeMonitor");
|
||||||
|
log_misc("gitadora",
|
||||||
|
"DisplayConfigGetDeviceInfo: fake target id={} -> DP connInst {}",
|
||||||
|
id, targetName->connectorInstance);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ret = DisplayConfigGetDeviceInfo_orig(requestPacket);
|
||||||
|
if (ret != ERROR_SUCCESS ||
|
||||||
|
requestPacket->type != DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// override the cached primary real monitor target info to look like HDMI/0
|
||||||
|
const auto targetName = reinterpret_cast<DISPLAYCONFIG_TARGET_DEVICE_NAME*>(requestPacket);
|
||||||
|
const auto& target = real_primary_path.targetInfo;
|
||||||
|
if (target.id == targetName->header.id &&
|
||||||
|
target.adapterId.HighPart == targetName->header.adapterId.HighPart &&
|
||||||
|
target.adapterId.LowPart == targetName->header.adapterId.LowPart)
|
||||||
|
{
|
||||||
|
targetName->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI;
|
||||||
|
targetName->connectorInstance = 0;
|
||||||
|
log_info("gitadora",
|
||||||
|
"overriding primary monitor (id={}) to pretend to be HDMI",
|
||||||
|
targetName->header.id);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void GitaDoraGame::attach() {
|
void GitaDoraGame::attach() {
|
||||||
Game::attach();
|
Game::attach();
|
||||||
|
|
||||||
@@ -297,11 +580,30 @@ namespace games::gitadora {
|
|||||||
// volume change prevention
|
// volume change prevention
|
||||||
hooks::audio::mme::init(avs::game::DLL_INSTANCE);
|
hooks::audio::mme::init(avs::game::DLL_INSTANCE);
|
||||||
|
|
||||||
// touch hook
|
// monitor/touch hooks (windowed or full screen)
|
||||||
if (ARENA_SINGLE_WINDOW) {
|
if (GRAPHICS_FORCE_SINGLE_ADAPTER || GRAPHICS_PREVENT_SECONDARY_WINDOW) {
|
||||||
|
// enable touch hook for subscreen overlay
|
||||||
wintouchemu::FORCE = true;
|
wintouchemu::FORCE = true;
|
||||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||||
wintouchemu::hook("GITADORA", avs::game::DLL_INSTANCE);
|
wintouchemu::hook("GITADORA", avs::game::DLL_INSTANCE);
|
||||||
|
|
||||||
|
#if !SPICE_XP
|
||||||
|
|
||||||
|
if (!GRAPHICS_WINDOWED) {
|
||||||
|
// monitor hook: always pretend to have 1 primary real monitor + 3 fake monitors
|
||||||
|
// (LEFT / RIGHT / SMALL) so the game accepts the arena cab topology
|
||||||
|
GetDisplayConfigBufferSizes_orig =
|
||||||
|
detour::iat_try("GetDisplayConfigBufferSizes",
|
||||||
|
GetDisplayConfigBufferSizes_hook, avs::game::DLL_INSTANCE);
|
||||||
|
QueryDisplayConfig_orig =
|
||||||
|
detour::iat_try("QueryDisplayConfig",
|
||||||
|
QueryDisplayConfig_hook, avs::game::DLL_INSTANCE);
|
||||||
|
DisplayConfigGetDeviceInfo_orig =
|
||||||
|
detour::iat_try("DisplayConfigGetDeviceInfo",
|
||||||
|
DisplayConfigGetDeviceInfo_hook, avs::game::DLL_INSTANCE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ namespace games::gitadora {
|
|||||||
// settings
|
// settings
|
||||||
extern bool TWOCHANNEL;
|
extern bool TWOCHANNEL;
|
||||||
extern std::optional<unsigned int> CAB_TYPE;
|
extern std::optional<unsigned int> CAB_TYPE;
|
||||||
extern bool ARENA_SINGLE_WINDOW;
|
|
||||||
extern bool P1_LEFTY;
|
extern bool P1_LEFTY;
|
||||||
extern bool P2_LEFTY;
|
extern bool P2_LEFTY;
|
||||||
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ namespace games::popn {
|
|||||||
} else if (requestPacket->type == DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME) {
|
} else if (requestPacket->type == DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME) {
|
||||||
const auto source = reinterpret_cast<DISPLAYCONFIG_SOURCE_DEVICE_NAME*>(requestPacket);
|
const auto source = reinterpret_cast<DISPLAYCONFIG_SOURCE_DEVICE_NAME*>(requestPacket);
|
||||||
// value must match WrappedIDirect3D9::GetAdapterIdentifier
|
// value must match WrappedIDirect3D9::GetAdapterIdentifier
|
||||||
wcscpy(source->viewGdiDeviceName, L"\\\\.\\DISPLAY_SPICE_FAKE");
|
wcscpy(source->viewGdiDeviceName, L"\\\\.\\DISPLAY_SPICE_FAKE_1");
|
||||||
} else {
|
} else {
|
||||||
log_fatal(
|
log_fatal(
|
||||||
"popn",
|
"popn",
|
||||||
|
|||||||
@@ -465,15 +465,21 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::RegisterSoftwareDevice(void *pIniti
|
|||||||
UINT STDMETHODCALLTYPE WrappedIDirect3D9::GetAdapterCount() {
|
UINT STDMETHODCALLTYPE WrappedIDirect3D9::GetAdapterCount() {
|
||||||
UINT result = pReal->GetAdapterCount();
|
UINT result = pReal->GetAdapterCount();
|
||||||
|
|
||||||
if (!FAKE_SUBSCREEN_ADAPTER && games::popn::is_pikapika_model() && result == 1) {
|
if (!FAKE_SUBSCREEN_ADAPTER) {
|
||||||
|
if (games::popn::is_pikapika_model() && result == 1) {
|
||||||
FAKE_SUBSCREEN_ADAPTER = true;
|
FAKE_SUBSCREEN_ADAPTER = true;
|
||||||
log_info(
|
log_info(
|
||||||
"graphics::d3d9",
|
"graphics::d3d9",
|
||||||
"GetAdapterCount returned 1, popn needs 2 adapters - enabliing fake submonitor mode");
|
"GetAdapterCount returned {}, popn needs 2 adapters - enabling fake submonitor mode", result);
|
||||||
}
|
|
||||||
|
|
||||||
if (FAKE_SUBSCREEN_ADAPTER) {
|
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
} else if (games::gitadora::is_arena_model() && !GRAPHICS_WINDOWED && result < 4) {
|
||||||
|
FAKE_SUBSCREEN_ADAPTER = true;
|
||||||
|
log_info(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"GetAdapterCount returned {}, gfdm needs 4 adapters - enabling fake submonitor mode", result);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -485,12 +491,14 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::GetAdapterIdentifier(
|
|||||||
D3DADAPTER_IDENTIFIER9 *pIdentifier)
|
D3DADAPTER_IDENTIFIER9 *pIdentifier)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (FAKE_SUBSCREEN_ADAPTER && Adapter == 1 && pIdentifier) {
|
if (FAKE_SUBSCREEN_ADAPTER && Adapter > 0 && pIdentifier) {
|
||||||
*pIdentifier = {};
|
*pIdentifier = {};
|
||||||
strcpy(pIdentifier->DeviceName, "\\\\.\\DISPLAY_SPICE_FAKE");
|
const std::string adapter_name = fmt::format("\\\\.\\DISPLAY_SPICE_FAKE_{}", Adapter);
|
||||||
|
strcpy(pIdentifier->DeviceName, adapter_name.c_str());
|
||||||
log_misc(
|
log_misc(
|
||||||
"graphics::d3d9",
|
"graphics::d3d9",
|
||||||
"GetAdapterIdentifier called for fake subscreen adapter 1: {}",
|
"GetAdapterIdentifier called for fake subscreen adapter {}: {}",
|
||||||
|
Adapter,
|
||||||
pIdentifier->DeviceName);
|
pIdentifier->DeviceName);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@@ -499,8 +507,8 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::GetAdapterIdentifier(
|
|||||||
}
|
}
|
||||||
|
|
||||||
UINT STDMETHODCALLTYPE WrappedIDirect3D9::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) {
|
UINT STDMETHODCALLTYPE WrappedIDirect3D9::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) {
|
||||||
if (FAKE_SUBSCREEN_ADAPTER && Adapter == 1) {
|
if (FAKE_SUBSCREEN_ADAPTER && Adapter > 0) {
|
||||||
log_misc("graphics::d3d9", "GetAdapterModeCount called for fake subscreen adapter");
|
log_misc("graphics::d3d9", "GetAdapterModeCount called for fake subscreen adapter {}", Adapter);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,8 +521,8 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::EnumAdapterModes(
|
|||||||
UINT Mode,
|
UINT Mode,
|
||||||
D3DDISPLAYMODE *pMode)
|
D3DDISPLAYMODE *pMode)
|
||||||
{
|
{
|
||||||
if (FAKE_SUBSCREEN_ADAPTER && Adapter == 1) {
|
if (FAKE_SUBSCREEN_ADAPTER && Adapter > 0) {
|
||||||
log_misc("graphics::d3d9", "EnumAdapterModes called for fake subscreen adapter");
|
log_misc("graphics::d3d9", "EnumAdapterModes called for fake subscreen adapter {}", Adapter);
|
||||||
if (Mode == 0 && pMode) {
|
if (Mode == 0 && pMode) {
|
||||||
pMode->Width = 1280;
|
pMode->Width = 1280;
|
||||||
pMode->Height = 800;
|
pMode->Height = 800;
|
||||||
@@ -622,8 +630,8 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CheckDeviceFormat(
|
|||||||
D3DRESOURCETYPE RType,
|
D3DRESOURCETYPE RType,
|
||||||
D3DFORMAT CheckFormat)
|
D3DFORMAT CheckFormat)
|
||||||
{
|
{
|
||||||
if (FAKE_SUBSCREEN_ADAPTER && Adapter == 1) {
|
if (FAKE_SUBSCREEN_ADAPTER && Adapter > 0) {
|
||||||
log_misc("graphics::d3d9", "CheckDeviceFormat called for fake subscreen adapter");
|
log_misc("graphics::d3d9", "CheckDeviceFormat called for fake subscreen adapter {}", Adapter);
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,10 +1151,15 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDeviceEx(
|
|||||||
|
|
||||||
*ppReturnedDeviceInterface = new WrappedIDirect3DDevice9(hFocusWindow, *ppReturnedDeviceInterface);
|
*ppReturnedDeviceInterface = new WrappedIDirect3DDevice9(hFocusWindow, *ppReturnedDeviceInterface);
|
||||||
|
|
||||||
// initialize sub screen if IIDX/SDVX requested a multi-head context
|
// initialize sub screen if the game requested a multi-head context
|
||||||
if (avs::game::is_model({"LDJ", "KFC", "M39"}) &&
|
if (avs::game::is_model({"LDJ", "KFC", "M39", "M32"}) &&
|
||||||
(orig_behavior_flags & D3DCREATE_ADAPTERGROUP_DEVICE)) {
|
(orig_behavior_flags & D3DCREATE_ADAPTERGROUP_DEVICE)) {
|
||||||
graphics_d3d9_ldj_init_sub_screen(*ppReturnedDeviceInterface, &pPresentationParameters[1]);
|
|
||||||
|
UINT i = 1;
|
||||||
|
if (games::gitadora::is_arena_model()) {
|
||||||
|
i = 2;
|
||||||
|
}
|
||||||
|
graphics_d3d9_ldj_init_sub_screen(*ppReturnedDeviceInterface, &pPresentationParameters[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1196,7 +1209,13 @@ static void graphics_d3d9_ldj_init_sub_screen(IDirect3DDevice9Ex *device, D3DPRE
|
|||||||
log_info("graphics::d3d9", "created additional swap chain for windowed mode");
|
log_info("graphics::d3d9", "created additional swap chain for windowed mode");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hr = device->GetSwapChain(1, &SUB_SWAP_CHAIN);
|
|
||||||
|
int swapchain = 1;
|
||||||
|
if (games::gitadora::is_arena_model()) {
|
||||||
|
swapchain = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = device->GetSwapChain(swapchain, &SUB_SWAP_CHAIN);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
log_warning("graphics::d3d9", "failed to acquire fullscreen sub swap chain, hr={}", FMT_HRESULT(hr));
|
log_warning("graphics::d3d9", "failed to acquire fullscreen sub swap chain, hr={}", FMT_HRESULT(hr));
|
||||||
} else {
|
} else {
|
||||||
@@ -1233,7 +1252,7 @@ static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) {
|
|||||||
// iidx/sdvx
|
// iidx/sdvx
|
||||||
int swapchain = 1;
|
int swapchain = 1;
|
||||||
if (games::gitadora::is_arena_model()) {
|
if (games::gitadora::is_arena_model()) {
|
||||||
swapchain = 3;
|
swapchain = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE && SUB_SWAP_CHAIN == nullptr) {
|
if (!ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE && SUB_SWAP_CHAIN == nullptr) {
|
||||||
@@ -1452,8 +1471,9 @@ void graphics_d3d9_on_present(
|
|||||||
// for IIDX TDJ / SDVX UFC, handle subscreen
|
// for IIDX TDJ / SDVX UFC, handle subscreen
|
||||||
const bool is_vm = games::sdvx::is_valkyrie_model();
|
const bool is_vm = games::sdvx::is_valkyrie_model();
|
||||||
const bool is_tdj = avs::game::is_model("LDJ") && games::iidx::TDJ_MODE;
|
const bool is_tdj = avs::game::is_model("LDJ") && games::iidx::TDJ_MODE;
|
||||||
const bool is_gfdm_arena =
|
const bool is_gfdm_arena = games::gitadora::is_arena_model() &&
|
||||||
games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW;
|
(GRAPHICS_FORCE_SINGLE_ADAPTER || GRAPHICS_PREVENT_SECONDARY_WINDOW);
|
||||||
|
|
||||||
const bool is_pika = games::popn::is_pikapika_model();
|
const bool is_pika = games::popn::is_pikapika_model();
|
||||||
if (is_vm || is_tdj || is_gfdm_arena || is_pika) {
|
if (is_vm || is_tdj || is_gfdm_arena || is_pika) {
|
||||||
graphics_d3d9_ldj_on_present(wrapped_device);
|
graphics_d3d9_ldj_on_present(wrapped_device);
|
||||||
|
|||||||
@@ -129,13 +129,17 @@ ULONG STDMETHODCALLTYPE WrappedIDirect3DDevice9::Release() {
|
|||||||
this->main_swapchain->Release();
|
this->main_swapchain->Release();
|
||||||
this->main_swapchain = nullptr;
|
this->main_swapchain = nullptr;
|
||||||
}
|
}
|
||||||
if (this->sub_swapchain) {
|
for (auto &sc : this->sub_swapchain) {
|
||||||
this->sub_swapchain->Release();
|
if (sc) {
|
||||||
this->sub_swapchain = nullptr;
|
sc->Release();
|
||||||
|
sc = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &sc : this->fake_sub_swapchain) {
|
||||||
|
if (sc) {
|
||||||
|
sc->Release();
|
||||||
|
sc = nullptr;
|
||||||
}
|
}
|
||||||
if (this->fake_sub_swapchain) {
|
|
||||||
this->fake_sub_swapchain->Release();
|
|
||||||
this->fake_sub_swapchain = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlay::ENABLED) {
|
if (overlay::ENABLED) {
|
||||||
@@ -250,27 +254,47 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::CreateAdditionalSwapChain(
|
|||||||
WRAP_VERBOSE;
|
WRAP_VERBOSE;
|
||||||
|
|
||||||
HRESULT hr = pReal->CreateAdditionalSwapChain(pPresentationParameters, ppSwapChain);
|
HRESULT hr = pReal->CreateAdditionalSwapChain(pPresentationParameters, ppSwapChain);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
bool create_swap_chain = false;
|
bool create_swap_chain = false;
|
||||||
if (avs::game::is_model({"LDJ", "KFC", "M39"})) {
|
if (avs::game::is_model({"LDJ", "KFC", "M39"})) {
|
||||||
create_swap_chain = true;
|
create_swap_chain = true;
|
||||||
|
|
||||||
} else if (games::gitadora::is_arena_model() &&
|
} else if (games::gitadora::is_arena_model() &&
|
||||||
games::gitadora::ARENA_SINGLE_WINDOW &&
|
(GRAPHICS_FORCE_SINGLE_ADAPTER || GRAPHICS_PREVENT_SECONDARY_WINDOW)) {
|
||||||
pPresentationParameters->BackBufferWidth == 800) {
|
if (pPresentationParameters->BackBufferWidth == 800) {
|
||||||
|
// SMALL (subscreen)
|
||||||
create_swap_chain = true;
|
create_swap_chain = true;
|
||||||
|
index = 0;
|
||||||
|
} else if (pPresentationParameters->BackBufferWidth == 1080) {
|
||||||
|
// LEFT/RIGHT
|
||||||
|
create_swap_chain = true;
|
||||||
|
index = 1;
|
||||||
|
if (sub_swapchain[index] || fake_sub_swapchain[index]) {
|
||||||
|
index = 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_warning("graphics::d3d9", "unknown swap chain detected in CreateAdditionalSwapChain");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_swap_chain) {
|
if (create_swap_chain) {
|
||||||
if (SUCCEEDED(hr) && !sub_swapchain) {
|
log_misc(
|
||||||
sub_swapchain = new WrappedIDirect3DSwapChain9(this, *ppSwapChain);
|
"graphics::d3d9",
|
||||||
sub_swapchain->should_run_hooks = false;
|
"CreateAdditionalSwapChain called for swap chain {}, creating swap chain",
|
||||||
} else if (FAILED(hr) && !fake_sub_swapchain) {
|
index);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr) && !sub_swapchain[index]) {
|
||||||
|
sub_swapchain[index] = new WrappedIDirect3DSwapChain9(this, *ppSwapChain);
|
||||||
|
sub_swapchain[index]->should_run_hooks = false;
|
||||||
|
} else if (FAILED(hr) && !fake_sub_swapchain[index]) {
|
||||||
log_warning("graphics::d3d9",
|
log_warning("graphics::d3d9",
|
||||||
"failed to create sub swap chain, hr={}, using fake swap chain",
|
"failed to create sub swap chain, hr={}, using fake swap chain",
|
||||||
FMT_HRESULT(hr));
|
FMT_HRESULT(hr));
|
||||||
|
|
||||||
fake_sub_swapchain = new FakeIDirect3DSwapChain9(this, pPresentationParameters, false);
|
fake_sub_swapchain[index] = new FakeIDirect3DSwapChain9(this, pPresentationParameters, false);
|
||||||
fake_sub_swapchain->AddRef();
|
fake_sub_swapchain[index]->AddRef();
|
||||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(fake_sub_swapchain);
|
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(fake_sub_swapchain[index]);
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
@@ -308,22 +332,20 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::GetSwapChain(
|
|||||||
if (iSwapChain == 1 && avs::game::is_model({"LDJ", "KFC", "M39"})) {
|
if (iSwapChain == 1 && avs::game::is_model({"LDJ", "KFC", "M39"})) {
|
||||||
swap = true;
|
swap = true;
|
||||||
}
|
}
|
||||||
if (games::gitadora::is_arena_model() &&
|
if (games::gitadora::is_arena_model() && iSwapChain == 2) {
|
||||||
games::gitadora::ARENA_SINGLE_WINDOW &&
|
|
||||||
iSwapChain == 3) {
|
|
||||||
swap = true;
|
swap = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swap) {
|
if (swap) {
|
||||||
if (sub_swapchain) {
|
if (sub_swapchain[0]) {
|
||||||
sub_swapchain->AddRef();
|
sub_swapchain[0]->AddRef();
|
||||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(sub_swapchain);
|
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(sub_swapchain[0]);
|
||||||
|
|
||||||
graphics_screens_register(iSwapChain);
|
graphics_screens_register(iSwapChain);
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
} else if (fake_sub_swapchain) {
|
} else if (fake_sub_swapchain[0]) {
|
||||||
fake_sub_swapchain->AddRef();
|
fake_sub_swapchain[0]->AddRef();
|
||||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(fake_sub_swapchain);
|
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(fake_sub_swapchain[0]);
|
||||||
|
|
||||||
graphics_screens_register(iSwapChain);
|
graphics_screens_register(iSwapChain);
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
@@ -344,7 +366,7 @@ UINT STDMETHODCALLTYPE WrappedIDirect3DDevice9::GetNumberOfSwapChains() {
|
|||||||
|
|
||||||
UINT n = pReal->GetNumberOfSwapChains();
|
UINT n = pReal->GetNumberOfSwapChains();
|
||||||
|
|
||||||
if (sub_swapchain && avs::game::is_model({"LDJ", "KFC", "M39"})) {
|
if (sub_swapchain[0] && avs::game::is_model({"LDJ", "KFC", "M39"})) {
|
||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -204,7 +204,8 @@ struct WrappedIDirect3DDevice9 : IDirect3DDevice9Ex {
|
|||||||
std::atomic_ulong refs = 1;
|
std::atomic_ulong refs = 1;
|
||||||
|
|
||||||
WrappedIDirect3DSwapChain9 *main_swapchain = nullptr;
|
WrappedIDirect3DSwapChain9 *main_swapchain = nullptr;
|
||||||
WrappedIDirect3DSwapChain9 *sub_swapchain = nullptr;
|
WrappedIDirect3DSwapChain9 *sub_swapchain[3] = { nullptr, nullptr, nullptr };
|
||||||
FakeIDirect3DSwapChain9 *fake_sub_swapchain = nullptr;
|
FakeIDirect3DSwapChain9 *fake_sub_swapchain[3] = { nullptr, nullptr, nullptr };
|
||||||
|
|
||||||
IDirect3DVertexShader9 *vertex_shader = nullptr;
|
IDirect3DVertexShader9 *vertex_shader = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only hook touch window if multiple windows are allowed
|
// only hook touch window if multiple windows are allowed
|
||||||
if (is_gfdm_sub_window && !games::gitadora::ARENA_SINGLE_WINDOW) {
|
if (is_gfdm_sub_window && GRAPHICS_WINDOWED && !GRAPHICS_PREVENT_SECONDARY_WINDOW) {
|
||||||
GFDM_SUBSCREEN_WINDOW = result;
|
GFDM_SUBSCREEN_WINDOW = result;
|
||||||
graphics_hook_subscreen_window(GFDM_SUBSCREEN_WINDOW);
|
graphics_hook_subscreen_window(GFDM_SUBSCREEN_WINDOW);
|
||||||
}
|
}
|
||||||
@@ -702,7 +702,7 @@ static BOOL WINAPI SetWindowPos_hook(HWND hWnd, HWND hWndInsertAfter,
|
|||||||
|
|
||||||
static BOOL WINAPI ShowWindow_hook(HWND hWnd, int nCmdShow) {
|
static BOOL WINAPI ShowWindow_hook(HWND hWnd, int nCmdShow) {
|
||||||
if (games::gitadora::is_arena_model() &&
|
if (games::gitadora::is_arena_model() &&
|
||||||
games::gitadora::ARENA_SINGLE_WINDOW &&
|
GRAPHICS_PREVENT_SECONDARY_WINDOW &&
|
||||||
hWnd != GRAPHICS_HOOKED_WINDOW) {
|
hWnd != GRAPHICS_HOOKED_WINDOW) {
|
||||||
log_info("graphics", "ShowWindow_hook - hiding sub window {}", fmt::ptr(hWnd));
|
log_info("graphics", "ShowWindow_hook - hiding sub window {}", fmt::ptr(hWnd));
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -644,8 +644,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::GitaDoraCabinetType].is_active()) {
|
if (options[launcher::Options::GitaDoraCabinetType].is_active()) {
|
||||||
games::gitadora::CAB_TYPE = options[launcher::Options::GitaDoraCabinetType].value_uint32();
|
games::gitadora::CAB_TYPE = options[launcher::Options::GitaDoraCabinetType].value_uint32();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::GitaDoraArenaSingleWindow].value_bool() && GRAPHICS_WINDOWED) {
|
if (options[launcher::Options::GitaDoraArenaSingleWindow].value_bool()) {
|
||||||
games::gitadora::ARENA_SINGLE_WINDOW = true;
|
// for full screen
|
||||||
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
||||||
|
// for windowed
|
||||||
|
GRAPHICS_PREVENT_SECONDARY_WINDOW = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::GitaDoraWailHold].is_active()) {
|
if (options[launcher::Options::GitaDoraWailHold].is_active()) {
|
||||||
socd::TILT_HOLD_MS = options[launcher::Options::GitaDoraWailHold].value_uint32();
|
socd::TILT_HOLD_MS = options[launcher::Options::GitaDoraWailHold].value_uint32();
|
||||||
|
|||||||
@@ -1056,9 +1056,12 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// GitaDoraArenaSingleWindow
|
// GitaDoraArenaSingleWindow
|
||||||
.title = "GitaDora Arena Single Window (EXPERIMENTAL)",
|
.title = "GitaDora Arena Disable Subscreens (EXPERIMENTAL)",
|
||||||
.name = "gdaonewindow",
|
.name = "gdaonewindow",
|
||||||
.desc = "For Arena Model, when combined with windowed mode, only show the main game window; enables subscreen overlay.",
|
.desc = "For Arena Model:\n\n"
|
||||||
|
"Windowed mode: instead of 4 windows, create 1 window.\n\n"
|
||||||
|
"Fullscreen mode: instead of requiring 4 monitors, use only the primary monitor. WARNING: requires 4K monitor.\n\n"
|
||||||
|
"To access the subscreen, use the subscreen overlay.",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.game_name = "GitaDora",
|
.game_name = "GitaDora",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ namespace wintouchemu {
|
|||||||
// same as iidx case above
|
// same as iidx case above
|
||||||
log_info("wintouchemu", "use mouse cursor API for popn overlay subscreen");
|
log_info("wintouchemu", "use mouse cursor API for popn overlay subscreen");
|
||||||
USE_MOUSE = true;
|
USE_MOUSE = true;
|
||||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
} else if (games::gitadora::is_arena_model() && GRAPHICS_PREVENT_SECONDARY_WINDOW) {
|
||||||
log_info("wintouchemu", "use mouse cursor API for gitadora overlay subscreen");
|
log_info("wintouchemu", "use mouse cursor API for gitadora overlay subscreen");
|
||||||
USE_MOUSE = true;
|
USE_MOUSE = true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ void overlay::SpiceOverlay::init() {
|
|||||||
window_sub = new overlay::windows::DRSDanceFloorDisplay(this);
|
window_sub = new overlay::windows::DRSDanceFloorDisplay(this);
|
||||||
} else if (avs::game::is_model("KFC")) {
|
} else if (avs::game::is_model("KFC")) {
|
||||||
window_sub = new overlay::windows::SDVXSubScreen(this);
|
window_sub = new overlay::windows::SDVXSubScreen(this);
|
||||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
} else if (games::gitadora::is_arena_model()) {
|
||||||
window_sub = new overlay::windows::GitaDoraSubScreen(this);
|
window_sub = new overlay::windows::GitaDoraSubScreen(this);
|
||||||
} else if (games::popn::is_pikapika_model()) {
|
} else if (games::popn::is_pikapika_model()) {
|
||||||
window_sub = new overlay::windows::PopnSubScreen(this);
|
window_sub = new overlay::windows::PopnSubScreen(this);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace overlay::windows {
|
|||||||
sub = "Show Valkyrie Subscreen";
|
sub = "Show Valkyrie Subscreen";
|
||||||
} else if (avs::game::is_model("REC")) {
|
} else if (avs::game::is_model("REC")) {
|
||||||
sub = "Show DRS Dance Floor";
|
sub = "Show DRS Dance Floor";
|
||||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
} else if (games::gitadora::is_arena_model()) {
|
||||||
sub = "Show GITADORA Subscreen";
|
sub = "Show GITADORA Subscreen";
|
||||||
} else if (games::popn::is_pikapika_model()) {
|
} else if (games::popn::is_pikapika_model()) {
|
||||||
sub = "Show Pop'n Subscreen";
|
sub = "Show Pop'n Subscreen";
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
if (!games::gitadora::is_arena_model()) {
|
if (!games::gitadora::is_arena_model()) {
|
||||||
this->disabled_message = "Requires Arena Model!";
|
this->disabled_message = "Requires Arena Model!";
|
||||||
|
} else if (!GRAPHICS_PREVENT_SECONDARY_WINDOW) {
|
||||||
|
if (GRAPHICS_WINDOWED) {
|
||||||
|
this->disabled_message = "Use the dedicated subscreen window!";
|
||||||
|
} else {
|
||||||
|
this->disabled_message = "Subscreen overlay disabled by user; enable single window mode for overlay.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->resize_callback = keep_10_by_16;
|
this->resize_callback = keep_10_by_16;
|
||||||
|
|||||||
Reference in New Issue
Block a user