diff --git a/src/android/i_video.c b/src/android/i_video.c
index bf0decb74118385ff2b776d8d470e5ea3a03a2ba..c29193e599a0846f10c39aa80c29571296c1b104 100644
--- a/src/android/i_video.c
+++ b/src/android/i_video.c
@@ -63,6 +63,13 @@ void VID_CheckGLLoaded(rendermode_t oldrender)
 	(void)oldrender;
 }
 
+INT32 VID_SetResolution(INT32 width, INT32 height)
+{
+  (void)width;
+  (void)height;
+  return 0;
+}
+
 const char *VID_GetModeName(INT32 modenum)
 {
   return "A320x240";
diff --git a/src/d_main.c b/src/d_main.c
index 24c70843a3bd03d383651d7423914a7fd4d3f0e5..29ad735cc06798ac365481b9fcd7f18dbff3c3ee 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -326,9 +326,16 @@ static void D_Display(void)
 	//    modes (resolution) are called.
 	// 4. The frame is ready to be drawn!
 
-	// Check for change of renderer or screen size (video mode)
-	if ((setrenderneeded || setmodeneeded) && !wipe)
-		SCR_SetMode(); // change video mode
+	// check for change of screen size
+	if (!wipe)
+	{
+		if (setresneeded[2])
+			SCR_SetResolution();
+		else if (setrenderneeded || setmodeneeded)
+		{
+			SCR_SetMode();
+		}
+	}
 
 	// Recalc the screen
 	if (vid.recalc)
@@ -731,7 +738,7 @@ void D_SRB2Loop(void)
 	con_startup = false;
 
 	// make sure to do a d_display to init mode _before_ load a level
-	SCR_SetMode(); // change video mode
+	SCR_SetResolution(); // change video resolution
 	SCR_Recalc();
 
 	chosenrendermode = render_none;
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 71cb5ca70375629ee06c7943e0c5be881555a0c1..a935a37703f4958207069cb0801ddb2c46f89657 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -3064,7 +3064,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
 	INT32 x, y;
 	float float_x, float_y, float_nextx, float_nexty;
 	float xfix, yfix;
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 
 	const float blackBack[16] =
 	{
@@ -3074,11 +3074,9 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
 		16.0f, -16.0f, 6.0f
 	};
 
-	// Use a power of two texture, dammit
-	if(screen_width <= 1024)
-		texsize = 1024;
-	if(screen_width <= 512)
-		texsize = 512;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	// X/Y stretch fix for all resolutions(!)
 	xfix = (float)(texsize)/((float)((screen_width)/(float)(SCREENVERTS-1)));
@@ -3165,14 +3163,12 @@ EXPORT void HWRAPI(FlushScreenTextures) (void)
 // Create Screen to fade from
 EXPORT void HWRAPI(StartScreenWipe) (void)
 {
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 	boolean firstTime = (startScreenWipe == 0);
 
-	// Use a power of two texture, dammit
-	if(screen_width <= 512)
-		texsize = 512;
-	else if(screen_width <= 1024)
-		texsize = 1024;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	// Create screen texture
 	if (firstTime)
@@ -3196,14 +3192,12 @@ EXPORT void HWRAPI(StartScreenWipe) (void)
 // Create Screen to fade to
 EXPORT void HWRAPI(EndScreenWipe)(void)
 {
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 	boolean firstTime = (endScreenWipe == 0);
 
-	// Use a power of two texture, dammit
-	if(screen_width <= 512)
-		texsize = 512;
-	else if(screen_width <= 1024)
-		texsize = 1024;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	// Create screen texture
 	if (firstTime)
@@ -3229,7 +3223,7 @@ EXPORT void HWRAPI(EndScreenWipe)(void)
 EXPORT void HWRAPI(DrawIntermissionBG)(void)
 {
 	float xfix, yfix;
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 
 	const float screenVerts[12] =
 	{
@@ -3241,10 +3235,9 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void)
 
 	float fix[8];
 
-	if(screen_width <= 1024)
-		texsize = 1024;
-	if(screen_width <= 512)
-		texsize = 512;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	xfix = 1/((float)(texsize)/((float)((screen_width))));
 	yfix = 1/((float)(texsize)/((float)((screen_height))));
@@ -3276,7 +3269,7 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void)
 // Do screen fades!
 EXPORT void HWRAPI(DoScreenWipe)(void)
 {
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 	float xfix, yfix;
 
 	INT32 fademaskdownloaded = tex_downloaded; // the fade mask that has been set
@@ -3299,11 +3292,9 @@ EXPORT void HWRAPI(DoScreenWipe)(void)
 		1.0f, 1.0f
 	};
 
-	// Use a power of two texture, dammit
-	if(screen_width <= 1024)
-		texsize = 1024;
-	if(screen_width <= 512)
-		texsize = 512;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	xfix = 1/((float)(texsize)/((float)((screen_width))));
 	yfix = 1/((float)(texsize)/((float)((screen_height))));
@@ -3367,14 +3358,12 @@ EXPORT void HWRAPI(DoScreenWipe)(void)
 // Create a texture from the screen.
 EXPORT void HWRAPI(MakeScreenTexture) (void)
 {
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 	boolean firstTime = (screentexture == 0);
 
-	// Use a power of two texture, dammit
-	if(screen_width <= 512)
-		texsize = 512;
-	else if(screen_width <= 1024)
-		texsize = 1024;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	// Create screen texture
 	if (firstTime)
@@ -3397,14 +3386,12 @@ EXPORT void HWRAPI(MakeScreenTexture) (void)
 
 EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
 {
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 	boolean firstTime = (finalScreenTexture == 0);
 
-	// Use a power of two texture, dammit
-	if(screen_width <= 512)
-		texsize = 512;
-	else if(screen_width <= 1024)
-		texsize = 1024;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	// Create screen texture
 	if (firstTime)
@@ -3431,15 +3418,14 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
 	float origaspect, newaspect;
 	float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen
 	FRGBAFloat clearColour;
-	INT32 texsize = 2048;
+	INT32 texsize = 512;
 
 	float off[12];
 	float fix[8];
 
-	if(screen_width <= 1024)
-		texsize = 1024;
-	if(screen_width <= 512)
-		texsize = 512;
+	// look for power of two that is large enough for the screen
+	while (texsize < screen_width || texsize < screen_height)
+		texsize <<= 1;
 
 	xfix = 1/((float)(texsize)/((float)((screen_width))));
 	yfix = 1/((float)(texsize)/((float)((screen_height))));
diff --git a/src/i_video.h b/src/i_video.h
index 8efca5f9ab28da6312755d9e11a6c8791149f26b..63aca9950748e8ae43697697635cbb3251630ceb 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -101,6 +101,18 @@ void VID_StartupOpenGL(void);
 */
 void VID_CheckGLLoaded(rendermode_t oldrender);
 
+/**	\brief	The VID_SetResolution function
+
+	The same as VID_SetMode, but allows
+	any arbitrary resolution.
+
+	\param	width width
+	\param	height height
+
+	\return	???
+*/
+INT32 VID_SetResolution(INT32 width, INT32 height);
+
 /**	\brief	The VID_GetModeName function
 
 	\param	modenum	video mode number
diff --git a/src/m_menu.c b/src/m_menu.c
index 3946803b290e0240cac36accd363113256580933..8f0cc015bada6c6a7c7e04dd69c4ff148dd4a534 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -168,10 +168,14 @@ static  INT32   (*setupcontrols)[2];  // pointer to the gamecontrols of the play
 // shhh... what am I doing... nooooo!
 static INT32 vidm_testingmode = 0;
 static INT32 vidm_previousmode;
+static INT32 vidm_previousres[3];
 static INT32 vidm_selected = 0;
 static INT32 vidm_nummodes;
 static INT32 vidm_column_size;
 
+#define vidm_customreslength 12 // (XXXXXxYYYYY) - 11 plus the zero terminator
+static char vidm_customres[vidm_customreslength];
+
 // new menus
 static fixed_t recatkdrawtimer = 0;
 static fixed_t ntsatkdrawtimer = 0;
@@ -3872,7 +3876,16 @@ void M_Ticker(void)
 	{
 		// restore the previous video mode
 		if (--vidm_testingmode == 0)
-			setmodeneeded = vidm_previousmode + 1;
+		{
+			if (vidm_previousres[2])
+			{
+				setresneeded[0] = vidm_previousres[0];
+				setresneeded[1] = vidm_previousres[1];
+				setresneeded[2] = 2;
+			}
+			else
+				setmodeneeded = vidm_previousmode + 1;
+		}
 	}
 
 	if (currentMenu == &OP_ScreenshotOptionsDef)
@@ -5834,7 +5847,7 @@ static void M_DrawNightsAttackMountains(void)
 
 	if (vid.height != BASEVIDHEIGHT * dupz)
 		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158);
-	V_DrawFill(0, y+50, vid.width, BASEVIDHEIGHT, V_SNAPTOLEFT|31);
+	V_DrawFill(0, y+50, vid.width, vid.height, V_SNAPTOLEFT|31);
 
 	V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background);
 	x += w;
@@ -9437,11 +9450,20 @@ static void M_DrawSetupChoosePlayerMenu(void)
 	}
 
 	y = (charseltimer / FRACUNIT) % 32;
+
+	V_DrawMappedPatch(0, y-(bgheight*3), V_SNAPTOTOP, charbg, colormap);
+	V_DrawMappedPatch(0, y-(bgheight*2), V_SNAPTOTOP, charbg, colormap);
 	V_DrawMappedPatch(0, y-bgheight, V_SNAPTOTOP, charbg, colormap);
 	V_DrawMappedPatch(0, y, V_SNAPTOTOP, charbg, colormap);
 	V_DrawMappedPatch(0, y+bgheight, V_SNAPTOTOP, charbg, colormap);
+	V_DrawMappedPatch(0, y+(bgheight*2), V_SNAPTOTOP, charbg, colormap);
+	V_DrawMappedPatch(0, y+(bgheight*3), V_SNAPTOTOP, charbg, colormap);
+
 	V_DrawMappedPatch(0, -y, V_SNAPTOTOP, charfg, colormap);
 	V_DrawMappedPatch(0, -y+fgheight, V_SNAPTOTOP, charfg, colormap);
+	V_DrawMappedPatch(0, -y+(fgheight*2), V_SNAPTOTOP, charfg, colormap);
+	V_DrawMappedPatch(0, -y+(fgheight*3), V_SNAPTOTOP, charfg, colormap);
+
 	V_DrawFill(fgwidth, 0, vid.width, vid.height, V_SNAPTOTOP|colormap[106]);
 
 	// Character pictures
@@ -13609,11 +13631,12 @@ static void M_DrawCameraOptionsMenu(void)
 #define MAXCOLUMNMODES   12     //max modes displayed in one column
 #define MAXMODEDESCS     (MAXCOLUMNMODES*3)
 
-static modedesc_t modedescs[MAXMODEDESCS];
+static modedesc_t modedescs[MAXMODEDESCS+1];
 
 static void M_VideoModeMenu(INT32 choice)
 {
 	INT32 i, j, vdup, nummodes, width, height;
+	boolean modefound = false;
 	const char *desc;
 
 	(void)choice;
@@ -13657,7 +13680,10 @@ static void M_VideoModeMenu(INT32 choice)
 						vdup = 1;
 
 						if (i == vid.modenum)
+						{
 							vidm_selected = j;
+							modefound = true;
+						}
 					}
 					else
 						vdup = 1;
@@ -13672,7 +13698,10 @@ static void M_VideoModeMenu(INT32 choice)
 				modedescs[vidm_nummodes].desc = desc;
 
 				if (i == vid.modenum)
+				{
 					vidm_selected = vidm_nummodes;
+					modefound = true;
+				}
 
 				// Pull out the width and height
 				sscanf(desc, "%u%*c%u", &width, &height);
@@ -13688,6 +13717,16 @@ static void M_VideoModeMenu(INT32 choice)
 
 	vidm_column_size = (vidm_nummodes+2) / 3;
 
+	// add the custom video mode entry
+	modedescs[vidm_nummodes].modenum = -1;
+	vidm_nummodes++;
+
+	if (!modefound)
+		vidm_selected = vidm_nummodes-1;
+
+	if (strlen(vidm_customres) == 0)
+		strncpy(vidm_customres, va("%dx%d", vid.width, vid.height), vidm_customreslength);
+
 	M_SetupNextMenu(&OP_VideoModeDef);
 }
 
@@ -13700,7 +13739,7 @@ static void M_DrawMainVideoMenu(void)
 		if (itemOn == 7)
 			y -= 10;
 		V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y,
-		(SCR_IsAspectCorrect(vid.width, vid.height) ? V_GREENMAP : V_YELLOWMAP),
+		(SCR_IsAspectCorrect(vid.width, vid.height) ? V_GREENMAP : V_YELLOWMAP)|V_ALLOWLOWERCASE,
 			va("%dx%d", vid.width, vid.height));
 	}
 }
@@ -13720,11 +13759,19 @@ static void M_DrawVideoMode(void)
 	col = OP_VideoModeDef.y + 24;
 	for (i = 0; i < vidm_nummodes; i++)
 	{
+		// custom video mode
+		if (modedescs[i].modenum == -1)
+		{
+			M_DrawLevelPlatterHeader(OP_VideoModeDef.y + 76, "Custom resolution", true, false);
+			V_DrawFill(19, OP_VideoModeDef.y + 92, (vidm_customreslength*8)+4, 8+6, 159);
+			V_DrawString(22, OP_VideoModeDef.y + 95, V_ALLOWLOWERCASE|V_MONOSPACE, vidm_customres);
+			continue;
+		}
 		if (i == vidm_selected)
-			V_DrawString(row, col, V_YELLOWMAP, modedescs[i].desc);
+			V_DrawString(row, col, V_YELLOWMAP|V_ALLOWLOWERCASE, modedescs[i].desc);
 		// Show multiples of 320x200 as green.
 		else
-			V_DrawString(row, col, (modedescs[i].goodratio) ? V_GREENMAP : 0, modedescs[i].desc);
+			V_DrawString(row, col, ((modedescs[i].goodratio) ? V_GREENMAP : 0)|V_ALLOWLOWERCASE, modedescs[i].desc);
 
 		col += 8;
 		if ((i % vidm_column_size) == (vidm_column_size-1))
@@ -13775,6 +13822,14 @@ static void M_DrawVideoMode(void)
 			V_YELLOWMAP, "Larger modes may have performance issues.");
 	}
 
+	if (modedescs[vidm_selected].modenum == -1)
+	{
+		if (skullAnimCounter < 4 && !vidm_testingmode)
+			V_DrawCharacter(22 + V_StringWidth(vidm_customres, V_ALLOWLOWERCASE|V_MONOSPACE), OP_VideoModeDef.y + 95,
+				'_' | 0x80, false);
+		return;
+	}
+
 	// Draw the cursor for the VidMode menu
 	i = 41 - 10 + ((vidm_selected / vidm_column_size)*7*13);
 	j = OP_VideoModeDef.y + 24 + ((vidm_selected % vidm_column_size)*8);
@@ -13914,11 +13969,19 @@ static void M_DrawColorMenu(void)
 // special menuitem key handler for video mode list
 static void M_HandleVideoMode(INT32 ch)
 {
+	size_t l;
 	if (vidm_testingmode > 0) switch (ch)
 	{
 		// change back to the previous mode quickly
 		case KEY_ESCAPE:
-			setmodeneeded = vidm_previousmode + 1;
+			if (vidm_previousres[2])
+			{
+				setresneeded[0] = vidm_previousres[0];
+				setresneeded[1] = vidm_previousres[1];
+				setresneeded[2] = 2;
+			}
+			else
+				setmodeneeded = vidm_previousmode + 1;
 			vidm_testingmode = 0;
 			break;
 
@@ -13960,7 +14023,30 @@ static void M_HandleVideoMode(INT32 ch)
 			break;
 
 		case KEY_ENTER:
-			if (vid.modenum == modedescs[vidm_selected].modenum)
+			// custom res
+			if (modedescs[vidm_selected].modenum == -1)
+			{
+				S_StartSound(NULL, sfx_menu1);
+				// Pull out the width and height
+				INT32 width = vid.width, height = vid.height;
+				if (strlen(vidm_customres) < 1)
+					break;
+				sscanf(vidm_customres, "%u%*c%u", &width, &height);
+
+				vidm_previousres[0] = vid.width;
+				vidm_previousres[1] = vid.height;
+				vidm_previousres[2] = 1;
+				vidm_testingmode = 15*TICRATE;
+
+				// in case the previous setmode was not finished
+				if (!setresneeded[2])
+				{
+					setresneeded[0] = width;
+					setresneeded[1] = height;
+					setresneeded[2] = 2;
+				}
+			}
+			else if (vid.modenum == modedescs[vidm_selected].modenum)
 			{
 				S_StartSound(NULL, sfx_strpst);
 				SCR_SetDefaultMode();
@@ -13970,6 +14056,7 @@ static void M_HandleVideoMode(INT32 ch)
 				S_StartSound(NULL, sfx_menu1);
 				vidm_testingmode = 15*TICRATE;
 				vidm_previousmode = vid.modenum;
+				vidm_previousres[2] = 0;
 				if (!setmodeneeded) // in case the previous setmode was not finished
 					setmodeneeded = modedescs[vidm_selected].modenum + 1;
 			}
@@ -13982,18 +14069,6 @@ static void M_HandleVideoMode(INT32 ch)
 				M_ClearMenus(true);
 			break;
 
-		case KEY_BACKSPACE:
-			S_StartSound(NULL, sfx_menu1);
-			CV_Set(&cv_scr_width, cv_scr_width.defaultvalue);
-			CV_Set(&cv_scr_height, cv_scr_height.defaultvalue);
-			CV_Set(&cv_scr_width_w, cv_scr_width_w.defaultvalue);
-			CV_Set(&cv_scr_height_w, cv_scr_height_w.defaultvalue);
-			if (cv_fullscreen.value)
-				setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value)+1;
-			else
-				setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value)+1;
-			break;
-
 		case KEY_F10: // Renderer toggle, also processed inside menus
 			CV_AddValue(&cv_renderer, 1);
 			break;
@@ -14003,7 +14078,72 @@ static void M_HandleVideoMode(INT32 ch)
 			CV_SetValue(&cv_fullscreen, !cv_fullscreen.value);
 			break;
 
+		// custom video mode
+		case KEY_BACKSPACE:
+			if (modedescs[vidm_selected].modenum != -1)
+			{
+				S_StartSound(NULL, sfx_menu1);
+				CV_Set(&cv_scr_width, cv_scr_width.defaultvalue);
+				CV_Set(&cv_scr_height, cv_scr_height.defaultvalue);
+				CV_Set(&cv_scr_width_w, cv_scr_width_w.defaultvalue);
+				CV_Set(&cv_scr_height_w, cv_scr_height_w.defaultvalue);
+				if (cv_fullscreen.value)
+				{
+					setresneeded[0] = cv_scr_width.value;
+					setresneeded[1] = cv_scr_height.value;
+					setresneeded[2] = 1;
+				}
+				else
+				{
+					setresneeded[0] = cv_scr_width_w.value;
+					setresneeded[1] = cv_scr_height_w.value;
+					setresneeded[2] = 2;
+				}
+
+				break;
+			}
+
+			if ((l = strlen(vidm_customres)) != 0)
+			{
+				S_StartSound(NULL,sfx_menu1); // Tails
+				vidm_customres[l-1] = 0;
+			}
+			break;
+
+		case KEY_DEL:
+			if (modedescs[vidm_selected].modenum != -1)
+				break;
+
+			if (vidm_customres[0])
+			{
+				S_StartSound(NULL,sfx_menu1); // Tails
+				vidm_customres[0] = 0;
+			}
+			break;
+
 		default:
+			if (modedescs[vidm_selected].modenum != -1)
+				break;
+
+			l = strlen(vidm_customres);
+			if (l >= vidm_customreslength-1)
+				break;
+
+			if ((ch == 'x' || ch == 'X') || (ch >= '0' && ch <= '9'))
+			{
+				S_StartSound(NULL,sfx_menu1); // Tails
+				vidm_customres[l] = (char)ch;
+				vidm_customres[l+1] = 0;
+			}
+			else if (ch >= 199 && ch <= 211 && ch != 202 && ch != 206) //numpad too!
+			{
+				char keypad_translation[] = {'7','8','9','-','4','5','6','+','1','2','3','0','.'};
+				ch = keypad_translation[ch - 199];
+				S_StartSound(NULL,sfx_menu1); // Tails
+				vidm_customres[l] = (char)ch;
+				vidm_customres[l+1] = 0;
+			}
+
 			break;
 	}
 }
diff --git a/src/screen.c b/src/screen.c
index 417e793bde540c62a9edf2b6a0b8073250ee7f73..098b1ec4b11084d4bc46f581c61ab21c3452120a 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -60,15 +60,20 @@ void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
 viddef_t vid;
 INT32 setmodeneeded; //video mode change needed if > 0 (the mode number to set + 1)
 UINT8 setrenderneeded = 0;
+INT32 setresneeded[3]; // if setresneeded[2] is > 0, set resolution
+
+static void SCR_ChangeFullscreen (void);
+static void SCR_ChangeWidthCVAR (void);
+static void SCR_ChangeHeightCVAR (void);
 
 static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}};
 
 //added : 03-02-98: default screen mode, as loaded/saved in config
-consvar_t cv_scr_width = CVAR_INIT ("scr_width", "1280", CV_SAVE, CV_Unsigned, NULL);
-consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, NULL);
+consvar_t cv_scr_width = CVAR_INIT ("scr_width", "1280", CV_SAVE, CV_Unsigned, SCR_ChangeWidthCVAR);
+consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, SCR_ChangeHeightCVAR);
+consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL);
 consvar_t cv_scr_width_w = CVAR_INIT ("scr_width_w", "640", CV_SAVE, CV_Unsigned, NULL);
 consvar_t cv_scr_height_w = CVAR_INIT ("scr_height_w", "400", CV_SAVE, CV_Unsigned, NULL);
-consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL);
 
 consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL);
 
@@ -82,8 +87,6 @@ CV_PossibleValue_t cv_renderer_t[] = {
 
 consvar_t cv_renderer = CVAR_INIT ("renderer", "Software", CV_SAVE|CV_CALL, cv_renderer_t, SCR_ChangeRenderer);
 
-static void SCR_ChangeFullscreen(void);
-
 consvar_t cv_fullscreen = CVAR_INIT ("fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen);
 
 // =========================================================================
@@ -106,83 +109,61 @@ boolean R_3DNow = false;
 boolean R_MMXExt = false;
 boolean R_SSE2 = false;
 
+//
+// setup the right draw routines for 8bpp
+//
 void SCR_SetDrawFuncs(void)
 {
-	//
-	//  setup the right draw routines for either 8bpp or 16bpp
-	//
-	if (true)//vid.bpp == 1) //Always run in 8bpp. todo: remove all 16bpp code?
-	{
-		colfuncs[BASEDRAWFUNC] = R_DrawColumn_8;
-		spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8;
-
-		colfunc = colfuncs[BASEDRAWFUNC];
-		spanfunc = spanfuncs[BASEDRAWFUNC];
-
-		colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8;
-		colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn_8;
-		colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8;
-		colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed_8;
-		colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn_8;
-		colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8;
-		colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn_8;
-		colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn_8;
-
-		spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8;
-		spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat_8;
-		spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8;
-		spanfuncs[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_8;
-		spanfuncs[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_8;
-		spanfuncs[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_8;
-		spanfuncs[SPANDRAWFUNC_SOLID] = R_DrawSolidColorSpan_8;
-		spanfuncs[SPANDRAWFUNC_TRANSSOLID] = R_DrawTransSolidColorSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDSOLID] = R_DrawTiltedSolidColorSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDTRANSSOLID] = R_DrawTiltedTransSolidColorSpan_8;
-		spanfuncs[SPANDRAWFUNC_WATERSOLID] = R_DrawWaterSolidColorSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDWATERSOLID] = R_DrawTiltedWaterSolidColorSpan_8;
-		spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
-		spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8;
-
-		// Lactozilla: Non-powers-of-two
-		spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_SPLAT] = R_DrawSplat_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_NPO2_8;
-
-	}
-/*	else if (vid.bpp > 1)
-	{
-		I_OutputMsg("using highcolor mode\n");
-		spanfunc = basespanfunc = R_DrawSpan_16;
-		transcolfunc = R_DrawTranslatedColumn_16;
-		transtransfunc = R_DrawTranslucentColumn_16; // No 16bit operation for this function
-
-		colfunc = basecolfunc = R_DrawColumn_16;
-		shadecolfunc = NULL; // detect error if used somewhere..
-		fuzzcolfunc = R_DrawTranslucentColumn_16;
-		walldrawerfunc = R_DrawWallColumn_16;
-	}*/
-	else
-		I_Error("unknown bytes per pixel mode %d\n", vid.bpp);
-/*
-	if (SCR_IsAspectCorrect(vid.width, vid.height))
-		CONS_Alert(CONS_WARNING, M_GetText("Resolution is not aspect-correct!\nUse a multiple of %dx%d\n"), BASEVIDWIDTH, BASEVIDHEIGHT);
-*/
+	colfuncs[BASEDRAWFUNC] = R_DrawColumn_8;
+	spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8;
+
+	colfunc = colfuncs[BASEDRAWFUNC];
+	spanfunc = spanfuncs[BASEDRAWFUNC];
+
+	colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8;
+	colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn_8;
+	colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8;
+	colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed_8;
+	colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn_8;
+	colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8;
+	colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn_8;
+	colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn_8;
+
+	spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8;
+	spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat_8;
+	spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8;
+	spanfuncs[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_8;
+	spanfuncs[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_8;
+	spanfuncs[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_8;
+	spanfuncs[SPANDRAWFUNC_SOLID] = R_DrawSolidColorSpan_8;
+	spanfuncs[SPANDRAWFUNC_TRANSSOLID] = R_DrawTransSolidColorSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDSOLID] = R_DrawTiltedSolidColorSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDTRANSSOLID] = R_DrawTiltedTransSolidColorSpan_8;
+	spanfuncs[SPANDRAWFUNC_WATERSOLID] = R_DrawWaterSolidColorSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDWATERSOLID] = R_DrawTiltedWaterSolidColorSpan_8;
+	spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
+	spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8;
+
+	// Lactozilla: Non-powers-of-two
+	spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_SPLAT] = R_DrawSplat_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_NPO2_8;
+	spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_NPO2_8;
 }
 
 void SCR_SetMode(void)
@@ -214,11 +195,27 @@ void SCR_SetMode(void)
 
 	V_SetPalette(0);
 
+	// set the apprpriate drawers
 	SCR_SetDrawFuncs();
 
-	// set the apprpriate drawer for the sky (tall or INT16)
 	setmodeneeded = 0;
-	setrenderneeded = 0;
+}
+
+void SCR_SetResolution(void)
+{
+	if (dedicated)
+		return;
+
+	if (!setresneeded[2] || WipeInAction)
+		return; // should never happen and don't change it during a wipe, BAD!
+
+	VID_SetResolution(setresneeded[0], setresneeded[1]);
+
+	V_SetPalette(0);
+
+	// set the apprpriate drawers
+	SCR_SetDrawFuncs();
+	setresneeded[2] = 0;
 }
 
 // do some initial settings for the game loading screen
@@ -347,8 +344,9 @@ void SCR_CheckDefaultMode(void)
 	if (scr_forcex && scr_forcey)
 	{
 		CONS_Printf(M_GetText("Using resolution: %d x %d\n"), scr_forcex, scr_forcey);
-		// returns -1 if not found, thus will be 0 (no mode change) if not found
-		setmodeneeded = VID_GetModeForSize(scr_forcex, scr_forcey) + 1;
+		setresneeded[0] = scr_forcex;
+		setresneeded[1] = scr_forcey;
+		setresneeded[2] = 2;
 	}
 	else
 	{
@@ -356,12 +354,16 @@ void SCR_CheckDefaultMode(void)
 		CONS_Printf(M_GetText("Windowed resolution: %d x %d\n"), cv_scr_width_w.value, cv_scr_height_w.value);
 		CONS_Printf(M_GetText("Default bit depth: %d bits\n"), cv_scr_depth.value);
 		if (cv_fullscreen.value)
-			setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; // see note above
+		{
+			setresneeded[0] = cv_scr_width.value;
+			setresneeded[1] = cv_scr_height.value;
+		}
 		else
-			setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value) + 1; // see note above
-
-		if (setmodeneeded <= 0)
-			CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution\n");
+		{
+			setresneeded[0] = cv_scr_width_w.value;
+			setresneeded[1] = cv_scr_height_w.value;
+		}
+		setresneeded[2] = 2;
 	}
 
 	if (cv_renderer.value != (signed)rendermode)
@@ -396,15 +398,16 @@ void SCR_ChangeFullscreen(void)
 	{
 		VID_PrepareModeList();
 		if (cv_fullscreen.value)
-			setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1;
+		{
+			setresneeded[0] = cv_scr_width.value;
+			setresneeded[1] = cv_scr_height.value;
+		}
 		else
-			setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value) + 1;
-
-		if (setmodeneeded <= 0) // hacky safeguard
 		{
-			CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution.\n");
-			setmodeneeded = VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT) + 1;
+			setresneeded[0] = cv_scr_width_w.value;
+			setresneeded[1] = cv_scr_height_w.value;
 		}
