diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index 76fce5e475172bdf3fe39577ff83f696434f5aee..e0c2f32735cb8d2fbc451031e1e6ae7b4a74d9fd 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -84,6 +84,8 @@ EXPORT void HWRAPI(EndScreenWipe) (void);
 EXPORT void HWRAPI(DoScreenWipe) (float alpha);
 EXPORT void HWRAPI(DrawIntermissionBG) (void);
 EXPORT void HWRAPI(MakeScreenTexture) (void);
+EXPORT void HWRAPI(MakeScreenFinalTexture) (void);
+EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height);
 // ==========================================================================
 //                                      HWR DRIVER OBJECT, FOR CLIENT PROGRAM
 // ==========================================================================
@@ -127,6 +129,8 @@ struct hwdriver_s
 	DoScreenWipe        pfnDoScreenWipe;
 	DrawIntermissionBG  pfnDrawIntermissionBG;
 	MakeScreenTexture   pfnMakeScreenTexture;
+	MakeScreenFinalTexture  pfnMakeScreenFinalTexture;
+	DrawScreenFinalTexture  pfnDrawScreenFinalTexture;
 };
 
 extern struct hwdriver_s hwdriver;
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 90bbea6fa878579a488633d9698765fbb45609bf..ae940d96c6ec0b6d409bfb9670c000be2d2757d0 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -5936,4 +5936,14 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
 		HWRWipeCounter = 1.0f;
 }
 
+void HWR_MakeScreenFinalTexture(void)
+{
+    HWD.pfnMakeScreenFinalTexture();
+}
+
+void HWR_DrawScreenFinalTexture(int width, int height)
+{
+    HWD.pfnDrawScreenFinalTexture(width, height);
+}
+
 #endif // HWRENDER
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 969946442d1e67ca55db6fde5e238ab5411459db..af7d821b1ac437632a062db460e09edffc2038bb 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -65,6 +65,8 @@ void HWR_StartScreenWipe(void);
 void HWR_EndScreenWipe(void);
 void HWR_DrawIntermissionBG(void);
 void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum);
+void HWR_MakeScreenFinalTexture(void);
+void HWR_DrawScreenFinalTexture(int width, int height);
 
 // This stuff is put here so MD2's can use them
 UINT32 HWR_Lighting(INT32 light, UINT32 color, UINT32 fadecolor, boolean fogblockpoly, boolean plane);
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 631bb66586fed9106a50d043de1bae43009f100f..028bc9889eccb920eb4eca47cfce7c764649101e 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -110,6 +110,7 @@ static GLint       viewport[4];
 static GLuint screentexture = 60000;
 static GLuint startScreenWipe = 60001;
 static GLuint endScreenWipe = 60002;
+static GLuint finalScreenTexture = 60003;
 #if 0
 GLuint screentexture = FIRST_TEX_AVAIL;
 #endif
@@ -269,8 +270,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
 #endif
 #ifndef MINI_GL_COMPATIBILITY
 /* 1.3 functions for multitexturing */
-#define pglActiveTexture, glActiveTexture;
-#define pglMultiTexCoord2f, glMultiTexCoord2f;
+#define pglActiveTexture glActiveTexture
+#define pglMultiTexCoord2f glMultiTexCoord2f
 #endif
 #else //!STATIC_OPENGL
 
@@ -520,13 +521,44 @@ boolean SetupGLfunc(void)
 // This has to be done after the context is created so the version number can be obtained
 boolean SetupGLFunc13(void)
 {
+	const GLubyte *version = pglGetString(GL_VERSION);
+	int glmajor, glminor;
+
+	gl13 = false;
 #ifdef MINI_GL_COMPATIBILITY
 	return false;
 #else
 #ifdef STATIC_OPENGL
 	gl13 = true;
 #else
-	if (isExtAvailable("GL_ARB_multitexture", gl_extensions))
+
+	// Parse the GL version
+	if (version != NULL)
+	{
+		if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
+		{
+			// Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
+			switch (glmajor)
+			{
+				case 1:
+					if (glminor == 3) gl13 = true;
+					break;
+				case 2:
+				case 3:
+				case 4:
+					gl13 = true;
+				default:
+					break;
+			}
+		}
+	}
+
+	if (gl13)
+	{
+		pglActiveTexture = GetGLFunc("glActiveTexture");
+		pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f");
+	}
+	else if (isExtAvailable("GL_ARB_multitexture", gl_extensions))
 	{
 		// Get the functions
 		pglActiveTexture  = GetGLFunc("glActiveTextureARB");
@@ -2245,6 +2277,7 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha)
 		pglActiveTexture(GL_TEXTURE0);
 		pglEnable(GL_TEXTURE_2D);
 		pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
+		pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
 		pglActiveTexture(GL_TEXTURE1);
 		pglEnable(GL_TEXTURE_2D);
@@ -2339,4 +2372,77 @@ EXPORT void HWRAPI(MakeScreenTexture) (void)
 	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
 }
 
+EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
+{
+	INT32 texsize = 2048;
+
+	// Use a power of two texture, dammit
+	if(screen_width <= 512)
+		texsize = 512;
+	else if(screen_width <= 1024)
+		texsize = 1024;
+
+	// Create screen texture
+	pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
+#ifdef KOS_GL_COMPATIBILITY
+	pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE);
+	pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE);
+#else
+	pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+#endif
+	Clamp2D(GL_TEXTURE_WRAP_S);
+	Clamp2D(GL_TEXTURE_WRAP_T);
+#ifndef KOS_GL_COMPATIBILITY
+	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, texsize, texsize, 0);
+#endif
+
+	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+
+}
+
+EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
+{
+	float xfix, yfix;
+	INT32 texsize = 2048;
+
+	if(screen_width <= 1024)
+		texsize = 1024;
+	if(screen_width <= 512)
+		texsize = 512;
+
+	xfix = 1/((float)(texsize)/((float)((screen_width))));
+	yfix = 1/((float)(texsize)/((float)((screen_height))));
+
+	//pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+	pglViewport(0, 0, width, height);
+
+	pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
+	pglBegin(GL_QUADS);
+
+		pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+		// Bottom left
+		pglTexCoord2f(0.0f, 0.0f);
+		pglVertex3f(-1, -1, 1.0f);
+
+		// Top left
+		pglTexCoord2f(0.0f, yfix);
+		pglVertex3f(-1, 1, 1.0f);
+
+		// Top right
+		pglTexCoord2f(xfix, yfix);
+		pglVertex3f(1, 1, 1.0f);
+
+		// Bottom right
+		pglTexCoord2f(xfix, 0.0f);
+		pglVertex3f(1, -1, 1.0f);
+
+	pglEnd();
+
+	SetModelView(screen_width, screen_height);
+	SetStates();
+
+	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+}
+
 #endif //HWRENDER
diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c
index 44ddf830ca43f4eafc8049c31089b7ecb2a6d1cd..54f5da3a083da6d9b3b9159b059389cbc7bc8271 100644
--- a/src/sdl/hwsym_sdl.c
+++ b/src/sdl/hwsym_sdl.c
@@ -105,6 +105,8 @@ void *hwSym(const char *funcName,void *handle)
 	GETFUNC(DoScreenWipe);
 	GETFUNC(DrawIntermissionBG);
 	GETFUNC(MakeScreenTexture);
+	GETFUNC(MakeScreenFinalTexture);
+	GETFUNC(DrawScreenFinalTexture);
 #else //HWRENDER
 	if (0 == strcmp("FinishUpdate", funcName))
 		return funcPointer; //&FinishUpdate;
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index d3793b6da79367bb6b2786e25a5f40352e2caaf7..a1e91ec754b83815e8cb48cb0b950b5b2065a836 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -301,37 +301,38 @@ SDL_bool framebuffer = SDL_FALSE;
 
 UINT8 keyboard_started = false;
 
