mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d1981fcde | |||
| 2f538fe2e4 | |||
| 8e01b2e5c8 | |||
| cd14ca800e | |||
| cb59fe14e9 | |||
| 9fd9290cd3 | |||
| 1dd99aac74 | |||
| 9e376f373e | |||
| d4e51b77d1 | |||
| 61181836b0 | |||
| 4e26c8afa5 | |||
| 7684028f99 | |||
| 1d6be8fe4b | |||
| c70cf40af3 | |||
| 5715d4e605 | |||
| 821a705a7d | |||
| 86f2a1fd39 | |||
| 86f218329a |
@@ -441,6 +441,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/scotto/io.cpp
|
games/scotto/io.cpp
|
||||||
games/drs/drs.cpp
|
games/drs/drs.cpp
|
||||||
games/drs/io.cpp
|
games/drs/io.cpp
|
||||||
|
games/drs/rgb_cam.cpp
|
||||||
games/we/we.cpp
|
games/we/we.cpp
|
||||||
games/we/io.cpp
|
games/we/io.cpp
|
||||||
games/we/touchpanel.cpp
|
games/we/touchpanel.cpp
|
||||||
@@ -554,6 +555,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
overlay/windows/camera_control.cpp
|
overlay/windows/camera_control.cpp
|
||||||
overlay/windows/card_manager.cpp
|
overlay/windows/card_manager.cpp
|
||||||
overlay/windows/drs_dancefloor.cpp
|
overlay/windows/drs_dancefloor.cpp
|
||||||
|
overlay/windows/gfdm_sub.cpp
|
||||||
overlay/windows/screen_resize.cpp
|
overlay/windows/screen_resize.cpp
|
||||||
overlay/windows/sdvx_sub.cpp
|
overlay/windows/sdvx_sub.cpp
|
||||||
overlay/windows/config.cpp
|
overlay/windows/config.cpp
|
||||||
|
|||||||
+24
-1
@@ -5,8 +5,9 @@
|
|||||||
#include "build/defs.h"
|
#include "build/defs.h"
|
||||||
#include "easrv/easrv.h"
|
#include "easrv/easrv.h"
|
||||||
#include "easrv/smartea.h"
|
#include "easrv/smartea.h"
|
||||||
#include "games/mfc/mfc.h"
|
#include "games/gitadora/gitadora.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/deferlog.h"
|
#include "util/deferlog.h"
|
||||||
#include "util/fileutils.h"
|
#include "util/fileutils.h"
|
||||||
@@ -528,6 +529,28 @@ namespace avs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update -WINDOW in app-config
|
||||||
|
if (games::gitadora::is_arena_model()) {
|
||||||
|
avs::core::property_search_remove_safe(app_config, nullptr, "/param/cmdline");
|
||||||
|
std::string cmdline{};
|
||||||
|
if (games::gitadora::is_drum()) {
|
||||||
|
if (GRAPHICS_WINDOWED) {
|
||||||
|
cmdline = "-d -DM -WINDOW";
|
||||||
|
} else {
|
||||||
|
cmdline = "-d -DM";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (GRAPHICS_WINDOWED) {
|
||||||
|
cmdline = "-g -GF -WINDOW";
|
||||||
|
} else {
|
||||||
|
cmdline = "-g -GF";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_info("avs-ea3", "using cmdline: `{}`", cmdline);
|
||||||
|
avs::core::property_node_create(app_config, nullptr,
|
||||||
|
avs::core::NODE_TYPE_str, "/param/cmdline", cmdline.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
auto app_param = avs::core::property_search_safe(app_config, nullptr, "/param");
|
auto app_param = avs::core::property_search_safe(app_config, nullptr, "/param");
|
||||||
|
|
||||||
// call the game init
|
// call the game init
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "bi2x_hook.h"
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
@@ -16,15 +18,19 @@ namespace games::ccj {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct AIO_SCI_COMM {
|
struct AIO_SCI_COMM {
|
||||||
|
uint8_t data[0xf8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB2 {
|
struct AIO_NMGR_IOB2 {
|
||||||
|
uint8_t data[0xe30];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_TBS {
|
struct AIO_IOB2_BI2X_TBS {
|
||||||
|
uint8_t data[0x4680];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_WRFIRM {
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
uint8_t data[0x20f48];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB__NODEINFO {
|
struct AIO_NMGR_IOB__NODEINFO {
|
||||||
@@ -72,6 +78,12 @@ namespace games::ccj {
|
|||||||
AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData;
|
AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// checked with UJK-001-2024060400
|
||||||
|
static_assert(sizeof(AIO_SCI_COMM) == 0xf8);
|
||||||
|
static_assert(sizeof(AIO_NMGR_IOB2) == 0xe30);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_TBS) == 0x4680);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48);
|
||||||
|
|
||||||
static void write_iccr_led(Lights::ccj_lights_t light, uint8_t value);
|
static void write_iccr_led(Lights::ccj_lights_t light, uint8_t value);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -621,4 +633,6 @@ namespace games::ccj {
|
|||||||
detour::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
detour::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||||||
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
namespace games::ccj {
|
namespace games::ccj {
|
||||||
void bi2x_hook_init();
|
void bi2x_hook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -68,9 +68,13 @@ namespace games::ccj {
|
|||||||
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(11),
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(11),
|
||||||
(void*)execexe_CreateFileW_hook,(void**)&execexe_CreateFileW_orig);
|
(void*)execexe_CreateFileW_hook,(void**)&execexe_CreateFileW_orig);
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
// insert BI2X hooks
|
// insert BI2X hooks
|
||||||
bi2x_hook_init();
|
bi2x_hook_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// insert trackball hooks
|
// insert trackball hooks
|
||||||
trackball_hook_init();
|
trackball_hook_init();
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/memutils.h"
|
#include "util/memutils.h"
|
||||||
|
#include "rgb_cam.h"
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
|
|
||||||
@@ -150,6 +151,7 @@ namespace games::drs {
|
|||||||
char DRS_TAPELED[DRS_TAPELED_COLS_TOTAL][3] {};
|
char DRS_TAPELED[DRS_TAPELED_COLS_TOTAL][3] {};
|
||||||
bool DISABLE_TOUCH = false;
|
bool DISABLE_TOUCH = false;
|
||||||
bool TRANSPOSE_TOUCH = false;
|
bool TRANSPOSE_TOUCH = false;
|
||||||
|
bool RGB_CAMERA_HOOK = false;
|
||||||
|
|
||||||
std::vector<TouchEvent> TOUCH_EVENTS;
|
std::vector<TouchEvent> TOUCH_EVENTS;
|
||||||
|
|
||||||
@@ -313,6 +315,10 @@ namespace games::drs {
|
|||||||
} else {
|
} else {
|
||||||
log_info("drs", "no native input method detected");
|
log_info("drs", "no native input method detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RGB_CAMERA_HOOK) {
|
||||||
|
init_rgb_camera_hook();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRSGame::detach() {
|
void DRSGame::detach() {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ namespace games::drs {
|
|||||||
extern std::vector<TouchEvent> TOUCH_EVENTS;
|
extern std::vector<TouchEvent> TOUCH_EVENTS;
|
||||||
extern bool DISABLE_TOUCH;
|
extern bool DISABLE_TOUCH;
|
||||||
extern bool TRANSPOSE_TOUCH;
|
extern bool TRANSPOSE_TOUCH;
|
||||||
|
extern bool RGB_CAMERA_HOOK;
|
||||||
|
|
||||||
void fire_touches(drs_touch_t *events, size_t event_count);
|
void fire_touches(drs_touch_t *events, size_t event_count);
|
||||||
void start_touch();
|
void start_touch();
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
#include "games/drs/rgb_cam.h"
|
||||||
|
|
||||||
|
// set version to Windows 7 to enable Media Foundation functions
|
||||||
|
#ifdef _WIN32_WINNT
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
#endif
|
||||||
|
#define _WIN32_WINNT 0x0601
|
||||||
|
|
||||||
|
// turn on C-style COM objects
|
||||||
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <mfobjects.h>
|
||||||
|
#include <mfidl.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "avs/game.h"
|
||||||
|
#include "cfg/configurator.h"
|
||||||
|
#include "hooks/cfgmgr32hook.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/memutils.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
|
||||||
|
static VTBL_TYPE(IMFActivate, GetAllocatedString) GetAllocatedString_orig = nullptr;
|
||||||
|
static decltype(MFEnumDeviceSources) *MFEnumDeviceSources_orig = nullptr;
|
||||||
|
|
||||||
|
namespace games::drs {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Camera related stuff
|
||||||
|
*/
|
||||||
|
static std::wstring CAMERA0_ID;
|
||||||
|
|
||||||
|
static HRESULT WINAPI GetAllocatedString_hook(IMFActivate* This, REFGUID guidKey, LPWSTR *ppwszValue,
|
||||||
|
UINT32 *pcchLength)
|
||||||
|
{
|
||||||
|
// call the original
|
||||||
|
HRESULT result = GetAllocatedString_orig(This, guidKey, ppwszValue, pcchLength);
|
||||||
|
|
||||||
|
// log the cam name
|
||||||
|
log_misc("drs::rgbcam", "obtained {}", ws2s(*ppwszValue));
|
||||||
|
|
||||||
|
// try first camera
|
||||||
|
wchar_t *pwc = nullptr;
|
||||||
|
if (CAMERA0_ID.length() == 23) {
|
||||||
|
pwc = wcsstr(*ppwszValue, CAMERA0_ID.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if camera could be identified
|
||||||
|
if (pwc) {
|
||||||
|
|
||||||
|
// fake the USB IDs
|
||||||
|
pwc[4] = L'2';
|
||||||
|
pwc[5] = L'8';
|
||||||
|
pwc[6] = L'8';
|
||||||
|
pwc[7] = L'c';
|
||||||
|
|
||||||
|
pwc[13] = L'0';
|
||||||
|
pwc[14] = L'0';
|
||||||
|
pwc[15] = L'0';
|
||||||
|
pwc[16] = L'2';
|
||||||
|
|
||||||
|
pwc[21] = L'0';
|
||||||
|
pwc[22] = L'0';
|
||||||
|
|
||||||
|
log_misc("drs::rgbcam", "replaced {}", ws2s(*ppwszValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return original result
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hook_camera(std::wstring camera_id, std::string camera_instance) {
|
||||||
|
// don't hook if camera 0 is already hooked
|
||||||
|
if (CAMERA0_ID.length() > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the camera ID
|
||||||
|
CAMERA0_ID = camera_id;
|
||||||
|
|
||||||
|
// cfgmgr hook
|
||||||
|
CFGMGR32_HOOK_SETTING camera_setting;
|
||||||
|
camera_setting.device_instance = 0xDEADBEEF;
|
||||||
|
camera_setting.parent_instance = ~camera_setting.device_instance;
|
||||||
|
camera_setting.device_id = "USB\\VEN_8086&DEV_8C2D";
|
||||||
|
camera_setting.device_node_id = "USB\\VID_288C&PID_0002&MI_00\\?&????????&?&????";
|
||||||
|
if (camera_instance.length() == 17) {
|
||||||
|
for (int i = 0; i < 17; i++) {
|
||||||
|
camera_setting.device_node_id[28 + i] = camera_instance[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfgmgr32hook_add(camera_setting);
|
||||||
|
|
||||||
|
log_info("drs::rgbcam", "hooked camera @ {}", ws2s(camera_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hook_camera_vtable(IMFActivate *camera) {
|
||||||
|
|
||||||
|
// hook allocated string method for camera identification
|
||||||
|
memutils::VProtectGuard camera_guard(camera->lpVtbl);
|
||||||
|
camera->lpVtbl->GetAllocatedString = GetAllocatedString_hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate,
|
||||||
|
UINT32 *pcSourceActivate) {
|
||||||
|
|
||||||
|
// call original function
|
||||||
|
HRESULT result_orig = MFEnumDeviceSources_orig(pAttributes, pppSourceActivate, pcSourceActivate);
|
||||||
|
|
||||||
|
// check for capture devices
|
||||||
|
if (FAILED(result_orig) || !*pcSourceActivate) {
|
||||||
|
return result_orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get camera
|
||||||
|
IMFActivate *camera = **pppSourceActivate;
|
||||||
|
|
||||||
|
// save original method for later use
|
||||||
|
if (GetAllocatedString_orig == nullptr) {
|
||||||
|
GetAllocatedString_orig = camera->lpVtbl->GetAllocatedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hook allocated string method for camera identification
|
||||||
|
hook_camera_vtable(camera);
|
||||||
|
|
||||||
|
// get camera link
|
||||||
|
LPWSTR camera_link_lpwstr;
|
||||||
|
UINT32 camera_link_length;
|
||||||
|
if (SUCCEEDED(GetAllocatedString_orig(
|
||||||
|
camera,
|
||||||
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
||||||
|
&camera_link_lpwstr,
|
||||||
|
&camera_link_length))) {
|
||||||
|
|
||||||
|
// cut name to make ID
|
||||||
|
std::wstring camera_link_ws = std::wstring(camera_link_lpwstr);
|
||||||
|
std::wstring camera_id = camera_link_ws.substr(8, 23);
|
||||||
|
|
||||||
|
log_info("drs::rgbcam", "found video capture device: {}", ws2s(camera_link_ws));
|
||||||
|
|
||||||
|
// only support cameras that start with \\?\usb
|
||||||
|
if (!string_begins_with(camera_link_ws, L"\\\\?\\usb")) {
|
||||||
|
return result_orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get camera instance
|
||||||
|
std::string camera_link = ws2s(camera_link_ws);
|
||||||
|
std::string camera_instance = camera_link.substr(32, 17);
|
||||||
|
|
||||||
|
// hook the camera
|
||||||
|
hook_camera(camera_id, camera_instance);
|
||||||
|
} else {
|
||||||
|
log_warning("drs::rgbcam", "failed to open camera");
|
||||||
|
}
|
||||||
|
|
||||||
|
// return result
|
||||||
|
return result_orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_rgb_camera_hook() {
|
||||||
|
log_info("drs::rgbcam", "initializing camera hook");
|
||||||
|
|
||||||
|
cfgmgr32hook_init(avs::game::DLL_INSTANCE);
|
||||||
|
|
||||||
|
// camera media framework hook
|
||||||
|
MFEnumDeviceSources_orig = detour::iat_try(
|
||||||
|
"MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace games::drs {
|
||||||
|
void init_rgb_camera_hook();
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "bi2x_hook.h"
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
@@ -18,24 +20,29 @@ namespace games::gitadora {
|
|||||||
// */
|
// */
|
||||||
|
|
||||||
struct AIO_NMGR_IOB2 {
|
struct AIO_NMGR_IOB2 {
|
||||||
|
uint8_t data[0xe18];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_AC1__SETTING {
|
struct AIO_IOB2_BI2X_AC1__SETTING {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB5 {
|
struct AIO_NMGR_IOB5 {
|
||||||
|
uint8_t data[0xb10];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_SCI_COMM {
|
struct AIO_SCI_COMM {
|
||||||
|
uint8_t data[0x100];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB5_Y32D {
|
struct AIO_IOB5_Y32D {
|
||||||
|
uint8_t data[0x2e8];
|
||||||
};
|
};
|
||||||
|
|
||||||
// struct AIO_IOB5_Y33I {
|
// struct AIO_IOB5_Y33I {
|
||||||
// };
|
// };
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_AC1 {
|
struct AIO_IOB2_BI2X_AC1 {
|
||||||
|
uint8_t data[0x4570];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB__NODEINFO {
|
struct AIO_NMGR_IOB__NODEINFO {
|
||||||
@@ -43,6 +50,7 @@ namespace games::gitadora {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_WRFIRM {
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
uint8_t data[0x20f48];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_SCI_COMM_T {
|
struct AIO_SCI_COMM_T {
|
||||||
@@ -159,6 +167,14 @@ namespace games::gitadora {
|
|||||||
uint8_t unk[0xB1];
|
uint8_t unk[0xB1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// verified with M32-007-2025092400
|
||||||
|
static_assert(sizeof(AIO_NMGR_IOB2) == 0xe18);
|
||||||
|
static_assert(sizeof(AIO_NMGR_IOB5) == 0xb10);
|
||||||
|
static_assert(sizeof(AIO_SCI_COMM) == 0x100);
|
||||||
|
static_assert(sizeof(AIO_IOB5_Y32D) == 0x2e8);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_AC1) == 0x4570);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typedefs
|
* typedefs
|
||||||
*/
|
*/
|
||||||
@@ -701,4 +717,6 @@ namespace games::gitadora {
|
|||||||
detour::trampoline_try(libaioDll, "aioNodeCtl_UpdateDevicesStatus",
|
detour::trampoline_try(libaioDll, "aioNodeCtl_UpdateDevicesStatus",
|
||||||
aioNodeCtl_UpdateDevicesStatus, &aioNodeCtl_UpdateDevicesStatus_orig);
|
aioNodeCtl_UpdateDevicesStatus, &aioNodeCtl_UpdateDevicesStatus_orig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
namespace games::gitadora {
|
namespace games::gitadora {
|
||||||
void bi2x_hook_init();
|
void bi2x_hook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
#include "hooks/audio/mme.h"
|
#include "hooks/audio/mme.h"
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
|
#include "misc/wintouchemu.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "util/cpuutils.h"
|
#include "util/cpuutils.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
@@ -19,8 +20,11 @@ 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<socd::SocdAlgorithm> PICK_ALGO = socd::SocdAlgorithm::PreferRecent;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prevent GitaDora from creating folders on F drive
|
* Prevent GitaDora from creating folders on F drive
|
||||||
@@ -224,8 +228,15 @@ namespace games::gitadora {
|
|||||||
overlay::UI_SCALE_PERCENT = 250;
|
overlay::UI_SCALE_PERCENT = 250;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for guitar wail SOCD cleaning
|
// for guitar wail SOCD cleaning
|
||||||
socd::ALGORITHM = socd::SocdAlgorithm::PreferRecent;
|
socd::ALGORITHM = socd::SocdAlgorithm::PreferRecent;
|
||||||
|
|
||||||
|
// for guitar picking
|
||||||
|
if (PICK_ALGO.has_value()) {
|
||||||
|
log_info("gitadora", "guitar pick SOCD algorithm: {}", static_cast<int>(PICK_ALGO.value()));
|
||||||
|
} else {
|
||||||
|
log_info("gitadora", "guitar pick SOCD algorithm: legacy");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,6 +296,13 @@ 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
|
||||||
|
if (ARENA_SINGLE_WINDOW) {
|
||||||
|
wintouchemu::FORCE = true;
|
||||||
|
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||||
|
wintouchemu::hook("GITADORA", avs::game::DLL_INSTANCE);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,18 @@
|
|||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "games/game.h"
|
#include "games/game.h"
|
||||||
|
#include "util/socd_cleaner.h"
|
||||||
|
|
||||||
namespace games::gitadora {
|
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<socd::SocdAlgorithm> PICK_ALGO;
|
||||||
|
|
||||||
class GitaDoraGame : public games::Game {
|
class GitaDoraGame : public games::Game {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -65,17 +65,18 @@ std::vector<Button> &games::gitadora::get_buttons() {
|
|||||||
"Drum Help",
|
"Drum Help",
|
||||||
"Drum Button Extra 1",
|
"Drum Button Extra 1",
|
||||||
"Drum Button Extra 2",
|
"Drum Button Extra 2",
|
||||||
|
|
||||||
|
"Drum Left Cymbal",
|
||||||
"Drum Hi-Hat",
|
"Drum Hi-Hat",
|
||||||
"Drum Hi-Hat Closed",
|
"Drum Left Pedal",
|
||||||
"Drum Hi-Hat Half-Open",
|
|
||||||
"Drum Snare",
|
"Drum Snare",
|
||||||
"Drum Hi-Tom",
|
"Drum Hi-Tom",
|
||||||
"Drum Low-Tom",
|
|
||||||
"Drum Right Cymbal",
|
|
||||||
"Drum Bass Pedal",
|
"Drum Bass Pedal",
|
||||||
"Drum Left Cymbal",
|
"Drum Low-Tom",
|
||||||
"Drum Left Pedal",
|
"Drum Floor Tom",
|
||||||
"Drum Floor Tom"
|
"Drum Right Cymbal",
|
||||||
|
"Drum Hi-Hat Closed",
|
||||||
|
"Drum Hi-Hat Half-Open"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,11 +111,11 @@ std::string games::gitadora::get_buttons_help() {
|
|||||||
"\n"
|
"\n"
|
||||||
" < R G B Y P --- Pick ] \n"
|
" < R G B Y P --- Pick ] \n"
|
||||||
"\n"
|
"\n"
|
||||||
" If you hold your guitar left-handed (frets on the right hand):\n"
|
" If you normally hold your guitar left-handed (frets on right hand):\n"
|
||||||
" * bind the buttons here as righty and use the in-game option\n"
|
" * here, hold the guitar as right-handed (frets on left hand),\n"
|
||||||
" to turn on LEFT mode to flip the order of buttons.\n"
|
" and bind the buttons, pick, and wail controls\n"
|
||||||
" * turn on GitaDora Lefty Guitar option in Options tab so that\n"
|
" * in Options tab, turn on GitaDora Lefty Guitar\n"
|
||||||
" wailing is recognized correctly.\n"
|
" * finally, use the in-game option to turn on LEFT mode\n"
|
||||||
"\n"
|
"\n"
|
||||||
"\n"
|
"\n"
|
||||||
"drums:\n"
|
"drums:\n"
|
||||||
@@ -126,8 +127,6 @@ std::string games::gitadora::get_buttons_help() {
|
|||||||
" Left Bass\n"
|
" Left Bass\n"
|
||||||
" Pedal Pedal\n"
|
" Pedal Pedal\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Drums are NOT velocity-sensitive!\n"
|
|
||||||
"\n"
|
|
||||||
" For MIDI drums with Open/Closed HiHat configurations or pads with\n"
|
" For MIDI drums with Open/Closed HiHat configurations or pads with\n"
|
||||||
" multiple hit zones, ensure you bind all variation using the Pages\n"
|
" multiple hit zones, ensure you bind all variation using the Pages\n"
|
||||||
" button at the bottom."
|
" button at the bottom."
|
||||||
@@ -138,7 +137,7 @@ std::string games::gitadora::get_analogs_help() {
|
|||||||
return
|
return
|
||||||
"guitar:\n"
|
"guitar:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"X axis: 0% when body is held facing monitor, 50% when facing flat on a table\n"
|
"X axis: 0% when body is held facing monitor, 50% when flat on a table\n"
|
||||||
"Y axis: 50% when held horizontal, 0% when neck is raised, 100% pointing down\n"
|
"Y axis: 50% when held horizontal, 0% when neck is raised, 100% pointing down\n"
|
||||||
"Z axis: 50% at rest, 100% when swinging neck toward monitor (only used in XG series)\n"
|
"Z axis: 50% at rest, 100% when swinging neck toward monitor (only used in XG series)\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|||||||
@@ -66,18 +66,21 @@ namespace games::gitadora {
|
|||||||
DrumHelp,
|
DrumHelp,
|
||||||
DrumButtonExtra1,
|
DrumButtonExtra1,
|
||||||
DrumButtonExtra2,
|
DrumButtonExtra2,
|
||||||
// note: this is the order they appear in the test menu
|
// note: this is the order of drums in the default layout
|
||||||
|
DrumLeftCymbal,
|
||||||
DrumHiHat,
|
DrumHiHat,
|
||||||
DrumHiHatClosed,
|
DrumLeftPedal,
|
||||||
DrumHiHatHalfOpen,
|
|
||||||
DrumSnare,
|
DrumSnare,
|
||||||
DrumHiTom,
|
DrumHiTom,
|
||||||
DrumLowTom,
|
|
||||||
DrumRightCymbal,
|
|
||||||
DrumBassPedal,
|
DrumBassPedal,
|
||||||
DrumLeftCymbal,
|
DrumLowTom,
|
||||||
DrumLeftPedal,
|
DrumFloorTom,
|
||||||
DrumFloorTom
|
DrumRightCymbal,
|
||||||
|
|
||||||
|
// these only exist for back compat
|
||||||
|
// (created before it was possible to map multiple input to a button)
|
||||||
|
DrumHiHatClosed,
|
||||||
|
DrumHiHatHalfOpen
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,22 +92,44 @@ bool games::gitadora::J33ISerialDevice::parse_msg(
|
|||||||
payload.buttons |= 1 << GUITAR_BTN_P;
|
payload.buttons |= 1 << GUITAR_BTN_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::GuitarP1PickUp])) {
|
|
||||||
if (!GFDM_GF_PICK_STATE_UP) {
|
const auto pick_up = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::GuitarP1PickUp]);
|
||||||
GFDM_GF_PICK_STATE_UP = true;
|
const auto pick_down = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::GuitarP1PickDown]);
|
||||||
payload.buttons |= 1 << GUITAR_PICK_UP;
|
if (!games::gitadora::PICK_ALGO.has_value()) {
|
||||||
|
// legacy behavior (detect rising edges only, input for 1 frame)
|
||||||
|
if (pick_up) {
|
||||||
|
if (!GFDM_GF_PICK_STATE_UP) {
|
||||||
|
GFDM_GF_PICK_STATE_UP = true;
|
||||||
|
payload.buttons |= 1 << GUITAR_PICK_UP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GFDM_GF_PICK_STATE_UP = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pick_down) {
|
||||||
|
if (!GFDM_GF_PICK_STATE_DOWN) {
|
||||||
|
GFDM_GF_PICK_STATE_DOWN = true;
|
||||||
|
payload.buttons |= 1 << GUITAR_PICK_DOWN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GFDM_GF_PICK_STATE_DOWN = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GFDM_GF_PICK_STATE_UP = false;
|
const auto socd = socd::socd_clean(
|
||||||
}
|
0,
|
||||||
|
pick_up,
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::GuitarP1PickDown])) {
|
pick_down,
|
||||||
if (!GFDM_GF_PICK_STATE_DOWN) {
|
get_performance_milliseconds(),
|
||||||
GFDM_GF_PICK_STATE_DOWN = true;
|
games::gitadora::PICK_ALGO.value()
|
||||||
|
);
|
||||||
|
if (socd == socd::SocdCCW) {
|
||||||
|
payload.buttons |= 1 << GUITAR_PICK_UP;
|
||||||
|
} else if (socd == socd::SocdCW) {
|
||||||
|
payload.buttons |= 1 << GUITAR_PICK_DOWN;
|
||||||
|
} else if (socd == socd::SocdBoth) {
|
||||||
|
payload.buttons |= 1 << GUITAR_PICK_UP;
|
||||||
payload.buttons |= 1 << GUITAR_PICK_DOWN;
|
payload.buttons |= 1 << GUITAR_PICK_DOWN;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
GFDM_GF_PICK_STATE_DOWN = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &analogs = get_analogs();
|
auto &analogs = get_analogs();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "bi2x_hook.h"
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
#include "util/execexe.h"
|
#include "util/execexe.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
@@ -9,9 +11,10 @@
|
|||||||
#include "util/tapeled.h"
|
#include "util/tapeled.h"
|
||||||
#include "pc.h"
|
#include "pc.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
#include "util/time.h"
|
||||||
|
#include "util/socd_cleaner.h"
|
||||||
|
|
||||||
namespace games::pc {
|
namespace games::pc {
|
||||||
bool PC_KNOB_MODE = false;
|
|
||||||
|
|
||||||
constexpr float RELATIVE_DECAY = 0.02f;
|
constexpr float RELATIVE_DECAY = 0.02f;
|
||||||
struct FADER_RELATIVE {
|
struct FADER_RELATIVE {
|
||||||
@@ -75,18 +78,22 @@ namespace games::pc {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct AIO_SCI_COMM {
|
struct AIO_SCI_COMM {
|
||||||
|
uint8_t data[0xf8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB2 {
|
struct AIO_NMGR_IOB2 {
|
||||||
|
uint8_t data[0xe30];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_AC1 {
|
struct AIO_IOB2_BI2X_AC1 {
|
||||||
|
uint8_t data[0x4538];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_AC1__SETTING {
|
struct AIO_IOB2_BI2X_AC1__SETTING {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_WRFIRM {
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
uint8_t data[0x20f48];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_AC1__INPUT
|
struct AIO_IOB2_BI2X_AC1__INPUT
|
||||||
@@ -191,6 +198,12 @@ namespace games::pc {
|
|||||||
AIO_IOB2_BI2X_AC1__ICNPIN ICnPinHist[20];
|
AIO_IOB2_BI2X_AC1__ICNPIN ICnPinHist[20];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// verified with XIF-2024122300
|
||||||
|
static_assert(sizeof(AIO_SCI_COMM) == 0xf8);
|
||||||
|
static_assert(sizeof(AIO_NMGR_IOB2) == 0xe30);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_AC1) == 0x4538);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typedefs
|
* typedefs
|
||||||
*/
|
*/
|
||||||
@@ -338,14 +351,21 @@ namespace games::pc {
|
|||||||
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2;
|
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]) &&
|
|
||||||
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) {
|
const auto now = get_performance_milliseconds();
|
||||||
val = 0.f;
|
|
||||||
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left])) {
|
const auto fader_l_socd = socd::socd_clean(
|
||||||
|
0, // Fader-L
|
||||||
|
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]),
|
||||||
|
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right]),
|
||||||
|
now);
|
||||||
|
|
||||||
|
if (fader_l_socd == socd::SocdCCW) {
|
||||||
val = -1.0f;
|
val = -1.0f;
|
||||||
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) {
|
} else if (fader_l_socd == socd::SocdCW) {
|
||||||
val = +1.0f;
|
val = +1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
o_DevStatus->Input.CN15_7 = (val < 0.2f) ? 0xFF : 0;
|
o_DevStatus->Input.CN15_7 = (val < 0.2f) ? 0xFF : 0;
|
||||||
o_DevStatus->Input.CN15_6 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
o_DevStatus->Input.CN15_6 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
||||||
o_DevStatus->Input.CN15_5 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
o_DevStatus->Input.CN15_5 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
||||||
@@ -363,14 +383,19 @@ namespace games::pc {
|
|||||||
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2;
|
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]) &&
|
|
||||||
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) {
|
const auto fader_r_socd = socd::socd_clean(
|
||||||
val = 0.f;
|
1, // Fader-R
|
||||||
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left])) {
|
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]),
|
||||||
|
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right]),
|
||||||
|
now);
|
||||||
|
|
||||||
|
if (fader_r_socd == socd::SocdCCW) {
|
||||||
val = -1.0f;
|
val = -1.0f;
|
||||||
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) {
|
} else if (fader_r_socd == socd::SocdCW) {
|
||||||
val = +1.0f;
|
val = +1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
o_DevStatus->Input.CN11_20 = (val < 0.2f) ? 0xFF : 0;
|
o_DevStatus->Input.CN11_20 = (val < 0.2f) ? 0xFF : 0;
|
||||||
o_DevStatus->Input.CN11_19 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
o_DevStatus->Input.CN11_19 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
||||||
o_DevStatus->Input.CN9_10 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
o_DevStatus->Input.CN9_10 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
||||||
@@ -737,3 +762,5 @@ namespace games::pc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
namespace games::pc {
|
namespace games::pc {
|
||||||
void bi2x_hook_init();
|
void bi2x_hook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -12,10 +12,12 @@
|
|||||||
#include "misc/wintouchemu.h"
|
#include "misc/wintouchemu.h"
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
|
#include "util/socd_cleaner.h"
|
||||||
|
|
||||||
namespace games::pc {
|
namespace games::pc {
|
||||||
std::string PC_INJECT_ARGS = "";
|
std::string PC_INJECT_ARGS = "";
|
||||||
bool PC_NO_IO = false;
|
bool PC_NO_IO = false;
|
||||||
|
bool PC_KNOB_MODE = false;
|
||||||
|
|
||||||
static acioemu::ACIOHandle *acioHandle = nullptr;
|
static acioemu::ACIOHandle *acioHandle = nullptr;
|
||||||
static std::wstring portName = L"COM1";
|
static std::wstring portName = L"COM1";
|
||||||
@@ -61,6 +63,11 @@ namespace games::pc {
|
|||||||
return ERROR_NOT_SUPPORTED;
|
return ERROR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCGame::pre_attach() {
|
||||||
|
// SOCD
|
||||||
|
socd::ALGORITHM = socd::SocdAlgorithm::PreferRecent;
|
||||||
|
}
|
||||||
|
|
||||||
void PCGame::attach() {
|
void PCGame::attach() {
|
||||||
Game::attach();
|
Game::attach();
|
||||||
|
|
||||||
@@ -78,9 +85,14 @@ namespace games::pc {
|
|||||||
execexe::load_library("libaio-iob2_video.dll");
|
execexe::load_library("libaio-iob2_video.dll");
|
||||||
execexe::load_library("win10actlog.dll");
|
execexe::load_library("win10actlog.dll");
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
if (!PC_NO_IO) {
|
if (!PC_NO_IO) {
|
||||||
bi2x_hook_init();
|
bi2x_hook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto user32Dll = "user32.dll";
|
const auto user32Dll = "user32.dll";
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace games::pc {
|
|||||||
public:
|
public:
|
||||||
PCGame() : Game("Polaris Chord") {}
|
PCGame() : Game("Polaris Chord") {}
|
||||||
|
|
||||||
|
virtual void pre_attach() override;
|
||||||
virtual void attach() override;
|
virtual void attach() override;
|
||||||
virtual void detach() override;
|
virtual void detach() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "bi2x_hook.h"
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
@@ -15,15 +17,19 @@ namespace games::qks {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct AIO_SCI_COMM {
|
struct AIO_SCI_COMM {
|
||||||
|
uint8_t data[0xf8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB {
|
struct AIO_NMGR_IOB {
|
||||||
|
uint8_t data[0xa00];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_AC1 {
|
struct AIO_IOB2_BI2X_AC1 {
|
||||||
|
uint8_t data[0x3908];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_IOB2_BI2X_WRFIRM {
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
uint8_t data[0x20f48];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIO_NMGR_IOB__NODEINFO {
|
struct AIO_NMGR_IOB__NODEINFO {
|
||||||
@@ -174,6 +180,12 @@ namespace games::qks {
|
|||||||
AIO_IOB2_BI2X_AC1__SETTING Setting;
|
AIO_IOB2_BI2X_AC1__SETTING Setting;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// verified with UKS-001-2024030600
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_AC1) == 0x3908);
|
||||||
|
static_assert(sizeof(AIO_SCI_COMM) == 0xf8);
|
||||||
|
static_assert(sizeof(AIO_NMGR_IOB) == 0xa00);
|
||||||
|
static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typedefs
|
* typedefs
|
||||||
*/
|
*/
|
||||||
@@ -602,4 +614,6 @@ namespace games::qks {
|
|||||||
detour::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
detour::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||||||
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace games::qks {
|
namespace games::qks {
|
||||||
void bi2x_hook_init();
|
void bi2x_hook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -86,9 +86,13 @@ namespace games::qks {
|
|||||||
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(9),
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(9),
|
||||||
execexe_CreateFileA_hook,&execexe_CreateFileA_orig);
|
execexe_CreateFileA_hook,&execexe_CreateFileA_orig);
|
||||||
|
|
||||||
|
#if SPICE64
|
||||||
|
|
||||||
// insert BI2X hooks
|
// insert BI2X hooks
|
||||||
bi2x_hook_init();
|
bi2x_hook_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// add card reader
|
// add card reader
|
||||||
acioHandle = new acioemu::ACIOHandle(portName.c_str());
|
acioHandle = new acioemu::ACIOHandle(portName.c_str());
|
||||||
devicehook_init_trampoline();
|
devicehook_init_trampoline();
|
||||||
|
|||||||
@@ -65,10 +65,6 @@ namespace games::sdvx {
|
|||||||
|
|
||||||
// prevent the game from randomly picking an ASIO device
|
// prevent the game from randomly picking an ASIO device
|
||||||
if (!USE_ASIO) {
|
if (!USE_ASIO) {
|
||||||
log_info(
|
|
||||||
"sdvx::asio",
|
|
||||||
"game tried to access HKLM\\SOFTWARE\\ASIO but ASIO is disabled; "
|
|
||||||
"access prevented, ASIO init will fail");
|
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
// convince the game to use our hook (so we can swap in the preferred device)
|
// convince the game to use our hook (so we can swap in the preferred device)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
|
#include "games/gitadora/gitadora.h"
|
||||||
#include "games/iidx/iidx.h"
|
#include "games/iidx/iidx.h"
|
||||||
#include "games/sdvx/sdvx.h"
|
#include "games/sdvx/sdvx.h"
|
||||||
#include "games/mfc/mfc.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) {
|
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) {
|
if (!ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE && SUB_SWAP_CHAIN == nullptr) {
|
||||||
ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE = true;
|
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)) {
|
if (FAILED(hr)) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"graphics::d3d9",
|
"graphics::d3d9",
|
||||||
@@ -1383,7 +1390,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;
|
||||||
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);
|
graphics_d3d9_ldj_on_present(wrapped_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
|
#include "games/gitadora/gitadora.h"
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "util/flags_helper.h"
|
#include "util/flags_helper.h"
|
||||||
@@ -249,8 +250,16 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::CreateAdditionalSwapChain(
|
|||||||
WRAP_VERBOSE;
|
WRAP_VERBOSE;
|
||||||
|
|
||||||
HRESULT hr = pReal->CreateAdditionalSwapChain(pPresentationParameters, ppSwapChain);
|
HRESULT hr = pReal->CreateAdditionalSwapChain(pPresentationParameters, ppSwapChain);
|
||||||
|
bool create_swap_chain = false;
|
||||||
if (avs::game::is_model({"LDJ", "KFC"})) {
|
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) {
|
if (SUCCEEDED(hr) && !sub_swapchain) {
|
||||||
sub_swapchain = new WrappedIDirect3DSwapChain9(this, *ppSwapChain);
|
sub_swapchain = new WrappedIDirect3DSwapChain9(this, *ppSwapChain);
|
||||||
sub_swapchain->should_run_hooks = false;
|
sub_swapchain->should_run_hooks = false;
|
||||||
@@ -295,7 +304,17 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::GetSwapChain(
|
|||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool swap = false;
|
||||||
if (iSwapChain == 1 && avs::game::is_model({"LDJ", "KFC"})) {
|
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) {
|
if (sub_swapchain) {
|
||||||
sub_swapchain->AddRef();
|
sub_swapchain->AddRef();
|
||||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(sub_swapchain);
|
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(sub_swapchain);
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ bool GRAPHICS_SHOW_CURSOR = false;
|
|||||||
graphics_orientation GRAPHICS_ADJUST_ORIENTATION = ORIENTATION_NORMAL;
|
graphics_orientation GRAPHICS_ADJUST_ORIENTATION = ORIENTATION_NORMAL;
|
||||||
bool GRAPHICS_WINDOWED = false;
|
bool GRAPHICS_WINDOWED = false;
|
||||||
std::vector<HWND> GRAPHICS_WINDOWS;
|
std::vector<HWND> GRAPHICS_WINDOWS;
|
||||||
std::optional<HWND> GRAPHICS_WINDOW_MAIN;
|
|
||||||
UINT GRAPHICS_FORCE_REFRESH = 0;
|
UINT GRAPHICS_FORCE_REFRESH = 0;
|
||||||
std::optional<uint32_t> GRAPHICS_FORCE_REFRESH_SUB;
|
std::optional<uint32_t> GRAPHICS_FORCE_REFRESH_SUB;
|
||||||
std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
||||||
@@ -98,6 +97,7 @@ static decltype(SetCursor) *SetCursor_orig = nullptr;
|
|||||||
static decltype(SetWindowLongA) *SetWindowLongA_orig = nullptr;
|
static decltype(SetWindowLongA) *SetWindowLongA_orig = nullptr;
|
||||||
static decltype(SetWindowLongW) *SetWindowLongW_orig = nullptr;
|
static decltype(SetWindowLongW) *SetWindowLongW_orig = nullptr;
|
||||||
static decltype(SetWindowPos) *SetWindowPos_orig = nullptr;
|
static decltype(SetWindowPos) *SetWindowPos_orig = nullptr;
|
||||||
|
static decltype(ShowWindow) *ShowWindow_orig = nullptr;
|
||||||
|
|
||||||
static void reset_window_hook(HWND hWnd) {
|
static void reset_window_hook(HWND hWnd) {
|
||||||
overlay::destroy(hWnd);
|
overlay::destroy(hWnd);
|
||||||
@@ -300,6 +300,30 @@ static BOOL WINAPI ClipCursor_hook(const RECT *lpRect) {
|
|||||||
return ClipCursor_orig(lpRect);
|
return ClipCursor_orig(lpRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fix_up_rb_auto_rotate_dimensions(DWORD &w, DWORD &h) {
|
||||||
|
// reflec beat
|
||||||
|
// for whatever reason, rb creates the first window it weird dimensions (774x1389 for reflesia, for example)
|
||||||
|
// so doing ChangeDisplaySettings as-is ends up with DISP_CHANGE_BADMODE
|
||||||
|
// while a second window (with title D3DProxyWindow) does get created with correct dimensions, it's
|
||||||
|
// too late to rotate the window then; as a workaround force the display change now with patched up dimensions
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
if (w == 774) {
|
||||||
|
// LBR, MBR reflesia
|
||||||
|
w = 768;
|
||||||
|
h = 1360;
|
||||||
|
changed = true;
|
||||||
|
} else if (w == 1086) {
|
||||||
|
// MBR (before reflesia)
|
||||||
|
w = 1080;
|
||||||
|
h = 1920;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
log_misc("graphics", "fix auto-rotate dimensions for reflec beat: w={}, h={}", w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName,
|
static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName,
|
||||||
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
|
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
|
||||||
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
|
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
|
||||||
@@ -324,10 +348,19 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
// set display orientation and/or refresh rate
|
// set display orientation and/or refresh rate
|
||||||
// only set orientation when the target window is portrait
|
// only set orientation when the target window is portrait
|
||||||
// (avoid doing this for SDVX subscreen which is in landscape, for example)
|
// (avoid doing this for SDVX subscreen which is in landscape, for example)
|
||||||
const auto adjust_orientation =
|
auto adjust_orientation =
|
||||||
(GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ||
|
(GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ||
|
||||||
GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CCW);
|
GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CCW);
|
||||||
|
|
||||||
|
// reflec beat
|
||||||
|
if (avs::game::is_model("KBR")) {
|
||||||
|
// KBR (rb1) launches landscape and draws rotated by itself, don't do any rotation
|
||||||
|
adjust_orientation = false;
|
||||||
|
} else if (avs::game::is_model({"LBR", "MBR"}) && window_name == "D3DProxyWindow") {
|
||||||
|
// do not auto-rotate for second window (D3DProxyWindow)
|
||||||
|
adjust_orientation = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((nHeight > nWidth && adjust_orientation) || GRAPHICS_FORCE_REFRESH > 0) {
|
if ((nHeight > nWidth && adjust_orientation) || GRAPHICS_FORCE_REFRESH > 0) {
|
||||||
DEVMODE mode {};
|
DEVMODE mode {};
|
||||||
|
|
||||||
@@ -337,11 +370,16 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
DWORD orientation = GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ? DMDO_90 : DMDO_270;
|
DWORD orientation = GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ? DMDO_90 : DMDO_270;
|
||||||
log_misc(
|
log_misc(
|
||||||
"graphics",
|
"graphics",
|
||||||
"auto-rotate: call ChangeDisplaySettings and rotate display to DMDO_xx mode {}",
|
"auto-rotate: call ChangeDisplaySettings and rotate display to DMDO_xx mode {}, w={}, h={}",
|
||||||
orientation);
|
orientation, nWidth, nHeight);
|
||||||
mode.dmPelsWidth = nWidth;
|
mode.dmPelsWidth = nWidth;
|
||||||
mode.dmPelsHeight = nHeight;
|
mode.dmPelsHeight = nHeight;
|
||||||
mode.dmDisplayOrientation = orientation;
|
mode.dmDisplayOrientation = orientation;
|
||||||
|
|
||||||
|
// reflec beat
|
||||||
|
if (avs::game::is_model({"LBR", "MBR"})) {
|
||||||
|
fix_up_rb_auto_rotate_dimensions(mode.dmPelsWidth, mode.dmPelsHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GRAPHICS_FORCE_REFRESH > 0) {
|
if (GRAPHICS_FORCE_REFRESH > 0) {
|
||||||
@@ -356,7 +394,7 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
|
|
||||||
const auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
|
const auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
|
||||||
if (disp_res != DISP_CHANGE_SUCCESSFUL) {
|
if (disp_res != DISP_CHANGE_SUCCESSFUL) {
|
||||||
log_warning("graphics", "failed to change display settings: {}", disp_res);
|
log_warning("graphics", "ChangeDisplaySettings failed: {}", disp_res);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_warning("graphics", "failed to get display settings");
|
log_warning("graphics", "failed to get display settings");
|
||||||
@@ -364,12 +402,10 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gfdm
|
// gfdm
|
||||||
bool is_gitadora_main_window = false;
|
|
||||||
if (avs::game::is_model({"J32", "J33", "K32", "K33", "L32", "L33", "M32"})) {
|
if (avs::game::is_model({"J32", "J33", "K32", "K33", "L32", "L33", "M32"})) {
|
||||||
// set window name
|
// set window name
|
||||||
if (!lpWindowName) {
|
if (!lpWindowName) {
|
||||||
lpWindowName = "GITADORA";
|
lpWindowName = "GITADORA";
|
||||||
is_gitadora_main_window = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +413,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_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");
|
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) {
|
if ((is_tdj_sub_window && GRAPHICS_IIDX_WSUB) || is_sdvx_sub_window || is_gfdm_sub_window) {
|
||||||
dwStyle &= ~(WS_MAXIMIZEBOX);
|
dwStyle &= ~(WS_MAXIMIZEBOX);
|
||||||
}
|
}
|
||||||
@@ -385,7 +421,7 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
if (is_gfdm_sub_window) {
|
if (is_gfdm_sub_window) {
|
||||||
dwStyle &= ~(WS_SIZEBOX);
|
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);
|
dwStyle &= ~(WS_OVERLAPPEDWINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,11 +448,6 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
hWndParent, hMenu, hInstance, lpParam);
|
hWndParent, hMenu, hInstance, lpParam);
|
||||||
GRAPHICS_WINDOWS.push_back(result);
|
GRAPHICS_WINDOWS.push_back(result);
|
||||||
|
|
||||||
// this is only really needed for arena model, but pre-arena model was single window anyway
|
|
||||||
if (is_gitadora_main_window) {
|
|
||||||
GRAPHICS_WINDOW_MAIN = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_tdj_sub_window) {
|
if (is_tdj_sub_window) {
|
||||||
// TDJ windowed mode: remember the subscreen window handle for later
|
// TDJ windowed mode: remember the subscreen window handle for later
|
||||||
TDJ_SUBSCREEN_WINDOW = result;
|
TDJ_SUBSCREEN_WINDOW = result;
|
||||||
@@ -433,13 +464,19 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
graphics_hook_subscreen_window(SDVX_SUBSCREEN_WINDOW);
|
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;
|
GFDM_SUBSCREEN_WINDOW = result;
|
||||||
graphics_hook_subscreen_window(GFDM_SUBSCREEN_WINDOW);
|
graphics_hook_subscreen_window(GFDM_SUBSCREEN_WINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_touch_indicators(result);
|
disable_touch_indicators(result);
|
||||||
log_misc("graphics", "CreateWindowExA returned {}", fmt::ptr(result));
|
log_misc(
|
||||||
|
"graphics",
|
||||||
|
"CreateWindowExA returned {}, {}",
|
||||||
|
fmt::ptr(result),
|
||||||
|
lpWindowName ? lpWindowName : "(null)");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,7 +508,8 @@ static HWND WINAPI CreateWindowExW_hook(DWORD dwExStyle, LPCWSTR lpClassName, LP
|
|||||||
}
|
}
|
||||||
|
|
||||||
// windowed mode adjustments
|
// windowed mode adjustments
|
||||||
if (GRAPHICS_WINDOWED) {
|
// check the width to filter out invisible system-created windows
|
||||||
|
if (GRAPHICS_WINDOWED && nWidth > 0) {
|
||||||
|
|
||||||
// change window style
|
// change window style
|
||||||
dwExStyle = 0;
|
dwExStyle = 0;
|
||||||
@@ -506,7 +544,12 @@ static HWND WINAPI CreateWindowExW_hook(DWORD dwExStyle, LPCWSTR lpClassName, LP
|
|||||||
hWndParent, hMenu, hInstance, lpParam);
|
hWndParent, hMenu, hInstance, lpParam);
|
||||||
GRAPHICS_WINDOWS.push_back(result);
|
GRAPHICS_WINDOWS.push_back(result);
|
||||||
|
|
||||||
log_misc("graphics", "CreateWindowExW returned {}", fmt::ptr(result));
|
log_misc(
|
||||||
|
"graphics",
|
||||||
|
"CreateWindowExW returned {}, {}",
|
||||||
|
fmt::ptr(result),
|
||||||
|
lpWindowName ? ws2s(lpWindowName) : "(null)");
|
||||||
|
|
||||||
disable_touch_indicators(result);
|
disable_touch_indicators(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -673,7 +716,7 @@ static BOOL WINAPI SetWindowPos_hook(HWND hWnd, HWND hWndInsertAfter,
|
|||||||
|
|
||||||
// prevent gitadora arena model from shifting windows around if the user has preferences
|
// prevent gitadora arena model from shifting windows around if the user has preferences
|
||||||
if (GRAPHICS_WINDOWED && games::gitadora::is_arena_model() &&
|
if (GRAPHICS_WINDOWED && games::gitadora::is_arena_model() &&
|
||||||
GRAPHICS_WINDOW_MAIN.has_value() && hWnd == GRAPHICS_WINDOW_MAIN.value() &&
|
GRAPHICS_HOOKED_WINDOW.has_value() && hWnd == GRAPHICS_HOOKED_WINDOW.value() &&
|
||||||
cfg::SCREENRESIZE->enable_window_resize) {
|
cfg::SCREENRESIZE->enable_window_resize) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -682,6 +725,18 @@ static BOOL WINAPI SetWindowPos_hook(HWND hWnd, HWND hWndInsertAfter,
|
|||||||
return SetWindowPos_orig(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
|
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_HOOKED_WINDOW) {
|
||||||
|
log_info("graphics", "ShowWindow_hook - hiding sub window {}", fmt::ptr(hWnd));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call original
|
||||||
|
return ShowWindow_orig(hWnd, nCmdShow);
|
||||||
|
}
|
||||||
|
|
||||||
static ATOM WINAPI RegisterClassA_hook(const WNDCLASSA *lpWndClass) {
|
static ATOM WINAPI RegisterClassA_hook(const WNDCLASSA *lpWndClass) {
|
||||||
|
|
||||||
// check for null
|
// check for null
|
||||||
@@ -824,6 +879,7 @@ void graphics_init() {
|
|||||||
SetWindowLongA_orig = detour::iat_try("SetWindowLongA", SetWindowLongA_hook);
|
SetWindowLongA_orig = detour::iat_try("SetWindowLongA", SetWindowLongA_hook);
|
||||||
SetWindowLongW_orig = detour::iat_try("SetWindowLongW", SetWindowLongW_hook);
|
SetWindowLongW_orig = detour::iat_try("SetWindowLongW", SetWindowLongW_hook);
|
||||||
SetWindowPos_orig = detour::iat_try("SetWindowPos", SetWindowPos_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("MessageBoxA", MessageBoxA_hook);
|
||||||
detour::iat_try("MessageBoxExA", MessageBoxExA_hook);
|
detour::iat_try("MessageBoxExA", MessageBoxExA_hook);
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ extern bool GRAPHICS_SHOW_CURSOR;
|
|||||||
extern bool GRAPHICS_WINDOWED;
|
extern bool GRAPHICS_WINDOWED;
|
||||||
extern graphics_orientation GRAPHICS_ADJUST_ORIENTATION;
|
extern graphics_orientation GRAPHICS_ADJUST_ORIENTATION;
|
||||||
extern std::vector<HWND> GRAPHICS_WINDOWS;
|
extern std::vector<HWND> GRAPHICS_WINDOWS;
|
||||||
extern std::optional<HWND> GRAPHICS_WINDOW_MAIN;
|
|
||||||
extern UINT GRAPHICS_FORCE_REFRESH;
|
extern UINT GRAPHICS_FORCE_REFRESH;
|
||||||
extern std::optional<uint32_t> GRAPHICS_FORCE_REFRESH_SUB;
|
extern std::optional<uint32_t> GRAPHICS_FORCE_REFRESH_SUB;
|
||||||
extern std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
extern std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
||||||
@@ -50,6 +49,7 @@ extern std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_WINDOW_SIZE;
|
|||||||
extern std::optional<std::string> GRAPHICS_WINDOW_POS;
|
extern std::optional<std::string> GRAPHICS_WINDOW_POS;
|
||||||
extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
|
extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
|
||||||
extern bool GRAPHICS_WINDOW_BACKBUFFER_SCALE;
|
extern bool GRAPHICS_WINDOW_BACKBUFFER_SCALE;
|
||||||
|
extern std::optional<HWND> GRAPHICS_HOOKED_WINDOW;
|
||||||
|
|
||||||
extern bool GRAPHICS_IIDX_WSUB;
|
extern bool GRAPHICS_IIDX_WSUB;
|
||||||
extern std::optional<std::string> GRAPHICS_WSUB_SIZE;
|
extern std::optional<std::string> GRAPHICS_WSUB_SIZE;
|
||||||
@@ -101,5 +101,8 @@ void graphics_capture_initial_window(HWND hWnd);
|
|||||||
void graphics_update_window_style(HWND hWnd);
|
void graphics_update_window_style(HWND hWnd);
|
||||||
void graphics_update_z_order(HWND hWnd, bool always_on_top);
|
void graphics_update_z_order(HWND hWnd, bool always_on_top);
|
||||||
void graphics_move_resize_window(HWND hWnd);
|
void graphics_move_resize_window(HWND hWnd);
|
||||||
bool graphics_window_change_crashes_game();
|
bool graphics_window_options_breaks_game();
|
||||||
|
bool graphics_window_decoration_change_crashes_game();
|
||||||
|
bool graphics_window_resize_breaks_game();
|
||||||
|
bool graphics_window_move_and_resize_breaks_game();
|
||||||
void graphics_load_windowed_subscreen_parameters();
|
void graphics_load_windowed_subscreen_parameters();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
|
#include "games/gitadora/gitadora.h"
|
||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
@@ -23,6 +24,7 @@ std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_WINDOW_SIZE;
|
|||||||
std::optional<std::string> GRAPHICS_WINDOW_POS;
|
std::optional<std::string> GRAPHICS_WINDOW_POS;
|
||||||
bool GRAPHICS_WINDOW_ALWAYS_ON_TOP = false;
|
bool GRAPHICS_WINDOW_ALWAYS_ON_TOP = false;
|
||||||
bool GRAPHICS_WINDOW_BACKBUFFER_SCALE = false;
|
bool GRAPHICS_WINDOW_BACKBUFFER_SCALE = false;
|
||||||
|
std::optional<HWND> GRAPHICS_HOOKED_WINDOW;
|
||||||
|
|
||||||
// IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed
|
// IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed
|
||||||
bool GRAPHICS_IIDX_WSUB = false;
|
bool GRAPHICS_IIDX_WSUB = false;
|
||||||
@@ -55,6 +57,8 @@ void graphics_capture_initial_window(HWND hWnd) {
|
|||||||
|
|
||||||
graphics_load_windowed_parameters();
|
graphics_load_windowed_parameters();
|
||||||
|
|
||||||
|
GRAPHICS_HOOKED_WINDOW = hWnd;
|
||||||
|
|
||||||
cfg::SCREENRESIZE->init_window_style = GetWindowLong(hWnd, GWL_STYLE);
|
cfg::SCREENRESIZE->init_window_style = GetWindowLong(hWnd, GWL_STYLE);
|
||||||
cfg::SCREENRESIZE->init_window_style_ex = GetWindowLong(hWnd, GWL_EXSTYLE);
|
cfg::SCREENRESIZE->init_window_style_ex = GetWindowLong(hWnd, GWL_EXSTYLE);
|
||||||
|
|
||||||
@@ -66,8 +70,9 @@ void graphics_capture_initial_window(HWND hWnd) {
|
|||||||
RECT rect;
|
RECT rect;
|
||||||
if (!GetClientRect(hWnd, &rect)) {
|
if (!GetClientRect(hWnd, &rect)) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"graphics",
|
"graphics-windowed",
|
||||||
"graphics_capture_initial_window - GetClientRect failed, GLE: {}",
|
"[{}] graphics_capture_initial_window - GetClientRect failed, GLE: {}",
|
||||||
|
fmt::ptr(hWnd),
|
||||||
GetLastError());
|
GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -79,12 +84,22 @@ void graphics_capture_initial_window(HWND hWnd) {
|
|||||||
cfg::SCREENRESIZE->init_client_aspect_ratio = (float)client_w / (float)client_h;
|
cfg::SCREENRESIZE->init_client_aspect_ratio = (float)client_w / (float)client_h;
|
||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
"graphics_capture_initial_window initial window size {}x{}, ratio {}",
|
"[{}] graphics_capture_initial_window initial window size {}x{}, ratio {}",
|
||||||
|
fmt::ptr(hWnd),
|
||||||
client_w, client_h, cfg::SCREENRESIZE->init_client_aspect_ratio);
|
client_w, client_h, cfg::SCREENRESIZE->init_client_aspect_ratio);
|
||||||
|
|
||||||
// ensure frame size is captured
|
// ensure frame size is captured
|
||||||
graphics_wm_style_changed(hWnd, false);
|
graphics_wm_style_changed(hWnd, false);
|
||||||
|
|
||||||
|
// if the game is not compatible, ignore user-supplied values and keep the current size
|
||||||
|
if (graphics_window_resize_breaks_game()) {
|
||||||
|
cfg::SCREENRESIZE->client_width = client_w;
|
||||||
|
cfg::SCREENRESIZE->client_height = client_h;
|
||||||
|
}
|
||||||
|
if (graphics_window_move_and_resize_breaks_game()) {
|
||||||
|
cfg::SCREENRESIZE->enable_window_resize = false;
|
||||||
|
}
|
||||||
|
|
||||||
// if there was no user-supplied dimension, seed it with the current size
|
// if there was no user-supplied dimension, seed it with the current size
|
||||||
// so that the next resize operation will work
|
// so that the next resize operation will work
|
||||||
if (cfg::SCREENRESIZE->client_width == 0) {
|
if (cfg::SCREENRESIZE->client_width == 0) {
|
||||||
@@ -98,7 +113,8 @@ void graphics_capture_initial_window(HWND hWnd) {
|
|||||||
// resize must be done before applying the border
|
// resize must be done before applying the border
|
||||||
if (cfg::SCREENRESIZE->enable_window_resize) {
|
if (cfg::SCREENRESIZE->enable_window_resize) {
|
||||||
log_info(
|
log_info(
|
||||||
"graphics-windowed", "change window rect - window offset: {}x{}, client size: {}x{}",
|
"graphics-windowed", "[{}] change window rect - window offset: {}x{}, client size: {}x{}",
|
||||||
|
fmt::ptr(hWnd),
|
||||||
cfg::SCREENRESIZE->window_offset_x,
|
cfg::SCREENRESIZE->window_offset_x,
|
||||||
cfg::SCREENRESIZE->window_offset_y,
|
cfg::SCREENRESIZE->window_offset_y,
|
||||||
cfg::SCREENRESIZE->client_width,
|
cfg::SCREENRESIZE->client_width,
|
||||||
@@ -108,12 +124,13 @@ void graphics_capture_initial_window(HWND hWnd) {
|
|||||||
// ddr hangs when window frame doesn't have overlapped
|
// ddr hangs when window frame doesn't have overlapped
|
||||||
if (cfg::SCREENRESIZE->window_decoration != cfg::WindowDecorationMode::Default) {
|
if (cfg::SCREENRESIZE->window_decoration != cfg::WindowDecorationMode::Default) {
|
||||||
log_info(
|
log_info(
|
||||||
"graphics-windowed", "change window style - decoration: {}",
|
"graphics-windowed", "[{}] change window style - decoration: {}",
|
||||||
|
fmt::ptr(hWnd),
|
||||||
cfg::SCREENRESIZE->window_decoration);
|
cfg::SCREENRESIZE->window_decoration);
|
||||||
graphics_update_window_style(hWnd);
|
graphics_update_window_style(hWnd);
|
||||||
}
|
}
|
||||||
if (cfg::SCREENRESIZE->window_always_on_top) {
|
if (cfg::SCREENRESIZE->window_always_on_top) {
|
||||||
log_info("graphics-windowed", "change window z-order - always on top");
|
log_info("graphics-windowed", "[{}] change window z-order - always on top", fmt::ptr(hWnd));
|
||||||
graphics_update_z_order(hWnd, true);
|
graphics_update_z_order(hWnd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +389,7 @@ void graphics_update_window_style(HWND hWnd) {
|
|||||||
if (!GRAPHICS_WINDOWED) {
|
if (!GRAPHICS_WINDOWED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (graphics_window_change_crashes_game()) {
|
if (graphics_window_decoration_change_crashes_game()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,6 +409,9 @@ void graphics_update_window_style(HWND hWnd) {
|
|||||||
break;
|
break;
|
||||||
case cfg::WindowDecorationMode::ResizableFrame:
|
case cfg::WindowDecorationMode::ResizableFrame:
|
||||||
style |= WS_OVERLAPPEDWINDOW;
|
style |= WS_OVERLAPPEDWINDOW;
|
||||||
|
if (graphics_window_resize_breaks_game()) {
|
||||||
|
style &= ~WS_SIZEBOX;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case cfg::WindowDecorationMode::Default:
|
case cfg::WindowDecorationMode::Default:
|
||||||
default:
|
default:
|
||||||
@@ -479,12 +499,19 @@ void graphics_move_resize_window(HWND hWnd) {
|
|||||||
log_debug("graphics-windowed", "graphics_move_resize_window returned");
|
log_debug("graphics-windowed", "graphics_move_resize_window returned");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool graphics_window_change_crashes_game() {
|
bool graphics_window_decoration_change_crashes_game() {
|
||||||
static std::once_flag flag;
|
static std::once_flag flag;
|
||||||
static bool result = false;
|
static bool result = false;
|
||||||
std::call_once(flag, []() {
|
std::call_once(flag, []() {
|
||||||
// ddr crashes when frame style changes
|
// ddr crashes when frame style changes
|
||||||
result = avs::game::is_model("MDX");
|
result = avs::game::is_model("MDX");
|
||||||
|
|
||||||
|
// changing window decoration also changes dimensions and position
|
||||||
|
// so this must be prevented
|
||||||
|
if (graphics_window_move_and_resize_breaks_game()) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
@@ -493,3 +520,43 @@ bool graphics_window_change_crashes_game() {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool graphics_window_move_and_resize_breaks_game() {
|
||||||
|
static std::once_flag flag;
|
||||||
|
static bool result = false;
|
||||||
|
|
||||||
|
std::call_once(flag, []() {
|
||||||
|
// games like reflec beat in use spice touch overlay for windowed mode
|
||||||
|
// and mouse input breaks if window is moved as the overlay does not
|
||||||
|
// currently support window moves/resizes
|
||||||
|
result = avs::game::is_model({"KBR", "LBR", "MBR"});
|
||||||
|
if (result) {
|
||||||
|
log_warning(
|
||||||
|
"graphics-windowed",
|
||||||
|
"ignoring changes to window properties due to incompatibility with this game");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool graphics_window_resize_breaks_game() {
|
||||||
|
// for whatever reason, gitadora games on dx/sd/sd2 cabs behave poorly when window is resized
|
||||||
|
// (eihter at launch or while it's running)
|
||||||
|
// usually results in: soft lock during scene transtions or really long transitions,
|
||||||
|
// backgrounds of menus not rendering, etc.
|
||||||
|
bool is_gitadora = avs::game::is_model({ "J32", "J33", "K32", "K33", "L32", "L33", "M32" });
|
||||||
|
bool is_arena = games::gitadora::is_arena_model();
|
||||||
|
|
||||||
|
bool result = graphics_window_move_and_resize_breaks_game() || (is_gitadora && !is_arena);
|
||||||
|
|
||||||
|
static std::once_flag flag;
|
||||||
|
std::call_once(flag, [&result]() {
|
||||||
|
if (result) {
|
||||||
|
log_warning(
|
||||||
|
"graphics-windowed",
|
||||||
|
"ignoring changes to window size due to incompatibility with this game");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -589,9 +589,25 @@ 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) {
|
||||||
|
games::gitadora::ARENA_SINGLE_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();
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::GitaDoraPickAlgo].is_active()) {
|
||||||
|
const auto text = options[launcher::Options::GitaDoraPickAlgo].value_text();
|
||||||
|
if (text == "legacy") {
|
||||||
|
games::gitadora::PICK_ALGO.reset();
|
||||||
|
} else if (text == "neutral") {
|
||||||
|
games::gitadora::PICK_ALGO = socd::SocdAlgorithm::Neutral;
|
||||||
|
} else if (text == "raw") {
|
||||||
|
games::gitadora::PICK_ALGO = socd::SocdAlgorithm::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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()) {
|
if (options[launcher::Options::LoadNostalgiaModule].value_bool()) {
|
||||||
attach_nostalgia = true;
|
attach_nostalgia = true;
|
||||||
}
|
}
|
||||||
@@ -1112,6 +1128,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::spice2x_DRSTransposeTouch].value_bool()) {
|
if (options[launcher::Options::spice2x_DRSTransposeTouch].value_bool()) {
|
||||||
games::drs::TRANSPOSE_TOUCH = true;
|
games::drs::TRANSPOSE_TOUCH = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::DRSRGBCameraHook].value_bool()) {
|
||||||
|
games::drs::RGB_CAMERA_HOOK = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::spice2x_AutoCard].is_active()) {
|
if (options[launcher::Options::spice2x_AutoCard].is_active()) {
|
||||||
const auto text = options[launcher::Options::spice2x_AutoCard].value_text();
|
const auto text = options[launcher::Options::spice2x_AutoCard].value_text();
|
||||||
if (text == "p1") {
|
if (text == "p1") {
|
||||||
@@ -1887,7 +1906,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
"This usually means one of the following:\n\n"
|
"This usually means one of the following:\n\n"
|
||||||
" 1. You put spice executables in the wrong place, or\n"
|
" 1. You put spice executables in the wrong place, or\n"
|
||||||
" 2. XML files in prop directory are malformed or missing, or\n"
|
" 2. XML files in prop directory are malformed or missing, or\n"
|
||||||
" 3. You passed in invalid options (usually, path overrides like -exec)\n\n"
|
" 3. You passed in invalid options (do not specify -exec or -modules if you don't know what you're doing)\n\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
log_fatal("launcher", "module auto detection failed, see log.txt for troubleshooting");
|
log_fatal("launcher", "module auto detection failed, see log.txt for troubleshooting");
|
||||||
|
|||||||
+276
-223
File diff suppressed because it is too large
Load Diff
@@ -100,8 +100,11 @@ namespace launcher {
|
|||||||
LoadGitaDoraModule,
|
LoadGitaDoraModule,
|
||||||
GitaDoraTwoChannelAudio,
|
GitaDoraTwoChannelAudio,
|
||||||
GitaDoraCabinetType,
|
GitaDoraCabinetType,
|
||||||
|
GitaDoraArenaSingleWindow,
|
||||||
GitaDoraLefty,
|
GitaDoraLefty,
|
||||||
GitaDoraWailHold,
|
GitaDoraWailHold,
|
||||||
|
GitaDoraPickAlgo,
|
||||||
|
GitaDoraSubOverlaySize,
|
||||||
LoadJubeatModule,
|
LoadJubeatModule,
|
||||||
LoadReflecBeatModule,
|
LoadReflecBeatModule,
|
||||||
LoadShogikaiModule,
|
LoadShogikaiModule,
|
||||||
@@ -234,6 +237,7 @@ namespace launcher {
|
|||||||
spice2x_IIDXWindowedTDJ,
|
spice2x_IIDXWindowedTDJ,
|
||||||
spice2x_DRSDisableTouch,
|
spice2x_DRSDisableTouch,
|
||||||
spice2x_DRSTransposeTouch,
|
spice2x_DRSTransposeTouch,
|
||||||
|
DRSRGBCameraHook,
|
||||||
spice2x_IIDXNativeTouch,
|
spice2x_IIDXNativeTouch,
|
||||||
spice2x_IIDXNoSub,
|
spice2x_IIDXNoSub,
|
||||||
spice2x_IIDXEmulateSubscreenKeypadTouch,
|
spice2x_IIDXEmulateSubscreenKeypadTouch,
|
||||||
|
|||||||
+32
-14
@@ -522,24 +522,42 @@ static long __cdecl gfdm_unit_get_input_p(int device, size_t player) {
|
|||||||
if (games::gitadora::is_guitar()) {
|
if (games::gitadora::is_guitar()) {
|
||||||
auto offset = player * 11;
|
auto offset = player * 11;
|
||||||
|
|
||||||
// pick up
|
const auto pick_up = Buttons::getState(RI_MGR, buttons.at(gitadora_button_mapping[3 + offset]));
|
||||||
if (Buttons::getState(RI_MGR, buttons.at(gitadora_button_mapping[3 + offset]))) {
|
const auto pick_down = Buttons::getState(RI_MGR, buttons.at(gitadora_button_mapping[4 + offset]));
|
||||||
if (!GFDM_GF_PICK_STATE_UP[player]) {
|
if (!games::gitadora::PICK_ALGO.has_value()) {
|
||||||
GFDM_GF_PICK_STATE_UP[player] = true;
|
// legacy behavior (detect rising edges only, input for 1 frame)
|
||||||
ret |= 0x80 | 0x20;
|
if (pick_up) {
|
||||||
|
if (!GFDM_GF_PICK_STATE_UP[player]) {
|
||||||
|
GFDM_GF_PICK_STATE_UP[player] = true;
|
||||||
|
ret |= 0x80 | 0x20;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GFDM_GF_PICK_STATE_UP[player] = false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
GFDM_GF_PICK_STATE_UP[player] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pick down
|
if (pick_down) {
|
||||||
if (Buttons::getState(RI_MGR, buttons.at(gitadora_button_mapping[4 + offset]))) {
|
if (!GFDM_GF_PICK_STATE_DOWN[player]) {
|
||||||
if (!GFDM_GF_PICK_STATE_DOWN[player]) {
|
GFDM_GF_PICK_STATE_DOWN[player] = true;
|
||||||
GFDM_GF_PICK_STATE_DOWN[player] = true;
|
ret |= 0x100 | 0x20;
|
||||||
ret |= 0x100 | 0x20;
|
}
|
||||||
|
} else {
|
||||||
|
GFDM_GF_PICK_STATE_DOWN[player] = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GFDM_GF_PICK_STATE_DOWN[player] = false;
|
const auto socd = socd::socd_clean(
|
||||||
|
player,
|
||||||
|
pick_up,
|
||||||
|
pick_down,
|
||||||
|
get_performance_milliseconds(),
|
||||||
|
games::gitadora::PICK_ALGO.value()
|
||||||
|
);
|
||||||
|
if (socd == socd::SocdCCW) {
|
||||||
|
ret |= 0x80 | 0x20; // pick up
|
||||||
|
} else if (socd == socd::SocdCW) {
|
||||||
|
ret |= 0x100 | 0x20; // pick down
|
||||||
|
} else if (socd == socd::SocdBoth) {
|
||||||
|
ret |= 0x100 | 0x80 | 0x20; // up and down
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// button R
|
// button R
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
|
#include "games/gitadora/gitadora.h"
|
||||||
#include "games/iidx/iidx.h"
|
#include "games/iidx/iidx.h"
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
@@ -390,7 +391,10 @@ namespace wintouchemu {
|
|||||||
} else if (avs::game::is_model("LDJ") && !GENERIC_SUB_WINDOW_FULLSIZE) {
|
} else if (avs::game::is_model("LDJ") && !GENERIC_SUB_WINDOW_FULLSIZE) {
|
||||||
// overlay subscreen in IIDX
|
// overlay subscreen in IIDX
|
||||||
// use mouse position as ImGui overlay will block the touch window
|
// 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;
|
USE_MOUSE = true;
|
||||||
} else {
|
} else {
|
||||||
// create touch window - create overlay if not yet existing at this point
|
// create touch window - create overlay if not yet existing at this point
|
||||||
|
|||||||
@@ -236,6 +236,26 @@ namespace nvapi {
|
|||||||
return NvAPI_DRS_SetSetting(h_session, h_profile, &drs_setting);
|
return NvAPI_DRS_SetSetting(h_session, h_profile, &drs_setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NvAPI_Status set_refresh_rate(NvDRSSessionHandle h_session, NvDRSProfileHandle h_profile) {
|
||||||
|
auto drs_setting = NVDRS_SETTING {};
|
||||||
|
drs_setting.version = NVDRS_SETTING_VER;
|
||||||
|
drs_setting.settingId = REFRESH_RATE_OVERRIDE_ID;
|
||||||
|
drs_setting.settingType = NVDRS_DWORD_TYPE;
|
||||||
|
drs_setting.u32PredefinedValue = REFRESH_RATE_OVERRIDE_APPLICATION_CONTROLLED;
|
||||||
|
drs_setting.u32CurrentValue = REFRESH_RATE_OVERRIDE_APPLICATION_CONTROLLED;
|
||||||
|
return NvAPI_DRS_SetSetting(h_session, h_profile, &drs_setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
NvAPI_Status set_max_fps(NvDRSSessionHandle h_session, NvDRSProfileHandle h_profile) {
|
||||||
|
auto drs_setting = NVDRS_SETTING {};
|
||||||
|
drs_setting.version = NVDRS_SETTING_VER;
|
||||||
|
drs_setting.settingId = FRL_FPS_ID;
|
||||||
|
drs_setting.settingType = NVDRS_DWORD_TYPE;
|
||||||
|
drs_setting.u32PredefinedValue = FRL_FPS_DISABLED;
|
||||||
|
drs_setting.u32CurrentValue = FRL_FPS_DISABLED;
|
||||||
|
return NvAPI_DRS_SetSetting(h_session, h_profile, &drs_setting);
|
||||||
|
}
|
||||||
|
|
||||||
void set_profile_settings() {
|
void set_profile_settings() {
|
||||||
if (!NVAPI_MODULE_LOAD_SUCCEEDED) {
|
if (!NVAPI_MODULE_LOAD_SUCCEEDED) {
|
||||||
return;
|
return;
|
||||||
@@ -266,22 +286,26 @@ namespace nvapi {
|
|||||||
log_info("nvapi", "setting VSync to Application Controlled...");
|
log_info("nvapi", "setting VSync to Application Controlled...");
|
||||||
if ((status = set_vsync_mode(h_session, h_profile)) != NVAPI_OK) {
|
if ((status = set_vsync_mode(h_session, h_profile)) != NVAPI_OK) {
|
||||||
log_warning("nvapi", "could not set VSync mode: {}", get_error_message(status));
|
log_warning("nvapi", "could not set VSync mode: {}", get_error_message(status));
|
||||||
NvAPI_DRS_DestroySession(h_session);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("nvapi", "applying preferred PState to Maximum Performance...");
|
log_info("nvapi", "applying preferred PState to Maximum Performance...");
|
||||||
if ((status = set_gpu_power_state(h_session, h_profile)) != NVAPI_OK) {
|
if ((status = set_gpu_power_state(h_session, h_profile)) != NVAPI_OK) {
|
||||||
log_warning("nvapi", "could not set preferred PState: {}", get_error_message(status));
|
log_warning("nvapi", "could not set preferred PState: {}", get_error_message(status));
|
||||||
NvAPI_DRS_DestroySession(h_session);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("nvapi", "disabling G-SYNC...");
|
log_info("nvapi", "disabling G-SYNC...");
|
||||||
if ((status = set_gsync_mode(h_session, h_profile)) != NVAPI_OK) {
|
if ((status = set_gsync_mode(h_session, h_profile)) != NVAPI_OK) {
|
||||||
log_warning("nvapi", "could not set G-Sync mode: {}", get_error_message(status));
|
log_warning("nvapi", "could not set G-Sync mode: {}", get_error_message(status));
|
||||||
NvAPI_DRS_DestroySession(h_session);
|
}
|
||||||
return;
|
|
||||||
|
log_info("nvapi", "setting preferred refresh rate to Application Controlled...");
|
||||||
|
if ((status = set_refresh_rate(h_session, h_profile)) != NVAPI_OK) {
|
||||||
|
log_warning("nvapi", "could not set preferred refresh rate: {}", get_error_message(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("nvapi", "disabling max framerate...");
|
||||||
|
if ((status = set_max_fps(h_session, h_profile)) != NVAPI_OK) {
|
||||||
|
log_warning("nvapi", "could not disable max framerate: {}", get_error_message(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("nvapi", "saving settings for DRS session...");
|
log_info("nvapi", "saving settings for DRS session...");
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "windows/generic_sub.h"
|
#include "windows/generic_sub.h"
|
||||||
#include "windows/iidx_seg.h"
|
#include "windows/iidx_seg.h"
|
||||||
#include "windows/iidx_sub.h"
|
#include "windows/iidx_sub.h"
|
||||||
|
#include "windows/gfdm_sub.h"
|
||||||
#include "windows/drs_dancefloor.h"
|
#include "windows/drs_dancefloor.h"
|
||||||
#include "windows/iopanel.h"
|
#include "windows/iopanel.h"
|
||||||
#include "windows/iopanel_ddr.h"
|
#include "windows/iopanel_ddr.h"
|
||||||
@@ -410,7 +411,10 @@ 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) {
|
||||||
|
window_sub = new overlay::windows::GitaDoraSubScreen(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window_sub) {
|
if (window_sub) {
|
||||||
this->window_add(window_sub);
|
this->window_add(window_sub);
|
||||||
if (AUTO_SHOW_SUBSCREEN) {
|
if (AUTO_SHOW_SUBSCREEN) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "games/iidx/iidx.h"
|
#include "games/iidx/iidx.h"
|
||||||
|
#include "games/gitadora/gitadora.h"
|
||||||
|
|
||||||
namespace overlay::windows {
|
namespace overlay::windows {
|
||||||
|
|
||||||
@@ -69,6 +70,8 @@ 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) {
|
||||||
|
sub = "Show GITADORA Subscreen";
|
||||||
}
|
}
|
||||||
|
|
||||||
build_button(this->overlay->window_sub, sub, size, NextItem::NEW_LINE, false);
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -930,6 +930,13 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// match on model and ext, ignoring dest/spec/rev
|
||||||
|
// sample: LDJ:J:E:A:2025011400
|
||||||
|
bool PatchManager::is_game_id_wildcard_matched(const std::string& id_from_config) {
|
||||||
|
return ((id_from_config.compare(0, 3, avs::game::MODEL) == 0) &&
|
||||||
|
(id_from_config.compare(10, 10, avs::game::EXT) == 0));
|
||||||
|
}
|
||||||
|
|
||||||
void PatchManager::config_load() {
|
void PatchManager::config_load() {
|
||||||
log_info("patchmanager", "loading config");
|
log_info("patchmanager", "loading config");
|
||||||
|
|
||||||
@@ -955,7 +962,7 @@ namespace overlay::windows {
|
|||||||
if (auto_apply != doc.MemberEnd() && auto_apply->value.IsArray()) {
|
if (auto_apply != doc.MemberEnd() && auto_apply->value.IsArray()) {
|
||||||
|
|
||||||
// get game id
|
// get game id
|
||||||
auto game_id = avs::game::get_identifier();
|
const auto game_id = avs::game::get_identifier();
|
||||||
|
|
||||||
// iterate entries
|
// iterate entries
|
||||||
setting_auto_apply = false;
|
setting_auto_apply = false;
|
||||||
@@ -964,15 +971,37 @@ namespace overlay::windows {
|
|||||||
if (entry.IsString()) {
|
if (entry.IsString()) {
|
||||||
|
|
||||||
// check if this is our game identifier
|
// check if this is our game identifier
|
||||||
std::string entry_id = entry.GetString();
|
const std::string entry_id = entry.GetString();
|
||||||
if (game_id == entry_id) {
|
|
||||||
setting_auto_apply = true;
|
if (!setting_auto_apply) {
|
||||||
|
if (game_id == entry_id) {
|
||||||
|
// exact match
|
||||||
|
setting_auto_apply = true;
|
||||||
|
log_misc(
|
||||||
|
"patchmanager",
|
||||||
|
"matched auto apply entry by full game identifier: {}",
|
||||||
|
entry_id);
|
||||||
|
|
||||||
|
} else if (is_game_id_wildcard_matched(entry_id)) {
|
||||||
|
// match on model and ext, ignoring dest/spec/rev
|
||||||
|
// sample: LDJ:J:E:A:2025011400
|
||||||
|
setting_auto_apply = true;
|
||||||
|
log_misc(
|
||||||
|
"patchmanager",
|
||||||
|
"matched auto apply entry by partial game identifier: {}:?:?:?:{}",
|
||||||
|
avs::game::MODEL, avs::game::EXT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// move to list
|
// move to list
|
||||||
setting_auto_apply_list.emplace_back(entry_id);
|
setting_auto_apply_list.emplace_back(entry_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!setting_auto_apply) {
|
||||||
|
log_misc(
|
||||||
|
"patchmanager",
|
||||||
|
"no auto apply entry matched, patches will not load automatically");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read enabled patches
|
// read enabled patches
|
||||||
@@ -1060,7 +1089,7 @@ namespace overlay::windows {
|
|||||||
auto game_id = avs::game::get_identifier();
|
auto game_id = avs::game::get_identifier();
|
||||||
bool game_id_added = false;
|
bool game_id_added = false;
|
||||||
for (auto &entry : setting_auto_apply_list) {
|
for (auto &entry : setting_auto_apply_list) {
|
||||||
if (entry == game_id) {
|
if (entry == game_id || is_game_id_wildcard_matched(entry)) {
|
||||||
if (!setting_auto_apply) {
|
if (!setting_auto_apply) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ namespace overlay::windows {
|
|||||||
std::string pe_identifier_for_patch = "");
|
std::string pe_identifier_for_patch = "");
|
||||||
|
|
||||||
void show_patch_tooltip(const PatchData& patch);
|
void show_patch_tooltip(const PatchData& patch);
|
||||||
|
|
||||||
|
bool is_game_id_wildcard_matched(const std::string& id_from_config);
|
||||||
};
|
};
|
||||||
|
|
||||||
PatchStatus is_patch_active(PatchData &patch);
|
PatchStatus is_patch_active(PatchData &patch);
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HWND ScreenResize::get_first_window() {
|
HWND ScreenResize::get_first_window() {
|
||||||
// hack for gitadora arena model which races to create many windows
|
// this is ideal
|
||||||
// so [0] is not always the main one
|
if (GRAPHICS_HOOKED_WINDOW.has_value()) {
|
||||||
if (GRAPHICS_WINDOW_MAIN.has_value()) {
|
return GRAPHICS_HOOKED_WINDOW.value();
|
||||||
return GRAPHICS_WINDOW_MAIN.value();
|
|
||||||
}
|
}
|
||||||
|
// we typically do not want to check GRAPHICS_WINDOWS because it may include
|
||||||
|
// system windows (e.g., CicMarshalWnd)
|
||||||
if (GRAPHICS_WINDOWS.size() == 0) {
|
if (GRAPHICS_WINDOWS.size() == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -201,7 +202,7 @@ namespace overlay::windows {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::BeginDisabled(graphics_window_change_crashes_game());
|
ImGui::BeginDisabled(graphics_window_decoration_change_crashes_game());
|
||||||
if (ImGui::Combo(
|
if (ImGui::Combo(
|
||||||
"Window Style",
|
"Window Style",
|
||||||
&cfg::SCREENRESIZE->window_decoration,
|
&cfg::SCREENRESIZE->window_decoration,
|
||||||
@@ -226,42 +227,59 @@ namespace overlay::windows {
|
|||||||
"Reduces pixelated scaling artifacts. Works great on some games, but completely broken on others.\n\n"
|
"Reduces pixelated scaling artifacts. Works great on some games, but completely broken on others.\n\n"
|
||||||
"This can't be changed in-game; instead, set -windowscale option in spicecfg and restart.");
|
"This can't be changed in-game; instead, set -windowscale option in spicecfg and restart.");
|
||||||
|
|
||||||
ImGui::Checkbox("Keep Aspect Ratio", &cfg::SCREENRESIZE->client_keep_aspect_ratio);
|
|
||||||
ImGui::Checkbox("Manual window move/resize", &cfg::SCREENRESIZE->enable_window_resize);
|
ImGui::BeginDisabled(graphics_window_move_and_resize_breaks_game());
|
||||||
|
{
|
||||||
|
ImGui::Checkbox("Keep Aspect Ratio", &cfg::SCREENRESIZE->client_keep_aspect_ratio);
|
||||||
|
ImGui::Checkbox("Manual window move/resize", &cfg::SCREENRESIZE->enable_window_resize);
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
ImGui::BeginDisabled(!cfg::SCREENRESIZE->enable_window_resize);
|
ImGui::BeginDisabled(!cfg::SCREENRESIZE->enable_window_resize);
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
const uint32_t step = 1;
|
const uint32_t step = 1;
|
||||||
const uint32_t step_fast = 10;
|
const uint32_t step_fast = 10;
|
||||||
ImGui::BeginDisabled(cfg::SCREENRESIZE->client_keep_aspect_ratio);
|
|
||||||
ImGui::InputScalar(
|
ImGui::BeginDisabled(graphics_window_resize_breaks_game());
|
||||||
"Width",
|
{
|
||||||
ImGuiDataType_U32,
|
ImGui::BeginDisabled(cfg::SCREENRESIZE->client_keep_aspect_ratio);
|
||||||
&cfg::SCREENRESIZE->client_width,
|
{
|
||||||
&step, &step_fast, nullptr);
|
ImGui::InputScalar(
|
||||||
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
"Width",
|
||||||
|
ImGuiDataType_U32,
|
||||||
|
&cfg::SCREENRESIZE->client_width,
|
||||||
|
&step, &step_fast, nullptr);
|
||||||
|
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::InputScalar(
|
||||||
|
"Height",
|
||||||
|
ImGuiDataType_U32,
|
||||||
|
&cfg::SCREENRESIZE->client_height,
|
||||||
|
&step, &step_fast, nullptr);
|
||||||
|
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
||||||
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
ImGui::InputScalar(
|
ImGui::BeginDisabled(graphics_window_move_and_resize_breaks_game());
|
||||||
"Height",
|
{
|
||||||
ImGuiDataType_U32,
|
ImGui::InputScalar(
|
||||||
&cfg::SCREENRESIZE->client_height,
|
"X Offset",
|
||||||
&step, &step_fast, nullptr);
|
ImGuiDataType_S32,
|
||||||
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
&cfg::SCREENRESIZE->window_offset_x,
|
||||||
|
&step, &step_fast, nullptr);
|
||||||
|
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
||||||
|
|
||||||
ImGui::InputScalar(
|
ImGui::InputScalar(
|
||||||
"X Offset",
|
"Y Offset",
|
||||||
ImGuiDataType_S32,
|
ImGuiDataType_S32,
|
||||||
&cfg::SCREENRESIZE->window_offset_x,
|
&cfg::SCREENRESIZE->window_offset_y,
|
||||||
&step, &step_fast, nullptr);
|
&step, &step_fast, nullptr);
|
||||||
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
||||||
|
}
|
||||||
ImGui::InputScalar(
|
ImGui::EndDisabled();
|
||||||
"Y Offset",
|
|
||||||
ImGuiDataType_S32,
|
|
||||||
&cfg::SCREENRESIZE->window_offset_y,
|
|
||||||
&step, &step_fast, nullptr);
|
|
||||||
changed |= ImGui::IsItemDeactivatedAfterEdit();
|
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
|
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
|
||||||
|
|||||||
@@ -15,18 +15,23 @@ namespace socd {
|
|||||||
|
|
||||||
SocdAlgorithm ALGORITHM = SocdAlgorithm::Neutral;
|
SocdAlgorithm ALGORITHM = SocdAlgorithm::Neutral;
|
||||||
|
|
||||||
static double last_rising_edge[2][2] = {};
|
static double last_rising_edge[4][2] = {};
|
||||||
static bool last_button_state[2][2] = {};
|
static bool last_button_state[4][2] = {};
|
||||||
|
|
||||||
// this has no locking, use only if you know there is only one i/o thread that will call this
|
// this has no locking, use only if you know there is only one i/o thread that will call this
|
||||||
SocdResult socd_clean(uint8_t device, bool ccw, bool cw, double time_now) {
|
SocdResult socd_clean(
|
||||||
if (device >= 2) {
|
uint8_t device, bool ccw, bool cw, double time_now,
|
||||||
|
std::optional<SocdAlgorithm> algorithm_override) {
|
||||||
|
|
||||||
|
if (device >= 4) {
|
||||||
log_fatal("socd", "invalid device index in socd_clean: {}", device);
|
log_fatal("socd", "invalid device index in socd_clean: {}", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOCD last input algorithm needs to keep track of rising edge times
|
SocdAlgorithm algo =
|
||||||
if (ALGORITHM != SocdAlgorithm::Neutral) {
|
algorithm_override.has_value() ? algorithm_override.value() : ALGORITHM;
|
||||||
// detect rising edges
|
|
||||||
|
// keep track of rising edge times
|
||||||
|
if (algo == SocdAlgorithm::PreferRecent || algo == SocdAlgorithm::PreferFirst) {
|
||||||
if (!last_button_state[device][SocdCCW] && ccw) {
|
if (!last_button_state[device][SocdCCW] && ccw) {
|
||||||
last_rising_edge[device][SocdCCW] = time_now;
|
last_rising_edge[device][SocdCCW] = time_now;
|
||||||
}
|
}
|
||||||
@@ -55,7 +60,7 @@ namespace socd {
|
|||||||
const auto cw_time = last_rising_edge[device][SocdCW];
|
const auto cw_time = last_rising_edge[device][SocdCW];
|
||||||
log_debug("socd", "ccw={}, cw ={}", ccw_time, cw_time);
|
log_debug("socd", "ccw={}, cw ={}", ccw_time, cw_time);
|
||||||
|
|
||||||
if (ALGORITHM == SocdAlgorithm::PreferRecent) {
|
if (algo == SocdAlgorithm::PreferRecent) {
|
||||||
// SOCD: prefer last input
|
// SOCD: prefer last input
|
||||||
if (ccw_time < cw_time) {
|
if (ccw_time < cw_time) {
|
||||||
// while CCW is being held, CW got pressed
|
// while CCW is being held, CW got pressed
|
||||||
@@ -67,7 +72,7 @@ namespace socd {
|
|||||||
// it's a tie; instead of none, we'll pick a direction
|
// it's a tie; instead of none, we'll pick a direction
|
||||||
return SocdCW;
|
return SocdCW;
|
||||||
}
|
}
|
||||||
} else if (ALGORITHM == SocdAlgorithm::PreferFirst) {
|
} else if (algo == SocdAlgorithm::PreferFirst) {
|
||||||
// SOCD: keep first input
|
// SOCD: keep first input
|
||||||
if (ccw_time < cw_time) {
|
if (ccw_time < cw_time) {
|
||||||
// while CCW is being held, CW got pressed
|
// while CCW is being held, CW got pressed
|
||||||
@@ -79,9 +84,15 @@ namespace socd {
|
|||||||
// it's a tie; instead of none, we'll pick a direction
|
// it's a tie; instead of none, we'll pick a direction
|
||||||
return SocdCW;
|
return SocdCW;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (algo == SocdAlgorithm::Neutral) {
|
||||||
// SOCD: neutral when both are pressed
|
// SOCD: neutral when both are pressed
|
||||||
return SocdNone;
|
return SocdNone;
|
||||||
|
} else if (algo == SocdAlgorithm::None) {
|
||||||
|
// SOCD: both are pressed
|
||||||
|
return SocdBoth;
|
||||||
|
} else {
|
||||||
|
log_fatal("socd", "invalid SOCD algorithm");
|
||||||
|
return SocdNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +108,8 @@ namespace socd {
|
|||||||
log_fatal("socd", "invalid device index in socd_clean: {}", device);
|
log_fatal("socd", "invalid device index in socd_clean: {}", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto socd_result = socd_clean(device, up, down, time_now);
|
const auto socd_result = socd_clean(
|
||||||
|
device + 2, up, down, time_now, SocdAlgorithm::PreferRecent);
|
||||||
|
|
||||||
if (up) {
|
if (up) {
|
||||||
most_recent_active[device][TiltUp] = time_now;
|
most_recent_active[device][TiltUp] = time_now;
|
||||||
@@ -125,7 +137,7 @@ namespace socd {
|
|||||||
result = TiltUp;
|
result = TiltUp;
|
||||||
} else if (socd_result == SocdCW) {
|
} else if (socd_result == SocdCW) {
|
||||||
result = TiltDown;
|
result = TiltDown;
|
||||||
} else {
|
} else if (socd_result == SocdBoth) {
|
||||||
result = TiltUp;
|
result = TiltUp;
|
||||||
}
|
}
|
||||||
} else if (is_up) {
|
} else if (is_up) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace socd {
|
namespace socd {
|
||||||
@@ -9,7 +10,8 @@ namespace socd {
|
|||||||
enum class SocdAlgorithm {
|
enum class SocdAlgorithm {
|
||||||
Neutral,
|
Neutral,
|
||||||
PreferRecent,
|
PreferRecent,
|
||||||
PreferFirst
|
PreferFirst,
|
||||||
|
None,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SocdAlgorithm ALGORITHM;
|
extern SocdAlgorithm ALGORITHM;
|
||||||
@@ -17,10 +19,16 @@ namespace socd {
|
|||||||
typedef enum _SocdResult {
|
typedef enum _SocdResult {
|
||||||
SocdCCW = 0,
|
SocdCCW = 0,
|
||||||
SocdCW = 1,
|
SocdCW = 1,
|
||||||
SocdNone = 2
|
SocdNone = 2,
|
||||||
|
SocdBoth = 3
|
||||||
} SocdResult;
|
} SocdResult;
|
||||||
|
|
||||||
SocdResult socd_clean(uint8_t device, bool ccw, bool cw, double time_now);
|
SocdResult socd_clean(
|
||||||
|
uint8_t device,
|
||||||
|
bool ccw,
|
||||||
|
bool cw,
|
||||||
|
double time_now,
|
||||||
|
std::optional<SocdAlgorithm> algorithm = std::nullopt);
|
||||||
|
|
||||||
// for guitar wail (up/down only)
|
// for guitar wail (up/down only)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user