+		setresneeded[2] = 1;
 	}
 	return;
 #endif
@@ -437,6 +440,24 @@ void SCR_ChangeRenderer(void)
 	setrenderneeded = cv_renderer.value;
 }
 
+// Called after changing the value of scr_width
+// Keeps the height the same
+void SCR_ChangeWidthCVAR(void)
+{
+	setresneeded[0] = cv_scr_width.value;
+	setresneeded[1] = vid.height;
+	setresneeded[2] = 1;
+}
+
+// Called after changing the value of scr_height
+// Keeps the width the same
+void SCR_ChangeHeightCVAR(void)
+{
+	setresneeded[0] = vid.width;
+	setresneeded[1] = cv_scr_height.value;
+	setresneeded[2] = 1;
+}
+
 boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
 {
 	return
diff --git a/src/screen.h b/src/screen.h
index 65e82ff4df2bff3701a0f57d4667ee32a34784f5..e6ca1aee47721c7e376ceb0fc34134d41bb6dff7 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -39,8 +39,8 @@
 // we try to re-allocate a minimum of buffers for stability of the memory,
 // so all the small-enough tables based on screen size, are allocated once
 // and for all at the maximum size.
-#define MAXVIDWIDTH 1920 // don't set this too high because actually
-#define MAXVIDHEIGHT 1200 // lots of tables are allocated with the MAX size.
+#define MAXVIDWIDTH 3840 // don't set this too high because actually
+#define MAXVIDHEIGHT 2560 // lots of tables are allocated with the MAX size.
 #define BASEVIDWIDTH 320 // NEVER CHANGE THIS! This is the original
 #define BASEVIDHEIGHT 200 // resolution of the graphics.
 
@@ -189,6 +189,7 @@ extern boolean R_SSE2;
 extern viddef_t vid;
 extern INT32 setmodeneeded; // mode number to set if needed, or 0
 extern UINT8 setrenderneeded;
+extern INT32 setresneeded[3]; // if setresneeded[2] is > 0, set resolution
 
 extern double averageFPS;
 
@@ -215,6 +216,9 @@ void SCR_SetMode(void);
 // Set drawer functions for Software
 void SCR_SetDrawFuncs(void);
 
+// Change resolution
+void SCR_SetResolution(void);
+
 // Recalc screen size dependent stuff
 void SCR_Recalc(void);
 
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 590d7d142a7a536678bfb96d3891c78264a19fba..136340ddfaf862de73ff31bd8897ffd3103438b2 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -623,6 +623,11 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
 			kbfocus = SDL_FALSE;
 			mousefocus = SDL_FALSE;
 			break;
+		case SDL_WINDOWEVENT_RESIZED:
+			setresneeded[0] = evt.data1;
+			setresneeded[1] = evt.data2;
+			setresneeded[2] = 1;
+			break;
 		case SDL_WINDOWEVENT_MAXIMIZED:
 			break;
 	}
