Initial re-upload of spice2x-24-08-24
This commit is contained in:
45
games/rb/io.cpp
Normal file
45
games/rb/io.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "io.h"
|
||||
|
||||
std::vector<Button> &games::rb::get_buttons() {
|
||||
static std::vector<Button> buttons;
|
||||
|
||||
if (buttons.empty()) {
|
||||
buttons = GameAPI::Buttons::getButtons("Reflec Beat");
|
||||
GameAPI::Buttons::sortButtons(
|
||||
&buttons,
|
||||
"Service",
|
||||
"Test"
|
||||
);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
std::vector<Light> &games::rb::get_lights() {
|
||||
static std::vector<Light> lights;
|
||||
|
||||
if (lights.empty()) {
|
||||
lights = GameAPI::Lights::getLights("Reflec Beat");
|
||||
|
||||
GameAPI::Lights::sortLights(
|
||||
&lights,
|
||||
"Pole R",
|
||||
"Pole G",
|
||||
"Pole B",
|
||||
"Escutcheon R",
|
||||
"Escutcheon G",
|
||||
"Escutcheon B",
|
||||
"Woofer R",
|
||||
"Woofer G",
|
||||
"Woofer B",
|
||||
"Title R",
|
||||
"Title G",
|
||||
"Title B",
|
||||
"Title Up R",
|
||||
"Title Up G",
|
||||
"Title Up B"
|
||||
);
|
||||
}
|
||||
|
||||
return lights;
|
||||
}
|
||||
40
games/rb/io.h
Normal file
40
games/rb/io.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "cfg/api.h"
|
||||
|
||||
namespace games::rb {
|
||||
|
||||
// all buttons in correct order
|
||||
namespace Buttons {
|
||||
enum {
|
||||
Service,
|
||||
Test
|
||||
};
|
||||
}
|
||||
|
||||
// all lights in correct order
|
||||
namespace Lights {
|
||||
enum {
|
||||
PoleR,
|
||||
PoleG,
|
||||
PoleB,
|
||||
EscutcheonR,
|
||||
EscutcheonG,
|
||||
EscutcheonB,
|
||||
WooferR,
|
||||
WooferG,
|
||||
WooferB,
|
||||
TitleR,
|
||||
TitleG,
|
||||
TitleB,
|
||||
TitleUpR,
|
||||
TitleUpG,
|
||||
TitleUpB
|
||||
};
|
||||
}
|
||||
|
||||
// getters
|
||||
std::vector<Button> &get_buttons();
|
||||
std::vector<Light> &get_lights();
|
||||
}
|
||||
56
games/rb/rb.cpp
Normal file
56
games/rb/rb.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "rb.h"
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "hooks/devicehook.h"
|
||||
#include "hooks/audio/backends/dsound/dsound_backend.h"
|
||||
#include "util/detour.h"
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
static decltype(SleepEx) *SleepEx_orig;
|
||||
|
||||
static DWORD WINAPI SleepEx_hook(DWORD dwMilliseconds, BOOL bAltertable) {
|
||||
|
||||
/*
|
||||
* Increase touch poll from ~110 FPS to ~500 FPS
|
||||
*/
|
||||
if (dwMilliseconds == 8) {
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
|
||||
// if we only sleep for 1ms we also don't need the high priority RB sets
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
|
||||
}
|
||||
dwMilliseconds = 1;
|
||||
}
|
||||
|
||||
// call original
|
||||
return SleepEx_orig(dwMilliseconds, bAltertable);
|
||||
}
|
||||
|
||||
games::rb::RBGame::RBGame() : Game("Reflec Beat") {
|
||||
}
|
||||
|
||||
void games::rb::RBGame::attach() {
|
||||
Game::attach();
|
||||
|
||||
// init stuff
|
||||
devicehook_init();
|
||||
|
||||
// add touch device
|
||||
devicehook_add(new ReflecBeatTouchDeviceHandle(false));
|
||||
|
||||
if (avs::game::is_model({"KBR", "LBR"})) {
|
||||
// dsound.dll hook
|
||||
audio_dsound_init();
|
||||
}
|
||||
|
||||
// hooks
|
||||
SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, avs::game::DLL_INSTANCE);
|
||||
}
|
||||
|
||||
void games::rb::RBGame::detach() {
|
||||
Game::detach();
|
||||
devicehook_dispose();
|
||||
}
|
||||
17
games/rb/rb.h
Normal file
17
games/rb/rb.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "games/game.h"
|
||||
|
||||
namespace games::rb {
|
||||
|
||||
extern uint16_t TOUCH_SCALING;
|
||||
|
||||
class RBGame : public games::Game {
|
||||
public:
|
||||
RBGame();
|
||||
virtual void attach();
|
||||
virtual void detach();
|
||||
};
|
||||
}
|
||||
209
games/rb/touch.cpp
Normal file
209
games/rb/touch.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "touch.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "touch/touch.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/time.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
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 - 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, 74);
|
||||
|
||||
// get bit positions
|
||||
int bit_x = 88 + grid_x;
|
||||
int bit_y = 74 - grid_y;
|
||||
|
||||
// insert bits
|
||||
data[3 + bit_x / 8] |= (char) 1 << (bit_x % 8);
|
||||
data[3 + bit_y / 8] |= (char) 1 << (bit_y % 8);
|
||||
}
|
||||
|
||||
bool games::rb::ReflecBeatTouchDeviceHandle::open(LPCWSTR lpFileName) {
|
||||
if (wcscmp(lpFileName, L"COM1") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// attach touch module
|
||||
HWND wnd = GetForegroundWindow();
|
||||
if (!string_begins_with(GetActiveWindowTitle(), WINDOW_TITLE)) {
|
||||
wnd = FindWindowBeginsWith(WINDOW_TITLE);
|
||||
}
|
||||
|
||||
if (wnd != nullptr) {
|
||||
|
||||
// reset window process to make the game not crash
|
||||
SetWindowLongPtr(wnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(DefWindowProc));
|
||||
|
||||
// check if windowed
|
||||
if (GRAPHICS_WINDOWED) {
|
||||
|
||||
// remove style borders
|
||||
LONG lStyle = GetWindowLong(wnd, GWL_STYLE);
|
||||
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
|
||||
SetWindowLongPtr(wnd, GWL_STYLE, lStyle);
|
||||
|
||||
// remove ex style borders
|
||||
LONG lExStyle = GetWindowLong(wnd, GWL_EXSTYLE);
|
||||
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
|
||||
SetWindowLongPtr(wnd, GWL_EXSTYLE, lExStyle);
|
||||
|
||||
// update window
|
||||
SetWindowPos(wnd, nullptr, 0, 0, 0, 0,
|
||||
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
|
||||
// create touch window
|
||||
touch_create_wnd(wnd);
|
||||
|
||||
} else {
|
||||
|
||||
// create touch window
|
||||
touch_create_wnd(wnd);
|
||||
|
||||
// show game window because it lost focus
|
||||
ShowWindow(wnd, SW_SHOW);
|
||||
}
|
||||
} else {
|
||||
|
||||
// fallback to dx hook
|
||||
touch_attach_dx_hook();
|
||||
}
|
||||
|
||||
// show cursor on window if mouse is used
|
||||
if (!is_touch_available()) {
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
|
||||
|
||||
// check buffer size
|
||||
if (nNumberOfBytesToRead < 20) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get window
|
||||
HWND window = GetForegroundWindow();
|
||||
if (window == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// update width and height
|
||||
RECT rect {};
|
||||
GetWindowRect(window, &rect);
|
||||
|
||||
// check for landscape (KBR)
|
||||
bool is_landscape = (rect.right - rect.left) > (rect.bottom - rect.top);
|
||||
if (is_landscape) {
|
||||
window_height = rect.right - rect.left;
|
||||
window_width = rect.bottom - rect.top;
|
||||
} else {
|
||||
window_width = rect.right - rect.left;
|
||||
window_height = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
// create data
|
||||
unsigned char data[20] {};
|
||||
|
||||
// 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);
|
||||
auto offset_y = (int) (window_height / 76.0 / 3.0);
|
||||
std::vector<TouchPoint> touch_points;
|
||||
touch_get_points(touch_points);
|
||||
for (auto &point : touch_points) {
|
||||
|
||||
// get touch point coordinates
|
||||
auto x = point.x;
|
||||
auto y = point.y;
|
||||
|
||||
// rotate touch points for KBR as it runs in landscape
|
||||
if (is_landscape) {
|
||||
x = point.y;
|
||||
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
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
// copy data to buffer
|
||||
memcpy(lpBuffer, data, 20);
|
||||
|
||||
// update frame logging
|
||||
if (log_fps) {
|
||||
log_frames++;
|
||||
if (log_time < get_system_seconds()) {
|
||||
if (log_time > 0) {
|
||||
log_info("reflecbeat", "polling at {} touch frames per second", log_frames);
|
||||
}
|
||||
log_frames = 0;
|
||||
log_time = get_system_seconds();
|
||||
}
|
||||
}
|
||||
|
||||
// return amount of bytes written
|
||||
return 20;
|
||||
}
|
||||
|
||||
int games::rb::ReflecBeatTouchDeviceHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
|
||||
return (int) nNumberOfBytesToWrite;
|
||||
}
|
||||
|
||||
int games::rb::ReflecBeatTouchDeviceHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool games::rb::ReflecBeatTouchDeviceHandle::close() {
|
||||
|
||||
// detach touch module
|
||||
touch_detach();
|
||||
|
||||
return true;
|
||||
}
|
||||
33
games/rb/touch.h
Normal file
33
games/rb/touch.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "hooks/devicehook.h"
|
||||
|
||||
namespace games::rb {
|
||||
|
||||
class ReflecBeatTouchDeviceHandle : public CustomHandle {
|
||||
private:
|
||||
|
||||
// state
|
||||
int window_width = 1080;
|
||||
int window_height = 1920;
|
||||
|
||||
// logging
|
||||
bool log_fps = false;
|
||||
uint64_t log_time = 0;
|
||||
int log_frames = 0;
|
||||
|
||||
void grid_insert(unsigned char *data, int cursor_x, int cursor_y);
|
||||
|
||||
public:
|
||||
|
||||
ReflecBeatTouchDeviceHandle(bool log_fps);
|
||||
|
||||
bool open(LPCWSTR lpFileName) override;
|
||||
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
|
||||
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
|
||||
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
|
||||
DWORD nOutBufferSize) override;
|
||||
bool close() override;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user