summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.build.yml4
-rw-r--r--.gitmodules3
-rw-r--r--CHANGES2
-rw-r--r--build.zig8
m---------lib/gfz0
-rw-r--r--src/Files.h1
-rw-r--r--src/Game.h11
-rw-r--r--src/GameInitDispose.cpp106
-rw-r--r--src/GameLoop.cpp291
-rw-r--r--src/GameTick.cpp35
-rw-r--r--src/MacInput.cpp22
-rw-r--r--src/MacInput.h99
-rw-r--r--src/Person.cpp72
-rw-r--r--src/Support.cpp39
-rw-r--r--src/Support.h5
-rw-r--r--src/Textures.h1
-rw-r--r--src/Timer.cpp26
-rw-r--r--src/Timer.h15
-rw-r--r--src/config.h4
-rw-r--r--src/config.zig12
-rw-r--r--src/main.zig31
21 files changed, 228 insertions, 559 deletions
diff --git a/.build.yml b/.build.yml
index 9216c2f..e9ba3b6 100644
--- a/.build.yml
+++ b/.build.yml
@@ -1,9 +1,9 @@
 image: archlinux
 packages:
+  - glfw
   - glu
   - libvorbis
   - openal
-  - sdl
   - stb
   - zig
 sources:
@@ -11,4 +11,4 @@ sources:
 tasks:
   - build: |
       cd blackshades
-      zig build
+      zig build -Drelease-fast=true
diff --git a/.gitmodules b/.gitmodules
index 1c3b457..9e32438 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,6 @@
 [submodule "lib/ini"]
 	path = lib/ini
 	url = https://github.com/ziglibs/ini
+[submodule "lib/gfz"]
+	path = lib/gfz
+	url = https://git.sr.ht/~cnx/gfz
diff --git a/CHANGES b/CHANGES
index 0e9d072..c999f94 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+Future changes shall be noted in git tag messages.
+
 Tag:	2.0.0
 Date:	2021-08-13
 