@@ -912,6 +917,7 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
 void I_GetEvent(void)
 {
 	SDL_Event evt;
+	char* dropped_filedir;
 	// We only want the first motion event,
 	// otherwise we'll end up catching the warp back to center.
 	//int mouseMotionOnce = 0;
@@ -1088,6 +1094,11 @@ void I_GetEvent(void)
 				if (currentMenu == &OP_JoystickSetDef)
 					M_SetupJoystickMenu(0);
 				break;
+			case SDL_DROPFILE:
+				dropped_filedir = evt.drop.file;
+				COM_BufInsertText(va("addfile \"%s\"", dropped_filedir));
+				SDL_free(dropped_filedir);    // Free dropped_filedir memory
+				break;
 			case SDL_QUIT:
 				LUA_HookBool(true, HOOK(GameQuit));
 				I_Quit();
@@ -1672,6 +1683,34 @@ INT32 VID_SetMode(INT32 modeNum)
 	return SDL_TRUE;
 }
 
+// VID_SetMode but no video modes
+INT32 VID_SetResolution(INT32 width, INT32 height)
+{
+	SDLdoUngrabMouse();
+
+	vid.recalc = 1;
+	vid.bpp = 1;
+
+	vid.width = (width < BASEVIDWIDTH) ? BASEVIDWIDTH : ((width > MAXVIDWIDTH) ? MAXVIDWIDTH : width);
+	vid.height = (height < BASEVIDHEIGHT) ? BASEVIDHEIGHT : ((height > MAXVIDHEIGHT) ? MAXVIDHEIGHT : height);
+	vid.modenum = VID_GetModeForSize(width, height);
+
+	SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, (setresneeded[2] == 2));
+
+	if (rendermode == render_soft)
+	{
+		if (bufSurface)
+		{
+			SDL_FreeSurface(bufSurface);
+			bufSurface = NULL;
+		}
+
+		Impl_VideoSetupBuffer();
+	}
+
+	return SDL_TRUE;
+}
+
 static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 {
 	int flags = 0;
@@ -1698,6 +1737,8 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
 #endif
 
+	flags |= SDL_WINDOW_RESIZABLE;
+
 	// Create a window
 	window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 			realwidth, realheight, flags);
diff --git a/src/st_stuff.c b/src/st_stuff.c
index b9f0c6bb93e1ab4d1b9e35a958670571883086e4..12f5c27bc1be98060c73a7176ba276c4e6c8e4ce 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1420,11 +1420,17 @@ void ST_drawTitleCard(void)
 
 	if (!splitscreen || (splitscreen && stplyr == &players[displayplayer]))
 	{
+		INT16 zzheight = SHORT(zigzag->height);
+		INT16 ztheight = SHORT(zztext->height);
 		zzticker = lt_ticker;
-		V_DrawMappedPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap);
-		V_DrawMappedPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap);
-		V_DrawMappedPatch(FixedInt(lt_zigzag), (-zztext->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap);
-		V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), (zzheight-zzticker) % zzheight, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), (-zzticker) % zzheight, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), ((-zzticker) % zzheight) + zzheight, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), ((-zzticker) % zzheight) + zzheight*2, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), (-ztheight+zzticker) % ztheight, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker % ztheight), V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker % ztheight) + ztheight, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap);
+		V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker % ztheight) + (ztheight*2), V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap);
 	}
 
 	if (actnum)