Update to spice2x-23-06-08
This commit is contained in:
+7
-7
@@ -11,13 +11,13 @@ namespace games::bc {
|
||||
Game::attach();
|
||||
|
||||
setupapihook_init(libutils::load_library("libaio.dll"));
|
||||
setupapihook_add({
|
||||
{ 0, 0, 0, 0, },
|
||||
"",
|
||||
"USB\\VID_1CCF&PID_8050\\0000",
|
||||
{},
|
||||
"COM3",
|
||||
});
|
||||
|
||||
SETUPAPI_SETTINGS settings {};
|
||||
const char hwid[] = "USB\\VID_1CCF&PID_8050\\0000";
|
||||
memcpy(settings.property_hardwareid, hwid, sizeof(hwid));
|
||||
const char comport[] = "COM3";
|
||||
memcpy(settings.interface_detail, comport, sizeof(comport));
|
||||
setupapihook_add(settings);
|
||||
|
||||
auto iob = new acio2emu::IOBHandle(L"COM3");
|
||||
iob->register_node(std::make_unique<TBSNode>());
|
||||
|
||||
+89
-18
@@ -15,6 +15,7 @@
|
||||
#include "acioemu/handle.h"
|
||||
#include "avs/core.h"
|
||||
#include "avs/game.h"
|
||||
#include "cfg/configurator.h"
|
||||
#include "games/io.h"
|
||||
#include "hooks/avshook.h"
|
||||
#include "hooks/cfgmgr32hook.h"
|
||||
@@ -23,6 +24,7 @@
|
||||
#include "hooks/setupapihook.h"
|
||||
#include "hooks/sleephook.h"
|
||||
#include "launcher/options.h"
|
||||
#include "touch/touch.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "util/detour.h"
|
||||
@@ -56,15 +58,19 @@ namespace games::iidx {
|
||||
bool FLIP_CAMS = false;
|
||||
bool DISABLE_CAMS = false;
|
||||
bool TDJ_MODE = false;
|
||||
bool FORCE_720P = false;
|
||||
std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt;
|
||||
std::optional<std::string> ASIO_DRIVER = std::nullopt;
|
||||
uint8_t DIGITAL_TT_SENS = 4;
|
||||
std::optional<std::string> SUBSCREEN_OVERLAY_SIZE = std::nullopt;
|
||||
|
||||
// states
|
||||
static HKEY real_asio_reg_handle = nullptr;
|
||||
static HKEY real_asio_device_reg_handle = nullptr;
|
||||
static uint16_t IIDXIO_TT_STATE[2]{};
|
||||
static uint16_t IIDXIO_TT_DIRECTION[2]{};
|
||||
static int8_t IIDXIO_TT_DIRECTION[2]{1, 1};
|
||||
static bool IIDXIO_TT_PRESSED[2]{};
|
||||
static bool IIDXIO_TT_ALT_PRESSED[2]{};
|
||||
char IIDXIO_LED_TICKER[10] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\x00'};
|
||||
bool IIDXIO_LED_TICKER_READONLY = false;
|
||||
std::mutex IIDX_LED_TICKER_LOCK;
|
||||
@@ -445,8 +451,8 @@ namespace games::iidx {
|
||||
// need to hook `avs2-core.dll` so AVS win32fs operations go through rom hook
|
||||
devicehook_init(avs::core::DLL_INSTANCE);
|
||||
|
||||
// hook touch window
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends("beatmania IIDX", "main", avs::game::DLL_INSTANCE);
|
||||
|
||||
// prevent crash on TDJ mode without correct DLL
|
||||
@@ -538,8 +544,21 @@ namespace games::iidx {
|
||||
if (DISABLE_CAMS) {
|
||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||
}
|
||||
if (SOUND_OUTPUT_DEVICE.has_value()) {
|
||||
SetEnvironmentVariable("SOUND_OUTPUT_DEVICE", SOUND_OUTPUT_DEVICE.value().c_str());
|
||||
|
||||
this->detect_sound_output_device();
|
||||
|
||||
// check bad model name
|
||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDJ")) {
|
||||
log_fatal(
|
||||
"iidx",
|
||||
"BAD MODEL NAME ERROR\n\n\n"
|
||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n"
|
||||
"If you are trying to boot IIDX with Lightning Model mode, please do the following instead:\n"
|
||||
" Revert your changes to XML file so it says <model __type=\"str\">LDJ</model>\n"
|
||||
" In SpiceCfg, enable 'IIDX TDJ Mode' or provide -iidxtdj flag in command line\n"
|
||||
" Apply any applicable settings / patches / hex edits\n"
|
||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n\n\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,6 +568,53 @@ namespace games::iidx {
|
||||
devicehook_dispose();
|
||||
}
|
||||
|
||||
void IIDXGame::detect_sound_output_device() {
|
||||
// if the user specified a value (other than auto), use it as the environment var
|
||||
// probably "wasapi" or "asio", but it's not explicitly checked here for forward compat
|
||||
if (SOUND_OUTPUT_DEVICE.has_value() && SOUND_OUTPUT_DEVICE.value() != "auto") {
|
||||
log_info(
|
||||
"iidx",
|
||||
"using user-supplied \"{}\" for SOUND_OUTPUT_DEVICE",
|
||||
SOUND_OUTPUT_DEVICE.value());
|
||||
SetEnvironmentVariable("SOUND_OUTPUT_DEVICE", SOUND_OUTPUT_DEVICE.value().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// automatic detection
|
||||
bool use_asio = false;
|
||||
log_misc("iidx", "auto-detect SOUND_OUTPUT_DEVICE...");
|
||||
if (ASIO_DRIVER.has_value()) {
|
||||
log_misc(
|
||||
"iidx",
|
||||
"-iidxasio is set to \"{}\", use asio for SOUND_OUTPUT_DEVICE",
|
||||
ASIO_DRIVER.value());
|
||||
use_asio = true;
|
||||
} else {
|
||||
HKEY subkey;
|
||||
LSTATUS result;
|
||||
result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\ASIO\\XONAR SOUND CARD(64)", &subkey);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
RegCloseKey(subkey);
|
||||
use_asio = true;
|
||||
log_misc(
|
||||
"iidx",
|
||||
"found HKLM\\SOFTWARE\\ASIO\\XONAR SOUND CARD(64), using asio for SOUND_OUTPUT_DEVICE");
|
||||
}
|
||||
}
|
||||
|
||||
const char* device = "wasapi";
|
||||
if (use_asio) {
|
||||
device = "asio";
|
||||
}
|
||||
log_info("iidx", "SOUND_OUTPUT_DEVICE set to {}", device);
|
||||
log_info(
|
||||
"iidx",
|
||||
"SOUND_OUTPUT_DEVICE only affects IIDX27+ and ignored by older games. "
|
||||
"If {} is not what you wanted, you can override it with -iidxsounddevice option",
|
||||
device);
|
||||
SetEnvironmentVariable("SOUND_OUTPUT_DEVICE", device);
|
||||
}
|
||||
|
||||
uint32_t get_pad() {
|
||||
uint32_t pad = 0;
|
||||
|
||||
@@ -701,7 +767,8 @@ namespace games::iidx {
|
||||
unsigned char get_tt(int player, bool slow) {
|
||||
|
||||
// check change value for high/low precision
|
||||
uint16_t change = slow ? (uint16_t) 1 : (uint16_t) 4;
|
||||
uint16_t change =
|
||||
slow ? (uint16_t) (DIGITAL_TT_SENS / 4) : (uint16_t) DIGITAL_TT_SENS;
|
||||
|
||||
// check player number
|
||||
if (player > 1)
|
||||
@@ -713,8 +780,11 @@ namespace games::iidx {
|
||||
player != 0 ? Buttons::P2_TTPlus : Buttons::P1_TTPlus));
|
||||
bool ttm = GameAPI::Buttons::getState(RI_MGR, buttons.at(
|
||||
player != 0 ? Buttons::P2_TTMinus : Buttons::P1_TTMinus));
|
||||
|
||||
bool ttpm = GameAPI::Buttons::getState(RI_MGR, buttons.at(
|
||||
player != 0 ? Buttons::P2_TTPlusMinus : Buttons::P1_TTPlusMinus));
|
||||
bool ttpm_alt = GameAPI::Buttons::getState(RI_MGR, buttons.at(
|
||||
player != 0 ? Buttons::P2_TTPlusMinusAlt : Buttons::P1_TTPlusMinusAlt));
|
||||
|
||||
// TT+
|
||||
if (ttp)
|
||||
@@ -725,19 +795,16 @@ namespace games::iidx {
|
||||
IIDXIO_TT_STATE[player] -= change;
|
||||
|
||||
// TT+/-
|
||||
if (ttpm) {
|
||||
if (IIDXIO_TT_DIRECTION[player] != 0u) {
|
||||
if (!IIDXIO_TT_PRESSED[player])
|
||||
IIDXIO_TT_DIRECTION[player] = 0;
|
||||
IIDXIO_TT_STATE[player] += change;
|
||||
} else {
|
||||
if (!IIDXIO_TT_PRESSED[player])
|
||||
IIDXIO_TT_DIRECTION[player] = 1;
|
||||
IIDXIO_TT_STATE[player] -= change;
|
||||
}
|
||||
IIDXIO_TT_PRESSED[player] = true;
|
||||
} else
|
||||
IIDXIO_TT_PRESSED[player] = false;
|
||||
bool ttpm_rising_edge = !IIDXIO_TT_PRESSED[player] && ttpm;
|
||||
bool ttpm_alt_rising_edge = !IIDXIO_TT_ALT_PRESSED[player] && ttpm_alt;
|
||||
if (ttpm_rising_edge || ttpm_alt_rising_edge) {
|
||||
IIDXIO_TT_DIRECTION[player] *= -1;
|
||||
}
|
||||
if (ttpm || ttpm_alt) {
|
||||
IIDXIO_TT_STATE[player] += (change * IIDXIO_TT_DIRECTION[player]);
|
||||
}
|
||||
IIDXIO_TT_PRESSED[player] = ttpm;
|
||||
IIDXIO_TT_ALT_PRESSED[player] = ttpm_alt;
|
||||
|
||||
// raw input
|
||||
auto &analogs = get_analogs();
|
||||
@@ -793,4 +860,8 @@ namespace games::iidx {
|
||||
const char* get_16seg() {
|
||||
return IIDXIO_LED_TICKER;
|
||||
}
|
||||
|
||||
bool is_tdj_fhd() {
|
||||
return TDJ_MODE && avs::game::is_ext(2022101900, MAXINT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,11 @@ namespace games::iidx {
|
||||
extern bool FLIP_CAMS;
|
||||
extern bool DISABLE_CAMS;
|
||||
extern bool TDJ_MODE;
|
||||
extern bool FORCE_720P;
|
||||
extern std::optional<std::string> SOUND_OUTPUT_DEVICE;
|
||||
extern std::optional<std::string> ASIO_DRIVER;
|
||||
extern uint8_t DIGITAL_TT_SENS;
|
||||
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
||||
|
||||
// state
|
||||
extern char IIDXIO_LED_TICKER[10];
|
||||
@@ -27,6 +30,9 @@ namespace games::iidx {
|
||||
virtual void attach() override;
|
||||
virtual void pre_attach() override;
|
||||
virtual void detach() override;
|
||||
|
||||
private:
|
||||
void detect_sound_output_device();
|
||||
};
|
||||
|
||||
// helper methods
|
||||
@@ -38,4 +44,5 @@ namespace games::iidx {
|
||||
unsigned char get_tt(int player, bool slow);
|
||||
unsigned char get_slider(uint8_t slider);
|
||||
const char* get_16seg();
|
||||
bool is_tdj_fhd();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ std::vector<Button> &games::iidx::get_buttons() {
|
||||
"P1 TT+",
|
||||
"P1 TT-",
|
||||
"P1 TT+/-",
|
||||
"P1 TT+/- Alternate",
|
||||
"P1 Start",
|
||||
"P2 1",
|
||||
"P2 2",
|
||||
@@ -32,6 +33,7 @@ std::vector<Button> &games::iidx::get_buttons() {
|
||||
"P2 TT+",
|
||||
"P2 TT-",
|
||||
"P2 TT+/-",
|
||||
"P2 TT+/- Alternate",
|
||||
"P2 Start",
|
||||
"EFFECT",
|
||||
"VEFX",
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace games::iidx {
|
||||
P1_TTPlus,
|
||||
P1_TTMinus,
|
||||
P1_TTPlusMinus,
|
||||
P1_TTPlusMinusAlt,
|
||||
P1_Start,
|
||||
P2_1,
|
||||
P2_2,
|
||||
@@ -32,6 +33,7 @@ namespace games::iidx {
|
||||
P2_TTPlus,
|
||||
P2_TTMinus,
|
||||
P2_TTPlusMinus,
|
||||
P2_TTPlusMinusAlt,
|
||||
P2_Start,
|
||||
Effect,
|
||||
VEFX,
|
||||
|
||||
+12
-10
@@ -366,8 +366,14 @@ namespace games {
|
||||
std::vector<unsigned short> vkey_defaults;
|
||||
|
||||
// overlay button definitions
|
||||
names.emplace_back("Screenshot");
|
||||
vkey_defaults.push_back(VK_SNAPSHOT);
|
||||
names.emplace_back("Toggle Sub Screen");
|
||||
vkey_defaults.push_back(VK_PRIOR);
|
||||
names.emplace_back("Insert Coin");
|
||||
vkey_defaults.push_back(VK_F1);
|
||||
names.emplace_back("Toggle IO Panel");
|
||||
vkey_defaults.push_back(VK_F2);
|
||||
names.emplace_back("Toggle Config");
|
||||
vkey_defaults.push_back(VK_F4);
|
||||
names.emplace_back("Toggle Virtual Keypad P1");
|
||||
@@ -382,12 +388,14 @@ namespace games {
|
||||
vkey_defaults.push_back(VK_F9);
|
||||
names.emplace_back("Toggle Patch Manager");
|
||||
vkey_defaults.push_back(VK_F10);
|
||||
names.emplace_back("Toggle Sub Screen");
|
||||
vkey_defaults.push_back(VK_PRIOR);
|
||||
names.emplace_back("Toggle VR Control");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Toggle Screen Resize");
|
||||
vkey_defaults.push_back(VK_F11);
|
||||
names.emplace_back("Toggle Overlay");
|
||||
vkey_defaults.push_back(VK_F12);
|
||||
names.emplace_back("Toggle VR Control");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Screen Resize");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Navigator Activate");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Navigator Cancel");
|
||||
@@ -400,18 +408,12 @@ namespace games {
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Navigator Right");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Screenshot");
|
||||
vkey_defaults.push_back(VK_SNAPSHOT);
|
||||
names.emplace_back("Hotkey Enable 1");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Hotkey Enable 2");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Hotkey Toggle");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Screen Resize");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
names.emplace_back("Toggle Screen Resize");
|
||||
vkey_defaults.push_back(0xFF);
|
||||
|
||||
// return sorted buttons
|
||||
buttons = GameAPI::Buttons::sortButtons(buttons, names, &vkey_defaults);
|
||||
|
||||
+6
-5
@@ -7,7 +7,10 @@ namespace games {
|
||||
|
||||
namespace OverlayButtons {
|
||||
enum {
|
||||
Screenshot,
|
||||
ToggleSubScreen,
|
||||
InsertCoin,
|
||||
ToggleIOPanel,
|
||||
ToggleConfig,
|
||||
ToggleVirtualKeypadP1,
|
||||
ToggleVirtualKeypadP2,
|
||||
@@ -15,21 +18,19 @@ namespace games {
|
||||
ToggleLog,
|
||||
ToggleControl,
|
||||
TogglePatchManager,
|
||||
ToggleSubScreen,
|
||||
ToggleVRControl,
|
||||
ToggleScreenResize,
|
||||
ToggleOverlay,
|
||||
ToggleVRControl,
|
||||
ScreenResize,
|
||||
NavigatorActivate,
|
||||
NavigatorCancel,
|
||||
NavigatorUp,
|
||||
NavigatorDown,
|
||||
NavigatorLeft,
|
||||
NavigatorRight,
|
||||
Screenshot,
|
||||
HotkeyEnable1,
|
||||
HotkeyEnable2,
|
||||
HotkeyToggle,
|
||||
ScreenResize,
|
||||
ToggleScreenResize,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+56
-9
@@ -10,9 +10,14 @@
|
||||
#include "util/detour.h"
|
||||
#include "util/libutils.h"
|
||||
|
||||
#define JB_BUTTON_SIZE 160
|
||||
#define JB_BUTTON_GAP 37
|
||||
#define JB_BUTTON_HITBOX (JB_BUTTON_SIZE + JB_BUTTON_GAP)
|
||||
|
||||
namespace games::jb {
|
||||
|
||||
// touch stuff
|
||||
bool TOUCH_LEGACY_BOX = false;
|
||||
static bool TOUCH_ENABLE = false;
|
||||
static bool TOUCH_ATTACHED = false;
|
||||
static bool IS_PORTRAIT = true;
|
||||
@@ -68,19 +73,61 @@ namespace games::jb {
|
||||
memset(TOUCH_STATE, 0, sizeof(TOUCH_STATE));
|
||||
|
||||
// check touch points
|
||||
// note that the IO code in device.cpp will correctly compensate for orientation, depending on the model.
|
||||
TOUCH_POINTS.clear();
|
||||
touch_get_points(TOUCH_POINTS);
|
||||
auto offset = IS_PORTRAIT ? 580 : 0;
|
||||
for (auto &tp : TOUCH_POINTS) {
|
||||
if (TOUCH_LEGACY_BOX) {
|
||||
auto offset = IS_PORTRAIT ? 580 : 0;
|
||||
for (auto &tp : TOUCH_POINTS) {
|
||||
|
||||
// get grid coordinates
|
||||
int x = tp.x * 4 / 768;
|
||||
int y = (tp.y - offset) * 4 / (1360 - 580);
|
||||
// get grid coordinates
|
||||
int x = tp.x * 4 / 768;
|
||||
int y = (tp.y - offset) * 4 / (1360 - 580);
|
||||
|
||||
// set the corresponding state
|
||||
int index = y * 4 + x;
|
||||
if (index >= 0 && index < 16) {
|
||||
TOUCH_STATE[index] = true;
|
||||
// set the corresponding state
|
||||
int index = y * 4 + x;
|
||||
if (index >= 0 && index < 16) {
|
||||
TOUCH_STATE[index] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto &tp : TOUCH_POINTS) {
|
||||
int x_relative = tp.x;
|
||||
int y_relative = tp.y;
|
||||
|
||||
// x_relative and y_relative are relative to the top-left pixel of the first button
|
||||
if (IS_PORTRAIT) {
|
||||
// which is at (8, 602) in portrait:
|
||||
// X: [8...759] (752 pixels wide)
|
||||
// Y: [602...1353] (752 pixels high)
|
||||
x_relative -= 8;
|
||||
y_relative -= 602;
|
||||
} else {
|
||||
// and at (8, 8) in landscape
|
||||
x_relative -= 8;
|
||||
y_relative -= 8;
|
||||
}
|
||||
|
||||
if (x_relative < 0 || y_relative < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// x_hitbox and y_hitbox is relative to top-left pixel of each button
|
||||
int x_index = x_relative / JB_BUTTON_HITBOX;
|
||||
int x_hitbox = x_relative % JB_BUTTON_HITBOX;
|
||||
int y_index = y_relative / JB_BUTTON_HITBOX;
|
||||
int y_hitbox = y_relative % JB_BUTTON_HITBOX;
|
||||
|
||||
// check if the gap was touched
|
||||
if (x_hitbox > JB_BUTTON_SIZE || y_hitbox > JB_BUTTON_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set the corresponding state
|
||||
int index = y_index * 4 + x_index;
|
||||
if (0 <= index && index < 16) {
|
||||
TOUCH_STATE[index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace games::jb {
|
||||
|
||||
// touch stuff
|
||||
extern bool TOUCH_LEGACY_BOX;
|
||||
extern bool TOUCH_STATE[16];
|
||||
void touch_update();
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
namespace games::rb {
|
||||
|
||||
extern uint16_t TOUCH_SCALING;
|
||||
|
||||
class RBGame : public games::Game {
|
||||
public:
|
||||
RBGame();
|
||||
|
||||
+21
-4
@@ -11,15 +11,20 @@
|
||||
|
||||
static std::string WINDOW_TITLE = "REFLEC BEAT";
|
||||
|
||||
namespace games::rb {
|
||||
uint16_t TOUCH_SCALING = 1000;
|
||||
}
|
||||
|
||||
games::rb::ReflecBeatTouchDeviceHandle::ReflecBeatTouchDeviceHandle(bool log_fps) {
|
||||
this->log_fps = log_fps;
|
||||
}
|
||||
|
||||
void games::rb::ReflecBeatTouchDeviceHandle::grid_insert(unsigned char *data, int cursor_x, int cursor_y) {
|
||||
|
||||
// scale to grid position
|
||||
// scale to grid position - there are 48 columns and 76 rows of IR sensors.
|
||||
// for whatever reason, the last y row (#75) results in weird input few rows above; just drop it
|
||||
int grid_x = CLAMP((cursor_x * 48) / window_width, 0, 47);
|
||||
int grid_y = CLAMP((cursor_y * 76) / window_height, 0, 75);
|
||||
int grid_y = CLAMP((cursor_y * 76) / window_height, 0, 74);
|
||||
|
||||
// get bit positions
|
||||
int bit_x = 88 + grid_x;
|
||||
@@ -121,6 +126,8 @@ int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberO
|
||||
// data header
|
||||
data[0] = 0x55;
|
||||
data[2] = 0x4C;
|
||||
|
||||
const auto SCALE_FACTOR = games::rb::TOUCH_SCALING / 1000.f;
|
||||
|
||||
// iterate all touch points
|
||||
auto offset_x = (int) (window_width / 48.0 / 3.0);
|
||||
@@ -139,9 +146,19 @@ int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberO
|
||||
y = window_height - point.x;
|
||||
}
|
||||
|
||||
// apply scaling
|
||||
x = x - (window_width * (1.f - SCALE_FACTOR) / 2);
|
||||
x = x / SCALE_FACTOR;
|
||||
y = y - (window_height * (1.f - SCALE_FACTOR) / 2);
|
||||
y = y / SCALE_FACTOR;
|
||||
|
||||
if (x < 0 || window_width <= x || y < 0 || window_height <= y) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// point scaling
|
||||
auto point_x = (int) ((x - window_width / 2.0) * 48.0 / 54.0 + window_width / 2.0);
|
||||
auto point_y = (int) (y - window_height / 76);
|
||||
const auto point_x = (int) ((x - window_width / 2.0) * 48.0 / 54.0 + window_width / 2.0);
|
||||
const auto point_y = (int) (y - window_height / 76);
|
||||
|
||||
// insert 9 times with offset to double the precision
|
||||
grid_insert(data, point_x, point_y);
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#include "games/io.h"
|
||||
#include "launcher/options.h"
|
||||
#include "io.h"
|
||||
#include "games/sdvx/sdvx.h"
|
||||
|
||||
namespace games::sdvx {
|
||||
constexpr bool BI2X_PASSTHROUGH = false;
|
||||
bool BI2X_INITIALIZED = false;
|
||||
|
||||
/*
|
||||
* class definitions
|
||||
@@ -104,7 +106,6 @@ namespace games::sdvx {
|
||||
if (!BI2X_PASSTHROUGH) {
|
||||
custom_node = new AIO_IOB2_BI2X_UFC;
|
||||
memset(&custom_node->data, 0, sizeof(custom_node->data));
|
||||
|
||||
return custom_node;
|
||||
} else {
|
||||
|
||||
@@ -163,18 +164,18 @@ namespace games::sdvx {
|
||||
|
||||
// volume left
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::VOL_L_Left])) {
|
||||
VOL_L -= 64;
|
||||
VOL_L -= ((uint16_t)DIGITAL_KNOB_SENS * 4);
|
||||
}
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::VOL_L_Right])) {
|
||||
VOL_L += 64;
|
||||
VOL_L += ((uint16_t)DIGITAL_KNOB_SENS * 4);
|
||||
}
|
||||
|
||||
// volume right
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::VOL_R_Left])) {
|
||||
VOL_R -= 64;
|
||||
VOL_R -= ((uint16_t)DIGITAL_KNOB_SENS * 4);
|
||||
}
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::VOL_R_Right])) {
|
||||
VOL_R += 64;
|
||||
VOL_R += ((uint16_t)DIGITAL_KNOB_SENS * 4);
|
||||
}
|
||||
|
||||
// update volumes
|
||||
@@ -364,6 +365,7 @@ namespace games::sdvx {
|
||||
aioNmgrIob2->pAIO_NMGR_IOB_BeginManage = AIO_NMGR_IOB_BeginManageStub;
|
||||
}
|
||||
log_info("bi2x_hook", "aioNMgrIob2_Create");
|
||||
BI2X_INITIALIZED = true;
|
||||
return &aioNmgrIob2;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "hooks/libraryhook.h"
|
||||
#include "hooks/powrprof.h"
|
||||
#include "hooks/sleephook.h"
|
||||
#include "touch/touch.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/sigscan.h"
|
||||
@@ -21,11 +22,118 @@
|
||||
#include "io.h"
|
||||
#include "acioemu/handle.h"
|
||||
|
||||
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
|
||||
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
|
||||
static decltype(RegOpenKeyA) *RegOpenKeyA_orig = nullptr;
|
||||
static decltype(RegOpenKeyExA) *RegOpenKeyExA_orig = nullptr;
|
||||
static decltype(RegQueryValueExA) *RegQueryValueExA_orig = nullptr;
|
||||
|
||||
namespace games::sdvx {
|
||||
|
||||
// constants
|
||||
const HKEY PARENT_ASIO_REG_HANDLE = reinterpret_cast<HKEY>(0x3001);
|
||||
const HKEY DEVICE_ASIO_REG_HANDLE = reinterpret_cast<HKEY>(0x3002);
|
||||
const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)";
|
||||
|
||||
// settings
|
||||
bool DISABLECAMS = false;
|
||||
bool NATIVETOUCH = false;
|
||||
uint8_t DIGITAL_KNOB_SENS = 16;
|
||||
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
|
||||
|
||||
std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt;
|
||||
std::optional<std::string> ASIO_DRIVER = std::nullopt;
|
||||
|
||||
// states
|
||||
static HKEY real_asio_reg_handle = nullptr;
|
||||
static HKEY real_asio_device_reg_handle = nullptr;
|
||||
|
||||
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
||||
if (lpSubKey != nullptr && phkResult != nullptr) {
|
||||
if (hKey == HKEY_LOCAL_MACHINE &&
|
||||
ASIO_DRIVER.has_value() &&
|
||||
_stricmp(lpSubKey, "software\\asio") == 0)
|
||||
{
|
||||
*phkResult = PARENT_ASIO_REG_HANDLE;
|
||||
|
||||
return RegOpenKeyA_orig(hKey, lpSubKey, &real_asio_reg_handle);
|
||||
}
|
||||
}
|
||||
|
||||
return RegOpenKeyA_orig(hKey, lpSubKey, phkResult);
|
||||
}
|
||||
|
||||
static LONG WINAPI RegOpenKeyExA_hook(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired,
|
||||
PHKEY phkResult)
|
||||
{
|
||||
if (lpSubKey != nullptr && phkResult != nullptr) {
|
||||
if (hKey == PARENT_ASIO_REG_HANDLE &&
|
||||
ASIO_DRIVER.has_value() &&
|
||||
_stricmp(lpSubKey, ORIGINAL_ASIO_DEVICE_NAME) == 0)
|
||||
{
|
||||
*phkResult = DEVICE_ASIO_REG_HANDLE;
|
||||
|
||||
log_info("sdvx::asio", "replacing '{}' with '{}'", lpSubKey, ASIO_DRIVER.value());
|
||||
|
||||
return RegOpenKeyExA_orig(real_asio_reg_handle, ASIO_DRIVER.value().c_str(), ulOptions, samDesired,
|
||||
&real_asio_device_reg_handle);
|
||||
}
|
||||
}
|
||||
|
||||
return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult);
|
||||
}
|
||||
|
||||
static LONG WINAPI RegEnumKeyA_hook(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName) {
|
||||
if (hKey == PARENT_ASIO_REG_HANDLE && ASIO_DRIVER.has_value()) {
|
||||
if (dwIndex == 0) {
|
||||
auto ret = RegEnumKeyA_orig(real_asio_reg_handle, dwIndex, lpName, cchName);
|
||||
|
||||
if (ret == ERROR_SUCCESS && lpName != nullptr) {
|
||||
log_info("sdvx::asio", "stubbing '{}' with '{}'", lpName, ORIGINAL_ASIO_DEVICE_NAME);
|
||||
|
||||
strncpy(lpName, ORIGINAL_ASIO_DEVICE_NAME, cchName);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return ERROR_NO_MORE_ITEMS;
|
||||
}
|
||||
}
|
||||
|
||||
return RegEnumKeyA_orig(hKey, dwIndex, lpName, cchName);
|
||||
}
|
||||
|
||||
static LONG WINAPI RegQueryValueExA_hook(HKEY hKey, LPCTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType,
|
||||
LPBYTE lpData, LPDWORD lpcbData)
|
||||
{
|
||||
if (lpValueName != nullptr && lpData != nullptr && lpcbData != nullptr) {
|
||||
if (hKey == DEVICE_ASIO_REG_HANDLE && ASIO_DRIVER.has_value()) {
|
||||
log_info("sdvx::asio", "RegQueryValueExA({}, \"{}\")", fmt::ptr((void *) hKey), lpValueName);
|
||||
|
||||
if (_stricmp(lpValueName, "Description") == 0) {
|
||||
// sdvx does a comparison against "XONAR SOUND CARD(64)"
|
||||
// otherwise you end up with this error:
|
||||
// M:BMSoundLib: ASIODriver: No such driver: XONAR SOUND CARD(64)
|
||||
memcpy(lpData, ORIGINAL_ASIO_DEVICE_NAME, strlen(ORIGINAL_ASIO_DEVICE_NAME) + 1);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} else {
|
||||
hKey = real_asio_device_reg_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fallback
|
||||
return RegQueryValueExA_orig(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
||||
}
|
||||
|
||||
static LONG WINAPI RegCloseKey_hook(HKEY hKey) {
|
||||
if (hKey == PARENT_ASIO_REG_HANDLE || hKey == DEVICE_ASIO_REG_HANDLE) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
return RegCloseKey_orig(hKey);
|
||||
}
|
||||
|
||||
SDVXGame::SDVXGame() : Game("Sound Voltex") {
|
||||
}
|
||||
@@ -161,6 +269,7 @@ namespace games::sdvx {
|
||||
// hook touch window
|
||||
if (!NATIVETOUCH) {
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends(
|
||||
"SOUND VOLTEX",
|
||||
"Main Screen",
|
||||
@@ -179,7 +288,21 @@ namespace games::sdvx {
|
||||
libraryhook_enable(avs::game::DLL_INSTANCE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ASIO device hook
|
||||
RegCloseKey_orig = detour::iat_try(
|
||||
"RegCloseKey", RegCloseKey_hook, avs::game::DLL_INSTANCE);
|
||||
RegEnumKeyA_orig = detour::iat_try(
|
||||
"RegEnumKeyA", RegEnumKeyA_hook, avs::game::DLL_INSTANCE);
|
||||
RegOpenKeyA_orig = detour::iat_try(
|
||||
"RegOpenKeyA", RegOpenKeyA_hook, avs::game::DLL_INSTANCE);
|
||||
RegOpenKeyExA_orig = detour::iat_try(
|
||||
"RegOpenKeyExA", RegOpenKeyExA_hook, avs::game::DLL_INSTANCE);
|
||||
RegQueryValueExA_orig = detour::iat_try(
|
||||
"RegQueryValueExA", RegQueryValueExA_hook, avs::game::DLL_INSTANCE);
|
||||
|
||||
#ifdef SPICE64
|
||||
powrprof_hook_init(avs::game::DLL_INSTANCE);
|
||||
|
||||
// hook camera
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "games/game.h"
|
||||
|
||||
namespace games::sdvx {
|
||||
|
||||
enum SdvxOverlayPosition {
|
||||
SDVX_OVERLAY_TOP,
|
||||
SDVX_OVERLAY_MIDDLE,
|
||||
SDVX_OVERLAY_BOTTOM
|
||||
};
|
||||
|
||||
// settings
|
||||
extern bool DISABLECAMS;
|
||||
extern bool NATIVETOUCH;
|
||||
extern uint8_t DIGITAL_KNOB_SENS;
|
||||
extern std::optional<std::string> ASIO_DRIVER;
|
||||
extern bool BI2X_INITIALIZED;
|
||||
extern SdvxOverlayPosition OVERLAY_POS;
|
||||
|
||||
class SDVXGame : public games::Game {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user