[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.
|
||||
*/
|
||||
|
||||
#include <SDL/SDL.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 "log.h"
|
||||
#include "joystick.h"
|
||||
|
||||
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.
|
||||
* @param namjoystick Looks for given string in the joystick name.
|
||||
* @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.
|
||||
* @param indjoystick Index of the joystick to use.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int joystick_use(int indjoystick) {
|
||||
/* Check to see if it exists. */
|
||||
if(indjoystick < 0 || indjoystick >= SDL_NumJoysticks()) {
|
||||
WARN("Joystick of index number %d does not exist. Switching to default (0)",
|
||||
indjoystick);
|
||||
indjoystick = 0;
|
||||
}
|
||||
if(joystick)
|
||||
/* Might as well close it if it is open already. */
|
||||
/* Close if already open. */
|
||||
if(joystick != NULL) {
|
||||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
}
|
||||
/* Start using the joystick. */
|
||||
joystick = SDL_JoystickOpen(indjoystick);
|
||||
if(joystick == NULL) {
|
||||
@ -55,16 +64,51 @@ int joystick_use(int indjoystick) {
|
||||
return -1;
|
||||
}
|
||||
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_JoystickNumBalls(joystick), SDL_JoystickNumHats(joystick));
|
||||
|
||||
/* Initialize the haptic if possible. */
|
||||
joystick_initHaptic();
|
||||
|
||||
/* For style purposes. */
|
||||
DEBUG();
|
||||
|
||||
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.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
@ -77,6 +121,11 @@ int joystick_init(void) {
|
||||
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. */
|
||||
numjoysticks = SDL_NumJoysticks();
|
||||
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.
|
||||
*/
|
||||
void joystick_exit(void) {
|
||||
SDL_JoystickClose(joystick);
|
||||
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||
if(haptic != NULL) {
|
||||
SDL_HapticClose(haptic);
|
||||
haptic = NULL;
|
||||
}
|
||||
#endif
|
||||
if(joystick != NULL) {
|
||||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
114
src/spfx.c
114
src/spfx.c
@ -4,8 +4,11 @@
|
||||
* @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 "log.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 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
|
||||
*
|
||||
@ -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_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 void spfx_base_free(SPFX_Base* effect);
|
||||
static void spfx_destroy(SPFX* layer, int* nlayer, int spfx);
|
||||
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.
|
||||
* @param name Name 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.
|
||||
* @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.
|
||||
* @param name Name to match.
|
||||
* @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.
|
||||
* @return 0 on success.
|
||||
*
|
||||
@ -152,12 +158,13 @@ int spfx_load(void) {
|
||||
/* Plasma hits. */
|
||||
spfx_base_load("PlaS", 400, 400, "plas.png", 6, 5);
|
||||
spfx_base_load("PlaM", 450, 450, "plam.png", 6, 5);
|
||||
|
||||
spfx_hapticInit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn void spfx_free(void)
|
||||
*
|
||||
* @brief Free the spfx stack.
|
||||
*/
|
||||
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.
|
||||
* @param effect Base effect identifier to use.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
* @param layer Layer the spfx is on.
|
||||
* @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.
|
||||
* @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.
|
||||
* @param layer Layer the spfx is on.
|
||||
* @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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Rumble will decay over time.
|
||||
* @param mod Modifier to increase levely by.
|
||||
*/
|
||||
void spfx_shake(double mod) {
|
||||
/* Add the modifier. */
|
||||
shake_rad += mod;
|
||||
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);
|
||||
|
||||
/* 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.
|
||||
*
|
||||
* 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.
|
||||
* @param layer Layer to render.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user