Added lightgun laser emulation
This commit is contained in:
parent
c658777645
commit
caf7927445
|
@ -31,7 +31,7 @@
|
|||
#include <Commctrl.h>
|
||||
#include <string>
|
||||
|
||||
#define LIGHTGUN_NUM_BUTTONS 16
|
||||
#define LIGHTGUN_NUM_BUTTONS 17
|
||||
#define XBOX_CTRL_NUM_BUTTONS 25
|
||||
#define SBC_NUM_BUTTONS 56
|
||||
#define HIGHEST_NUM_BUTTONS SBC_NUM_BUTTONS
|
||||
|
|
|
@ -178,7 +178,7 @@ const auto InputDevice::FindPort(std::string_view Port) const
|
|||
});
|
||||
}
|
||||
|
||||
void InputDevice::SetPort(std::string_view Port, bool Connect)
|
||||
void InputDevice::SetPort2(std::string_view Port, bool Connect)
|
||||
{
|
||||
if (Connect) {
|
||||
m_XboxPort.emplace_back(Port);
|
||||
|
|
|
@ -122,7 +122,8 @@ public:
|
|||
// retrieves the port this device is attached to
|
||||
bool GetPort(std::string_view Port) const;
|
||||
// sets the port this device is attached to
|
||||
void SetPort(std::string_view Port, bool Connect);
|
||||
// NOTE: using SetPort2 to avoid a collision with the SetPort macro provided by Windows headers
|
||||
void SetPort2(std::string_view Port, bool Connect);
|
||||
// retuns true if it is a libusb device, false otherwise
|
||||
virtual bool IsLibusb() const { return false; };
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
|
||||
#include <core\kernel\exports\xboxkrnl.h> // For PKINTERRUPT, etc.
|
||||
#include "D3dx9math.h" // For the matrix math functions
|
||||
#include "SdlJoystick.h"
|
||||
#include "XInputPad.h"
|
||||
#include "RawDevice.h"
|
||||
|
@ -273,7 +274,7 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack)
|
|||
else {
|
||||
auto host_dev = g_InputDeviceManager.FindDevice(port);
|
||||
if (host_dev != nullptr) {
|
||||
host_dev->SetPort(port, false);
|
||||
host_dev->SetPort2(port, false);
|
||||
}
|
||||
if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
|
||||
if (type != to_underlying(dev->type)) {
|
||||
|
@ -310,7 +311,7 @@ void InputDeviceManager::DisconnectDevice(DeviceState *dev, std::string_view por
|
|||
}
|
||||
auto host_dev = g_InputDeviceManager.FindDevice(port);
|
||||
if (host_dev != nullptr) {
|
||||
host_dev->SetPort(port, false);
|
||||
host_dev->SetPort2(port, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,7 +330,7 @@ void InputDeviceManager::BindHostDevice(int type, std::string_view port)
|
|||
g_EmuShared->GetInputDevNameSettings(dev_name, port_num);
|
||||
auto dev = FindDevice(std::string(dev_name));
|
||||
if (dev != nullptr) {
|
||||
dev->SetPort(port, true);
|
||||
dev->SetPort2(port, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -356,7 +357,7 @@ void InputDeviceManager::BindHostDevice(int type, std::string_view port)
|
|||
});
|
||||
dev->SetBindings(index, (it != controls.end()) ? *it : nullptr, port_str);
|
||||
}
|
||||
dev->SetPort(port, true);
|
||||
dev->SetPort2(port, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,24 +492,36 @@ bool InputDeviceManager::UpdateInputLightgun(std::shared_ptr<InputDevice> &Devic
|
|||
// We change the toggle buttons only when a press -> release input transaction is completed
|
||||
// 0 -> Turbo left
|
||||
// 1 -> Turbo right
|
||||
// 2 -> Laser
|
||||
XpadInput *in_buf = reinterpret_cast<XpadInput *>(static_cast<uint8_t *>(Buffer) + XID_PACKET_HEADER);
|
||||
uint8_t last_turbo = g_devs[Port_num].info.ligthgun.turbo;
|
||||
for (int i = 14, j = 0; i < 16; i++, j++) {
|
||||
g_devs[Port_num].info.ligthgun.last_turbo = g_devs[Port_num].info.ligthgun.turbo;
|
||||
for (int i = 14, j = 0; i < 17; i++, j++) {
|
||||
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
|
||||
uint8_t curr_state = static_cast<uint8_t>(!!state);
|
||||
if ((~curr_state) & ((g_devs[Port_num].info.ligthgun.last_turbo_state >> j) & 1)) {
|
||||
if (j == 0) {
|
||||
if ((~curr_state) & ((g_devs[Port_num].info.ligthgun.last_in_state >> j) & 1)) {
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
if (g_devs[Port_num].info.ligthgun.turbo != 2) {
|
||||
g_devs[Port_num].info.ligthgun.turbo += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (g_devs[Port_num].info.ligthgun.turbo != 0) {
|
||||
g_devs[Port_num].info.ligthgun.turbo -= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
g_devs[Port_num].info.ligthgun.laser ^= 1;
|
||||
if (g_devs[Port_num].info.ligthgun.laser) {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
(g_devs[Port_num].info.ligthgun.last_turbo_state &= ~(1 << j)) |= (curr_state << j);
|
||||
(g_devs[Port_num].info.ligthgun.last_in_state &= ~(1 << j)) |= (curr_state << j);
|
||||
}
|
||||
|
||||
in_buf->wButtons = XINPUT_LIGHTGUN_ONSCREEN;
|
||||
|
@ -532,7 +545,7 @@ bool InputDeviceManager::UpdateInputLightgun(std::shared_ptr<InputDevice> &Devic
|
|||
// Turbo mode 2
|
||||
start_idx = 8;
|
||||
++g_devs[Port_num].info.ligthgun.turbo_delay;
|
||||
if (last_turbo != g_devs[Port_num].info.ligthgun.turbo) {
|
||||
if (g_devs[Port_num].info.ligthgun.last_turbo != g_devs[Port_num].info.ligthgun.turbo) {
|
||||
g_devs[Port_num].info.ligthgun.turbo_delay = 0;
|
||||
}
|
||||
if (g_devs[Port_num].info.ligthgun.turbo_delay == LIGHTGUN_GRIP_DELAY) {
|
||||
|
@ -887,3 +900,51 @@ void InputDeviceManager::HotplugHandler(bool is_sdl)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImVec2 InputDeviceManager::CalcLaserPos(int port)
|
||||
{
|
||||
static ImVec2 laser_coord[XBOX_NUM_PORTS] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
|
||||
|
||||
// If somebody else is currently holding the lock, we won't wait and instead we report the last known laser position
|
||||
if (m_Mtx.try_lock()) {
|
||||
static D3DXVECTOR4 coeff_vec;
|
||||
|
||||
// If the rendering window was not resized, we can skip calculating the conversion matrix
|
||||
if (g_bRenderWindowResized) {
|
||||
g_bRenderWindowResized = false;
|
||||
|
||||
// We convert the laser input coordinates given by xinput (in the sThumbLXY members of XpadInput) with the procedure described in the link below
|
||||
// https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/samples/jj635757(v=vs.85)?redirectedfrom=MSDN
|
||||
// NOTE: the d3d math functions work even when d3d was not intialized, which happens when running with LLE GPU turned on
|
||||
/*
|
||||
xinput -> screen
|
||||
v = M^-1 * u
|
||||
width 0 0 1 0 a
|
||||
height = 0 0 0 1 * b
|
||||
0 -32768 32767 1 0 c
|
||||
0 -32767 -32768 0 1 d
|
||||
*/
|
||||
RECT rect;
|
||||
GetClientRect(m_hwnd, &rect);
|
||||
const auto width = std::max(rect.right - rect.left, 1l);
|
||||
const auto height = std::max(rect.bottom - rect.top, 1l);
|
||||
D3DXMATRIX inverted_mtx, transposed_mtx;
|
||||
D3DXMATRIX src_mtx(0, 0, 1, 0, 0, 0, 0, 1, -32768, 32767, 1, 0, -32767, -32768, 0, 1);
|
||||
D3DXVECTOR4 screen_vec(width, height, 0, 0);
|
||||
D3DXMatrixInverse(&inverted_mtx, nullptr, &src_mtx);
|
||||
D3DXMatrixTranspose(&transposed_mtx, &inverted_mtx);
|
||||
D3DXVec4Transform(&coeff_vec, &screen_vec, &transposed_mtx);
|
||||
}
|
||||
|
||||
// x' = ax + by + c
|
||||
// y' = bx - ay + d
|
||||
int16_t laser_x = g_devs[port].info.buff.ctrl.InBuffer.sThumbLX;
|
||||
int16_t laser_y = g_devs[port].info.buff.ctrl.InBuffer.sThumbLY;
|
||||
laser_coord[port].x = coeff_vec.x * laser_x + coeff_vec.y * laser_y + coeff_vec.z;
|
||||
laser_coord[port].y = coeff_vec.y * laser_x - coeff_vec.x * laser_y + coeff_vec.w;
|
||||
|
||||
m_Mtx.unlock();
|
||||
}
|
||||
|
||||
return laser_coord[port];
|
||||
}
|
||||
|
|
|
@ -31,11 +31,7 @@
|
|||
#include <thread>
|
||||
#include "InputDevice.h"
|
||||
#include "EmuDevice.h"
|
||||
|
||||
// Prevent a collision with the SetPort provided by Windows
|
||||
#ifdef WIN32
|
||||
#undef SetPort
|
||||
#endif
|
||||
#include <imgui.h>
|
||||
|
||||
#define PORT_INVALID -1
|
||||
#define PORT_1 0
|
||||
|
@ -162,9 +158,11 @@ struct XidSBCOutput {
|
|||
struct LightGunData {
|
||||
xbox::short_xt offset_x;
|
||||
xbox::short_xt offset_y;
|
||||
uint8_t last_turbo_state;
|
||||
uint8_t last_in_state;
|
||||
uint8_t last_turbo;
|
||||
uint8_t turbo_delay;
|
||||
uint8_t turbo;
|
||||
uint8_t laser;
|
||||
};
|
||||
|
||||
struct SbcData {
|
||||
|
@ -234,6 +232,8 @@ public:
|
|||
void UpdateOpt(bool is_gui);
|
||||
// device hotplug event handler
|
||||
void HotplugHandler(bool is_sdl);
|
||||
// converts xinput -> screen coordinates to display the lightgun laser on the rendering window
|
||||
ImVec2 CalcLaserPos(int port);
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -137,6 +137,7 @@ inline int button_lightgun_id[LIGHTGUN_NUM_BUTTONS] = {
|
|||
IDC_LG_AIM_NEGY,
|
||||
IDC_TURBO_LEFT,
|
||||
IDC_TURBO_RIGHT,
|
||||
IDC_LASER,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -244,6 +245,7 @@ inline constexpr const char *button_lightgun_names[LIGHTGUN_NUM_BUTTONS] = {
|
|||
"Aim Y-",
|
||||
"Turbo Left",
|
||||
"Turbo Right",
|
||||
"Laser",
|
||||
};
|
||||
|
||||
constexpr bool check_button_name_size(unsigned max_num_buttons)
|
||||
|
|
|
@ -15,7 +15,14 @@
|
|||
|
||||
#include "core/kernel/init/CxbxKrnl.h"
|
||||
|
||||
bool ImGuiUI::Initialize()
|
||||
const ImColor ImGuiUI::m_laser_col[4] = {
|
||||
ImColor(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)), // ply1: red
|
||||
ImColor(ImVec4(0.0f, 1.0f, 0.0f, 1.0f)), // ply2: green
|
||||
ImColor(ImVec4(0.0f, 0.0f, 1.0f, 1.0f)), // ply3: blue
|
||||
ImColor(ImVec4(1.0f, 1.0f, 0.0f, 1.0f)) // ply4: yellow
|
||||
};
|
||||
|
||||
bool ImGuiUI::Initialize(int backbuffer_scale)
|
||||
{
|
||||
IMGUI_CHECKVERSION();
|
||||
m_imgui_context = ImGui::CreateContext();
|
||||
|
@ -48,6 +55,7 @@ bool ImGuiUI::Initialize()
|
|||
|
||||
// Internal initialize (when necessary, move into its own function.)
|
||||
fps_counter = 30.0f;
|
||||
m_backbuffer_scale = backbuffer_scale;
|
||||
|
||||
// Miscs
|
||||
m_audio.Initialize();
|
||||
|
@ -190,3 +198,12 @@ void ImGuiUI::DrawWidgets()
|
|||
|
||||
m_audio.DrawWidgets(m_is_focus, input_handler);
|
||||
}
|
||||
|
||||
void ImGuiUI::DrawLightgunLaser(int port)
|
||||
{
|
||||
ImGui::Begin("Laser", nullptr, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoDecoration);
|
||||
|
||||
ImGui::GetForegroundDrawList()->AddCircleFilled(g_InputDeviceManager.CalcLaserPos(port), 10 * m_backbuffer_scale, m_laser_col[port], 32);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
|
@ -32,10 +32,11 @@ public:
|
|||
|
||||
void DrawMenu();
|
||||
void DrawWidgets();
|
||||
void DrawLightgunLaser(int port);
|
||||
|
||||
protected:
|
||||
|
||||
bool Initialize();
|
||||
bool Initialize(int backbuffer_scale);
|
||||
void Shutdown();
|
||||
|
||||
template<class C, class T>
|
||||
|
@ -61,6 +62,8 @@ protected:
|
|||
overlay_settings m_settings;
|
||||
unsigned int m_lle_flags;
|
||||
float fps_counter;
|
||||
int m_backbuffer_scale;
|
||||
static const ImColor m_laser_col[4];
|
||||
// Make them as settings storage.
|
||||
/*bool m_show_fps;
|
||||
bool m_show_LLE_stats;
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
std::unique_ptr<RenderBase> g_renderbase;
|
||||
|
||||
bool RenderBase::Initialize()
|
||||
bool RenderBase::Initialize(int backbuffer_scale)
|
||||
{
|
||||
if (!ImGuiUI::Initialize()) {
|
||||
if (!ImGuiUI::Initialize(backbuffer_scale)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
RenderBase() = default;
|
||||
virtual ~RenderBase() = default;
|
||||
|
||||
virtual bool Initialize();
|
||||
virtual bool Initialize(int backbuffer_scale);
|
||||
virtual void Shutdown();
|
||||
|
||||
template<class C, class T>
|
||||
|
|
|
@ -87,6 +87,7 @@ using namespace std::literals::chrono_literals;
|
|||
|
||||
// Global(s)
|
||||
HWND g_hEmuWindow = NULL; // rendering window
|
||||
bool g_bRenderWindowResized = true; // indicates that the rendering window has had its size changed
|
||||
bool g_bClipCursor = false; // indicates that the mouse cursor should be confined inside the rendering window
|
||||
IDirect3DDevice9Ex *g_pD3DDevice = nullptr; // Direct3D Device
|
||||
|
||||
|
@ -194,6 +195,11 @@ static void CxbxImGui_RenderD3D9(ImGuiUI* m_imgui, IDirect3DSurface9* renderTarg
|
|||
|
||||
m_imgui->DrawMenu();
|
||||
m_imgui->DrawWidgets();
|
||||
for (int port = PORT_1; port < XBOX_NUM_PORTS; ++port) {
|
||||
if (g_devs[port].type == XBOX_INPUT_DEVICE::LIGHTGUN && g_devs[port].info.ligthgun.laser) {
|
||||
m_imgui->DrawLightgunLaser(port);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndFrame();
|
||||
|
||||
|
@ -663,7 +669,7 @@ void CxbxInitWindow(bool bFullInit)
|
|||
|
||||
SetFocus(g_hEmuWindow);
|
||||
g_renderbase = std::unique_ptr<RenderBase>(new RenderBase());
|
||||
g_renderbase->Initialize();
|
||||
g_renderbase->Initialize(g_RenderUpscaleFactor);
|
||||
|
||||
ImGui_ImplWin32_Init(g_hEmuWindow);
|
||||
g_renderbase->SetWindowRelease([] {
|
||||
|
@ -2032,6 +2038,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
|
|||
|
||||
case WM_SIZE:
|
||||
{
|
||||
g_bRenderWindowResized = true;
|
||||
switch(wParam)
|
||||
{
|
||||
case SIZE_RESTORED:
|
||||
|
|
|
@ -265,8 +265,9 @@ void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type,
|
|||
dev->info.ucInputStateSize = sizeof(XpadInput);
|
||||
dev->info.ucFeedbackSize = sizeof(XpadOutput);
|
||||
dev->info.ligthgun.offset_x = dev->info.ligthgun.offset_x = 0;
|
||||
dev->info.ligthgun.last_turbo_state = dev->info.ligthgun.turbo = 0;
|
||||
dev->info.ligthgun.turbo_delay = 0;
|
||||
dev->info.ligthgun.last_in_state = dev->info.ligthgun.turbo_delay = 0;
|
||||
dev->info.ligthgun.turbo = dev->info.ligthgun.last_turbo = 0;
|
||||
dev->info.ligthgun.laser = 1; // laser on by default
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER):
|
||||
|
|
|
@ -187,6 +187,7 @@ bool CxbxIsElevated();
|
|||
/*! kernel thunk table */
|
||||
extern uint32_t CxbxKrnl_KernelThunkTable[379];
|
||||
|
||||
extern bool g_bRenderWindowResized;
|
||||
extern bool g_bClipCursor;
|
||||
extern bool g_CxbxPrintUEM;
|
||||
extern ULONG g_CxbxFatalErrorCode;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "common\input\InputManager.h"
|
||||
|
||||
// FIXME
|
||||
#define qemu_mutex_lock_iothread()
|
||||
#define qemu_mutex_unlock_iothread()
|
||||
|
@ -713,6 +715,11 @@ static void CxbxImGui_RenderOpenGL(ImGuiUI* m_imgui, std::nullptr_t unused)
|
|||
|
||||
m_imgui->DrawMenu();
|
||||
m_imgui->DrawWidgets();
|
||||
for (int port = PORT_1; port < XBOX_NUM_PORTS; ++port) {
|
||||
if (g_devs[port].type == XBOX_INPUT_DEVICE::LIGHTGUN && g_devs[port].info.ligthgun.laser) {
|
||||
m_imgui->DrawLightgunLaser(port);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
|
||||
static constexpr std::array<std::array<const char *, LIGHTGUN_NUM_BUTTONS>, 2> button_lightgun_default = { {
|
||||
{ "Pad N", "Pad S", "Pad W", "Pad E", "Start", "Back", "Button A", "Button B", "Button X", "Button Y", "Left X+", "Left X-",
|
||||
"Left Y+", "Left Y-", "Shoulder L", "Shoulder R" },
|
||||
{ "UP", "DOWN", "LEFT", "RIGHT", "RETURN", "SPACE", "Click 0", "Click 1", "W", "E", "Cursor X+", "Cursor X-", "Cursor Y+", "Cursor Y-", "S", "D" }
|
||||
"Left Y+", "Left Y-", "Shoulder L", "Shoulder R", "Thumb R" },
|
||||
{ "UP", "DOWN", "LEFT", "RIGHT", "RETURN", "SPACE", "Click 0", "Click 1", "W", "E", "Cursor X+", "Cursor X-", "Cursor Y+", "Cursor Y-", "S", "D", "C"}
|
||||
} };
|
||||
|
||||
static LightgunInputWindow *g_InputWindow = nullptr;
|
||||
|
@ -214,7 +214,8 @@ INT_PTR CALLBACK DlgLightgunConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, L
|
|||
case IDC_LG_AIM_POSY:
|
||||
case IDC_LG_AIM_NEGY:
|
||||
case IDC_TURBO_LEFT:
|
||||
case IDC_TURBO_RIGHT: {
|
||||
case IDC_TURBO_RIGHT:
|
||||
case IDC_LASER: {
|
||||
if (HIWORD(wParam) == BN_CLICKED) {
|
||||
g_InputWindow->BindButton(LOWORD(wParam));
|
||||
}
|
||||
|
|
|
@ -250,11 +250,14 @@ BEGIN
|
|||
LTEXT "Right",IDC_STATIC,285,129,20,14,SS_CENTERIMAGE
|
||||
PUSHBUTTON "Default Bindings",IDC_DEFAULT,362,200,69,14,BS_FLAT
|
||||
PUSHBUTTON "Clear",IDC_CLEAR,443,200,50,14,BS_FLAT
|
||||
GROUPBOX "Turbo switch",IDC_TURBO,396,66,121,121,WS_GROUP
|
||||
PUSHBUTTON "",IDC_TURBO_LEFT,443,76,57,14,BS_FLAT
|
||||
GROUPBOX "Turbo switch",IDC_POWER_SWITCH,396,66,121,52,WS_GROUP
|
||||
PUSHBUTTON "",IDC_TURBO_LEFT,443,132,57,14,BS_FLAT
|
||||
PUSHBUTTON "",IDC_TURBO_RIGHT,443,94,57,14,BS_FLAT
|
||||
LTEXT "Left",IDC_STATIC,412,76,20,14,SS_CENTERIMAGE
|
||||
LTEXT "Right",IDC_STATIC,412,94,20,14,SS_CENTERIMAGE
|
||||
GROUPBOX "Power switch",IDC_TURBO,396,121,121,66,WS_GROUP
|
||||
PUSHBUTTON "",IDC_LASER,443,76,57,14,BS_FLAT
|
||||
LTEXT "Laser",IDC_STATIC,412,132,20,14,SS_CENTERIMAGE
|
||||
END
|
||||
|
||||
IDD_LIBUSB_CFG DIALOGEX 0, 0, 250, 35
|
||||
|
|
|
@ -293,6 +293,8 @@
|
|||
#define IDC_TURBO_LEFT 1339
|
||||
#define IDC_TURBO_RIGHT 1340
|
||||
#define IDC_TURBO 1341
|
||||
#define IDC_POWER_SWITCH 1342
|
||||
#define IDC_LASER 1343
|
||||
#define ID_FILE_EXIT 40005
|
||||
#define ID_HELP_ABOUT 40008
|
||||
#define ID_EMULATION_START 40009
|
||||
|
|
Loading…
Reference in New Issue