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);
   }
 }