-#if 0
-static void signal_handler(INT32 num)
+FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
 {
 	//static char msg[] = "oh no! back to reality!\r\n";
-	char *      sigmsg;
+	const char *      sigmsg;
 	char        sigdef[32];
 
+	D_QuitNetGame(); // Fix server freezes
+
 	switch (num)
 	{
 	case SIGINT:
-		sigmsg = "interrupt";
+		sigmsg = "SIGINT - interrupted";
 		break;
 	case SIGILL:
-		sigmsg = "illegal instruction - invalid function image";
+		sigmsg = "SIGILL - illegal instruction - invalid function image";
 		break;
 	case SIGFPE:
-		sigmsg = "floating point exception";
+		sigmsg = "SIGFPE - floating point exception";
 		break;
 	case SIGSEGV:
-		sigmsg = "segment violation";
+		sigmsg = "SIGSEGV - segment violation";
 		break;
 	case SIGTERM:
-		sigmsg = "Software termination signal from kill";
+		sigmsg = "SIGTERM - Software termination signal from kill";
 		break;
 #if !(defined (__unix_) || defined (UNIXCOMMON))
 	case SIGBREAK:
-		sigmsg = "Ctrl-Break sequence";
+		sigmsg = "SIGBREAK - Ctrl-Break sequence";
 		break;
 #endif
 	case SIGABRT:
-		sigmsg = "abnormal termination triggered by abort call";
+		sigmsg = "SIGABRT - abnormal termination triggered by abort call";
 		break;
 	default:
 		sprintf(sigdef,"signal number %d", num);
@@ -339,13 +340,17 @@ static void signal_handler(INT32 num)
 	}
 
 	I_OutputMsg("signal_handler() error: %s\n", sigmsg);
+
+	SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
+		"Signal caught",
+		sigmsg, NULL);
+	I_ShutdownSystem();
 	signal(num, SIG_DFL);               //default signal action
 	raise(num);
 	I_Quit();
 }
-#endif
 
-#if defined (NDEBUG) && !defined (DC) && !defined (_WIN32_WCE)
+#if !defined (DC)
 FUNCNORETURN static ATTRNORETURN void quit_handler(int num)
 {
 	signal(num, SIG_DFL); //default signal action
@@ -737,21 +742,21 @@ static inline void I_ShutdownConsole(void){}
 //
 void I_StartupKeyboard (void)
 {
-#if defined (NDEBUG) && !defined (DC)
+#if !defined (DC)
 #ifdef SIGILL
-//	signal(SIGILL , signal_handler);
+	signal(SIGILL , signal_handler);
 #endif
 #ifdef SIGINT
 	signal(SIGINT , quit_handler);
 #endif
 #ifdef SIGSEGV
-//	signal(SIGSEGV , signal_handler);
+	signal(SIGSEGV , signal_handler);
 #endif
 #ifdef SIGBREAK
 	signal(SIGBREAK , quit_handler);
 #endif
 #ifdef SIGABRT
-//	signal(SIGABRT , signal_handler);
+	signal(SIGABRT , signal_handler);
 #endif
 #ifdef SIGTERM
 	signal(SIGTERM , quit_handler);
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index a59db26cc529a934de705fa701aa549af5d161d6..660263b3fb3424b72a41ba24fa080cda2d08589a 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -124,8 +124,8 @@ static      SDL_Color    localPalette[256];
 static      SDL_Rect   **modeList = NULL;
 static       Uint8       BitsPerPixel = 16;
 #endif
-static       Uint16      realwidth = BASEVIDWIDTH;
-static       Uint16      realheight = BASEVIDHEIGHT;
+Uint16      realwidth = BASEVIDWIDTH;
+Uint16      realheight = BASEVIDHEIGHT;
 static const Uint32      surfaceFlagsW = 0/*|SDL_RESIZABLE*/;
 static const Uint32      surfaceFlagsF = 0;
 static       SDL_bool    mousegrabok = SDL_TRUE;
@@ -174,7 +174,6 @@ static void Impl_SetWindowIcon(void);
 static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
 {
 	static SDL_bool wasfullscreen = SDL_FALSE;
-	static SDL_bool glfallbackresolution = SDL_FALSE;
 	Uint32 rmask;
 	Uint32 gmask;
 	Uint32 bmask;
@@ -195,16 +194,15 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
 		else if (!fullscreen && wasfullscreen)
 		{
 			wasfullscreen = SDL_FALSE;
-			glfallbackresolution = SDL_FALSE;
 			SDL_SetWindowFullscreen(window, 0);
 			SDL_SetWindowSize(window, width, height);
-			SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+			SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
 		}
 		else if (!wasfullscreen)
 		{
 			// Reposition window only in windowed mode
 			SDL_SetWindowSize(window, width, height);
-			SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+			SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
 		}
 	}
 	else
@@ -221,26 +219,6 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
 
 	if (rendermode == render_opengl)
 	{
-		int sdlw, sdlh;
-		SDL_GetWindowSize(window, &sdlw, &sdlh);
-		// Logical fullscreen is not implemented yet for OpenGL, so...
-		// Special case handling
-		if (glfallbackresolution == SDL_FALSE && fullscreen && width != sdlw && height != sdlh)
-		{
-			if (VID_GetModeForSize(sdlw, sdlh) != -1)
-			{
-				wasfullscreen = SDL_TRUE;
-				VID_SetMode(VID_GetModeForSize(sdlw, sdlh));
-				return;
-			}
-			else
-			{
-				wasfullscreen = SDL_TRUE;
-				glfallbackresolution = SDL_TRUE;
-				VID_SetMode(-1);
-				return;
-			}
-		}
 		OglSdlSurface(vid.width, vid.height);
 	}
 
@@ -278,221 +256,150 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
 	}
 }
 
