From 54beb595dce72b82fb450f75c5b0b8e6100d24ef Mon Sep 17 00:00:00 2001 From: Allanis <allanis@saracraft.net> Date: Sat, 2 Feb 2013 21:13:25 +0000 Subject: [PATCH] [Add] Dynamic key bindind loading from configuration file. --- bin/conf.example | 15 +++ src/log.h | 1 + src/main.c | 103 +++++++++++++++++---- src/opengl.c | 29 ++++-- src/opengl.h | 1 + src/player.c | 231 ++++++++++++++++++++++++++++------------------- src/player.h | 11 +-- src/space.c | 8 +- 8 files changed, 269 insertions(+), 130 deletions(-) create mode 100644 bin/conf.example diff --git a/bin/conf.example b/bin/conf.example new file mode 100644 index 0000000..b89c21b --- /dev/null +++ b/bin/conf.example @@ -0,0 +1,15 @@ +--WINDOW. +width = 800 +height = 640 +fullscreen = 0 + +-- JOYSTICK. +-- Can be number or substring of joystick name. +joystick = "Precision" + +-- KEYBINDINGS. +-- Type can be keyboard, jaxis or jbutton. +accel = { type = "jbutton", key = 0 } +left = { type = "jaxis", key = 0 } +right = { type = "jaxis", key = 0 } + diff --git a/src/log.h b/src/log.h index 0e3acf7..a727791 100644 --- a/src/log.h +++ b/src/log.h @@ -4,6 +4,7 @@ #define LOG(str, args...)(fprintf(stdout, str"\n", ## args)) #define WARN(str, args...)(fprintf(stderr, "[%d] "str"\n", SDL_GetTicks(), ## args)) +#define ERR(str, args...) (fprintf(stderr, "%s:%d: "str"\n", __FILE__, __LINE__, ## args)) #ifdef DEBUG # undef DEBUG diff --git a/src/main.c b/src/main.c index e75fec0..e8c3d32 100644 --- a/src/main.c +++ b/src/main.c @@ -18,14 +18,14 @@ #include "ai.h" #include "pilot.h" -#define WINDOW_CAPTION "Lephisto" -#define CONF_FILE "conf" +#define WINDOW_CAPTION "Lephisto" +#define CONF_FILE "conf" +#define MINIMUM_FPS 0.5 -static gl_font fdefault; +extern const char* keybindNames[]; // Keybindings. -static int quit = 0; - -static unsigned int time = 0; +static int quit = 0; // Primary loop. +static unsigned int time = 0; // Calculate FPS and movement. // Prototypes. @@ -49,6 +49,9 @@ static void print_usage(char** argv) { } int main(int argc, char** argv) { + int i; + // Initialize SDL for possible warnings. + SDL_Init(0); // Default values.. gl_screen.w = 800; gl_screen.h = 640; @@ -57,10 +60,19 @@ int main(int argc, char** argv) { int indjoystick = -1; char* namjoystick = NULL; + // input. + input_init(); + input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_UP, 0); + input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0); + input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_LEFT, 0); + input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0); + input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_RIGHT, 0); + input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0); + // Use Lua to parse configuration file. lua_State* L = luaL_newstate(); - if(luaL_dofile(L, CONF_FILE) == 0) { - // OpenGL. + if(luaL_dofile(L, CONF_FILE) == 0) { // Conf file exists. + // OpenGL properties. lua_getglobal(L, "width"); if(lua_isnumber(L, -1)) gl_screen.w = (int)lua_tonumber(L, -1); @@ -78,6 +90,45 @@ int main(int argc, char** argv) { indjoystick = (int)lua_tonumber(L, -1); else if(lua_isstring(L, -1)) namjoystick = strdup((char*)lua_tostring(L, -1)); + + // Grab the keybindings if there are any. + char* str; + int type, key, reverse; + for(i = 0; keybindNames[i]; i++) { + lua_getglobal(L, keybindNames[i]); + str = NULL; + key = -1; + reverse = 0; + if(lua_istable(L, -1)) { // It's a table alright. + // Get the event type. + lua_pushstring(L, "type"); + lua_gettable(L, -2); + if(lua_isstring(L, -1)) + str = (char*)lua_tostring(L, -1); + + // Get the key. + lua_pushstring(L, "key"); + lua_gettable(L, -3); + if(lua_isnumber(L, -1)) + str = (int)lua_tonumber(L, -1); + + // Is it reversed? Only useful for axis. + lua_pushstring(L, "reverse"); + lua_gettable(L, -4); + if(lua_isnumber(L, -1)) + reverse = 1; + + if(key != -1 && str != NULL) { // Keybind is valid! + // Get the type. + if(strcmp(str, "null")==0) type = KEYBIND_NULL; + else if(strcmp(str, "keyboard")==0) type = KEYBIND_KEYBOARD; + else if(strcmp(str, "jaxis")==0) type = KEYBIND_JAXIS; + else if(strcmp(str, "jbutton")==0) type = KEYBIND_JBUTTON; + // Set the keybind. + input_setKeybind((char*)keybindNames[i], type, key, reverse); + } else WARN("Malformed keybind in %s", CONF_FILE); + } + } } lua_close(L); @@ -105,8 +156,6 @@ int main(int argc, char** argv) { // Random numbers. rng_init(); - // SDL_Init is first called here, so it's important to be - // initialized first. if(gl_init()) { // Initializes video output. WARN("Error initializing video output, exiting..."); @@ -132,7 +181,7 @@ int main(int argc, char** argv) { if(ai_init()) WARN("Error initializing AI"); - gl_fontInit(&fdefault, "../gfx/fonts/FreeSans.ttf", 16); + gl_fontInit(NULL, "../gfx/fonts/FreeSans.ttf", 16); // Data loading. ships_load(); @@ -149,35 +198,51 @@ int main(int argc, char** argv) { // Main looops. SDL_Event event; + // flushes the event loop, since I notices that when the joystick is loaded, it + // creates button events that results in the player starting out accelerating. + while(SDL_PollEvent(&event)); while(!quit) { // Event loop. while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) quit = 1; // Handle quit. - handle_input(&event); + input_handle(&event); // handles all the events the player keybinds. } update_all(); } - space_exit(); // Unload data. - pilots_free(); + space_exit(); // Clean up the universe!!! + pilots_free(); // Free the pilots, they where locked up D: ships_free(); - gl_freeFont(&fdefault); + gl_freeFont(NULL); // Exit subsystems. - joystick_exit(); - gl_exit(); // Kills video output. + ai_exit(); // Stop the Lua AI magicness. + joystick_exit(); // Release joystick. + input_exit(); // Clean up keybindings. + gl_exit(); // Kills video output. exit(EXIT_SUCCESS); } // Update all the things. +// Space: +// -- Stars. +// -- Movement. +// -- Render. // Pilots: // -- Think (ai). // -- Solid. static void update_all(void) { double dt = (double)(SDL_GetTicks() - time) / 1000.0; time = SDL_GetTicks(); + + if(dt > MINIMUM_FPS) { + Vec2 pos = { .x = 10., .y = gl_screen.h-40 }; + gl_print(NULL, &pos, "FPS is really low! Skipping frames."); + SDL_GL_SwapBuffers(); + } + glClear(GL_COLOR_BUFFER_BIT); space_render(dt); @@ -188,6 +253,8 @@ static void update_all(void) { SDL_GL_SwapBuffers(); } + +// Spit this out on display. static double fps = 0.; static double fps_cur = 0.; static double fps_dt = 1.; @@ -199,6 +266,6 @@ static void display_fps(const double dt) { fps_dt = fps_cur = 0.; } Vec2 pos = { .x = 10., .y = (double)(gl_screen.h-20) }; - gl_print(&fdefault, &pos, "%3.2f", fps); + gl_print(NULL, &pos, "%3.2f", fps); } diff --git a/src/opengl.c b/src/opengl.c index 10c1cd7..899e7d6 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -20,9 +20,12 @@ gl_info gl_screen; // Our precious camera. Vec2* gl_camera; +// Default font. +gl_font gl_defFont; + // Misc. -static int flip_surface(SDL_Surface* surface); -static int pot(int n); +static int _flip_surface(SDL_Surface* surface); +static int _pot(int n); // gl_texture. static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh); // Gl font. @@ -33,7 +36,7 @@ static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* te // ================ // Get me the closest power of two plox. -static int pot(int n) { +static int _pot(int n) { int i = 1; while(i < n) i<<=1; @@ -41,7 +44,7 @@ static int pot(int n) { } // Flips the surface vertically. Return 0 on success. -static int flip_surface(SDL_Surface* surface) { +static int _flip_surface(SDL_Surface* surface) { // Flip the image. Uint8* rowhi, *rowlo, *tmpbuf; int y; @@ -80,8 +83,8 @@ static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh) { int potw, poth; // Make size power of two. - potw = pot(surface->w); - poth = pot(surface->h); + potw = _pot(surface->w); + poth = _pot(surface->h); if(rw)*rw = potw; if(rh)*rh = poth; @@ -198,7 +201,7 @@ gl_texture* gl_newImage(const char* path) { SDL_FreeSurface(tmp); // Free the temp surface. - if(flip_surface(surface)) { + if(_flip_surface(surface)) { WARN("Error flipping surface"); return NULL; } @@ -301,11 +304,14 @@ void gl_bindCamera(const Vec2* pos) { } // Print text on screen! YES!!!! Just like printf! But different! +// Defaults ft_font to gl_defFont if NULL. void gl_print(const gl_font* ft_font, const Vec2* pos, const char* fmt, ...) { //float h = ft_font->h / .63; // Slightly increases font size. char text[256]; va_list ap; + if(ft_font == NULL) ft_font = &gl_defFont; + if(fmt == NULL) return; else { // convert the symbols to text. @@ -353,8 +359,8 @@ static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* te bitmap = bitmap_glyph->bitmap; // To simplify. // Need the POT wrapping for GL. - w = pot(bitmap.width); - h = pot(bitmap.rows); + w = _pot(bitmap.width); + h = _pot(bitmap.rows); // Memory for textured data. // Bitmap is useing two channels, one for luminosity and one for alpha. @@ -406,6 +412,8 @@ static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* te } void gl_fontInit(gl_font* font, const char* fname, unsigned int h) { + if(font == NULL) font = &gl_defFont; + font->textures = malloc(sizeof(GLuint)*128); font->h = h; @@ -438,6 +446,7 @@ void gl_fontInit(gl_font* font, const char* fname, unsigned int h) { } void gl_freeFont(gl_font* font) { + if(font == NULL) font = &gl_defFont; glDeleteLists(font->list_base, 128); glDeleteTextures(128, font->textures); free(font->textures); @@ -455,7 +464,7 @@ int gl_init(void) { flags |= SDL_FULLSCREEN * gl_screen.fullscreen; // Initializes video. - if(SDL_Init(SDL_INIT_VIDEO) < 0) { + if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { WARN("Unable to initialize SDL: %s", SDL_GetError()); return -1; } diff --git a/src/opengl.h b/src/opengl.h index f9613f5..fb0866f 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -45,6 +45,7 @@ typedef struct { } gl_font; // gl_font loading/freeing. +// If font is NULL it uses the internal default font, same with gl_print void gl_fontInit(gl_font* font, const char* fname, unsigned int h); void gl_freeFont(gl_font* font); diff --git a/src/player.c b/src/player.c index 550b758..161a641 100644 --- a/src/player.c +++ b/src/player.c @@ -1,139 +1,188 @@ +#include <malloc.h> #include "def.h" #include "pilot.h" #include "log.h" #include "player.h" -Pilot* player = NULL; -static unsigned int player_flags = PLAYER_FLAG_NULL; +#define KEY_PRESS 1. +#define KEY_RELEASE -1. -static double player_turn = 0.; -static double player_acc = 0.; +// Keybind structure. +typedef struct { + char* name; // Keybinding name, taken from keybindNames[] + KeybindType type; // type, defined in player.h. + int key; // Key/axis/button event number. + double reverse; // 1. if normal, -1 if reversed, only useful for joystick axis. +} Keybind; +static Keybind** player_input; // Contains the players keybindings. +// Name of each keybinding. +const char* keybindNames[] = { "accel", "left", "right" }; -// To be used in pilot.c +Pilot* player = NULL; // extern in pilot.h +static double player_turn = 0.; // Turn velocity from input. +static double player_acc = 0.; // Accel velocity from input. + +// Used in pilot.c +// Basically uses keyboard input instead of AI input. void player_think(Pilot* player, const double dt) { player->solid->dir_vel = 0.; if(player_turn) - player->solid->dir_vel -= player->ship->turn*player_turn/(double)(1<<15); -#if 0 - if(player_isFlag(PLAYER_FLAG_MOV_LEFT)) - player->solid->dir_vel += player->ship->turn; - if(player_isFlag(PLAYER_FLAG_MOV_RIGHT)) - player->solid->dir_vel -= player->ship->turn; -#endif + player->solid->dir_vel -= player->ship->turn * player_turn; - player->solid->force = player->ship->thrust*player_acc/(double)(1<<15); + player->solid->force = player->ship->thrust * player_acc; } -// Flag manipulationz. -int player_isFlag(unsigned int flag) { - return player_flags & flag; +// Initialization/exit functions (does not assign keys). +void input_init(void) { + Keybind* tmp; + int i; + for(i = 0; keybindNames[i]; i++); // Get number of bindings. + player_input = (Keybind**)malloc(i*sizeof(Keybind*)); + + // Create a null keybinding for each. + for(i = 0; keybindNames[i]; i++) { + tmp = MALLOC_L(Keybind); + tmp->name = (char*)keybindNames[i]; + tmp->type = KEYBIND_NULL; + tmp->key = 0; + tmp->reverse = 1.; + player_input[i] = tmp; + } } -void player_setFlag(unsigned int flag) { - if(!player_isFlag(flag)) - player_flags |= flag; +void input_exit(void) { + int i; + for(i = 0; keybindNames[i]; i++) + free(player_input[i]); + free(player_input); } -void player_rmFlag(unsigned int flag) { - if(player_isFlag(flag)) - player_flags ^= flag; +// Binds key of type [type] to action keybind. +void input_setKeybind(char* keybind, KeybindType type, int key, int reverse) { + int i; + for(i = 0; keybindNames[i]; i++) { + if(strcmp(keybind, player_input[i]->name)==0) { + player_input[i]->type = type; + player_input[i]->key = key; + player_input[i]->reverse = reverse ? -1. : 1.; + return; + } + } +} + +// == Run input method. ================================================ +// keynum : Index of the player_input keybind. +// value : Value of keypress (defined above). +// abs : Whether or not it's an abs value (For those pesky joysticks. +// ===================================================================== +static void input_key(int keynum, double value, int abs) { + if(strcmp(player_input[keynum]->name, "accel")==0) { + if(abs)player_acc = value; + else player_acc += value; + } + else if(strcmp(player_input[keynum]->name, "left")==0) { + if(abs)player_turn = -value; + else player_turn -= value; + } + else if(strcmp(player_input[keynum]->name, "right")==0) { + if(abs) player_turn = value; + else player_turn += value; + } + + //Make sure values are sane. + player_acc = ABS(player_acc); + if(player_acc > 1.) player_acc = 1.; + if(player_turn > 1.) player_turn = 1.; + else if(player_turn < -1.) player_turn = -1.; } // --Events-- +static void input_joyaxis(int axis, int value); +static void input_joydown(int button); +static void input_joyup(int button); +static void input_keydown(SDLKey key); +static void input_keyup(SDLKey key); + // Joystick. -static void handle_joyaxis(int axis, int value) { - switch(axis) { - case 0: - player_turn = (double)value; - break; - case 1: - if(value <= 0) - player_acc = (double)-value; - break; - } + +// Axis. +static void input_joyaxis(int axis, int value) { + int i; + for(i = 0; keybindNames[i]; i++) + if(player_input[i]->type == KEYBIND_JAXIS && player_input[i]->key == axis) { + input_key(i, -(player_input[i]->reverse) * (double)value / 32767., 1); + return; + } } -static void handle_joydown(int button) { - switch(button) { - case 0: - player_acc += (double)(1<<15); - break; - case 1: - break; - } +// Joystick button down. +static void input_joydown(int button) { + int i; + for(i = 0; keybindNames[i]; i++) + if(player_input[i]->type == KEYBIND_JBUTTON && player_input[i]->key == button) { + input_key(i, KEY_RELEASE, 0); + return; + } } -static void handle_joyup(int button) { - switch(button) { - case 0: - player_acc -=(double)(1<<15); - break; - case 1: - break; - } +// Joystick button up. +static void input_joyup(int button) { + int i; + for(i = 0; keybindNames[i]; i++) + if(player_input[i]->type == KEYBIND_JBUTTON && player_input[i]->key == button) { + input_key(i, KEY_RELEASE, 0); + return; + } } // Keyboard. -static void handle_keydown(SDLKey key) { + +// Key down. +static void input_keydown(SDLKey key) { + int i; + for(i = 0; keybindNames[i]; i++) + if(player_input[i]->type == KEYBIND_KEYBOARD && player_input[i]->key == key) { + input_key(i, KEY_PRESS, 0); + return; + } + + // Fire Escape. SDL_Event quit; - switch(key) { - case SDLK_ESCAPE: - quit.type = SDL_QUIT; - SDL_PushEvent(&quit); - break; - case SDLK_LEFT: - case SDLK_a: - player_turn -= (double)(1<<15); - break; - case SDLK_RIGHT: - case SDLK_d: - player_turn += (double)(1<<15); - break; - case SDLK_UP: - case SDLK_w: - player_acc += (double)(1<<15); - break; - default: - break; + if(key == SDLK_ESCAPE) { + quit.type = SDL_QUIT; + SDL_PushEvent(&quit); } } -static void handle_keyup(SDLKey key) { - switch(key) { - case SDLK_LEFT: - case SDLK_a: - player_turn += (double)(1<<15); - break; - case SDLK_RIGHT: - case SDLK_d: - player_turn -= (double)(1<<15); - break; - case SDLK_UP: - case SDLK_w: - player_acc -= (double)(1<<15); - //break; - default: - break; - } +// Key up. +static void input_keyup(SDLKey key) { + int i; + for(i = 0; keybindNames[i]; i++) + if(player_input[i]->type == KEYBIND_KEYBOARD && player_input[i]->key == key) { + input_key(i, KEY_RELEASE, 0); + return; + } } // Global input. -void handle_input(SDL_Event* event) { + +// Just seperates the event types. +void input_handle(SDL_Event* event) { switch(event->type) { case SDL_JOYAXISMOTION: - handle_joyaxis(event->jaxis.axis, event->jaxis.value); + input_joyaxis(event->jaxis.axis, event->jaxis.value); break; case SDL_JOYBUTTONDOWN: - handle_joydown(event->jbutton.button); + input_joydown(event->jbutton.button); break; case SDL_JOYBUTTONUP: - handle_joyup(event->jbutton.button); + input_joyup(event->jbutton.button); case SDL_KEYDOWN: - handle_keydown(event->key.keysym.sym); + input_keydown(event->key.keysym.sym); break; case SDL_KEYUP: - handle_keyup(event->key.keysym.sym); + input_keyup(event->key.keysym.sym); break; } } diff --git a/src/player.h b/src/player.h index 4ed69d7..8db8010 100644 --- a/src/player.h +++ b/src/player.h @@ -1,16 +1,15 @@ #pragma once #include <SDL.h> -// Flags. -#define PLAYER_FLAG_NULL (1<<0) -#define PLAYER_FLAG_MOV_LEFT (1<<1) -#define PLAYER_FLAG_MOV_RIGHT (1<<2) -#define PLAYER_FLAG_MOV_ACC (1<<3) +typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType; int player_isFlag(unsigned int flag); void player_setFlag(unsigned int flag); void player_rmFlag(unsigned int flag); // Input. -void handle_input(SDL_Event* event); +void input_init(void); +void input_exit(void); +void input_set_Keybind(char* keybind, KeybindType type, int key, int reverse); +void input_handle(SDL_Event* event); diff --git a/src/space.c b/src/space.c index 3258767..0a372b5 100644 --- a/src/space.c +++ b/src/space.c @@ -1,5 +1,3 @@ -#include <SDL.h> -#include <SDL_opengl.h> #include "log.h" #include "physics.h" #include "opengl.h" @@ -21,9 +19,9 @@ void space_init(void) { nstars = (500*gl_screen.w*gl_screen.h + STAR_BUF*STAR_BUF)/(800*640);; stars = malloc(sizeof(Star)*nstars); for(i = 0; i < nstars; i++) { - stars[i].brightness = (float)RNG(50, 200)/256.; - stars[i].pos.x = (float)RNG(-STAR_BUF, gl_screen.w + STAR_BUF); - stars[i].pos.y = (float)RNG(-STAR_BUF, gl_screen.h + STAR_BUF); + stars[i].brightness = (double)RNG(50, 200)/256.; + stars[i].pos.x = (double)RNG(-STAR_BUF, gl_screen.w + STAR_BUF); + stars[i].pos.y = (double)RNG(-STAR_BUF, gl_screen.h + STAR_BUF); } }