mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-10 23:24:06 +02:00
#353 XInput support
This commit is contained in:
@@ -639,8 +639,10 @@ enum InputKey {
|
||||
IK_Z = (1 << 9),
|
||||
IK_L = (1 << 10),
|
||||
IK_R = (1 << 11),
|
||||
IK_START = (1 << 12),
|
||||
IK_SELECT = (1 << 13)
|
||||
IK_LT = (1 << 12),
|
||||
IK_RT = (1 << 13),
|
||||
IK_START = (1 << 14),
|
||||
IK_SELECT = (1 << 15),
|
||||
};
|
||||
|
||||
// action keys (ItemObj::input)
|
||||
|
@@ -2745,7 +2745,7 @@ struct Lara : ItemObj
|
||||
if (keys & IK_X) input |= IN_WALK;
|
||||
if (keys & IK_Y) input |= IN_UP | IN_DOWN;
|
||||
if (keys & IK_Z) input |= IN_LOOK;
|
||||
#elif defined(__GBA__) || defined(__GBA_WIN__) || defined(__WIN32__)
|
||||
#elif defined(__GBA__) || defined(__GBA_WIN__)
|
||||
int32 ikA, ikB;
|
||||
|
||||
if (gSettings.controls_swap) {
|
||||
@@ -2793,6 +2793,13 @@ struct Lara : ItemObj
|
||||
if (keys & IK_Y) input |= IN_JUMP;
|
||||
if (keys & IK_L) input |= IN_LOOK;
|
||||
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
|
||||
|
||||
if (keys & IK_LEFT) input |= IN_LEFT;
|
||||
|
@@ -18,6 +18,9 @@ HDC hDC;
|
||||
LARGE_INTEGER g_timer;
|
||||
LARGE_INTEGER g_current;
|
||||
|
||||
LARGE_INTEGER gTimerFreq;
|
||||
LARGE_INTEGER gTimerStart;
|
||||
|
||||
void osSetPalette(const uint16* palette)
|
||||
{
|
||||
//
|
||||
@@ -25,7 +28,9 @@ void osSetPalette(const uint16* palette)
|
||||
|
||||
int32 osGetSystemTimeMS()
|
||||
{
|
||||
return GetTickCount();
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
return int32((count.QuadPart - gTimerStart.QuadPart) * 1000L / gTimerFreq.QuadPart);
|
||||
}
|
||||
|
||||
bool osSaveSettings()
|
||||
@@ -90,8 +95,188 @@ bool osLoadGame()
|
||||
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) {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt
|
||||
|
||||
HWAVEOUT waveOut;
|
||||
@@ -197,14 +382,19 @@ LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* osLoadLevel(const char* name)
|
||||
const void* osLoadScreen(LevelID id)
|
||||
{
|
||||
return (const void*)1; // TODO
|
||||
}
|
||||
|
||||
const void* osLoadLevel(LevelID id)
|
||||
{
|
||||
// level1
|
||||
char buf[32];
|
||||
|
||||
delete[] levelData;
|
||||
|
||||
sprintf(buf, "data/%s.PHD", name);
|
||||
sprintf(buf, "data/%s.PHD", (char*)gLevelInfo[id].data);
|
||||
|
||||
FILE *f = fopen(buf, "rb");
|
||||
|
||||
@@ -225,8 +415,17 @@ void* osLoadLevel(const char* name)
|
||||
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)
|
||||
{
|
||||
QueryPerformanceFrequency(&gTimerFreq);
|
||||
QueryPerformanceCounter(&gTimerStart);
|
||||
|
||||
// int argc = (lpCmdLine && strlen(lpCmdLine)) ? 2 : 1;
|
||||
// const char* argv[] = { "", lpCmdLine };
|
||||
|
||||
@@ -250,8 +449,9 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
|
||||
soundInit();
|
||||
inputInit();
|
||||
|
||||
gameInit(gLevelInfo[gLevelID].name);
|
||||
gameInit();
|
||||
|
||||
MSG msg;
|
||||
|
||||
@@ -266,6 +466,8 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||
#ifdef _DEBUG
|
||||
Sleep(4);
|
||||
#endif
|
||||
inputUpdate();
|
||||
|
||||
int32 frame = (GetTickCount() - startTime) / 33;
|
||||
if (GetAsyncKeyState('R')) frame /= 10;
|
||||
|
||||
@@ -280,6 +482,7 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||
}
|
||||
} while (msg.message != WM_QUIT);
|
||||
|
||||
inputFree();
|
||||
gameFree();
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user