-//
-//  Translates the SDL key into SRB2 key
-//
-
-static INT32 SDLatekey(SDL_Keycode sym)
+static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
 {
-	INT32 rc = sym + 0x80;
-
-	switch (sym)
-	{
-		case SDLK_LEFT:
-			rc = KEY_LEFTARROW;
-			break;
-		case SDLK_RIGHT:
-			rc = KEY_RIGHTARROW;
-			break;
-		case SDLK_DOWN:
-			rc = KEY_DOWNARROW;
-			break;
-		case SDLK_UP:
-			rc = KEY_UPARROW;
-			break;
-
-		case SDLK_ESCAPE:
-			rc = KEY_ESCAPE;
-			break;
-		case SDLK_SPACE:
-			rc = KEY_SPACE;
-			break;
-		case SDLK_RETURN:
-		case SDLK_KP_ENTER:
-			rc = KEY_ENTER;
-			break;
-		case SDLK_TAB:
-			rc = KEY_TAB;
-			break;
-		case SDLK_F1:
-			rc = KEY_F1;
-			break;
-		case SDLK_F2:
-			rc = KEY_F2;
-			break;
-		case SDLK_F3:
-			rc = KEY_F3;
-			break;
-		case SDLK_F4:
-			rc = KEY_F4;
-			break;
-		case SDLK_F5:
-			rc = KEY_F5;
-			break;
-		case SDLK_F6:
-			rc = KEY_F6;
-			break;
-		case SDLK_F7:
-			rc = KEY_F7;
-			break;
-		case SDLK_F8:
-			rc = KEY_F8;
-			break;
-		case SDLK_F9:
-			rc = KEY_F9;
-			break;
-		case SDLK_F10:
-			rc = KEY_F10;
-			break;
-		case SDLK_F11:
-			rc = KEY_F11;
-			break;
-		case SDLK_F12:
-			rc = KEY_F12;
-			break;
-
-		case SDLK_BACKSPACE:
-			rc = KEY_BACKSPACE;
-			break;
-		case SDLK_DELETE:
-			rc = KEY_DEL;
-			break;
-
-		case SDLK_KP_EQUALS: //Alam & Logan: WTF? Mac KB haves one! XD
-		case SDLK_PAUSE:
-			rc = KEY_PAUSE;
-			break;
-
-		case SDLK_EQUALS:
-		case SDLK_PLUS:
-			rc = KEY_EQUALS;
-			break;
-
-		case SDLK_MINUS:
-			rc = KEY_MINUS;
-			break;
-
-		case SDLK_LSHIFT:
-			rc = KEY_LSHIFT;
-			break;
-
-		case SDLK_RSHIFT:
-			rc = KEY_RSHIFT;
-			break;
-
-		case SDLK_CAPSLOCK:
-			rc = KEY_CAPSLOCK;
-			break;
-
-		case SDLK_LCTRL:
-			rc = KEY_LCTRL;
-			break;
-		case SDLK_RCTRL:
-			rc = KEY_RCTRL;
-			break;
-
-		case SDLK_LALT:
-			rc = KEY_LALT;
-			break;
-		case SDLK_RALT:
-			rc = KEY_RALT;
-			break;
-
-		case SDLK_NUMLOCKCLEAR:
-			rc = KEY_NUMLOCK;
-			break;
-		case SDLK_SCROLLLOCK:
-			rc = KEY_SCROLLLOCK;
-			break;
-
-		case SDLK_PAGEUP:
-			rc = KEY_PGUP;
-			break;
-		case SDLK_PAGEDOWN:
-			rc = KEY_PGDN;
-			break;
-		case SDLK_END:
-			rc = KEY_END;
-			break;
-		case SDLK_HOME:
-			rc = KEY_HOME;
-			break;
-		case SDLK_INSERT:
-			rc = KEY_INS;
-			break;
-
-		case SDLK_KP_0:
-			rc = KEY_KEYPAD0;
-			break;
-		case SDLK_KP_1:
-			rc = KEY_KEYPAD1;
-			break;
-		case SDLK_KP_2:
-			rc = KEY_KEYPAD2;
-			break;
-		case SDLK_KP_3:
-			rc = KEY_KEYPAD3;
-			break;
-		case SDLK_KP_4:
-			rc = KEY_KEYPAD4;
-			break;
-		case SDLK_KP_5:
-			rc = KEY_KEYPAD5;
-			break;
-		case SDLK_KP_6:
-			rc = KEY_KEYPAD6;
-			break;
-		case SDLK_KP_7:
-			rc = KEY_KEYPAD7;
-			break;
-		case SDLK_KP_8:
-			rc = KEY_KEYPAD8;
-			break;
-		case SDLK_KP_9:
-			rc = KEY_KEYPAD9;
-			break;
-
-		case SDLK_KP_PERIOD:
-			rc = KEY_KPADDEL;
-			break;
-		case SDLK_KP_DIVIDE:
-			rc = KEY_KPADSLASH;
-			break;
-		case SDLK_KP_MULTIPLY:
-			rc = '*';
-			break;
-		case SDLK_KP_MINUS:
-			rc = KEY_MINUSPAD;
-			break;
-		case SDLK_KP_PLUS:
-			rc = KEY_PLUSPAD;
-			break;
-
-		case SDLK_LMETA:
-			rc = KEY_LEFTWIN;
-			break;
-		case SDLK_RMETA:
-			rc = KEY_RIGHTWIN;
-			break;
-
-		case SDLK_MENU:
-			rc = KEY_MENU;
-			break;
-
+	if (code >= SDL_SCANCODE_A && code <= SDL_SCANCODE_Z)
+	{
+		// get lowercase ASCII
+		return code - SDL_SCANCODE_A + 'a';
+	}
+	if (code >= SDL_SCANCODE_1 && code <= SDL_SCANCODE_9)
+	{
+		return code - SDL_SCANCODE_1 + '1';
+	}
+	else if (code == SDL_SCANCODE_0)
+	{
+		return '0';
+	}
+	if (code >= SDL_SCANCODE_F1 && code <= SDL_SCANCODE_F12)
+	{
+		return KEY_F1 + (code - SDL_SCANCODE_F1);
+	}
+	switch (code)
+	{
+		case SDL_SCANCODE_KP_0:
+			return KEY_KEYPAD0;
+		case SDL_SCANCODE_KP_1:
+			return KEY_KEYPAD1;
+		case SDL_SCANCODE_KP_2:
+			return KEY_KEYPAD2;
+		case SDL_SCANCODE_KP_3:
+			return KEY_KEYPAD3;
+		case SDL_SCANCODE_KP_4:
+			return KEY_KEYPAD4;
+		case SDL_SCANCODE_KP_5:
+			return KEY_KEYPAD5;
+		case SDL_SCANCODE_KP_6:
+			return KEY_KEYPAD6;
+		case SDL_SCANCODE_KP_7:
+			return KEY_KEYPAD7;
+		case SDL_SCANCODE_KP_8:
+			return KEY_KEYPAD8;
+		case SDL_SCANCODE_KP_9:
+			return KEY_KEYPAD9;
+
+		case SDL_SCANCODE_RETURN:
+			return KEY_ENTER;
+		case SDL_SCANCODE_ESCAPE:
+			return KEY_ESCAPE;
+		case SDL_SCANCODE_BACKSPACE:
+			return KEY_BACKSPACE;
+		case SDL_SCANCODE_TAB:
+			return KEY_TAB;
+		case SDL_SCANCODE_SPACE:
+			return KEY_SPACE;
+		case SDL_SCANCODE_MINUS:
+			return KEY_MINUS;
+		case SDL_SCANCODE_EQUALS:
+			return KEY_EQUALS;
+		case SDL_SCANCODE_LEFTBRACKET:
+			return '[';
+		case SDL_SCANCODE_RIGHTBRACKET:
+			return ']';
+		case SDL_SCANCODE_BACKSLASH:
+			return '\\';
+		case SDL_SCANCODE_NONUSHASH:
+			return '#';
+		case SDL_SCANCODE_SEMICOLON:
+			return ';';
+		case SDL_SCANCODE_APOSTROPHE:
+			return '\'';
+		case SDL_SCANCODE_GRAVE:
+			return '`';
+		case SDL_SCANCODE_COMMA:
+			return ',';
+		case SDL_SCANCODE_PERIOD:
+			return '.';
+		case SDL_SCANCODE_SLASH:
+			return '/';
+		case SDL_SCANCODE_CAPSLOCK:
+			return KEY_CAPSLOCK;
+		case SDL_SCANCODE_PRINTSCREEN:
+			return 0; // undefined?
+		case SDL_SCANCODE_SCROLLLOCK:
+			return KEY_SCROLLLOCK;
+		case SDL_SCANCODE_PAUSE:
+			return KEY_PAUSE;
+		case SDL_SCANCODE_INSERT:
+			return KEY_INS;
+		case SDL_SCANCODE_HOME:
+			return KEY_HOME;
+		case SDL_SCANCODE_PAGEUP:
+			return KEY_PGUP;
+		case SDL_SCANCODE_DELETE:
+			return KEY_DEL;
+		case SDL_SCANCODE_END:
+			return KEY_END;
+		case SDL_SCANCODE_PAGEDOWN:
+			return KEY_PGDN;
+		case SDL_SCANCODE_RIGHT:
+			return KEY_RIGHTARROW;
+		case SDL_SCANCODE_LEFT:
+			return KEY_LEFTARROW;
+		case SDL_SCANCODE_DOWN:
+			return KEY_DOWNARROW;
+		case SDL_SCANCODE_UP:
+			return KEY_UPARROW;
+		case SDL_SCANCODE_NUMLOCKCLEAR:
+			return KEY_NUMLOCK;
+		case SDL_SCANCODE_KP_DIVIDE:
+			return KEY_KPADSLASH;
+		case SDL_SCANCODE_KP_MULTIPLY:
+			return '*'; // undefined?
+		case SDL_SCANCODE_KP_MINUS:
+			return KEY_MINUSPAD;
+		case SDL_SCANCODE_KP_PLUS:
+			return KEY_PLUSPAD;
+		case SDL_SCANCODE_KP_ENTER:
+			return KEY_ENTER;
+		case SDL_SCANCODE_KP_PERIOD:
+			return KEY_KPADDEL;
+		case SDL_SCANCODE_NONUSBACKSLASH:
+			return '\\';
+
+		case SDL_SCANCODE_LSHIFT:
+			return KEY_LSHIFT;
+		case SDL_SCANCODE_RSHIFT:
+			return KEY_RSHIFT;
+		case SDL_SCANCODE_LCTRL:
+			return KEY_LCTRL;
+		case SDL_SCANCODE_RCTRL:
+			return KEY_RCTRL;
+		case SDL_SCANCODE_LALT:
+			return KEY_LALT;
+		case SDL_SCANCODE_RALT:
+			return KEY_RALT;
+		case SDL_SCANCODE_LGUI:
+			return KEY_LEFTWIN;
+		case SDL_SCANCODE_RGUI:
+			return KEY_RIGHTWIN;
 		default:
-			if (sym >= SDLK_SPACE && sym <= SDLK_DELETE)
-				rc = sym - SDLK_SPACE + ' ';
-			else if (sym >= 'A' && sym <= 'Z')
-				rc = sym - 'A' + 'a';
-			else if (sym)
-			{
-				I_OutputMsg("Unknown Keycode %i, Name: %s\n",sym, SDL_GetKeyName( sym ));
-			}
-			else if (!sym) rc = 0;
 			break;
 	}
-
-	return rc;
+	DBG_Printf("Unknown incoming scancode: %d, represented %c\n",
+				code,
+				SDL_GetKeyName(SDL_GetKeyFromScancode(code)));
+	return 0;
 }
 
 static void SDLdoUngrabMouse(void)
@@ -809,7 +716,7 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type)
 	{
 		return;
 	}
