[Add] First implementation of force feedback (haptic feedback for
joysticks).
This commit is contained in:
parent
b36afb79da
commit
99dc05be86
@ -4,18 +4,26 @@
|
|||||||
* @brief Handles joystick initialization.
|
* @brief Handles joystick initialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <SDL/SDL.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <SDL/SDL.h>
|
||||||
|
#include <SDL/SDL_joystick.h>
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
#include "SDL/SDL_haptic.h"
|
||||||
|
#endif
|
||||||
#include "lephisto.h"
|
#include "lephisto.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "joystick.h"
|
#include "joystick.h"
|
||||||
|
|
||||||
static SDL_Joystick* joystick = NULL; /**< Current joystick in use. */
|
static SDL_Joystick* joystick = NULL; /**< Current joystick in use. */
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
static int has_haptick = 0; /**< Does the player have haptic? */
|
||||||
|
SDL_Haptic* haptic = NULL; /**< Current haptic to use, externed in spfx.c */
|
||||||
|
unsigned int haptic_query = 0; /**< Properties of the haptic device. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void joystick_initHaptic(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn int joystick_get(char* namjoystick)
|
|
||||||
*
|
|
||||||
* @brief Get the joystick index by name.
|
* @brief Get the joystick index by name.
|
||||||
* @param namjoystick Looks for given string in the joystick name.
|
* @param namjoystick Looks for given string in the joystick name.
|
||||||
* @return The index if found, defaults to 0 if it isn't found.
|
* @return The index if found, defaults to 0 if it isn't found.
|
||||||
@ -32,21 +40,22 @@ int joystick_get(char* namjoystick) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn int joystick_use(int indjoystick)
|
|
||||||
*
|
|
||||||
* @brief Make the game use a joystick by index.
|
* @brief Make the game use a joystick by index.
|
||||||
* @param indjoystick Index of the joystick to use.
|
* @param indjoystick Index of the joystick to use.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
*/
|
*/
|
||||||
int joystick_use(int indjoystick) {
|
int joystick_use(int indjoystick) {
|
||||||
|
/* Check to see if it exists. */
|
||||||
if(indjoystick < 0 || indjoystick >= SDL_NumJoysticks()) {
|
if(indjoystick < 0 || indjoystick >= SDL_NumJoysticks()) {
|
||||||
WARN("Joystick of index number %d does not exist. Switching to default (0)",
|
WARN("Joystick of index number %d does not exist. Switching to default (0)",
|
||||||
indjoystick);
|
indjoystick);
|
||||||
indjoystick = 0;
|
indjoystick = 0;
|
||||||
}
|
}
|
||||||
if(joystick)
|
/* Close if already open. */
|
||||||
/* Might as well close it if it is open already. */
|
if(joystick != NULL) {
|
||||||
SDL_JoystickClose(joystick);
|
SDL_JoystickClose(joystick);
|
||||||
|
joystick = NULL;
|
||||||
|
}
|
||||||
/* Start using the joystick. */
|
/* Start using the joystick. */
|
||||||
joystick = SDL_JoystickOpen(indjoystick);
|
joystick = SDL_JoystickOpen(indjoystick);
|
||||||
if(joystick == NULL) {
|
if(joystick == NULL) {
|
||||||
@ -55,16 +64,51 @@ int joystick_use(int indjoystick) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
LOG("Using joystick %d - %s", indjoystick, SDL_JoystickName(indjoystick));
|
LOG("Using joystick %d - %s", indjoystick, SDL_JoystickName(indjoystick));
|
||||||
DEBUG("\t\tWith %d axes, %d buttons, %d balls, and %d hats\n",
|
DEBUG(" With %d axes, %d buttons, %d balls, and %d hats\n",
|
||||||
SDL_JoystickNumAxes(joystick), SDL_JoystickNumButtons(joystick),
|
SDL_JoystickNumAxes(joystick), SDL_JoystickNumButtons(joystick),
|
||||||
SDL_JoystickNumBalls(joystick), SDL_JoystickNumHats(joystick));
|
SDL_JoystickNumBalls(joystick), SDL_JoystickNumHats(joystick));
|
||||||
|
|
||||||
|
/* Initialize the haptic if possible. */
|
||||||
|
joystick_initHaptic();
|
||||||
|
|
||||||
|
/* For style purposes. */
|
||||||
|
DEBUG();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn int joystick_init(void)
|
* @brief Initializes force feedback for the loaded device.
|
||||||
*
|
*/
|
||||||
|
static void joystick_initHaptic(void) {
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
if(has_haptic && SDL_JoystickIsHaptic(joystick)) {
|
||||||
|
/* Close haptic if already open. */
|
||||||
|
if(haptic != NULL) {
|
||||||
|
SDL_HapticClose(haptic);
|
||||||
|
haptic = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to create haptic device. */
|
||||||
|
haptic = SDL_HapticOpenFromJoystick(joystick);
|
||||||
|
if(haptic == NULL) {
|
||||||
|
WARN("Unable to initialize force feedback.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to see what it supports. */
|
||||||
|
haptic_query = SDL_HapticQuery(haptic);
|
||||||
|
if(!(haptic_query & SDL_HAPTIC_SINE)) {
|
||||||
|
SDL_HapticClose(haptic);
|
||||||
|
haptic = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DEBUG(" force feedback enabled");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* @brief Initializes the joystick subsystem.
|
* @brief Initializes the joystick subsystem.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
*/
|
*/
|
||||||
@ -77,6 +121,11 @@ int joystick_init(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
if(SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0)
|
||||||
|
has_haptic = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Figure out how many joysticks there are. */
|
/* Figure out how many joysticks there are. */
|
||||||
numjoysticks = SDL_NumJoysticks();
|
numjoysticks = SDL_NumJoysticks();
|
||||||
LOG("%d joystick%s detected", numjoysticks, (numjoysticks==1)?"":"s");
|
LOG("%d joystick%s detected", numjoysticks, (numjoysticks==1)?"":"s");
|
||||||
@ -90,11 +139,18 @@ int joystick_init(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void joystick_exit(void)
|
|
||||||
*
|
|
||||||
* @brief Exit the joystick subsystem.
|
* @brief Exit the joystick subsystem.
|
||||||
*/
|
*/
|
||||||
void joystick_exit(void) {
|
void joystick_exit(void) {
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
if(haptic != NULL) {
|
||||||
|
SDL_HapticClose(haptic);
|
||||||
|
haptic = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(joystick != NULL) {
|
||||||
SDL_JoystickClose(joystick);
|
SDL_JoystickClose(joystick);
|
||||||
|
joystick = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
src/spfx.c
114
src/spfx.c
@ -4,8 +4,11 @@
|
|||||||
* @brief Handle the specific effects.
|
* @brief Handle the specific effects.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <inttypes.h>
|
||||||
|
#include <SDL/SDL.h>
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
#include "SDL_haptic.h"
|
||||||
|
#endif
|
||||||
#include "lephisto.h"
|
#include "lephisto.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pilot.h"
|
#include "pilot.h"
|
||||||
@ -27,6 +30,13 @@ Vec2 shake_pos = { .x = 0., .y = 0. }; /**< Current shake pos. Used in nebula
|
|||||||
static Vec2 shake_vel = { .x = 0., .y = 0. }; /**< Current shake vel. */
|
static Vec2 shake_vel = { .x = 0., .y = 0. }; /**< Current shake vel. */
|
||||||
static int shake_off = 1; /**< 1 if shake is not active. */
|
static int shake_off = 1; /**< 1 if shake is not active. */
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
extern SDL_Haptic* haptic; /**< From joystick.c */
|
||||||
|
extern unsigned int haptic_query; /**< From joystick.c */
|
||||||
|
static int haptic_rumble = -1; /**< Haptic rumble effect ID. */
|
||||||
|
static SDL_HapticEffect haptic_rumbleEffect; /**< Haptic rumble effect. */
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct SPFX_Base
|
* @struct SPFX_Base
|
||||||
*
|
*
|
||||||
@ -67,14 +77,16 @@ static SPFX* spfx_stack_back = NULL; /**< Back special effect layer. */
|
|||||||
static int spfx_nstack_back = 0; /**< Number of special effects in the back. */
|
static int spfx_nstack_back = 0; /**< Number of special effects in the back. */
|
||||||
static int spfx_mstack_back = 0; /**< Memory allocated for special effects in back. */
|
static int spfx_mstack_back = 0; /**< Memory allocated for special effects in back. */
|
||||||
|
|
||||||
|
/* General. */
|
||||||
static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int sy);
|
static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int sy);
|
||||||
static void spfx_base_free(SPFX_Base* effect);
|
static void spfx_base_free(SPFX_Base* effect);
|
||||||
static void spfx_destroy(SPFX* layer, int* nlayer, int spfx);
|
static void spfx_destroy(SPFX* layer, int* nlayer, int spfx);
|
||||||
static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt);
|
static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt);
|
||||||
|
/* Haptic. */
|
||||||
|
static int spfx_hapticInit(void);
|
||||||
|
static void spfx_hapticRumble(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int sy)
|
|
||||||
*
|
|
||||||
* @brief Load an SPFX_Base into the stack based on some params.
|
* @brief Load an SPFX_Base into the stack based on some params.
|
||||||
* @param name Name of the spfx.
|
* @param name Name of the spfx.
|
||||||
* @param ttl Time to live of the spfx.
|
* @param ttl Time to live of the spfx.
|
||||||
@ -102,8 +114,6 @@ static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static void spfx_base_free(SPFX_Base* effect)
|
|
||||||
*
|
|
||||||
* @brief Free an SPFX_Base.
|
* @brief Free an SPFX_Base.
|
||||||
* @param effect SPFX_Base to free.
|
* @param effect SPFX_Base to free.
|
||||||
*/
|
*/
|
||||||
@ -113,8 +123,6 @@ static void spfx_base_free(SPFX_Base* effect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn int spfx_get(char* name)
|
|
||||||
*
|
|
||||||
* @brief Get the id of an spfx based on name.
|
* @brief Get the id of an spfx based on name.
|
||||||
* @param name Name to match.
|
* @param name Name to match.
|
||||||
* @return ID of the special effect or -1 on error.
|
* @return ID of the special effect or -1 on error.
|
||||||
@ -129,8 +137,6 @@ int spfx_get(char* name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn int spfx_load(void)
|
|
||||||
*
|
|
||||||
* @brief Load the spfx stack.
|
* @brief Load the spfx stack.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
*
|
*
|
||||||
@ -152,12 +158,13 @@ int spfx_load(void) {
|
|||||||
/* Plasma hits. */
|
/* Plasma hits. */
|
||||||
spfx_base_load("PlaS", 400, 400, "plas.png", 6, 5);
|
spfx_base_load("PlaS", 400, 400, "plas.png", 6, 5);
|
||||||
spfx_base_load("PlaM", 450, 450, "plam.png", 6, 5);
|
spfx_base_load("PlaM", 450, 450, "plam.png", 6, 5);
|
||||||
|
|
||||||
|
spfx_hapticInit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_free(void)
|
|
||||||
*
|
|
||||||
* @brief Free the spfx stack.
|
* @brief Free the spfx stack.
|
||||||
*/
|
*/
|
||||||
void spfx_free(void) {
|
void spfx_free(void) {
|
||||||
@ -180,11 +187,6 @@ void spfx_free(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_add(int effect,
|
|
||||||
* const double px, const double py,
|
|
||||||
* const double vx, const double vy,
|
|
||||||
* const int layer) {
|
|
||||||
*
|
|
||||||
* @brief Create a new special effect.
|
* @brief Create a new special effect.
|
||||||
* @param effect Base effect identifier to use.
|
* @param effect Base effect identifier to use.
|
||||||
* @param px X position of the effect.
|
* @param px X position of the effect.
|
||||||
@ -242,8 +244,6 @@ void spfx_add(int effect,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_clear(void)
|
|
||||||
*
|
|
||||||
* @brief Clear all the currently running effects.
|
* @brief Clear all the currently running effects.
|
||||||
*/
|
*/
|
||||||
void spfx_clear(void) {
|
void spfx_clear(void) {
|
||||||
@ -264,8 +264,6 @@ void spfx_clear(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static void spfx_destroy(SPFX* layer, int* nlayer, int spfx)
|
|
||||||
*
|
|
||||||
* @brief Destroys an active spfx.
|
* @brief Destroys an active spfx.
|
||||||
* @param layer Layer the spfx is on.
|
* @param layer Layer the spfx is on.
|
||||||
* @param nlayer Pointer to the number of elements in the layer.
|
* @param nlayer Pointer to the number of elements in the layer.
|
||||||
@ -277,8 +275,6 @@ static void spfx_destroy(SPFX* layer, int* nlayer, int spfx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_update(const double dt)
|
|
||||||
*
|
|
||||||
* @brief Update all the spfx.
|
* @brief Update all the spfx.
|
||||||
* @param dt Current delta tick.
|
* @param dt Current delta tick.
|
||||||
*/
|
*/
|
||||||
@ -288,8 +284,6 @@ void spfx_update(const double dt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt)
|
|
||||||
*
|
|
||||||
* @brief Update an individual spfx.
|
* @brief Update an individual spfx.
|
||||||
* @param layer Layer the spfx is on.
|
* @param layer Layer the spfx is on.
|
||||||
* @param nlayer Pointer to the assosiated nlayer.
|
* @param nlayer Pointer to the assosiated nlayer.
|
||||||
@ -313,8 +307,6 @@ static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_start(double dt)
|
|
||||||
*
|
|
||||||
* @brief Prepare the rendering for the special effects.
|
* @brief Prepare the rendering for the special effects.
|
||||||
*
|
*
|
||||||
* Should be called at the beginning of the rendering loop.
|
* Should be called at the beginning of the rendering loop.
|
||||||
@ -360,24 +352,78 @@ void spfx_start(const double dt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_shake(double mod)
|
|
||||||
*
|
|
||||||
* @brief Increases the current rumble level.
|
* @brief Increases the current rumble level.
|
||||||
*
|
*
|
||||||
* Rumble will decay over time.
|
* Rumble will decay over time.
|
||||||
* @param mod Modifier to increase levely by.
|
* @param mod Modifier to increase levely by.
|
||||||
*/
|
*/
|
||||||
void spfx_shake(double mod) {
|
void spfx_shake(double mod) {
|
||||||
|
/* Add the modifier. */
|
||||||
shake_rad += mod;
|
shake_rad += mod;
|
||||||
if(shake_rad > SHAKE_MAX) shake_rad = SHAKE_MAX;
|
if(shake_rad > SHAKE_MAX) shake_rad = SHAKE_MAX;
|
||||||
shake_off = 0;
|
|
||||||
|
|
||||||
vect_pset(&shake_vel, SHAKE_VEL_MOD*shake_rad, RNGF() * 2. * M_PI);
|
vect_pset(&shake_vel, SHAKE_VEL_MOD*shake_rad, RNGF() * 2. * M_PI);
|
||||||
|
|
||||||
|
/* Rumble if it wasn't rumbling before. */
|
||||||
|
if(shake_off == 1)
|
||||||
|
spfx_hapticRumble();
|
||||||
|
|
||||||
|
/* Notify that rumble is active. */
|
||||||
|
shake_off = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the rumble effect.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
static int spfx_hapticInit(void) {
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
SDL_HapticEffect* efx;
|
||||||
|
|
||||||
|
efx = &haptic_rumbleEffect;
|
||||||
|
memset(efx, 0, sizeof(SDL_HapticEffect));
|
||||||
|
efx->type = SDL_HAPTIC_SINE;
|
||||||
|
efx->periodic.direction.type = SDL_HAPTIC_POLAR;
|
||||||
|
efx->periodic.length = 1000;
|
||||||
|
efx->periodic.period = 200;
|
||||||
|
efx->periodic.magnitude = 0x4000;
|
||||||
|
efx->periodic.fade_length = 1000;
|
||||||
|
efx->periodic.fade_level = 0;
|
||||||
|
|
||||||
|
haptic_rumble = SDL_HapticNewEffect(haptic, efx);
|
||||||
|
if(haptic_rumble < 0) {
|
||||||
|
WARN("Unable to upload haptic effect: %s.", SDL_GetError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Run a rumble effect.
|
||||||
|
*/
|
||||||
|
static void spfx_hapticRumble(void) {
|
||||||
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||||
|
SDL_HapticEffect* efx;
|
||||||
|
|
||||||
|
if(haptic_rumble >= 0) {
|
||||||
|
/* Stop the effect if it was playing. */
|
||||||
|
SDL_HapticStopEffect(haptic, haptic_rumble);
|
||||||
|
|
||||||
|
/* Update the effect. */
|
||||||
|
efx = &haptic_rumbleEffect;
|
||||||
|
efx->periodic.length = (uint32_t)(1000.*shake_rad / SHAKE_DECAY);
|
||||||
|
if(SDL_HapticUpdateEffect(haptic, haptic_rumble, &haptic_rumbleEffect) < 0) {
|
||||||
|
WARN("Failed to update effect: %s.", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run the new effect. */
|
||||||
|
SDL_HapticRunEffect(haptic, haptic_rumble, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_cinematic(void)
|
|
||||||
*
|
|
||||||
* @brief Set the cinematic mode.
|
* @brief Set the cinematic mode.
|
||||||
*
|
*
|
||||||
* Should be run at the end of the render loop if needed.
|
* Should be run at the end of the render loop if needed.
|
||||||
@ -403,8 +449,6 @@ void spfx_cinematic(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void spfx_render(const int layer)
|
|
||||||
*
|
|
||||||
* @brief Render the entire spfx layer.
|
* @brief Render the entire spfx layer.
|
||||||
* @param layer Layer to render.
|
* @param layer Layer to render.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user