Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <XInput.h>
|
||||
#endif
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "binds.h"
|
||||
|
||||
#define JOY_AXIS_MAX 16
|
||||
#define JOY_BUTTON_MAX 64
|
||||
#define GLFW_DEADZONE 0.1
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
//As XInput is not available on XP, we need to load it manually
|
||||
struct XInputLibrary {
|
||||
HMODULE dll;
|
||||
|
||||
decltype(XInputGetState)* xInputGetState;
|
||||
decltype(XInputSetState)* xInputSetState;
|
||||
|
||||
XInputLibrary() : dll(0), xInputGetState(0) {
|
||||
}
|
||||
|
||||
~XInputLibrary() {
|
||||
if(dll != NULL)
|
||||
FreeLibrary(dll);
|
||||
}
|
||||
|
||||
bool load() {
|
||||
//There are three current variants of the library, we try to get the most recent one
|
||||
//XInput1_4.dll from Window 8
|
||||
//XInput1_3.dll from DirectX
|
||||
//XInput9_1_0.dll on Vista
|
||||
dll = LoadLibrary("XInput1_4.dll");
|
||||
if(dll == NULL)
|
||||
dll = LoadLibrary("XInput1_3.dll");
|
||||
if(dll == NULL)
|
||||
dll = LoadLibrary("XInput9_1_0.dll");
|
||||
if(dll == NULL)
|
||||
return false;
|
||||
|
||||
xInputGetState = (decltype(xInputGetState))GetProcAddress(dll, "XInputGetState");
|
||||
xInputSetState = (decltype(xInputSetState))GetProcAddress(dll, "XInputSetState");
|
||||
|
||||
return xInputGetState != 0;
|
||||
}
|
||||
|
||||
bool getState(DWORD index, XINPUT_STATE& state) {
|
||||
if(!dll || !xInputGetState)
|
||||
return false;
|
||||
|
||||
return xInputGetState(index, &state) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void setVibration(DWORD index, float lowFreq, float hiFreq) {
|
||||
if(xInputSetState) {
|
||||
XINPUT_VIBRATION vibration;
|
||||
ZeroMemory(&vibration, sizeof(vibration));
|
||||
|
||||
if(lowFreq >= 1.f)
|
||||
vibration.wLeftMotorSpeed = 65535;
|
||||
else if(lowFreq <= 0.f)
|
||||
vibration.wLeftMotorSpeed = 0;
|
||||
else
|
||||
vibration.wLeftMotorSpeed = (WORD)(lowFreq * 65535.f);
|
||||
|
||||
if(hiFreq >= 1.f)
|
||||
vibration.wRightMotorSpeed = 65535;
|
||||
else if(hiFreq <= 0.f)
|
||||
vibration.wRightMotorSpeed = 0;
|
||||
else
|
||||
vibration.wRightMotorSpeed = (WORD)(hiFreq * 65535.f);
|
||||
|
||||
xInputSetState(index, &vibration);
|
||||
}
|
||||
}
|
||||
} xinput;
|
||||
|
||||
#endif
|
||||
|
||||
namespace scripts {
|
||||
|
||||
enum JoystickButtonState {
|
||||
JBS_Off = GLFW_RELEASE,
|
||||
JBS_On = GLFW_PRESS,
|
||||
JBS_Released,
|
||||
JBS_Pressed
|
||||
};
|
||||
|
||||
//TODO: This should go through a driver, not directly glfw
|
||||
class Joystick {
|
||||
public:
|
||||
bool isXInput;
|
||||
int index;
|
||||
|
||||
unsigned axisCount;
|
||||
float axes[JOY_AXIS_MAX];
|
||||
|
||||
unsigned buttonCount;
|
||||
unsigned char buttons[JOY_BUTTON_MAX];
|
||||
|
||||
Joystick(unsigned Index) : axisCount(0), axes(), buttonCount(0), buttons(), isXInput(false) {
|
||||
#ifdef _WIN32
|
||||
XINPUT_STATE state;
|
||||
if(xinput.load() && xinput.getState(Index - 1, state)) {
|
||||
index = (int)Index - 1;
|
||||
isXInput = true;
|
||||
poll();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if(Index >= 1 && Index <= 16)
|
||||
index = GLFW_JOYSTICK_1 + (int)Index - 1;
|
||||
poll();
|
||||
}
|
||||
|
||||
bool poll() {
|
||||
if(isXInput) {
|
||||
#ifdef _WIN32
|
||||
XINPUT_STATE state;
|
||||
auto buttonUpdate = [this,&state](unsigned btn, bool pressed) {
|
||||
auto& button = buttons[btn];
|
||||
if(pressed) {
|
||||
if(button == JBS_Pressed)
|
||||
button = JBS_On;
|
||||
else if(button != JBS_On)
|
||||
button = JBS_Pressed;
|
||||
}
|
||||
else {
|
||||
if(button == JBS_Released)
|
||||
button = JBS_Off;
|
||||
else if(button != JBS_Off)
|
||||
button = JBS_Released;
|
||||
}
|
||||
};
|
||||
|
||||
auto deadZone = [](int value, int deadzone, int scale) -> float {
|
||||
if(value >= -deadzone && value <= deadzone)
|
||||
return 0;
|
||||
bool neg = value < 0;
|
||||
if(neg)
|
||||
value = -value;
|
||||
|
||||
float result = (float)(value - deadzone) / (float)(scale - deadzone);
|
||||
return neg ? -result : result;
|
||||
};
|
||||
|
||||
if(xinput.getState(index, state)) {
|
||||
buttonCount = 16;
|
||||
buttonUpdate(0, state.Gamepad.wButtons & XINPUT_GAMEPAD_A);
|
||||
buttonUpdate(1, state.Gamepad.wButtons & XINPUT_GAMEPAD_B);
|
||||
buttonUpdate(2, state.Gamepad.wButtons & XINPUT_GAMEPAD_X);
|
||||
buttonUpdate(3, state.Gamepad.wButtons & XINPUT_GAMEPAD_Y);
|
||||
buttonUpdate(4, state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP);
|
||||
buttonUpdate(5, state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
|
||||
buttonUpdate(6, state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
|
||||
buttonUpdate(7, state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
|
||||
buttonUpdate(8, state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
buttonUpdate(9, state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD);
|
||||
buttonUpdate(10, state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB);
|
||||
buttonUpdate(11, state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
buttonUpdate(12, state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD);
|
||||
buttonUpdate(13, state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB);
|
||||
buttonUpdate(14, state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK);
|
||||
buttonUpdate(15, state.Gamepad.wButtons & XINPUT_GAMEPAD_START);
|
||||
|
||||
axisCount = 6;
|
||||
axes[0] = deadZone(state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, 32768);
|
||||
axes[1] = deadZone(state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, 32768);
|
||||
axes[2] = deadZone(state.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, 32768);
|
||||
axes[3] = deadZone(state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, 32768);
|
||||
axes[4] = deadZone(state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
|
||||
axes[5] = deadZone(state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#ifdef LIN_MODE
|
||||
else if(true) {
|
||||
//Statically figured out button/axes numbers from the xboxdrv linux driver.
|
||||
int btnCnt;
|
||||
auto* newState = glfwGetJoystickButtons(index, &btnCnt);
|
||||
|
||||
int axCnt;
|
||||
const float* glfwAxes = glfwGetJoystickAxes(index, &axCnt);
|
||||
|
||||
auto setButton = [this](unsigned btn, bool pressed) {
|
||||
auto& button = buttons[btn];
|
||||
if(pressed) {
|
||||
if(button == JBS_Pressed)
|
||||
button = JBS_On;
|
||||
else if(button != JBS_On)
|
||||
button = JBS_Pressed;
|
||||
}
|
||||
else {
|
||||
if(button == JBS_Released)
|
||||
button = JBS_Off;
|
||||
else if(button != JBS_Off)
|
||||
button = JBS_Released;
|
||||
}
|
||||
};
|
||||
|
||||
auto buttonUpdate = [&](unsigned btn, unsigned index) {
|
||||
if((int)index >= btnCnt) {
|
||||
buttons[btn] = JBS_Off;
|
||||
return;
|
||||
}
|
||||
setButton(btn, newState[index]);
|
||||
};
|
||||
|
||||
auto buttonFromAxis = [&](unsigned btn, unsigned index, float thresMin, float thresMax) {
|
||||
if((int)index >= axCnt) {
|
||||
buttons[btn] = JBS_Off;
|
||||
return;
|
||||
}
|
||||
|
||||
setButton(btn, glfwAxes[index] >= thresMin && glfwAxes[index] <= thresMax);
|
||||
};
|
||||
|
||||
auto axisUpdate = [&](unsigned ax, unsigned index) {
|
||||
if((int)index >= axCnt) {
|
||||
axes[ax] = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
float val = glfwAxes[index];
|
||||
if(val >= -GLFW_DEADZONE && val <= GLFW_DEADZONE)
|
||||
axes[ax] = 0.f;
|
||||
else if(val < 0)
|
||||
axes[ax] = -((-val - GLFW_DEADZONE) / (1.f - GLFW_DEADZONE));
|
||||
else
|
||||
axes[ax] = (val - GLFW_DEADZONE) / (1.f - GLFW_DEADZONE);
|
||||
};
|
||||
|
||||
auto triggerAxis = [&](unsigned ax, unsigned index, float mult) {
|
||||
if((int)index >= axCnt) {
|
||||
axes[ax] = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
float val = glfwAxes[index] * mult;
|
||||
if(val <= -0.9f)
|
||||
axes[ax] = 0.f;
|
||||
else
|
||||
axes[ax] = (val + 0.9f) / 1.9f;
|
||||
};
|
||||
|
||||
buttonUpdate(0, 0);
|
||||
buttonUpdate(1, 1);
|
||||
buttonUpdate(2, 2);
|
||||
buttonUpdate(3, 3);
|
||||
buttonFromAxis(4, 7, 0.1f, 1.f);
|
||||
buttonFromAxis(5, 6, -1.f, -0.1f);
|
||||
buttonFromAxis(6, 7, -1.f, -0.1f);
|
||||
buttonFromAxis(7, 6, 0.1f, 1.f);
|
||||
buttonUpdate(8, 4);
|
||||
buttonFromAxis(9, 5, -1.f, 0.f);
|
||||
buttonUpdate(10, 9);
|
||||
buttonUpdate(11, 5);
|
||||
buttonFromAxis(12, 4, 0.f, 1.f);
|
||||
buttonUpdate(13, 10);
|
||||
buttonUpdate(14, 6);
|
||||
buttonUpdate(15, 7);
|
||||
buttonCount = 16;
|
||||
|
||||
axisUpdate(0, 0);
|
||||
axisUpdate(1, 1);
|
||||
axisUpdate(2, 2);
|
||||
axisUpdate(3, 3);
|
||||
triggerAxis(4, 5, -1.f);
|
||||
triggerAxis(5, 4, 1.f);
|
||||
axisCount = 6;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
int cnt;
|
||||
auto* newState = glfwGetJoystickButtons(index, &cnt);
|
||||
buttonCount = cnt;
|
||||
|
||||
if(buttonCount == 0)
|
||||
return false;
|
||||
|
||||
for(unsigned i = 0; i < JOY_BUTTON_MAX; ++i) {
|
||||
if(buttons[i] == newState[i])
|
||||
continue;
|
||||
|
||||
if(newState[i] == GLFW_PRESS) {
|
||||
if(buttons[i] == JBS_Pressed)
|
||||
buttons[i] = JBS_On;
|
||||
else
|
||||
buttons[i] = JBS_Pressed;
|
||||
}
|
||||
else {
|
||||
if(buttons[i] == JBS_Released)
|
||||
buttons[i] = JBS_Off;
|
||||
else
|
||||
buttons[i] = JBS_Released;
|
||||
}
|
||||
}
|
||||
|
||||
const float* glfwAxes = glfwGetJoystickAxes(index, &cnt);
|
||||
axisCount = cnt;
|
||||
|
||||
for(int i = 0; i < cnt && i < JOY_AXIS_MAX; ++i) {
|
||||
//Static deadzone, because glfw
|
||||
float val = glfwAxes[i];
|
||||
if(val >= -GLFW_DEADZONE && val <= GLFW_DEADZONE)
|
||||
axes[i] = 0.f;
|
||||
else if(val < 0)
|
||||
axes[i] = -((-val - GLFW_DEADZONE) / (1.f - GLFW_DEADZONE));
|
||||
else
|
||||
axes[i] = (val - GLFW_DEADZONE) / (1.f - GLFW_DEADZONE);
|
||||
}
|
||||
return buttonCount > 0;
|
||||
}
|
||||
}
|
||||
|
||||
float getAxis(unsigned axis) const {
|
||||
if(axis < JOY_AXIS_MAX)
|
||||
return axes[axis];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char getButton(unsigned id) const {
|
||||
if(id < JOY_BUTTON_MAX)
|
||||
return buttons[id];
|
||||
else
|
||||
return JBS_Off;
|
||||
}
|
||||
|
||||
bool getPressed(unsigned id) const {
|
||||
auto state = getButton(id);
|
||||
return state == JBS_On || state == JBS_Pressed;
|
||||
}
|
||||
|
||||
bool connected() const {
|
||||
return glfwJoystickPresent(index) == GL_TRUE;
|
||||
}
|
||||
|
||||
void setVibration(float lowFreq, float hiFreq) {
|
||||
#ifdef _WIN32
|
||||
if(isXInput) {
|
||||
xinput.setVibration(index, lowFreq, hiFreq);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void construct(void* memory, unsigned index) {
|
||||
new(memory) Joystick(index);
|
||||
}
|
||||
};
|
||||
|
||||
void RegisterJoystickBinds() {
|
||||
ClassBind joystick("Joystick", asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C, sizeof(Joystick));
|
||||
|
||||
joystick.addConstructor("void f(uint)", asFUNCTION(Joystick::construct));
|
||||
|
||||
joystick.addMethod("bool connected() const", asMETHOD(Joystick,connected));
|
||||
joystick.addMethod("bool poll()", asMETHOD(Joystick,poll));
|
||||
joystick.addMethod("float get_axis(uint index) const", asMETHOD(Joystick,getAxis));
|
||||
joystick.addMethod("uint8 get_button(uint index) const", asMETHOD(Joystick,getButton));
|
||||
joystick.addMethod("bool get_pressed(uint index) const", asMETHOD(Joystick,getPressed));
|
||||
joystick.addMethod("void setVibration(float low, float high) const", asMETHOD(Joystick,setVibration));
|
||||
|
||||
joystick.addMember("uint axisCount", offsetof(Joystick,axisCount));
|
||||
joystick.addMember("uint buttonCount", offsetof(Joystick,buttonCount));
|
||||
|
||||
EnumBind buttonStates("JoystickButtonState");
|
||||
buttonStates["JBS_On"] = JBS_On;
|
||||
buttonStates["JBS_Off"] = JBS_Off;
|
||||
buttonStates["JBS_Pressed"] = JBS_Pressed;
|
||||
buttonStates["JBS_Released"] = JBS_Released;
|
||||
|
||||
EnumBind gamepad("GamepadKeys");
|
||||
gamepad["GP_A"] = 0;
|
||||
gamepad["GP_B"] = 1;
|
||||
gamepad["GP_X"] = 2;
|
||||
gamepad["GP_Y"] = 3;
|
||||
gamepad["GP_UP"] = 4;
|
||||
gamepad["GP_LEFT"] = 5;
|
||||
gamepad["GP_DOWN"] = 6;
|
||||
gamepad["GP_RIGHT"] = 7;
|
||||
gamepad["GP_LB"] = 8;
|
||||
gamepad["GP_LT"] = 9;
|
||||
gamepad["GP_L3"] = 10;
|
||||
gamepad["GP_RB"] = 11;
|
||||
gamepad["GP_RT"] = 12;
|
||||
gamepad["GP_R3"] = 13;
|
||||
gamepad["GP_BACK"] = 14;
|
||||
gamepad["GP_START"] = 15;
|
||||
|
||||
gamepad["GP_AXIS_LX"] = 0;
|
||||
gamepad["GP_AXIS_LY"] = 1;
|
||||
gamepad["GP_AXIS_RX"] = 2;
|
||||
gamepad["GP_AXIS_RY"] = 3;
|
||||
gamepad["GP_AXIS_LT"] = 4;
|
||||
gamepad["GP_AXIS_RT"] = 5;
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user