mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
glfw, game: add rumble support (#1605)
* glfw: add rumble support * game: add rumble support * oops
This commit is contained in:
parent
9225514d97
commit
4da1a81af8
|
@ -113,8 +113,8 @@ u64 CPadGetData(u64 cpad_info) {
|
|||
// ps2 controllers would send an enabled bit if the button was NOT pressed, but we don't do
|
||||
// that here. removed code that flipped the bits.
|
||||
|
||||
if (cpad->change_time != 0) {
|
||||
scePadSetActDirect(cpad->number, 0, cpad->direct);
|
||||
if (cpad->buzz_act) {
|
||||
scePadSetActDirect(cpad->number, 0, cpad);
|
||||
}
|
||||
cpad->valid = pad_state;
|
||||
}
|
||||
|
@ -142,7 +142,8 @@ u64 CPadGetData(u64 cpad_info) {
|
|||
}
|
||||
break;
|
||||
case 40: // controller mode - check for extra modes
|
||||
cpad->change_time = 0;
|
||||
// cpad->change_time = 0;
|
||||
cpad->buzz_act = 0;
|
||||
if (scePadInfoMode(cpad->number, 0, InfoModeIdTable, -1) == 0) {
|
||||
// no controller modes
|
||||
cpad->state = 90;
|
||||
|
@ -169,11 +170,13 @@ u64 CPadGetData(u64 cpad_info) {
|
|||
// get number of actuators (2 for DS2)
|
||||
if (scePadInfoAct(cpad->number, 0, -1, 0) < 1) {
|
||||
// no actuators means no vibration. skip to end!
|
||||
cpad->change_time = 0;
|
||||
// cpad->change_time = 0;
|
||||
cpad->buzz_act = 0;
|
||||
cpad->state = 99;
|
||||
} else {
|
||||
// we have actuators to use.
|
||||
cpad->change_time = 1; // remember to update pad times.
|
||||
// cpad->change_time = 1; // remember to update pad times.
|
||||
cpad->buzz_act = 1;
|
||||
cpad->state = 75;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -91,10 +91,10 @@ int scePadRead(int port, int /*slot*/, u8* rdata) {
|
|||
return 32;
|
||||
}
|
||||
|
||||
// buzzer control. We don't care right now, return success.
|
||||
int scePadSetActDirect(int /*port*/, int /*slot*/, const u8* /*data*/) {
|
||||
return 1;
|
||||
int scePadSetActDirect(int port, int /*slot*/, CPadInfo* cpad) {
|
||||
return Pad::rumble(port, ((float)cpad->buzz_val[0]) / 255, ((float)cpad->buzz_val[1]) / 255);
|
||||
}
|
||||
|
||||
int scePadSetActAlign(int /*port*/, int /*slot*/, const u8* /*data*/) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#define InfoActSize 3
|
||||
#define InfoActCurr 4
|
||||
|
||||
struct CPadInfo;
|
||||
|
||||
namespace ee {
|
||||
|
||||
// controller modes (not in the lib)
|
||||
|
@ -52,7 +54,7 @@ int scePadPortOpen(int port, int slot, void* data);
|
|||
int scePadGetState(int port, int slot);
|
||||
int scePadInfoMode(int port, int slot, int term, int offs);
|
||||
int scePadRead(int port, int slot, u8* rdata);
|
||||
int scePadSetActDirect(int port, int slot, const u8* data);
|
||||
int scePadSetActDirect(int port, int slot, CPadInfo* cpad);
|
||||
int scePadSetActAlign(int port, int slot, const u8* data);
|
||||
int scePadSetMainMode(int port, int slot, int offs, int lock);
|
||||
int scePadGetReqState(int port, int slot);
|
||||
|
|
|
@ -363,4 +363,12 @@ void update_gamepads() {
|
|||
clear_pad(1);
|
||||
}
|
||||
|
||||
int rumble(int pad, float slow_motor, float fast_motor) {
|
||||
if (g_gamepads.gamepad_idx[pad] != -1 &&
|
||||
glfwSetJoystickRumble(g_gamepads.gamepad_idx[pad], slow_motor, fast_motor)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}; // namespace Pad
|
||||
|
|
|
@ -91,5 +91,6 @@ void input_mode_pad_set(s64);
|
|||
|
||||
void initialize();
|
||||
void update_gamepads();
|
||||
int rumble(int pad, float slow_motor, float fast_motor);
|
||||
|
||||
} // namespace Pad
|
||||
|
|
31
third-party/glfw/include/GLFW/glfw3.h
generated
vendored
31
third-party/glfw/include/GLFW/glfw3.h
generated
vendored
|
@ -5763,6 +5763,37 @@ GLFWAPI const char* glfwGetGamepadName(int jid);
|
|||
*/
|
||||
GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
|
||||
|
||||
/*! @brief Sets the intensity of a joystick's rumble effect.
|
||||
*
|
||||
* This function sends vibration data to joysticks that implement haptic feedback
|
||||
* effects using two vibration motors: a low-frequency motor, and a
|
||||
* high-frequency motor.
|
||||
*
|
||||
* Vibration intensity is a value between 0.0 and 1.0 inclusive, where 0.0 is no
|
||||
* vibration, and 1.0 is maximum vibration. It is set separately for the
|
||||
* joystick's low frequency and high frequency rumble motors.
|
||||
*
|
||||
* If the specified joystick is not present or does not support the rumble effect,
|
||||
* this function will return `GLFW_FALSE` but will not generate an error.
|
||||
*
|
||||
* @param[in] jid The [joystick](@ref joysticks) to vibrate.
|
||||
* @param[in] slowMotorIntensity The low frequency vibration intensity.
|
||||
* @param[in] fastMotorIntensity The high frequency vibration intensity.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is connected,
|
||||
* or the joystick does not support the rumble effect.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_INVALID_ENUM.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @note @win32 This function is only implemented for XInput devices.
|
||||
* @note @macos This function is not implemented.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI int glfwSetJoystickRumble(int jid, float slowMotorIntensity, float fastMotorIntensity);
|
||||
|
||||
/*! @brief Sets the clipboard to the specified string.
|
||||
*
|
||||
* This function sets the system clipboard to the specified, UTF-8 encoded
|
||||
|
|
4
third-party/glfw/src/cocoa_joystick.m
generated
vendored
4
third-party/glfw/src/cocoa_joystick.m
generated
vendored
|
@ -475,3 +475,7 @@ void _glfwUpdateGamepadGUIDCocoa(char* guid)
|
|||
}
|
||||
}
|
||||
|
||||
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
28
third-party/glfw/src/input.c
generated
vendored
28
third-party/glfw/src/input.c
generated
vendored
|
@ -1375,6 +1375,34 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
|||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwSetJoystickRumble(int jid, float slowMotorIntensity, float fastMotorIntensity)
|
||||
{
|
||||
_GLFWjoystick* js;
|
||||
|
||||
assert(jid >= GLFW_JOYSTICK_1);
|
||||
assert(jid <= GLFW_JOYSTICK_LAST);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return GLFW_FALSE;
|
||||
|
||||
slowMotorIntensity = slowMotorIntensity < 0.0f ? 0.0f : slowMotorIntensity;
|
||||
slowMotorIntensity = slowMotorIntensity > 1.0f ? 1.0f : slowMotorIntensity;
|
||||
|
||||
fastMotorIntensity = fastMotorIntensity < 0.0f ? 0.0f : fastMotorIntensity;
|
||||
fastMotorIntensity = fastMotorIntensity > 1.0f ? 1.0f : fastMotorIntensity;
|
||||
|
||||
return _glfwPlatformSetJoystickRumble(js, slowMotorIntensity, fastMotorIntensity);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||
{
|
||||
assert(string != NULL);
|
||||
|
|
2
third-party/glfw/src/internal.h
generated
vendored
2
third-party/glfw/src/internal.h
generated
vendored
|
@ -899,6 +899,8 @@ void* _glfwPlatformLoadModule(const char* path);
|
|||
void _glfwPlatformFreeModule(void* module);
|
||||
GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name);
|
||||
|
||||
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
|
|
77
third-party/glfw/src/linux_joystick.c
generated
vendored
77
third-party/glfw/src/linux_joystick.c
generated
vendored
|
@ -122,6 +122,48 @@ static void pollAbsState(_GLFWjoystick* js)
|
|||
|
||||
#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
|
||||
|
||||
static void initJoystickForceFeedback(_GLFWjoystickLinux *linjs)
|
||||
{
|
||||
linjs->rumble = NULL;
|
||||
struct ff_effect* effect = NULL;
|
||||
|
||||
char ffBits[(FF_CNT + 7) / 8] = {0};
|
||||
if (ioctl(linjs->fd, EVIOCGBIT(EV_FF, sizeof(ffBits)), ffBits) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBitSet(FF_RUMBLE, ffBits))
|
||||
{
|
||||
effect = malloc(sizeof(struct ff_effect));
|
||||
*effect = (struct ff_effect)
|
||||
{
|
||||
.type = FF_RUMBLE,
|
||||
.id = -1,
|
||||
.direction = 0,
|
||||
.trigger = {
|
||||
.button = 0,
|
||||
.interval = 0
|
||||
},
|
||||
.replay = {
|
||||
.length = 2000, // xinput rumble lasts ~2 seconds
|
||||
.delay = 0
|
||||
},
|
||||
.u.rumble = {
|
||||
.strong_magnitude = 0,
|
||||
.weak_magnitude = 0
|
||||
}
|
||||
};
|
||||
|
||||
if (ioctl(linjs->fd, EVIOCSFF, effect) < 0)
|
||||
{
|
||||
free(effect);
|
||||
} else {
|
||||
linjs->rumble = effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to open the specified joystick device
|
||||
//
|
||||
static GLFWbool openJoystickDevice(const char* path)
|
||||
|
@ -135,7 +177,7 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||
}
|
||||
|
||||
_GLFWjoystickLinux linjs = {0};
|
||||
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
linjs.fd = open(path, O_RDWR | O_NONBLOCK);
|
||||
if (linjs.fd == -1)
|
||||
return GLFW_FALSE;
|
||||
|
||||
|
@ -222,6 +264,8 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||
}
|
||||
}
|
||||
|
||||
initJoystickForceFeedback(&linjs);
|
||||
|
||||
_GLFWjoystick* js =
|
||||
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||
if (!js)
|
||||
|
@ -246,6 +290,8 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||
static void closeJoystick(_GLFWjoystick* js)
|
||||
{
|
||||
close(js->linjs.fd);
|
||||
if(js->linjs.rumble)
|
||||
free(js->linjs.rumble);
|
||||
_glfwFreeJoystick(js);
|
||||
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
||||
}
|
||||
|
@ -420,6 +466,35 @@ int _glfwPollJoystickLinux(_GLFWjoystick* js, int mode)
|
|||
return js->present;
|
||||
}
|
||||
|
||||
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||
{
|
||||
_GLFWjoystickLinux *linjs = &js->linjs;
|
||||
|
||||
if (!js->linjs.rumble)
|
||||
return GLFW_FALSE;
|
||||
|
||||
js->linjs.rumble->u.rumble = (struct ff_rumble_effect)
|
||||
{
|
||||
.strong_magnitude = 65535 * slowMotorIntensity,
|
||||
.weak_magnitude = 65535 * fastMotorIntensity
|
||||
};
|
||||
|
||||
struct input_event play =
|
||||
{
|
||||
.type = EV_FF,
|
||||
.code = linjs->rumble->id,
|
||||
.value = 1
|
||||
};
|
||||
|
||||
if (ioctl(linjs->fd, EVIOCSFF, linjs->rumble) < 0 ||
|
||||
write(linjs->fd, (const void*) &play, sizeof(play)) < 0)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
const char* _glfwGetMappingNameLinux(void)
|
||||
{
|
||||
return "Linux";
|
||||
|
|
1
third-party/glfw/src/linux_joystick.h
generated
vendored
1
third-party/glfw/src/linux_joystick.h
generated
vendored
|
@ -43,6 +43,7 @@ typedef struct _GLFWjoystickLinux
|
|||
int absMap[ABS_CNT];
|
||||
struct input_absinfo absInfo[ABS_CNT];
|
||||
int hats[4][2];
|
||||
struct ff_effect *rumble;
|
||||
} _GLFWjoystickLinux;
|
||||
|
||||
// Linux-specific joystick API data
|
||||
|
|
4
third-party/glfw/src/null_joystick.c
generated
vendored
4
third-party/glfw/src/null_joystick.c
generated
vendored
|
@ -56,3 +56,7 @@ void _glfwUpdateGamepadGUIDNull(char* guid)
|
|||
{
|
||||
}
|
||||
|
||||
// int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||
// {
|
||||
// return GLFW_FALSE;
|
||||
// }
|
2
third-party/glfw/src/win32_init.c
generated
vendored
2
third-party/glfw/src/win32_init.c
generated
vendored
|
@ -120,6 +120,8 @@ static GLFWbool loadLibraries(void)
|
|||
_glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetCapabilities");
|
||||
_glfw.win32.xinput.GetState = (PFN_XInputGetState)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetState");
|
||||
_glfw.win32.xinput.SetState = (PFN_XInputSetState)
|
||||
GetProcAddress(_glfw.win32.xinput.instance, "XInputSetState");
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
14
third-party/glfw/src/win32_joystick.c
generated
vendored
14
third-party/glfw/src/win32_joystick.c
generated
vendored
|
@ -756,3 +756,17 @@ void _glfwUpdateGamepadGUIDWin32(char* guid)
|
|||
}
|
||||
}
|
||||
|
||||
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||
{
|
||||
XINPUT_VIBRATION effect;
|
||||
|
||||
if (js->win32.device)
|
||||
return GLFW_FALSE;
|
||||
|
||||
ZeroMemory(&effect, sizeof(XINPUT_VIBRATION));
|
||||
|
||||
effect.wLeftMotorSpeed = (WORD)(65535.0f * slowMotorIntensity);
|
||||
effect.wRightMotorSpeed = (WORD)(65535.0f * fastMotorIntensity);
|
||||
|
||||
return (int) (XInputSetState(js->win32.index, &effect) == ERROR_SUCCESS);
|
||||
}
|
3
third-party/glfw/src/win32_platform.h
generated
vendored
3
third-party/glfw/src/win32_platform.h
generated
vendored
|
@ -269,8 +269,10 @@ typedef enum
|
|||
// xinput.dll function pointer typedefs
|
||||
typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
|
||||
typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
|
||||
typedef DWORD (WINAPI * PFN_XInputSetState)(DWORD,XINPUT_VIBRATION*);
|
||||
#define XInputGetCapabilities _glfw.win32.xinput.GetCapabilities
|
||||
#define XInputGetState _glfw.win32.xinput.GetState
|
||||
#define XInputSetState _glfw.win32.xinput.SetState
|
||||
|
||||
// dinput8.dll function pointer typedefs
|
||||
typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
|
||||
|
@ -461,6 +463,7 @@ typedef struct _GLFWlibraryWin32
|
|||
HINSTANCE instance;
|
||||
PFN_XInputGetCapabilities GetCapabilities;
|
||||
PFN_XInputGetState GetState;
|
||||
PFN_XInputSetState SetState;
|
||||
} xinput;
|
||||
|
||||
struct {
|
||||
|
|
17
third-party/glfw/tests/joysticks.c
generated
vendored
17
third-party/glfw/tests/joysticks.c
generated
vendored
|
@ -58,6 +58,9 @@ static GLFWwindow* window;
|
|||
static int joysticks[GLFW_JOYSTICK_LAST + 1];
|
||||
static int joystick_count = 0;
|
||||
|
||||
static float slowRumble[GLFW_JOYSTICK_LAST + 1];
|
||||
static float fastRumble[GLFW_JOYSTICK_LAST + 1];
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
|
@ -175,7 +178,9 @@ int main(void)
|
|||
struct nk_context* nk;
|
||||
struct nk_font_atlas* atlas;
|
||||
|
||||
memset(joysticks, 0, sizeof(joysticks));
|
||||
memset(joysticks, 0, sizeof(joysticks));
|
||||
memset(slowRumble, 0, sizeof(slowRumble));
|
||||
memset(fastRumble, 0, sizeof(fastRumble));
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
|
@ -326,6 +331,16 @@ int main(void)
|
|||
|
||||
nk_layout_row_dynamic(nk, 30, 8);
|
||||
hat_widget(nk, hat);
|
||||
|
||||
nk_layout_row_dynamic(nk, 30, 2);
|
||||
nk_label(nk, "Slow rumble motor intensity", NK_TEXT_LEFT);
|
||||
nk_label(nk, "Fast rumble motor intensity", NK_TEXT_LEFT);
|
||||
|
||||
nk_layout_row_dynamic(nk, 30, 2);
|
||||
slowRumble[i] = nk_slide_float(nk, 0.0f, slowRumble[i], 1.0f, 0.05f);
|
||||
fastRumble[i] = nk_slide_float(nk, 0.0f, fastRumble[i], 1.0f, 0.05f);
|
||||
|
||||
glfwSetJoystickRumble(joysticks[i], slowRumble[i], fastRumble[i]);
|
||||
}
|
||||
else
|
||||
nk_label(nk, "Joystick has no gamepad mapping", NK_TEXT_LEFT);
|
||||
|
|
Loading…
Reference in a new issue