-	event.data1 = SDLatekey(evt.keysym.sym);
+	event.data1 = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode);
 	if (event.data1) D_PostEvent(&event);
 }
 
@@ -818,30 +725,34 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt)
 	event_t event;
 	int wwidth, wheight;
 
-	SDL_GetWindowSize(window, &wwidth, &wheight);
-
-	if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window))
+	if (USE_MOUSEINPUT)
 	{
-		SDLdoUngrabMouse();
-		return;
-	}
+		SDL_GetWindowSize(window, &wwidth, &wheight);
 
-	if ((evt.x == realwidth/2) && (evt.y == realheight/2))
-	{
-		return;
-	}
-	else
-	{
-		event.data2 = (evt.xrel) * (wwidth / realwidth);
-		event.data3 = -evt.yrel * (wheight / realheight);
-	}
+		if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window))
+		{
+			SDLdoUngrabMouse();
+			return;
+		}
+
+		if ((evt.x == realwidth/2) && (evt.y == realheight/2))
+		{
+			return;
+		}
+		else
+		{
+			event.data2 = (INT32)lround((evt.xrel) * ((float)wwidth / (float)realwidth));
+			event.data3 = (INT32)lround(-evt.yrel * ((float)wheight / (float)realheight));
+		}
 
-	event.type = ev_mouse;
+		event.type = ev_mouse;
 
