mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-14 17:14:29 +02:00
#353 XInput support
This commit is contained in:
@@ -639,8 +639,10 @@ enum InputKey {
|
|||||||
IK_Z = (1 << 9),
|
IK_Z = (1 << 9),
|
||||||
IK_L = (1 << 10),
|
IK_L = (1 << 10),
|
||||||
IK_R = (1 << 11),
|
IK_R = (1 << 11),
|
||||||
IK_START = (1 << 12),
|
IK_LT = (1 << 12),
|
||||||
IK_SELECT = (1 << 13)
|
IK_RT = (1 << 13),
|
||||||
|
IK_START = (1 << 14),
|
||||||
|
IK_SELECT = (1 << 15),
|
||||||
};
|
};
|
||||||
|
|
||||||
// action keys (ItemObj::input)
|
// action keys (ItemObj::input)
|
||||||
|
@@ -2745,7 +2745,7 @@ struct Lara : ItemObj
|
|||||||
if (keys & IK_X) input |= IN_WALK;
|
if (keys & IK_X) input |= IN_WALK;
|
||||||
if (keys & IK_Y) input |= IN_UP | IN_DOWN;
|
if (keys & IK_Y) input |= IN_UP | IN_DOWN;
|
||||||
if (keys & IK_Z) input |= IN_LOOK;
|
if (keys & IK_Z) input |= IN_LOOK;
|
||||||
#elif defined(__GBA__) || defined(__GBA_WIN__) || defined(__WIN32__)
|
#elif defined(__GBA__) || defined(__GBA_WIN__)
|
||||||
int32 ikA, ikB;
|
int32 ikA, ikB;
|
||||||
|
|
||||||
if (gSettings.controls_swap) {
|
if (gSettings.controls_swap) {
|
||||||
@@ -2793,6 +2793,13 @@ struct Lara : ItemObj
|
|||||||
if (keys & IK_Y) input |= IN_JUMP;
|
if (keys & IK_Y) input |= IN_JUMP;
|
||||||
if (keys & IK_L) input |= IN_LOOK;
|
if (keys & IK_L) input |= IN_LOOK;
|
||||||
if (keys & IK_R) input |= IN_WALK;
|
if (keys & IK_R) input |= IN_WALK;
|
||||||
|
#elif defined(__WIN32__)
|
||||||
|
if (keys & IK_A) input |= IN_ACTION;
|
||||||
|
if (keys & IK_B) input |= IN_UP | IN_DOWN;
|
||||||
|
if (keys & IK_Y) input |= IN_WEAPON;
|
||||||
|
if (keys & IK_X) input |= IN_JUMP;
|
||||||
|
if (keys & IK_L) input |= IN_LOOK;
|
||||||
|
if (keys & IK_R) input |= IN_WALK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (keys & IK_LEFT) input |= IN_LEFT;
|
if (keys & IK_LEFT) input |= IN_LEFT;
|
||||||
|
@@ -18,6 +18,9 @@ HDC hDC;
|
|||||||
LARGE_INTEGER g_timer;
|
LARGE_INTEGER g_timer;
|
||||||
LARGE_INTEGER g_current;
|
LARGE_INTEGER g_current;
|
||||||
|
|
||||||
|
LARGE_INTEGER gTimerFreq;
|
||||||
|
LARGE_INTEGER gTimerStart;
|
||||||
|
|
||||||
void osSetPalette(const uint16* palette)
|
void osSetPalette(const uint16* palette)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@@ -25,7 +28,9 @@ void osSetPalette(const uint16* palette)
|
|||||||
|
|
||||||
int32 osGetSystemTimeMS()
|
int32 osGetSystemTimeMS()
|
||||||
{
|
{
|
||||||
return GetTickCount();
|
LARGE_INTEGER count;
|
||||||
|
QueryPerformanceCounter(&count);
|
||||||
|
return int32((count.QuadPart - gTimerStart.QuadPart) * 1000L / gTimerFreq.QuadPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool osSaveSettings()
|
bool osSaveSettings()
|
||||||
@@ -90,8 +95,188 @@ bool osLoadGame()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define INPUT_JOY_COUNT 4
|
||||||
|
|
||||||
|
#define USE_GAMEPAD_XINPUT
|
||||||
|
|
||||||
|
// gamepad
|
||||||
|
#ifdef USE_GAMEPAD_XINPUT
|
||||||
|
typedef struct _XINPUT_GAMEPAD {
|
||||||
|
WORD wButtons;
|
||||||
|
BYTE bLeftTrigger;
|
||||||
|
BYTE bRightTrigger;
|
||||||
|
SHORT sThumbLX;
|
||||||
|
SHORT sThumbLY;
|
||||||
|
SHORT sThumbRX;
|
||||||
|
SHORT sThumbRY;
|
||||||
|
} XINPUT_GAMEPAD, * PXINPUT_GAMEPAD;
|
||||||
|
|
||||||
|
typedef struct _XINPUT_STATE {
|
||||||
|
DWORD dwPacketNumber;
|
||||||
|
XINPUT_GAMEPAD Gamepad;
|
||||||
|
} XINPUT_STATE, * PXINPUT_STATE;
|
||||||
|
|
||||||
|
typedef struct _XINPUT_VIBRATION {
|
||||||
|
WORD wLeftMotorSpeed;
|
||||||
|
WORD wRightMotorSpeed;
|
||||||
|
} XINPUT_VIBRATION, * PXINPUT_VIBRATION;
|
||||||
|
|
||||||
|
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
|
||||||
|
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
|
||||||
|
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
|
||||||
|
|
||||||
|
DWORD(WINAPI* _XInputGetState) (DWORD dwUserIndex, XINPUT_STATE* pState);
|
||||||
|
DWORD(WINAPI* _XInputSetState) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||||
|
void (WINAPI* _XInputEnable) (BOOL enable);
|
||||||
|
|
||||||
|
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
||||||
|
#define JOY_MIN_UPDATE_FX_TIME 50
|
||||||
|
|
||||||
|
struct JoyDevice {
|
||||||
|
int32 vL, vR; // current value for left/right motor vibration
|
||||||
|
int32 oL, oR; // last applied value
|
||||||
|
int32 time; // time when we can send vibration update
|
||||||
|
int32 mask; // buttons mask
|
||||||
|
bool ready;
|
||||||
|
} joyDevice[INPUT_JOY_COUNT];
|
||||||
|
|
||||||
|
bool osJoyReady(int index) {
|
||||||
|
return joyDevice[index].ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void osJoyVibrate(int32 index, int32 L, int32 R)
|
||||||
|
{
|
||||||
|
joyDevice[index].vL = L;
|
||||||
|
joyDevice[index].vR = R;
|
||||||
|
}
|
||||||
|
|
||||||
|
void joyRumble(int index)
|
||||||
|
{
|
||||||
|
if (!_XInputSetState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
JoyDevice& joy = joyDevice[index];
|
||||||
|
|
||||||
|
if (!joy.ready)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((joy.vL == joy.oL) && (joy.vR == joy.oR))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (osGetSystemTimeMS() < joy.time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XINPUT_VIBRATION vibration;
|
||||||
|
vibration.wLeftMotorSpeed = WORD(joy.vL << 8);
|
||||||
|
vibration.wRightMotorSpeed = WORD(joy.vR << 8);
|
||||||
|
_XInputSetState(index, &vibration);
|
||||||
|
joy.oL = joy.vL;
|
||||||
|
joy.oR = joy.vR;
|
||||||
|
joy.time = osGetSystemTimeMS() + JOY_MIN_UPDATE_FX_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inputInit() {
|
||||||
|
memset(joyDevice, 0, sizeof(joyDevice));
|
||||||
|
|
||||||
|
HMODULE h = LoadLibrary("xinput1_3.dll");
|
||||||
|
if (h == NULL) {
|
||||||
|
h = LoadLibrary("xinput9_1_0.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#define GetProcAddr(lib, x) (x = (decltype(x))GetProcAddress(lib, #x + 1))
|
||||||
|
|
||||||
|
GetProcAddr(h, _XInputGetState);
|
||||||
|
GetProcAddr(h, _XInputSetState);
|
||||||
|
GetProcAddr(h, _XInputEnable);
|
||||||
|
|
||||||
|
for (int i = 0; i < INPUT_JOY_COUNT; i++)
|
||||||
|
{
|
||||||
|
XINPUT_STATE state;
|
||||||
|
int res = _XInputGetState(i, &state);
|
||||||
|
joyDevice[i].ready = (_XInputGetState(i, &state) == ERROR_SUCCESS);
|
||||||
|
|
||||||
|
if (joyDevice[i].ready)
|
||||||
|
LOG("Gamepad %d is ready\n", i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void inputFree()
|
||||||
|
{
|
||||||
|
memset(joyDevice, 0, sizeof(joyDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
void inputUpdate()
|
||||||
|
{
|
||||||
|
if (!_XInputGetState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < INPUT_JOY_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (!joyDevice[i].ready)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
joyRumble(i);
|
||||||
|
|
||||||
|
XINPUT_STATE state;
|
||||||
|
if (_XInputGetState(i, &state) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
inputFree();
|
||||||
|
inputInit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const InputKey buttons[] = { IK_UP, IK_DOWN, IK_LEFT, IK_RIGHT, IK_START, IK_SELECT, IK_NONE, IK_NONE, IK_L, IK_R, IK_NONE, IK_NONE, IK_A, IK_B, IK_X, IK_Y };
|
||||||
|
|
||||||
|
int32 curMask = state.Gamepad.wButtons;
|
||||||
|
int32 oldMask = joyDevice[i].mask;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
bool wasDown = (oldMask & (1 << i)) != 0;
|
||||||
|
bool isDown = (curMask & (1 << i)) != 0;
|
||||||
|
|
||||||
|
if (isDown == wasDown)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (isDown && !wasDown) {
|
||||||
|
keys |= buttons[i];
|
||||||
|
} else {
|
||||||
|
keys &= ~buttons[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
joyDevice[i].mask = curMask;
|
||||||
|
|
||||||
|
|
||||||
|
//osJoyVibrate(j, state.Gamepad.bLeftTrigger / 255.0f, state.Gamepad.bRightTrigger / 255.0f); // vibration test
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input::setJoyPos(j, jkL, joyDir(joyAxis(state.Gamepad.sThumbLX, -32768, 32767),
|
||||||
|
joyAxis(-state.Gamepad.sThumbLY, -32768, 32767)));
|
||||||
|
Input::setJoyPos(j, jkR, joyDir(joyAxis(state.Gamepad.sThumbRX, -32768, 32767),
|
||||||
|
joyAxis(-state.Gamepad.sThumbRY, -32768, 32767)));
|
||||||
|
Input::setJoyPos(j, jkLT, vec2(state.Gamepad.bLeftTrigger / 255.0f, 0.0f));
|
||||||
|
Input::setJoyPos(j, jkRT, vec2(state.Gamepad.bRightTrigger / 255.0f, 0.0f));
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(USE_GAMEPAD_WINMM)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
void osJoyVibrate(int32 index, int32 L, int32 R) {}
|
void osJoyVibrate(int32 index, int32 L, int32 R) {}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt
|
uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt
|
||||||
|
|
||||||
HWAVEOUT waveOut;
|
HWAVEOUT waveOut;
|
||||||
@@ -197,14 +382,19 @@ LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* osLoadLevel(const char* name)
|
const void* osLoadScreen(LevelID id)
|
||||||
|
{
|
||||||
|
return (const void*)1; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* osLoadLevel(LevelID id)
|
||||||
{
|
{
|
||||||
// level1
|
// level1
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
|
||||||
delete[] levelData;
|
delete[] levelData;
|
||||||
|
|
||||||
sprintf(buf, "data/%s.PHD", name);
|
sprintf(buf, "data/%s.PHD", (char*)gLevelInfo[id].data);
|
||||||
|
|
||||||
FILE *f = fopen(buf, "rb");
|
FILE *f = fopen(buf, "rb");
|
||||||
|
|
||||||
@@ -225,8 +415,17 @@ void* osLoadLevel(const char* name)
|
|||||||
return (void*)levelData;
|
return (void*)levelData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hint to the driver to use discrete GPU
|
||||||
|
extern "C" {
|
||||||
|
__declspec(dllexport) int NvOptimusEnablement = 1; // NVIDIA
|
||||||
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; // AMD
|
||||||
|
}
|
||||||
|
|
||||||
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
|
QueryPerformanceFrequency(&gTimerFreq);
|
||||||
|
QueryPerformanceCounter(&gTimerStart);
|
||||||
|
|
||||||
// int argc = (lpCmdLine && strlen(lpCmdLine)) ? 2 : 1;
|
// int argc = (lpCmdLine && strlen(lpCmdLine)) ? 2 : 1;
|
||||||
// const char* argv[] = { "", lpCmdLine };
|
// const char* argv[] = { "", lpCmdLine };
|
||||||
|
|
||||||
@@ -250,8 +449,9 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||||
|
|
||||||
soundInit();
|
soundInit();
|
||||||
|
inputInit();
|
||||||
|
|
||||||
gameInit(gLevelInfo[gLevelID].name);
|
gameInit();
|
||||||
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
@@ -266,6 +466,8 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Sleep(4);
|
Sleep(4);
|
||||||
#endif
|
#endif
|
||||||
|
inputUpdate();
|
||||||
|
|
||||||
int32 frame = (GetTickCount() - startTime) / 33;
|
int32 frame = (GetTickCount() - startTime) / 33;
|
||||||
if (GetAsyncKeyState('R')) frame /= 10;
|
if (GetAsyncKeyState('R')) frame /= 10;
|
||||||
|
|
||||||
@@ -280,6 +482,7 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||||||
}
|
}
|
||||||
} while (msg.message != WM_QUIT);
|
} while (msg.message != WM_QUIT);
|
||||||
|
|
||||||
|
inputFree();
|
||||||
gameFree();
|
gameFree();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user