Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic gamepad support and button remapping #35

Open
wants to merge 11 commits into
base: trunk
Choose a base branch
from
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ bin_PROGRAMS = sopwith

COMMON_SOURCES = \
font.h \
gamepad.h \
pcsound.h \
std.h \
swasynio.c swasynio.h \
Expand Down
36 changes: 36 additions & 0 deletions src/gamepad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// Gamepad Interface
//

#ifndef __GAMEPAD_H__
#define __GAMEPAD_H__

typedef enum {
BTN_UNKNOWN,
BTN_PULLUP,
BTN_PULLDOWN,
BTN_FLIP,
BTN_BOMB,
BTN_FIRE,
BTN_HOME,
BTN_MISSILE,
BTN_STARBURST,
BTN_ACCEL,
BTN_DECEL,
BTN_SOUND,
NUM_BTNS,
} sopbtn_t;

void Gamepad_Init(void);
int Gamepad_GetBtn(void);
int Gamepad_GetGameBtns(void);
const char *Gamepad_BtnName(int btn);

int isLastInputGamepad(void);
void setLastInputGamepad(int input);
int isGamepadInitted(void);

extern int btnbindings[NUM_BTNS];
extern int btnsdown[NUM_BTNS];

#endif
2 changes: 1 addition & 1 deletion src/sdl/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ AM_CFLAGS=@CFLAGS@ @SDL_CFLAGS@ -I$(srcdir)/..

noinst_LIBRARIES = libsdlsopwith.a libsdlsopmain.a

libsdlsopwith_a_SOURCES = video.c pcsound.c timer.c
libsdlsopwith_a_SOURCES = video.c pcsound.c timer.c gamepad.c
libsdlsopmain_a_SOURCES = main.c

194 changes: 194 additions & 0 deletions src/sdl/gamepad.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#include <SDL.h>
#include "gamepad.h"
#include "video.h"

SDL_GameController *gamepad = NULL;
static int gamepad_initted = 0;
static int last_input_gamepad = 0;

int btnbindings[NUM_BTNS] = {
-1, // BTN_UNKNOWN
SDL_CONTROLLER_BUTTON_DPAD_LEFT, // BTN_PULLUP
SDL_CONTROLLER_BUTTON_DPAD_RIGHT, // BTN_PULLDOWN
SDL_CONTROLLER_BUTTON_Y, // BTN_FLIP
SDL_CONTROLLER_BUTTON_A, // BTN_BOMB
SDL_CONTROLLER_BUTTON_X, // BTN_FIRE
SDL_CONTROLLER_BUTTON_START, // BTN_HOME
SDL_CONTROLLER_BUTTON_LEFTSTICK, // BTN_MISSILE
SDL_CONTROLLER_BUTTON_RIGHTSTICK, // BTN_STARBURST
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,// BTN_ACCEL
SDL_CONTROLLER_BUTTON_LEFTSHOULDER, // BTN_DECEL
SDL_CONTROLLER_BUTTON_BACK, // BTN_SOUND
};

int btnsdown[NUM_BTNS];

const char *btnnames[] = {
"A", // 0, SDL_CONTROLLER_BUTTON_A
"B", // 1, SDL_CONTROLLER_BUTTON_B
"X", // 2, SDL_CONTROLLER_BUTTON_X
"Y", // 3, SDL_CONTROLLER_BUTTON_Y
"Back", // 4, SDL_CONTROLLER_BUTTON_BACK
"Guide Button", // 5, SDL_CONTROLLER_BUTTON_GUIDE
"Start", // 6, SDL_CONTROLLER_BUTTON_START
"Left Stick", // 7, SDL_CONTROLLER_BUTTON_LEFTSTICK
"Right Stick", // 8, SDL_CONTROLLER_BUTTON_RIGHTSTICK
"LB", // 9, SDL_CONTROLLER_BUTTON_LEFTSHOULDER
"RB", // 10, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
"D-Pad Up", // 11, SDL_CONTROLLER_BUTTON_DPAD_UP
"D-Pad Down", // 12, SDL_CONTROLLER_BUTTON_DPAD_DOWN
"D-Pad Left", // 13, SDL_CONTROLLER_BUTTON_DPAD_LEFT
"D-Pad Right", // 14, SDL_CONTROLLER_BUTTON_DPAD_RIGHT
"Misc", // 15, SDL_CONTROLLER_BUTTON_MISC1
"Paddle 1", // 16, SDL_CONTROLLER_BUTTON_PADDLE1
"Paddle 2", // 17, SDL_CONTROLLER_BUTTON_PADDLE2
"Paddle 3", // 18, SDL_CONTROLLER_BUTTON_PADDLE3
"Paddle 4", // 19, SDL_CONTROLLER_BUTTON_PADDLE4
"Touchpad", // 20, SDL_CONTROLLER_BUTTON_TOUCHPAD
};

void Gamepad_Init(void)
{
if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) {
printf("Gamepad could not initialize! SDL_Error: %s\n", SDL_GetError());
} else {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if (...

if (SDL_NumJoysticks() > 0) {
gamepad = SDL_GameControllerOpen(0);
}
}

gamepad_initted = 1;
}