-	if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window)
-	{
-		D_PostEvent(&event);
-		HalfWarpMouse(wwidth, wheight);
+		if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window)
+		{
+			D_PostEvent(&event);
+			SDL_SetWindowGrab(window, SDL_TRUE);
+			HalfWarpMouse(wwidth, wheight);
+		}
 	}
 }
 
@@ -868,9 +779,11 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
 		else if (evt.button == SDL_BUTTON_RIGHT)
 			event.data1 = KEY_MOUSE1+1;
 		else if (evt.button == SDL_BUTTON_LEFT)
-			event.data1= KEY_MOUSE1;
-		else if (evt.button <= MOUSEBUTTONS)
-			event.data1 = KEY_MOUSE1 + evt.which - SDL_BUTTON_LEFT;
+			event.data1 = KEY_MOUSE1;
+		else if (evt.button == SDL_BUTTON_X1)
+			event.data1 = KEY_MOUSE1+3;
+		else if (evt.button == SDL_BUTTON_X2)
+			event.data1 = KEY_MOUSE1+4;
 		if (event.type == ev_keyup || event.type == ev_keydown)
 		{
 			D_PostEvent(&event);
@@ -912,7 +825,7 @@ static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt)
 
 	// Determine the Joystick IDs for each current open joystick
 	joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev);