diff --git a/build.zig b/build.zig
index 86a81db..7294e1a 100644
--- a/build.zig
+++ b/build.zig
@@ -14,7 +14,6 @@ pub fn build(b: *std.build.Builder) void {
     exe.addCSourceFile("src/GameLoop.cpp", &cxxflags);
     exe.addCSourceFile("src/GameTick.cpp", &cxxflags);
     exe.addCSourceFile("src/Globals.cpp", &cxxflags);
-    exe.addCSourceFile("src/MacInput.cpp", &cxxflags);
     exe.addCSourceFile("src/Models.cpp", &cxxflags);
     exe.addCSourceFile("src/Person.cpp", &cxxflags);
     exe.addCSourceFile("src/Quaternions.cpp", &cxxflags);
@@ -23,17 +22,18 @@ pub fn build(b: *std.build.Builder) void {
     exe.addCSourceFile("src/Sprites.cpp", &cxxflags);
     exe.addCSourceFile("src/Support.cpp", &cxxflags);
     exe.addCSourceFile("src/Text.cpp", &cxxflags);
-    exe.addCSourceFile("src/Timer.cpp", &cxxflags);
     exe.addCSourceFile("src/Textures.cpp", &cxxflags);
 
+    exe.addPackage(.{ .name = "gfz", .path = "lib/gfz/src/gfz.zig" });
+    exe.linkSystemLibrary("glfw");
     exe.addPackage(.{ .name = "ini", .path = "lib/ini/src/ini.zig" });
     exe.addPackage(.{ .name = "loca", .path = "lib/loca/src/main.zig" });
     exe.addPackage(.{ .name = "zeal", .path = "lib/zeal/src/zeal.zig" });
+    exe.linkSystemLibrary("openal");
+
     exe.linkSystemLibrary("GL");
     exe.linkSystemLibrary("GLU");
-    exe.linkSystemLibrary("SDL");
     exe.linkSystemLibrary("c++");
-    exe.linkSystemLibrary("openal");
     exe.linkSystemLibrary("vorbisfile");
 
     // Standard target options allows the person running `zig build` to choose
diff --git a/lib/gfz b/lib/gfz
new file mode 160000
+Subproject be76fd8b6e8ce2c4be4a53e0f3e9ced369ad5e6
diff --git a/src/Files.h b/src/Files.h
index b743e2b..48eba94 100644
--- a/src/Files.h
+++ b/src/Files.h
@@ -13,7 +13,6 @@
 #include <GL/gl.h>
 #include <GL/glu.h>
 
-#include "MacInput.h"              // Header for Special Mac Input functions
 #include "Support.h"
 
 #define FILE_STRINGS              130
diff --git a/src/Game.h b/src/Game.h
index 0d819c6..d2b454f 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -32,11 +32,8 @@
 #include <string.h>
 #include <ctype.h>
 #include <cstdarg>
-#include <SDL/SDL.h>
 #include <AL/al.h>
 
-#include "Timer.h"
-#include "MacInput.h"
 #include "Quaternions.h"
 #include "Camera.h"
 #include "Skeleton.h"
@@ -57,19 +54,17 @@
 class Game {
 	void saveHighScore();
 	void updateSong();
-	void handleMenu(unsigned char*);
-	void handleToggles(unsigned char*);
+	void handleMenu();
+	void handleToggles();
 	void mouseLook();
 	XYZ aimPlayer();
 	XYZ aimBot(int);
 	void setListener(XYZ&);
 public:
 	// Event loop
-	Boolean	gQuit;
 	float gamespeed;
 	float multiplier2, multiplier3, multiplier4, multiplier5;
-	float end, start, timetaken, framespersecond;
-	timer theTimer;
+	float framespersecond;
 	float sps;
 	int maxfps;
 
diff --git a/src/GameInitDispose.cpp b/src/GameInitDispose.cpp
index b208df5..7599837 100644
--- a/src/GameInitDispose.cpp
+++ b/src/GameInitDispose.cpp
@@ -21,6 +21,7 @@
 // along with Black Shades.  If not, see <https://www.gnu.org/licenses/>.
 
 #include <AL/alc.h>
+#include <GLFW/glfw3.h>
 
 #include "config.h"
 #include "Textures.h"
@@ -61,9 +62,10 @@ extern int psychickey;
 Game* makeGame(Config config)
 {
 	auto game = new Game();
-	game->screenwidth = config.screen_width;
-	game->screenheight = config.screen_height;
+	game->screenwidth = config.width;
+	game->screenheight = config.height;
 	game->usermousesensitivity = config.mouse_sensitivity;
+	game->mousesensitivity = game->usermousesensitivity;
 	game->debug = config.debug;
 	game->vblsync = config.vsync;
 	blood = config.blood;
@@ -72,6 +74,27 @@ Game* makeGame(Config config)
 	game->customlevels = config.custom_levels;
 	game->musictoggle = config.music;
 	game->azertykeyboard = config.azerty;
+
+	if (!game->initialized) {
+		// TODO: Read high score
+		ifstream ipstream2 {"highscore.txt"};
+		if (!ipstream2) {
+			ofstream opstream("highscore.txt");
+			opstream << (game->highscore = 0) << endl;
+			opstream << (game->beatgame = 0) << endl;
+			opstream.close();
+		} else {
+			ipstream2 >> game->highscore;
+			ipstream2.ignore(256,'\n');
+			ipstream2 >> game->beatgame;
+			ipstream2.close();
+		}
+
+		game->sps = 40;
+		game->maxfps = 90;
+		game->disttest = true;
+		game->cubetest = true;
+	}
 	return game;
 }
 
@@ -370,7 +393,7 @@ void Game::LoadingScreen(float percent)
 	static char string[256]="";
 	sprintf (string, "LOADING...");
 	text.glPrint(280,195,string,1,1,640,480);
-	SDL_GL_SwapBuffers( );
+	glfwSwapBuffers(glfwGetCurrentContext());
 }
 
 void LoadPersonSpriteTexture(char *fileName, GLuint *textureid)
@@ -658,25 +681,24 @@ void initGame(Game* game)
 
 	if (!game->initialized) {
 		if (game->azertykeyboard) {
-			forwardskey = MAC_Z_KEY;
-			backwardskey = MAC_S_KEY;
-			leftkey = MAC_Q_KEY;
-			rightkey = MAC_D_KEY;
-			aimkey = MAC_A_KEY;
-			psychicaimkey = MAC_E_KEY;
-			psychickey = MAC_W_KEY;
+			forwardskey = GLFW_KEY_Z;
+			backwardskey = GLFW_KEY_S;
+			leftkey = GLFW_KEY_Q;
+			rightkey = GLFW_KEY_D;
+			aimkey = GLFW_KEY_A;
+			psychicaimkey = GLFW_KEY_E;
+			psychickey = GLFW_KEY_W;
 		} else {
-			forwardskey = MAC_W_KEY;
-			backwardskey = MAC_S_KEY;
-			leftkey = MAC_A_KEY;
-			rightkey = MAC_D_KEY;
-			aimkey = MAC_Q_KEY;
-			psychicaimkey = MAC_E_KEY;
-			psychickey = MAC_Z_KEY;
+			forwardskey = GLFW_KEY_W;
+			backwardskey = GLFW_KEY_S;
+			leftkey = GLFW_KEY_A;
+			rightkey = GLFW_KEY_D;
+			aimkey = GLFW_KEY_Q;
+			psychicaimkey = GLFW_KEY_E;
+			psychickey = GLFW_KEY_Z;
 		}
 
 		soundscalefactor=soundscalefactordefault; //Setup sound falloff
-		game->gQuit = false;
 
 		// Sounds
 		LoadSounds(game->musictoggle);
@@ -1787,61 +1809,17 @@ void initGame(Game* game)
 	decals.howmanydecals=0;
 	sprites.howmanysprites=0;
 	game->losedelay = 1;
+	game->framespersecond = 60.0f;
 }
 
 void initGl(Game* game)
 {
-	// Config
-	game->mousesensitivity = 1.0f;
-	if (!game->initialized) {
-		// TODO: Read high score
-		ifstream ipstream2 {"highscore.txt"};
-		if (!ipstream2) {
-			ofstream opstream("highscore.txt");
-			opstream << (game->highscore = 0) << endl;
-			opstream << (game->beatgame = 0) << endl;
-			opstream.close();
-		} else {
-			ipstream2 >> game->highscore;
-			ipstream2.ignore(256,'\n');
-			ipstream2 >> game->beatgame;
-			ipstream2.close();
-		}
-
-		game->sps = 40;
-		game->maxfps = 90;
-		game->disttest = true;
-		game->cubetest = true;
-	}
-
-	// Setup screen
-	if (SDL_Init(SDL_INIT_VIDEO) == -1) {
-		fprintf(stderr, "SDL Init Video failed: %s\n", SDL_GetError());
-		exit(EXIT_FAILURE);
-	}
-	atexit(SDL_Quit);
-
-	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
-	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
-	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
-	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
-	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
-	if (SDL_SetVideoMode(game->screenwidth, game->screenheight,
-	                     0, SDL_OPENGL) == NULL) {
-		fprintf(stderr, "(OpenGL) SDL SetVideoMode failed: %s\n",
-			SDL_GetError());
-		exit(EXIT_FAILURE);
-	}
-	SDL_WM_SetCaption("Black Shades", "Black Shades");
-	SDL_EnableUNICODE(1); /* toggle it to ON */
-
 	game->text.LoadFontTexture((char*) ":Data:Textures:Font.png");
 	game->text.BuildFont();
 	glAlphaFunc(GL_GREATER, 0.01);
 	glDepthFunc(GL_LESS);
 	glPolygonOffset(-8,0);
-	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
 
 GLvoid Game::ReSizeGLScene(float fov, float near)
diff --git a/src/GameLoop.cpp b/src/GameLoop.cpp
index a4b4a60..c0caaaf 100644
--- a/src/GameLoop.cpp
+++ b/src/GameLoop.cpp
@@ -19,6 +19,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Black Shades.  If not, see <https://www.gnu.org/licenses/>.
 
+#include "GLFW/glfw3.h"
+
 #include "Game.h"
 
 extern float multiplier;
@@ -106,237 +108,66 @@ void Game::HandleKeyDown(char key)
 	}
 }
 
-static int mapinit = 0;
-static int sdlkeymap[SDLK_LAST];
-static unsigned char ourkeys[16];
-
-static void init_sdlkeymap()
-{
-	int i;
-	for (i = 0; i < SDLK_LAST; i++)
-		sdlkeymap[i] = -1;
-
-	sdlkeymap[SDLK_1] = MAC_1_KEY;
-	sdlkeymap[SDLK_2] = MAC_2_KEY;
-	sdlkeymap[SDLK_3] = MAC_3_KEY;
-	sdlkeymap[SDLK_4] = MAC_4_KEY;
-	sdlkeymap[SDLK_5] = MAC_5_KEY;
-	sdlkeymap[SDLK_6] = MAC_6_KEY;
-	sdlkeymap[SDLK_7] = MAC_7_KEY;
-	sdlkeymap[SDLK_8] = MAC_8_KEY;
-	sdlkeymap[SDLK_9] = MAC_9_KEY;
-	sdlkeymap[SDLK_0] = MAC_0_KEY;
-	sdlkeymap[SDLK_KP1] = MAC_NUMPAD_1_KEY;
-	sdlkeymap[SDLK_KP2] = MAC_NUMPAD_2_KEY;
-	sdlkeymap[SDLK_KP3] = MAC_NUMPAD_3_KEY;
-	sdlkeymap[SDLK_KP4] = MAC_NUMPAD_4_KEY;
-	sdlkeymap[SDLK_KP5] = MAC_NUMPAD_5_KEY;
-	sdlkeymap[SDLK_KP6] = MAC_NUMPAD_6_KEY;
-	sdlkeymap[SDLK_KP7] = MAC_NUMPAD_7_KEY;
-	sdlkeymap[SDLK_KP8] = MAC_NUMPAD_8_KEY;
-	sdlkeymap[SDLK_KP9] = MAC_NUMPAD_9_KEY;
-	sdlkeymap[SDLK_KP0] = MAC_NUMPAD_0_KEY;
-	sdlkeymap[SDLK_a] = MAC_A_KEY;
-	sdlkeymap[SDLK_b] = MAC_B_KEY;
-	sdlkeymap[SDLK_c] = MAC_C_KEY;
-	sdlkeymap[SDLK_d] = MAC_D_KEY;
-	sdlkeymap[SDLK_e] = MAC_E_KEY;
-	sdlkeymap[SDLK_f] = MAC_F_KEY;
-	sdlkeymap[SDLK_g] = MAC_G_KEY;
-	sdlkeymap[SDLK_h] = MAC_H_KEY;
-	sdlkeymap[SDLK_i] = MAC_I_KEY;
-	sdlkeymap[SDLK_j] = MAC_J_KEY;
-	sdlkeymap[SDLK_k] = MAC_K_KEY;
-	sdlkeymap[SDLK_l] = MAC_L_KEY;
-	sdlkeymap[SDLK_m] = MAC_M_KEY;
-	sdlkeymap[SDLK_n] = MAC_N_KEY;
-	sdlkeymap[SDLK_o] = MAC_O_KEY;
-	sdlkeymap[SDLK_p] = MAC_P_KEY;
-	sdlkeymap[SDLK_q] = MAC_Q_KEY;
-	sdlkeymap[SDLK_r] = MAC_R_KEY;
-	sdlkeymap[SDLK_s] = MAC_S_KEY;
-	sdlkeymap[SDLK_t] = MAC_T_KEY;
-	sdlkeymap[SDLK_u] = MAC_U_KEY;
-	sdlkeymap[SDLK_v] = MAC_V_KEY;
-	sdlkeymap[SDLK_w] = MAC_W_KEY;
-	sdlkeymap[SDLK_x] = MAC_X_KEY;
-	sdlkeymap[SDLK_y] = MAC_Y_KEY;
-	sdlkeymap[SDLK_z] = MAC_Z_KEY;
-	sdlkeymap[SDLK_F1] = MAC_F1_KEY;
-	sdlkeymap[SDLK_F2] = MAC_F2_KEY;
-	sdlkeymap[SDLK_F3] = MAC_F3_KEY;
-	sdlkeymap[SDLK_F4] = MAC_F4_KEY;
-	sdlkeymap[SDLK_F5] = MAC_F5_KEY;
-	sdlkeymap[SDLK_F6] = MAC_F6_KEY;
-	sdlkeymap[SDLK_F7] = MAC_F7_KEY;
-	sdlkeymap[SDLK_F8] = MAC_F8_KEY;
-	sdlkeymap[SDLK_F9] = MAC_F9_KEY;
-	sdlkeymap[SDLK_F10] = MAC_F10_KEY;
-	sdlkeymap[SDLK_F11] = MAC_F11_KEY;
-	sdlkeymap[SDLK_F12] = MAC_F12_KEY;
-	sdlkeymap[SDLK_RETURN] = MAC_RETURN_KEY;
-	sdlkeymap[SDLK_KP_ENTER] = MAC_ENTER_KEY;
-	sdlkeymap[SDLK_TAB] = MAC_TAB_KEY;
-	sdlkeymap[SDLK_SPACE] = MAC_SPACE_KEY;
-	sdlkeymap[SDLK_BACKSPACE] = MAC_DELETE_KEY;
-	sdlkeymap[SDLK_ESCAPE] = MAC_ESCAPE_KEY;
-	sdlkeymap[SDLK_LCTRL] = MAC_CONTROL_KEY;
-	sdlkeymap[SDLK_RCTRL] = MAC_CONTROL_KEY;
-	sdlkeymap[SDLK_LSHIFT] = MAC_SHIFT_KEY;
-	sdlkeymap[SDLK_RSHIFT] = MAC_SHIFT_KEY;
-	sdlkeymap[SDLK_CAPSLOCK] = MAC_CAPS_LOCK_KEY;
-	sdlkeymap[SDLK_LALT] = MAC_OPTION_KEY;
-	sdlkeymap[SDLK_RALT] = MAC_OPTION_KEY;
-	sdlkeymap[SDLK_PAGEUP] = MAC_PAGE_UP_KEY;
-	sdlkeymap[SDLK_PAGEDOWN] = MAC_PAGE_DOWN_KEY;
-	sdlkeymap[SDLK_INSERT] = MAC_INSERT_KEY;
-	sdlkeymap[SDLK_DELETE] = MAC_DEL_KEY;
-	sdlkeymap[SDLK_HOME] = MAC_HOME_KEY;
-	sdlkeymap[SDLK_END] = MAC_END_KEY;
-	sdlkeymap[SDLK_LEFTBRACKET] = MAC_LEFT_BRACKET_KEY;
-	sdlkeymap[SDLK_RIGHTBRACKET] = MAC_RIGHT_BRACKET_KEY;
-	sdlkeymap[SDLK_UP] = MAC_ARROW_UP_KEY;
-	sdlkeymap[SDLK_DOWN] = MAC_ARROW_DOWN_KEY;
-	sdlkeymap[SDLK_LEFT] = MAC_ARROW_LEFT_KEY;
-	sdlkeymap[SDLK_RIGHT] = MAC_ARROW_RIGHT_KEY;
-
-	mapinit = 1;
-}
-
-void GetKeys(unsigned long *keys)
-{
-	/* this is just weird */
-	memcpy(keys, ourkeys, sizeof(ourkeys));
-}
-
-static void DoSDLKey(Game *g, SDL_Event *event)
-{
-	if (mapinit == 0)
-		init_sdlkeymap();
-
-	int mackey = sdlkeymap[event->key.keysym.sym];
-	if (mackey != -1) {
-		int index = mackey / 8;
-		int mask = 1 << (mackey % 8);
-
-		if (event->type == SDL_KEYDOWN)
-			ourkeys[index] |= mask;
-		else
-			ourkeys[index] &= ~mask;
-	}
-
-	if (event->key.keysym.unicode
-	    && !(event->key.keysym.unicode & 0xFF80))
-		/* hey, at least it was aleady public */
-		g->HandleKeyDown(event->key.keysym.unicode);
-}
-
-static void ProcessSDLEvents(Game* g)
-{
-	SDL_Event event;
-	while (SDL_PollEvent(&event)) {
-		switch (event.type) {
-		case SDL_KEYDOWN:
-			if (event.key.keysym.sym == SDLK_RETURN
-			    && event.key.keysym.mod & KMOD_ALT) {
-				SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
-				break;
-			} else if (event.key.keysym.sym == SDLK_g
-			           && event.key.keysym.mod & KMOD_CTRL) {
-				if (SDL_WM_GrabInput(SDL_GRAB_QUERY)
-				    == SDL_GRAB_OFF) {
-					SDL_WM_GrabInput(SDL_GRAB_ON);
-					SDL_ShowCursor(SDL_DISABLE);
-				} else {
-					SDL_WM_GrabInput(SDL_GRAB_OFF);
-					SDL_ShowCursor(SDL_ENABLE);
-				}
-				break;
-			}
-		case SDL_KEYUP:
-			DoSDLKey(g, &event);
-			break;
-		case SDL_QUIT:
-			exit(0);
-		}
-	}
-}
-
 void eventLoop(Game* game)
 {
-	unsigned char theKeyMap[16];
-	game->gQuit = false;
-	game->framespersecond = 60.0f;
-
-	while (!game->gQuit) {
-		ProcessSDLEvents(game);
-		game->start = TimerGetTime(&game->theTimer);
-
-		GLfloat oldmult = multiplier;
-		int colaccuracy = min(game->sps,
-			game->sps / game->framespersecond + 1.0f);
-		multiplier /= colaccuracy;
-		for (int i = 0; i < (int) (colaccuracy + 0.5f); i++)
-			game->Tick();
-		if (game->DrawGLScene())
-			SDL_GL_SwapBuffers();
-		else
-			game->gQuit = true;
-		multiplier = oldmult;
-
-		do {
-			game->end = TimerGetTime(&game->theTimer);
-			game->timetaken = game->end - game->start;
-			game->framespersecond = 6e8f / game->timetaken;
-		} while (game->framespersecond > game->maxfps);
-
-		game->multiplier5 = game->multiplier4;
-		game->multiplier4 = game->multiplier3;
-		game->multiplier3 = game->multiplier2;
-		game->multiplier2 = 1 / game->framespersecond;
-		multiplier = (game->multiplier2 + game->multiplier3
-			+ game->multiplier4 + game->multiplier5) / 4.0f;
-		multiplier = min(max(multiplier, 0.00001f), 1.0f);
-		if (visions == 1 && !game->mainmenu)
-			multiplier /= 3;
-		if (slomo)
-			multiplier /= 5;
-		if (game->paused)
-			multiplier = 0;
-
-		GetKeys((unsigned long*) theKeyMap);
-		if (IsKeyDown(theKeyMap, MAC_COMMAND_KEY)
-		    &&IsKeyDown(theKeyMap, MAC_Q_KEY)) {
-			game->gQuit = true;
-			if (game->score > game->highscore) {
-				game->highscore = game->score;
-				/* TODO */
-				ofstream opstream("highscore.txt");
-				opstream << game->highscore;
-				opstream << "\n";
-				opstream << game->beatgame;
-				opstream.close();
-			}
-		}
-
-		if (IsKeyDown(theKeyMap, MAC_ESCAPE_KEY)) {
-			alSourcePause(gSourceID[rainsound]);
-			game->mainmenu = 1;
-			alSourcePlay(gSourceID[souloutsound]);
-			game->flashamount = 1.0f;
-			game->flashr = game->flashg = game->flashb = 1.0f;
-			alSourceStop(gSourceID[visionsound]);
-			game->whichsong = mainmenusong;
-			alSourceStop(gSourceID[knifesong]);
-			alSourceStop(gSourceID[shootsong]);
-			alSourceStop(gSourceID[zombiesong]);
-			alSourceStop(gSourceID[mainmenusong]);
-			alSourcef(gSourceID[knifesong], AL_MIN_GAIN, 0);
-			alSourcef(gSourceID[shootsong], AL_MIN_GAIN, 0);
-			alSourcef(gSourceID[zombiesong], AL_MIN_GAIN, 0);
-			alSourcef(gSourceID[mainmenusong], AL_MIN_GAIN, 0);
-			alSourcePlay(gSourceID[game->whichsong]);
-			alSourcef(gSourceID[game->whichsong], AL_MIN_GAIN, 1);
-		}
+	/*
+	 * SDL_Event event;
+	 * while (SDL_PollEvent(&event)) {
+	 * 	if (event.type == SDL_KEYUP
+	 * 	    && event.key.keysym.unicode
+	 * 	    && !(event.key.keysym.unicode & 0xFF80))
+	 * 		game->HandleKeyDown(event.key.keysym.unicode);
+	 * }
+	 */
+
+	auto start = glfwGetTime();
+	GLfloat oldmult = multiplier;
+	int colaccuracy = min(game->sps,
+		game->sps / game->framespersecond + 1.0f);
+	multiplier /= colaccuracy;
+	for (int i = 0; i < (int) (colaccuracy + 0.5f); i++)
+		game->Tick();
+	auto window = glfwGetCurrentContext();
+	if (game->DrawGLScene())
+		glfwSwapBuffers(window);
+	else
+		glfwSetWindowShouldClose(window, GLFW_TRUE);
+	multiplier = oldmult;
+
+	do game->framespersecond = 1.0 / (glfwGetTime() - start);
+	while (game->framespersecond > game->maxfps);
+
+	game->multiplier5 = game->multiplier4;
+	game->multiplier4 = game->multiplier3;
+	game->multiplier3 = game->multiplier2;
+	game->multiplier2 = 1 / game->framespersecond;
+	multiplier = (game->multiplier2 + game->multiplier3
+		+ game->multiplier4 + game->multiplier5) / 4.0f;
+	multiplier = min(max(multiplier, 0.00001f), 1.0f);
+	if (visions == 1 && !game->mainmenu)
+		multiplier /= 3;
+	if (slomo)
+		multiplier /= 5;
+	if (game->paused)
+		multiplier = 0;
+
+	if (IsKeyDown(GLFW_KEY_ESCAPE)) {
+		alSourcePause(gSourceID[rainsound]);
+		game->mainmenu = 1;
+		alSourcePlay(gSourceID[souloutsound]);
+		game->flashamount = 1.0f;
+		game->flashr = game->flashg = game->flashb = 1.0f;
+		alSourceStop(gSourceID[visionsound]);
+		game->whichsong = mainmenusong;
+		alSourceStop(gSourceID[knifesong]);
+		alSourceStop(gSourceID[shootsong]);
+		alSourceStop(gSourceID[zombiesong]);
+		alSourceStop(gSourceID[mainmenusong]);
+		alSourcef(gSourceID[knifesong], AL_MIN_GAIN, 0);
+		alSourcef(gSourceID[shootsong], AL_MIN_GAIN, 0);
+		alSourcef(gSourceID[zombiesong], AL_MIN_GAIN, 0);
+		alSourcef(gSourceID[mainmenusong], AL_MIN_GAIN, 0);
+		alSourcePlay(gSourceID[game->whichsong]);
+		alSourcef(gSourceID[game->whichsong], AL_MIN_GAIN, 1);
 	}
 }
diff --git a/src/GameTick.cpp b/src/GameTick.cpp
index 2932d8c..6536547 100644
--- a/src/GameTick.cpp
+++ b/src/GameTick.cpp
@@ -22,6 +22,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Black Shades.  If not, see <https://www.gnu.org/licenses/>.
 
+#include <GLFW/glfw3.h>
+
 #include "Game.h"
 
 extern float multiplier;
@@ -122,18 +124,19 @@ void Game::updateSong()
 	alSourcePlay(gSourceID[whichsong]);
 }
 
-void Game::handleMenu(unsigned char* theKeyMap)
+void Game::handleMenu()
 {
-	if (IsKeyDown(theKeyMap, MAC_SPACE_KEY))
+	if (IsKeyDown(GLFW_KEY_SPACE))
 		mainmenu = 0;
 
 	GetMouse(&mouseloc);
 	float mousex = (float) mouseloc.h * 640 / screenwidth;
 	float mousey = 480 - (float) mouseloc.v * 480 / screenheight;
 
+	int button = Button();
 	oldmouseoverbutton = mouseoverbutton;
 	mouseoverbutton = 0;
-	if (mousex > 120 && mousex < 560 && Button() && !oldbutton) {
+	if (mousex > 120 && mousex < 560 && button && !oldbutton) {
 		if (mousey > 235 && mousey < 305)
 			mouseoverbutton = 1;
 		else if (mousey > 112 && mousey < 182)
@@ -141,7 +144,7 @@ void Game::handleMenu(unsigned char* theKeyMap)
 	} else if (!mainmenuness) {
 		mouseoverbutton = 1;
 	}
-	oldbutton = Button();
+	oldbutton = button;
 
 	switch (mouseoverbutton) {
 	case 1:
@@ -168,7 +171,7 @@ void Game::handleMenu(unsigned char* theKeyMap)
 		} else {
 			flashamount = flashr = 1;
 			flashg = flashb = 0;
-			gQuit = true;
+			glfwSetWindowShouldClose(glfwGetCurrentContext(), true);
 		}
 
 		alSourcePlay(gSourceID[losesound]);
@@ -177,9 +180,9 @@ void Game::handleMenu(unsigned char* theKeyMap)
 	}
 }
 
-void Game::handleToggles(unsigned char* theKeyMap)
+void Game::handleToggles()
 {
-	if (!IsKeyDown(theKeyMap, psychickey)) {
+	if (!IsKeyDown(psychickey)) {
 		oldvisionkey = 0;
 	} else if (!oldvisionkey) {
 		oldvisionkey = 1;
@@ -220,7 +223,7 @@ void Game::handleToggles(unsigned char* theKeyMap)
 		}
 	}
 
-	if (!IsKeyDown(theKeyMap, MAC_TAB_KEY)) {
+	if (!IsKeyDown(GLFW_KEY_TAB)) {
 		tabkeydown = 0;
 	} else if (!tabkeydown && debug) {
 		thirdperson++;
@@ -229,13 +232,13 @@ void Game::handleToggles(unsigned char* theKeyMap)
 		tabkeydown = 1;
 	}
 
-	if (!IsKeyDown(theKeyMap, aimkey)) {
+	if (!IsKeyDown(aimkey)) {
 		aimtoggle = 0;
 	} else if (!aimtoggle) {
 		person[0].aiming ^= aimtoggle = 1;
 	}
 
-	if (!IsKeyDown(theKeyMap, MAC_R_KEY)) {
+	if (!IsKeyDown(GLFW_KEY_R)) {
 		reloadtoggle = 0;
 	} else if (!reloadtoggle) {
 		if (person[0].reloads[person[0].whichgun] > 0
@@ -244,7 +247,7 @@ void Game::handleToggles(unsigned char* theKeyMap)
 		reloadtoggle = 1;
 	}
 
-	if (!IsKeyDown(theKeyMap, psychicaimkey)) {
+	if (!IsKeyDown(psychicaimkey)) {
 		slomokeydown = 0;
 	} else if (!slomokeydown && !slomo) {
 		flashamount = 0.5;
@@ -407,10 +410,8 @@ XYZ Game::aimBot(int j)
 
 void Game::Tick()
 {
-	unsigned char theKeyMap[16];
-	GetKeys((unsigned long*) theKeyMap);
 	if (mainmenu) {
-		handleMenu(theKeyMap);
+		handleMenu();
 		return;
 	}
 
@@ -471,7 +472,7 @@ void Game::Tick()
 	flatfacing.y = 0;
 	Normalise(&flatfacing);
 
-	handleToggles(theKeyMap);
+	handleToggles();
 	mouseLook();
 
 	//Check collision with buildings
@@ -690,7 +691,7 @@ void Game::Tick()
 
 	}
 
-	if (IsKeyDown(theKeyMap, MAC_SPACE_KEY)
+	if (IsKeyDown(GLFW_KEY_SPACE)
 	    && person[0].playerrotation == person[0].playerlowrotation
 	    && person[0].targetanimation == joganim
 	    && person[0].currentanimation == joganim
@@ -2138,7 +2139,7 @@ void Game::Tick()
 
 			XYZ end {start + aim * 1000};
 			if (debug && j == 0
-			    && IsKeyDown(theKeyMap, MAC_G_KEY)) {
+			    && IsKeyDown(GLFW_KEY_G)) {
 				sprites.MakeSprite(grenadesprite, 1, 1, 1, 1,
 					start, aim * 200, 1.01);
 				continue;
diff --git a/src/MacInput.cpp b/src/MacInput.cpp
deleted file mode 100644
index a52a1d7..0000000
--- a/src/MacInput.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-/**> HEADER FILES <**/
-#include "MacInput.h"
-
-/********************> IsKeyDown() <*****/
-Boolean	IsKeyDown( unsigned char *keyMap, unsigned short theKey )
-{
-	long	keyMapIndex;
-	Boolean	isKeyDown;
-	short	bitToCheck;
-
-	// Calculate the key map index
-	keyMapIndex = keyMap[theKey/8];
-
-	// Calculate the individual bit to check
-	bitToCheck = theKey%8;
-
-	// Check the status of the key
-	isKeyDown = ( keyMapIndex >> bitToCheck ) & 0x01;
-
-	// Return the status of the key
-	return isKeyDown;
-}
diff --git a/src/MacInput.h b/src/MacInput.h
deleted file mode 100644
index fbe2c6d..0000000
--- a/src/MacInput.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef _MACINPUT_H_
-#define _MACINPUT_H_
-
-/**> HEADER FILES <**/
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "Support.h"
-
-/**> CONSTANT DECLARATIONS <**/
-// Mac Keyboard Codes
-#define	MAC_1_KEY				0x12
-#define	MAC_2_KEY				0x13
-#define	MAC_3_KEY				0x14
-#define	MAC_4_KEY				0x15
-#define	MAC_5_KEY				0x17
-#define	MAC_6_KEY				0x16
-#define	MAC_7_KEY				0x1A
-#define	MAC_8_KEY				0x1C
-#define	MAC_9_KEY				0x19
-#define	MAC_0_KEY				0x1D
-#define	MAC_NUMPAD_1_KEY		0x53
-#define	MAC_NUMPAD_2_KEY		0x54
-#define	MAC_NUMPAD_3_KEY		0x55
-#define	MAC_NUMPAD_4_KEY		0x56
-#define	MAC_NUMPAD_5_KEY		0x57
-#define	MAC_NUMPAD_6_KEY		0x58
-#define	MAC_NUMPAD_7_KEY		0x59
-#define	MAC_NUMPAD_8_KEY		0x5B
-#define	MAC_NUMPAD_9_KEY		0x5C
-#define	MAC_NUMPAD_0_KEY		0x52
-#define	MAC_A_KEY				0x00
-#define	MAC_B_KEY				0x0B
-#define	MAC_C_KEY				0x08
-#define	MAC_D_KEY				0x02
-#define	MAC_E_KEY				0x0E
-#define	MAC_F_KEY				0x03
-#define	MAC_G_KEY				0x05
-#define	MAC_H_KEY				0x04
-#define	MAC_I_KEY				0x22
-#define	MAC_J_KEY				0x26
-#define	MAC_K_KEY				0x28
-#define	MAC_L_KEY				0x25
-#define	MAC_M_KEY				0x2E
-#define	MAC_N_KEY				0x2D
-#define	MAC_O_KEY				0x1F
-#define	MAC_P_KEY				0x23
-#define	MAC_Q_KEY				0x0C
-#define	MAC_R_KEY				0x0F
-#define	MAC_S_KEY				0x01
-#define	MAC_T_KEY				0x11
-#define	MAC_U_KEY				0x20
-#define	MAC_V_KEY				0x09
-#define	MAC_W_KEY				0x0D
-#define	MAC_X_KEY				0x07
-#define	MAC_Y_KEY				0x10
-#define	MAC_Z_KEY				0x06
-#define	MAC_F1_KEY				0x7A
-#define	MAC_F2_KEY				0x78
-#define	MAC_F3_KEY				0x63
-#define	MAC_F4_KEY				0x76
-#define	MAC_F5_KEY				0x60
-#define	MAC_F6_KEY				0x61
-#define	MAC_F7_KEY				0x62
-#define	MAC_F8_KEY				0x64
-#define	MAC_F9_KEY				0x65
-#define	MAC_F10_KEY				0x6D
-#define	MAC_F11_KEY				0x67
-#define	MAC_F12_KEY				0x6F
-#define	MAC_RETURN_KEY			0x24
-#define	MAC_ENTER_KEY			0x4C
-#define	MAC_TAB_KEY				0x30
-#define	MAC_SPACE_KEY			0x31
-#define	MAC_DELETE_KEY			0x33
-#define	MAC_ESCAPE_KEY			0x35
-#define	MAC_COMMAND_KEY			0x37
-#define	MAC_SHIFT_KEY			0x38
-#define	MAC_CAPS_LOCK_KEY		0x39
-#define	MAC_OPTION_KEY			0x3A
-#define	MAC_CONTROL_KEY			0x3B
-#define	MAC_PAGE_UP_KEY			0x74
-#define	MAC_PAGE_DOWN_KEY		0x79
-#define	MAC_INSERT_KEY			0x72
-#define	MAC_DEL_KEY				0x75
-#define	MAC_HOME_KEY			0x73
-#define	MAC_END_KEY				0x77
-#define	MAC_LEFT_BRACKET_KEY	0x21
-#define	MAC_RIGHT_BRACKET_KEY	0x1E
-#define	MAC_ARROW_UP_KEY		0x7E
-#define	MAC_ARROW_DOWN_KEY		0x7D
-#define	MAC_ARROW_LEFT_KEY		0x7B
-#define	MAC_ARROW_RIGHT_KEY		0x7C
-
-/**> FUNCTION PROTOTYPES <**/
-Boolean	IsKeyDown( unsigned char *keyMap, unsigned short theKey );
-void 	MoveMouse(int xcoord, int ycoord, Point *mouseloc);
-void 	RefreshMouse(Point *mouseloc);
-
-#endif
diff --git a/src/Person.cpp b/src/Person.cpp
index d02d002..9e49cbb 100644
--- a/src/Person.cpp
+++ b/src/Person.cpp
@@ -17,6 +17,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Black Shades.  If not, see <https://www.gnu.org/licenses/>.
 
+#include <GLFW/glfw3.h>
+
 #include "Person.h"
 
 extern float multiplier;
@@ -680,42 +682,47 @@ void 	Person::DoStuff(int who){
 		if(visions==0&&targetanimation==joganim)speed=2.2;
 		if(visions==0&&targetanimation!=joganim)speed=1.3;
 		if(visions==0&&targetanimation==walkanim)speed=2.5;
-		unsigned char	theKeyMap[16];
-		GetKeys( ( unsigned long * )theKeyMap );
 
-		if(IsKeyDown( theKeyMap, MAC_SHIFT_KEY )||visions==1){
-			moveanim=joganim;
-		}else{
+		if (IsKeyDown(GLFW_KEY_LEFT_SHIFT) || visions == 1)
+			moveanim = joganim;
+		else
 			moveanim=walkanim;
+		if (IsKeyDown(GLFW_KEY_LEFT_CONTROL)
+		    && currentanimation == idleanim
+		    && targetanimation == idleanim) {
+			targetanimation = crouchanim;
+			target = 0;
 		}
-		if(IsKeyDown( theKeyMap, MAC_CONTROL_KEY )&&currentanimation==idleanim&&targetanimation==idleanim){
-			targetanimation=crouchanim;
-			target=0;
-		}
-		if(!IsKeyDown( theKeyMap, MAC_CONTROL_KEY )&&currentanimation==crouchanim&&targetanimation==crouchanim){
-			targetanimation=idleanim;
-			target=0;
+		if (!IsKeyDown(GLFW_KEY_LEFT_CONTROL)
+		    && currentanimation == crouchanim
+		    && targetanimation == crouchanim) {
+			targetanimation = idleanim;
+			target = 0;
 		}
 		if((onground||(who==0&&visions==1))&&currentanimation!=crouchanim){
-			if ( IsKeyDown( theKeyMap, forwardskey )&&!( IsKeyDown( theKeyMap, backwardskey ))){
+			if (IsKeyDown(forwardskey) && !IsKeyDown(backwardskey)) {
 				if(targetanimation!=moveanim)targetframe=0;
 				targetanimation=moveanim;
 			}
-			if ( IsKeyDown( theKeyMap, rightkey )&&!( IsKeyDown( theKeyMap, leftkey ))){
+			if (IsKeyDown(rightkey) && !IsKeyDown(leftkey)) {
 				if(targetanimation!=moveanim)targetframe=0;
 				targetanimation=moveanim;
 				playerlowrotation-=90;
-				if(IsKeyDown( theKeyMap, forwardskey ))playerlowrotation+=45;
-				if(IsKeyDown( theKeyMap, backwardskey ))playerlowrotation-=235;
+				if (IsKeyDown(forwardskey))
+					playerlowrotation += 45;
+				if (IsKeyDown(backwardskey))
+					playerlowrotation -= 235;
 			}
-			if ( IsKeyDown( theKeyMap, leftkey )&&!( IsKeyDown( theKeyMap, rightkey ))){
+			if (IsKeyDown(leftkey) && !IsKeyDown(rightkey)) {
 				if(targetanimation!=moveanim)targetframe=0;
 				targetanimation=moveanim;
 				playerlowrotation+=90;
-				if(IsKeyDown( theKeyMap, forwardskey ))playerlowrotation-=45;
-				if(IsKeyDown( theKeyMap, backwardskey ))playerlowrotation+=235;
+				if (IsKeyDown(forwardskey))
+					playerlowrotation -= 45;
+				if (IsKeyDown(backwardskey))
+					playerlowrotation += 235;
 			}
-			if ( IsKeyDown( theKeyMap, backwardskey )){
+			if (IsKeyDown(backwardskey)) {
 				if(targetanimation!=moveanim)targetframe=0;
 				targetanimation=moveanim;
 				backwardsanim=1;
@@ -724,31 +731,36 @@ void 	Person::DoStuff(int who){
 		//air control
 		if(!onground){
 			float oldplayerrotation=playerrotation;
-			if ( IsKeyDown( theKeyMap, forwardskey )&&!( IsKeyDown( theKeyMap, backwardskey ))){
+			if (IsKeyDown(forwardskey) && !IsKeyDown(backwardskey)) {
 				facing=0;
 				facing.z=1;
 				facing=DoRotation(facing,0,playerrotation,0);
 				velocity=velocity+facing*multiplier*4;
 			}
-			if ( IsKeyDown( theKeyMap, rightkey )&&!( IsKeyDown( theKeyMap, leftkey ))){
+			if (IsKeyDown(rightkey) && !IsKeyDown(leftkey)) {
 				playerrotation-=90;
-				if(IsKeyDown( theKeyMap, forwardskey ))playerrotation+=45;
-				if(IsKeyDown( theKeyMap, backwardskey ))playerrotation-=45;
+				if (IsKeyDown(forwardskey))
+					playerrotation += 45;
+				if (IsKeyDown(backwardskey))
+					playerrotation -= 45;
 				facing=0;
 				facing.z=1;
 				facing=DoRotation(facing,0,playerrotation,0);
 				velocity=velocity+facing*multiplier*4;
 			}
-			if ( IsKeyDown( theKeyMap, leftkey )&&!( IsKeyDown( theKeyMap, rightkey ))){
+			if (IsKeyDown(leftkey) && !IsKeyDown(rightkey)) {
 				playerrotation+=90;
-				if(IsKeyDown( theKeyMap, forwardskey ))playerrotation-=45;
-				if(IsKeyDown( theKeyMap, backwardskey ))playerrotation+=45;
+				if (IsKeyDown(forwardskey))
+					playerrotation -= 45;
+				if (IsKeyDown(backwardskey))
+					playerrotation += 45;
 				facing=0;
 				facing.z=1;
 				facing=DoRotation(facing,0,playerrotation,0);
 				velocity=velocity+facing*multiplier*4;
 			}
-			if ( IsKeyDown( theKeyMap, backwardskey )&&!IsKeyDown( theKeyMap, forwardskey )&&!IsKeyDown( theKeyMap, leftkey )&&!IsKeyDown( theKeyMap, rightkey )){
+			if (IsKeyDown(backwardskey) && !IsKeyDown(forwardskey)
+			    && !IsKeyDown(leftkey) && !IsKeyDown(rightkey)) {
 				playerrotation+=180;
 				facing=0;
 				facing.z=1;
@@ -757,7 +769,9 @@ void 	Person::DoStuff(int who){
 			}
 			playerrotation=oldplayerrotation;
 		}
-		if(!IsKeyDown( theKeyMap, forwardskey )&&!IsKeyDown( theKeyMap, leftkey )&&!IsKeyDown( theKeyMap, rightkey )&&!IsKeyDown( theKeyMap, backwardskey )&&(targetanimation==joganim||targetanimation==walkanim)){
+		if (!IsKeyDown(forwardskey) && !IsKeyDown(leftkey)
+		    && !IsKeyDown(rightkey) && !IsKeyDown(backwardskey)
+		    && (targetanimation==joganim||targetanimation==walkanim)) {
 			if(!(targetanimation==walkanim&&(targetframe==0||targetframe==2))){
 				targetanimation=idleanim;
 				targetframe=0;
diff --git a/src/Support.cpp b/src/Support.cpp
index 33794d9..4703b14 100644
--- a/src/Support.cpp
+++ b/src/Support.cpp
@@ -6,7 +6,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#include <SDL/SDL.h>
+#include <GLFW/glfw3.h>
 #include <vorbis/vorbisfile.h>
 
 #include "Support.h"
@@ -21,38 +21,23 @@ int Random()
 #endif
 }
 
-void Microseconds(UnsignedWide *microTickCount)
-{
-	/* NOTE: hi isn't used in BS, so it's not implemented here */
-	/* TODO: does game need microsecond precision? */
-	microTickCount->hi = 0;
-	microTickCount->lo = SDL_GetTicks() * 1000;
-}
-
 void GetMouse(Point *p)
 {
-	int x;
-	int y;
-
-	SDL_GetMouseState(&x, &y);
-
-	p->h = x;
-	p->v = y;
+	double xpos, ypos;
+	glfwGetCursorPos(glfwGetCurrentContext(), &xpos, &ypos);
+	p->h = xpos;
+	p->v = ypos;
 }
 
 void GetMouseRel(Point *p)
 {
-	int x;
-	int y;
-
-	SDL_GetRelativeMouseState(&x, &y);
-
-	p->h = x;
-	p->v = y;
+	return GetMouse(p);
 }
+
 int Button(void)
 {
-	return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(1));
+	auto window = glfwGetCurrentContext();
+	return glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
 }
 
 void MoveMouse(int xcoord, int ycoord, Point *mouseloc)
@@ -61,6 +46,12 @@ void MoveMouse(int xcoord, int ycoord, Point *mouseloc)
 	GetMouse(mouseloc);
 }
 
+bool IsKeyDown(int key)
+{
+	auto window = glfwGetCurrentContext();
+	return glfwGetKey(window, key) == GLFW_PRESS;
+}
+
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
diff --git a/src/Support.h b/src/Support.h
index d0bbd92..83ea163 100644
--- a/src/Support.h
+++ b/src/Support.h
@@ -32,11 +32,12 @@ typedef struct Point
 #define FSClose(fildes) close(fildes)
 
 int Random();
-void Microseconds(UnsignedWide *microTickCount);
 void GetMouse(Point *p);
 void GetMouseRel(Point *p);
-void GetKeys(unsigned long *keys);
+void MoveMouse(int xcoord, int ycoord, Point *mouseloc);
 int Button(void);
+bool IsKeyDown(int key);
+
 void loadOgg(char* filename, ALuint buffer, ALuint source);
 
 FILE *cfh_fopen(const char *filename, const char *mode);
diff --git a/src/Textures.h b/src/Textures.h
index 9c1a60f..d9fb92a 100644
--- a/src/Textures.h
+++ b/src/Textures.h
@@ -19,7 +19,6 @@
 #ifndef BLACKSHADES_TEXTURES_H
 #define BLACKSHADES_TEXTURES_H
 
-#include <SDL/SDL.h>
 #include <GL/gl.h>
 
 GLuint loadTexture(const char* filename, GLenum minFilter = GL_LINEAR,
diff --git a/src/Timer.cpp b/src/Timer.cpp
deleted file mode 100644
index 869c154..0000000
--- a/src/Timer.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/**> HEADER FILES <**/
-#include <string.h>
-#include "Timer.h"
-#include "Support.h"
-
-/********************> Timer <*****/
-void TimerInit(timer* theTimer)
-{
-	UnsignedWide			ms;
-
-	Microseconds(&ms);
-
-	memset(theTimer, 0, sizeof(timer));
-
-	theTimer->mm_timer_start	= ms.lo;
-	theTimer->mm_timer_elapsed	= theTimer->mm_timer_start;
-}
-
-float TimerGetTime(timer* theTimer)
-{
-	UnsignedWide			ms;
-
-	Microseconds(&ms);
-
-	return( (float) (ms.lo - theTimer->mm_timer_start) * 1000.0f);
-}
diff --git a/src/Timer.h b/src/Timer.h
deleted file mode 100644
index 2974383..0000000
--- a/src/Timer.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _TIMER_H_
-#define _TIMER_H_
-
-/**> HEADER FILES <**/
-class timer
-{
-	public:
-	unsigned long mm_timer_start;
-	unsigned long mm_timer_elapsed;
-};
-
-void TimerInit(timer* theTimer);
-float TimerGetTime(timer* theTimer);
-
-#endif
diff --git a/src/config.h b/src/config.h
index fa456b2..3443853 100644
--- a/src/config.h
+++ b/src/config.h
@@ -5,8 +5,8 @@
 #include <stdint.h>
 
 struct Config {
-	int screen_width;
-	int screen_height;
+	int width;
+	int height;
 	float mouse_sensitivity;
 	bool debug;
 	bool vsync;
diff --git a/src/config.zig b/src/config.zig
index 4bde82c..f382d77 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -29,8 +29,8 @@ const std = @import("std");
 
 /// Game configuration.
 pub const Config = extern struct {
-    screen_width: c_int = 640,
-    screen_height: c_int = 480,
+    width: c_int = 640,
+    height: c_int = 480,
     mouse_sensitivity: f32 = 0.7,
     debug: bool = false,
     vsync: bool = true,
@@ -67,8 +67,8 @@ pub fn parse(allocator: *Allocator, base_dir: []const u8) !Config {
         const output = try createFile(path, .{});
         defer output.close();
         const writer = output.writer();
-        try writer.print("screen width = {}\n", .{ config.screen_width });
-        try writer.print("screen height = {}\n", .{ config.screen_height });
+        try writer.print("screen width = {}\n", .{ config.width });
+        try writer.print("screen height = {}\n", .{ config.height });
         try writer.print("mouse sensitivity = {d:.1}\n",
                          .{ config.mouse_sensitivity });
         try writer.print("debug = {}\n", .{ config.debug });
@@ -89,9 +89,9 @@ pub fn parse(allocator: *Allocator, base_dir: []const u8) !Config {
     while (try parser.next()) |record|
         switch (record) {
             .property => |kv| if (eql(u8, kv.key, "screen width")) {
-                config.screen_width = try parseInt(c_int, kv.value, 10);
+                config.width = try parseInt(c_int, kv.value, 10);
             } else if (eql(u8, kv.key, "screen height")) {
-                config.screen_height = try parseInt(c_int, kv.value, 10);
+                config.height = try parseInt(c_int, kv.value, 10);
             } else if (eql(u8, kv.key, "mouse_sensitivity")) {
                 config.mouse_sensitivity = try parseFloat(f32, kv.value);
             } else if (eql(u8, kv.key, "debug")) {
diff --git a/src/main.zig b/src/main.zig
index baca0e0..8552e10 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -18,24 +18,41 @@
 
 const Loca = @import("loca").Loca;
 const allocator = @import("std").heap.c_allocator;
+const gf = @import("gfz");
 const legacy = @cImport(@cInclude("Game.h"));
 const configuration = @import("config.zig");
-const zeal = @import("zeal");
+const al = @import("zeal");
+const gl = @import("zgl");
 
 pub fn main() !void {
     const loca = try Loca.init(allocator, .{});
     defer loca.deinit();
     const config = try configuration.parse(allocator, loca.user_config);
+    const game = legacy.makeGame(@bitCast(legacy.Config, config));
+
+    try gf.init();
+    defer gf.deinit() catch unreachable;
+    const window = try gf.Window.create(config.width, config.height,
+                                        "Black Shades", .{}, .{});
+    try window.makeCurrent();
+    try window.setInputMode(.sticky_keys, true);
+    if (config.menu) {
+        try window.setInputMode(.sticky_mouse_buttons, true);
+        try window.setCursorMode(.hidden);
+    }
+    legacy.initGl(game);
 
-    const device = try zeal.Device.init(null);
+    const device = try al.Device.init(null);
     defer device.deinit() catch unreachable;
-    const context = try zeal.Context.init(device, &.{ });
+    const context = try al.Context.init(device, &.{});
     defer context.deinit() catch unreachable;
-    try zeal.useContext(context);
+    try al.useContext(context);
 
-    const game = legacy.makeGame(@bitCast(legacy.Config, config));
-    legacy.initGl(game);
     legacy.initGame(game);
     defer legacy.closeGame(game);
-    legacy.eventLoop(game);
+    while (!try window.shouldClose()) {
+        legacy.eventLoop(game);
+        try window.swapBuffers();
+        try gf.pollEvents();
+    }
 }