diff --git a/src/spice2x/games/rb/rb.cpp b/src/spice2x/games/rb/rb.cpp index 35fdee1..68f4434 100644 --- a/src/spice2x/games/rb/rb.cpp +++ b/src/spice2x/games/rb/rb.cpp @@ -6,27 +6,32 @@ #include "util/detour.h" #include "util/precise_timer.h" #include "util/logging.h" +#include "cfg/configurator.h" #include "touch.h" +namespace games::rb { + uint16_t TOUCH_POLL_RATE = 0; +} + static decltype(SleepEx) *SleepEx_orig; -static DWORD WINAPI SleepEx_hook(DWORD dwMilliseconds, BOOL bAltertable) { +static DWORD WINAPI SleepEx_hook(DWORD dwMilliseconds, BOOL bAlertable) { - // increase touch poll from ~110 FPS to ~500 FPS (Sleep) or ~1000 FPS (Win10 high-res timer) + // increase touch poll rate if (dwMilliseconds == 8) { - dwMilliseconds = 1; + dwMilliseconds = 1000 / games::rb::TOUCH_POLL_RATE; } // most calls from rb are actually non-alertable - if (!bAltertable) { + if (!bAlertable) { static thread_local timeutils::PreciseSleepTimer timer; timer.sleep(dwMilliseconds); return 0; } // call original - return SleepEx_orig(dwMilliseconds, bAltertable); + return SleepEx_orig(dwMilliseconds, bAlertable); } games::rb::RBGame::RBGame() : Game("Reflec Beat") { @@ -35,6 +40,10 @@ games::rb::RBGame::RBGame() : Game("Reflec Beat") { void games::rb::RBGame::attach() { Game::attach(); + if (1000 < games::rb::TOUCH_POLL_RATE) { + log_fatal("rb", "-rbtouchsize is set too high; cannot exceed 1000"); + } + // init stuff devicehook_init(); @@ -47,7 +56,12 @@ void games::rb::RBGame::attach() { } // hooks - SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, avs::game::DLL_INSTANCE); + if (0 < TOUCH_POLL_RATE) { + log_info("rb", "force increasing touch poll rate by hooking SleepEx ({}Hz)", TOUCH_POLL_RATE); + SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, avs::game::DLL_INSTANCE); + } else { + log_info("rb", "not changing touch poll rate (120Hz by default)"); + } } void games::rb::RBGame::detach() { diff --git a/src/spice2x/games/rb/rb.h b/src/spice2x/games/rb/rb.h index 311a161..9066499 100644 --- a/src/spice2x/games/rb/rb.h +++ b/src/spice2x/games/rb/rb.h @@ -7,6 +7,8 @@ namespace games::rb { extern uint16_t TOUCH_SCALING; + extern uint8_t TOUCH_SIZE; + extern uint16_t TOUCH_POLL_RATE; class RBGame : public games::Game { public: diff --git a/src/spice2x/games/rb/touch.cpp b/src/spice2x/games/rb/touch.cpp index 4831d1c..be134d6 100644 --- a/src/spice2x/games/rb/touch.cpp +++ b/src/spice2x/games/rb/touch.cpp @@ -13,6 +13,7 @@ static std::string WINDOW_TITLE = "REFLEC BEAT"; namespace games::rb { uint16_t TOUCH_SCALING = 1000; + uint8_t TOUCH_SIZE = 1; } games::rb::ReflecBeatTouchDeviceHandle::ReflecBeatTouchDeviceHandle(bool log_fps) { @@ -160,16 +161,20 @@ int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberO 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 + // center grid_insert(data, point_x, point_y); - grid_insert(data, point_x - offset_x, point_y); - grid_insert(data, point_x - offset_x, point_y - offset_y); - grid_insert(data, point_x - offset_x, point_y + offset_y); - grid_insert(data, point_x + offset_x, point_y); - grid_insert(data, point_x + offset_x, point_y + offset_y); - grid_insert(data, point_x + offset_x, point_y - offset_y); - grid_insert(data, point_x, point_y - offset_y); - grid_insert(data, point_x, point_y + offset_y); + + // surrounding points + if (games::rb::TOUCH_SIZE == 3) { + grid_insert(data, point_x - offset_x, point_y); // west + grid_insert(data, point_x - offset_x, point_y - offset_y); // northwest + grid_insert(data, point_x - offset_x, point_y + offset_y); // southwest + grid_insert(data, point_x + offset_x, point_y); // east + grid_insert(data, point_x + offset_x, point_y + offset_y); // southeast + grid_insert(data, point_x + offset_x, point_y - offset_y); // northeast + grid_insert(data, point_x, point_y - offset_y); // north + grid_insert(data, point_x, point_y + offset_y); // south + } } // copy data to buffer diff --git a/src/spice2x/launcher/launcher.cpp b/src/spice2x/launcher/launcher.cpp index 69709b2..0135018 100644 --- a/src/spice2x/launcher/launcher.cpp +++ b/src/spice2x/launcher/launcher.cpp @@ -1205,9 +1205,20 @@ int main_implementation(int argc, char *argv[]) { } } + // reflec beat touch emulation if (options[launcher::Options::spice2x_RBTouchScale].is_active()) { games::rb::TOUCH_SCALING = options[launcher::Options::spice2x_RBTouchScale].value_uint32(); } + if (options[launcher::Options::RBTouchSize].is_active()) { + const auto text = options[launcher::Options::RBTouchSize].value_text(); + if (text == "3") { + games::rb::TOUCH_SIZE = 3; + } + } + if (options[launcher::Options::RBTouchPollRate].is_active()) { + games::rb::TOUCH_POLL_RATE = options[launcher::Options::RBTouchPollRate].value_uint32(); + } + if (options[launcher::Options::spice2x_AsioForceUnload].value_bool()) { hooks::audio::ASIO_FORCE_UNLOAD_ON_STOP = true; } diff --git a/src/spice2x/launcher/options.cpp b/src/spice2x/launcher/options.cpp index d417b66..004e45d 100644 --- a/src/spice2x/launcher/options.cpp +++ b/src/spice2x/launcher/options.cpp @@ -2317,7 +2317,7 @@ static const std::vector OPTION_DEFINITIONS = { }, { // spice2x_RBTouchScale - .title = "RB Scale Touch Input", + .title = "RB Touch Emulation Scale", .name = "sp2x-rbscaletouch", .display_name = "rbscaletouch", .aliases= "rbscaletouch", @@ -2327,6 +2327,31 @@ static const std::vector OPTION_DEFINITIONS = { .game_name = "Reflec Beat", .category = "Game Options", }, + { + // RBTouchSize + .title = "RB Touch Emulation Size", + .name = "rbtouchsize", + .desc = "Size of the touch area; how many IR sensors a single finger activates. Default: 1 (1x1).", + .type = OptionType::Enum, + .game_name = "Reflec Beat", + .category = "Game Options", + .elements = { + {"1", "1x1"}, + {"3", "3x3"}, + }, + }, + { + // RBTouchPollRate + .title = "RB Touch Emulation Poll Hz", + .name = "rbtouchhz", + .desc = "By default, the game polls for touch at 120Hz. " + "This option overrides that rate; enter a number betwen 1 and 1000.\n\n" + "It should be noted that higher poll does not necessarily improve accuracy or performance.", + .type = OptionType::Integer, + .setting_name = "250", + .game_name = "Reflec Beat", + .category = "Game Options", + }, { // spice2x_AsioForceUnload .title = "ASIO Force Unload On Stop", diff --git a/src/spice2x/launcher/options.h b/src/spice2x/launcher/options.h index 9d3ff4a..61f3e56 100644 --- a/src/spice2x/launcher/options.h +++ b/src/spice2x/launcher/options.h @@ -242,6 +242,8 @@ namespace launcher { spice2x_JubeatLegacyTouch, JubeatTouchAlgo, spice2x_RBTouchScale, + RBTouchSize, + RBTouchPollRate, spice2x_AsioForceUnload, spice2x_IIDXNoESpec, spice2x_IIDXWindowedTDJ,