-	joyid[1] = SDL_JoystickInstanceID(JoyInfo.dev);
+	joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
 
 	evt.axis++;
 	event.data1 = event.data2 = event.data3 = INT32_MAX;
@@ -951,7 +864,7 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
 
 	// Determine the Joystick IDs for each current open joystick
 	joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev);
-	joyid[1] = SDL_JoystickInstanceID(JoyInfo.dev);
+	joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
 
 	if (evt.which == joyid[0])
 	{
@@ -984,6 +897,9 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
 void I_GetEvent(void)
 {
 	SDL_Event evt;
+	// We only want the first motion event,
+	// otherwise we'll end up catching the warp back to center.
+	int mouseMotionOnce = 0;
 
 	if (!graphics_started)
 	{
@@ -1002,7 +918,8 @@ void I_GetEvent(void)
 				Impl_HandleKeyboardEvent(evt.key, evt.type);
 				break;
 			case SDL_MOUSEMOTION:
-				Impl_HandleMouseMotionEvent(evt.motion);
+				if (!mouseMotionOnce) Impl_HandleMouseMotionEvent(evt.motion);
+				mouseMotionOnce = 1;
 				break;
 			case SDL_MOUSEBUTTONUP:
 			case SDL_MOUSEBUTTONDOWN:
@@ -1841,6 +1758,8 @@ void I_StartupGraphics(void)
 		HWD.pfnDoScreenWipe     = hwSym("DoScreenWipe",NULL);
 		HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL);
 		HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL);
+		HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL);
+		HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL);
 		// check gl renderer lib
 		if (HWD.pfnGetRenderVersion() != VERSION)
 			I_Error("%s", M_GetText("The version of the renderer doesn't match the version of the executable\nBe sure you have installed SRB2 properly.\n"));
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index 6cbecaf3c87937b9b3911ba6759f8fc2a4f7d5a0..ba7e6517652b1d766c51a27c3136b570f16aef2d 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -201,13 +201,22 @@ boolean OglSdlSurface(INT32 w, INT32 h)
 void OglSdlFinishUpdate(boolean waitvbl)
 {
 	static boolean oldwaitvbl = false;
+	int sdlw, sdlh;
 	if (oldwaitvbl != waitvbl)
 	{
 		SDL_GL_SetSwapInterval(waitvbl ? 1 : 0);
 	}
+
 	oldwaitvbl = waitvbl;
 
+	SDL_GetWindowSize(window, &sdlw, &sdlh);
+
+	HWR_MakeScreenFinalTexture();
+	HWR_DrawScreenFinalTexture(sdlw, sdlh);
 	SDL_GL_SwapWindow(window);
+
+	SetModelView(realwidth, realheight);
+	SetStates();
 }
 
 EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette, RGBA_t *pgamma)
diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h
index 72f130a52ef0c0f3bfe39b9eb5271404941529b3..7e144644ce325d7c18b1d0916ad3fdae3f384421 100644
--- a/src/sdl/ogl_sdl.h
+++ b/src/sdl/ogl_sdl.h
@@ -27,6 +27,8 @@ void OglSdlFinishUpdate(boolean vidwait);
 extern SDL_Window *window;
 extern SDL_Renderer *renderer;
 extern SDL_GLContext sdlglcontext;
+extern Uint16      realwidth;
+extern Uint16      realheight;
 
 #ifdef _CREATE_DLL_
 EXPORT void HWRAPI( OglSdlSetPalette ) (RGBA_t *palette, RGBA_t *pgamma);
diff --git a/src/sdl12/hwsym_sdl.c b/src/sdl12/hwsym_sdl.c
index 44ddf830ca43f4eafc8049c31089b7ecb2a6d1cd..54f5da3a083da6d9b3b9159b059389cbc7bc8271 100644
--- a/src/sdl12/hwsym_sdl.c
+++ b/src/sdl12/hwsym_sdl.c
@@ -105,6 +105,8 @@ void *hwSym(const char *funcName,void *handle)
 	GETFUNC(DoScreenWipe);
 	GETFUNC(DrawIntermissionBG);
 	GETFUNC(MakeScreenTexture);
+	GETFUNC(MakeScreenFinalTexture);
+	GETFUNC(DrawScreenFinalTexture);
 #else //HWRENDER
 	if (0 == strcmp("FinishUpdate", funcName))
 		return funcPointer; //&FinishUpdate;
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index c6ea016f2a84ea6a20a7ea57b284c85aab7dfb58..8fa4d17f73c8857f49b4a3ab0ca9a8ae69ea9381 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -122,6 +122,8 @@ static loadfunc_t hwdFuncTable[] = {
 	{"DoScreenWipe@4",      &hwdriver.pfnDoScreenWipe},
 	{"DrawIntermissionBG@0",&hwdriver.pfnDrawIntermissionBG},
 	{"MakeScreenTexture@0", &hwdriver.pfnMakeScreenTexture},
+	{"MakeScreenFinalTexture@0", &hwdriver.pfnMakeScreenFinalTexture},
+	{"DrawScreenFinalTexture@8", &hwdriver.pfnDrawScreenFinalTexture},
 #else
 	{"Init",                &hwdriver.pfnInit},
 	{"Shutdown",            &hwdriver.pfnShutdown},
@@ -150,6 +152,8 @@ static loadfunc_t hwdFuncTable[] = {
 	{"DoScreenWipe",        &hwdriver.pfnDoScreenWipe},
 	{"DrawIntermissionBG",  &hwdriver.pfnDrawIntermissionBG},
 	{"MakeScreenTexture",   &hwdriver.pfnMakeScreenTexture},
+	{"MakeScreenFinalTexture", &hwdriver.pfnMakeScreenFinalTexture},
+	{"DrawScreenFinalTexture", &hwdriver.pfnDrawScreenFinalTexture},
 #endif
 	{NULL,NULL}
 };