void Gamepad_Shutdown(void)
{
if (gamepad_initted) {
// Close the gamepad
if (gamepad != NULL) {
SDL_GameControllerClose(gamepad);
gamepad = NULL;
}
gamepad_initted = 0;
}
}

static void getevents(void)
{
SDL_Event event;

while (SDL_PollEvent(&event)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this means that there are now two event loops: the one in the gamepad code and the one in the video code. This will mean that some events get discarded mistakenly. You need to use a single combined event loop.

switch (event.type) {
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
last_input_gamepad = 1;
break;
}
}

if(last_input_gamepad == 1) {
for (int i = 1; i < NUM_BTNS; ++i) {
if (btnbindings[i] != -1) {
if (SDL_GameControllerGetButton(gamepad, btnbindings[i])) {
btnsdown[i] |= 3; // Button is pressed
} else {
btnsdown[i] &= ~1; // Button is not pressed
}
}
}
}
}

int Gamepad_GetBtn(void)
{
int btn = -1;
SDL_Event event;

while (btn == -1) {
if (SDL_WaitEventTimeout(&event, 10)) {
if (event.type == SDL_CONTROLLERBUTTONDOWN) {
btn = event.cbutton.button;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Justreturn event.cbutton.button; and you can eliminate the btn variable.

break;
} else if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.sym == SDLK_ESCAPE) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can combine the two if statements with an &&

return -1;
}
}
}
}
return btn;
}

int Gamepad_GetGameBtns(void)
{
int i, c = 0;

getevents();

if (btnsdown[BTN_FLIP]) {
btnsdown[BTN_FLIP] = 0;
c |= K_FLIP;
}
if (btnsdown[BTN_PULLUP]) {
c |= K_FLAPU;
}
if (btnsdown[BTN_PULLDOWN]) {
c |= K_FLAPD;
}
if (btnsdown[BTN_ACCEL]) {
c |= K_ACCEL;
}
if (btnsdown[BTN_DECEL]) {
c |= K_DEACC;
}
if (btnsdown[BTN_SOUND]) {
btnsdown[BTN_SOUND] = 0;
c |= K_SOUND;
}
if (btnsdown[BTN_BOMB]) {
c |= K_BOMB;
}
if (btnsdown[BTN_FIRE]) {
c |= K_SHOT;
}
if (btnsdown[BTN_HOME]) {
c |= K_HOME;
}
if (btnsdown[BTN_MISSILE]) {
btnsdown[BTN_MISSILE] = 0;
c |= K_MISSILE;
}
if (btnsdown[BTN_STARBURST]) {
btnsdown[BTN_STARBURST] = 0;
c |= K_STARBURST;
}

// clear bits in button array

for (i=0; i<NUM_BTNS; ++i) {
btnsdown[i] &= ~2;
}

return c;
}

const char *Gamepad_BtnName(int btn)
{
if (btn < 0 || btn >= sizeof(btnnames) / sizeof(btnnames[0])) {
return "Unknown";
}
return btnnames[btn];
}

int isLastInputGamepad(void)
{
return last_input_gamepad;
}

void setLastInputGamepad(int input)
{
last_input_gamepad = input;
}

int isGamepadInitted(void) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get rid of this function; just add a check to Gamepad_GetGameBtns that returns 0 if !gamepad_initted.

return gamepad_initted;
}
17 changes: 10 additions & 7 deletions src/sdl/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@
#include <sys/types.h>

#include "video.h"
#include "gamepad.h"
#include "sw.h"
#include "swinit.h"

// lcd mode to emulate my old laptop i used to play sopwith on :)

//#define LCD

static SDL_Color cga_pal[] = {{}, {}, {}, {}};

typedef struct {
Expand Down Expand Up @@ -536,12 +533,12 @@ void Vid_SetVideoPalette(int palette)

const char* Vid_GetVideoPaletteName(int palette)
{
return VideoPalettes[palette].name;
return VideoPalettes[palette].name;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too much indentation. Side note, can you try to avoid including unrelated changes?

}

int Vid_GetNumVideoPalettes(void)
{
int numPalettes = sizeof(VideoPalettes) / sizeof(VideoPalettes[0]);
int numPalettes = sizeof(VideoPalettes) / sizeof(VideoPalettes[0]);
return numPalettes;
}

Expand Down Expand Up @@ -609,8 +606,10 @@ static void getevents(void)
sopkey_t translated;

while (SDL_PollEvent(&event)) {

switch (event.type) {
case SDL_KEYDOWN:
setLastInputGamepad(false);
if (event.key.keysym.sym == SDLK_LALT) {
altdown = 1;
} else if (event.key.keysym.sym == SDLK_LCTRL
Expand Down Expand Up @@ -649,6 +648,7 @@ static void getevents(void)
break;

case SDL_KEYUP:
setLastInputGamepad(false);
if (event.key.keysym.sym == SDLK_LALT) {
altdown = 0;
} else if (event.key.keysym.sym == SDLK_LCTRL
Expand Down Expand Up @@ -689,6 +689,9 @@ static void getevents(void)
need_redraw = 1;
break;
}
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
setLastInputGamepad(true);
}
}

Expand Down Expand Up @@ -779,4 +782,4 @@ void error_exit(char *s, ...)

fprintf(stderr, "%s\n", buf);
exit(1);
}
}
Loading