Initial re-upload of spice2x-24-08-24
This commit is contained in:
466
games/drs/drs.cpp
Normal file
466
games/drs/drs.cpp
Normal file
@@ -0,0 +1,466 @@
|
||||
#include "drs.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <thread>
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "games/game.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/memutils.h"
|
||||
#include "misc/vrutil.h"
|
||||
|
||||
#pragma pack(push)
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
WORD unk1;
|
||||
WORD unk2;
|
||||
WORD device_id;
|
||||
WORD vid;
|
||||
WORD pid;
|
||||
WORD pvn;
|
||||
WORD max_point_num;
|
||||
};
|
||||
uint8_t raw[2356];
|
||||
};
|
||||
} dev_info_t;
|
||||
|
||||
typedef struct {
|
||||
DWORD cid;
|
||||
DWORD type;
|
||||
DWORD unused;
|
||||
DWORD y;
|
||||
DWORD x;
|
||||
DWORD height;
|
||||
DWORD width;
|
||||
DWORD unk8;
|
||||
} touch_data_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
enum touch_type {
|
||||
TS_DOWN = 1,
|
||||
TS_MOVE = 2,
|
||||
TS_UP = 3,
|
||||
};
|
||||
|
||||
void *user_data = nullptr;
|
||||
void (*touch_callback)(
|
||||
dev_info_t *dev_info,
|
||||
const touch_data_t *touch_data,
|
||||
int touch_points,
|
||||
int unk1,
|
||||
const void *user_data);
|
||||
|
||||
namespace games::drs {
|
||||
|
||||
void* TouchSDK_Constructor(void* in) {
|
||||
return in;
|
||||
}
|
||||
|
||||
bool TouchSDK_SendData(dev_info_t*,
|
||||
unsigned char * const, int, unsigned char * const,
|
||||
unsigned char* output, int output_size) {
|
||||
|
||||
// fake success
|
||||
if (output_size >= 4) {
|
||||
output[0] = 0xfc;
|
||||
output[1] = 0xa5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_SetSignalInit(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void TouchSDK_Destructor(void* This) {
|
||||
}
|
||||
|
||||
int TouchSDK_GetYLedTotal(dev_info_t*, int) {
|
||||
return 53;
|
||||
}
|
||||
|
||||
int TouchSDK_GetXLedTotal(dev_info_t*, int) {
|
||||
return 41;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableTouch(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableDrag(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableWheel(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableRightClick(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_SetMultiTouchMode(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_EnableTouchWidthData(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_EnableRawData(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_SetAllEnable(dev_info_t*, bool, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int TouchSDK_GetTouchDeviceCount(void* This) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int TouchSDK_GetTouchSDKVersion(void) {
|
||||
return 0x01030307;
|
||||
}
|
||||
|
||||
int TouchSDK_InitTouch(void* This, dev_info_t *devices, int max_devices, void* touch_event_cb,
|
||||
void* hotplug_callback, void* userdata) {
|
||||
|
||||
// fake touch device
|
||||
memset(devices, 0, sizeof(devices[0].raw));
|
||||
devices[0].unk1 = 0x1122;
|
||||
devices[0].unk2 = 0x3344;
|
||||
devices[0].device_id = 0;
|
||||
devices[0].vid = 0xDEAD;
|
||||
devices[0].pid = 0xBEEF;
|
||||
devices[0].pvn = 0xC0DE;
|
||||
devices[0].max_point_num = 16;
|
||||
|
||||
// remember provided callback and userdata
|
||||
touch_callback = (decltype(touch_callback)) touch_event_cb;
|
||||
user_data = userdata;
|
||||
|
||||
// success
|
||||
return 1;
|
||||
}
|
||||
|
||||
char DRS_TAPELED[38 * 49][3] {};
|
||||
bool VR_STARTED = false;
|
||||
bool DISABLE_TOUCH = false;
|
||||
bool TRANSPOSE_TOUCH = false;
|
||||
linalg::aliases::float3 VR_SCALE(100, 100, 1.f);
|
||||
linalg::aliases::float3 VR_OFFSET(0.f, 0.f, -0.1f);
|
||||
float VR_ROTATION = 0.f;
|
||||
VRFoot VR_FOOTS[2] {
|
||||
{1},
|
||||
{2},
|
||||
};
|
||||
|
||||
std::vector<TouchEvent> TOUCH_EVENTS;
|
||||
|
||||
inline DWORD scale_double_to_xy(double val) {
|
||||
return static_cast<DWORD>(val * 32768);
|
||||
}
|
||||
|
||||
inline DWORD scale_double_to_height(double val) {
|
||||
return static_cast<DWORD>(val * 1312);
|
||||
}
|
||||
|
||||
inline DWORD scale_double_to_width(double val) {
|
||||
return static_cast<DWORD>(val * 1696);
|
||||
}
|
||||
|
||||
void fire_touches(drs_touch_t *events, size_t event_count) {
|
||||
|
||||
// check callback first
|
||||
if (!touch_callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
// generate touch data
|
||||
auto game_touches = std::make_unique<touch_data_t[]>(event_count);
|
||||
for (size_t i = 0; i < event_count; i++) {
|
||||
|
||||
// initialize touch value
|
||||
game_touches[i].cid = (DWORD) events[i].id;
|
||||
game_touches[i].unk8 = 0;
|
||||
|
||||
// copy scaled values
|
||||
game_touches[i].x = scale_double_to_xy(events[i].x);
|
||||
game_touches[i].y = scale_double_to_xy(events[i].y);
|
||||
game_touches[i].width = scale_double_to_width(events[i].width);
|
||||
game_touches[i].height = scale_double_to_height(events[i].height);
|
||||
|
||||
// decide touch type
|
||||
switch(events[i].type) {
|
||||
case DRS_DOWN:
|
||||
game_touches[i].type = TS_DOWN;
|
||||
break;
|
||||
case DRS_UP:
|
||||
game_touches[i].type = TS_UP;
|
||||
break;
|
||||
case DRS_MOVE:
|
||||
game_touches[i].type = TS_MOVE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// build device information
|
||||
dev_info_t dev;
|
||||
dev.unk1 = 0;
|
||||
dev.unk2 = 0;
|
||||
dev.device_id = 0;
|
||||
dev.vid = 0xDEAD;
|
||||
dev.pid = 0xBEEF;
|
||||
dev.pvn = 0xC0DE;
|
||||
dev.max_point_num = 16;
|
||||
|
||||
// fire callback
|
||||
touch_callback(&dev, game_touches.get(), (int) event_count, 0, user_data);
|
||||
}
|
||||
|
||||
uint32_t VRFoot::get_index() {
|
||||
if (index == ~0u) {
|
||||
if (id == 1) return vrutil::INDEX_LEFT;
|
||||
if (id == 2) return vrutil::INDEX_RIGHT;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
linalg::aliases::float3 VRFoot::to_world(linalg::aliases::float3 pos) {
|
||||
pos = linalg::aliases::float3(-pos.z, pos.x, pos.y);
|
||||
const float deg_to_rad = (float) (1 / 180.f * M_PI);
|
||||
auto s = sinf(VR_ROTATION * deg_to_rad);
|
||||
auto c = cosf(VR_ROTATION * deg_to_rad);
|
||||
pos = linalg::aliases::float3(pos.x * c - pos.y * s,
|
||||
pos.x * s + pos.y * c,
|
||||
pos.z);
|
||||
return pos * VR_SCALE + VR_OFFSET;
|
||||
}
|
||||
|
||||
void start_vr() {
|
||||
if (vrutil::STATUS != vrutil::VRStatus::Running) return;
|
||||
if (!VR_STARTED) {
|
||||
VR_STARTED = true;
|
||||
std::thread t([] {
|
||||
log_info("drs", "starting VR thread");
|
||||
|
||||
// dance floor plane
|
||||
const linalg::aliases::float3 plane_normal(0, 0, 1);
|
||||
const linalg::aliases::float3 plane_point(0, 0, 0);
|
||||
const float touch_width = 1.f;
|
||||
const float touch_height = 1.f;
|
||||
|
||||
// main loop
|
||||
while (vrutil::STATUS == vrutil::VRStatus::Running) {
|
||||
|
||||
// iterate foots
|
||||
for (auto &foot : VR_FOOTS) {
|
||||
vr::TrackedDevicePose_t pose;
|
||||
vr::VRControllerState_t state;
|
||||
vrutil::get_con_pose(foot.get_index(), &pose, &state);
|
||||
|
||||
// only accept valid poses
|
||||
if (pose.bPoseIsValid) {
|
||||
auto length = std::max(foot.length, 0.001f);
|
||||
|
||||
// get components
|
||||
auto translation = foot.to_world(vrutil::get_translation(
|
||||
pose.mDeviceToAbsoluteTracking));
|
||||
auto direction = -linalg::qzdir(linalg::qmul(
|
||||
vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m),
|
||||
foot.rotation));
|
||||
direction = linalg::aliases::float3 {
|
||||
-direction.z, direction.x, direction.y
|
||||
};
|
||||
|
||||
// get intersection point
|
||||
auto intersection = vrutil::intersect_point(
|
||||
direction, translation,
|
||||
plane_normal, plane_point);
|
||||
auto distance = linalg::distance(
|
||||
translation, intersection);
|
||||
|
||||
// update event details
|
||||
foot.height = std::max(0.f, translation.z - intersection.z);
|
||||
foot.event.id = foot.id;
|
||||
foot.event.x = (intersection.x / 38.f) * touch_width;
|
||||
foot.event.y = (intersection.y / 49.f) * touch_height;
|
||||
if (translation.z > intersection.z) {
|
||||
foot.event.width = foot.size_base
|
||||
+ foot.size_scale * std::max(0.f, 1.f - distance / length);
|
||||
} else {
|
||||
foot.event.width = foot.size_base + foot.size_scale;
|
||||
}
|
||||
foot.event.height = foot.event.width;
|
||||
|
||||
// check if controller points down
|
||||
if (direction.z < 0) {
|
||||
|
||||
// check if plane in range
|
||||
if (distance <= length) {
|
||||
|
||||
// check previous event
|
||||
switch (foot.event.type) {
|
||||
case DRS_UP:
|
||||
|
||||
// generate down event
|
||||
foot.event.type = DRS_DOWN;
|
||||
break;
|
||||
|
||||
case DRS_DOWN:
|
||||
case DRS_MOVE:
|
||||
|
||||
// generate move event
|
||||
foot.event.type = DRS_MOVE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// send event
|
||||
drs::fire_touches(&foot.event, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// foot not intersecting with plane
|
||||
switch (foot.event.type) {
|
||||
case DRS_DOWN:
|
||||
case DRS_MOVE:
|
||||
|
||||
// generate up event
|
||||
foot.event.type = DRS_UP;
|
||||
drs::fire_touches(&foot.event, 1);
|
||||
break;
|
||||
|
||||
case DRS_UP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// slow down
|
||||
vrutil::scan();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
VR_STARTED = false;
|
||||
return nullptr;
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
}
|
||||
|
||||
void start_touch() {
|
||||
std::thread t([] {
|
||||
log_info("drs", "starting touch input thread");
|
||||
|
||||
// main loop
|
||||
while (TRUE) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
TOUCH_EVENTS.clear();
|
||||
touch_get_events(TOUCH_EVENTS);
|
||||
for (auto &te : TOUCH_EVENTS) {
|
||||
drs_touch_t drs_event;
|
||||
switch (te.type) {
|
||||
case TOUCH_DOWN:
|
||||
drs_event.type = DRS_DOWN;
|
||||
break;
|
||||
case TOUCH_UP:
|
||||
drs_event.type = DRS_UP;
|
||||
break;
|
||||
case TOUCH_MOVE:
|
||||
drs_event.type = DRS_MOVE;
|
||||
break;
|
||||
}
|
||||
drs_event.id = te.id;
|
||||
|
||||
// DRS uses 100x100 (px) as default foot size, so use that
|
||||
const float w = 100.1/1920.f;
|
||||
const float h = 100.1/1080.f;
|
||||
drs_event.width = w;
|
||||
drs_event.height = h;
|
||||
|
||||
const float x = te.x / 1920.f;
|
||||
const float y = te.y / 1080.f;
|
||||
// note that only x-y are transposed, not w-h
|
||||
if (TRANSPOSE_TOUCH) {
|
||||
drs_event.x = y;
|
||||
drs_event.y = x;
|
||||
} else {
|
||||
drs_event.x = x;
|
||||
drs_event.y = y;
|
||||
}
|
||||
drs::fire_touches(&drs_event, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
|
||||
DRSGame::DRSGame() : Game("DANCERUSH") {
|
||||
}
|
||||
|
||||
void DRSGame::attach() {
|
||||
Game::attach();
|
||||
|
||||
// TouchSDK hooks
|
||||
detour::iat("??0TouchSDK@@QEAA@XZ",
|
||||
(void *) &TouchSDK_Constructor, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?SendData@TouchSDK@@QEAA_NU_DeviceInfo@@QEAEH1HH@Z",
|
||||
(void *) &TouchSDK_SendData, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?SetSignalInit@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_SetSignalInit, avs::game::DLL_INSTANCE);
|
||||
detour::iat("??1TouchSDK@@QEAA@XZ",
|
||||
(void *) &TouchSDK_Destructor, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?GetYLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_GetYLedTotal, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?GetXLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_GetXLedTotal, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?DisableTouch@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_DisableTouch, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?DisableDrag@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_DisableDrag, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?DisableWheel@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_DisableWheel, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?DisableRightClick@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_DisableRightClick, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?SetMultiTouchMode@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_SetMultiTouchMode, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?EnableTouchWidthData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_EnableTouchWidthData, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?EnableRawData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
|
||||
(void *) &TouchSDK_EnableRawData, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?SetAllEnable@TouchSDK@@QEAA_NU_DeviceInfo@@_NH@Z",
|
||||
(void *) &TouchSDK_SetAllEnable, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?GetTouchDeviceCount@TouchSDK@@QEAAHXZ",
|
||||
(void *) &TouchSDK_GetTouchDeviceCount, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?GetTouchSDKVersion@TouchSDK@@QEAAIXZ",
|
||||
(void *) &TouchSDK_GetTouchSDKVersion, avs::game::DLL_INSTANCE);
|
||||
detour::iat("?InitTouch@TouchSDK@@QEAAHPEAU_DeviceInfo@@HP6AXU2@PEBU_TouchPointData@@HHPEBX@ZP6AX1_N3@ZPEAX@Z",
|
||||
(void *) &TouchSDK_InitTouch, avs::game::DLL_INSTANCE);
|
||||
|
||||
if (vrutil::STATUS == vrutil::VRStatus::Running) {
|
||||
start_vr();
|
||||
} else if (!DISABLE_TOUCH) {
|
||||
start_touch();
|
||||
} else {
|
||||
log_info("drs", "no native input method detected");
|
||||
}
|
||||
}
|
||||
|
||||
void DRSGame::detach() {
|
||||
Game::detach();
|
||||
}
|
||||
}
|
||||
56
games/drs/drs.h
Normal file
56
games/drs/drs.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "games/game.h"
|
||||
#include "external/linalg.h"
|
||||
#include "touch/touch.h"
|
||||
|
||||
namespace games::drs {
|
||||
|
||||
enum DRS_TOUCH_TYPE {
|
||||
DRS_DOWN = 0,
|
||||
DRS_UP = 1,
|
||||
DRS_MOVE = 2,
|
||||
};
|
||||
|
||||
typedef struct drs_touch {
|
||||
int type = DRS_UP;
|
||||
int id = 0;
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
double width = 1;
|
||||
double height = 1;
|
||||
} drs_touch_t;
|
||||
|
||||
struct VRFoot {
|
||||
uint32_t id;
|
||||
uint32_t index = ~0u;
|
||||
float length = 3.1f;
|
||||
float size_base = 0.05f;
|
||||
float size_scale = 0.1f;
|
||||
float height = 3.f;
|
||||
linalg::aliases::float4 rotation {0, 0, 0, 1};
|
||||
drs_touch_t event {};
|
||||
uint32_t get_index();
|
||||
linalg::aliases::float3 to_world(linalg::aliases::float3 pos);
|
||||
};
|
||||
|
||||
extern char DRS_TAPELED[38 * 49][3];
|
||||
extern linalg::aliases::float3 VR_SCALE;
|
||||
extern linalg::aliases::float3 VR_OFFSET;
|
||||
extern float VR_ROTATION;
|
||||
extern VRFoot VR_FOOTS[2];
|
||||
extern std::vector<TouchEvent> TOUCH_EVENTS;
|
||||
extern bool DISABLE_TOUCH;
|
||||
extern bool TRANSPOSE_TOUCH;
|
||||
|
||||
void fire_touches(drs_touch_t *events, size_t event_count);
|
||||
void start_vr();
|
||||
void start_touch();
|
||||
|
||||
class DRSGame : public games::Game {
|
||||
public:
|
||||
DRSGame();
|
||||
virtual void attach() override;
|
||||
virtual void detach() override;
|
||||
};
|
||||
}
|
||||
57
games/drs/io.cpp
Normal file
57
games/drs/io.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "io.h"
|
||||
|
||||
std::vector<Button> &games::drs::get_buttons() {
|
||||
static std::vector<Button> buttons;
|
||||
|
||||
if (buttons.empty()) {
|
||||
buttons = GameAPI::Buttons::getButtons("DANCERUSH");
|
||||
|
||||
GameAPI::Buttons::sortButtons(
|
||||
&buttons,
|
||||
"Service",
|
||||
"Test",
|
||||
"Coin Mech",
|
||||
"P1 Start",
|
||||
"P1 Up",
|
||||
"P1 Down",
|
||||
"P1 Left",
|
||||
"P1 Right",
|
||||
"P2 Start",
|
||||
"P2 Up",
|
||||
"P2 Down",
|
||||
"P2 Left",
|
||||
"P2 Right"
|
||||
);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
std::vector<Light> &games::drs::get_lights() {
|
||||
static std::vector<Light> lights;
|
||||
|
||||
if (lights.empty()) {
|
||||
lights = GameAPI::Lights::getLights("DANCERUSH");
|
||||
GameAPI::Lights::sortLights(
|
||||
&lights,
|
||||
"P1 Start",
|
||||
"P1 Menu Up",
|
||||
"P1 Menu Down",
|
||||
"P1 Menu Left",
|
||||
"P1 Menu Right",
|
||||
"P2 Start",
|
||||
"P2 Menu Up",
|
||||
"P2 Menu Down",
|
||||
"P2 Menu Left",
|
||||
"P2 Menu Right",
|
||||
"Card Reader R",
|
||||
"Card Reader G",
|
||||
"Card Reader B",
|
||||
"Title Panel R",
|
||||
"Title Panel G",
|
||||
"Title Panel B"
|
||||
);
|
||||
}
|
||||
|
||||
return lights;
|
||||
}
|
||||
52
games/drs/io.h
Normal file
52
games/drs/io.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "cfg/api.h"
|
||||
|
||||
namespace games::drs {
|
||||
|
||||
// all buttons in correct order
|
||||
namespace Buttons {
|
||||
enum {
|
||||
Service,
|
||||
Test,
|
||||
CoinMech,
|
||||
P1_Start,
|
||||
P1_Up,
|
||||
P1_Down,
|
||||
P1_Left,
|
||||
P1_Right,
|
||||
P2_Start,
|
||||
P2_Up,
|
||||
P2_Down,
|
||||
P2_Left,
|
||||
P2_Right
|
||||
};
|
||||
}
|
||||
|
||||
// all lights in correct order
|
||||
namespace Lights {
|
||||
enum {
|
||||
P1_START,
|
||||
P1_MENU_UP,
|
||||
P1_MENU_DOWN,
|
||||
P1_MENU_LEFT,
|
||||
P1_MENU_RIGHT,
|
||||
P2_START,
|
||||
P2_MENU_UP,
|
||||
P2_MENU_DOWN,
|
||||
P2_MENU_LEFT,
|
||||
P2_MENU_RIGHT,
|
||||
CARD_READER_R,
|
||||
CARD_READER_G,
|
||||
CARD_READER_B,
|
||||
TITLE_PANEL_R,
|
||||
TITLE_PANEL_G,
|
||||
TITLE_PANEL_B,
|
||||
};
|
||||
}
|
||||
|
||||
// getters
|
||||
std::vector<Button> &get_buttons();
|
||||
std::vector<Light> &get_lights();
|
||||
}
|
||||
Reference in New Issue
Block a user