diff --git a/.travis.yml b/.travis.yml
index 4648ae567fe77f0522e7d52c2c7d924b92ea61e4..a9f4ddfb441e17f282d9d488239cb5d3fdd5578f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -57,49 +57,6 @@ matrix:
               - gcc-4.8
           compiler: gcc-4.8
           #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
-        - os: linux
-          addons:
-            apt:
-              sources:
-              - ubuntu-toolchain-r-test
-              packages:
-              - libsdl2-mixer-dev
-              - libpng-dev
-              - libgl1-mesa-dev
-              - libgme-dev
-              - p7zip-full
-              - gcc-4.9
-          compiler: gcc-4.9
-          #gcc-4.9 (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3
-        - os: linux
-          addons:
-            apt:
-              sources:
-              - ubuntu-toolchain-r-test
-              packages:
-              - libsdl2-mixer-dev
-              - libpng-dev
-              - libgl1-mesa-dev
-              - libgme-dev
-              - p7zip-full
-              - gcc-5
-          compiler: gcc-5
-          #gcc-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204
-        - os: linux
-          addons:
-            apt:
-              sources:
-              - ubuntu-toolchain-r-test
-              packages:
-              - libsdl2-mixer-dev
-              - libpng-dev
-              - libgl1-mesa-dev
-              - libgme-dev
-              - p7zip-full
-              - gcc-6
-          compiler: gcc-6
-          env: WFLAGS="-Wno-tautological-compare"
-          #gcc-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511
         - os: linux
           addons:
             apt:
diff --git a/src/Makefile b/src/Makefile
index 57bd0644ef9852622a3e6ed7b3634c09a999901a..7a67c3f02de037dea8cbc56bb5d328589d0a0c5b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,3 +1,4 @@
+
 #     GNU Make makefile for SRB2
 #############################################################################
 # Copyright (C) 1998-2000 by DooM Legacy Team.
@@ -65,6 +66,7 @@
 #     Compile without 3D sound support, add 'NOHS=1'
 #     Compile with GDBstubs, add 'RDB=1'
 #     Compile without PNG, add 'NOPNG=1'
+#     Compile without zlib, add 'NOZLIB=1'
 #
 # Addon for SDL:
 #     To Cross-Compile, add 'SDL_CONFIG=/usr/*/bin/sdl-config'
@@ -118,6 +120,7 @@ include Makefile.cfg
 
 ifdef DUMMY
 NOPNG=1
+NOZLIB=1
 NONET=1
 NOHW=1
 NOHS=1
@@ -198,6 +201,7 @@ endif
 
 ifdef NDS
 NOPNG=1
+NOZLIB=1
 NONET=1
 #NOHW=1
 NOHS=1
@@ -324,13 +328,6 @@ LIBS+=$(PNG_LDFLAGS)
 CFLAGS+=$(PNG_CFLAGS)
 endif
 
-ZLIB_PKGCONFIG?=zlib
-ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
-ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
-
-LIBS+=$(ZLIB_LDFLAGS)
-CFLAGS+=$(ZLIB_CFLAGS)
-
 ifdef HAVE_LIBGME
 OPTS+=-DHAVE_LIBGME
 
@@ -342,6 +339,18 @@ LIBS+=$(LIBGME_LDFLAGS)
 CFLAGS+=$(LIBGME_CFLAGS)
 endif
 
+ifndef NOZLIB
+OPTS+=-DHAVE_ZLIB
+ZLIB_PKGCONFIG?=zlib
+ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
+ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
+
+LIBS+=$(ZLIB_LDFLAGS)
+CFLAGS+=$(ZLIB_CFLAGS)
+else
+NOPNG=1
+endif
+
 ifdef STATIC
 LIBS:=-static $(LIBS)
 endif
@@ -421,7 +430,8 @@ endif
 
 ifdef PROFILEMODE
 	# build with profiling information
-	CFLAGS:=-pg $(CFLAGS)
+	CFLAGS+=-pg
+	LDFLAGS+=-pg
 endif
 
 ifdef ZDEBUG
diff --git a/src/android/i_cdmus.c b/src/android/i_cdmus.c
index c5aac8f18a30143eca66f48be31de81ab1fb80e6..426bc5dc9ebdbf130614725e96fadbba42f6dd2c 100644
--- a/src/android/i_cdmus.c
+++ b/src/android/i_cdmus.c
@@ -8,7 +8,7 @@
 
 UINT8 cdaudio_started = 0;
 
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 
diff --git a/src/android/i_sound.c b/src/android/i_sound.c
index ecf96f2f053cf2ca8e3cb135b34cfc7e2dccd0c0..2bb304424af8b8dafe3dfc9df46eef877ef4cc89 100644
--- a/src/android/i_sound.c
+++ b/src/android/i_sound.c
@@ -21,13 +21,14 @@ void I_ShutdownSound(void){}
 //  SFX I/O
 //
 
-INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority)
+INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority, INT32 channel)
 {
         (void)id;
         (void)vol;
         (void)sep;
         (void)pitch;
         (void)priority;
+        (void)channel;
         return -1;
 }
 
@@ -55,90 +56,87 @@ void I_SetSfxVolume(INT32 volume)
         (void)volume;
 }
 
-//
-//  MUSIC I/O
-//
+/// ------------------------
+//  MUSIC SYSTEM
+/// ------------------------
+
 UINT8 music_started = 0;
+UINT8 digmusic_started = 0;
 
 void I_InitMusic(void){}
 
 void I_ShutdownMusic(void){}
 
-void I_PauseSong(INT32 handle)
+/// ------------------------
+//  MUSIC PROPERTIES
+/// ------------------------
+
+musictype_t I_SongType(void)
 {
-        (void)handle;
+	return MU_NONE;
 }
 
-void I_ResumeSong(INT32 handle)
+boolean I_SongPlaying(void)
 {
-        (void)handle;
+	return false;
 }
 
-//
-//  MIDI I/O
-//
-
-UINT8 midimusic_started = 0;
-
-void I_InitMIDIMusic(void){}
+boolean I_SongPaused(void)
+{
+	return false;
+}
 
-void I_ShutdownMIDIMusic(void){}
+/// ------------------------
+//  MUSIC EFFECTS
+/// ------------------------
 
-void I_SetMIDIMusicVolume(INT32 volume)
+boolean I_SetSongSpeed(float speed)
 {
-        (void)volume;
+        (void)speed;
+        return false;
 }
 
-INT32 I_RegisterSong(void *data, size_t len)
+/// ------------------------
+//  MUSIC PLAYBACK
+/// ------------------------
+
+UINT8 midimusic_started = 0;
+
+boolean I_LoadSong(char *data, size_t len)
 {
         (void)data;
         (void)len;
         return -1;
 }
 
-boolean I_PlaySong(INT32 handle, INT32 looping)
+void I_UnloadSong()
+{
+
+}
+
+boolean I_PlaySong(boolean looping)
 {
         (void)handle;
         (void)looping;
         return false;
 }
 
-void I_StopSong(INT32 handle)
+void I_StopSong(void)
 {
         (void)handle;
 }
 
-void I_UnRegisterSong(INT32 handle)
+void I_PauseSong(void)
 {
         (void)handle;
 }
 
-//
-//  DIGMUSIC I/O
-//
-
-UINT8 digmusic_started = 0;
-
-void I_InitDigMusic(void){}
-
-void I_ShutdownDigMusic(void){}
-
-boolean I_StartDigSong(const char *musicname, INT32 looping)
+void I_ResumeSong(void)
 {
-        (void)musicname;
-        (void)looping;
-        return false;
+        (void)handle;
 }
 
-void I_StopDigSong(void){}
-
-void I_SetDigMusicVolume(INT32 volume)
+void I_SetMusicVolume(INT32 volume)
 {
         (void)volume;
 }
-
-boolean I_SetSongSpeed(float speed)
-{
-        (void)speed;
-        return false;
-}
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index fc80e56b423dbd073d6b8774a81ff4f95c070aa9..1007d0858808d830e8b1333aed2b78748db229a8 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -401,8 +401,7 @@ static void ExtraDataTicker(void)
 							DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic));
 						}
 						CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]);
-						D_FreeTextcmd(gametic);
-						return;
+						break;
 					}
 				}
 			}
@@ -1569,8 +1568,6 @@ static void CL_LoadReceivedSavegame(void)
 	automapactive = false;
 
 	// load a base level
-	playerdeadview = false;
-
 	if (P_LoadNetGame())
 	{
 		const INT32 actnum = mapheaderinfo[gamemap-1]->actnum;
@@ -2244,7 +2241,7 @@ static void Command_connect(void)
 	// Assume we connect directly.
 	boolean viams = false;
 
-	if (COM_Argc() < 2)
+	if (COM_Argc() < 2 || *COM_Argv(1) == 0)
 	{
 		CONS_Printf(M_GetText(
 			"Connect <serveraddress> (port): connect to a server\n"
@@ -3296,7 +3293,7 @@ void SV_StopServer(void)
 	localtextcmd[0] = 0;
 	localtextcmd2[0] = 0;
 
-	for (i = 0; i < BACKUPTICS; i++)
+	for (i = firstticstosend; i < firstticstosend + BACKUPTICS; i++)
 		D_Clearticcmd(i);
 
 	consoleplayer = 0;
diff --git a/src/d_main.c b/src/d_main.c
index 063d284539e9b535ce263633920e477dece2a161..1705326751e2bc65b270b8a8b0f153c535d15775 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -121,20 +121,17 @@ INT32 postimgparam;
 postimg_t postimgtype2 = postimg_none;
 INT32 postimgparam2;
 
+// These variables are only true if
+// whether the respective sound system is disabled
+// or they're init'ed, but the player just toggled them
 #ifdef _XBOX
-boolean nomidimusic = true, nosound = true;
-boolean nodigimusic = true;
+boolean midi_disabled = true, sound_disabled = true;
+boolean digital_disabled = true;
 #else
-boolean nomidimusic = false, nosound = false;
-boolean nodigimusic = false; // No fmod-based music
-#endif
-
-// These variables are only true if
-// the respective sound system is initialized
-// and active, but no sounds/music should play.
-boolean music_disabled = false;
+boolean midi_disabled = false;
 boolean sound_disabled = false;
 boolean digital_disabled = false;
+#endif
 
 boolean advancedemo;
 #ifdef DEBUGFILE
@@ -720,7 +717,6 @@ void D_StartTitle(void)
 	maptol = 0;
 
 	gameaction = ga_nothing;
-	playerdeadview = false;
 	displayplayer = consoleplayer = 0;
 	//demosequence = -1;
 	gametype = GT_COOP;
@@ -730,11 +726,6 @@ void D_StartTitle(void)
 	CON_ToggleOff();
 
 	// Reset the palette
-#ifdef HWRENDER
-	if (rendermode == render_opengl)
-		HWR_SetPaletteColor(0);
-	else
-#endif
 	if (rendermode != render_none)
 		V_SetPaletteLump("PLAYPAL");
 }
@@ -1056,19 +1047,10 @@ void D_SRB2Main(void)
 
 	if (M_CheckParm("-password") && M_IsNextParm())
 		D_SetPassword(M_GetNextParm());
-	else
-	{
-		size_t z;
-		char junkpw[25];
-		for (z = 0; z < 24; z++)
-			junkpw[z] = (char)(rand() & 64)+32;
-		junkpw[24] = '\0';
-		D_SetPassword(junkpw);
-	}
 
 	// add any files specified on the command line with -file wadfile
 	// to the wad list
-	if (!(M_CheckParm("-connect")))
+	if (!(M_CheckParm("-connect") && !M_CheckParm("-server")))
 	{
 		if (M_CheckParm("-file"))
 		{
@@ -1224,21 +1206,29 @@ void D_SRB2Main(void)
 	R_Init();
 
 	// setting up sound
-	CONS_Printf("S_Init(): Setting up sound.\n");
+	if (dedicated)
+	{
+		sound_disabled = true;
+		midi_disabled = digital_disabled = true;
+	}
+	else
+	{
+		CONS_Printf("S_InitSfxChannels(): Setting up sound channels.\n");
+	}
 	if (M_CheckParm("-nosound"))
-		nosound = true;
+		sound_disabled = true;
 	if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic
-		nomidimusic = nodigimusic = true;
+		midi_disabled = digital_disabled = true;
 	else
 	{
 		if (M_CheckParm("-nomidimusic"))
-			nomidimusic = true; ; // WARNING: DOS version initmusic in I_StartupSound
+			midi_disabled = true; ; // WARNING: DOS version initmusic in I_StartupSound
 		if (M_CheckParm("-nodigmusic"))
-			nodigimusic = true; // WARNING: DOS version initmusic in I_StartupSound
+			digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound
 	}
 	I_StartupSound();
 	I_InitMusic();
-	S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value);
+	S_InitSfxChannels(cv_soundvolume.value);
 
 	CONS_Printf("ST_Init(): Init status bar.\n");
 	ST_Init();
@@ -1323,7 +1313,7 @@ void D_SRB2Main(void)
 		ultimatemode = true;
 	}
 
-	if (autostart || netgame || M_CheckParm("+connect") || M_CheckParm("-connect"))
+	if (autostart || netgame)
 	{
 		gameaction = ga_nothing;
 
@@ -1361,8 +1351,7 @@ void D_SRB2Main(void)
 			}
 		}
 
-		if (server && !M_CheckParm("+map") && !M_CheckParm("+connect")
-			&& !M_CheckParm("-connect"))
+		if (server && !M_CheckParm("+map"))
 		{
 			// Prevent warping to nonexistent levels
 			if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR)
diff --git a/src/d_main.h b/src/d_main.h
index 6dc273b1558d8ac6329a15100946dc889095eebf..d73b19d1f6e5fd34ab5fd0470a5c762379c6fd8b 100644
--- a/src/d_main.h
+++ b/src/d_main.h
@@ -34,7 +34,7 @@ void D_SRB2Loop(void) FUNCNORETURN;
 // D_SRB2Main()
 // Not a globally visible function, just included for source reference,
 // calls all startup code, parses command line options.
-// If not overrided by user input, calls N_AdvanceDemo.
+// If not overrided by user input, calls D_AdvanceDemo.
 //
 void D_SRB2Main(void);
 
@@ -51,9 +51,6 @@ const char *D_Home(void);
 //
 // BASE LEVEL
 //
-void D_PageTicker(void);
-// pagename is lumpname of a 320x200 patch to fill the screen
-void D_PageDrawer(const char *pagename);
 void D_AdvanceDemo(void);
 void D_StartTitle(void);
 
diff --git a/src/d_net.c b/src/d_net.c
index 643c41ac921507e6a76613348fa90d859a2e1daa..8de5cf088aaf6b2d6c17d5fc9d9f51ff5c5c0b69 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -49,7 +49,9 @@ doomcom_t *doomcom = NULL;
 /// \brief network packet data, points inside doomcom
 doomdata_t *netbuffer = NULL;
 
+#ifdef DEBUGFILE
 FILE *debugfile = NULL; // put some net info in a file during the game
+#endif
 
 #define MAXREBOUND 8
 static doomdata_t reboundstore[MAXREBOUND];
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index e4ac8d9b82a88ca49da5c48884c0d2d9904c426d..885c811d199224c3660a2890b71a5cc283c42a2e 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -2656,10 +2656,12 @@ static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt,
 
 #define BASESALT "basepasswordstorage"
 static UINT8 adminpassmd5[16];
+static boolean adminpasswordset = false;
 
 void D_SetPassword(const char *pw)
 {
 	D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5);
+	adminpasswordset = true;
 }
 
 // Remote Administration
@@ -2731,6 +2733,12 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
 	if (client)
 		return;
 
+	if (!adminpasswordset)
+	{
+		CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]);
+		return;
+	}
+
 	// Do the final pass to compare with the sent md5
 	D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", playernum), &finalmd5);
 
@@ -3947,19 +3955,18 @@ static void Command_RestartAudio_f(void)
 		return;
 
 	S_StopMusic();
+	S_StopSounds();
 	I_ShutdownMusic();
 	I_ShutdownSound();
 	I_StartupSound();
 	I_InitMusic();
-	
+
 // These must be called or no sound and music until manually set.
 
 	I_SetSfxVolume(cv_soundvolume.value);
-	I_SetDigMusicVolume(cv_digmusicvolume.value);
-	I_SetMIDIMusicVolume(cv_midimusicvolume.value);
+	S_SetMusicVolume(cv_digmusicvolume.value, cv_midimusicvolume.value);
 	if (Playing()) // Gotta make sure the player is in a level
 		P_RestoreMusic(&players[consoleplayer]);
-	
 }
 
 /** Quits a game and returns to the title screen.
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index d8fae72f798ff874e17d630628f3e269a37fe7a3..023bbd094d2daff0a23db6c80a2ad28e91c9eeec 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -212,7 +212,6 @@ void Command_ExitGame_f(void);
 void Command_Retry_f(void);
 void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
 void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
-void ObjectPlace_OnChange(void);
 void ItemFinder_OnChange(void);
 void D_SetPassword(const char *pw);
 
diff --git a/src/d_netfil.c b/src/d_netfil.c
index 172624ad297a753c43abf0e348c3a6df07d8c1f6..6742cfe284403fc70c1ccdeeadcb23bf890fa0ef 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -990,19 +990,41 @@ filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum)
 	return FS_FOUND; // will never happen, but makes the compiler shut up
 }
 
+// Rewritten by Monster Iestyn to be less stupid
+// Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned
+// (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore)
 filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath)
 {
-	filestatus_t homecheck = filesearch(filename, srb2home, wantedmd5sum, false, 10);
-	if (homecheck == FS_FOUND)
-		return filesearch(filename, srb2home, wantedmd5sum, completepath, 10);
+	filestatus_t homecheck; // store result of last file search
+	boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third)
 
-	homecheck = filesearch(filename, srb2path, wantedmd5sum, false, 10);
-	if (homecheck == FS_FOUND)
-		return filesearch(filename, srb2path, wantedmd5sum, completepath, 10);
+	// first, check SRB2's "home" directory
+	homecheck = filesearch(filename, srb2home, wantedmd5sum, completepath, 10);
 
+	if (homecheck == FS_FOUND) // we found the file, so return that we have :)
+		return FS_FOUND;
+	else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
+		badmd5 = true;
+	// if not found at all, just move on without doing anything
+
+	// next, check SRB2's "path" directory
+	homecheck = filesearch(filename, srb2path, wantedmd5sum, completepath, 10);
+
+	if (homecheck == FS_FOUND) // we found the file, so return that we have :)
+		return FS_FOUND;
+	else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
+		badmd5 = true;
+	// if not found at all, just move on without doing anything
+
+	// finally check "." directory
 #ifdef _arch_dreamcast
-	return filesearch(filename, "/cd", wantedmd5sum, completepath, 10);
+	homecheck = filesearch(filename, "/cd", wantedmd5sum, completepath, 10);
 #else
-	return filesearch(filename, ".", wantedmd5sum, completepath, 10);
+	homecheck = filesearch(filename, ".", wantedmd5sum, completepath, 10);
 #endif
+
+	if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement
+		return homecheck; // otherwise return the result we got
+
+	return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found
 }
diff --git a/src/djgppdos/i_cdmus.c b/src/djgppdos/i_cdmus.c
index f707add5ef097681f9d2e211b549f4588289501a..2a629ca1738a1ad7e5d36ae6c83a16fdcd2c22e8 100644
--- a/src/djgppdos/i_cdmus.c
+++ b/src/djgppdos/i_cdmus.c
@@ -50,7 +50,7 @@ static boolean wasPlaying;
 static int     cdVolume=0;          // current cd volume (0-31)
 
 // 0-31 like Music & Sfx, though CD hardware volume is 0-255.
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 // allow Update for next/loop track
 // some crap cd drivers take up to
diff --git a/src/djgppdos/i_sound.c b/src/djgppdos/i_sound.c
index 88fc807f408cb4f285086fdabd854658b83063ad..52c90aac2d2450ede35eb9773e8b9a222e661783 100644
--- a/src/djgppdos/i_sound.c
+++ b/src/djgppdos/i_sound.c
@@ -134,21 +134,12 @@ FUNCINLINE static ATTRINLINE int Volset(int vol)
 
 void I_SetSfxVolume(INT32 volume)
 {
-	if (nosound)
+	if (sound_disabled)
 		return;
 
 	set_volume (Volset(volume),-1);
 }
 
-void I_SetMIDIMusicVolume(INT32 volume)
-{
-	if (nomidimusic)
-		return;
-
-	// Now set volume on output device.
-	set_volume (-1, Volset(volume));
-}
-
 //
 // Starting a sound means adding it
 //  to the current list of active sounds
@@ -165,11 +156,13 @@ INT32 I_StartSound ( sfxenum_t     id,
                    INT32         vol,
                    INT32         sep,
                    INT32         pitch,
-                   INT32         priority )
+                   INT32         priority,
+				   INT32         channel)
 {
 	int voice;
+	(void)channel;
 
-	if (nosound)
+	if (sound_disabled)
 	return 0;
 
 	// UNUSED
@@ -190,7 +183,7 @@ void I_StopSound (INT32 handle)
 	//  an setting the channel to zero.
 	int voice=handle & (VIRTUAL_VOICES-1);
 
-	if (nosound)
+	if (sound_disabled)
 		return;
 
 	if (voice_check(voice)==S_sfx[handle>>VOICESSHIFT].data)
@@ -199,7 +192,7 @@ void I_StopSound (INT32 handle)
 
 INT32 I_SoundIsPlaying(INT32 handle)
 {
-	if (nosound)
+	if (sound_disabled)
 		return FALSE;
 
 	if (voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data)
@@ -229,7 +222,7 @@ void I_UpdateSoundParams( INT32 handle,
 	int voice=handle & (VIRTUAL_VOICES-1);
 	int numsfx=handle>>VOICESSHIFT;
 
-	if (nosound)
+	if (sound_disabled)
 		return;
 
 	if (voice_check(voice)==S_sfx[numsfx].data)
@@ -270,17 +263,17 @@ void I_StartupSound(void)
 	char   err[255];
 #endif
 
-	if (nosound)
+	if (sound_disabled)
 		sfxcard=DIGI_NONE;
 	else
 		sfxcard=DIGI_AUTODETECT;
 
-	if (nomidimusic)
+	if (midi_disabled)
 		midicard=MIDI_NONE;
 	else
 		midicard=MIDI_AUTODETECT; //DetectMusicCard();
 
-	nodigimusic=true; //Alam: No OGG/MP3/IT/MOD support
+	digital_disabled=true; //Alam: No OGG/MP3/IT/MOD support
 
 	// Secure and configure sound device first.
 	CONS_Printf("I_StartupSound: ");
@@ -293,8 +286,8 @@ void I_StartupSound(void)
 	{
 		sprintf (err,"Sound init error : %s\n",allegro_error);
 		CONS_Error (err);
-		nosound=true;
-		nomidimusic=true;
+		sound_disabled=true;
+		midi_disabled=true;
 	}
 	else
 	{
@@ -321,7 +314,11 @@ static MIDI* currsong;   //im assuming only 1 song will be played at once
 static int      islooping=0;
 static int      musicdies=-1;
 UINT8           music_started=0;
+boolean         songpaused=false;
 
+/// ------------------------
+//  MUSIC SYSTEM
+/// ------------------------
 
 /* load_midi_mem:
  *  Loads a standard MIDI file from memory, returning a pointer to
@@ -389,163 +386,162 @@ static MIDI *load_midi_mem(char *mempointer,int *e)
 	return midi;
 }
 
-void I_InitMIDIMusic(void)
+void I_InitMusic(void)
 {
-	if (nomidimusic)
+	if (midi_disabled)
 		return;
 
 	I_AddExitFunc(I_ShutdownMusic);
 	music_started = true;
+	songpaused = false;
 }
 
-void I_ShutdownMIDIMusic(void)
+void I_ShutdownMusic(void)
 {
 	if ( !music_started )
 		return;
 
-	I_StopSong(1);
+	I_StopSong();
 
 	music_started=false;
 }
 
-void I_InitDigMusic(void)
+/// ------------------------
+//  MUSIC PROPERTIES
+/// ------------------------
+
+musictype_t I_SongType(void)
 {
-//	CONS_Printf("Digital music not yet supported under DOS.\n");
+	if (currsong)
+		return MU_MID;
+	else
+		return MU_NONE;
 }
 
-void I_ShutdownDigMusic(void)
+boolean I_SongPlaying()
 {
-//	CONS_Printf("Digital music not yet supported under DOS.\n");
+	return (boolean)currsong;
 }
 
-void I_InitMusic(void)
+boolean I_SongPaused()
 {
-	if (!nodigimusic)
-		I_InitDigMusic();
-	if (!nomidimusic)
-		I_InitMIDIMusic();
+	return songpaused;
 }
 
-void I_ShutdownMusic(void)
+/// ------------------------
+//  MUSIC EFFECTS
+/// ------------------------
+
+boolean I_SetSongSpeed(float speed)
 {
-	I_ShutdownMIDIMusic();
-	I_ShutdownDigMusic();
+	(void)speed;
+	return false;
 }
 
-boolean I_PlaySong(INT32 handle, INT32 looping)
+/// ------------------------
+//  MUSIC PLAYBACK
+/// ------------------------
+
+boolean I_LoadSong(char *data, size_t len)
 {
-	handle = 0;
-	if (nomidimusic)
-		return false;
+	int e = len; //Alam: For error
+	if (midi_disabled)
+		return 0;
 
-	islooping = looping;
-	musicdies = gametic + NEWTICRATE*30;
-	if (play_midi(currsong,looping)==0)
-		return true;
-	return false;
+	if (memcmp(data,"MThd",4)==0) // support mid file in WAD !!!
+	{
+		currsong=load_midi_mem(data,&e);
+	}
+	else
+	{
+		CONS_Printf("Music Lump is not a MIDI lump\n");
+		return 0;
+	}
+
+	if (currsong==NULL)
+	{
+		CONS_Printf("Not a valid mid file : %d\n",e);
+		return 0;
+	}
+
+	return 1;
 }
 
-void I_PauseSong (INT32 handle)
+void I_UnloadSong(void)
 {
 	handle = 0;
-	if (nomidimusic)
+	if (midi_disabled)
 		return;
 
-	midi_pause();
+	//destroy_midi(currsong);
 }
 
-void I_ResumeSong (INT32 handle)
+boolean I_PlaySong(boolean looping)
 {
 	handle = 0;
-	if (nomidimusic)
-		return;
+	if (midi_disabled)
+		return false;
 
-	midi_resume();
+	islooping = looping;
+	musicdies = gametic + NEWTICRATE*30;
+	if (play_midi(currsong,looping)==0)
+		return true;
+	return false;
 }
 
-void I_StopSong(INT32 handle)
+void I_StopSong(void)
 {
 	handle = 0;
-	if (nomidimusic)
+	if (midi_disabled)
 		return;
 
 	islooping = 0;
 	musicdies = 0;
 	stop_midi();
+	songpaused = false;
 }
 
-// Is the song playing?
-#if 0
-int I_QrySongPlaying(int handle)
+void I_PauseSong (INT32 handle)
 {
-	if (nomidimusic)
-		return 0;
-
-	//return islooping || musicdies > gametic;
-	return (midi_pos==-1);
+	handle = 0;
+	if (midi_disabled)
+		return;
+	midi_pause();
+	songpaused = true;
 }
-#endif
 
-void I_UnRegisterSong(INT32 handle)
+void I_ResumeSong (INT32 handle)
 {
 	handle = 0;
-	if (nomidimusic)
+	if (midi_disabled)
 		return;
-
-	//destroy_midi(currsong);
+	midi_resume();
+	songpaused = false;
 }
 
-INT32 I_RegisterSong(void *data, size_t len)
+void I_SetMusicVolume(INT32 volume)
 {
-	int e = len; //Alam: For error
-	if (nomidimusic)
-		return 0;
-
-	if (memcmp(data,"MThd",4)==0) // support mid file in WAD !!!
-	{
-		currsong=load_midi_mem(data,&e);
-	}
-	else
-	{
-		CONS_Printf("Music Lump is not a MIDI lump\n");
-		return 0;
-	}
-
-	if (currsong==NULL)
-	{
-		CONS_Printf("Not a valid mid file : %d\n",e);
-		return 0;
-	}
+	if (midi_disabled)
+		return;
 
-	return 1;
+	// Now set volume on output device.
+	set_volume (-1, Volset(volume));
 }
 
-/// \todo Add OGG/MP3 support for dos
-boolean I_StartDigSong(const char *musicname, INT32 looping)
+boolean I_SetSongTrack(INT32 track)
 {
-	musicname = NULL;
-	looping = 0;
-	//CONS_Printf("I_StartDigSong: Not yet supported under DOS.\n");
+	(void)track;
 	return false;
 }
 
-void I_StopDigSong(void)
-{
-//	CONS_Printf("I_StopDigSong: Not yet supported under DOS.\n");
-}
-
-void I_SetDigMusicVolume(INT32 volume)
+// Is the song playing?
+#if 0
+int I_QrySongPlaying(int handle)
 {
-	volume = 0;
-	if (nodigimusic)
-		return;
-
-	// Now set volume on output device.
-//	CONS_Printf("Digital music not yet supported under DOS.\n");
-}
+	if (midi_disabled)
+		return 0;
 
-boolean I_SetSongSpeed(float speed)
-{
-	(void)speed;
-	return false;
+	//return islooping || musicdies > gametic;
+	return (midi_pos==-1);
 }
+#endif
diff --git a/src/doomstat.h b/src/doomstat.h
index 8072a15528f56a23727da9a6d7b32bcf86db4166..53db6eb252817182fc312717800a64f18b836907 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -85,10 +85,7 @@ extern boolean fromlevelselect;
 // Internal parameters for sound rendering.
 // ========================================
 
-extern boolean nomidimusic; // defined in d_main.c
-extern boolean nosound;
-extern boolean nodigimusic;
-extern boolean music_disabled;
+extern boolean midi_disabled;
 extern boolean sound_disabled;
 extern boolean digital_disabled;
 
@@ -445,19 +442,17 @@ extern mapthing_t *redctfstarts[MAXPLAYERS]; // CTF
 
 #if defined (macintosh)
 #define DEBFILE(msg) I_OutputMsg(msg)
-extern FILE *debugfile;
 #else
 #define DEBUGFILE
 #ifdef DEBUGFILE
 #define DEBFILE(msg) { if (debugfile) { fputs(msg, debugfile); fflush(debugfile); } }
-extern FILE *debugfile;
 #else
 #define DEBFILE(msg) {}
-extern FILE *debugfile;
 #endif
 #endif
 
 #ifdef DEBUGFILE
+extern FILE *debugfile;
 extern INT32 debugload;
 #endif
 
diff --git a/src/dummy/i_sound.c b/src/dummy/i_sound.c
index 51dbb610d13657ab567bfd8314ea53dc6ba40350..7275bb1ae5d9345e035aa775b602b5fb3bf4f8a1 100644
--- a/src/dummy/i_sound.c
+++ b/src/dummy/i_sound.c
@@ -23,13 +23,14 @@ void I_UpdateSound(void){};
 //  SFX I/O
 //
 
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
 {
 	(void)id;
 	(void)vol;
 	(void)sep;
 	(void)pitch;
 	(void)priority;
+	(void)channel;
 	return -1;
 }
 
@@ -57,91 +58,88 @@ void I_SetSfxVolume(UINT8 volume)
 	(void)volume;
 }
 
-//
-//  MUSIC I/O
-//
+/// ------------------------
+//  MUSIC SYSTEM
+/// ------------------------
 
 void I_InitMusic(void){}
 
 void I_ShutdownMusic(void){}
 
-void I_PauseSong(INT32 handle)
+/// ------------------------
+//  MUSIC PROPERTIES
+/// ------------------------
+
+musictype_t I_SongType(void)
 {
-	(void)handle;
+	return MU_NONE;
 }
 
-void I_ResumeSong(INT32 handle)
+boolean I_SongPlaying(void)
 {
-	(void)handle;
+	return false;
 }
 
-//
-//  MIDI I/O
-//
-
-void I_InitMIDIMusic(void){}
+boolean I_SongPaused(void)
+{
+	return false;
+}
 
-void I_ShutdownMIDIMusic(void){}
+/// ------------------------
+//  MUSIC EFFECTS
+/// ------------------------
 
-void I_SetMIDIMusicVolume(UINT8 volume)
+boolean I_SetSongSpeed(float speed)
 {
-	(void)volume;
+	(void)speed;
+	return false;
 }
 
-INT32 I_RegisterSong(void *data, size_t len)
+/// ------------------------
+//  MUSIC PLAYBACK
+/// ------------------------
+
+boolean I_LoadSong(char *data, size_t len)
 {
 	(void)data;
 	(void)len;
 	return -1;
 }
 
-boolean I_PlaySong(INT32 handle, boolean looping)
+void I_UnloadSong(void)
 {
 	(void)handle;
-	(void)looping;
-	return false;
 }
 
-void I_StopSong(INT32 handle)
+boolean I_PlaySong(boolean looping)
 {
 	(void)handle;
+	(void)looping;
+	return false;
 }
 
-void I_UnRegisterSong(INT32 handle)
+void I_StopSong(void)
 {
 	(void)handle;
 }
 
-//
-//  DIGMUSIC I/O
-//
-
-void I_InitDigMusic(void){}
-
-void I_ShutdownDigMusic(void){}
-
-boolean I_StartDigSong(const char *musicname, boolean looping)
+void I_PauseSong(void)
 {
-	(void)musicname;
-	(void)looping;
-	return false;
+	(void)handle;
 }
 
-void I_StopDigSong(void){}
-
-void I_SetDigMusicVolume(UINT8 volume)
+void I_ResumeSong(void)
 {
-	(void)volume;
+	(void)handle;
 }
 
-boolean I_SetSongSpeed(float speed)
+void I_SetMusicVolume(UINT8 volume)
 {
-	(void)speed;
-	return false;
+	(void)volume;
 }
 
 boolean I_SetSongTrack(int track)
 {
 	(void)track;
 	return false;
-}
+}
\ No newline at end of file
diff --git a/src/f_finale.c b/src/f_finale.c
index 692abb35f4837a921a97ff0a8fefb13189e10a9c..fb1387c11e1a31b147ba93b7b9d3fdfefd126668 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -233,11 +233,19 @@ static void F_SkyScroll(INT32 scrollspeed)
 #ifdef HWRENDER
 	else if (rendermode != render_none)
 	{ // if only software rendering could be this simple and retarded
-		scrolled = animtimer;
-		if (scrolled > 0)
-			V_DrawScaledPatch(scrolled - SHORT(pat->width), 0, 0, pat);
-		for (x = 0; x < fakedwidth; x += SHORT(pat->width))
-			V_DrawScaledPatch(x + scrolled, 0, 0, pat);
+		INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
+		INT32 y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz;
+		scrolled = animtimer * dupz;
+		for (x = 0; x < vid.width; x += pw)
+		{
+			for (y = 0; y < vid.height; y += ph)
+			{
+				if (scrolled > 0)
+					V_DrawScaledPatch(scrolled - pw, y, V_NOSCALESTART, pat);
+
+				V_DrawScaledPatch(x + scrolled, y, V_NOSCALESTART, pat);
+			}
+		}
 	}
 #endif
 
@@ -434,7 +442,6 @@ void F_StartIntro(void)
 
 	G_SetGamestate(GS_INTRO);
 	gameaction = ga_nothing;
-	playerdeadview = false;
 	paused = false;
 	CON_ToggleOff();
 	CON_ClearHUD();
@@ -969,7 +976,6 @@ static const char *credits[] = {
 	"\1Programming",
 	"Alam \"GBC\" Arias",
 	"Logan \"GBA\" Arias",
-	"Tim \"RedEnchilada\" Bordelon",
 	"Callum Dickinson",
 	"Scott \"Graue\" Feeney",
 	"Nathan \"Jazz\" Giroux",
@@ -978,12 +984,12 @@ static const char *credits[] = {
 	"Ronald \"Furyhunter\" Kinard", // The SDL2 port
 	"John \"JTE\" Muniz",
 	"Ehab \"Wolfy\" Saeed",
+	"\"Kaito Sinclaire\"",
 	"\"SSNTails\"",
-	"Matthew \"Inuyasha\" Walsh",
 	"",
 	"\1Programming",
 	"\1Assistance",
-	"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
+	"\"chi.miru\"", // helped port slope drawing code from ZDoom
 	"Andrew \"orospakr\" Clunis",
 	"Gregor \"Oogaland\" Dick",
 	"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
@@ -999,7 +1005,7 @@ static const char *credits[] = {
 	"",
 	"\1Sprite Artists",
 	"Odi \"Iceman404\" Atunzu",
-	"Victor \"VAdaPEGA\" Ara\x1Fjo", // Ara�jo -- sorry for our limited font! D:
+	"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
 	"Jim \"MotorRoach\" DeMello",
 	"Desmond \"Blade\" DesJardins",
 	"Sherman \"CoatRack\" DesJardins",
@@ -1017,7 +1023,7 @@ static const char *credits[] = {
 	"\1Music and Sound",
 	"\1Production",
 	"Malcolm \"RedXVI\" Brown",
-	"David \"Bulmybag\" Bulmer",
+	"Dave \"DemonTomatoDave\" Bulmer",
 	"Paul \"Boinciel\" Clempson",
 	"Cyan Helkaraxe",
 	"Kepa \"Nev3r\" Iceta",
@@ -1041,13 +1047,13 @@ static const char *credits[] = {
 	"Kepa \"Nev3r\" Iceta",
 	"Thomas \"Shadow Hog\" Igoe",
 	"Erik \"Torgo\" Nielsen",
+	"\"Kaito Sinclaire\"",
 	"Wessel \"Spherallic\" Smit",
 	"\"Spazzo\"",
 	"\"SSNTails\"",
 	"Rob Tisdell",
 	"Jarrett \"JEV3\" Voight",
 	"Johnny \"Sonikku\" Wallbank",
-	"Matthew \"Inuyasha\" Walsh",
 	"Marco \"Digiku\" Zafra",
 	"",
 	"\1Boss Design",
@@ -1123,7 +1129,6 @@ void F_StartCredits(void)
 	}
 
 	gameaction = ga_nothing;
-	playerdeadview = false;
 	paused = false;
 	CON_ToggleOff();
 	CON_ClearHUD();
@@ -1270,7 +1275,6 @@ void F_StartGameEvaluation(void)
 		G_SaveGame((UINT32)cursaveslot);
 
 	gameaction = ga_nothing;
-	playerdeadview = false;
 	paused = false;
 	CON_ToggleOff();
 	CON_ClearHUD();
@@ -1381,7 +1385,6 @@ void F_StartGameEnd(void)
 	G_SetGamestate(GS_GAMEEND);
 
 	gameaction = ga_nothing;
-	playerdeadview = false;
 	paused = false;
 	CON_ToggleOff();
 	CON_ClearHUD();
@@ -1584,7 +1587,6 @@ void F_StartContinue(void)
 	gameaction = ga_nothing;
 
 	keypressed = false;
-	playerdeadview = false;
 	paused = false;
 	CON_ToggleOff();
 	CON_ClearHUD();
@@ -1753,7 +1755,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
 	G_SetGamestate(GS_CUTSCENE);
 
 	gameaction = ga_nothing;
-	playerdeadview = false;
 	paused = false;
 	CON_ToggleOff();
 
diff --git a/src/g_game.c b/src/g_game.c
index e2f35ad1342c6fecc05f595b74a0e97bfa8f7e38..d6ce01dca29c4849cb7f034709d54be7caf35c8a 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -3578,7 +3578,8 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
 		unlocktriggers = 0;
 
 		// clear itemfinder, just in case
-		CV_StealthSetValue(&cv_itemfinder, 0);
+		if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds
+			CV_StealthSetValue(&cv_itemfinder, 0);
 	}
 
 	// internal game map
@@ -3605,7 +3606,6 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
 	mapmusflags |= MUSIC_RELOADRESET;
 
 	ultimatemode = pultmode;
-	playerdeadview = false;
 	automapactive = false;
 	imcontinuing = false;
 
@@ -4351,6 +4351,7 @@ void G_GhostTicker(void)
 				p->next = g->next;
 			else
 				ghosts = g->next;
+			Z_Free(g);
 			continue;
 		}
 		p = g;
@@ -5303,29 +5304,28 @@ void G_AddGhost(char *defdemoname)
 	mthing = playerstarts[0];
 	I_Assert(mthing);
 	{ // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling.
-		fixed_t x,y,z;
-		sector_t *sector;
-		x = mthing->x << FRACBITS;
-		y = mthing->y << FRACBITS;
-		sector = R_PointInSubsector(x, y)->sector;
+		fixed_t z,f,c;
+		gh->mo = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST);
+		gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT);
+		f = gh->mo->floorz;
+		c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height;
 		if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP))
 		{
-			z = sector->ceilingheight - mobjinfo[MT_PLAYER].height;
+			z = c;
 			if (mthing->options >> ZSHIFT)
 				z -= ((mthing->options >> ZSHIFT) << FRACBITS);
-			if (z < sector->floorheight)
-				z = sector->floorheight;
+			if (z < f)
+				z = f;
 		}
 		else
 		{
-			z = sector->floorheight;
+			z = f;
 			if (mthing->options >> ZSHIFT)
 				z += ((mthing->options >> ZSHIFT) << FRACBITS);
-			if (z > sector->ceilingheight - mobjinfo[MT_PLAYER].height)
-				z = sector->ceilingheight - mobjinfo[MT_PLAYER].height;
+			if (z > c)
+				z = c;
 		}
-		gh->mo = P_SpawnMobj(x, y, z, MT_GHOST);
-		gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT);
+		gh->mo->z = z;
 	}
 	gh->mo->state = states+S_PLAY_STND;
 	gh->mo->sprite = gh->mo->state->sprite;
@@ -5523,8 +5523,14 @@ boolean G_CheckDemoStatus(void)
 {
 	boolean saved;
 
-	if(ghosts) // ... ... ...
-		ghosts = NULL; // :)
+	while (ghosts)
+	{
+		demoghost *next = ghosts->next;
+		Z_Free(ghosts);
+		ghosts = next;
+	}
+	ghosts = NULL;
+
 
 	// DO NOT end metal sonic demos here
 
diff --git a/src/hardware/hw3sound.c b/src/hardware/hw3sound.c
index c68430921fa4053b5e3fc96fe23f94804291a0ea..f7c6e1da025e1db33471bd8775bc6a8ff4c826a3 100644
--- a/src/hardware/hw3sound.c
+++ b/src/hardware/hw3sound.c
@@ -361,7 +361,7 @@ INT32 HW3S_I_StartSound(const void *origin_p, source3D_data_t *source_parm, chan
 
 	if (splitscreen) listenmobj2 = players[secondarydisplayplayer].mo;
 
-	if (nosound)
+	if (sound_disabled)
 		return -1;
 
 	sfx = &S_sfx[sfx_id];
diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c
index 17eb8761c9650eea7ca4b87d6dc157a3dd078979..a32609fc80ebb1e0316f1c1f6d2dd5897a00c707 100644
--- a/src/hardware/hw_bsp.c
+++ b/src/hardware/hw_bsp.c
@@ -564,8 +564,6 @@ static inline void HWR_SubsecPoly(INT32 num, poly_t *poly)
 	subsector_t *sub;
 	seg_t *lseg;
 
-	sscount++;
-
 	sub = &subsectors[num];
 	count = sub->numlines;
 	lseg = &segs[sub->firstline];
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 70d776d9e962c219d3449bdd3db262e6017962db..c05ff3e7927b0a0f9867ba63d71b0863b93a83b9 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -20,8 +20,8 @@
 #define _HWR_DEFS_
 #include "../doomtype.h"
 
-#define ZCLIP_PLANE 4.0f
-#define NZCLIP_PLANE 0.9f
+#define ZCLIP_PLANE 4.0f // Used for the actual game drawing
+#define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures
 
 // ==========================================================================
 //                                                               SIMPLE TYPES
@@ -133,12 +133,13 @@ enum EPolyFlags
 
 	PF_Masked           = 0x00000001,   // Poly is alpha scaled and 0 alpha pels are discarded (holes in texture)
 	PF_Translucent      = 0x00000002,   // Poly is transparent, alpha = level of transparency
-	PF_Additive         = 0x00000024,   // Poly is added to the frame buffer
+	PF_Additive         = 0x00000004,   // Poly is added to the frame buffer
 	PF_Environment      = 0x00000008,   // Poly should be drawn environment mapped.
 	                                    // Hurdler: used for text drawing
 	PF_Substractive     = 0x00000010,   // for splat
 	PF_NoAlphaTest      = 0x00000020,   // hiden param
-	PF_Blending         = (PF_Environment|PF_Additive|PF_Translucent|PF_Masked|PF_Substractive)&~PF_NoAlphaTest,
+	PF_Fog              = 0x00000040,   // Fog blocks
+	PF_Blending         = (PF_Environment|PF_Additive|PF_Translucent|PF_Masked|PF_Substractive|PF_Fog)&~PF_NoAlphaTest,
 
 		// other flag bits
 
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index f23753ee53ff4ef65833cd3c661b80391e45526a..84081dd25f6b906dfa8b56b7a6b914b9230fcdc5 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -147,10 +147,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 //  | /|
 //  |/ |
 //  0--1
-	float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
-	float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
-	float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale);
-	float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale);
+	float dupx, dupy, fscale, fwidth, fheight;
 
 	if (alphalevel >= 10 && alphalevel < 13)
 		return;
@@ -161,40 +158,108 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 	else
 		HWR_GetMappedPatch(gpatch, colormap);
 
+	dupx = (float)vid.dupx;
+	dupy = (float)vid.dupy;
+
 	switch (option & V_SCALEPATCHMASK)
 	{
 	case V_NOSCALEPATCH:
-		pdupx = pdupy = 2.0f;
+		dupx = dupy = 1.0f;
 		break;
 	case V_SMALLSCALEPATCH:
-		pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx);
-		pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy);
+		dupx = (float)vid.smalldupx;
+		dupy = (float)vid.smalldupy;
 		break;
 	case V_MEDSCALEPATCH:
-		pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx);
-		pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy);
+		dupx = (float)vid.meddupx;
+		dupy = (float)vid.meddupy;
 		break;
 	}
 
-	if (option & V_NOSCALESTART)
-		sdupx = sdupy = 2.0f;
+	dupx = dupy = (dupx < dupy ? dupx : dupy);
+	fscale = FIXED_TO_FLOAT(pscale);
+
+	if (option & V_OFFSET)
+	{
+		cx -= (float)gpatch->leftoffset * dupx * fscale;
+		cy -= (float)gpatch->topoffset * dupy * fscale;
+	}
+	else
+	{
+		cy -= (float)gpatch->topoffset * fscale;
+		if (option & V_FLIP)
+			cx -= ((float)gpatch->width - (float)gpatch->leftoffset) * fscale;
+		else
+			cx -= (float)gpatch->leftoffset * fscale;
+	}
 
 	if (option & V_SPLITSCREEN)
-		sdupy /= 2.0f;
+		cy /= 2;
+
+	if (!(option & V_NOSCALESTART))
+	{
+		cx = cx * dupx;
+		cy = cy * dupy;
+
+		if (!(option & V_SCALEPATCHMASK))
+		{
+			// if it's meant to cover the whole screen, black out the rest
+			// cx and cy are possibly *slightly* off from float maths
+			// This is done before here compared to software because we directly alter cx and cy to centre
+			if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
+			{
+				// Need to temporarily cache the real patch to get the colour of the top left pixel
+				patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
+				const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
+				const UINT8 *source = (const UINT8 *)(column) + 3;
+				HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
+				Z_Free(realpatch);
+			}
+			// centre screen
+			if (vid.width != BASEVIDWIDTH * vid.dupx)
+			{
+				if (option & V_SNAPTORIGHT)
+					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
+				else if (!(option & V_SNAPTOLEFT))
+					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
+			}
+			if (vid.height != BASEVIDHEIGHT * vid.dupy)
+			{
+				if ((option & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM))
+					cy += ((float)vid.height/2 - ((float)BASEVIDHEIGHT/2 * dupy));
+				else if (option & V_SNAPTOBOTTOM)
+					cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
+				else if (!(option & V_SNAPTOTOP))
+					cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2;
+			}
+		}
+	}
 
-	if (option & V_FLIP) // Need to flip both this and sow
+	if (pscale != FRACUNIT)
 	{
-		v[0].x = v[3].x = (cx*sdupx-(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1;
-		v[2].x = v[1].x = (cx*sdupx+gpatch->leftoffset*pdupx)/vid.width - 1;
+		fwidth = (float)gpatch->width * fscale * dupx;
+		fheight = (float)gpatch->height * fscale * dupy;
 	}
 	else
 	{
-		v[0].x = v[3].x = (cx*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1;
-		v[2].x = v[1].x = (cx*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1;
+		fwidth = (float)gpatch->width * dupx;
+		fheight = (float)gpatch->height * dupy;
 	}
 
-	v[0].y = v[1].y = 1-(cy*sdupy-gpatch->topoffset*pdupy)/vid.height;
-	v[2].y = v[3].y = 1-(cy*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height;
+	// positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
+	cx = -1 + (cx / (vid.width/2));
+	cy = 1 - (cy / (vid.height/2));
+
+	// fwidth and fheight are similar
+	fwidth /= vid.width / 2;
+	fheight /= vid.height / 2;
+
+	// set the polygon vertices to the right positions
+	v[0].x = v[3].x = cx;
+	v[2].x = v[1].x = cx + fwidth;
+
+	v[0].y = v[1].y = cy;
+	v[2].y = v[3].y = cy - fheight;
 
 	v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
 
@@ -247,10 +312,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
 //  | /|
 //  |/ |
 //  0--1
-	float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
-	float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
-	float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale);
-	float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale);
+	float dupx, dupy, fscale, fwidth, fheight;
 
 	if (alphalevel >= 10 && alphalevel < 13)
 		return;
@@ -258,28 +320,109 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
 	// make patch ready in hardware cache
 	HWR_GetPatch(gpatch);
 
+	dupx = (float)vid.dupx;
+	dupy = (float)vid.dupy;
+
 	switch (option & V_SCALEPATCHMASK)
 	{
 	case V_NOSCALEPATCH:
-		pdupx = pdupy = 2.0f;
+		dupx = dupy = 1.0f;
 		break;
 	case V_SMALLSCALEPATCH:
-		pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx);
-		pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy);
+		dupx = (float)vid.smalldupx;
+		dupy = (float)vid.smalldupy;
 		break;
 	case V_MEDSCALEPATCH:
-		pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx);
-		pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy);
+		dupx = (float)vid.meddupx;
+		dupy = (float)vid.meddupy;
 		break;
 	}
 
-	if (option & V_NOSCALESTART)
-		sdupx = sdupy = 2.0f;
+	dupx = dupy = (dupx < dupy ? dupx : dupy);
+	fscale = FIXED_TO_FLOAT(pscale);
+
+	cy -= (float)gpatch->topoffset * fscale;
+	cx -= (float)gpatch->leftoffset * fscale;
+
+	if (!(option & V_NOSCALESTART))
+	{
+		cx = cx * dupx;
+		cy = cy * dupy;
 
-	v[0].x = v[3].x =     (cx*sdupx -           gpatch->leftoffset  * pdupx) / vid.width - 1;
-	v[2].x = v[1].x =     (cx*sdupx + ((w-sx) - gpatch->leftoffset) * pdupx) / vid.width - 1;
-	v[0].y = v[1].y = 1 - (cy*sdupy -           gpatch->topoffset   * pdupy) / vid.height;
-	v[2].y = v[3].y = 1 - (cy*sdupy + ((h-sy) - gpatch->topoffset)  * pdupy) / vid.height;
+		if (!(option & V_SCALEPATCHMASK))
+		{
+			// if it's meant to cover the whole screen, black out the rest
+			// cx and cy are possibly *slightly* off from float maths
+			// This is done before here compared to software because we directly alter cx and cy to centre
+			if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
+			{
+				// Need to temporarily cache the real patch to get the colour of the top left pixel
+				patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
+				const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
+				const UINT8 *source = (const UINT8 *)(column) + 3;
+				HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
+				Z_Free(realpatch);
+			}
+			// centre screen
+			if (vid.width != BASEVIDWIDTH * vid.dupx)
+			{
+				if (option & V_SNAPTORIGHT)
+					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
+				else if (!(option & V_SNAPTOLEFT))
+					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
+			}
+			if (vid.height != BASEVIDHEIGHT * vid.dupy)
+			{
+				if ((option & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM))
+					cy += ((float)vid.height/2 - ((float)BASEVIDHEIGHT/2 * dupy));
+				else if (option & V_SNAPTOBOTTOM)
+					cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
+				else if (!(option & V_SNAPTOTOP))
+					cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2;
+			}
+		}
+	}
+
+	fwidth = w;
+	fheight = h;
+
+	if (fwidth > w - sx)
+		fwidth = w - sx;
+
+	if (fheight > h - sy)
+		fheight = h - sy;
+
+	if (fwidth > gpatch->width)
+		fwidth = gpatch->width;
+
+	if (fheight > gpatch->height)
+		fheight = gpatch->height;
+
+	if (pscale != FRACUNIT)
+	{
+		fwidth *=  fscale * dupx;
+		fheight *=  fscale * dupy;
+	}
+	else
+	{
+		fwidth *= dupx;
+		fheight *= dupy;
+	}
+
+	// positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
+	cx = -1 + (cx / (vid.width/2));
+	cy = 1 - (cy / (vid.height/2));
+
+	// fwidth and fheight are similar
+	fwidth /= vid.width / 2;
+	fheight /= vid.height / 2;
+
+	// set the polygon vertices to the right positions
+	v[0].x = v[3].x = cx;
+	v[2].x = v[1].x = cx + fwidth;
+
+	v[0].y = v[1].y = cy;
+	v[2].y = v[3].y = cy - fheight;
 
 	v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
 
@@ -656,7 +799,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 {
 	FOutVector v[4];
 	FSurfaceInfo Surf;
-	float sdupx, sdupy;
+	float fx, fy, fw, fh;
 
 	if (w < 0 || h < 0)
 		return; // consistency w/ software
@@ -665,16 +808,79 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 //  | /|
 //  |/ |
 //  0--1
-	sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
-	sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
 
-	if (color & V_NOSCALESTART)
-		sdupx = sdupy = 2.0f;
+	fx = (float)x;
+	fy = (float)y;
+	fw = (float)w;
+	fh = (float)h;
 
-	v[0].x = v[3].x = (x*sdupx)/vid.width - 1;
-	v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1;
-	v[0].y = v[1].y = 1-(y*sdupy)/vid.height;
-	v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height;
+	if (!(color & V_NOSCALESTART))
+	{
+		float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
+
+		if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
+		{
+			RGBA_t rgbaColour = V_GetColor(color);
+			FRGBAFloat clearColour;
+			clearColour.red = (float)rgbaColour.s.red / 255;
+			clearColour.green = (float)rgbaColour.s.green / 255;
+			clearColour.blue = (float)rgbaColour.s.blue / 255;
+			clearColour.alpha = 1;
+			HWD.pfnClearBuffer(true, false, &clearColour);
+			return;
+		}
+
+		fx *= dupx;
+		fy *= dupy;
+		fw *= dupx;
+		fh *= dupy;
+
+		if (vid.width != BASEVIDWIDTH * vid.dupx)
+		{
+			if (color & V_SNAPTORIGHT)
+				fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
+			else if (!(color & V_SNAPTOLEFT))
+				fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
+		}
+		if (vid.height != BASEVIDHEIGHT * dupy)
+		{
+			// same thing here
+			if (color & V_SNAPTOBOTTOM)
+				fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
+			else if (!(color & V_SNAPTOTOP))
+				fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
+		}
+	}
+
+	if (fx >= vid.width || fy >= vid.height)
+		return;
+	if (fx < 0)
+	{
+		fw += fx;
+		fx = 0;
+	}
+	if (fy < 0)
+	{
+		fh += fy;
+		fy = 0;
+	}
+
+	if (fw <= 0 || fh <= 0)
+		return;
+	if (fx + fw > vid.width)
+		fw = (float)vid.width - fx;
+	if (fy + fh > vid.height)
+		fh = (float)vid.height - fy;
+
+	fx = -1 + fx / (vid.width / 2);
+	fy = 1 - fy / (vid.height / 2);
+	fw = fw / (vid.width / 2);
+	fh = fh / (vid.height / 2);
+
+	v[0].x = v[3].x = fx;
+	v[2].x = v[1].x = fx + fw;
+	v[0].y = v[1].y = fy;
+	v[2].y = v[3].y = fy - fh;
 
 	//Hurdler: do we still use this argb color? if not, we should remove it
 	v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index 7672f47c26a71febd941e0ec2157dafd5446e24d..a5ac82001084f5bf755c6025b1bbcfdccb40432d 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -79,6 +79,7 @@ EXPORT char *HWRAPI(GetRenderer) (void);
 #define SCREENVERTS 10
 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]);
 #endif
+EXPORT void HWRAPI(FlushScreenTextures) (void);
 EXPORT void HWRAPI(StartScreenWipe) (void);
 EXPORT void HWRAPI(EndScreenWipe) (void);
 EXPORT void HWRAPI(DoScreenWipe) (float alpha);
@@ -124,6 +125,7 @@ struct hwdriver_s
 #ifdef SHUFFLE
 	PostImgRedraw       pfnPostImgRedraw;
 #endif
+	FlushScreenTextures pfnFlushScreenTextures;
 	StartScreenWipe     pfnStartScreenWipe;
 	EndScreenWipe       pfnEndScreenWipe;
 	DoScreenWipe        pfnDoScreenWipe;
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 94eef1d3e46e95f825f7ac89088cbb6674636225..fea06caffa4cb1b218e41b3d53694d5714dab7ec 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -68,6 +68,7 @@ typedef struct gr_vissprite_s
 	struct gr_vissprite_s *prev;
 	struct gr_vissprite_s *next;
 	float x1, x2;
+	float z1, z2;
 	float tz, ty;
 	lumpnum_t patchlumpnum;
 	boolean flip;
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 05391f4d051ed0fd8c2b4a63cefdcbd53e39ad1d..ecb70a0f9bea7099d6298ea19ac456589d63ce8c 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -117,7 +117,7 @@ consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_c
 consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
                              CV_anisotropic_ONChange, 0, NULL, NULL, 0, 0, NULL};
 //static consvar_t cv_grzbuffer = {"gr_zbuffer", "On", 0, CV_OnOff};
-consvar_t cv_grcorrecttricks = {"gr_correcttricks", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 static void CV_FogDensity_ONChange(void)
@@ -489,10 +489,10 @@ UINT32 HWR_Lighting(INT32 light, UINT32 color, UINT32 fadecolor, boolean fogbloc
 }
 
 
-static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // Let's see if this can work
+static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this can work
 {
-	RGBA_t realcolor, fogcolor, surfcolor;
-	INT32 alpha, fogalpha;
+	RGBA_t realcolor, surfcolor;
+	INT32 alpha;
 
 	// Don't go out of bounds
 	if (light < 0)
@@ -501,13 +501,11 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // L
 		light = 255;
 
 	realcolor.rgba = color;
-	fogcolor.rgba = fadecolor;
 
 	alpha = (realcolor.s.alpha*255)/25;
-	fogalpha = (fogcolor.s.alpha*255)/25;
 
-	// Fog blocks seem to get slightly more opaque with more opaque colourmap opacity, and much more opaque with darker brightness
-	surfcolor.s.alpha = (UINT8)(CALCLIGHT(light, ((0xFF-light)+alpha)/2)+CALCLIGHT(0xFF-light, ((light)+fogalpha)/2));
+	// at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255
+	surfcolor.s.alpha = (alpha*light)/(2*256)+255-light;
 
 	return surfcolor.s.alpha;
 }
@@ -773,10 +771,10 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, true);
 	}
 
-	if (PolyFlags & PF_Translucent)
+	if (PolyFlags & (PF_Translucent|PF_Fog))
 	{
 		Surf.FlatColor.s.alpha = (UINT8)alpha;
-		PolyFlags |= PF_Modulated|PF_Occlude|PF_Clip;
+		PolyFlags |= PF_Modulated|PF_Clip;
 	}
 	else
 		PolyFlags |= PF_Masked|PF_Modulated|PF_Clip;
@@ -1067,12 +1065,11 @@ static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
 //
 // HWR_SplitWall
 //
-static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, UINT32 cutflag)
+static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, UINT32 cutflag, ffloor_t *pfloor)
 {
 	/* SoM: split up and light walls according to the
 	 lightlist. This may also include leaving out parts
 	 of the wall that can't be seen */
-	GLTexture_t * glTex;
 
 	float realtop, realbot, top, bot;
 	float pegt, pegb, pegmul;
@@ -1095,8 +1092,8 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 	INT32   solid, i;
 	lightlist_t *  list = sector->lightlist;
 	const UINT8 alpha = Surf->FlatColor.s.alpha;
-	FUINT lightnum;
-	extracolormap_t *colormap;
+	FUINT lightnum = sector->lightlevel;
+	extracolormap_t *colormap = NULL;
 
 	realtop = top = wallVerts[3].y;
 	realbot = bot = wallVerts[0].y;
@@ -1112,7 +1109,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 	endpegmul = (endpegb - endpegt) / (endtop - endbot);
 #endif
 
-	for (i = 1; i < sector->numlights; i++)
+	for (i = 0; i < sector->numlights; i++)
 	{
 #ifdef ESLOPE
         if (endtop < endrealbot)
@@ -1120,35 +1117,38 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 		if (top < realbot)
 			return;
 
-	//Hurdler: fix a crashing bug, but is it correct?
-//		if (!list[i].caster)
-//			continue;
+	// There's a compiler warning here if this comment isn't here because of indentation
+		if (!(list[i].flags & FF_NOSHADE))
+		{
+			if (pfloor && (pfloor->flags & FF_FOG))
+			{
+				lightnum = pfloor->master->frontsector->lightlevel;
+				colormap = pfloor->master->frontsector->extra_colormap;
+			}
+			else
+			{
+				lightnum = *list[i].lightlevel;
+				colormap = list[i].extra_colormap;
+			}
+		}
 
 		solid = false;
 
-		if (list[i].caster)
+		if ((sector->lightlist[i].flags & FF_CUTSOLIDS) && !(cutflag & FF_EXTRA))
+			solid = true;
+		else if ((sector->lightlist[i].flags & FF_CUTEXTRA) && (cutflag & FF_EXTRA))
 		{
-			if (sector->lightlist[i].caster->flags & FF_CUTSOLIDS && !(cutflag & FF_EXTRA))
-				solid = true;
-			else if (sector->lightlist[i].caster->flags & FF_CUTEXTRA && cutflag & FF_EXTRA)
+			if (sector->lightlist[i].flags & FF_EXTRA)
 			{
-				if (sector->lightlist[i].caster->flags & FF_EXTRA)
-				{
-					if (sector->lightlist[i].caster->flags == cutflag) // Only merge with your own types
-						solid = true;
-				}
-				else
+				if ((sector->lightlist[i].flags & (FF_FOG|FF_SWIMMABLE)) == (cutflag & (FF_FOG|FF_SWIMMABLE))) // Only merge with your own types
 					solid = true;
 			}
 			else
-				solid = false;
+				solid = true;
 		}
 		else
 			solid = false;
 
-		if (cutflag == FF_CUTSOLIDS) // These are regular walls sent in from StoreWallRange, they shouldn't be cut from this
-			solid = false;
-
 #ifdef ESLOPE
 		if (list[i].slope)
 		{
@@ -1188,34 +1188,55 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 			if (solid && endtop > endbheight)
 				endtop = endbheight;
 #endif
-			continue;
 		}
 
+#ifdef ESLOPE
+		if (i + 1 < sector->numlights)
+		{
+			if (list[i+1].slope)
+			{
+				temp = P_GetZAt(list[i+1].slope, v1x, v1y);
+				bheight = FIXED_TO_FLOAT(temp);
+				temp = P_GetZAt(list[i+1].slope, v2x, v2y);
+				endbheight = FIXED_TO_FLOAT(temp);
+			}
+			else
+				bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height);
+		}
+		else
+		{
+			bheight = realbot;
+			endbheight = endrealbot;
+		}
+#else
+		if (i + 1 < sector->numlights)
+		{
+			bheight = FIXED_TO_FLOAT(list[i+1].height);
+		}
+		else
+		{
+			bheight = realbot;
+		}
+#endif
+
+#ifdef ESLOPE
+		if (endbheight >= endtop)
+#endif
+		if (bheight >= top)
+			continue;
+
 		//Found a break;
-		bot = height;
+		bot = bheight;
 
 		if (bot < realbot)
 			bot = realbot;
 
 #ifdef ESLOPE
-		endbot = endheight;
+		endbot = endbheight;
 
 		if (endbot < endrealbot)
 			endbot = endrealbot;
 #endif
-
-		// colormap test
-		if (list[i-1].caster)
-		{
-			lightnum = *list[i-1].lightlevel;
-			colormap = list[i-1].extra_colormap;
-		}
-		else
-		{
-			lightnum = sector->lightlevel;
-			colormap = sector->extra_colormap;
-		}
-
 		Surf->FlatColor.s.alpha = alpha;
 
 #ifdef ESLOPE
@@ -1238,23 +1259,16 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 		wallVerts[0].y = wallVerts[1].y = bot;
 #endif
 
-		glTex = HWR_GetTexture(texnum);
-		if (cutflag & FF_TRANSLUCENT)
+		if (cutflag & FF_FOG)
+			HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap);
+		else if (cutflag & FF_TRANSLUCENT)
 			HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap);
-		else if (glTex->mipmap.flags & TF_TRANSPARENT)
-			HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Environment, false, lightnum, colormap);
 		else
 			HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap);
 
-		if (solid)
-			top = bheight;
-		else
-			top = height;
+		top = bot;
 #ifdef ESLOPE
-		if (solid)
-			endtop = endbheight;
-		else
-			endtop = endheight;
+		endtop = endbot;
 #endif
 	}
 
@@ -1266,17 +1280,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 	if (top <= realbot)
 		return;
 
-	if (list[i-1].caster)
-	{
-		lightnum = *list[i-1].lightlevel;
-		colormap = list[i-1].extra_colormap;
-	}
-	else
-	{
-		lightnum = sector->lightlevel;
-		colormap = sector->extra_colormap;
-	}
-		Surf->FlatColor.s.alpha = alpha;
+	Surf->FlatColor.s.alpha = alpha;
 
 #ifdef ESLOPE
 	wallVerts[3].t = pegt + ((realtop - top) * pegmul);
@@ -1298,119 +1302,14 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
     wallVerts[0].y = wallVerts[1].y = bot;
 #endif
 
-	glTex = HWR_GetTexture(texnum);
-	if (cutflag & FF_TRANSLUCENT)
+	if (cutflag & FF_FOG)
+		HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap);
+	else if (cutflag & FF_TRANSLUCENT)
 		HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap);
-	else if (glTex->mipmap.flags & TF_TRANSPARENT)
-		HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Environment, false, lightnum, colormap);
 	else
 		HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap);
 }
 
-//
-// HWR_SplitFog
-// Exclusively for fog
-//
-static void HWR_SplitFog(sector_t *sector, wallVert3D *wallVerts, FSurfaceInfo* Surf, UINT32 cutflag, FUINT lightnum, extracolormap_t *colormap)
-{
-	/* SoM: split up and light walls according to the
-	 lightlist. This may also include leaving out parts
-	 of the wall that can't be seen */
-	float realtop, realbot, top, bot;
-	float pegt, pegb, pegmul;
-	float height = 0.0f, bheight = 0.0f;
-	INT32   solid, i;
-	lightlist_t *  list = sector->lightlist;
-	const UINT8 alpha = Surf->FlatColor.s.alpha;
-
-	realtop = top = wallVerts[2].y;
-	realbot = bot = wallVerts[0].y;
-	pegt = wallVerts[2].t;
-	pegb = wallVerts[0].t;
-	pegmul = (pegb - pegt) / (top - bot);
-
-	for (i = 1; i < sector->numlights; i++)
-	{
-		if (top < realbot)
-			return;
-
-	//Hurdler: fix a crashing bug, but is it correct?
-//		if (!list[i].caster)
-//			continue;
-
-		solid = false;
-
-		if (list[i].caster)
-		{
-			if (sector->lightlist[i].caster->flags & FF_FOG && cutflag & FF_FOG) // Only fog cuts fog
-			{
-				if (sector->lightlist[i].caster->flags & FF_EXTRA)
-				{
-					if (sector->lightlist[i].caster->flags == cutflag) // only cut by the same
-						solid = true;
-				}
-				else
-					solid = true;
-			}
-		}
-
-		height = FIXED_TO_FLOAT(list[i].height);
-
-		if (solid)
-			bheight = FIXED_TO_FLOAT(*list[i].caster->bottomheight);
-
-		if (height >= top)
-		{
-			if (solid && top > bheight)
-				top = bheight;
-			continue;
-		}
-
-		//Found a break;
-		bot = height;
-
-		if (bot < realbot)
-			bot = realbot;
-
-		{
-
-
-
-			Surf->FlatColor.s.alpha = alpha;
-		}
-
-		wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul);
-		wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul);
-
-		// set top/bottom coords
-		wallVerts[2].y = wallVerts[3].y = top;
-		wallVerts[0].y = wallVerts[1].y = bot;
-
-		if (!solid) // Don't draw it if there's more fog behind it
-			HWR_AddTransparentWall(wallVerts, Surf, 0, PF_Translucent|PF_NoTexture, true, lightnum, colormap);
-
-		top = height;
-	}
-
-	bot = realbot;
-	if (top <= realbot)
-		return;
-
-	{
-
-		Surf->FlatColor.s.alpha = alpha;
-	}
-
-	wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul);
-	wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul);
-
-	// set top/bottom coords
-	wallVerts[2].y = wallVerts[3].y = top;
-	wallVerts[0].y = wallVerts[1].y = bot;
-
-	HWR_AddTransparentWall(wallVerts, Surf, 0, PF_Translucent|PF_NoTexture, true, lightnum, colormap);
-}
-
 // HWR_DrawSkyWalls
 // Draw walls into the depth buffer so that anything behind is culled properly
 static void HWR_DrawSkyWall(wallVert3D *wallVerts, FSurfaceInfo *Surf, fixed_t bottom, fixed_t top)
@@ -1687,7 +1586,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #endif
 
 			if (gr_frontsector->numlights)
-				HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
+				HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTLEVEL, NULL);
 			else if (grTex->mipmap.flags & TF_TRANSPARENT)
 				HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
 			else
@@ -1770,7 +1669,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #endif
 
 			if (gr_frontsector->numlights)
-				HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
+				HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTLEVEL, NULL);
 			else if (grTex->mipmap.flags & TF_TRANSPARENT)
 				HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
 			else
@@ -2033,15 +1932,14 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 			}
 #endif
 
-			if (grTex->mipmap.flags & TF_TRANSPARENT)
-				blendmode = PF_Translucent;
-
 			if (gr_frontsector->numlights)
 			{
 				if (!(blendmode & PF_Masked))
-					HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT);
+					HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT, NULL);
 				else
-					HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS);
+				{
+					HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL);
+				}
 			}
 			else if (!(blendmode & PF_Masked))
 				HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap);
@@ -2192,7 +2090,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #endif
 			// I don't think that solid walls can use translucent linedef types...
 			if (gr_frontsector->numlights)
-				HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS);
+				HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL);
 			else
 			{
 				if (grTex->mipmap.flags & TF_TRANSPARENT)
@@ -2284,27 +2182,34 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				}
 				else if (drawtextured)
 				{
-#ifdef ESLOPE // P.S. this is better-organized than the old version
-					fixed_t offs = sides[(newline ? newline : rover->master)->sidenum[0]].rowoffset;
-					grTex = HWR_GetTexture(texnum);
-
-					wallVerts[3].t = (*rover->topheight - h + offs) * grTex->scaleY;
-					wallVerts[2].t = (*rover->topheight - hS + offs) * grTex->scaleY;
-					wallVerts[0].t = (*rover->topheight - l + offs) * grTex->scaleY;
-					wallVerts[1].t = (*rover->topheight - lS + offs) * grTex->scaleY;
-#else
-					grTex = HWR_GetTexture(texnum);
+					fixed_t texturevpeg;
 
+					// Wow, how was this missing from OpenGL for so long?
+					// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
+					// -- Monster Iestyn 26/06/18
 					if (newline)
 					{
-						wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY;
-						wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY;
+						texturevpeg = sides[newline->sidenum[0]].rowoffset;
+						if (newline->flags & ML_DONTPEGBOTTOM)
+							texturevpeg -= *rover->topheight - *rover->bottomheight;
 					}
 					else
 					{
-						wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY;
-						wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY;
+						texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
+						if (gr_linedef->flags & ML_DONTPEGBOTTOM)
+							texturevpeg -= *rover->topheight - *rover->bottomheight;
 					}
+
+					grTex = HWR_GetTexture(texnum);
+
+#ifdef ESLOPE
+					wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
+					wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY;
+					wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
+					wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY;
+#else
+					wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
+					wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
 #endif
 
 					wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
@@ -2314,7 +2219,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				{
 					FBITFIELD blendmode;
 
-					blendmode = PF_Translucent|PF_NoTexture;
+					blendmode = PF_Fog|PF_NoTexture;
 
 					lightnum = rover->master->frontsector->lightlevel;
 					colormap = rover->master->frontsector->extra_colormap;
@@ -2322,15 +2227,15 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 					if (rover->master->frontsector->extra_colormap)
 					{
 
-						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba,rover->master->frontsector->extra_colormap->fadergba);
+						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba);
 					}
 					else
 					{
-						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG,FADEFOG);
+						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG);
 					}
 
 					if (gr_frontsector->numlights)
-						HWR_SplitFog(gr_frontsector, wallVerts, &Surf, rover->flags, lightnum, colormap);
+						HWR_SplitWall(gr_frontsector, wallVerts, 0, &Surf, rover->flags, rover);
 					else
 						HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
 				}
@@ -2338,18 +2243,14 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				{
 					FBITFIELD blendmode = PF_Masked;
 
-					if (rover->flags & FF_TRANSLUCENT)
+					if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
 					{
 						blendmode = PF_Translucent;
 						Surf.FlatColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
 					}
-					else if (grTex->mipmap.flags & TF_TRANSPARENT)
-					{
-						blendmode = PF_Environment;
-					}
 
 					if (gr_frontsector->numlights)
-						HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags);
+						HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags, rover);
 					else
 					{
 						if (blendmode != PF_Masked)
@@ -2438,22 +2339,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				{
 					FBITFIELD blendmode;
 
-					blendmode = PF_Translucent|PF_NoTexture;
+					blendmode = PF_Fog|PF_NoTexture;
 
 					lightnum = rover->master->frontsector->lightlevel;
 					colormap = rover->master->frontsector->extra_colormap;
 
 					if (rover->master->frontsector->extra_colormap)
 					{
-						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba,rover->master->frontsector->extra_colormap->fadergba);
+						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba);
 					}
 					else
 					{
-						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG,FADEFOG);
+						Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG);
 					}
 
 					if (gr_backsector->numlights)
-						HWR_SplitFog(gr_backsector, wallVerts, &Surf, rover->flags, lightnum, colormap);
+						HWR_SplitWall(gr_backsector, wallVerts, 0, &Surf, rover->flags, rover);
 					else
 						HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
 				}
@@ -2461,18 +2362,14 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				{
 					FBITFIELD blendmode = PF_Masked;
 
-					if (rover->flags & FF_TRANSLUCENT)
+					if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
 					{
 						blendmode = PF_Translucent;
 						Surf.FlatColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
 					}
-					else if (grTex->mipmap.flags & TF_TRANSPARENT)
-					{
-						blendmode = PF_Environment;
-					}
 
 					if (gr_backsector->numlights)
-						HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags);
+						HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags, rover);
 					else
 					{
 						if (blendmode != PF_Masked)
@@ -2786,7 +2683,7 @@ static void HWR_AddLine(seg_t * line)
 	angle_t span, tspan;
 
 	// SoM: Backsector needs to be run through R_FakeFlat
-	sector_t tempsec;
+	static sector_t tempsec;
 
 	if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES))
 		return;
@@ -3011,8 +2908,8 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
 	py2 = bspcoord[checkcoord[boxpos][3]];
 
 	// check clip list for an open space
-	angle1 = R_PointToAngle(px1, py1) - dup_viewangle;
-	angle2 = R_PointToAngle(px2, py2) - dup_viewangle;
+	angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle;
+	angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle;
 
 	span = angle1 - angle2;
 
@@ -3345,7 +3242,7 @@ static void HWR_Subsector(size_t num)
 	INT16 count;
 	seg_t *line;
 	subsector_t *sub;
-	sector_t tempsec; //SoM: 4/7/2000
+	static sector_t tempsec; //SoM: 4/7/2000
 	INT32 floorlightlevel;
 	INT32 ceilinglightlevel;
 	INT32 locFloorHeight, locCeilingHeight;
@@ -3367,7 +3264,6 @@ static void HWR_Subsector(size_t num)
 
 	if (num < numsubsectors)
 	{
-		sscount++;
 		// subsector
 		sub = &subsectors[num];
 		// sector
@@ -3528,8 +3424,6 @@ static void HWR_Subsector(size_t num)
 	{
 		/// \todo fix light, xoffs, yoffs, extracolormap ?
 		ffloor_t * rover;
-
-		R_Prep3DFloors(gr_frontsector);
 		for (rover = gr_frontsector->ffloors;
 			rover; rover = rover->next)
 		{
@@ -3563,19 +3457,19 @@ static void HWR_Subsector(size_t num)
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
 
 					if (rover->master->frontsector->extra_colormap)
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba, rover->master->frontsector->extra_colormap->fadergba);
+						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba);
 					else
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG, FADEFOG);
+						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG);
 
 					HWR_AddTransparentFloor(0,
 					                       &extrasubsectors[num],
 										   false,
 					                       *rover->bottomheight,
 					                       *gr_frontsector->lightlist[light].lightlevel,
-					                       alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
+					                       alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
 										   true, rover->master->frontsector->extra_colormap);
 				}
-				else if (rover->flags & FF_TRANSLUCENT) // SoM: Flags are more efficient
+				else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient
 				{
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
 #ifndef SORTING
@@ -3626,19 +3520,19 @@ static void HWR_Subsector(size_t num)
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
 
 					if (rover->master->frontsector->extra_colormap)
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba, rover->master->frontsector->extra_colormap->fadergba);
+						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba);
 					else
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG, FADEFOG);
+						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG);
 
 					HWR_AddTransparentFloor(0,
 					                       &extrasubsectors[num],
 										   true,
 					                       *rover->topheight,
 					                       *gr_frontsector->lightlist[light].lightlevel,
-					                       alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
+					                       alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
 										   true, rover->master->frontsector->extra_colormap);
 				}
-				else if (rover->flags & FF_TRANSLUCENT)
+				else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
 				{
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
 #ifndef SORTING
@@ -4040,12 +3934,10 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
 
 static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale)
 {
-	UINT8 i;
-	float tr_x, tr_y;
-	FOutVector *wv;
 	FOutVector swallVerts[4];
 	FSurfaceInfo sSurf;
 	fixed_t floorheight, mobjfloor;
+	float offset = 0;
 
 	mobjfloor = HWR_OpaqueFloorAtPos(
 		spr->mobj->x, spr->mobj->y,
@@ -4055,7 +3947,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
 		angle_t shadowdir;
 
 		// Set direction
-		if (splitscreen && stplyr != &players[displayplayer])
+		if (splitscreen && stplyr == &players[secondarydisplayplayer])
 			shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value);
 		else
 			shadowdir = localangle + FixedAngle(cv_cam_rotate.value);
@@ -4084,6 +3976,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
 		}
 
 		floorheight = FixedInt(spr->mobj->z - floorheight);
+
+		offset = floorheight;
 	}
 	else
 		floorheight = FixedInt(spr->mobj->z - mobjfloor);
@@ -4096,47 +3990,42 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
 	//  0--1
 
 	// x1/x2 were already scaled in HWR_ProjectSprite
+	// First match the normal sprite
 	swallVerts[0].x = swallVerts[3].x = spr->x1;
 	swallVerts[2].x = swallVerts[1].x = spr->x2;
+	swallVerts[0].z = swallVerts[3].z = spr->z1;
+	swallVerts[2].z = swallVerts[1].z = spr->z2;
 
 	if (spr->mobj && this_scale != 1.0f)
 	{
 		// Always a pixel above the floor, perfectly flat.
 		swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3);
 
-		swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset) * this_scale;
-		swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset * this_scale;
+		// Now transform the TOP vertices along the floor in the direction of the camera
+		swallVerts[3].x = spr->x1 + ((gpatch->height * this_scale) + offset) * gr_viewcos;
+		swallVerts[2].x = spr->x2 + ((gpatch->height * this_scale) + offset) * gr_viewcos;
+		swallVerts[3].z = spr->z1 + ((gpatch->height * this_scale) + offset) * gr_viewsin;
+		swallVerts[2].z = spr->z2 + ((gpatch->height * this_scale) + offset) * gr_viewsin;
 	}
 	else
 	{
 		// Always a pixel above the floor, perfectly flat.
 		swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3);
 
-		// Spread out top away from the camera. (Fixme: Make it always move out in the same direction!... somehow.)
-		swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset);
-		swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset;
+		// Now transform the TOP vertices along the floor in the direction of the camera
+		swallVerts[3].x = spr->x1 + (gpatch->height + offset) * gr_viewcos;
+		swallVerts[2].x = spr->x2 + (gpatch->height + offset) * gr_viewcos;
+		swallVerts[3].z = spr->z1 + (gpatch->height + offset) * gr_viewsin;
+		swallVerts[2].z = spr->z2 + (gpatch->height + offset) * gr_viewsin;
 	}
 
-	// transform
-	wv = swallVerts;
-
-	for (i = 0; i < 4; i++,wv++)
+	// We also need to move the bottom ones away when shadowoffs is on
+	if (cv_shadowoffs.value)
 	{
-		// Offset away from the camera based on height from floor.
-		if (cv_shadowoffs.value)
-			wv->z += floorheight;
-		wv->z += 3;
-
-		//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-		tr_x = wv->z;
-		tr_y = wv->y;
-		wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
-		wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
-		// ---------------------- mega lame test ----------------------------------
-
-		//scale y before frustum so that frustum can be scaled to screen height
-		wv->y *= ORIGINAL_ASPECT * gr_fovlud;
-		wv->x *= gr_fovlud;
+		swallVerts[0].x = spr->x1 + offset * gr_viewcos;
+		swallVerts[1].x = spr->x2 + offset * gr_viewcos;
+		swallVerts[0].z = spr->z1 + offset * gr_viewsin;
+		swallVerts[1].z = spr->z2 + offset * gr_viewsin;
 	}
 
 	if (spr->flip)
@@ -4216,6 +4105,291 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
 	}
 }
 
+static void HWR_SplitSprite(gr_vissprite_t *spr)
+{
+	float this_scale = 1.0f;
+	FOutVector wallVerts[4];
+	GLPatch_t *gpatch;
+	FSurfaceInfo Surf;
+	const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
+	extracolormap_t *colormap;
+	FUINT lightlevel;
+	FBITFIELD blend = 0;
+	UINT8 alpha;
+
+	INT32 i;
+	float realtop, realbot, top, bot;
+	float towtop, towbot, towmult;
+	float bheight;
+	const sector_t *sector = spr->mobj->subsector->sector;
+	const lightlist_t *list = sector->lightlist;
+#ifdef ESLOPE
+	float endrealtop, endrealbot, endtop, endbot;
+	float endbheight;
+	fixed_t temp;
+	fixed_t v1x, v1y, v2x, v2y;
+#endif
+
+	this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
+
+	if (hires)
+		this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale);
+
+	gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
+
+	// cache the patch in the graphics card memory
+	//12/12/99: Hurdler: same comment as above (for md2)
+	//Hurdler: 25/04/2000: now support colormap in hardware mode
+	HWR_GetMappedPatch(gpatch, spr->colormap);
+
+	// Draw shadow BEFORE sprite
+	if (cv_shadow.value // Shadows enabled
+		&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
+		&& !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow.
+#ifdef ALAM_LIGHTING
+		&& !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow.
+		&& (!spr->mobj->player || spr->mobj->player->powers[pw_super])) // Except for non-super players.
+#endif
+		&& (spr->mobj->z >= spr->mobj->floorz)) // Without this, your shadow shows on the floor, even after you die and fall through the ground.
+	{
+		////////////////////
+		// SHADOW SPRITE! //
+		////////////////////
+		HWR_DrawSpriteShadow(spr, gpatch, this_scale);
+	}
+
+	wallVerts[0].x = wallVerts[3].x = spr->x1;
+	wallVerts[2].x = wallVerts[1].x = spr->x2;
+	wallVerts[0].z = wallVerts[3].z = spr->z1;
+	wallVerts[1].z = wallVerts[2].z = spr->z2;
+
+	wallVerts[2].y = wallVerts[3].y = spr->ty;
+	if (spr->mobj && this_scale != 1.0f)
+		wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale;
+	else
+		wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height;
+
+	v1x = FLOAT_TO_FIXED(spr->x1);
+	v1y = FLOAT_TO_FIXED(spr->z1);
+	v2x = FLOAT_TO_FIXED(spr->x2);
+	v2y = FLOAT_TO_FIXED(spr->z2);
+
+	if (spr->flip)
+	{
+		wallVerts[0].sow = wallVerts[3].sow = gpatch->max_s;
+		wallVerts[2].sow = wallVerts[1].sow = 0;
+	}else{
+		wallVerts[0].sow = wallVerts[3].sow = 0;
+		wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s;
+	}
+
+	// flip the texture coords (look familiar?)
+	if (spr->vflip)
+	{
+		wallVerts[3].tow = wallVerts[2].tow = gpatch->max_t;
+		wallVerts[0].tow = wallVerts[1].tow = 0;
+	}else{
+		wallVerts[3].tow = wallVerts[2].tow = 0;
+		wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t;
+	}
+
+	realtop = top = wallVerts[3].y;
+	realbot = bot = wallVerts[0].y;
+	towtop = wallVerts[3].tow;
+	towbot = wallVerts[0].tow;
+	towmult = (towbot - towtop) / (top - bot);
+
+#ifdef ESLOPE
+	endrealtop = endtop = wallVerts[2].y;
+	endrealbot = endbot = wallVerts[1].y;
+#endif
+
+	if (!cv_translucency.value) // translucency disabled
+	{
+		Surf.FlatColor.s.alpha = 0xFF;
+		blend = PF_Translucent|PF_Occlude;
+	}
+	else if (spr->mobj->flags2 & MF2_SHADOW)
+	{
+		Surf.FlatColor.s.alpha = 0x40;
+		blend = PF_Translucent;
+	}
+	else if (spr->mobj->frame & FF_TRANSMASK)
+		blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
+	else
+	{
+		// BP: i agree that is little better in environement but it don't
+		//     work properly under glide nor with fogcolor to ffffff :(
+		// Hurdler: PF_Environement would be cool, but we need to fix
+		//          the issue with the fog before
+		Surf.FlatColor.s.alpha = 0xFF;
+		blend = PF_Translucent|PF_Occlude;
+	}
+
+	alpha = Surf.FlatColor.s.alpha;
+
+	// Start with the lightlevel and colormap from the top of the sprite
+	lightlevel = *list[sector->numlights - 1].lightlevel;
+	colormap = list[sector->numlights - 1].extra_colormap;
+	i = 0;
+	temp = FLOAT_TO_FIXED(realtop);
+
+	if (spr->mobj->frame & FF_FULLBRIGHT)
+		lightlevel = 255;
+
+#ifdef ESLOPE
+	for (i = 1; i < sector->numlights; i++)
+	{
+		fixed_t h = sector->lightlist[i].slope ? P_GetZAt(sector->lightlist[i].slope, spr->mobj->x, spr->mobj->y)
+					: sector->lightlist[i].height;
+		if (h <= temp)
+		{
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = *list[i-1].lightlevel;
+			colormap = list[i-1].extra_colormap;
+			break;
+		}
+	}
+#else
+	i = R_GetPlaneLight(sector, temp, false);
+	if (!(spr->mobj->frame & FF_FULLBRIGHT))
+		lightlevel = *list[i].lightlevel;
+	colormap = list[i].extra_colormap;
+#endif
+
+	for (i = 0; i < sector->numlights; i++)
+	{
+#ifdef ESLOPE
+		if (endtop < endrealbot)
+#endif
+		if (top < realbot)
+			return;
+
+		// even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite
+		if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
+		{
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = *list[i].lightlevel;
+			colormap = list[i].extra_colormap;
+		}
+
+#ifdef ESLOPE
+		if (i + 1 < sector->numlights)
+		{
+			if (list[i+1].slope)
+			{
+				temp = P_GetZAt(list[i+1].slope, v1x, v1y);
+				bheight = FIXED_TO_FLOAT(temp);
+				temp = P_GetZAt(list[i+1].slope, v2x, v2y);
+				endbheight = FIXED_TO_FLOAT(temp);
+			}
+			else
+				bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height);
+		}
+		else
+		{
+			bheight = realbot;
+			endbheight = endrealbot;
+		}
+#else
+		if (i + 1 < sector->numlights)
+		{
+			bheight = FIXED_TO_FLOAT(list[i+1].height);
+		}
+		else
+		{
+			bheight = realbot;
+		}
+#endif
+
+#ifdef ESLOPE
+		if (endbheight >= endtop)
+#endif
+		if (bheight >= top)
+			continue;
+
+		bot = bheight;
+
+		if (bot < realbot)
+			bot = realbot;
+
+#ifdef ESLOPE
+		endbot = endbheight;
+
+		if (endbot < endrealbot)
+			endbot = endrealbot;
+#endif
+
+#ifdef ESLOPE
+		wallVerts[3].tow = towtop + ((realtop - top) * towmult);
+		wallVerts[2].tow = towtop + ((endrealtop - endtop) * towmult);
+		wallVerts[0].tow = towtop + ((realtop - bot) * towmult);
+		wallVerts[1].tow = towtop + ((endrealtop - endbot) * towmult);
+
+		wallVerts[3].y = top;
+		wallVerts[2].y = endtop;
+		wallVerts[0].y = bot;
+		wallVerts[1].y = endbot;
+#else
+		wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult);
+		wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult);
+
+		wallVerts[2].y = wallVerts[3].y = top;
+		wallVerts[0].y = wallVerts[1].y = bot;
+#endif
+
+		if (colormap)
+			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
+		else
+			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
+
+		Surf.FlatColor.s.alpha = alpha;
+
+		HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip);
+
+		top = bot;
+#ifdef ESLOPE
+		endtop = endbot;
+#endif
+	}
+
+	bot = realbot;
+#ifdef ESLOPE
+	endbot = endrealbot;
+	if (endtop <= endrealbot)
+#endif
+	if (top <= realbot)
+		return;
+
+	// If we're ever down here, somehow the above loop hasn't draw all the light levels of sprite
+#ifdef ESLOPE
+	wallVerts[3].tow = towtop + ((realtop - top) * towmult);
+	wallVerts[2].tow = towtop + ((endrealtop - endtop) * towmult);
+	wallVerts[0].tow = towtop + ((realtop - bot) * towmult);
+	wallVerts[1].tow = towtop + ((endrealtop - endbot) * towmult);
+
+	wallVerts[3].y = top;
+	wallVerts[2].y = endtop;
+	wallVerts[0].y = bot;
+	wallVerts[1].y = endbot;
+#else
+	wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult);
+	wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult);
+
+	wallVerts[2].y = wallVerts[3].y = top;
+	wallVerts[0].y = wallVerts[1].y = bot;
+#endif
+
+	if (colormap)
+		Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
+	else
+		Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
+
+	Surf.FlatColor.s.alpha = alpha;
+
+	HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip);
+}
+
 // -----------------+
 // HWR_DrawSprite   : Draw flat sprites
 //                  : (monsters, bonuses, weapons, lights, ...)
@@ -4223,10 +4397,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
 // -----------------+
 static void HWR_DrawSprite(gr_vissprite_t *spr)
 {
-	UINT8 i;
-	float tr_x, tr_y, this_scale = 1.0f;
+	float this_scale = 1.0f;
 	FOutVector wallVerts[4];
-	FOutVector *wv;
 	GLPatch_t *gpatch; // sprite patch converted to hardware
 	FSurfaceInfo Surf;
 	const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
@@ -4241,6 +4413,12 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 	if (!spr->mobj->subsector)
 		return;
 
+	if (spr->mobj->subsector->sector->numlights)
+	{
+		HWR_SplitSprite(spr);
+		return;
+	}
+
 	// cache sprite graphics
 	//12/12/99: Hurdler:
 	//          OK, I don't change anything for MD2 support because I want to be
@@ -4273,24 +4451,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 
 	// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
 	// and the 2d map coords of start/end vertices
-	wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz;
-
-	// transform
-	wv = wallVerts;
-
-	for (i = 0; i < 4; i++,wv++)
-	{
-		//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-		tr_x = wv->z;
-		tr_y = wv->y;
-		wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
-		wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
-		// ---------------------- mega lame test ----------------------------------
-
-		//scale y before frustum so that frustum can be scaled to screen height
-		wv->y *= ORIGINAL_ASPECT * gr_fovlud;
-		wv->x *= gr_fovlud;
-	}
+	wallVerts[0].z = wallVerts[3].z = spr->z1;
+	wallVerts[1].z = wallVerts[2].z = spr->z2;
 
 	if (spr->flip)
 	{
@@ -4342,26 +4504,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 		UINT8 lightlevel = 255;
 		extracolormap_t *colormap = sector->extra_colormap;
 
-		if (sector->numlights)
-		{
-			INT32 light;
-
-			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
-
-			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = *sector->lightlist[light].lightlevel;
-
-			if (sector->lightlist[light].extra_colormap)
-				colormap = sector->lightlist[light].extra_colormap;
-		}
-		else
-		{
-			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = sector->lightlevel;
-
-			if (sector->extra_colormap)
-				colormap = sector->extra_colormap;
-		}
+		if (!(spr->mobj->frame & FF_FULLBRIGHT))
+			lightlevel = sector->lightlevel;
 
 		if (colormap)
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
@@ -4401,11 +4545,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 // Sprite drawer for precipitation
 static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 {
-	UINT8 i;
 	FBITFIELD blend = 0;
-	float tr_x, tr_y;
 	FOutVector wallVerts[4];
-	FOutVector *wv;
 	GLPatch_t *gpatch; // sprite patch converted to hardware
 	FSurfaceInfo Surf;
 
@@ -4431,24 +4572,8 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 
 	// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
 	// and the 2d map coords of start/end vertices
-	wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz;
-
-	// transform
-	wv = wallVerts;
-
-	for (i = 0; i < 4; i++, wv++)
-	{
-		//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-		tr_x = wv->z;
-		tr_y = wv->y;
-		wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
-		wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
-		// ---------------------- mega lame test ----------------------------------
-
-		//scale y before frustum so that frustum can be scaled to screen height
-		wv->y *= ORIGINAL_ASPECT * gr_fovlud;
-		wv->x *= gr_fovlud;
-	}
+	wallVerts[0].z = wallVerts[3].z = spr->z1;
+	wallVerts[1].z = wallVerts[2].z = spr->z2;
 
 	wallVerts[0].sow = wallVerts[3].sow = 0;
 	wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s;
@@ -4581,6 +4706,33 @@ static void HWR_SortVisSprites(void)
 		gr_vsprsortedhead.prev->next = best;
 		gr_vsprsortedhead.prev = best;
 	}
+
+	// Sryder:	Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the
+	//			mix and they want to be translucent. So let's place all the translucent sprites and MD2's AFTER
+	//			everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine.
+	//			We just need to move all translucent ones to the end in order
+	// TODO:	Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that
+	best = gr_vsprsortedhead.next;
+	for (i = 0; i < gr_visspritecount; i++)
+	{
+		if ((best->mobj->flags2 & MF2_SHADOW) || (best->mobj->frame & FF_TRANSMASK))
+		{
+			if (best == gr_vsprsortedhead.next)
+			{
+				gr_vsprsortedhead.next = best->next;
+			}
+			best->prev->next = best->next;
+			best->next->prev = best->prev;
+			best->prev = gr_vsprsortedhead.prev;
+			gr_vsprsortedhead.prev->next = best;
+			gr_vsprsortedhead.prev = best;
+			ds = best;
+			best = best->next;
+			ds->next = &gr_vsprsortedhead;
+		}
+		else
+			best = best->next;
+	}
 }
 
 // A drawnode is something that points to a 3D floor, 3D side, or masked
@@ -4914,6 +5066,7 @@ static void HWR_CreateDrawNodes(void)
 //  Draw all vissprites
 // --------------------------------------------------------------------------
 #ifdef SORTING
+// added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other
 static void HWR_DrawSprites(void)
 {
 	if (gr_visspritecount > 0)
@@ -4934,44 +5087,20 @@ static void HWR_DrawSprites(void)
 				{
 					if (!cv_grmd2.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
 						HWR_DrawSprite(spr);
+					else
+						HWR_DrawMD2(spr);
 				}
-				else if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
-					HWR_DrawSprite(spr);
-		}
-	}
-}
-#endif
-// --------------------------------------------------------------------------
-//  Draw all MD2
-// --------------------------------------------------------------------------
-static void HWR_DrawMD2S(void)
-{
-	if (gr_visspritecount > 0)
-	{
-		gr_vissprite_t *spr;
-
-		// draw all MD2 back to front
-		for (spr = gr_vsprsortedhead.next;
-			spr != &gr_vsprsortedhead;
-			spr = spr->next)
-		{
-#ifdef HWPRECIP
-			if (!spr->precip)
-			{
-#endif
-				if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
+				else
 				{
-					if (md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false && md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)
+					if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
+						HWR_DrawSprite(spr);
+					else
 						HWR_DrawMD2(spr);
 				}
-				else if (md2_models[spr->mobj->sprite].notfound == false && md2_models[spr->mobj->sprite].scale > 0.0f)
-					HWR_DrawMD2(spr);
-#ifdef HWPRECIP
-			}
-#endif
 		}
 	}
 }
+#endif
 
 // --------------------------------------------------------------------------
 // HWR_AddSprites
@@ -5010,8 +5139,10 @@ static void HWR_AddSprites(sector_t *sec)
 
 			approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
 
-			if (approx_dist <= limit_dist)
-				HWR_ProjectSprite(thing);
+			if (approx_dist > limit_dist)
+				continue;
+
+			HWR_ProjectSprite(thing);
 		}
 	}
 	else
@@ -5033,8 +5164,10 @@ static void HWR_AddSprites(sector_t *sec)
 
 			approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
 
-			if (approx_dist <= limit_dist)
-				HWR_ProjectPrecipitationSprite(precipthing);
+			if (approx_dist > limit_dist)
+				continue;
+
+			HWR_ProjectPrecipitationSprite(precipthing);
 		}
 	}
 	else
@@ -5056,8 +5189,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
 {
 	gr_vissprite_t *vis;
 	float tr_x, tr_y;
-	float tx, tz;
+	float tz;
 	float x1, x2;
+	float z1, z2;
+	float rightsin, rightcos;
 	float this_scale;
 	float gz, gzt;
 	spritedef_t *sprdef;
@@ -5084,7 +5219,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	if (tz < ZCLIP_PLANE && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
 		return;
 
-	tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
+	// The above can stay as it works for cutting sprites that are too close
+	tr_x = FIXED_TO_FLOAT(thing->x);
+	tr_y = FIXED_TO_FLOAT(thing->y);
 
 	// decide which patch to use for sprite relative to player
 #ifdef RANGECHECK
@@ -5139,23 +5276,23 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
 		this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
 
-	// calculate edges of the shape
+	rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
+	rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
 	if (flip)
-		tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale;
+	{
+		x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale);
+		x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale);
+	}
 	else
-		tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale;
-
-	// project x
-	x1 = gr_windowcenterx + (tx * gr_centerx / tz);
-
-	//faB : tr_x doesnt matter
-	// hurdler: it's used in cliptosolidsegs
-	tr_x = x1;
-
-	x1 = tx;
+	{
+		x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale);
+		x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale);
+	}
 
-	tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale;
-	x2 = gr_windowcenterx + (tx * gr_centerx / tz);
+	z1 = tr_y + x1 * rightsin;
+	z2 = tr_y - x2 * rightsin;
+	x1 = tr_x + x1 * rightcos;
+	x2 = tr_x - x2 * rightcos;
 
 	if (thing->eflags & MFE_VERTICALFLIP)
 	{
@@ -5175,7 +5312,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	}
 
 	heightsec = thing->subsector->sector->heightsec;
-	phs = players[displayplayer].mo->subsector->sector->heightsec;
+	if (viewplayer->mo && viewplayer->mo->subsector)
+		phs = viewplayer->mo->subsector->sector->heightsec;
+	else
+		phs = -1;
 
 	if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
 	{
@@ -5192,13 +5332,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	// store information in a vissprite
 	vis = HWR_NewVisSprite();
 	vis->x1 = x1;
-#if 0
 	vis->x2 = x2;
-#else
-	(void)x2;
-#endif
-	vis->x2 = tx;
-	vis->tz = tz;
+	vis->z1 = z1;
+	vis->z2 = z2;
+	vis->tz = tz; // Keep tz for the simple sprite sorting that happens
 	vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
 	vis->patchlumpnum = sprframe->lumppat[rot];
 	vis->flip = flip;
@@ -5229,7 +5366,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
 		vis->colormap = colormaps;
 
 	// set top/bottom coords
-	vis->ty = gzt - gr_viewz;
+	vis->ty = gzt;
 
 	//CONS_Debug(DBG_RENDER, "------------------\nH: sprite  : %d\nH: frame   : %x\nH: type    : %d\nH: sname   : %s\n\n",
 	//            thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]);
@@ -5248,8 +5385,10 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 {
 	gr_vissprite_t *vis;
 	float tr_x, tr_y;
-	float tx, tz;
+	float tz;
 	float x1, x2;
+	float z1, z2;
+	float rightsin, rightcos;
 	spritedef_t *sprdef;
 	spriteframe_t *sprframe;
 	size_t lumpoff;
@@ -5267,7 +5406,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 	if (tz < ZCLIP_PLANE)
 		return;
 
-	tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
+	tr_x = FIXED_TO_FLOAT(thing->x);
+	tr_y = FIXED_TO_FLOAT(thing->y);
 
 	// decide which patch to use for sprite relative to player
 	if ((unsigned)thing->sprite >= numsprites)
@@ -5294,32 +5434,42 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 	lumpoff = sprframe->lumpid[0];
 	flip = sprframe->flip; // Will only be 0x00 or 0xFF
 
-	// calculate edges of the shape
-	tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
-
-	// project x
-	x1 = gr_windowcenterx + (tx * gr_centerx / tz);
-
-	//faB : tr_x doesnt matter
-	// hurdler: it's used in cliptosolidsegs
-	tr_x = x1;
+	rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
+	rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
+	if (flip)
+	{
+		x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
+		x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
+	}
+	else
+	{
+		x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
+		x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
+	}
 
-	x1 = tx;
+	z1 = tr_y + x1 * rightsin;
+	z2 = tr_y - x2 * rightsin;
+	x1 = tr_x + x1 * rightcos;
+	x2 = tr_x - x2 * rightcos;
 
-	tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width);
-	x2 = gr_windowcenterx + (tx * gr_centerx / tz);
+	// okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok
+	if (!(thing->precipflags & PCF_THUNK))
+	{
+		if (thing->precipflags & PCF_RAIN)
+			P_RainThinker(thing);
+		else
+			P_SnowThinker(thing);
+		thing->precipflags |= PCF_THUNK;
+	}
 
 	//
 	// store information in a vissprite
 	//
 	vis = HWR_NewVisSprite();
 	vis->x1 = x1;
-#if 0
 	vis->x2 = x2;
-#else
-	(void)x2;
-#endif
-	vis->x2 = tx;
+	vis->z1 = z1;
+	vis->z2 = z2;
 	vis->tz = tz;
 	vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
 	vis->patchlumpnum = sprframe->lumppat[rot];
@@ -5329,7 +5479,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 	vis->colormap = colormaps;
 
 	// set top/bottom coords
-	vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz;
+	vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset);
 
 	vis->precip = true;
 }
@@ -5357,12 +5507,13 @@ static void HWR_DrawSkyBackground(player_t *player)
 	//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
 	//         because it's called just after clearing the screen
 	//         and thus, the near clipping plane is set to 3.99
-	v[0].x = v[3].x = -4.0f;
-	v[1].x = v[2].x =  4.0f;
-	v[0].y = v[1].y = -4.0f;
-	v[2].y = v[3].y =  4.0f;
+	// Sryder: Just use the near clipping plane value then
+	v[0].x = v[3].x = -ZCLIP_PLANE-1;
+	v[1].x = v[2].x =  ZCLIP_PLANE+1;
+	v[0].y = v[1].y = -ZCLIP_PLANE-1;
+	v[2].y = v[3].y =  ZCLIP_PLANE+1;
 
-	v[0].z = v[1].z = v[2].z = v[3].z = 4.0f;
+	v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1;
 
 	// X
 
@@ -5430,7 +5581,7 @@ static inline void HWR_ClearView(void)
 	                 (INT32)gr_viewwindowy,
 	                 (INT32)(gr_viewwindowx + gr_viewwidth),
 	                 (INT32)(gr_viewwindowy + gr_viewheight),
-	                 3.99f);
+	                 ZCLIP_PLANE);
 	HWD.pfnClearBuffer(false, true, 0);
 
 	//disable clip window - set to full size
@@ -5469,6 +5620,8 @@ void HWR_SetViewSize(void)
 
 	gr_pspritexscale = gr_viewwidth / BASEVIDWIDTH;
 	gr_pspriteyscale = ((vid.height*gr_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
+
+	HWD.pfnFlushScreenTextures();
 }
 
 // ==========================================================================
@@ -5477,7 +5630,6 @@ void HWR_SetViewSize(void)
 void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 {
 	const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
-	FTransform stransform;
 	postimg_t *type;
 
 	if (splitscreen && player == &players[secondarydisplayplayer])
@@ -5541,31 +5693,12 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 	atransform.y      = gr_viewy;  // FIXED_TO_FLOAT(viewy)
 	atransform.z      = gr_viewz;  // FIXED_TO_FLOAT(viewz)
 	atransform.scalex = 1;
-	atransform.scaley = ORIGINAL_ASPECT;
+	atransform.scaley = (float)vid.width/vid.height;
 	atransform.scalez = 1;
 	atransform.fovxangle = fpov; // Tails
 	atransform.fovyangle = fpov; // Tails
 	atransform.splitscreen = splitscreen;
 
-	// Transform for sprites
-	stransform.anglex = 0.0f;
-	stransform.angley = -270.0f;
-
-	if (*type == postimg_flip)
-		stransform.flip = true;
-	else
-		stransform.flip = false;
-
-	stransform.x      = 0.0f;
-	stransform.y      = 0.0f;
-	stransform.z      = 0.0f;
-	stransform.scalex = 1;
-	stransform.scaley = 1;
-	stransform.scalez = 1;
-	stransform.fovxangle = 90.0f;
-	stransform.fovyangle = 90.0f;
-	stransform.splitscreen = splitscreen;
-
 	gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
 
 	//------------------------------------------------------------------------
@@ -5644,10 +5777,7 @@ if (0)
 #ifdef SORTING
 	HWR_SortVisSprites();
 #endif
-	HWR_DrawMD2S();
 
-	// Draw the sprites with trivial transform
-	HWD.pfnSetTransform(&stransform);
 #ifdef SORTING
 	HWR_DrawSprites();
 #endif
@@ -5692,7 +5822,6 @@ if (0)
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 {
 	const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
-	FTransform stransform;
 	postimg_t *type;
 
 	const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
@@ -5771,31 +5900,12 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 	atransform.y      = gr_viewy;  // FIXED_TO_FLOAT(viewy)
 	atransform.z      = gr_viewz;  // FIXED_TO_FLOAT(viewz)
 	atransform.scalex = 1;
-	atransform.scaley = ORIGINAL_ASPECT;
+	atransform.scaley = (float)vid.width/vid.height;
 	atransform.scalez = 1;
 	atransform.fovxangle = fpov; // Tails
 	atransform.fovyangle = fpov; // Tails
 	atransform.splitscreen = splitscreen;
 
-	// Transform for sprites
-	stransform.anglex = 0.0f;
-	stransform.angley = -270.0f;
-
-	if (*type == postimg_flip)
-		stransform.flip = true;
-	else
-		stransform.flip = false;
-
-	stransform.x      = 0.0f;
-	stransform.y      = 0.0f;
-	stransform.z      = 0.0f;
-	stransform.scalex = 1;
-	stransform.scaley = 1;
-	stransform.scalez = 1;
-	stransform.fovxangle = 90.0f;
-	stransform.fovyangle = 90.0f;
-	stransform.splitscreen = splitscreen;
-
 	gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
 
 	//------------------------------------------------------------------------
@@ -5874,10 +5984,7 @@ if (0)
 #ifdef SORTING
 	HWR_SortVisSprites();
 #endif
-	HWR_DrawMD2S();
 
-	// Draw the sprites with trivial transform
-	HWD.pfnSetTransform(&stransform);
 #ifdef SORTING
 	HWR_DrawSprites();
 #endif
@@ -6068,6 +6175,7 @@ void HWR_Shutdown(void)
 	HWR_FreeExtraSubsectors();
 	HWR_FreePolyPool();
 	HWR_FreeTextureCache();
+	HWD.pfnFlushScreenTextures();
 }
 
 void transform(float *cx, float *cy, float *cz)
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index f59c1d4fcca7b41fc671a0724f3b0c2a0abeedb5..756d5a09821b052fe93668be33d04189af4fdc39 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -33,6 +33,7 @@
 #include "hw_drv.h"
 #include "hw_light.h"
 #include "hw_md2.h"
+#include "../d_main.h"
 #include "../r_bsp.h"
 #include "../r_main.h"
 #include "../m_misc.h"
@@ -67,6 +68,10 @@
  #endif
 #endif
 
+#ifndef errno
+#include "errno.h"
+#endif
+
 #define NUMVERTEXNORMALS 162
 float avertexnormals[NUMVERTEXNORMALS][3] = {
 {-0.525731f, 0.000000f, 0.850651f},
@@ -288,7 +293,8 @@ static md2_model_t *md2_readModel(const char *filename)
 	if (model == NULL)
 		return 0;
 
-	file = fopen(filename, "rb");
+	//Filename checking fixed ~Monster Iestyn and Golden
+	file = fopen(va("%s"PATHSEP"%s", srb2home, filename), "rb");
 	if (!file)
 	{
 		free(model);
@@ -477,7 +483,8 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_
 #endif
 #endif
 	png_FILE_p png_FILE;
-	char *pngfilename = va("md2/%s", filename);
+	//Filename checking fixed ~Monster Iestyn and Golden
+	char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename);
 
 	FIL_ForceExtension(pngfilename, ".png");
 	png_FILE = fopen(pngfilename, "rb");
@@ -605,7 +612,8 @@ static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h,
 	size_t pw, ph, size, ptr = 0;
 	INT32 ch, rep;
 	FILE *file;
-	char *pcxfilename = va("md2/%s", filename);
+	//Filename checking fixed ~Monster Iestyn and Golden
+	char *pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename);
 
 	FIL_ForceExtension(pcxfilename, ".pcx");
 	file = fopen(pcxfilename, "rb");
@@ -795,11 +803,12 @@ void HWR_InitMD2(void)
 	}
 
 	// read the md2.dat file
-	f = fopen("md2.dat", "rt");
+	//Filename checking fixed ~Monster Iestyn and Golden
+	f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt");
 
 	if (!f)
 	{
-		CONS_Printf("%s", M_GetText("Error while loading md2.dat\n"));
+		CONS_Printf("%s %s\n", M_GetText("Error while loading md2.dat:"), strerror(errno));
 		nomd2s = true;
 		return;
 	}
@@ -861,7 +870,8 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup
 	CONS_Printf("AddPlayerMD2()...\n");
 
 	// read the md2.dat file
-	f = fopen("md2.dat", "rt");
+	//Filename checking fixed ~Monster Iestyn and Golden
+	f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt");
 
 	if (!f)
 	{
@@ -906,7 +916,8 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu
 		return;
 
 	// Read the md2.dat file
-	f = fopen("md2.dat", "rt");
+	//Filename checking fixed ~Monster Iestyn and Golden
+	f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt");
 
 	if (!f)
 	{
@@ -1347,7 +1358,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames;
 		buff = md2->model->glCommandBuffer;
 		curr = &md2->model->frames[frame];
-		if (cv_grmd2.value == 1)
+		if (cv_grmd2.value == 1 && tics <= durs)
 		{
 			// frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation
 			if (spr->mobj->frame & FF_ANIMATE)
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 205b399b89c12f44702bfb2122b8cb5b944bf7db..8e3ae3e21bfdca783189e828e9a210ca4817305b 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -59,7 +59,7 @@ typedef struct GLRGBAFloat GLRGBAFloat;
 #define      N_PI_DEMI               (M_PIl/2.0f) //(1.5707963268f)
 
 #define      ASPECT_RATIO            (1.0f)  //(320.0f/200.0f)
-#define      FAR_CLIPPING_PLANE      150000.0f // Draw further! Tails 01-21-2001
+#define      FAR_CLIPPING_PLANE      32768.0f // Draw further! Tails 01-21-2001
 static float NEAR_CLIPPING_PLANE =   NZCLIP_PLANE;
 
 // **************************************************************************
@@ -107,10 +107,19 @@ static GLint       viewport[4];
 #endif
 
 // Yay for arbitrary  numbers! NextTexAvail is buggy for some reason.
-static GLuint screentexture = 60000;
-static GLuint startScreenWipe = 60001;
-static GLuint endScreenWipe = 60002;
-static GLuint finalScreenTexture = 60003;
+// Sryder:	NextTexAvail is broken for these because palette changes or changes to the texture filter or antialiasing
+//			flush all of the stored textures, leaving them unavailable at times such as between levels
+//			These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs
+//			can know when the textures aren't there, as textures are always considered resident in their virtual memory
+// TODO:	Store them in a more normal way
+#define SCRTEX_SCREENTEXTURE 65535
+#define SCRTEX_STARTSCREENWIPE 65534
+#define SCRTEX_ENDSCREENWIPE 65533
+#define SCRTEX_FINALSCREENTEXTURE 65532
+static GLuint screentexture = 0;
+static GLuint startScreenWipe = 0;
+static GLuint endScreenWipe = 0;
+static GLuint finalScreenTexture = 0;
 #if 0
 GLuint screentexture = FIRST_TEX_AVAIL;
 #endif
@@ -263,6 +272,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
 /* texture mapping */ //GL_EXT_copy_texture
 #ifndef KOS_GL_COMPATIBILITY
 #define pglCopyTexImage2D glCopyTexImage2D
+#define pglCopyTexSubImage2D glCopyTexSubImage2D
 #endif
 
 #else //!STATIC_OPENGL
@@ -387,6 +397,8 @@ static PFNglBindTexture pglBindTexture;
 /* texture mapping */ //GL_EXT_copy_texture
 typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
 static PFNglCopyTexImage2D pglCopyTexImage2D;
+typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+static PFNglCopyTexSubImage2D pglCopyTexSubImage2D;
 #endif
 /* GLU functions */
 typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
@@ -503,6 +515,7 @@ boolean SetupGLfunc(void)
 	GETOPENGLFUNC(pglBindTexture , glBindTexture)
 
 	GETOPENGLFUNC(pglCopyTexImage2D , glCopyTexImage2D)
+	GETOPENGLFUNC(pglCopyTexSubImage2D , glCopyTexSubImage2D)
 
 #undef GETOPENGLFUNC
 
@@ -654,6 +667,10 @@ void SetModelView(GLint w, GLint h)
 {
 //	DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h);
 
+	// The screen textures need to be flushed if the width or height change so that they be remade for the correct size
+	if (screen_width != w || screen_height != h)
+		FlushScreenTextures();
+
 	screen_width = w;
 	screen_height = h;
 
@@ -801,6 +818,7 @@ void Flush(void)
 		screentexture = FIRST_TEX_AVAIL;
 	}
 #endif
+
 	tex_downloaded = 0;
 }
 
@@ -1056,30 +1074,56 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags)
 			switch (PolyFlags & PF_Blending) {
 				case PF_Translucent & PF_Blending:
 					pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_NOTEQUAL, 0.0f);
+#endif
 					break;
 				case PF_Masked & PF_Blending:
 					// Hurdler: does that mean lighting is only made by alpha src?
 					// it sounds ok, but not for polygonsmooth
 					pglBlendFunc(GL_SRC_ALPHA, GL_ZERO);                // 0 alpha = holes in texture
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_GREATER, 0.5f);
+#endif
 					break;
 				case PF_Additive & PF_Blending:
 #ifdef ATI_RAGE_PRO_COMPATIBILITY
 					pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
 #else
 					pglBlendFunc(GL_SRC_ALPHA, GL_ONE);                 // src * alpha + dest
+#endif
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_NOTEQUAL, 0.0f);
 #endif
 					break;
 				case PF_Environment & PF_Blending:
 					pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_NOTEQUAL, 0.0f);
+#endif
 					break;
 				case PF_Substractive & PF_Blending:
 					// good for shadow
 					// not realy but what else ?
 					pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_NOTEQUAL, 0.0f);
+#endif
+					break;
+				case PF_Fog & PF_Fog:
+					// Sryder: Fog
+					// multiplies input colour by input alpha, and destination colour by input colour, then adds them
+					pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR);
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_NOTEQUAL, 0.0f);
+#endif
 					break;
 				default : // must be 0, otherwise it's an error
 					// No blending
 					pglBlendFunc(GL_ONE, GL_ZERO);   // the same as no blending
+#ifndef KOS_GL_COMPATIBILITY
+					pglAlphaFunc(GL_GREATER, 0.5f);
+#endif
 					break;
 			}
 		}
@@ -1339,6 +1383,7 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
 						tex[w*j+i].s.green = 0;
 						tex[w*j+i].s.blue  = 0;
 						tex[w*j+i].s.alpha = 0;
+						pTexInfo->flags |= TF_TRANSPARENT; // there is a hole in it
 					}
 					else
 					{
@@ -1409,8 +1454,22 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
 		tex_downloaded = pTexInfo->downloaded;
 		pglBindTexture(GL_TEXTURE_2D, pTexInfo->downloaded);
 
-		pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
-		pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
+		// disable texture filtering on any texture that has holes so there's no dumb borders or blending issues
+		if (pTexInfo->flags & TF_TRANSPARENT)
+		{
+#ifdef KOS_GL_COMPATIBILITY
+			pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NONE);
+			pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NONE);
+#else
+			pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+#endif
+		}
+		else
+		{
+			pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
+			pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
+		}
 
 #ifdef KOS_GL_COMPATIBILITY
 		pglTexImage2D(GL_TEXTURE_2D, 0, GL_ARGB4444, w, h, 0, GL_ARGB4444, GL_UNSIGNED_BYTE, ptex);
@@ -1864,12 +1923,6 @@ static  void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration,
 			ambient[1] = 0.75f;
 		if (ambient[2] > 0.75f)
 			ambient[2] = 0.75f;
-
-		if (color[3] < 255)
-		{
-			pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-			pglDepthMask(GL_FALSE);
-		}
 	}
 
 	pglEnable(GL_CULL_FACE);
@@ -1896,10 +1949,12 @@ static  void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration,
 		pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
 		pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
 #endif
+		if (color[3] < 255)
+			SetBlend(PF_Translucent|PF_Modulated|PF_Clip);
+		else
+			SetBlend(PF_Masked|PF_Modulated|PF_Occlude|PF_Clip);
 	}
 
-	DrawPolygon(NULL, NULL, 0, PF_Masked|PF_Modulated|PF_Occlude|PF_Clip);
-
 	pglPushMatrix(); // should be the same as glLoadIdentity
 	//Hurdler: now it seems to work
 	pglTranslatef(pos->x, pos->z, pos->y);
@@ -1907,14 +1962,6 @@ static  void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration,
 		scaley = -scaley;
 	pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
 	pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f);
-	//pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
-
-	// Remove depth mask when the model is transparent so it doesn't cut thorugh sprites // SRB2CBTODO: For all stuff too?!
-	if (color && color[3] < 255)
-	{
-		pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
-		pglDepthMask(GL_FALSE);
-	}
 
 	val = *gl_cmd_buffer++;
 
@@ -1982,7 +2029,6 @@ static  void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration,
 	if (color)
 		pglDisable(GL_LIGHTING);
 	pglShadeModel(GL_FLAT);
-	pglDepthMask(GL_TRUE);
 	pglDisable(GL_CULL_FACE);
 }
 
@@ -2135,10 +2181,25 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
 }
 #endif //SHUFFLE
 
+// Sryder:	This needs to be called whenever the screen changes resolution in order to reset the screen textures to use
+//			a new size
+EXPORT void HWRAPI(FlushScreenTextures) (void)
+{
+	pglDeleteTextures(1, &screentexture);
+	pglDeleteTextures(1, &startScreenWipe);
+	pglDeleteTextures(1, &endScreenWipe);
+	pglDeleteTextures(1, &finalScreenTexture);
+	screentexture = 0;
+	startScreenWipe = 0;
+	endScreenWipe = 0;
+	finalScreenTexture = 0;
+}
+
 // Create Screen to fade from
 EXPORT void HWRAPI(StartScreenWipe) (void)
 {
 	INT32 texsize = 2048;
+	boolean firstTime = (startScreenWipe == 0);
 
 	// Use a power of two texture, dammit
 	if(screen_width <= 512)
@@ -2147,27 +2208,38 @@ EXPORT void HWRAPI(StartScreenWipe) (void)
 		texsize = 1024;
 
 	// Create screen texture
+	if (firstTime)
+		startScreenWipe = SCRTEX_STARTSCREENWIPE;
 	pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
+
+	if (firstTime)
+	{
 #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);
+		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);
+		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_RGB, 0, 0, texsize, texsize, 0);
 #endif
-	Clamp2D(GL_TEXTURE_WRAP_S);
-	Clamp2D(GL_TEXTURE_WRAP_T);
+	}
+	else
 #ifndef KOS_GL_COMPATIBILITY
-	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
+		pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
 #endif
 
-	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+	tex_downloaded = startScreenWipe;
 }
 
 // Create Screen to fade to
 EXPORT void HWRAPI(EndScreenWipe)(void)
 {
 	INT32 texsize = 2048;
+	boolean firstTime = (endScreenWipe == 0);
 
 	// Use a power of two texture, dammit
 	if(screen_width <= 512)
@@ -2176,21 +2248,32 @@ EXPORT void HWRAPI(EndScreenWipe)(void)
 		texsize = 1024;
 
 	// Create screen texture
+	if (firstTime)
+		endScreenWipe = SCRTEX_ENDSCREENWIPE;
 	pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
+
+	if (firstTime)
+	{
 #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);
+		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);
+		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_RGB, 0, 0, texsize, texsize, 0);
 #endif
-	Clamp2D(GL_TEXTURE_WRAP_S);
-	Clamp2D(GL_TEXTURE_WRAP_T);
+	}
+	else
 #ifndef KOS_GL_COMPATIBILITY
-	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
+		pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
 #endif
 
-	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+
+	tex_downloaded = endScreenWipe;
 }
 
 
@@ -2232,7 +2315,7 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void)
 
 	pglEnd();
 
-	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+	tex_downloaded = screentexture;
 }
 
 // Do screen fades!
@@ -2323,6 +2406,7 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha)
 
 		pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit
 		pglActiveTexture(GL_TEXTURE0);
+		tex_downloaded = endScreenWipe;
 	}
 	else
 	{
@@ -2348,11 +2432,10 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha)
 		pglTexCoord2f(xfix, 0.0f);
 		pglVertex3f(1.0f, -1.0f, 1.0f);
 	pglEnd();
+	tex_downloaded = endScreenWipe;
 #ifndef MINI_GL_COMPATIBILITY
 	}
 #endif
-
-	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
 }
 
 
@@ -2360,6 +2443,7 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha)
 EXPORT void HWRAPI(MakeScreenTexture) (void)
 {
 	INT32 texsize = 2048;
+	boolean firstTime = (screentexture == 0);
 
 	// Use a power of two texture, dammit
 	if(screen_width <= 512)
@@ -2368,26 +2452,37 @@ EXPORT void HWRAPI(MakeScreenTexture) (void)
 		texsize = 1024;
 
 	// Create screen texture
+	if (firstTime)
+		screentexture = SCRTEX_SCREENTEXTURE;
 	pglBindTexture(GL_TEXTURE_2D, screentexture);
+
+	if (firstTime)
+	{
 #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);
+		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);
+		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);
+		Clamp2D(GL_TEXTURE_WRAP_S);
+		Clamp2D(GL_TEXTURE_WRAP_T);
+#ifndef KOS_GL_COMPATIBILITY
+		pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
+#endif
+	}
+	else
 #ifndef KOS_GL_COMPATIBILITY
-	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
+		pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
 #endif
 
-	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+	tex_downloaded = screentexture;
 }
 
 EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
 {
 	INT32 texsize = 2048;
+	boolean firstTime = (finalScreenTexture == 0);
 
 	// Use a power of two texture, dammit
 	if(screen_width <= 512)
@@ -2396,27 +2491,40 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
 		texsize = 1024;
 
 	// Create screen texture
+	if (firstTime)
+		finalScreenTexture = SCRTEX_FINALSCREENTEXTURE;
 	pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
+
+	if (firstTime)
+	{
 #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);
+		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);
+		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);
+		Clamp2D(GL_TEXTURE_WRAP_S);
+		Clamp2D(GL_TEXTURE_WRAP_T);
 #ifndef KOS_GL_COMPATIBILITY
-	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
+		pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
+#endif
+	}
+	else
+#ifndef KOS_GL_COMPATIBILITY
+		pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
 #endif
 
-	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
+	tex_downloaded = finalScreenTexture;
 
 }
 
 EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
 {
 	float xfix, yfix;
+	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;
 
 	if(screen_width <= 1024)
@@ -2427,35 +2535,47 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
 	xfix = 1/((float)(texsize)/((float)((screen_width))));
 	yfix = 1/((float)(texsize)/((float)((screen_height))));
 
-	//pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+	origaspect = (float)screen_width / screen_height;
+	newaspect = (float)width / height;
+	if (origaspect < newaspect)
+	{
+		xoff = origaspect / newaspect;
+		yoff = 1;
+	}
+	else if (origaspect > newaspect)
+	{
+		xoff = 1;
+		yoff = newaspect / origaspect;
+	}
+
 	pglViewport(0, 0, width, height);
 
+	clearColour.red = clearColour.green = clearColour.blue = 0;
+	clearColour.alpha = 1;
+	ClearBuffer(true, false, &clearColour);
 	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);
+		pglVertex3f(-xoff, -yoff, 1.0f);
 
 		// Top left
 		pglTexCoord2f(0.0f, yfix);
-		pglVertex3f(-1, 1, 1.0f);
+		pglVertex3f(-xoff, yoff, 1.0f);
 
 		// Top right
 		pglTexCoord2f(xfix, yfix);
-		pglVertex3f(1, 1, 1.0f);
+		pglVertex3f(xoff, yoff, 1.0f);
 
 		// Bottom right
 		pglTexCoord2f(xfix, 0.0f);
-		pglVertex3f(1, -1, 1.0f);
+		pglVertex3f(xoff, -yoff, 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
+	tex_downloaded = finalScreenTexture;
 }
 
 #endif //HWRENDER
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index 7b22f33f189b5a602ca043862b21ca2e8cc0d678..5356ba8acd40e3a765b9fc7e099f3f849d73c7df 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -78,9 +78,6 @@ extern boolean chat_on;
 // set true whenever the tab rankings are being shown for any reason
 extern boolean hu_showscores;
 
-// P_DeathThink sets this true to show scores while dead, in multiplayer
-extern boolean playerdeadview;
-
 // init heads up data at game startup.
 void HU_Init(void);
 
diff --git a/src/i_sound.h b/src/i_sound.h
index 084479ee1860485b23537983653b067e7b2d0094..2f73017ddd94fdb93e08f69fe9b11cee9977060f 100644
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -18,6 +18,21 @@
 #include "sounds.h"
 #include "command.h"
 
+// copied from SDL mixer, plus GME
+typedef enum {
+	MU_NONE,
+	MU_CMD,
+	MU_WAV,
+	MU_MOD,
+	MU_MID,
+	MU_OGG,
+	MU_MP3,
+	MU_MP3_MAD_UNUSED, // use MU_MP3 instead
+	MU_FLAC,
+	MU_MODPLUG_UNUSED, // use MU_MOD instead
+	MU_GME
+} musictype_t;
+
 /**	\brief Sound subsystem runing and waiting
 */
 extern UINT8 sound_started;
@@ -51,9 +66,9 @@ void I_StartupSound(void);
 */
 void I_ShutdownSound(void);
 
-//
-//  SFX I/O
-//
+/// ------------------------
+///  SFX I/O
+/// ------------------------
 
 /**	\brief	Starts a sound in a particular sound channel.
 	\param	id	sfxid
@@ -64,7 +79,7 @@ void I_ShutdownSound(void);
 
 	\return	sfx handle
 */
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority);
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel);
 
 /**	\brief	Stops a sound channel.
 
@@ -105,9 +120,10 @@ void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch);
 */
 void I_SetSfxVolume(UINT8 volume);
 
-//
-//  MUSIC I/O
-//
+/// ------------------------
+//  MUSIC SYSTEM
+/// ------------------------
+
 /** \brief Init the music systems
 */
 void I_InitMusic(void);
@@ -116,41 +132,23 @@ void I_InitMusic(void);
 */
 void I_ShutdownMusic(void);
 
-/**	\brief	PAUSE game handling.
+/// ------------------------
+//  MUSIC PROPERTIES
+/// ------------------------
 
-	\param	handle	song handle
+musictype_t I_SongType(void);
+boolean I_SongPlaying(void);
+boolean I_SongPaused(void);
 
-	\return	void
-*/
-void I_PauseSong(INT32 handle);
-
-/**	\brief	RESUME game handling
+/// ------------------------
+//  MUSIC EFFECTS
+/// ------------------------
 
-	\param	handle	song handle
-
-	\return	void
-*/
-void I_ResumeSong(INT32 handle);
-
-//
-//  MIDI I/O
-//
-
-/**	\brief Startup the MIDI music system
-*/
-void I_InitMIDIMusic(void);
-
-/**	\brief Shutdown the MIDI music system
-*/
-void I_ShutdownMIDIMusic(void);
-
-/**	\brief	The I_SetMIDIMusicVolume function
-
-	\param	volume	volume to set at
+boolean I_SetSongSpeed(float speed);
 
-	\return	void
-*/
-void I_SetMIDIMusicVolume(UINT8 volume);
+/// ------------------------
+//  MUSIC PLAYBACK
+/// ------------------------
 
 /**	\brief	Registers a song handle to song data.
 
@@ -161,7 +159,16 @@ void I_SetMIDIMusicVolume(UINT8 volume);
 
 	\todo Remove this
 */
-INT32 I_RegisterSong(void *data, size_t len);
+boolean I_LoadSong(char *data, size_t len);
+
+/**	\brief	See ::I_LoadSong, then think backwards
+
+	\param	handle	song handle
+
+	\sa I_LoadSong
+	\todo remove midi handle
+*/
+void I_UnloadSong(void);
 
 /**	\brief	Called by anything that wishes to start music
 
@@ -172,7 +179,7 @@ INT32 I_RegisterSong(void *data, size_t len);
 
 	\todo pass music name, not handle
 */
-boolean I_PlaySong(INT32 handle, boolean looping);
+boolean I_PlaySong(boolean looping);
 
 /**	\brief	Stops a song over 3 seconds
 
@@ -181,58 +188,37 @@ boolean I_PlaySong(INT32 handle, boolean looping);
 
 	/todo drop handle
 */
-void I_StopSong(INT32 handle);
+void I_StopSong(void);
 
-/**	\brief	See ::I_RegisterSong, then think backwards
+/**	\brief	PAUSE game handling.
 
 	\param	handle	song handle
 
-	\sa I_RegisterSong
-	\todo remove midi handle
-*/
-void I_UnRegisterSong(INT32 handle);
-
-//
-//  DIGMUSIC I/O
-//
-
-/**	\brief Startup the music system
-*/
-void I_InitDigMusic(void);
-
-/**	\brief Shutdown the music system
+	\return	void
 */
-void I_ShutdownDigMusic(void);
-
-boolean I_SetSongSpeed(float speed);
-
-boolean I_SetSongTrack(INT32 track);
-
-/**	\brief The I_StartDigSong function
+void I_PauseSong(void);
 
-	\param	musicname	music lump name
-	\param	looping	if true, loop the song
+/**	\brief	RESUME game handling
 
-	\return	if true, song playing
-*/
-boolean I_StartDigSong(const char *musicname, boolean looping);
+	\param	handle	song handle
 
-/**	\brief stop non-MIDI song
+	\return	void
 */
-void I_StopDigSong(void);
+void I_ResumeSong(void);
 
-/**	\brief The I_SetDigMusicVolume function
+/**	\brief	The I_SetMusicVolume function
 
 	\param	volume	volume to set at
 
 	\return	void
 */
-void I_SetDigMusicVolume(UINT8 volume);
+void I_SetMusicVolume(UINT8 volume);
 
-//
-// CD MUSIC I/O
-//
+boolean I_SetSongTrack(INT32 track);
 
+/// ------------------------
+//  CD MUSIC I/O
+/// ------------------------
 
 /**	\brief  cd music interface
 */
@@ -279,4 +265,4 @@ void I_PlayCD(UINT8 track, UINT8 looping);
 */
 boolean I_SetVolumeCD(INT32 volume);
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c
index 566e73748e1baf088aa212e6ae7ebefc423500de..3239b7c5ea4016296b48c921bb893d1e82e4c86d 100644
--- a/src/lua_consolelib.c
+++ b/src/lua_consolelib.c
@@ -77,7 +77,9 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum)
 
 deny:
 	//must be hacked/buggy client
-	lua_settop(gL, 0); // clear stack
+	if (gL) // check if Lua is actually turned on first, you dummmy -- Monster Iestyn 04/07/18
+		lua_settop(gL, 0); // clear stack
+
 	CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]);
 	if (server)
 	{
diff --git a/src/lua_script.c b/src/lua_script.c
index ce96878bfb25592b7b9c968b428d3e98b2e36470..9b87f0c297865176a8c9fb66cc95d22102080a96 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -182,19 +182,21 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump)
 {
 	MYFILE f;
 	char *name;
+	size_t len;
 	f.wad = wad;
 	f.size = W_LumpLengthPwad(wad, lump);
 	f.data = Z_Malloc(f.size, PU_LUA, NULL);
 	W_ReadLumpPwad(wad, lump, f.data);
 	f.curpos = f.data;
 
-	name = malloc(strlen(wadfiles[wad]->filename)+10);
+	len = strlen(wadfiles[wad]->filename);
+	name = malloc(len+10);
 	strcpy(name, wadfiles[wad]->filename);
-	if (!fasticmp(&name[strlen(name) - 4], ".lua")) {
+	if (!fasticmp(&name[len - 4], ".lua")) {
 		// If it's not a .lua file, copy the lump name in too.
-		name[strlen(wadfiles[wad]->filename)] = '|';
-		M_Memcpy(name+strlen(wadfiles[wad]->filename)+1, wadfiles[wad]->lumpinfo[lump].name, 8);
-		name[strlen(wadfiles[wad]->filename)+9] = '\0';
+		name[len] = '|';
+		M_Memcpy(name+len+1, wadfiles[wad]->lumpinfo[lump].name, 8);
+		name[len+9] = '\0';
 	}
 
 	LUA_LoadFile(&f, name);
@@ -851,7 +853,7 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
 		LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR);
 		break;
 	case ARCH_MAPHEADER:
-		LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_MAPHEADER);
+		LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER);
 		break;
 	case ARCH_TEND:
 		return 1;
diff --git a/src/m_anigif.c b/src/m_anigif.c
index 2540665ad57e8f901f315238ad74d9c352e01878..e2af700953deabdde06e0419afaa81409c7afdf6 100644
--- a/src/m_anigif.c
+++ b/src/m_anigif.c
@@ -492,7 +492,9 @@ static void GIF_framewrite(void)
 
 	// screen regions are handled in GIF_lzw
 	{
-		UINT16 delay = 3; // todo
+		int d1 = (int)((100.0/NEWTICRATE)*(gif_frames+1));
+		int d2 = (int)((100.0/NEWTICRATE)*(gif_frames));
+		UINT16 delay = d1-d2;
 		INT32 startline;
 
 		WRITEMEM(p, gifframe_gchead, 4);
diff --git a/src/m_fixed.c b/src/m_fixed.c
index ce7471a28dac8cbd57aa96c58ed74d04fc00ded3..014457386030740900f05ebd5048a37e522ddddf 100644
--- a/src/m_fixed.c
+++ b/src/m_fixed.c
@@ -33,7 +33,9 @@
 */
 fixed_t FixedMul(fixed_t a, fixed_t b)
 {
-	return (fixed_t)((((INT64)a * b) ) / FRACUNIT);
+	// Need to cast to unsigned before shifting to avoid undefined behaviour
+	// for negative integers
+	return (fixed_t)(((UINT64)((INT64)a * b)) >> FRACBITS);
 }
 
 #endif //__USE_C_FIXEDMUL__
diff --git a/src/m_menu.c b/src/m_menu.c
index ea93d1e2dfea8cae98ac891d134f38816e60b489..c9adbfb9c94646c43671f1e78a4a838c283e87d0 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -6295,6 +6295,13 @@ static void M_DrawConnectIPMenu(void)
 static void M_ConnectIP(INT32 choice)
 {
 	(void)choice;
+
+	if (*setupm_ip == 0)
+	{
+		M_StartMessage("You must specify an IP address.\n", NULL, MM_NOTHING);
+		return;
+	}
+
 	COM_BufAddText(va("connect \"%s\"\n", setupm_ip));
 
 	// A little "please wait" message.
@@ -6536,7 +6543,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
 			if (choice < 32 || choice > 127 || itemOn != 0)
 				break;
 			l = strlen(setupm_name);
-			if (l < MAXPLAYERNAME-1)
+			if (l < MAXPLAYERNAME)
 			{
 				S_StartSound(NULL,sfx_menu1); // Tails
 				setupm_name[l] =(char)choice;
@@ -6943,82 +6950,95 @@ static void M_ChangeControl(INT32 choice)
 // Toggles sound systems in-game.
 static void M_ToggleSFX(void)
 {
-	if (nosound)
+	if (sound_disabled)
 	{
-		nosound = false;
-		I_StartupSound();
-		if (nosound) return;
-		S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value);
+		sound_disabled = false;
+		S_InitSfxChannels(cv_soundvolume.value);
+		S_StartSound(NULL, sfx_strpst);
 		M_StartMessage(M_GetText("SFX Enabled\n"), NULL, MM_NOTHING);
 	}
 	else
 	{
-		if (sound_disabled)
-		{
-			sound_disabled = false;
-			M_StartMessage(M_GetText("SFX Enabled\n"), NULL, MM_NOTHING);
-		}
-		else
-		{
-			sound_disabled = true;
-			S_StopSounds();
-			M_StartMessage(M_GetText("SFX Disabled\n"), NULL, MM_NOTHING);
-		}
+		sound_disabled = true;
+		S_StopSounds();
+		M_StartMessage(M_GetText("SFX Disabled\n"), NULL, MM_NOTHING);
 	}
 }
 
 static void M_ToggleDigital(void)
 {
-	if (nodigimusic)
+	if (digital_disabled)
 	{
-		nodigimusic = false;
-		I_InitDigMusic();
-		if (nodigimusic) return;
-		S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value);
+		digital_disabled = false;
+		I_InitMusic();
 		S_StopMusic();
-		S_ChangeMusicInternal("lclear", false);
+		if (Playing())
+			P_RestoreMusic(&players[consoleplayer]);
+		else
+			S_ChangeMusicInternal("lclear", false);
 		M_StartMessage(M_GetText("Digital Music Enabled\n"), NULL, MM_NOTHING);
 	}
 	else
 	{
-		if (digital_disabled)
-		{
-			digital_disabled = false;
-			M_StartMessage(M_GetText("Digital Music Enabled\n"), NULL, MM_NOTHING);
-		}
-		else
+		digital_disabled = true;
+		if (S_MusicType() != MU_MID)
 		{
-			digital_disabled = true;
-			S_StopMusic();
-			M_StartMessage(M_GetText("Digital Music Disabled\n"), NULL, MM_NOTHING);
+			if (midi_disabled)
+				S_StopMusic();
+			else
+			{
+				char mmusic[7];
+				UINT16 mflags;
+				boolean looping;
+
+				if (S_MusicInfo(mmusic, &mflags, &looping) && S_MIDIExists(mmusic))
+				{
+					S_StopMusic();
+					S_ChangeMusic(mmusic, mflags, looping);
+				}
+				else
+					S_StopMusic();
+			}
 		}
+		M_StartMessage(M_GetText("Digital Music Disabled\n"), NULL, MM_NOTHING);
 	}
 }
 
 static void M_ToggleMIDI(void)
 {
-	if (nomidimusic)
+	if (midi_disabled)
 	{
-		nomidimusic = false;
-		I_InitMIDIMusic();
-		if (nomidimusic) return;
-		S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value);
-		S_ChangeMusicInternal("lclear", false);
+		midi_disabled = false;
+		I_InitMusic();
+		if (Playing())
+			P_RestoreMusic(&players[consoleplayer]);
+		else
+			S_ChangeMusicInternal("lclear", false);
 		M_StartMessage(M_GetText("MIDI Music Enabled\n"), NULL, MM_NOTHING);
 	}
 	else
 	{
-		if (music_disabled)
-		{
-			music_disabled = false;
-			M_StartMessage(M_GetText("MIDI Music Enabled\n"), NULL, MM_NOTHING);
-		}
-		else
+		midi_disabled = true;
+		if (S_MusicType() == MU_MID)
 		{
-			music_disabled = true;
-			S_StopMusic();
-			M_StartMessage(M_GetText("MIDI Music Disabled\n"), NULL, MM_NOTHING);
+			if (digital_disabled)
+				S_StopMusic();
+			else
+			{
+				char mmusic[7];
+				UINT16 mflags;
+				boolean looping;
+
+				if (S_MusicInfo(mmusic, &mflags, &looping) && S_DigExists(mmusic))
+				{
+					S_StopMusic();
+					S_ChangeMusic(mmusic, mflags, looping);
+				}
+				else
+					S_StopMusic();
+			}
 		}
+		M_StartMessage(M_GetText("MIDI Music Disabled\n"), NULL, MM_NOTHING);
 	}
 }
 
diff --git a/src/m_misc.c b/src/m_misc.c
index 041899a3b77060ac6868494a11f3a25a39748376..5c4e7f2f943c0e0e33d1d147d66c5d4659430e8b 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -56,7 +56,9 @@ typedef off_t off64_t;
 #endif
 #endif
 
-#if defined (_WIN32)
+#if defined(__MINGW32__) && ((__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3))
+#define PRIdS "u"
+#elif defined (_WIN32) 
 #define PRIdS "Iu"
 #elif defined (_PSP) || defined (_arch_dreamcast) || defined (DJGPP) || defined (_WII) || defined (_NDS) || defined (_PS3)
 #define PRIdS "u"
diff --git a/src/nds/i_sound.c b/src/nds/i_sound.c
index 8dea4ad7d494ae78eba6eeefd9a6e0a3e5109184..a17c7f66a24a746e68e78147dc943fd0892c093b 100644
--- a/src/nds/i_sound.c
+++ b/src/nds/i_sound.c
@@ -21,13 +21,14 @@ void I_ShutdownSound(void){}
 //  SFX I/O
 //
 
-INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority)
+INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority, INT32 channel)
 {
 	(void)id;
 	(void)vol;
 	(void)sep;
 	(void)pitch;
 	(void)priority;
+	(void)channel;
 	return -1;
 }
 
diff --git a/src/p_local.h b/src/p_local.h
index 1fd7ada04219b928fe1619e2398fb4fef5ba500a..b82bcf0ecfab5c930b7416d6ed92ddca8fe7516a 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -68,7 +68,6 @@
 
 // both the head and tail of the thinker list
 extern thinker_t thinkercap;
-extern INT32 runcount;
 
 void P_InitThinkers(void);
 void P_AddThinker(thinker_t *thinker);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 5f85474c65f25a9b50479ecfbe7fff0b4975bb72..2a29c32ad104ba7644431fea3445d3c21451659a 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -3840,7 +3840,8 @@ void P_RecalcPrecipInSector(sector_t *sector)
 //
 void P_NullPrecipThinker(precipmobj_t *mobj)
 {
-	(void)mobj;
+	//(void)mobj;
+	mobj->precipflags &= ~PCF_THUNK;
 }
 
 void P_SnowThinker(precipmobj_t *mobj)
@@ -3860,25 +3861,26 @@ void P_RainThinker(precipmobj_t *mobj)
 	{
 		// cycle through states,
 		// calling action functions at transitions
-		if (mobj->tics > 0 && --mobj->tics == 0)
-		{
-			// you can cycle through multiple states in a tic
-			if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate))
-				return; // freed itself
-		}
+		if (mobj->tics <= 0)
+			return;
+
+		if (--mobj->tics)
+			return;
+
+		if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate))
+			return;
+
+		if (mobj->state != &states[S_RAINRETURN])
+			return;
+
+		mobj->z = mobj->ceilingz;
+		P_SetPrecipMobjState(mobj, S_RAIN1);
 
-		if (mobj->state == &states[S_RAINRETURN])
-		{
-			mobj->z = mobj->ceilingz;
-			P_SetPrecipMobjState(mobj, S_RAIN1);
-		}
 		return;
 	}
 
 	// adjust height
-	mobj->z += mobj->momz;
-
-	if (mobj->z <= mobj->floorz)
+	if ((mobj->z += mobj->momz) <= mobj->floorz)
 	{
 		// no splashes on sky or bottomless pits
 		if (mobj->precipflags & PCF_PIT)
@@ -7926,14 +7928,15 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
 static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 {
 	precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type);
-	mo->thinker.function.acp1 = (actionf_p1)P_RainThinker;
+	mo->precipflags |= PCF_RAIN;
+	//mo->thinker.function.acp1 = (actionf_p1)P_RainThinker;
 	return mo;
 }
 
 static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 {
 	precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type);
-	mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker;
+	//mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker;
 	return mo;
 }
 
@@ -8228,7 +8231,7 @@ void P_PrecipitationEffects(void)
 	if (!playeringame[displayplayer] || !players[displayplayer].mo)
 		return;
 
-	if (nosound || sound_disabled)
+	if (sound_disabled)
 		return; // Sound off? D'aw, no fun.
 
 	if (players[displayplayer].mo->subsector->sector->ceilingpic == skyflatnum)
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 79cffae894651ef5a0d31f1583b24d748f8f8b14..620028d81a89ad43df4f00e1d12aa09d12576a1a 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -252,6 +252,10 @@ typedef enum {
 	PCF_FOF = 4,
 	// Above MOVING FOF (this means we need to keep floorz up to date...)
 	PCF_MOVINGFOF = 8,
+	// Is rain.
+	PCF_RAIN = 16,
+	// Ran the thinker this tic.
+	PCF_THUNK = 32,
 } precipflag_t;
 // Map Object definition.
 typedef struct mobj_s
diff --git a/src/p_saveg.c b/src/p_saveg.c
index d1ec8e5abfc5aad9cc973265e709723489b2a2c0..17d28302ee71cc841d055f91a675ceb92349c89d 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1661,8 +1661,7 @@ static void P_NetArchiveThinkers(void)
 	for (th = thinkercap.next; th != &thinkercap; th = th->next)
 	{
 		if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed
-		 || th->function.acp1 == (actionf_p1)P_RainThinker
-		 || th->function.acp1 == (actionf_p1)P_SnowThinker))
+		 || th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
 			numsaved++;
 
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
@@ -1671,8 +1670,7 @@ static void P_NetArchiveThinkers(void)
 			continue;
 		}
 #ifdef PARANOIA
-		else if (th->function.acp1 == (actionf_p1)P_RainThinker
-			|| th->function.acp1 == (actionf_p1)P_SnowThinker);
+		else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker);
 #endif
 		else if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
 		{
diff --git a/src/p_setup.c b/src/p_setup.c
index 8e746457be9216e8fec73e43bc2dbc24a0d5ea6e..17a6797f4c77f5d37b2f54c29f1edcac1b2a8ffb 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2503,11 +2503,6 @@ boolean P_SetupLevel(boolean skipprecip)
 
 
 	// Reset the palette
-#ifdef HWRENDER
-	if (rendermode == render_opengl)
-		HWR_SetPaletteColor(0);
-	else
-#endif
 	if (rendermode != render_none)
 		V_SetPaletteLump("PLAYPAL");
 
@@ -2565,6 +2560,7 @@ boolean P_SetupLevel(boolean skipprecip)
 	{
 		tic_t starttime = I_GetTime();
 		tic_t endtime = starttime + (3*TICRATE)/2;
+		tic_t nowtime;
 
 		S_StartSound(NULL, sfx_s3kaf);
 
@@ -2574,9 +2570,17 @@ boolean P_SetupLevel(boolean skipprecip)
 		F_WipeEndScreen();
 		F_RunWipe(wipedefs[wipe_speclevel_towhite], false);
 
+		nowtime = lastwipetic;
 		// Hold on white for extra effect.
-		while (I_GetTime() < endtime)
-			I_Sleep();
+		while (nowtime < endtime)
+		{
+			// wait loop
+			while (!((nowtime = I_GetTime()) - lastwipetic))
+				I_Sleep();
+			lastwipetic = nowtime;
+			if (moviemode) // make sure we save frames for the white hold too
+				M_SaveFrame();
+		}
 
 		ranspecialwipe = 1;
 	}
@@ -2669,7 +2673,6 @@ boolean P_SetupLevel(boolean skipprecip)
 		P_CreateBlockMap(); // Graue 02-29-2004
 	P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS);
 
-	R_MakeColormaps();
 	P_LoadLineDefs2();
 	P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
 	P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
@@ -2994,7 +2997,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
 
 	if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX)
 	{
-		CONS_Printf(M_GetText("Errors occured while loading %s; not added.\n"), wadfilename);
+		CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename);
 		return false;
 	}
 	else wadnum = (UINT16)(numwadfiles-1);
diff --git a/src/p_spec.c b/src/p_spec.c
index c62c3b209579e423e309b48e23982e07486c21f7..ff6691a994193b307fd27cbd70425a9085fc9aa5 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -2039,8 +2039,7 @@ void P_SwitchWeather(INT32 weathernum)
 
 		for (think = thinkercap.next; think != &thinkercap; think = think->next)
 		{
-			if ((think->function.acp1 != (actionf_p1)P_SnowThinker)
-				&& (think->function.acp1 != (actionf_p1)P_RainThinker))
+			if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
 				continue; // not a precipmobj thinker
 
 			precipmobj = (precipmobj_t *)think;
@@ -2056,14 +2055,12 @@ void P_SwitchWeather(INT32 weathernum)
 
 		for (think = thinkercap.next; think != &thinkercap; think = think->next)
 		{
+			if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
+				continue; // not a precipmobj thinker
+			precipmobj = (precipmobj_t *)think;
+
 			if (swap == PRECIP_RAIN) // Snow To Rain
 			{
-				if (!(think->function.acp1 == (actionf_p1)P_SnowThinker
-					|| think->function.acp1 == (actionf_p1)P_NullPrecipThinker))
-					continue; // not a precipmobj thinker
-
-				precipmobj = (precipmobj_t *)think;
-
 				precipmobj->flags = mobjinfo[MT_RAIN].flags;
 				st = &states[mobjinfo[MT_RAIN].spawnstate];
 				precipmobj->state = st;
@@ -2074,18 +2071,13 @@ void P_SwitchWeather(INT32 weathernum)
 
 				precipmobj->precipflags &= ~PCF_INVISIBLE;
 
-				think->function.acp1 = (actionf_p1)P_RainThinker;
+				precipmobj->precipflags |= PCF_RAIN;
+				//think->function.acp1 = (actionf_p1)P_RainThinker;
 			}
 			else if (swap == PRECIP_SNOW) // Rain To Snow
 			{
 				INT32 z;
 
-				if (!(think->function.acp1 == (actionf_p1)P_RainThinker
-					|| think->function.acp1 == (actionf_p1)P_NullPrecipThinker))
-					continue; // not a precipmobj thinker
-
-				precipmobj = (precipmobj_t *)think;
-
 				precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags;
 				z = M_RandomByte();
 
@@ -2103,19 +2095,13 @@ void P_SwitchWeather(INT32 weathernum)
 				precipmobj->frame = st->frame;
 				precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed;
 
-				precipmobj->precipflags &= ~PCF_INVISIBLE;
+				precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_RAIN);
 
-				think->function.acp1 = (actionf_p1)P_SnowThinker;
+				//think->function.acp1 = (actionf_p1)P_SnowThinker;
 			}
 			else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse.
 			{
-				if (!(think->function.acp1 == (actionf_p1)P_RainThinker
-					|| think->function.acp1 == (actionf_p1)P_SnowThinker))
-					continue;
-
-				precipmobj = (precipmobj_t *)think;
-
-				think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
+				//think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
 
 				precipmobj->precipflags |= PCF_INVISIBLE;
 			}
diff --git a/src/p_tick.c b/src/p_tick.c
index f4bc59323ff19dd9eef671c88900c1f1299d70fc..5ba747078bb30231690820e27c13159d3b6647cf 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -56,12 +56,12 @@ void Command_Numthinkers_f(void)
 		CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n"));
 		CONS_Printf(
 			"\t1: P_MobjThinker\n"
-			"\t2: P_RainThinker\n"
-			"\t3: P_SnowThinker\n"
-			"\t4: P_NullPrecipThinker\n"
-			"\t5: T_Friction\n"
-			"\t6: T_Pusher\n"
-			"\t7: P_RemoveThinkerDelayed\n");
+			/*"\t2: P_RainThinker\n"
+			"\t3: P_SnowThinker\n"*/
+			"\t2: P_NullPrecipThinker\n"
+			"\t3: T_Friction\n"
+			"\t4: T_Pusher\n"
+			"\t5: P_RemoveThinkerDelayed\n");
 		return;
 	}
 
@@ -73,27 +73,27 @@ void Command_Numthinkers_f(void)
 			action = (actionf_p1)P_MobjThinker;
 			CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
 			break;
-		case 2:
+		/*case 2:
 			action = (actionf_p1)P_RainThinker;
 			CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker");
 			break;
 		case 3:
 			action = (actionf_p1)P_SnowThinker;
 			CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
-			break;
-		case 4:
+			break;*/
+		case 2:
 			action = (actionf_p1)P_NullPrecipThinker;
 			CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");
 			break;
-		case 5:
+		case 3:
 			action = (actionf_p1)T_Friction;
 			CONS_Printf(M_GetText("Number of %s: "), "T_Friction");
 			break;
-		case 6:
+		case 4:
 			action = (actionf_p1)T_Pusher;
 			CONS_Printf(M_GetText("Number of %s: "), "T_Pusher");
 			break;
-		case 7:
+		case 5:
 			action = (actionf_p1)P_RemoveThinkerDelayed;
 			CONS_Printf(M_GetText("Number of %s: "), "P_RemoveThinkerDelayed");
 			break;
diff --git a/src/p_user.c b/src/p_user.c
index 7abf8534756db744e43c7c3cf9daba07bc98e626..7e206930d2775b4ebdb65c5d515525bbc99aae1c 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -8648,8 +8648,6 @@ void P_DoPityCheck(player_t *player)
 // P_PlayerThink
 //
 
-boolean playerdeadview; // show match/chaos/tag/capture the flag rankings while in death view
-
 void P_PlayerThink(player_t *player)
 {
 	ticcmd_t *cmd;
@@ -8838,10 +8836,6 @@ void P_PlayerThink(player_t *player)
 	if (player->playerstate == PST_DEAD)
 	{
 		player->mo->flags2 &= ~MF2_SHADOW;
-		// show the multiplayer rankings while dead
-		if (player == &players[displayplayer])
-			playerdeadview = true;
-
 		P_DeathThink(player);
 
 		return;
@@ -8862,9 +8856,6 @@ void P_PlayerThink(player_t *player)
 		player->lives = cv_startinglives.value;
 	}
 
-	if (player == &players[displayplayer])
-		playerdeadview = false;
-
 	if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)
 	{
 		cmd->buttons &= BT_USE; // Remove all buttons except BT_USE
diff --git a/src/r_data.c b/src/r_data.c
index d19882dd395379abe81fe5e3924193cb4b2d3811..f2c9b1466b0a0961611c69e3cb0d0222ae4b307c 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1038,9 +1038,6 @@ void R_ReInitColormaps(UINT16 num)
 
 static lumpnum_t foundcolormaps[MAXCOLORMAPS];
 
-static char colormapFixingArray[MAXCOLORMAPS][3][9];
-static size_t carrayindex;
-
 //
 // R_ClearColormaps
 //
@@ -1052,8 +1049,6 @@ void R_ClearColormaps(void)
 
 	num_extra_colormaps = 0;
 
-	carrayindex = 0;
-
 	for (i = 0; i < MAXCOLORMAPS; i++)
 		foundcolormaps[i] = LUMPERROR;
 
@@ -1087,7 +1082,7 @@ INT32 R_ColormapNumForName(char *name)
 	extra_colormaps[num_extra_colormaps].fadecolor = 0x0;
 	extra_colormaps[num_extra_colormaps].maskamt = 0x0;
 	extra_colormaps[num_extra_colormaps].fadestart = 0;
-	extra_colormaps[num_extra_colormaps].fadeend = 33;
+	extra_colormaps[num_extra_colormaps].fadeend = 31;
 	extra_colormaps[num_extra_colormaps].fog = 0;
 
 	num_extra_colormaps++;
@@ -1110,12 +1105,12 @@ static int RoundUp(double number);
 INT32 R_CreateColormap(char *p1, char *p2, char *p3)
 {
 	double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb;
-	double r, g, b, cbrightness, maskamt = 0, othermask = 0;
+	double maskamt = 0, othermask = 0;
 	int mask, fog = 0;
 	size_t mapnum = num_extra_colormaps;
 	size_t i;
 	UINT32 cr, cg, cb, maskcolor, fadecolor;
-	UINT32 fadestart = 0, fadeend = 33, fadedist = 33;
+	UINT32 fadestart = 0, fadeend = 31, fadedist = 31;
 
 #define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0)
 	if (p1[0] == '#')
@@ -1156,14 +1151,14 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3)
 		// Get parameters like fadestart, fadeend, and the fogflag
 		fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10);
 		fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10);
-		if (fadestart > 32)
+		if (fadestart > 30)
 			fadestart = 0;
-		if (fadeend > 33 || fadeend < 1)
-			fadeend = 33;
+		if (fadeend > 31 || fadeend < 1)
+			fadeend = 31;
 		fadedist = fadeend - fadestart;
-		fog = NUMFROMCHAR(p2[1]) ? 1 : 0;
+		fog = NUMFROMCHAR(p2[1]);
 	}
-#undef getnum
+#undef NUMFROMCHAR
 
 	if (p3[0] == '#')
 	{
@@ -1194,38 +1189,8 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3)
 	if (num_extra_colormaps == MAXCOLORMAPS)
 		I_Error("R_CreateColormap: Too many colormaps! the limit is %d\n", MAXCOLORMAPS);
 
-	strncpy(colormapFixingArray[num_extra_colormaps][0], p1, 8);
-	strncpy(colormapFixingArray[num_extra_colormaps][1], p2, 8);
-	strncpy(colormapFixingArray[num_extra_colormaps][2], p3, 8);
-
 	num_extra_colormaps++;
 
-	if (rendermode == render_soft)
-	{
-		for (i = 0; i < 256; i++)
-		{
-			r = pLocalPalette[i].s.red;
-			g = pLocalPalette[i].s.green;
-			b = pLocalPalette[i].s.blue;
-			cbrightness = sqrt((r*r) + (g*g) + (b*b));
-
-			map[i][0] = (cbrightness * cmaskr) + (r * othermask);
-			if (map[i][0] > 255.0l)
-				map[i][0] = 255.0l;
-			deltas[i][0] = (map[i][0] - cdestr) / (double)fadedist;
-
-			map[i][1] = (cbrightness * cmaskg) + (g * othermask);
-			if (map[i][1] > 255.0l)
-				map[i][1] = 255.0l;
-			deltas[i][1] = (map[i][1] - cdestg) / (double)fadedist;
-
-			map[i][2] = (cbrightness * cmaskb) + (b * othermask);
-			if (map[i][2] > 255.0l)
-				map[i][2] = 255.0l;
-			deltas[i][2] = (map[i][2] - cdestb) / (double)fadedist;
-		}
-	}
-
 	foundcolormaps[mapnum] = LUMPERROR;
 
 	// aligned on 8 bit for asm code
@@ -1237,114 +1202,18 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3)
 	extra_colormaps[mapnum].fadeend = (UINT16)fadeend;
 	extra_colormaps[mapnum].fog = fog;
 
-	return (INT32)mapnum;
-}
-
-void R_MakeColormaps(void)
-{
-	size_t i;
-
-	carrayindex = num_extra_colormaps;
-	num_extra_colormaps = 0;
-
-	for (i = 0; i < carrayindex; i++)
-		R_CreateColormap2(colormapFixingArray[i][0], colormapFixingArray[i][1],
-			colormapFixingArray[i][2]);
-}
-
-void R_CreateColormap2(char *p1, char *p2, char *p3)
-{
-	double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb;
-	double r, g, b, cbrightness;
-	double maskamt = 0, othermask = 0;
-	int mask, p, fog = 0;
-	size_t mapnum = num_extra_colormaps;
-	size_t i;
-	char *colormap_p;
-	UINT32 cr, cg, cb, maskcolor, fadecolor;
-	UINT32 fadestart = 0, fadeend = 33, fadedist = 33;
-
-#define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0)
-	if (p1[0] == '#')
-	{
-		cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2]));
-		cmaskr = cr;
-		cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4]));
-		cmaskg = cg;
-		cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6]));
-		cmaskb = cb;
-		// Create a rough approximation of the color (a 16 bit color)
-		maskcolor = ((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11);
-		if (p1[7] >= 'a' && p1[7] <= 'z')
-			mask = (p1[7] - 'a');
-		else if (p1[7] >= 'A' && p1[7] <= 'Z')
-			mask = (p1[7] - 'A');
-		else
-			mask = 24;
-
-		maskamt = (double)(mask/24.0l);
-
-		othermask = 1 - maskamt;
-		maskamt /= 0xff;
-		cmaskr *= maskamt;
-		cmaskg *= maskamt;
-		cmaskb *= maskamt;
-	}
-	else
-	{
-		cmaskr = cmaskg = cmaskb = 0xff;
-		maskamt = 0;
-		maskcolor = ((0xff) >> 3) + (((0xff) >> 2) << 5) + (((0xff) >> 3) << 11);
-	}
-
-#define NUMFROMCHAR(c) (c >= '0' && c <= '9' ? c - '0' : 0)
-	if (p2[0] == '#')
-	{
-		// Get parameters like fadestart, fadeend, and the fogflag
-		fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10);
-		fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10);
-		if (fadestart > 32)
-			fadestart = 0;
-		if (fadeend > 33 || fadeend < 1)
-			fadeend = 33;
-		fadedist = fadeend - fadestart;
-		fog = NUMFROMCHAR(p2[1]) ? 1 : 0;
-	}
-#undef getnum
-
-	if (p3[0] == '#')
-	{
-		cdestr = cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2]));
-		cdestg = cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4]));
-		cdestb = cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6]));
-		fadecolor = (((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11));
-	}
-	else
-		cdestr = cdestg = cdestb = fadecolor = 0;
-#undef HEX2INT
-
-	for (i = 0; i < num_extra_colormaps; i++)
-	{
-		if (foundcolormaps[i] != LUMPERROR)
-			continue;
-		if (maskcolor == extra_colormaps[i].maskcolor
-			&& fadecolor == extra_colormaps[i].fadecolor
-			&& (float)maskamt == (float)extra_colormaps[i].maskamt
-			&& fadestart == extra_colormaps[i].fadestart
-			&& fadeend == extra_colormaps[i].fadeend
-			&& fog == extra_colormaps[i].fog)
-		{
-			return;
-		}
-	}
-
-	if (num_extra_colormaps == MAXCOLORMAPS)
-		I_Error("R_CreateColormap: Too many colormaps! the limit is %d\n", MAXCOLORMAPS);
-
-	num_extra_colormaps++;
-
+	// This code creates the colormap array used by software renderer
 	if (rendermode == render_soft)
 	{
+		double r, g, b, cbrightness;
+		int p;
+		char *colormap_p;
+
+		// Initialise the map and delta arrays
+		// map[i] stores an RGB color (as double) for index i,
+		//  which is then converted to SRB2's palette later
+		// deltas[i] stores a corresponding fade delta between the RGB color and the final fade color;
+		//  map[i]'s values are decremented by after each use
 		for (i = 0; i < 256; i++)
 		{
 			r = pLocalPalette[i].s.red;
@@ -1367,25 +1236,13 @@ void R_CreateColormap2(char *p1, char *p2, char *p3)
 				map[i][2] = 255.0l;
 			deltas[i][2] = (map[i][2] - cdestb) / (double)fadedist;
 		}
-	}
-
-	foundcolormaps[mapnum] = LUMPERROR;
 
-	// aligned on 8 bit for asm code
-	extra_colormaps[mapnum].colormap = NULL;
-	extra_colormaps[mapnum].maskcolor = (UINT16)maskcolor;
-	extra_colormaps[mapnum].fadecolor = (UINT16)fadecolor;
-	extra_colormaps[mapnum].maskamt = maskamt;
-	extra_colormaps[mapnum].fadestart = (UINT16)fadestart;
-	extra_colormaps[mapnum].fadeend = (UINT16)fadeend;
-	extra_colormaps[mapnum].fog = fog;
-
-#define ABS2(x) ((x) < 0 ? -(x) : (x))
-	if (rendermode == render_soft)
-	{
+		// Now allocate memory for the actual colormap array itself!
 		colormap_p = Z_MallocAlign((256 * 34) + 10, PU_LEVEL, NULL, 8);
 		extra_colormaps[mapnum].colormap = (UINT8 *)colormap_p;
 
+		// Calculate the palette index for each palette index, for each light level
+		// (as well as the two unused colormap lines we inherited from Doom)
 		for (p = 0; p < 34; p++)
 		{
 			for (i = 0; i < 256; i++)
@@ -1397,7 +1254,7 @@ void R_CreateColormap2(char *p1, char *p2, char *p3)
 
 				if ((UINT32)p < fadestart)
 					continue;
-
+#define ABS2(x) ((x) < 0 ? -(x) : (x))
 				if (ABS2(map[i][0] - cdestr) > ABS2(deltas[i][0]))
 					map[i][0] -= deltas[i][0];
 				else
@@ -1412,12 +1269,12 @@ void R_CreateColormap2(char *p1, char *p2, char *p3)
 					map[i][2] -= deltas[i][2];
 				else
 					map[i][2] = cdestb;
+#undef ABS2
 			}
 		}
 	}
-#undef ABS2
 
-	return;
+	return (INT32)mapnum;
 }
 
 // Thanks to quake2 source!
diff --git a/src/r_data.h b/src/r_data.h
index 1e9e0eb5edce620cfa9b4bd3a9123bc18f95c231..a656e5db7351137041f85c107c9826b4938b347d 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -93,8 +93,6 @@ void R_ReInitColormaps(UINT16 num);
 void R_ClearColormaps(void);
 INT32 R_ColormapNumForName(char *name);
 INT32 R_CreateColormap(char *p1, char *p2, char *p3);
-void R_CreateColormap2(char *p1, char *p2, char *p3);
-void R_MakeColormaps(void);
 const char *R_ColormapNameForNum(INT32 num);
 
 extern INT32 numtextures;
diff --git a/src/r_draw8.c b/src/r_draw8.c
index 39585f58798dcd6ebd39cdd87d07f1acb90247a6..800f28b6be69ca7ad84d4cd0d083089b1ac936e3 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -297,7 +297,7 @@ void R_DrawTranslucentColumn_8(void)
 				// Re-map color indices from wall texture column
 				// using a lighting/special effects LUT.
 				// heightmask is the Tutti-Frutti fix
-				*dest = colormap[*(transmap + (source[frac>>FRACBITS]<<8) + (*dest))];
+				*dest = *(transmap + (colormap[source[frac>>FRACBITS]]<<8) + (*dest));
 				dest += vid.width;
 				if ((frac += fracstep) >= heightmask)
 					frac -= heightmask;
@@ -308,15 +308,15 @@ void R_DrawTranslucentColumn_8(void)
 		{
 			while ((count -= 2) >= 0) // texture height is a power of 2
 			{
-				*dest = colormap[*(transmap + ((source[(frac>>FRACBITS)&heightmask]<<8)) + (*dest))];
+				*dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest));
 				dest += vid.width;
 				frac += fracstep;
-				*dest = colormap[*(transmap + ((source[(frac>>FRACBITS)&heightmask]<<8)) + (*dest))];
+				*dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest));
 				dest += vid.width;
 				frac += fracstep;
 			}
 			if (count & 1)
-				*dest = colormap[*(transmap + ((source[(frac>>FRACBITS)&heightmask]<<8)) + (*dest))];
+				*dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest));
 		}
 	}
 }
@@ -367,8 +367,7 @@ void R_DrawTranslatedTranslucentColumn_8(void)
 				//  using a lighting/special effects LUT.
 				// heightmask is the Tutti-Frutti fix
 
-				*dest = dc_colormap[*(dc_transmap
-					+ (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest))];
+				*dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest));
 
 				dest += vid.width;
 				if ((frac += fracstep) >= heightmask)
@@ -380,17 +379,15 @@ void R_DrawTranslatedTranslucentColumn_8(void)
 		{
 			while ((count -= 2) >= 0) // texture height is a power of 2
 			{
-				*dest = dc_colormap[*(dc_transmap
-					+ (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest))];
+				*dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest));
 				dest += vid.width;
 				frac += fracstep;
-				*dest = dc_colormap[*(dc_transmap
-					+ (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest))];
+				*dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest));
 				dest += vid.width;
 				frac += fracstep;
 			}
 			if (count & 1)
-				*dest = dc_colormap[*(dc_transmap + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]] <<8) + (*dest))];
+				*dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest));
 		}
 	}
 }
@@ -738,8 +735,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 		v = (INT64)(vz*z) + viewy;
 
 		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-
-		*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+		*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 		dest++;
 		iz += ds_sz.x;
 		uz += ds_su.x;
@@ -776,7 +772,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 		for (i = SPANSIZE-1; i >= 0; i--)
 		{
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 			dest++;
 			u += stepu;
 			v += stepv;
@@ -792,7 +788,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 			u = (INT64)(startu);
 			v = (INT64)(startv);
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 		}
 		else
 		{
@@ -813,7 +809,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 			for (; width != 0; width--)
 			{
 				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-				*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+				*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 				dest++;
 				u += stepu;
 				v += stepv;
@@ -1124,49 +1120,49 @@ void R_DrawTranslucentSplat_8 (void)
 		// need!
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[0] = colormap[*(ds_transmap + (val << 8) + dest[0])];
+			dest[0] = *(ds_transmap + (colormap[val] << 8) + dest[0]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[1] = colormap[*(ds_transmap + (val << 8) + dest[1])];
+			dest[1] = *(ds_transmap + (colormap[val] << 8) + dest[1]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[2] = colormap[*(ds_transmap + (val << 8) + dest[2])];
+			dest[2] = *(ds_transmap + (colormap[val] << 8) + dest[2]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[3] = colormap[*(ds_transmap + (val << 8) + dest[3])];
+			dest[3] = *(ds_transmap + (colormap[val] << 8) + dest[3]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[4] = colormap[*(ds_transmap + (val << 8) + dest[4])];
+			dest[4] = *(ds_transmap + (colormap[val] << 8) + dest[4]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[5] = colormap[*(ds_transmap + (val << 8) + dest[5])];
+			dest[5] = *(ds_transmap + (colormap[val] << 8) + dest[5]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[6] = colormap[*(ds_transmap + (val << 8) + dest[6])];
+			dest[6] = *(ds_transmap + (colormap[val] << 8) + dest[6]);
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[7] = colormap[*(ds_transmap + (val << 8) + dest[7])];
+			dest[7] = *(ds_transmap + (colormap[val] << 8) + dest[7]);
 		xposition += xstep;
 		yposition += ystep;
 
@@ -1177,7 +1173,7 @@ void R_DrawTranslucentSplat_8 (void)
 	{
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			*dest = colormap[*(ds_transmap + (val << 8) + *dest)];
+			*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
 
 		dest++;
 		xposition += xstep;
@@ -1220,35 +1216,35 @@ void R_DrawTranslucentSpan_8 (void)
 		// SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't
 		// have the uber complicated math to calculate it now, so that was a memory write we didn't
 		// need!
-		dest[0] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[0])];
+		dest[0] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[0]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[1])];
+		dest[1] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[1]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[2])];
+		dest[2] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[2]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[3])];
+		dest[3] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[3]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[4])];
+		dest[4] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[4]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[5])];
+		dest[5] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[5]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[6])];
+		dest[6] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[6]);
 		xposition += xstep;
 		yposition += ystep;
 
-		dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[7])];
+		dest[7] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[7]);
 		xposition += xstep;
 		yposition += ystep;
 
@@ -1257,7 +1253,7 @@ void R_DrawTranslucentSpan_8 (void)
 	}
 	while (count--)
 	{
-		*dest = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dest)];
+		*dest = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + *dest);
 		dest++;
 		xposition += xstep;
 		yposition += ystep;
diff --git a/src/r_main.c b/src/r_main.c
index 7d5d1699429002edecf2939022eca2aed7c4f99f..fb84e8d7288168aaf190509f84a1e341fa1a96d3 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -60,7 +60,6 @@ fixed_t projectiony; // aspect ratio
 // just for profiling purposes
 size_t framecount;
 
-size_t sscount;
 size_t loopcount;
 
 fixed_t viewx, viewy, viewz;
@@ -482,9 +481,6 @@ static void R_InitTextureMapping(void)
 	// Take out the fencepost cases from viewangletox.
 	for (i = 0; i < FINEANGLES/2; i++)
 	{
-		t = FixedMul(FINETANGENT(i), focallength);
-		t = centerx - t;
-
 		if (viewangletox[i] == -1)
 			viewangletox[i] = 0;
 		else if (viewangletox[i] == viewwidth+1)
@@ -954,8 +950,6 @@ void R_SkyboxFrame(player_t *player)
 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
 
-	sscount = 0;
-
 	// recalc necessary stuff for mouseaiming
 	// slopes are already calculated for the full possible view (which is 4*viewheight).
 
@@ -1079,8 +1073,6 @@ void R_SetupFrame(player_t *player, boolean skybox)
 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
 
-	sscount = 0;
-
 	// recalc necessary stuff for mouseaiming
 	// slopes are already calculated for the full possible view (which is 4*viewheight).
 
@@ -1225,9 +1217,9 @@ void R_RenderPlayerView(player_t *player)
 	if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1
 	{
 		if (cv_homremoval.value == 1)
-			V_DrawFill(0, 0, vid.width, vid.height, 31); // No HOM effect!
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // No HOM effect!
 		else //'development' HOM removal -- makes it blindingly obvious if HOM is spotted.
-			V_DrawFill(0, 0, vid.width, vid.height, 128+(timeinmap&15));
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 128+(timeinmap&15));
 	}
 
 	// load previous saved value of skyVisible for the player
diff --git a/src/r_plane.c b/src/r_plane.c
index b7b9eaff3388ba7c042ece77748b539b08cad70d..2c4a13290c73c7c4eba84a416893cb0f9c336921 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -37,6 +37,9 @@
 // Quincunx antialiasing of flats!
 //#define QUINCUNX
 
+// good night sweet prince
+#define SHITPLANESPARENCY
+
 //SoM: 3/23/2000: Use Boom visplane hashing.
 #define MAXVISPLANES 512
 
@@ -768,7 +771,11 @@ void R_DrawSinglePlane(visplane_t *pl)
 		else // Opaque, but allow transparent flat pixels
 			spanfunc = splatfunc;
 
-		if (pl->extra_colormap && pl->extra_colormap->fog)
+#ifdef SHITPLANESPARENCY
+		if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog))
+#else
+		if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2))
+#endif
 			light = (pl->lightlevel >> LIGHTSEGSHIFT);
 		else
 			light = LIGHTLEVELS-1;
@@ -822,7 +829,11 @@ void R_DrawSinglePlane(visplane_t *pl)
 			else // Opaque, but allow transparent flat pixels
 				spanfunc = splatfunc;
 
-			if (pl->extra_colormap && pl->extra_colormap->fog)
+#ifdef SHITPLANESPARENCY
+			if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog))
+#else
+			if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2))
+#endif
 				light = (pl->lightlevel >> LIGHTSEGSHIFT);
 			else
 				light = LIGHTLEVELS-1;
diff --git a/src/r_state.h b/src/r_state.h
index 49d0457b262c767621dde508f85f3a481a9feb3d..ac3e1fa42576a050c4edfdf177b560defc08eead 100644
--- a/src/r_state.h
+++ b/src/r_state.h
@@ -108,7 +108,4 @@ extern angle_t rw_normalangle;
 // angle to line origin
 extern angle_t rw_angle1;
 
-// Segs count?
-extern size_t sscount;
-
 #endif
diff --git a/src/r_things.c b/src/r_things.c
index 331febabd41c4a5bda0e77c574f31548fcc9c19d..910a52b30591a4deedb578e759f6fac69659d122 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1023,7 +1023,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
 			else
 */
 			if (!((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK) || thing->flags2 & MF2_SHADOW)
-				&& (!newsprite->extra_colormap || !newsprite->extra_colormap->fog)))
+				&& (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1))))
 			{
 				lindex = FixedMul(sprite->xscale, FixedDiv(640, vid.width))>>(LIGHTSCALESHIFT);
 
@@ -1324,7 +1324,7 @@ static void R_ProjectSprite(mobj_t *thing)
 		vis->transmap = transtables + (thing->frame & FF_TRANSMASK) - 0x10000;
 
 	if (((thing->frame & FF_FULLBRIGHT) || (thing->flags2 & MF2_SHADOW))
-		&& (!vis->extra_colormap || !vis->extra_colormap->fog))
+		&& (!vis->extra_colormap || !(vis->extra_colormap->fog & 1)))
 	{
 		// full bright: goggles
 		vis->colormap = colormaps;
@@ -1451,6 +1451,17 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
 			return;
 	}
 
+	// okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok
+	if (!(thing->precipflags & PCF_THUNK))
+	{
+		if (thing->precipflags & PCF_RAIN)
+			P_RainThinker(thing);
+		else
+			P_SnowThinker(thing);
+		thing->precipflags |= PCF_THUNK;
+	}
+
+
 	//SoM: 3/17/2000: Disregard sprites that are out of view..
 	gzt = thing->z + spritecachedinfo[lump].topoffset;
 	gz = gzt - spritecachedinfo[lump].height;
@@ -1569,8 +1580,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 
 			approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
 
-			if (approx_dist <= limit_dist)
-				R_ProjectSprite(thing);
+			if (approx_dist > limit_dist)
+				continue;
+
+			R_ProjectSprite(thing);
 		}
 	}
 	else
@@ -1591,8 +1604,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 
 			approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
 
-			if (approx_dist <= limit_dist)
-				R_ProjectPrecipitationSprite(precipthing);
+			if (approx_dist > limit_dist)
+				continue;
+
+			R_ProjectPrecipitationSprite(precipthing);
 		}
 	}
 	else
diff --git a/src/s_sound.c b/src/s_sound.c
index 47a9555614532bc0631f5cd1d6c6db93d0e30e15..e8d94ca8e8592975adcd2c65d5982750f5839321 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -78,7 +78,7 @@ consvar_t stereoreverse = {"stereoreverse", "Off", CV_SAVE, CV_OnOff, NULL, 0, N
 static consvar_t precachesound = {"precachesound", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 // actual general (maximum) sound & music volume, saved into the config
-consvar_t cv_soundvolume = {"soundvolume", "31", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_soundvolume = {"soundvolume", "18", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_digmusicvolume = {"digmusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_midimusicvolume = {"midimusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 // number of channels available
@@ -226,7 +226,7 @@ void S_RegisterSoundStuff(void)
 {
 	if (dedicated)
 	{
-		nosound = true;
+		sound_disabled = true;
 		return;
 	}
 
@@ -400,7 +400,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
 	mobj_t *listenmobj = players[displayplayer].mo;
 	mobj_t *listenmobj2 = NULL;
 
-	if (sound_disabled || !sound_started || nosound)
+	if (sound_disabled || !sound_started)
 		return;
 
 	// Don't want a sound? Okay then...
@@ -529,7 +529,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
 
 		// Assigns the handle to one of the channels in the
 		// mix/output buffer.
-		channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority);
+		channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
 	}
 
 dontplay:
@@ -579,7 +579,7 @@ dontplay:
 
 	// Assigns the handle to one of the channels in the
 	// mix/output buffer.
-	channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority);
+	channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
 }
 
 void S_StartSound(const void *origin, sfxenum_t sfx_id)
@@ -716,7 +716,7 @@ void S_UpdateSounds(void)
 		return;
 	}
 
-	if (dedicated || nosound)
+	if (dedicated || sound_disabled)
 		return;
 
 	if (players[displayplayer].awayviewtics)
@@ -1151,6 +1151,43 @@ void S_StartSoundName(void *mo, const char *soundname)
 	S_StartSound(mo, soundnum);
 }
 
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX volume,
+//  allocates channel buffer, sets S_sfx lookup.
+//
+void S_InitSfxChannels(INT32 sfxVolume)
+{
+	INT32 i;
+
+	if (dedicated)
+		return;
+
+	S_SetSfxVolume(sfxVolume);
+
+	SetChannelsNum();
+
+	// Note that sounds have not been cached (yet).
+	for (i = 1; i < NUMSFX; i++)
+	{
+		S_sfx[i].usefulness = -1; // for I_GetSfx()
+		S_sfx[i].lumpnum = LUMPERROR;
+	}
+
+	// precache sounds if requested by cmdline, or precachesound var true
+	if (!sound_disabled && (M_CheckParm("-precachesound") || precachesound.value))
+	{
+		// Initialize external data (all sounds) at start, keep static.
+		CONS_Printf(M_GetText("Loading sounds... "));
+
+		for (i = 1; i < NUMSFX; i++)
+			if (S_sfx[i].name)
+				S_sfx[i].data = I_GetSfx(&S_sfx[i]);
+
+		CONS_Printf(M_GetText(" pre-cached all sound data\n"));
+	}
+}
+
 /// ------------------------
 /// Music
 /// ------------------------
@@ -1177,31 +1214,109 @@ const char *compat_special_music_slots[16] =
 };
 #endif
 
-#define music_playing (music_name[0]) // String is empty if no music is playing
-
 static char      music_name[7]; // up to 6-character name
-static lumpnum_t music_lumpnum; // lump number of music (used??)
-static void     *music_data;    // music raw data
-static INT32     music_handle;  // once registered, the handle for the music
+static void      *music_data;
+static UINT16    music_flags;
+static boolean   music_looping;
+
+/// ------------------------
+/// Music Status
+/// ------------------------
+
+boolean S_DigMusicDisabled(void)
+{
+	return digital_disabled;
+}
+
+boolean S_MIDIMusicDisabled(void)
+{
+	return midi_disabled;
+}
+
+boolean S_MusicDisabled(void)
+{
+	return (midi_disabled && digital_disabled);
+}
+
+boolean S_MusicPlaying(void)
+{
+	return I_SongPlaying();
+}
+
+boolean S_MusicPaused(void)
+{
+	return I_SongPaused();
+}
 
-static boolean mus_paused     = 0;  // whether songs are mus_paused
+musictype_t S_MusicType(void)
+{
+	return I_SongType();
+}
+
+boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping)
+{
+	if (!I_SongPlaying())
+		return false;
+
+	strncpy(mname, music_name, 7);
+	mname[6] = 0;
+	*mflags = music_flags;
+	*looping = music_looping;
+
+	return (boolean)mname[0];
+}
 
-static boolean S_MIDIMusic(const char *mname, boolean looping)
+boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi)
+{
+	return (
+		(checkDigi ? W_CheckNumForName(va("O_%s", mname)) != LUMPERROR : false)
+		|| (checkMIDI ? W_CheckNumForName(va("D_%s", mname)) != LUMPERROR : false)
+	);
+}
+
+/// ------------------------
+/// Music Effects
+/// ------------------------
+
+boolean S_SpeedMusic(float speed)
+{
+	return I_SetSongSpeed(speed);
+}
+
+/// ------------------------
+/// Music Playback
+/// ------------------------
+
+static boolean S_LoadMusic(const char *mname)
 {
 	lumpnum_t mlumpnum;
 	void *mdata;
-	INT32 mhandle;
 
-	if (nomidimusic || music_disabled)
-		return false; // didn't search.
+	if (S_MusicDisabled())
+		return false;
 
-	if (W_CheckNumForName(va("d_%s", mname)) == LUMPERROR)
+	if (!S_DigMusicDisabled() && S_DigExists(mname))
+		mlumpnum = W_GetNumForName(va("o_%s", mname));
+	else if (!S_MIDIMusicDisabled() && S_MIDIExists(mname))
+		mlumpnum = W_GetNumForName(va("d_%s", mname));
+	else if (S_DigMusicDisabled() && S_DigExists(mname))
+	{
+		CONS_Alert(CONS_NOTICE, "Digital music is disabled!\n");
+		return false;
+	}
+	else if (S_MIDIMusicDisabled() && S_MIDIExists(mname))
+	{
+		CONS_Alert(CONS_NOTICE, "MIDI music is disabled!\n");
 		return false;
-	mlumpnum = W_GetNumForName(va("d_%s", mname));
+	}
+	else
+	{
+		CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), mname);
+		return false;
+	}
 
 	// load & register it
 	mdata = W_CacheLumpNum(mlumpnum, PU_MUSIC);
-	mhandle = I_RegisterSong(mdata, W_LumpLength(mlumpnum));
 
 #ifdef MUSSERV
 	if (msg_id != -1)
@@ -1215,31 +1330,43 @@ static boolean S_MIDIMusic(const char *mname, boolean looping)
 	}
 #endif
 
-	// play it
-	if (!I_PlaySong(mhandle, looping))
+	if (I_LoadSong(mdata, W_LumpLength(mlumpnum)))
+	{
+		strncpy(music_name, mname, 7);
+		music_name[6] = 0;
+		music_data = mdata;
+		return true;
+	}
+	else
 		return false;
+}
 
-	strncpy(music_name, mname, 7);
-	music_name[6] = 0;
-	music_lumpnum = mlumpnum;
-	music_data = mdata;
-	music_handle = mhandle;
-	return true;
+static void S_UnloadMusic(void)
+{
+	I_UnloadSong();
+
+#ifndef HAVE_SDL //SDL uses RWOPS
+	Z_ChangeTag(music_data, PU_CACHE);
+#endif
+	music_data = NULL;
+
+	music_name[0] = 0;
+	music_flags = 0;
+	music_looping = false;
 }
 
-static boolean S_DigMusic(const char *mname, boolean looping)
+static boolean S_PlayMusic(boolean looping)
 {
-	if (nodigimusic || digital_disabled)
-		return false; // try midi
+	if (S_MusicDisabled())
+		return false;
 
-	if (!I_StartDigSong(mname, looping))
+	if (!I_PlaySong(looping))
+	{
+		S_UnloadMusic();
 		return false;
+	}
 
-	strncpy(music_name, mname, 7);
-	music_name[6] = 0;
-	music_lumpnum = LUMPERROR;
-	music_data = NULL;
-	music_handle = 0;
+	S_InitMusicVolume(); // switch between digi and sequence volume
 	return true;
 }
 
@@ -1249,7 +1376,7 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping)
 	S_ClearSfx();
 #endif
 
-	if ((nomidimusic || music_disabled) && (nodigimusic || digital_disabled))
+	if (S_MusicDisabled())
 		return;
 
 	// No Music (empty string)
@@ -1259,121 +1386,105 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping)
 		return;
 	}
 
-	if (strncmp(music_name, mmusic, 6))
+	if (strnicmp(music_name, mmusic, 6))
 	{
 		S_StopMusic(); // shutdown old music
-		if (!S_DigMusic(mmusic, looping) && !S_MIDIMusic(mmusic, looping))
+
+		if (!S_LoadMusic(mmusic))
+		{
+			CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", mmusic);
+			return;
+		}
+
+		music_flags = mflags;
+		music_looping = looping;
+
+		if (!S_PlayMusic(looping))
 		{
-			CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), mmusic);
+			CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", mmusic);
 			return;
 		}
 	}
 	I_SetSongTrack(mflags & MUSIC_TRACKMASK);
 }
 
-boolean S_SpeedMusic(float speed)
-{
-	return I_SetSongSpeed(speed);
-}
-
 void S_StopMusic(void)
 {
-	if (!music_playing)
+	if (!I_SongPlaying())
 		return;
 
-	if (mus_paused)
-		I_ResumeSong(music_handle);
-
-	if (!nodigimusic)
-		I_StopDigSong();
+	if (I_SongPaused())
+		I_ResumeSong();
 
 	S_SpeedMusic(1.0f);
-	I_StopSong(music_handle);
-	I_UnRegisterSong(music_handle);
-
-#ifndef HAVE_SDL //SDL uses RWOPS
-	Z_ChangeTag(music_data, PU_CACHE);
-#endif
-
-	music_data = NULL;
-	music_name[0] = 0;
+	I_StopSong();
+	S_UnloadMusic(); // for now, stopping also means you unload the song
 }
 
-void S_SetDigMusicVolume(INT32 volume)
+//
+// Stop and resume music, during game PAUSE.
+//
+void S_PauseAudio(void)
 {
-	if (volume < 0 || volume > 31)
-		CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n");
+	if (I_SongPlaying() && !I_SongPaused())
+		I_PauseSong();
 
-	CV_SetValue(&cv_digmusicvolume, volume&31);
-	actualdigmusicvolume = cv_digmusicvolume.value;   //check for change of var
-
-#ifdef DJGPPDOS
-	I_SetDigMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
+	// pause cd music
+#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
+	I_PauseCD();
+#else
+	I_StopCD();
 #endif
-	I_SetDigMusicVolume(volume&31);
 }
 
-void S_SetMIDIMusicVolume(INT32 volume)
+void S_ResumeAudio(void)
 {
-	if (volume < 0 || volume > 31)
-		CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n");
+	if (I_SongPlaying() && I_SongPaused())
+		I_ResumeSong();
 
-	CV_SetValue(&cv_midimusicvolume, volume&0x1f);
-	actualmidimusicvolume = cv_midimusicvolume.value;   //check for change of var
-
-#ifdef DJGPPDOS
-	I_SetMIDIMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
-#endif
-	I_SetMIDIMusicVolume(volume&0x1f);
+	// resume cd music
+	I_ResumeCD();
 }
 
-/// ------------------------
-/// Init & Others
-/// ------------------------
-
-//
-// Initializes sound stuff, including volume
-// Sets channels, SFX and music volume,
-//  allocates channel buffer, sets S_sfx lookup.
-//
-void S_Init(INT32 sfxVolume, INT32 digMusicVolume, INT32 midiMusicVolume)
+void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume)
 {
-	INT32 i;
-
-	if (dedicated)
-		return;
-
-	S_SetSfxVolume(sfxVolume);
-	S_SetDigMusicVolume(digMusicVolume);
-	S_SetMIDIMusicVolume(midiMusicVolume);
-
-	SetChannelsNum();
+	if (digvolume < 0)
+		digvolume = cv_digmusicvolume.value;
+	if (seqvolume < 0)
+		seqvolume = cv_midimusicvolume.value;
+
+	if (digvolume < 0 || digvolume > 31)
+		CONS_Alert(CONS_WARNING, "digmusicvolume should be between 0-31\n");
+	CV_SetValue(&cv_digmusicvolume, digvolume&31);
+	actualdigmusicvolume = cv_digmusicvolume.value;   //check for change of var
 
-	// no sounds are playing, and they are not mus_paused
-	mus_paused = 0;
+	if (seqvolume < 0 || seqvolume > 31)
+		CONS_Alert(CONS_WARNING, "midimusicvolume should be between 0-31\n");
+	CV_SetValue(&cv_midimusicvolume, seqvolume&31);
+	actualmidimusicvolume = cv_midimusicvolume.value;   //check for change of var
 
-	// Note that sounds have not been cached (yet).
-	for (i = 1; i < NUMSFX; i++)
-	{
-		S_sfx[i].usefulness = -1; // for I_GetSfx()
-		S_sfx[i].lumpnum = LUMPERROR;
-	}
+#ifdef DJGPPDOS
+	digvolume = seqvolume = 31;
+#endif
 
-	// precache sounds if requested by cmdline, or precachesound var true
-	if (!nosound && (M_CheckParm("-precachesound") || precachesound.value))
+	switch(I_SongType())
 	{
-		// Initialize external data (all sounds) at start, keep static.
-		CONS_Printf(M_GetText("Loading sounds... "));
-
-		for (i = 1; i < NUMSFX; i++)
-			if (S_sfx[i].name)
-				S_sfx[i].data = I_GetSfx(&S_sfx[i]);
-
-		CONS_Printf(M_GetText(" pre-cached all sound data\n"));
+		case MU_MID:
+		//case MU_MOD:
+		//case MU_GME:
+			I_SetMusicVolume(seqvolume&31);
+			break;
+		default:
+			I_SetMusicVolume(digvolume&31);
+			break;
 	}
 }
 
 
+/// ------------------------
+/// Init & Others
+/// ------------------------
+
 //
 // Per level startup code.
 // Kills playing sounds at start of level,
@@ -1388,46 +1499,7 @@ void S_Start(void)
 		mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
 	}
 
-	mus_paused = 0;
-
 	if (cv_resetmusic.value)
 		S_StopMusic();
 	S_ChangeMusic(mapmusname, mapmusflags, true);
 }
-
-//
-// Stop and resume music, during game PAUSE.
-//
-void S_PauseAudio(void)
-{
-	if (!nodigimusic)
-		I_PauseSong(0);
-
-	if (music_playing && !mus_paused)
-	{
-		I_PauseSong(music_handle);
-		mus_paused = true;
-	}
-
-	// pause cd music
-#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
-	I_PauseCD();
-#else
-	I_StopCD();
-#endif
-}
-
-void S_ResumeAudio(void)
-{
-	if (!nodigimusic)
-		I_ResumeSong(0);
-	else
-	if (music_playing && mus_paused)
-	{
-		I_ResumeSong(music_handle);
-		mus_paused = false;
-	}
-
-	// resume cd music
-	I_ResumeCD();
-}
diff --git a/src/s_sound.h b/src/s_sound.h
index 39ec769a68b6aa13ac4056e26c4edec3c8af59fb..a2d51a59bdb58a6dbe8996e3d27aeaf402586deb 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -14,6 +14,7 @@
 #ifndef __S_SOUND__
 #define __S_SOUND__
 
+#include "i_sound.h" // musictype_t
 #include "sounds.h"
 #include "m_fixed.h"
 #include "command.h"
@@ -69,9 +70,9 @@ void S_RegisterSoundStuff(void);
 
 //
 // Initializes sound stuff, including volume
-// Sets channels, SFX and music volume, allocates channel buffer, sets S_sfx lookup.
+// Sets channels, SFX, allocates channel buffer, sets S_sfx lookup.
 //
-void S_Init(INT32 sfxVolume, INT32 digMusicVolume, INT32 midiMusicVolume);
+void S_InitSfxChannels(INT32 sfxVolume);
 
 //
 // Per level startup code.
@@ -97,6 +98,33 @@ void S_StartSoundAtVolume(const void *origin, sfxenum_t sound_id, INT32 volume);
 // Stop sound for thing at <origin>
 void S_StopSound(void *origin);
 
+//
+// Music Status
+//
+
+boolean S_DigMusicDisabled(void);
+boolean S_MIDIMusicDisabled(void);
+boolean S_MusicDisabled(void);
+boolean S_MusicPlaying(void);
+boolean S_MusicPaused(void);
+musictype_t S_MusicType(void);
+boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping);
+boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi);
+#define S_DigExists(a) S_MusicExists(a, false, true)
+#define S_MIDIExists(a) S_MusicExists(a, true, false)
+
+
+//
+// Music Properties
+//
+
+// Set Speed of Music
+boolean S_SpeedMusic(float speed);
+
+//
+// Music Routines
+//
+
 // Start music track, arbitrary, given its name, and set whether looping
 // note: music flags 12 bits for tracknum (gme, other formats with more than one track)
 //       13-15 aren't used yet
@@ -104,9 +132,6 @@ void S_StopSound(void *origin);
 #define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b)
 void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping);
 
-// Set Speed of Music
-boolean S_SpeedMusic(float speed);
-
 // Stops the music.
 void S_StopMusic(void);
 
@@ -121,9 +146,11 @@ void S_UpdateSounds(void);
 
 FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);
 
-void S_SetDigMusicVolume(INT32 volume);
-void S_SetMIDIMusicVolume(INT32 volume);
 void S_SetSfxVolume(INT32 volume);
+void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume);
+#define S_SetDigMusicVolume(a) S_SetMusicVolume(a,-1)
+#define S_SetMIDIMusicVolume(a) S_SetMusicVolume(-1,a)
+#define S_InitMusicVolume() S_SetMusicVolume(-1,-1)
 
 INT32 S_OriginPlaying(void *origin);
 INT32 S_IdPlaying(sfxenum_t id);
diff --git a/src/sdl/IMG_xpm.c b/src/sdl/IMG_xpm.c
index e08736d66515b89367f29022afd4ed663e570497..8adfd3434f1fa72a2afc59ee3a5059483c5c417c 100644
--- a/src/sdl/IMG_xpm.c
+++ b/src/sdl/IMG_xpm.c
@@ -1,27 +1,24 @@
 /*
-    SDL_image:  An example image loading library for use with SDL
-    Copyright (C) 1999-2004 Sam Lantinga
+  SDL_image:  An example image loading library for use with SDL
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
 
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Library General Public License for more details.
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
 
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-    Sam Lantinga
-    slouken@libsdl.org
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
 */
 
-/* $Id: IMG_xpm.c,v 1.10 2004/01/04 22:04:38 slouken Exp $ */
-
 /*
  * XPM (X PixMap) image loader:
  *
@@ -45,98 +42,110 @@
  * requires about 13K in binary form.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-//#include "SDL_image.h"
-
+#if 0
+#include "SDL_image.h"
+#else
+extern SDLCALL int SDLCALL IMG_isXPM(SDL_RWops *src);
+extern SDLCALL SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src);
+extern SDLCALL SDL_Surface * SDLCALL IMG_ReadXPMFromArray(const char **xpm);
+#define IMG_SetError    SDL_SetError
+#define IMG_GetError    SDL_GetError
+#endif
 
 #ifdef LOAD_XPM
 
 /* See if an image is contained in a data source */
-#if 0
 int IMG_isXPM(SDL_RWops *src)
 {
-        char magic[9];
+    Sint64 start;
+    int is_XPM;
+    char magic[9];
 
-        return (SDL_RWread(src, magic, sizeof (magic), 1)
-                && memcmp(magic, "/* XPM */", 9) == 0);
+    if ( !src )
+        return 0;
+    start = SDL_RWtell(src);
+    is_XPM = 0;
+    if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
+        if ( SDL_memcmp(magic, "/* XPM */", sizeof(magic)) == 0 ) {
+            is_XPM = 1;
+        }
+    }
+    SDL_RWseek(src, start, RW_SEEK_SET);
+    return(is_XPM);
 }
-#endif
 
 /* Hash table to look up colors from pixel strings */
 #define STARTING_HASH_SIZE 256
 
 struct hash_entry {
-        char *key;
-        Uint32 color;
-        struct hash_entry *next;
+    const char *key;
+    Uint32 color;
+    struct hash_entry *next;
 };
 
 struct color_hash {
-        struct hash_entry **table;
-        struct hash_entry *entries; /* array of all entries */
-        struct hash_entry *next_free;
-        size_t size;
-        int maxnum;
+    struct hash_entry **table;
+    struct hash_entry *entries; /* array of all entries */
+    struct hash_entry *next_free;
+    int size;
+    int maxnum;
 };
 
-static int hash_key(const char *key, int cpp, size_t size)
+static int hash_key(const char *key, int cpp, int size)
 {
-        int hash;
+    int hash;
 
-        hash = 0;
-        while ( cpp-- > 0 ) {
-                hash = hash * 33 + *key++;
-        }
-        return (int)(hash & (size - 1));
+    hash = 0;
+    while ( cpp-- > 0 ) {
+        hash = hash * 33 + *key++;
+    }
+    return hash & (size - 1);
 }
 
 static struct color_hash *create_colorhash(int maxnum)
 {
-        size_t bytes;
-		int s;
-        struct color_hash *hash;
-
-        /* we know how many entries we need, so we can allocate
-           everything here */
-        hash = malloc(sizeof *hash);
-        if (!hash)
-                return NULL;
+    int bytes, s;
+    struct color_hash *hash;
 
-        /* use power-of-2 sized hash table for decoding speed */
-        for (s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
-                ;
-        hash->size = s;
-        hash->maxnum = maxnum;
-        bytes = hash->size * sizeof (struct hash_entry **);
-        hash->entries = NULL;        /* in case malloc fails */
-        hash->table = malloc(bytes);
-        if (!hash->table)
-                return NULL;
-        memset(hash->table, 0, bytes);
-        hash->entries = malloc(maxnum * sizeof (struct hash_entry));
-        if (!hash->entries)
-        {
-                free(hash->table);
-                return NULL;
-        }
-        hash->next_free = hash->entries;
-        return hash;
+    /* we know how many entries we need, so we can allocate
+       everything here */
+    hash = (struct color_hash *)SDL_malloc(sizeof *hash);
+    if (!hash)
+        return NULL;
+
+    /* use power-of-2 sized hash table for decoding speed */
+    for (s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
+        ;
+    hash->size = s;
+    hash->maxnum = maxnum;
+    bytes = hash->size * sizeof(struct hash_entry **);
+    hash->entries = NULL;   /* in case malloc fails */
+    hash->table = (struct hash_entry **)SDL_malloc(bytes);
+    if (!hash->table) {
+        SDL_free(hash);
+        return NULL;
+    }
+    SDL_memset(hash->table, 0, bytes);
+    hash->entries = (struct hash_entry *)SDL_malloc(maxnum * sizeof(struct hash_entry));
+    if (!hash->entries) {
+        SDL_free(hash->table);
+        SDL_free(hash);
+        return NULL;
+    }
+    hash->next_free = hash->entries;
+    return hash;
 }
 
 static int add_colorhash(struct color_hash *hash,
                          char *key, int cpp, Uint32 color)
 {
-        const int indexkey = hash_key(key, cpp, hash->size);
-        struct hash_entry *e = hash->next_free++;
-        e->color = color;
-        e->key = key;
-        e->next = hash->table[indexkey];
-        hash->table[indexkey] = e;
-        return 1;
+    int index = hash_key(key, cpp, hash->size);
+    struct hash_entry *e = hash->next_free++;
+    e->color = color;
+    e->key = key;
+    e->next = hash->table[index];
+    hash->table[index] = e;
+    return 1;
 }
 
 /* fast lookup that works if cpp == 1 */
@@ -144,88 +153,756 @@ static int add_colorhash(struct color_hash *hash,
 
 static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
 {
-        struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
-        while (entry) {
-                if (memcmp(key, entry->key, cpp) == 0)
-                        return entry->color;
-                entry = entry->next;
-        }
-        return 0;                /* garbage in - garbage out */
+    struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
+    while (entry) {
+        if (SDL_memcmp(key, entry->key, cpp) == 0)
+            return entry->color;
+        entry = entry->next;
+    }
+    return 0;       /* garbage in - garbage out */
 }
 
 static void free_colorhash(struct color_hash *hash)
 {
-        if (hash && hash->table) {
-                free(hash->table);
-                free(hash->entries);
-                free(hash);
-        }
-}
-
-/* portable case-insensitive string comparison */
-static int string_equal(const char *a, const char *b, size_t n)
-{
-        while (*a && *b && n) {
-                if (toupper((unsigned char)*a) != toupper((unsigned char)*b))
-                        return 0;
-                a++;
-                b++;
-                n--;
-        }
-        return *a == *b;
+    if (hash) {
+        if (hash->table)
+            SDL_free(hash->table);
+        if (hash->entries)
+            SDL_free(hash->entries);
+        SDL_free(hash);
+    }
 }
 
-#undef ARRAYSIZE
-#define ARRAYSIZE(a) (int)(sizeof (a) / sizeof ((a)[0]))
-
 /*
  * convert colour spec to RGB (in 0xrrggbb format).
  * return 1 if successful.
  */
-static int color_to_rgb(const char *spec, size_t speclen, Uint32 *rgb)
+static int color_to_rgb(const char *spec, int speclen, Uint32 *rgb)
 {
-        /* poor man's rgb.txt */
-        static struct { const char *name; Uint32 rgb; } known[] = {
-                {"none",  0xffffffff},
-                {"black", 0x00000000},
-                {"white", 0x00ffffff},
-                {"red",   0x00ff0000},
-                {"green", 0x0000ff00},
-                {"blue",  0x000000ff}
-        };
-
-        if (spec[0] == '#') {
-                char buf[7];
-                switch (speclen) {
-                case 4:
-                        buf[0] = buf[1] = spec[1];
-                        buf[2] = buf[3] = spec[2];
-                        buf[4] = buf[5] = spec[3];
-                        break;
-                case 7:
-                        memcpy(buf, spec + 1, 6);
-                        break;
-                case 13:
-                        buf[0] = spec[1];
-                        buf[1] = spec[2];
-                        buf[2] = spec[5];
-                        buf[3] = spec[6];
-                        buf[4] = spec[9];
-                        buf[5] = spec[10];
-                        break;
-                }
-                buf[6] = '\0';
-                *rgb = (Uint32)strtol(buf, NULL, 16);
+    /* poor man's rgb.txt */
+    static struct { const char *name; Uint32 rgb; } known[] = {
+        { "none",                 0xFFFFFFFF },
+        { "black",                0x000000 },
+        { "white",                0xFFFFFF },
+        { "red",                  0xFF0000 },
+        { "green",                0x00FF00 },
+        { "blue",                 0x0000FF },
+/* This table increases the size of the library by 40K, so it's disabled by default */
+#ifdef EXTENDED_XPM_COLORS
+        { "aliceblue",            0xf0f8ff },
+        { "antiquewhite",         0xfaebd7 },
+        { "antiquewhite1",        0xffefdb },
+        { "antiquewhite2",        0xeedfcc },
+        { "antiquewhite3",        0xcdc0b0 },
+        { "antiquewhite4",        0x8b8378 },
+        { "aqua",                 0x00ffff },
+        { "aquamarine",           0x7fffd4 },
+        { "aquamarine1",          0x7fffd4 },
+        { "aquamarine2",          0x76eec6 },
+        { "aquamarine3",          0x66cdaa },
+        { "aquamarine4",          0x458b74 },
+        { "azure",                0xf0ffff },
+        { "azure1",               0xf0ffff },
+        { "azure2",               0xe0eeee },
+        { "azure3",               0xc1cdcd },
+        { "azure4",               0x838b8b },
+        { "beige",                0xf5f5dc },
+        { "bisque",               0xffe4c4 },
+        { "bisque1",              0xffe4c4 },
+        { "bisque2",              0xeed5b7 },
+        { "bisque3",              0xcdb79e },
+        { "bisque4",              0x8b7d6b },
+        { "black",                0x000000 },
+        { "blanchedalmond",       0xffebcd },
+        { "blue",                 0x0000ff },
+        { "blue1",                0x0000ff },
+        { "blue2",                0x0000ee },
+        { "blue3",                0x0000cd },
+        { "blue4",                0x00008B },
+        { "blueviolet",           0x8a2be2 },
+        { "brown",                0xA52A2A },
+        { "brown1",               0xFF4040 },
+        { "brown2",               0xEE3B3B },
+        { "brown3",               0xCD3333 },
+        { "brown4",               0x8B2323 },
+        { "burlywood",            0xDEB887 },
+        { "burlywood1",           0xFFD39B },
+        { "burlywood2",           0xEEC591 },
+        { "burlywood3",           0xCDAA7D },
+        { "burlywood4",           0x8B7355 },
+        { "cadetblue",            0x5F9EA0 },
+        { "cadetblue",            0x5f9ea0 },
+        { "cadetblue1",           0x98f5ff },
+        { "cadetblue2",           0x8ee5ee },
+        { "cadetblue3",           0x7ac5cd },
+        { "cadetblue4",           0x53868b },
+        { "chartreuse",           0x7FFF00 },
+        { "chartreuse1",          0x7FFF00 },
+        { "chartreuse2",          0x76EE00 },
+        { "chartreuse3",          0x66CD00 },
+        { "chartreuse4",          0x458B00 },
+        { "chocolate",            0xD2691E },
+        { "chocolate1",           0xFF7F24 },
+        { "chocolate2",           0xEE7621 },
+        { "chocolate3",           0xCD661D },
+        { "chocolate4",           0x8B4513 },
+        { "coral",                0xFF7F50 },
+        { "coral1",               0xFF7256 },
+        { "coral2",               0xEE6A50 },
+        { "coral3",               0xCD5B45 },
+        { "coral4",               0x8B3E2F },
+        { "cornflowerblue",       0x6495ed },
+        { "cornsilk",             0xFFF8DC },
+        { "cornsilk1",            0xFFF8DC },
+        { "cornsilk2",            0xEEE8CD },
+        { "cornsilk3",            0xCDC8B1 },
+        { "cornsilk4",            0x8B8878 },
+        { "crimson",              0xDC143C },
+        { "cyan",                 0x00FFFF },
+        { "cyan1",                0x00FFFF },
+        { "cyan2",                0x00EEEE },
+        { "cyan3",                0x00CDCD },
+        { "cyan4",                0x008B8B },
+        { "darkblue",             0x00008b },
+        { "darkcyan",             0x008b8b },
+        { "darkgoldenrod",        0xb8860b },
+        { "darkgoldenrod1",       0xffb90f },
+        { "darkgoldenrod2",       0xeead0e },
+        { "darkgoldenrod3",       0xcd950c },
+        { "darkgoldenrod4",       0x8b6508 },
+        { "darkgray",             0xa9a9a9 },
+        { "darkgreen",            0x006400 },
+        { "darkgrey",             0xa9a9a9 },
+        { "darkkhaki",            0xbdb76b },
+        { "darkmagenta",          0x8b008b },
+        { "darkolivegreen",       0x556b2f },
+        { "darkolivegreen1",      0xcaff70 },
+        { "darkolivegreen2",      0xbcee68 },
+        { "darkolivegreen3",      0xa2cd5a },
+        { "darkolivegreen4",      0x6e8b3d },
+        { "darkorange",           0xff8c00 },
+        { "darkorange1",          0xff7f00 },
+        { "darkorange2",          0xee7600 },
+        { "darkorange3",          0xcd6600 },
+        { "darkorange4",          0x8b4500 },
+        { "darkorchid",           0x9932cc },
+        { "darkorchid1",          0xbf3eff },
+        { "darkorchid2",          0xb23aee },
+        { "darkorchid3",          0x9a32cd },
+        { "darkorchid4",          0x68228b },
+        { "darkred",              0x8b0000 },
+        { "darksalmon",           0xe9967a },
+        { "darkseagreen",         0x8fbc8f },
+        { "darkseagreen1",        0xc1ffc1 },
+        { "darkseagreen2",        0xb4eeb4 },
+        { "darkseagreen3",        0x9bcd9b },
+        { "darkseagreen4",        0x698b69 },
+        { "darkslateblue",        0x483d8b },
+        { "darkslategray",        0x2f4f4f },
+        { "darkslategray1",       0x97ffff },
+        { "darkslategray2",       0x8deeee },
+        { "darkslategray3",       0x79cdcd },
+        { "darkslategray4",       0x528b8b },
+        { "darkslategrey",        0x2f4f4f },
+        { "darkturquoise",        0x00ced1 },
+        { "darkviolet",           0x9400D3 },
+        { "darkviolet",           0x9400d3 },
+        { "deeppink",             0xff1493 },
+        { "deeppink1",            0xff1493 },
+        { "deeppink2",            0xee1289 },
+        { "deeppink3",            0xcd1076 },
+        { "deeppink4",            0x8b0a50 },
+        { "deepskyblue",          0x00bfff },
+        { "deepskyblue1",         0x00bfff },
+        { "deepskyblue2",         0x00b2ee },
+        { "deepskyblue3",         0x009acd },
+        { "deepskyblue4",         0x00688b },
+        { "dimgray",              0x696969 },
+        { "dimgrey",              0x696969 },
+        { "dodgerblue",           0x1e90ff },
+        { "dodgerblue1",          0x1e90ff },
+        { "dodgerblue2",          0x1c86ee },
+        { "dodgerblue3",          0x1874cd },
+        { "dodgerblue4",          0x104e8b },
+        { "firebrick",            0xB22222 },
+        { "firebrick1",           0xFF3030 },
+        { "firebrick2",           0xEE2C2C },
+        { "firebrick3",           0xCD2626 },
+        { "firebrick4",           0x8B1A1A },
+        { "floralwhite",          0xfffaf0 },
+        { "forestgreen",          0x228b22 },
+        { "fractal",              0x808080 },
+        { "fuchsia",              0xFF00FF },
+        { "gainsboro",            0xDCDCDC },
+        { "ghostwhite",           0xf8f8ff },
+        { "gold",                 0xFFD700 },
+        { "gold1",                0xFFD700 },
+        { "gold2",                0xEEC900 },
+        { "gold3",                0xCDAD00 },
+        { "gold4",                0x8B7500 },
+        { "goldenrod",            0xDAA520 },
+        { "goldenrod1",           0xFFC125 },
+        { "goldenrod2",           0xEEB422 },
+        { "goldenrod3",           0xCD9B1D },
+        { "goldenrod4",           0x8B6914 },
+        { "gray",                 0x7E7E7E },
+        { "gray",                 0xBEBEBE },
+        { "gray0",                0x000000 },
+        { "gray1",                0x030303 },
+        { "gray10",               0x1A1A1A },
+        { "gray100",              0xFFFFFF },
+        { "gray11",               0x1C1C1C },
+        { "gray12",               0x1F1F1F },
+        { "gray13",               0x212121 },
+        { "gray14",               0x242424 },
+        { "gray15",               0x262626 },
+        { "gray16",               0x292929 },
+        { "gray17",               0x2B2B2B },
+        { "gray18",               0x2E2E2E },
+        { "gray19",               0x303030 },
+        { "gray2",                0x050505 },
+        { "gray20",               0x333333 },
+        { "gray21",               0x363636 },
+        { "gray22",               0x383838 },
+        { "gray23",               0x3B3B3B },
+        { "gray24",               0x3D3D3D },
+        { "gray25",               0x404040 },
+        { "gray26",               0x424242 },
+        { "gray27",               0x454545 },
+        { "gray28",               0x474747 },
+        { "gray29",               0x4A4A4A },
+        { "gray3",                0x080808 },
+        { "gray30",               0x4D4D4D },
+        { "gray31",               0x4F4F4F },
+        { "gray32",               0x525252 },
+        { "gray33",               0x545454 },
+        { "gray34",               0x575757 },
+        { "gray35",               0x595959 },
+        { "gray36",               0x5C5C5C },
+        { "gray37",               0x5E5E5E },
+        { "gray38",               0x616161 },
+        { "gray39",               0x636363 },
+        { "gray4",                0x0A0A0A },
+        { "gray40",               0x666666 },
+        { "gray41",               0x696969 },
+        { "gray42",               0x6B6B6B },
+        { "gray43",               0x6E6E6E },
+        { "gray44",               0x707070 },
+        { "gray45",               0x737373 },
+        { "gray46",               0x757575 },
+        { "gray47",               0x787878 },
+        { "gray48",               0x7A7A7A },
+        { "gray49",               0x7D7D7D },
+        { "gray5",                0x0D0D0D },
+        { "gray50",               0x7F7F7F },
+        { "gray51",               0x828282 },
+        { "gray52",               0x858585 },
+        { "gray53",               0x878787 },
+        { "gray54",               0x8A8A8A },
+        { "gray55",               0x8C8C8C },
+        { "gray56",               0x8F8F8F },
+        { "gray57",               0x919191 },
+        { "gray58",               0x949494 },
+        { "gray59",               0x969696 },
+        { "gray6",                0x0F0F0F },
+        { "gray60",               0x999999 },
+        { "gray61",               0x9C9C9C },
+        { "gray62",               0x9E9E9E },
+        { "gray63",               0xA1A1A1 },
+        { "gray64",               0xA3A3A3 },
+        { "gray65",               0xA6A6A6 },
+        { "gray66",               0xA8A8A8 },
+        { "gray67",               0xABABAB },
+        { "gray68",               0xADADAD },
+        { "gray69",               0xB0B0B0 },
+        { "gray7",                0x121212 },
+        { "gray70",               0xB3B3B3 },
+        { "gray71",               0xB5B5B5 },
+        { "gray72",               0xB8B8B8 },
+        { "gray73",               0xBABABA },
+        { "gray74",               0xBDBDBD },
+        { "gray75",               0xBFBFBF },
+        { "gray76",               0xC2C2C2 },
+        { "gray77",               0xC4C4C4 },
+        { "gray78",               0xC7C7C7 },
+        { "gray79",               0xC9C9C9 },
+        { "gray8",                0x141414 },
+        { "gray80",               0xCCCCCC },
+        { "gray81",               0xCFCFCF },
+        { "gray82",               0xD1D1D1 },
+        { "gray83",               0xD4D4D4 },
+        { "gray84",               0xD6D6D6 },
+        { "gray85",               0xD9D9D9 },
+        { "gray86",               0xDBDBDB },
+        { "gray87",               0xDEDEDE },
+        { "gray88",               0xE0E0E0 },
+        { "gray89",               0xE3E3E3 },
+        { "gray9",                0x171717 },
+        { "gray90",               0xE5E5E5 },
+        { "gray91",               0xE8E8E8 },
+        { "gray92",               0xEBEBEB },
+        { "gray93",               0xEDEDED },
+        { "gray94",               0xF0F0F0 },
+        { "gray95",               0xF2F2F2 },
+        { "gray96",               0xF5F5F5 },
+        { "gray97",               0xF7F7F7 },
+        { "gray98",               0xFAFAFA },
+        { "gray99",               0xFCFCFC },
+        { "green",                0x008000 },
+        { "green",                0x00FF00 },
+        { "green1",               0x00FF00 },
+        { "green2",               0x00EE00 },
+        { "green3",               0x00CD00 },
+        { "green4",               0x008B00 },
+        { "greenyellow",          0xadff2f },
+        { "grey",                 0xBEBEBE },
+        { "grey0",                0x000000 },
+        { "grey1",                0x030303 },
+        { "grey10",               0x1A1A1A },
+        { "grey100",              0xFFFFFF },
+        { "grey11",               0x1C1C1C },
+        { "grey12",               0x1F1F1F },
+        { "grey13",               0x212121 },
+        { "grey14",               0x242424 },
+        { "grey15",               0x262626 },
+        { "grey16",               0x292929 },
+        { "grey17",               0x2B2B2B },
+        { "grey18",               0x2E2E2E },
+        { "grey19",               0x303030 },
+        { "grey2",                0x050505 },
+        { "grey20",               0x333333 },
+        { "grey21",               0x363636 },
+        { "grey22",               0x383838 },
+        { "grey23",               0x3B3B3B },
+        { "grey24",               0x3D3D3D },
+        { "grey25",               0x404040 },
+        { "grey26",               0x424242 },
+        { "grey27",               0x454545 },
+        { "grey28",               0x474747 },
+        { "grey29",               0x4A4A4A },
+        { "grey3",                0x080808 },
+        { "grey30",               0x4D4D4D },
+        { "grey31",               0x4F4F4F },
+        { "grey32",               0x525252 },
+        { "grey33",               0x545454 },
+        { "grey34",               0x575757 },
+        { "grey35",               0x595959 },
+        { "grey36",               0x5C5C5C },
+        { "grey37",               0x5E5E5E },
+        { "grey38",               0x616161 },
+        { "grey39",               0x636363 },
+        { "grey4",                0x0A0A0A },
+        { "grey40",               0x666666 },
+        { "grey41",               0x696969 },
+        { "grey42",               0x6B6B6B },
+        { "grey43",               0x6E6E6E },
+        { "grey44",               0x707070 },
+        { "grey45",               0x737373 },
+        { "grey46",               0x757575 },
+        { "grey47",               0x787878 },
+        { "grey48",               0x7A7A7A },
+        { "grey49",               0x7D7D7D },
+        { "grey5",                0x0D0D0D },
+        { "grey50",               0x7F7F7F },
+        { "grey51",               0x828282 },
+        { "grey52",               0x858585 },
+        { "grey53",               0x878787 },
+        { "grey54",               0x8A8A8A },
+        { "grey55",               0x8C8C8C },
+        { "grey56",               0x8F8F8F },
+        { "grey57",               0x919191 },
+        { "grey58",               0x949494 },
+        { "grey59",               0x969696 },
+        { "grey6",                0x0F0F0F },
+        { "grey60",               0x999999 },
+        { "grey61",               0x9C9C9C },
+        { "grey62",               0x9E9E9E },
+        { "grey63",               0xA1A1A1 },
+        { "grey64",               0xA3A3A3 },
+        { "grey65",               0xA6A6A6 },
+        { "grey66",               0xA8A8A8 },
+        { "grey67",               0xABABAB },
+        { "grey68",               0xADADAD },
+        { "grey69",               0xB0B0B0 },
+        { "grey7",                0x121212 },
+        { "grey70",               0xB3B3B3 },
+        { "grey71",               0xB5B5B5 },
+        { "grey72",               0xB8B8B8 },
+        { "grey73",               0xBABABA },
+        { "grey74",               0xBDBDBD },
+        { "grey75",               0xBFBFBF },
+        { "grey76",               0xC2C2C2 },
+        { "grey77",               0xC4C4C4 },
+        { "grey78",               0xC7C7C7 },
+        { "grey79",               0xC9C9C9 },
+        { "grey8",                0x141414 },
+        { "grey80",               0xCCCCCC },
+        { "grey81",               0xCFCFCF },
+        { "grey82",               0xD1D1D1 },
+        { "grey83",               0xD4D4D4 },
+        { "grey84",               0xD6D6D6 },
+        { "grey85",               0xD9D9D9 },
+        { "grey86",               0xDBDBDB },
+        { "grey87",               0xDEDEDE },
+        { "grey88",               0xE0E0E0 },
+        { "grey89",               0xE3E3E3 },
+        { "grey9",                0x171717 },
+        { "grey90",               0xE5E5E5 },
+        { "grey91",               0xE8E8E8 },
+        { "grey92",               0xEBEBEB },
+        { "grey93",               0xEDEDED },
+        { "grey94",               0xF0F0F0 },
+        { "grey95",               0xF2F2F2 },
+        { "grey96",               0xF5F5F5 },
+        { "grey97",               0xF7F7F7 },
+        { "grey98",               0xFAFAFA },
+        { "grey99",               0xFCFCFC },
+        { "honeydew",             0xF0FFF0 },
+        { "honeydew1",            0xF0FFF0 },
+        { "honeydew2",            0xE0EEE0 },
+        { "honeydew3",            0xC1CDC1 },
+        { "honeydew4",            0x838B83 },
+        { "hotpink",              0xff69b4 },
+        { "hotpink1",             0xff6eb4 },
+        { "hotpink2",             0xee6aa7 },
+        { "hotpink3",             0xcd6090 },
+        { "hotpink4",             0x8b3a62 },
+        { "indianred",            0xcd5c5c },
+        { "indianred1",           0xff6a6a },
+        { "indianred2",           0xee6363 },
+        { "indianred3",           0xcd5555 },
+        { "indianred4",           0x8b3a3a },
+        { "indigo",               0x4B0082 },
+        { "ivory",                0xFFFFF0 },
+        { "ivory1",               0xFFFFF0 },
+        { "ivory2",               0xEEEEE0 },
+        { "ivory3",               0xCDCDC1 },
+        { "ivory4",               0x8B8B83 },
+        { "khaki",                0xF0E68C },
+        { "khaki1",               0xFFF68F },
+        { "khaki2",               0xEEE685 },
+        { "khaki3",               0xCDC673 },
+        { "khaki4",               0x8B864E },
+        { "lavender",             0xE6E6FA },
+        { "lavenderblush",        0xfff0f5 },
+        { "lavenderblush1",       0xfff0f5 },
+        { "lavenderblush2",       0xeee0e5 },
+        { "lavenderblush3",       0xcdc1c5 },
+        { "lavenderblush4",       0x8b8386 },
+        { "lawngreen",            0x7cfc00 },
+        { "lemonchiffon",         0xfffacd },
+        { "lemonchiffon1",        0xfffacd },
+        { "lemonchiffon2",        0xeee9bf },
+        { "lemonchiffon3",        0xcdc9a5 },
+        { "lemonchiffon4",        0x8b8970 },
+        { "lightblue",            0xadd8e6 },
+        { "lightblue1",           0xbfefff },
+        { "lightblue2",           0xb2dfee },
+        { "lightblue3",           0x9ac0cd },
+        { "lightblue4",           0x68838b },
+        { "lightcoral",           0xf08080 },
+        { "lightcyan",            0xe0ffff },
+        { "lightcyan1",           0xe0ffff },
+        { "lightcyan2",           0xd1eeee },
+        { "lightcyan3",           0xb4cdcd },
+        { "lightcyan4",           0x7a8b8b },
+        { "lightgoldenrod",       0xeedd82 },
+        { "lightgoldenrod1",      0xffec8b },
+        { "lightgoldenrod2",      0xeedc82 },
+        { "lightgoldenrod3",      0xcdbe70 },
+        { "lightgoldenrod4",      0x8b814c },
+        { "lightgoldenrodyellow", 0xfafad2 },
+        { "lightgray",            0xd3d3d3 },
+        { "lightgreen",           0x90ee90 },
+        { "lightgrey",            0xd3d3d3 },
+        { "lightpink",            0xffb6c1 },
+        { "lightpink1",           0xffaeb9 },
+        { "lightpink2",           0xeea2ad },
+        { "lightpink3",           0xcd8c95 },
+        { "lightpink4",           0x8b5f65 },
+        { "lightsalmon",          0xffa07a },
+        { "lightsalmon1",         0xffa07a },
+        { "lightsalmon2",         0xee9572 },
+        { "lightsalmon3",         0xcd8162 },
+        { "lightsalmon4",         0x8b5742 },
+        { "lightseagreen",        0x20b2aa },
+        { "lightskyblue",         0x87cefa },
+        { "lightskyblue1",        0xb0e2ff },
+        { "lightskyblue2",        0xa4d3ee },
+        { "lightskyblue3",        0x8db6cd },
+        { "lightskyblue4",        0x607b8b },
+        { "lightslateblue",       0x8470ff },
+        { "lightslategray",       0x778899 },
+        { "lightslategrey",       0x778899 },
+        { "lightsteelblue",       0xb0c4de },
+        { "lightsteelblue1",      0xcae1ff },
+        { "lightsteelblue2",      0xbcd2ee },
+        { "lightsteelblue3",      0xa2b5cd },
+        { "lightsteelblue4",      0x6e7b8b },
+        { "lightyellow",          0xffffe0 },
+        { "lightyellow1",         0xffffe0 },
+        { "lightyellow2",         0xeeeed1 },
+        { "lightyellow3",         0xcdcdb4 },
+        { "lightyellow4",         0x8b8b7a },
+        { "lime",                 0x00FF00 },
+        { "limegreen",            0x32cd32 },
+        { "linen",                0xFAF0E6 },
+        { "magenta",              0xFF00FF },
+        { "magenta1",             0xFF00FF },
+        { "magenta2",             0xEE00EE },
+        { "magenta3",             0xCD00CD },
+        { "magenta4",             0x8B008B },
+        { "maroon",               0x800000 },
+        { "maroon",               0xB03060 },
+        { "maroon1",              0xFF34B3 },
+        { "maroon2",              0xEE30A7 },
+        { "maroon3",              0xCD2990 },
+        { "maroon4",              0x8B1C62 },
+        { "mediumaquamarine",     0x66cdaa },
+        { "mediumblue",           0x0000cd },
+        { "mediumforestgreen",    0x32814b },
+        { "mediumgoldenrod",      0xd1c166 },
+        { "mediumorchid",         0xba55d3 },
+        { "mediumorchid1",        0xe066ff },
+        { "mediumorchid2",        0xd15fee },
+        { "mediumorchid3",        0xb452cd },
+        { "mediumorchid4",        0x7a378b },
+        { "mediumpurple",         0x9370db },
+        { "mediumpurple1",        0xab82ff },
+        { "mediumpurple2",        0x9f79ee },
+        { "mediumpurple3",        0x8968cd },
+        { "mediumpurple4",        0x5d478b },
+        { "mediumseagreen",       0x3cb371 },
+        { "mediumslateblue",      0x7b68ee },
+        { "mediumspringgreen",    0x00fa9a },
+        { "mediumturquoise",      0x48d1cc },
+        { "mediumvioletred",      0xc71585 },
+        { "midnightblue",         0x191970 },
+        { "mintcream",            0xf5fffa },
+        { "mistyrose",            0xffe4e1 },
+        { "mistyrose1",           0xffe4e1 },
+        { "mistyrose2",           0xeed5d2 },
+        { "mistyrose3",           0xcdb7b5 },
+        { "mistyrose4",           0x8b7d7b },
+        { "moccasin",             0xFFE4B5 },
+        { "navajowhite",          0xffdead },
+        { "navajowhite1",         0xffdead },
+        { "navajowhite2",         0xeecfa1 },
+        { "navajowhite3",         0xcdb38b },
+        { "navajowhite4",         0x8b795e },
+        { "navy",                 0x000080 },
+        { "navyblue",             0x000080 },
+        { "none",                 0x0000FF },
+        { "oldlace",              0xfdf5e6 },
+        { "olive",                0x808000 },
+        { "olivedrab",            0x6b8e23 },
+        { "olivedrab1",           0xc0ff3e },
+        { "olivedrab2",           0xb3ee3a },
+        { "olivedrab3",           0x9acd32 },
+        { "olivedrab4",           0x698b22 },
+        { "opaque",               0x000000 },
+        { "orange",               0xFFA500 },
+        { "orange1",              0xFFA500 },
+        { "orange2",              0xEE9A00 },
+        { "orange3",              0xCD8500 },
+        { "orange4",              0x8B5A00 },
+        { "orangered",            0xff4500 },
+        { "orangered1",           0xff4500 },
+        { "orangered2",           0xee4000 },
+        { "orangered3",           0xcd3700 },
+        { "orangered4",           0x8b2500 },
+        { "orchid",               0xDA70D6 },
+        { "orchid1",              0xFF83FA },
+        { "orchid2",              0xEE7AE9 },
+        { "orchid3",              0xCD69C9 },
+        { "orchid4",              0x8B4789 },
+        { "palegoldenrod",        0xeee8aa },
+        { "palegreen",            0x98fb98 },
+        { "palegreen1",           0x9aff9a },
+        { "palegreen2",           0x90ee90 },
+        { "palegreen3",           0x7ccd7c },
+        { "palegreen4",           0x548b54 },
+        { "paleturquoise",        0xafeeee },
+        { "paleturquoise1",       0xbbffff },
+        { "paleturquoise2",       0xaeeeee },
+        { "paleturquoise3",       0x96cdcd },
+        { "paleturquoise4",       0x668b8b },
+        { "palevioletred",        0xdb7093 },
+        { "palevioletred1",       0xff82ab },
+        { "palevioletred2",       0xee799f },
+        { "palevioletred3",       0xcd6889 },
+        { "palevioletred4",       0x8b475d },
+        { "papayawhip",           0xffefd5 },
+        { "peachpuff",            0xffdab9 },
+        { "peachpuff1",           0xffdab9 },
+        { "peachpuff2",           0xeecbad },
+        { "peachpuff3",           0xcdaf95 },
+        { "peachpuff4",           0x8b7765 },
+        { "peru",                 0xCD853F },
+        { "pink",                 0xFFC0CB },
+        { "pink1",                0xFFB5C5 },
+        { "pink2",                0xEEA9B8 },
+        { "pink3",                0xCD919E },
+        { "pink4",                0x8B636C },
+        { "plum",                 0xDDA0DD },
+        { "plum1",                0xFFBBFF },
+        { "plum2",                0xEEAEEE },
+        { "plum3",                0xCD96CD },
+        { "plum4",                0x8B668B },
+        { "powderblue",           0xb0e0e6 },
+        { "purple",               0x800080 },
+        { "purple",               0xA020F0 },
+        { "purple1",              0x9B30FF },
+        { "purple2",              0x912CEE },
+        { "purple3",              0x7D26CD },
+        { "purple4",              0x551A8B },
+        { "red",                  0xFF0000 },
+        { "red1",                 0xFF0000 },
+        { "red2",                 0xEE0000 },
+        { "red3",                 0xCD0000 },
+        { "red4",                 0x8B0000 },
+        { "rosybrown",            0xbc8f8f },
+        { "rosybrown1",           0xffc1c1 },
+        { "rosybrown2",           0xeeb4b4 },
+        { "rosybrown3",           0xcd9b9b },
+        { "rosybrown4",           0x8b6969 },
+        { "royalblue",            0x4169e1 },
+        { "royalblue1",           0x4876ff },
+        { "royalblue2",           0x436eee },
+        { "royalblue3",           0x3a5fcd },
+        { "royalblue4",           0x27408b },
+        { "saddlebrown",          0x8b4513 },
+        { "salmon",               0xFA8072 },
+        { "salmon1",              0xFF8C69 },
+        { "salmon2",              0xEE8262 },
+        { "salmon3",              0xCD7054 },
+        { "salmon4",              0x8B4C39 },
+        { "sandybrown",           0xf4a460 },
+        { "seagreen",             0x2e8b57 },
+        { "seagreen1",            0x54ff9f },
+        { "seagreen2",            0x4eee94 },
+        { "seagreen3",            0x43cd80 },
+        { "seagreen4",            0x2e8b57 },
+        { "seashell",             0xFFF5EE },
+        { "seashell1",            0xFFF5EE },
+        { "seashell2",            0xEEE5DE },
+        { "seashell3",            0xCDC5BF },
+        { "seashell4",            0x8B8682 },
+        { "sienna",               0xA0522D },
+        { "sienna1",              0xFF8247 },
+        { "sienna2",              0xEE7942 },
+        { "sienna3",              0xCD6839 },
+        { "sienna4",              0x8B4726 },
+        { "silver",               0xC0C0C0 },
+        { "skyblue",              0x87ceeb },
+        { "skyblue1",             0x87ceff },
+        { "skyblue2",             0x7ec0ee },
+        { "skyblue3",             0x6ca6cd },
+        { "skyblue4",             0x4a708b },
+        { "slateblue",            0x6a5acd },
+        { "slateblue1",           0x836fff },
+        { "slateblue2",           0x7a67ee },
+        { "slateblue3",           0x6959cd },
+        { "slateblue4",           0x473c8b },
+        { "slategray",            0x708090 },
+        { "slategray1",           0xc6e2ff },
+        { "slategray2",           0xb9d3ee },
+        { "slategray3",           0x9fb6cd },
+        { "slategray4",           0x6c7b8b },
+        { "slategrey",            0x708090 },
+        { "snow",                 0xFFFAFA },
+        { "snow1",                0xFFFAFA },
+        { "snow2",                0xEEE9E9 },
+        { "snow3",                0xCDC9C9 },
+        { "snow4",                0x8B8989 },
+        { "springgreen",          0x00ff7f },
+        { "springgreen1",         0x00ff7f },
+        { "springgreen2",         0x00ee76 },
+        { "springgreen3",         0x00cd66 },
+        { "springgreen4",         0x008b45 },
+        { "steelblue",            0x4682b4 },
+        { "steelblue1",           0x63b8ff },
+        { "steelblue2",           0x5cacee },
+        { "steelblue3",           0x4f94cd },
+        { "steelblue4",           0x36648b },
+        { "tan",                  0xD2B48C },
+        { "tan1",                 0xFFA54F },
+        { "tan2",                 0xEE9A49 },
+        { "tan3",                 0xCD853F },
+        { "tan4",                 0x8B5A2B },
+        { "teal",                 0x008080 },
+        { "thistle",              0xD8BFD8 },
+        { "thistle1",             0xFFE1FF },
+        { "thistle2",             0xEED2EE },
+        { "thistle3",             0xCDB5CD },
+        { "thistle4",             0x8B7B8B },
+        { "tomato",               0xFF6347 },
+        { "tomato1",              0xFF6347 },
+        { "tomato2",              0xEE5C42 },
+        { "tomato3",              0xCD4F39 },
+        { "tomato4",              0x8B3626 },
+        { "transparent",          0x0000FF },
+        { "turquoise",            0x40E0D0 },
+        { "turquoise1",           0x00F5FF },
+        { "turquoise2",           0x00E5EE },
+        { "turquoise3",           0x00C5CD },
+        { "turquoise4",           0x00868B },
+        { "violet",               0xEE82EE },
+        { "violetred",            0xd02090 },
+        { "violetred1",           0xff3e96 },
+        { "violetred2",           0xee3a8c },
+        { "violetred3",           0xcd3278 },
+        { "violetred4",           0x8b2252 },
+        { "wheat",                0xF5DEB3 },
+        { "wheat1",               0xFFE7BA },
+        { "wheat2",               0xEED8AE },
+        { "wheat3",               0xCDBA96 },
+        { "wheat4",               0x8B7E66 },
+        { "white",                0xFFFFFF },
+        { "whitesmoke",           0xf5f5f5 },
+        { "yellow",               0xFFFF00 },
+        { "yellow1",              0xFFFF00 },
+        { "yellow2",              0xEEEE00 },
+        { "yellow3",              0xCDCD00 },
+        { "yellow4",              0x8B8B00 },
+        { "yellowgreen",          0x9acd32 },
+#endif /* EXTENDED_XPM_COLORS */
+        {"none",                  0xFFFFFF}
+    };
+
+    if (spec[0] == '#') {
+        char buf[7];
+        switch(speclen) {
+        case 4:
+            buf[0] = buf[1] = spec[1];
+            buf[2] = buf[3] = spec[2];
+            buf[4] = buf[5] = spec[3];
+            break;
+        case 7:
+            SDL_memcpy(buf, spec + 1, 6);
+            break;
+        case 13:
+            buf[0] = spec[1];
+            buf[1] = spec[2];
+            buf[2] = spec[5];
+            buf[3] = spec[6];
+            buf[4] = spec[9];
+            buf[5] = spec[10];
+            break;
+        }
+        buf[6] = '\0';
+        *rgb = (Uint32)SDL_strtol(buf, NULL, 16);
+        return 1;
+    } else {
+        size_t i;
+        for (i = 0; i < SDL_arraysize(known); i++) {
+            if (SDL_strncasecmp(known[i].name, spec, speclen) == 0) {
+                *rgb = known[i].rgb;
                 return 1;
-        } else {
-                int i;
-                for (i = 0; i < ARRAYSIZE(known); i++)
-                        if (string_equal(known[i].name, spec, speclen)) {
-                                *rgb = known[i].rgb;
-                                return 1;
-                        }
-                return 0;
+            }
         }
+        return 0;
+    }
 }
 
 #ifndef MAX
@@ -243,263 +920,278 @@ static const char *error;
  */
 static const char *get_next_line(const char ***lines, SDL_RWops *src, int len)
 {
-        char *linebufnew;
-        if (lines) {
-                return *(*lines)++;
+    char *linebufnew;
+
+    if (lines) {
+        return *(*lines)++;
+    } else {
+        char c;
+        int n;
+        do {
+            if (SDL_RWread(src, &c, 1, 1) <= 0) {
+                error = "Premature end of data";
+                return NULL;
+            }
+        } while (c != '"');
+        if (len) {
+            len += 4;   /* "\",\n\0" */
+            if (len > buflen){
+                buflen = len;
+                linebufnew = (char *)SDL_realloc(linebuf, buflen);
+                if (!linebufnew) {
+                    SDL_free(linebuf);
+                    error = "Out of memory";
+                    return NULL;
+                }
+                linebuf = linebufnew;
+            }
+            if (SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
+                error = "Premature end of data";
+                return NULL;
+            }
+            n = len - 2;
         } else {
-                char c;
-                int n;
-                do {
-                        if (SDL_RWread(src, &c, 1, 1) <= 0) {
-                                error = "Premature end of data";
-                                return NULL;
-                        }
-                } while (c != '"');
-                if (len) {
-                        len += 4;        /* "\",\n\0" */
-                        if (len > buflen){
-                                buflen = len;
-                                linebufnew = realloc(linebuf, buflen);
-                                if(!linebufnew) {
-                                        free(linebuf);
-                                        error = "Out of memory";
-                                        return NULL;
-                                }
-                                linebuf = linebufnew;
-                        }
-                        if (SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
-                                error = "Premature end of data";
-                                return NULL;
-                        }
-                        n = len - 2;
-                } else {
-                        n = 0;
-                        do {
-                                if (n >= buflen - 1) {
-                                        if (buflen == 0)
-                                                buflen = 16;
-                                        buflen *= 2;
-                                        linebufnew = realloc(linebuf, buflen);
-                                        if(!linebufnew) {
-                                                free(linebuf);
-                                                error = "Out of memory";
-                                                return NULL;
-                                        }
-                                        linebuf = linebufnew;
-                                }
-                                if (SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
-                                        error = "Premature end of data";
-                                        return NULL;
-                                }
-                        } while (linebuf[n++] != '"');
-                        n--;
+            n = 0;
+            do {
+                if (n >= buflen - 1) {
+                    if (buflen == 0)
+                        buflen = 16;
+                    buflen *= 2;
+                    linebufnew = (char *)SDL_realloc(linebuf, buflen);
+                    if (!linebufnew) {
+                        SDL_free(linebuf);
+                        error = "Out of memory";
+                        return NULL;
+                    }
+                    linebuf = linebufnew;
                 }
-                linebuf[n] = '\0';
-                return linebuf;
+                if (SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
+                    error = "Premature end of data";
+                    return NULL;
+                }
+            } while (linebuf[n++] != '"');
+            n--;
         }
+        linebuf[n] = '\0';
+        return linebuf;
+    }
 }
 
-#define SKIPSPACE(p)                            \
-do {                                            \
-        while (isspace((unsigned char)*(p)))        \
-              ++(p);                                \
+#define SKIPSPACE(p)                \
+do {                        \
+    while (SDL_isspace((unsigned char)*(p))) \
+          ++(p);                \
 } while (0)
 
-#define SKIPNONSPACE(p)                                 \
-do {                                                    \
-        while (!isspace((unsigned char)*(p)) && *p)        \
-              ++(p);                                        \
+#define SKIPNONSPACE(p)                 \
+do {                            \
+    while (!SDL_isspace((unsigned char)*(p)) && *p)  \
+          ++(p);                    \
 } while (0)
 
 /* read XPM from either array or RWops */
 static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src)
 {
-        SDL_Surface *image = NULL;
-        int indexc;
-        int x, y;
-        int w, h, ncolors, cpp;
-        int indexed;
-        Uint8 *dst;
-        struct color_hash *colors = NULL;
-        SDL_Color *im_colors = NULL;
-        char *keystrings = NULL, *nextkey;
-        const char *line;
-        const char ***xpmlines = NULL;
-        int pixels_len;
-
-        error = NULL;
-        linebuf = NULL;
-        buflen = 0;
-
-        if (xpm)
-                xpmlines = &xpm;
+    Sint64 start = 0;
+    SDL_Surface *image = NULL;
+    int index;
+    int x, y;
+    int w, h, ncolors, cpp;
+    int indexed;
+    Uint8 *dst;
+    struct color_hash *colors = NULL;
+    SDL_Color *im_colors = NULL;
+    char *keystrings = NULL, *nextkey;
+    const char *line;
+    const char ***xpmlines = NULL;
+    int pixels_len;
+
+    error = NULL;
+    linebuf = NULL;
+    buflen = 0;
+
+    if (src)
+        start = SDL_RWtell(src);
+
+    if (xpm)
+        xpmlines = &xpm;
 
+    line = get_next_line(xpmlines, src, 0);
+    if (!line)
+        goto done;
+    /*
+     * The header string of an XPMv3 image has the format
+     *
+     * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
+     *
+     * where the hotspot coords are intended for mouse cursors.
+     * Right now we don't use the hotspots but it should be handled
+     * one day.
+     */
+    if (SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
+       || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
+        error = "Invalid format description";
+        goto done;
+    }
+
+    keystrings = (char *)SDL_malloc(ncolors * cpp);
+    if (!keystrings) {
+        error = "Out of memory";
+        goto done;
+    }
+    nextkey = keystrings;
+
+    /* Create the new surface */
+    if (ncolors <= 256) {
+        indexed = 1;
+        image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
+                         0, 0, 0, 0);
+        im_colors = image->format->palette->colors;
+        image->format->palette->ncolors = ncolors;
+    } else {
+        indexed = 0;
+        image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
+                         0xff0000, 0x00ff00, 0x0000ff, 0);
+    }
+    if (!image) {
+        /* Hmm, some SDL error (out of memory?) */
+        goto done;
+    }
+
+    /* Read the colors */
+    colors = create_colorhash(ncolors);
+    if (!colors) {
+        error = "Out of memory";
+        goto done;
+    }
+    for (index = 0; index < ncolors; ++index ) {
+        const char *p;
         line = get_next_line(xpmlines, src, 0);
         if (!line)
-                goto done;
-        /*
-         * The header string of an XPMv3 image has the format
-         *
-         * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
-         *
-         * where the hotspot coords are intended for mouse cursors.
-         * Right now we don't use the hotspots but it should be handled
-         * one day.
-         */
-        if (sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
-           || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
-                error = "Invalid format description";
-                goto done;
-        }
+            goto done;
 
-        keystrings = malloc(ncolors * cpp);
-        if (!keystrings) {
-                error = "Out of memory";
-                goto done;
-        }
-        nextkey = keystrings;
-
-        /* Create the new surface */
-        if (ncolors <= 256) {
-                indexed = 1;
-                image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
-                                             0, 0, 0, 0);
-                im_colors = image->format->palette->colors;
-                image->format->palette->ncolors = ncolors;
-        } else {
-                indexed = 0;
-                image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
-                                             0xff0000, 0x00ff00, 0x0000ff, 0);
-        }
-        if (!image) {
-                /* Hmm, some SDL error (out of memory?) */
-                goto done;
-        }
+        p = line + cpp + 1;
 
-        /* Read the colors */
-        colors = create_colorhash(ncolors);
-        if (!colors) {
-                error = "Out of memory";
+        /* parse a colour definition */
+        for (;;) {
+            char nametype;
+            const char *colname;
+            Uint32 rgb, pixel;
+
+            SKIPSPACE(p);
+            if (!*p) {
+                error = "colour parse error";
                 goto done;
+            }
+            nametype = *p;
+            SKIPNONSPACE(p);
+            SKIPSPACE(p);
+            colname = p;
+            SKIPNONSPACE(p);
+            if (nametype == 's')
+                continue;      /* skip symbolic colour names */
+
+            if (!color_to_rgb(colname, (int)(p - colname), &rgb))
+                continue;
+
+            SDL_memcpy(nextkey, line, cpp);
+            if (indexed) {
+                SDL_Color *c = im_colors + index;
+                c->r = (Uint8)(rgb >> 16);
+                c->g = (Uint8)(rgb >> 8);
+                c->b = (Uint8)(rgb);
+                pixel = index;
+            } else
+                pixel = rgb;
+            add_colorhash(colors, nextkey, cpp, pixel);
+            nextkey += cpp;
+            if (rgb == 0xffffffff)
+                SDL_SetColorKey(image, SDL_TRUE, pixel);
+            break;
         }
-        for (indexc = 0; indexc < ncolors; ++indexc ) {
-                const char *p;
-                line = get_next_line(xpmlines, src, 0);
-                if (!line)
-                        goto done;
-
-                p = line + cpp + 1;
-
-                /* parse a colour definition */
-                for (;;) {
-                        char nametype;
-                        const char *colname;
-                        Uint32 rgb, pixel;
-
-                        SKIPSPACE(p);
-                        if (!*p) {
-                                error = "colour parse error";
-                                goto done;
-                        }
-                        nametype = *p;
-                        SKIPNONSPACE(p);
-                        SKIPSPACE(p);
-                        colname = p;
-                        SKIPNONSPACE(p);
-                        if (nametype == 's')
-                                continue;      /* skip symbolic colour names */
-
-                        if (!color_to_rgb(colname, p - colname, &rgb))
-                                continue;
-
-                        memcpy(nextkey, line, cpp);
-                        if (indexed) {
-                                SDL_Color *c = im_colors + indexc;
-                                c->r = (Uint8)(rgb >> 16);
-                                c->g = (Uint8)(rgb >> 8);
-                                c->b = (Uint8)(rgb);
-                                pixel = indexc;
-                        } else
-                                pixel = rgb;
-                        add_colorhash(colors, nextkey, cpp, pixel);
-                        nextkey += cpp;
-                        if (rgb == 0xffffffff)
-                                SDL_SetColorKey(image, SDL_SRCCOLORKEY, pixel);
-                        break;
-                }
-        }
+    }
 
-        /* Read the pixels */
-        pixels_len = w * cpp;
-        dst = image->pixels;
-        for (y = 0; y < h; y++) {
-                line = get_next_line(xpmlines, src, pixels_len);
-                if (indexed) {
-                        /* optimization for some common cases */
-                        if (cpp == 1)
-                                for (x = 0; x < w; x++)
-                                        dst[x] = (Uint8)QUICK_COLORHASH(colors,
-                                                                 line + x);
-                        else
-                                for (x = 0; x < w; x++)
-                                        dst[x] = (Uint8)get_colorhash(colors,
-                                                               line + x * cpp,
-                                                               cpp);
-                } else {
-                        for (x = 0; x < w; x++)
-                                ((Uint32*)dst)[x] = get_colorhash(colors,
-                                                                line + x * cpp,
-                                                                  cpp);
-                }
-                dst += image->pitch;
+    /* Read the pixels */
+    pixels_len = w * cpp;
+    dst = (Uint8 *)image->pixels;
+    for (y = 0; y < h; y++) {
+        line = get_next_line(xpmlines, src, pixels_len);
+        if (!line)
+            goto done;
+
+        if (indexed) {
+            /* optimization for some common cases */
+            if (cpp == 1)
+                for (x = 0; x < w; x++)
+                    dst[x] = (Uint8)QUICK_COLORHASH(colors,
+                                 line + x);
+            else
+                for (x = 0; x < w; x++)
+                    dst[x] = (Uint8)get_colorhash(colors,
+                                   line + x * cpp,
+                                   cpp);
+        } else {
+            for (x = 0; x < w; x++)
+                ((Uint32*)dst)[x] = get_colorhash(colors,
+                                line + x * cpp,
+                                  cpp);
         }
+        dst += image->pitch;
+    }
 
 done:
-        if (error) {
-                SDL_FreeSurface(image);
-                image = NULL;
-                SDL_SetError(error);
+    if (error) {
+        if ( src )
+            SDL_RWseek(src, start, RW_SEEK_SET);
+        if ( image ) {
+            SDL_FreeSurface(image);
+            image = NULL;
         }
-        free(keystrings);
-        free_colorhash(colors);
-        free(linebuf);
-        return(image);
+        IMG_SetError("%s", error);
+    }
+    if (keystrings)
+        SDL_free(keystrings);
+    free_colorhash(colors);
+    if (linebuf)
+        SDL_free(linebuf);
+    return(image);
 }
 
 /* Load a XPM type image from an RWops datasource */
-#if 0
 SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
 {
-        if ( !src ) {
-                /* The error message has been set in SDL_RWFromFile */
-                return NULL;
-        }
-        return load_xpm(NULL, src);
+    if ( !src ) {
+        /* The error message has been set in SDL_RWFromFile */
+        return NULL;
+    }
+    return load_xpm(NULL, src);
 }
-#endif
 
-static inline SDL_Surface *IMG_ReadXPMFromArray(const char **xpm)
+SDL_Surface *IMG_ReadXPMFromArray(const char **xpm)
 {
-        return load_xpm(xpm, NULL);
+    if (!xpm) {
+        IMG_SetError("array is NULL");
+        return NULL;
+    }
+    return load_xpm(xpm, NULL);
 }
 
 #else  /* not LOAD_XPM */
 
 /* See if an image is contained in a data source */
-#if 0
 int IMG_isXPM(SDL_RWops *src)
 {
-        return(0);
+    return(0);
 }
 
+
 /* Load a XPM type image from an SDL datasource */
 SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
 {
-        return(NULL);
+    return(NULL);
 }
-#endif
 
-static inline SDL_Surface *IMG_ReadXPMFromArray(const char **xpm)
+SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
 {
     return NULL;
 }
diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm
index cf72960dfc9048d1ab23b3c59ed4d29d65f4c404..30259d55efd623ca9087209df7ae03fbca10e5dd 100644
--- a/src/sdl/SDL_icon.xpm
+++ b/src/sdl/SDL_icon.xpm
@@ -1,425 +1,213 @@
 /* XPM */
-static char * C:\Repo\srb2\src\sdl\SDL_icon_xpm[] = {
-"32 32 390 2",
-"  	c None",
-". 	c #4F4F70",
-"+ 	c #4D4D87",
-"@ 	c #4D4D84",
-"# 	c #4E4E6C",
-"$ 	c #6C6C95",
-"% 	c #5E5EB2",
-"& 	c #6B6BE7",
-"* 	c #7373F9",
-"= 	c #7C7CFF",
-"- 	c #6F70E7",
-"; 	c #494BB2",
-"> 	c #4F4FA3",
-", 	c #6464D4",
-"' 	c #7979F5",
-") 	c #5F5FCA",
-"! 	c #5D5D93",
-"~ 	c #3A3A9F",
-"{ 	c #6060AC",
-"] 	c #777793",
-"^ 	c #5C5CB3",
-"/ 	c #7373EA",
-"( 	c #7A7AFF",
-"_ 	c #7575FF",
-": 	c #7979FF",
-"< 	c #6264DD",
-"[ 	c #47478C",
-"} 	c #564567",
-"| 	c #4647D0",
-"1 	c #5C5CAE",
-"2 	c #5E5EFF",
-"3 	c #2929FF",
-"4 	c #1D1DFF",
-"5 	c #1919D1",
-"6 	c #4F4F90",
-"7 	c #1E1ECE",
-"8 	c #5858FF",
-"9 	c #6767A8",
-"0 	c #4949A0",
-"a 	c #7070FB",
-"b 	c #7D7DFF",
-"c 	c #7777FF",
-"d 	c #7373FF",
-"e 	c #7272FF",
-"f 	c #7878FF",
-"g 	c #6465D8",
-"h 	c #363886",
-"i 	c #9F7655",
-"j 	c #C89B5C",
-"k 	c #1D1CB7",
-"l 	c #3031B1",
-"m 	c #1919F4",
-"n 	c #1111FF",
-"o 	c #1818FF",
-"p 	c #1B1BFF",
-"q 	c #1C1CFF",
-"r 	c #2626B3",
-"s 	c #1E1EC8",
-"t 	c #1A1AE8",
-"u 	c #24249F",
-"v 	c #2F2FD2",
-"w 	c #7676FF",
-"x 	c #6869E2",
-"y 	c #414290",
-"z 	c #8C6751",
-"A 	c #FCBA68",
-"B 	c #E9BD7D",
-"C 	c #201EB8",
-"D 	c #090AB8",
-"E 	c #1616EB",
-"F 	c #1818FD",
-"G 	c #1414EE",
-"H 	c #1010E1",
-"I 	c #0E0EE2",
-"J 	c #0E0EF4",
-"K 	c #0606B2",
-"L 	c #7A7A89",
-"M 	c #0C0C9A",
-"N 	c #0A0AA7",
-"O 	c #2424E4",
-"P 	c #6669E6",
-"Q 	c #4F4A8F",
-"R 	c #BF853B",
-"S 	c #FFD98D",
-"T 	c #CDAB76",
-"U 	c #1717C4",
-"V 	c #0F10BA",
-"W 	c #0909B6",
-"X 	c #0505C3",
-"Y 	c #0000B6",
-"Z 	c #0000BE",
-"` 	c #0000AD",
-" .	c #1D1D83",
-"..	c #63638E",
-"+.	c #090975",
-"@.	c #1414F3",
-"#.	c #5B5BFF",
-"$.	c #7B7BFF",
-"%.	c #7070FF",
-"&.	c #6E6EFF",
-"*.	c #7172F6",
-"=.	c #625DAF",
-"-.	c #BA9E6C",
-";.	c #887167",
-">.	c #090DF2",
-",.	c #1313BE",
-"'.	c #000085",
-").	c #0000AC",
-"!.	c #0202AA",
-"~.	c #242488",
-"{.	c #1414C7",
-"].	c #1717FF",
-"^.	c #5959FF",
-"/.	c #7F7FFF",
-"(.	c #7474FF",
-"_.	c #7171FF",
-":.	c #8686FF",
-"<.	c #7574FF",
-"[.	c #797CFF",
-"}.	c #5756B8",
-"|.	c #1C19A4",
-"1.	c #1617FF",
-"2.	c #1212BD",
-"3.	c #040485",
-"4.	c #0707A4",
-"5.	c #1B1B71",
-"6.	c #373797",
-"7.	c #1616FF",
-"8.	c #5050FF",
-"9.	c #8080FF",
-"0.	c #AAAAFF",
-"a.	c #AEAEF6",
-"b.	c #8A8AEF",
-"c.	c #6969FB",
-"d.	c #2728FF",
-"e.	c #1314FF",
-"f.	c #1919FF",
-"g.	c #1313E8",
-"h.	c #1F1FF4",
-"i.	c #5454FF",
-"j.	c #6D6DF0",
-"k.	c #6868B5",
-"l.	c #0B0BB8",
-"m.	c #1212C5",
-"n.	c #1616FC",
-"o.	c #1515FF",
-"p.	c #1212FF",
-"q.	c #2323FF",
-"r.	c #3636FF",
-"s.	c #4040FF",
-"t.	c #4343F9",
-"u.	c #5D5DB8",
-"v.	c #7F7F92",
-"w.	c #878793",
-"x.	c #4B4B94",
-"y.	c #0B0CE2",
-"z.	c #1313FF",
-"A.	c #4C4CFF",
-"B.	c #8282FF",
-"C.	c #7171ED",
-"D.	c #636394",
-"E.	c #575785",
-"F.	c #A9A99C",
-"G.	c #1414BC",
-"H.	c #1414FF",
-"I.	c #0707FD",
-"J.	c #2525AA",
-"K.	c #A8A8A4",
-"L.	c #EBEBE2",
-"M.	c #F9F9F2",
-"N.	c #E1E1CC",
-"O.	c #4D4D9F",
-"P.	c #0B0BF7",
-"Q.	c #2121FF",
-"R.	c #3232FF",
-"S.	c #5555FF",
-"T.	c #6161B4",
-"U.	c #B5B5B2",
-"V.	c #FFFFF8",
-"W.	c #4F4F9A",
-"X.	c #0B0BF5",
-"Y.	c #1616C5",
-"Z.	c #A8A8A1",
-"`.	c #FFFFFC",
-" +	c #FFFFFF",
-".+	c #C0C0C4",
-"++	c #1212D4",
-"@+	c #4444FF",
-"#+	c #6464FF",
-"$+	c #8383FF",
-"%+	c #6767C3",
-"&+	c #E4E4E4",
-"*+	c #9494AE",
-"=+	c #0808DF",
-"-+	c #0D0DF2",
-";+	c #61619A",
-">+	c #F1F1E0",
-",+	c #E8E8DD",
-"'+	c #2424BB",
-")+	c #1010FF",
-"!+	c #3434FF",
-"~+	c #6161FF",
-"{+	c #6969D2",
-"]+	c #EFEFF0",
-"^+	c #C2C2BA",
-"/+	c #1010B6",
-"(+	c #0909AC",
-"_+	c #A4A49A",
-":+	c #EAEADE",
-"<+	c #2525B8",
-"[+	c #2F2FFF",
-"}+	c #3C3CB5",
-"|+	c #EEEEEE",
-"1+	c #BBBBAD",
-"2+	c #0B0B56",
-"3+	c #0B0BFC",
-"4+	c #1212EF",
-"5+	c #0C0C3E",
-"6+	c #919187",
-"7+	c #DEDED6",
-"8+	c #1F1FC0",
-"9+	c #1A1AFF",
-"0+	c #1717FA",
-"a+	c #1515F8",
-"b+	c #1111FC",
-"c+	c #494992",
-"d+	c #999998",
-"e+	c #3E3E3B",
-"f+	c #3C3C99",
-"g+	c #535397",
-"h+	c #5A5A4D",
-"i+	c #6F6F70",
-"j+	c #BFBFC9",
-"k+	c #1111D6",
-"l+	c #1515F1",
-"m+	c #0F0FE2",
-"n+	c #0D0DD9",
-"o+	c #0909CD",
-"p+	c #0808C7",
-"q+	c #0505C7",
-"r+	c #0303CB",
-"s+	c #0101C0",
-"t+	c #0202AF",
-"u+	c #0606AC",
-"v+	c #121283",
-"w+	c #BBBBBB",
-"x+	c #BEBEBE",
-"y+	c #2F2F2E",
-"z+	c #C7C8BB",
-"A+	c #D8DAD1",
-"B+	c #272828",
-"C+	c #929292",
-"D+	c #8688C7",
-"E+	c #0506F6",
-"F+	c #1616F5",
-"G+	c #0B0BD3",
-"H+	c #0202B6",
-"I+	c #0000AF",
-"J+	c #0000B4",
-"K+	c #0000BD",
-"L+	c #0000BB",
-"M+	c #00009E",
-"N+	c #2C2C7E",
-"O+	c #6A6A8B",
-"P+	c #959595",
-"Q+	c #F0F0F1",
-"R+	c #E1E1E1",
-"S+	c #8C8E90",
-"T+	c #BEBEBF",
-"U+	c #C9C7C5",
-"V+	c #939699",
-"W+	c #E7EAED",
-"X+	c #CBCBC7",
-"Y+	c #413B9B",
-"Z+	c #0607DD",
-"`+	c #0C0CE2",
-" @	c #0303B9",
-".@	c #0000A8",
-"+@	c #181888",
-"@@	c #6A6A6A",
-"#@	c #626263",
-"$@	c #4B4B4C",
-"%@	c #3E3B36",
-"&@	c #9B805C",
-"*@	c #D9B07D",
-"=@	c #C9AE89",
-"-@	c #B9AF9E",
-";@	c #C7C5C4",
-">@	c #CBCCCF",
-",@	c #C7C6C6",
-"'@	c #AEA59A",
-")@	c #B69974",
-"!@	c #D8B87F",
-"~@	c #9B8272",
-"{@	c #0E0B9B",
-"]@	c #0000B7",
-"^@	c #0000B8",
-"/@	c #000082",
-"(@	c #00007A",
-"_@	c #636379",
-":@	c #62533E",
-"<@	c #B59B6C",
-"[@	c #DEB07B",
-"}@	c #FECC90",
-"|@	c #FFCE92",
-"1@	c #FEC98C",
-"2@	c #F1BD82",
-"3@	c #D1A979",
-"4@	c #BC9E73",
-"5@	c #CCA777",
-"6@	c #EAB980",
-"7@	c #FFCD90",
-"8@	c #FFD595",
-"9@	c #FDD782",
-"0@	c #413678",
-"a@	c #0000AE",
-"b@	c #000077",
-"c@	c #010193",
-"d@	c #0C0CE4",
-"e@	c #38389E",
-"f@	c #EEC585",
-"g@	c #FFDA9D",
-"h@	c #FFC992",
-"i@	c #FFC88F",
-"j@	c #FFC990",
-"k@	c #FFCE93",
-"l@	c #FFD094",
-"m@	c #FFCC92",
-"n@	c #C9A174",
-"o@	c #EDBD88",
-"p@	c #FAD287",
-"q@	c #3A2F7F",
-"r@	c #0000BA",
-"s@	c #0000B0",
-"t@	c #0101B2",
-"u@	c #1111ED",
-"v@	c #1919C1",
-"w@	c #95887C",
-"x@	c #DCAC6E",
-"y@	c #FFD393",
-"z@	c #FFCD94",
-"A@	c #FFCA93",
-"B@	c #FFC991",
-"C@	c #FFC78E",
-"D@	c #FFCB91",
-"E@	c #E0B581",
-"F@	c #BB9A6F",
-"G@	c #FFDC97",
-"H@	c #C1A173",
-"I@	c #0E0B9A",
-"J@	c #0000B5",
-"K@	c #0101B6",
-"L@	c #1010E0",
-"M@	c #1616EC",
-"N@	c #A68156",
-"O@	c #E7AC6B",
-"P@	c #FFC582",
-"Q@	c #FFCF8F",
-"R@	c #FFD195",
-"S@	c #FFD296",
-"T@	c #FFD396",
-"U@	c #FFD193",
-"V@	c #FFD28F",
-"W@	c #D2A96B",
-"X@	c #2F2482",
-"Y@	c #0000C1",
-"Z@	c #0000C0",
-"`@	c #0000BF",
-" #	c #0101BF",
-".#	c #1212F0",
-"+#	c #767698",
-"@#	c #9C866E",
-"##	c #A9865D",
-"$#	c #C0915D",
-"%#	c #C89760",
-"&#	c #C29360",
-"*#	c #AD8A61",
-"=#	c #9D8971",
-"-#	c #7F7A7A",
-";#	c #70708F",
-">#	c #6F6F91",
-",#	c #575788",
-"'#	c #464687",
-")#	c #2F2F87",
-"!#	c #15158F",
-"~#	c #0101A8",
-"{#	c #1313FB",
-"]#	c #57579F",
-"^#	c #343487",
-"/#	c #434388",
+static const char *SDL_icon_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 175 2 ",
+"   c None",
+".  c #2E2E2E",
+"X  c #3C3C3C",
+"o  c #493939",
+"O  c #4E473F",
+"+  c #161658",
+"@  c #131369",
+"#  c #06067B",
+"$  c #111173",
+"%  c #16167F",
+"&  c #252567",
+"*  c #372B7C",
+"=  c #3D3679",
+"-  c #41414A",
+";  c #575655",
+":  c #6A5841",
+">  c #5B4B72",
+",  c #616160",
+"<  c #7B7B7B",
+"1  c #906E49",
+"2  c #89685D",
+"3  c #A67B4A",
+"4  c #AA7F50",
+"5  c #9B7560",
+"6  c #856C78",
+"7  c #997B7D",
+"8  c #B48552",
+"9  c #BA8A55",
+"0  c #A48665",
+"q  c #B98F67",
+"w  c #B9946A",
+"e  c #B7937A",
+"r  c #C8955C",
+"t  c #CA9966",
+"y  c #DAA469",
+"u  c #C9A37B",
+"i  c #D7AB7B",
+"p  c #DFB07D",
+"a  c #EBAE6A",
+"s  c #E5B27A",
+"d  c #F1B779",
+"f  c #0A0A83",
+"g  c #05058B",
+"h  c #060687",
+"j  c #101089",
+"k  c #131382",
+"l  c #040494",
+"z  c #02029D",
+"x  c #0C0B9C",
+"c  c #120F9E",
+"v  c #19199B",
+"b  c #382D84",
+"n  c #39398D",
+"m  c #222296",
+"M  c #0101A6",
+"N  c #0A0AA2",
+"B  c #0202AC",
+"V  c #1919A2",
+"C  c #1616AD",
+"Z  c #0000B5",
+"A  c #0202BC",
+"S  c #0C0CB6",
+"D  c #1313B3",
+"F  c #1011BD",
+"G  c #1B1BBE",
+"H  c #2B2BAC",
+"J  c #3737A1",
+"K  c #2A26BE",
+"L  c #2A29B4",
+"P  c #3B3BB8",
+"I  c #48478B",
+"U  c #57578A",
+"Y  c #4A499A",
+"T  c #524F95",
+"R  c #565399",
+"E  c #4C4CA8",
+"W  c #524DA7",
+"Q  c #5353A4",
+"!  c #5555A9",
+"~  c #5555B4",
+"^  c #5656B7",
+"/  c #6464A6",
+"(  c #6F67B5",
+")  c #0404C3",
+"_  c #0707CA",
+"`  c #1414CB",
+"'  c #1A1AC6",
+"]  c #0A0AD3",
+"[  c #0D0DDC",
+"{  c #1A1AD4",
+"}  c #1010DF",
+"|  c #1E1EDE",
+" . c #1817DE",
+".. c #221FCA",
+"X. c #2B2BCC",
+"o. c #2727C9",
+"O. c #3434C3",
+"+. c #3434D4",
+"@. c #0F0FE2",
+"#. c #1313E5",
+"$. c #1515ED",
+"%. c #1B1BEA",
+"&. c #1C1CE4",
+"*. c #1515F4",
+"=. c #1818F3",
+"-. c #1717FD",
+";. c #1818FF",
+":. c #2B2BE9",
+">. c #2424FF",
+",. c #2A2AFF",
+"<. c #2222F1",
+"1. c #3737FF",
+"2. c #5D5DC3",
+"3. c #5F5FC9",
+"4. c #5655C2",
+"5. c #4747D1",
+"6. c #5B5BD4",
+"7. c #6565C8",
+"8. c #6363DA",
+"9. c #4545FF",
+"0. c #4D4DFC",
+"q. c #5454FF",
+"w. c #5959FF",
+"e. c #6969E5",
+"r. c #6B6CEA",
+"t. c #6666E7",
+"y. c #6B6BFE",
+"u. c #6767F8",
+"i. c #7070F6",
+"p. c #7373FF",
+"a. c #7C7CFF",
+"s. c #91918F",
+"d. c #8F9090",
+"f. c #979797",
+"g. c #9C9C9C",
+"h. c #8585A1",
+"j. c #9C9CA7",
+"k. c #9292B6",
+"l. c #A4A4A4",
+"z. c #BDB2A4",
+"x. c #A4A4B1",
+"c. c #BFBFBD",
+"v. c #BABAB7",
+"b. c #C8AA87",
+"n. c #DAAE82",
+"m. c #DBB081",
+"M. c #EBBA85",
+"N. c #F3BF84",
+"B. c #F2BE88",
+"V. c #C2B3A3",
+"C. c #FBC386",
+"Z. c #FCC68C",
+"A. c #FFC88F",
+"S. c #F4C387",
+"D. c #FFC990",
+"F. c #C3C1BF",
+"G. c #8F8FCB",
+"H. c #BDBDC2",
+"J. c #BDBDD1",
+"K. c #8888F9",
+"L. c #A4A4FB",
+"P. c #CDCDCC",
+"I. c #CECAC6",
+"U. c #D3CFCA",
+"Y. c #D3D0CC",
+"T. c #C0C0D5",
+"R. c #D6D5D4",
+"E. c #D7D7DD",
+"W. c #E1E1DF",
+"Q. c #DEDEE1",
+"!. c #E4E4E4",
+"~. c #E8E8E8",
+"^. c #F0F0EE",
+"/. c #F5F5F2",
+"(. c #FFFFFF",
+/* pixels */
 "                                                                ",
 "                                                                ",
 "                                                                ",
-"                              . + @ #                           ",
-"                      $ % & * = - ; > , ' ) !                   ",
-"      ~ {       ] ^ / = ( _ : < [ } | 1 2 3 4 5 6               ",
-"      7 8 9   0 a b c d e f g h i j k l m n o p q r             ",
-"      s t u v _ f d d d w x y z A B C D E F G H I J K L         ",
-"      M N O _ c e d d d _ P Q R S T U V W X Y Z `  ...          ",
-"      +.@.#.$.d d d d %.&._ *.=.-.;.>.,.'.).!.~.                ",
-"      {.].^./.(.d d _.$.:._ <.[.}.|.1.2.3.4.5.                  ",
-"    6.7.7.4 8.e : w 9.0.a.b.c.2 d.e.f.g.h.i.j.k.                ",
-"    l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.o o z.A.B./.b C.D.            ",
-"    E.F.G.].o H.z.I.J.K.L.M.N.O.P.o o o Q.R.S._.b B.T.          ",
-"    U.V.W.X.f.f.7.Y.Z.`. + + +.+++].o o o.n z.q.@+#+$+%+        ",
-"    &+ +*+=+].o -+;+>+ + + + +,+'+H.o o o o o H.)+o !+~+{+      ",
-"    ]+ +^+/+H.o.(+_+ + + + + +:+<+z.o o o o o o o 7.n H.[+}+    ",
-"    |+ +1+2+3+4+5+6+ + + + + +7+8+H.o o f.9+f.9+f.F 0+a+b+o.c+  ",
-"    &+ +d+e+f+g+h+i+ + + + + +j+k+].f.9+l+m+n+o+p+q+r+s+t+u+v+  ",
-"    w+ +x+y+z+A+B+C+ + + + + +D+E+9+F+G+H+I+J+K+L+M+N+O+        ",
-"    P+Q+R+S+T+U+V+W+ + + + +X+Y+Z+`+ @I+J+Z .@+@E.              ",
-"    @@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@I+/@(@_@                ",
-"      :@<@[@}@|@1@2@3@4@5@6@7@8@9@0@L+a@b@c@d@e@                ",
-"        f@g@h@i@i@j@k@l@|@m@n@o@p@q@r@s@t@u@p v@                ",
-"        w@x@y@z@A@B@i@C@D@E@F@G@H@I@L+J@K@L@p M@                ",
-"            N@O@P@Q@R@S@T@U@V@W@X@Y@Z@Y@`@ #.#p +#              ",
-"                @###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#              ",
-"                                              ^#/#              ",
+"                              I Q T =                           ",
+"                      Q 7.e.r.i.8.E E 3.r.6.J                   ",
+"      H ~       n 4.r.p.p.p.p.8.R > 5.^ w.,.-.{ v               ",
+"      { 9.^ & P t.p.p.p.p.p.8.I 5 q K L <.;.;.;.-.'             ",
+"      { %.H +.y.p.p.p.p.p.e.Y 2 a n.K F $.*.$.@.} ] N           ",
+"      x D :.y.p.p.p.p.p.p.r.R 8 C.u ..F A ) A Z M h $           ",
+"      f =.q.p.p.p.p.p.p.p.p.i.( e 6 $.` l B M g                 ",
+"      ` ;.q.p.p.p.p.p.a.K.a.p.p.4.L -.` l N %                   ",
+"    V =.-.>.q.y.p.p.p.L.L.K.i.w.,.-.;.$.<.q.u.2.                ",
+"    D { =.-.;.>.1.1.9.( h.h.Q &.-.-.-.;.9.p.p.p.r.!             ",
+"    U j.o.-.;.-.;.-.P x.Q.^.R.~ *.-.;.;.>.1.q.y.p.i.2.          ",
+"    H./.! *.;.;.;.o.x./.(.(.(.J.| -.-.;.-.-.;.,.9.u.p.7.        ",
+"    !.(.k.#.;.-.=./ !.(.(.(.(.Q.X.-.;.;.;.;.-.-.;.;.1.w.6.      ",
+"    ~.(.H.G ;.-.D j.(.(.(.(.(.!.O.-.-.;.;.;.-.;.-.;.-.;.,.O.    ",
+"    ~.(.v.@ *.$.+ d.(.(.(.(.(.E.o.-.-.;.;.-.;.;.;.*.=.=.*.$.v   ",
+"    ~.(.l.- Y T ; < (.(.(.(.(.J.&.-.;.;.$.@.[ ] _ ) ) Z B B f   ",
+"    P.(.F.X c.I.X f.(.(.(.(.(.G.=.-.=.] A Z Z Z Z z f $         ",
+"    l.!.R.s.F.I.g.W.(.(.(.(.R.E  .[ A Z Z Z B g $               ",
+"    . , ; - 0 M.b.V.U.R.Y.z.u n.7 c Z Z B g # +                 ",
+"      : w p Z.D.A.S.p u i M.A.A.S.* Z B h z ] C                 ",
+"        s D.D.A.A.A.A.A.A.A.i B.B.b A Z Z @.-.`                 ",
+"        1 y C.D.A.A.A.A.A.M.u Z.e c A Z Z [ ;.&.                ",
+"            8 y d C.A.A.A.C.B.t * B Z Z Z A #.=.m               ",
+"                3 9 r t r 9 8 o @ $ # f j l B #.V               ",
+"                                              j k               ",
 "                                                                ",
 "                                                                ",
 "                                                                ",
-"                                                                "};
+"                                                                "
+};
diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c
index f4686d2bf4f3e95626ba6a69322ce44b379ce8ec..05ac6450e2267c0c08182775cece05eeaefabeab 100644
--- a/src/sdl/hwsym_sdl.c
+++ b/src/sdl/hwsym_sdl.c
@@ -94,6 +94,7 @@ void *hwSym(const char *funcName,void *handle)
 #ifdef SHUFFLE
 	GETFUNC(PostImgRedraw);
 #endif //SHUFFLE
+	GETFUNC(FlushScreenTextures);
 	GETFUNC(StartScreenWipe);
 	GETFUNC(EndScreenWipe);
 	GETFUNC(DoScreenWipe);
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index e86a39cab063e1a4ac2ebb251b597c37ec2f65db..7b14f1f18d99f54b6517853acc72caa795b73295 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -124,6 +124,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #include "macosx/mac_resources.h"
 #endif
 
+#ifndef errno
+#include <errno.h>
+#endif
+
 // Locations for searching the srb2.srb
 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
 #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2"
@@ -1150,6 +1154,7 @@ static void I_ShutdownJoystick2(void)
 		D_PostEvent(&event);
 	}
 
+	joystick2_started = 0;
 	JoyReset(&JoyInfo2);
 	if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
 	{
@@ -1679,7 +1684,7 @@ static void I_ShutdownMouse2(void)
 	EscapeCommFunction(mouse2filehandle, CLRRTS);
 
 	PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT |
-	          PURGE_TXCLEAR | PURGE_RXCLEAR);
+			  PURGE_TXCLEAR | PURGE_RXCLEAR);
 
 	CloseHandle(mouse2filehandle);
 
@@ -1872,11 +1877,11 @@ void I_StartupMouse2(void)
 	{
 		// COM file handle
 		mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ | GENERIC_WRITE,
-		                               0,                     // exclusive access
-		                               NULL,                  // no security attrs
-		                               OPEN_EXISTING,
-		                               FILE_ATTRIBUTE_NORMAL,
-		                               NULL);
+									   0,                     // exclusive access
+									   NULL,                  // no security attrs
+									   OPEN_EXISTING,
+									   FILE_ATTRIBUTE_NORMAL,
+									   NULL);
 		if (mouse2filehandle == INVALID_HANDLE_VALUE)
 		{
 			INT32 e = GetLastError();
@@ -1896,7 +1901,7 @@ void I_StartupMouse2(void)
 
 	// purge buffers
 	PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT
-	          | PURGE_TXCLEAR | PURGE_RXCLEAR);
+			  | PURGE_TXCLEAR | PURGE_RXCLEAR);
 
 	// setup port to 1200 7N1
 	dcb.DCBlength = sizeof (DCB);
@@ -2025,7 +2030,7 @@ static void I_ShutdownTimer(void)
 tic_t I_GetTime (void)
 {
 	static Uint32 basetime = 0;
-	       Uint32 ticks = SDL_GetTicks();
+		   Uint32 ticks = SDL_GetTicks();
 
 	if (!basetime)
 		basetime = ticks;
@@ -2091,7 +2096,6 @@ INT32 I_StartupSystem(void)
 	return 0;
 }
 
-
 //
 // I_Quit
 //
@@ -2370,7 +2374,7 @@ void I_GetDiskFreeSpace(INT64 *freespace)
 	{
 		DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
 		GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector,
-		                 &NumberOfFreeClusters, &TotalNumberOfClusters);
+						 &NumberOfFreeClusters, &TotalNumberOfClusters);
 		*freespace = BytesPerSector*SectorsPerCluster*NumberOfFreeClusters;
 	}
 #else // Dummy for platform independent; 1GB should be enough
@@ -2592,22 +2596,22 @@ static const char *locateWad(void)
 
 #ifdef CMAKECONFIG
 #ifndef NDEBUG
-    I_OutputMsg(","CMAKE_ASSETS_DIR);
-    strcpy(returnWadPath, CMAKE_ASSETS_DIR);
-    if (isWadPathOk(returnWadPath))
-    {
-        return returnWadPath;
-    }
+	I_OutputMsg(","CMAKE_ASSETS_DIR);
+	strcpy(returnWadPath, CMAKE_ASSETS_DIR);
+	if (isWadPathOk(returnWadPath))
+	{
+		return returnWadPath;
+	}
 #endif
 #endif
 
 #ifdef __APPLE__
-    OSX_GetResourcesPath(returnWadPath);
-    I_OutputMsg(",%s", returnWadPath);
-    if (isWadPathOk(returnWadPath))
-    {
-        return returnWadPath;
-    }
+	OSX_GetResourcesPath(returnWadPath);
+	I_OutputMsg(",%s", returnWadPath);
+	if (isWadPathOk(returnWadPath))
+	{
+		return returnWadPath;
+	}
 #endif
 
 	// examine default dirs
@@ -2712,7 +2716,30 @@ const char *I_LocateWad(void)
 #ifdef __linux__
 #define MEMINFO_FILE "/proc/meminfo"
 #define MEMTOTAL "MemTotal:"
+#define MEMAVAILABLE "MemAvailable:"
 #define MEMFREE "MemFree:"
+#define CACHED "Cached:"
+#define BUFFERS "Buffers:"
+#define SHMEM "Shmem:"
+
+/* Parse the contents of /proc/meminfo (in buf), return value of "name"
+ * (example: MemTotal) */
+static long get_entry(const char* name, const char* buf)
+{
+	long val;
+	char* hit = strstr(buf, name);
+	if (hit == NULL) {
+		return -1;
+	}
+
+	errno = 0;
+	val = strtol(hit + strlen(name), NULL, 10);
+	if (errno != 0) {
+		CONS_Alert(CONS_ERROR, M_GetText("get_entry: strtol() failed: %s\n"), strerror(errno));
+		return -1;
+	}
+	return val;
+}
 #endif
 
 // quick fix for compil
@@ -2784,6 +2811,11 @@ UINT32 I_GetFreeMem(UINT32 *total)
 	UINT32 totalKBytes;
 	INT32 n;
 	INT32 meminfo_fd = -1;
+	long Cached;
+	long MemFree;
+	long Buffers;
+	long Shmem;
+	long MemAvailable = -1;
 
 	meminfo_fd = open(MEMINFO_FILE, O_RDONLY);
 	n = read(meminfo_fd, buf, 1023);
@@ -2809,16 +2841,28 @@ UINT32 I_GetFreeMem(UINT32 *total)
 	memTag += sizeof (MEMTOTAL);
 	totalKBytes = atoi(memTag);
 
-	if ((memTag = strstr(buf, MEMFREE)) == NULL)
+	if ((memTag = strstr(buf, MEMAVAILABLE)) == NULL)
 	{
-		// Error
-		if (total)
-			*total = 0L;
-		return 0;
-	}
+		Cached = get_entry(CACHED, buf);
+		MemFree = get_entry(MEMFREE, buf);
+		Buffers = get_entry(BUFFERS, buf);
+		Shmem = get_entry(SHMEM, buf);
+		MemAvailable = Cached + MemFree + Buffers - Shmem;
 
-	memTag += sizeof (MEMFREE);
-	freeKBytes = atoi(memTag);
+		if (MemAvailable == -1)
+		{
+			// Error
+			if (total)
+				*total = 0L;
+			return 0;
+		}
+		freeKBytes = MemAvailable;
+	}
+	else
+	{
+		memTag += sizeof (MEMAVAILABLE);
+		freeKBytes = atoi(memTag);
+	}
 
 	if (total)
 		*total = totalKBytes << 10;
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 1bda0e1804fde86a55b897dad032d0ad8bc2cb4e..30ef1b27b30b938fd2def893239ce2a8efe204b6 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -39,6 +39,10 @@
 
 #ifdef HAVE_IMAGE
 #include "SDL_image.h"
+#elif 1
+#define LOAD_XPM //I want XPM!
+#include "IMG_xpm.c" //Alam: I don't want to add SDL_Image.dll/so
+#define HAVE_IMAGE //I have SDL_Image, sortof
 #endif
 
 #ifdef HAVE_IMAGE
@@ -562,7 +566,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
 		// Tell game we got focus back, resume music if necessary
 		window_notinfocus = false;
 		if (!paused)
-			I_ResumeSong(0); //resume it
+			I_ResumeSong(); //resume it
 
 		if (!firsttimeonmouse)
 		{
@@ -574,7 +578,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
 	{
 		// Tell game we lost focus, pause music
 		window_notinfocus = true;
-		I_PauseSong(0);
+		I_PauseSong();
 
 		if (!disable_mouse)
 		{
@@ -658,6 +662,14 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
 
 	SDL_memset(&event, 0, sizeof(event_t));
 
+	// Ignore the event if the mouse is not actually focused on the window.
+	// This can happen if you used the mouse to restore keyboard focus;
+	// this apparently makes a mouse button down event but not a mouse button up event,
+	// resulting in whatever key was pressed down getting "stuck" if we don't ignore it.
+	// -- Monster Iestyn (28/05/18)
+	if (SDL_GetMouseFocus() != window)
+		return;
+
 	/// \todo inputEvent.button.which
 	if (USE_MOUSEINPUT)
 	{
@@ -1442,6 +1454,7 @@ void I_StartupGraphics(void)
 #ifdef SHUFFLE
 		HWD.pfnPostImgRedraw    = hwSym("PostImgRedraw",NULL);
 #endif
+		HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL);
 		HWD.pfnStartScreenWipe  = hwSym("StartScreenWipe",NULL);
 		HWD.pfnEndScreenWipe    = hwSym("EndScreenWipe",NULL);
 		HWD.pfnDoScreenWipe     = hwSym("DoScreenWipe",NULL);
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 71832459182305a2bed1cf1e9e94446508fb8dd0..4d86d7a3cefb9624a96c5ef76f84bfb546138566 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -34,14 +34,18 @@
 	(SDL_MIXER_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
 #endif
 
+// thanks alam for making the buildbots happy!
+#if SDL_MIXER_VERSION_ATLEAST(2,0,2)
+#define MUS_MP3_MAD MUS_MP3_MAD_UNUSED
+#define MUS_MODPLUG MUS_MODPLUG_UNUSED
+#endif
+
 #ifdef HAVE_LIBGME
 #include "gme/gme.h"
 #define GME_TREBLE 5.0
 #define GME_BASS 1.0
-#ifdef HAVE_PNG /// TODO: compile with zlib support without libpng
-
-#define HAVE_ZLIB
 
+#ifdef HAVE_ZLIB
 #ifndef _MSC_VER
 #ifndef _LARGEFILE64_SOURCE
 #define _LARGEFILE64_SOURCE
@@ -57,28 +61,35 @@
 #endif
 
 #include "zlib.h"
-#endif
-#endif
+#endif // HAVE_ZLIB
+#endif // HAVE_LIBGME
 
 UINT8 sound_started = false;
 
-static boolean midimode;
 static Mix_Music *music;
-static UINT8 music_volume, midi_volume, sfx_volume;
+static UINT8 music_volume, sfx_volume;
 static float loop_point;
+static boolean songpaused;
 
 #ifdef HAVE_LIBGME
 static Music_Emu *gme;
 static INT32 current_track;
 #endif
 
+/// ------------------------
+/// Audio System
+/// ------------------------
+
 void I_StartupSound(void)
 {
 	I_Assert(!sound_started);
 
 	// EE inits audio first so we're following along.
 	if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO)
-		CONS_Printf("SDL Audio already started\n");
+	{
+		CONS_Debug(DBG_DETAILED, "SDL Audio already started\n");
+		return;
+	}
 	else if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
 	{
 		CONS_Alert(CONS_ERROR, "Error initializing SDL Audio: %s\n", SDL_GetError());
@@ -86,9 +97,8 @@ void I_StartupSound(void)
 		return;
 	}
 
-	midimode = false;
 	music = NULL;
-	music_volume = midi_volume = sfx_volume = 0;
+	music_volume = sfx_volume = 0;
 
 #if SDL_MIXER_VERSION_ATLEAST(1,2,11)
 	Mix_Init(MIX_INIT_FLAC|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG);
@@ -102,6 +112,7 @@ void I_StartupSound(void)
 	}
 
 	sound_started = true;
+	songpaused = false;
 	Mix_AllocateChannels(256);
 }
 
@@ -128,6 +139,10 @@ FUNCMATH void I_UpdateSound(void)
 {
 }
 
+/// ------------------------
+/// SFX
+/// ------------------------
+
 // this is as fast as I can possibly make it.
 // sorry. more asm needed.
 static Mix_Chunk *ds2chunk(void *stream)
@@ -244,6 +259,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
 {
 	void *lump;
 	Mix_Chunk *chunk;
+	SDL_RWops *rw;
 #ifdef HAVE_LIBGME
 	Music_Emu *emu;
 	gme_info_t *info;
@@ -304,7 +320,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
 					gme_track_info(emu, &info, 0);
 
 					len = (info->play_length * 441 / 10) << 2;
-					mem = Z_Malloc(len, PU_SOUND, NULL);
+					mem = malloc(len);
 					gme_play(emu, len >> 1, mem);
 					gme_delete(emu);
 
@@ -359,7 +375,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
 		}
 		Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up
 #else
-		//CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n");
+		return NULL; // No zlib support
 #endif
 	}
 	// Try to read it as a GME sound
@@ -376,7 +392,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
 		gme_track_info(emu, &info, 0);
 
 		len = (info->play_length * 441 / 10) << 2;
-		mem = Z_Malloc(len, PU_SOUND, NULL);
+		mem = malloc(len);
 		gme_play(emu, len >> 1, mem);
 		gme_delete(emu);
 
@@ -385,21 +401,43 @@ void *I_GetSfx(sfxinfo_t *sfx)
 #endif
 
 	// Try to load it as a WAVE or OGG using Mixer.
-	return Mix_LoadWAV_RW(SDL_RWFromMem(lump, sfx->length), 1);
+	rw = SDL_RWFromMem(lump, sfx->length);
+	if (rw != NULL)
+	{
+		chunk = Mix_LoadWAV_RW(rw, 1);
+		return chunk;
+	}
+
+	return NULL; // haven't been able to get anything
 }
 
 void I_FreeSfx(sfxinfo_t *sfx)
 {
 	if (sfx->data)
+	{
+		Mix_Chunk *chunk = (Mix_Chunk*)sfx->data;
+		UINT8 *abufdata = NULL;
+		if (chunk->allocated == 0)
+		{
+			// We allocated the data in this chunk, so get the abuf from mixer, then let it free the chunk, THEN we free the data
+			// I believe this should ensure the sound is not playing when we free it
+			abufdata = chunk->abuf;
+		}
 		Mix_FreeChunk(sfx->data);
+		if (abufdata)
+		{
+			// I'm going to assume we used Z_Malloc to allocate this data.
+			Z_Free(abufdata);
+		}
+	}
 	sfx->data = NULL;
 	sfx->lumpnum = LUMPERROR;
 }
 
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
 {
 	UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127
-	INT32 handle = Mix_PlayChannel(-1, S_sfx[id].data, 0);
+	INT32 handle = Mix_PlayChannel(channel, S_sfx[id].data, 0);
 	Mix_Volume(handle, volume);
 	Mix_SetPanning(handle, min((UINT16)(0xff-sep)<<1, 0xff), min((UINT16)(sep)<<1, 0xff));
 	(void)pitch; // Mixer can't handle pitch
@@ -430,11 +468,10 @@ void I_SetSfxVolume(UINT8 volume)
 	sfx_volume = volume;
 }
 
-//
-// Music
-//
+/// ------------------------
+/// Music Hooks
+/// ------------------------
 
-// Music hooks
 static void music_loop(void)
 {
 	Mix_PlayMusic(music, 0);
@@ -450,7 +487,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
 	(void)udata;
 
 	// no gme? no music.
-	if (!gme || gme_track_ended(gme))
+	if (!gme || gme_track_ended(gme) || songpaused)
 		return;
 
 	// play gme into stream
@@ -458,80 +495,105 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
 
 	// apply volume to stream
 	for (i = 0, p = (short *)stream; i < len/2; i++, p++)
-		*p = ((INT32)*p) * music_volume / 31;
+		*p = ((INT32)*p) * music_volume*2 / 42;
 }
 #endif
 
+
+/// ------------------------
+/// Music System
+/// ------------------------
+
 FUNCMATH void I_InitMusic(void)
 {
 }
 
 void I_ShutdownMusic(void)
 {
-	I_ShutdownDigMusic();
-	I_ShutdownMIDIMusic();
+	I_UnloadSong();
 }
 
-void I_PauseSong(INT32 handle)
-{
-	(void)handle;
-	Mix_PauseMusic();
-}
+/// ------------------------
+/// Music Properties
+/// ------------------------
 
-void I_ResumeSong(INT32 handle)
+musictype_t I_SongType(void)
 {
-	(void)handle;
-	Mix_ResumeMusic();
+#ifdef HAVE_LIBGME
+	if (gme)
+		return MU_GME;
+	else
+#endif
+	if (!music)
+		return MU_NONE;
+	else if (Mix_GetMusicType(music) == MUS_MID)
+		return MU_MID;
+	else if (Mix_GetMusicType(music) == MUS_MOD || Mix_GetMusicType(music) == MUS_MODPLUG)
+		return MU_MOD;
+	else if (Mix_GetMusicType(music) == MUS_MP3 || Mix_GetMusicType(music) == MUS_MP3_MAD)
+		return MU_MP3;
+	else
+		return (musictype_t)Mix_GetMusicType(music);
 }
 
-//
-// Digital Music
-//
-
-void I_InitDigMusic(void)
+boolean I_SongPlaying(void)
 {
+	return (
 #ifdef HAVE_LIBGME
-	gme = NULL;
-	current_track = -1;
+		(I_SongType() == MU_GME && gme) ||
 #endif
+		(boolean)music
+	);
 }
 
-void I_ShutdownDigMusic(void)
+boolean I_SongPaused(void)
 {
-	if (midimode)
-		return;
+	return songpaused;
+}
+
+/// ------------------------
+/// Music Effects
+/// ------------------------
+
+boolean I_SetSongSpeed(float speed)
+{
+	if (speed > 250.0f)
+		speed = 250.0f; //limit speed up to 250x
 #ifdef HAVE_LIBGME
 	if (gme)
 	{
-		Mix_HookMusic(NULL, NULL);
-		gme_delete(gme);
-		gme = NULL;
+		SDL_LockAudio();
+		gme_set_tempo(gme, speed);
+		SDL_UnlockAudio();
+		return true;
 	}
+#else
+	(void)speed;
 #endif
-	if (!music)
-		return;
-	Mix_HookMusicFinished(NULL);
-	Mix_FreeMusic(music);
-	music = NULL;
+	return false;
 }
 
-boolean I_StartDigSong(const char *musicname, boolean looping)
-{
-	char *data;
-	size_t len;
-	lumpnum_t lumpnum = W_CheckNumForName(va("O_%s",musicname));
+/// ------------------------
+/// Music Playback
+/// ------------------------
 
-	I_Assert(!music);
+boolean I_LoadSong(char *data, size_t len)
+{
+	const char *key1 = "LOOP";
+	const char *key2 = "POINT=";
+	const char *key3 = "MS=";
+	const size_t key1len = strlen(key1);
+	const size_t key2len = strlen(key2);
+	const size_t key3len = strlen(key3);
+	char *p = data;
+	SDL_RWops *rw;
+
+	if (music
 #ifdef HAVE_LIBGME
-	I_Assert(!gme);
+		|| gme
 #endif
-
-	if (lumpnum == LUMPERROR)
-		return false;
-	midimode = false;
-
-	data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC);
-	len = W_LumpLength(lumpnum);
+	)
+		I_UnloadSong();
 
 #ifdef HAVE_LIBGME
 	if ((UINT8)data[0] == 0x1F
@@ -617,66 +679,95 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 		}
 		Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up
 #else
-		//CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n");
+		CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n");
+		return true;
 #endif
 	}
 	else if (!gme_open_data(data, len, &gme, 44100))
 	{
 		gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
-		gme_start_track(gme, 0);
-		current_track = 0;
 		gme_set_equalizer(gme, &eq);
-		Mix_HookMusic(mix_gme, gme);
 		return true;
 	}
 #endif
 
-	music = Mix_LoadMUS_RW(SDL_RWFromMem(data, len), SDL_FALSE);
+	rw = SDL_RWFromMem(data, len);
+	if (rw != NULL)
+	{
+		music = Mix_LoadMUS_RW(rw, 1);
+	}
 	if (!music)
 	{
 		CONS_Alert(CONS_ERROR, "Mix_LoadMUS_RW: %s\n", Mix_GetError());
-		return true;
+		return false;
 	}
 
 	// Find the OGG loop point.
 	loop_point = 0.0f;
-	if (looping)
+
+	while ((UINT32)(p - data) < len)
 	{
-		const char *key1 = "LOOP";
-		const char *key2 = "POINT=";
-		const char *key3 = "MS=";
-		const size_t key1len = strlen(key1);
-		const size_t key2len = strlen(key2);
-		const size_t key3len = strlen(key3);
-		char *p = data;
-		while ((UINT32)(p - data) < len)
+		if (strncmp(p++, key1, key1len))
+			continue;
+		p += key1len-1; // skip OOP (the L was skipped in strncmp)
+		if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=?
 		{
-			if (strncmp(p++, key1, key1len))
-				continue;
-			p += key1len-1; // skip OOP (the L was skipped in strncmp)
-			if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=?
-			{
-				p += key2len; // skip POINT=
-				loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count.
-				// because SDL_Mixer is USELESS and can't even tell us
-				// something simple like the frequency of the streaming music,
-				// we are unfortunately forced to assume that ALL MUSIC is 44100hz.
-				// This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly.
-			}
-			else if (!strncmp(p, key3, key3len)) // is it LOOPMS=?
-			{
-				p += key3len; // skip MS=
-				loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds.
-				// Everything that uses LOOPMS will work perfectly with SDL_Mixer.
-			}
-			// Neither?! Continue searching.
+			p += key2len; // skip POINT=
+			loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count.
+			// because SDL_Mixer is USELESS and can't even tell us
+			// something simple like the frequency of the streaming music,
+			// we are unfortunately forced to assume that ALL MUSIC is 44100hz.
+			// This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly.
+		}
+		else if (!strncmp(p, key3, key3len)) // is it LOOPMS=?
+		{
+			p += key3len; // skip MS=
+			loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds.
+			// Everything that uses LOOPMS will work perfectly with SDL_Mixer.
 		}
+		// Neither?! Continue searching.
+	}
+
+	return true;
+}
+
+void I_UnloadSong(void)
+{
+	I_StopSong();
+
+#ifdef HAVE_LIBGME
+	if (gme)
+	{
+		gme_delete(gme);
+		gme = NULL;
 	}
+#endif
+	if (music)
+	{
+		Mix_FreeMusic(music);
+		music = NULL;
+	}
+}
+
+boolean I_PlaySong(boolean looping)
+{
+#ifdef HAVE_LIBGME
+	if (gme)
+	{
+		gme_start_track(gme, 0);
+		current_track = 0;
+		Mix_HookMusic(mix_gme, gme);
+		return true;
+	}
+	else
+#endif
+	if (!music)
+		return false;
 
 	if (Mix_PlayMusic(music, looping && loop_point == 0.0f ? -1 : 0) == -1)
 	{
 		CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
-		return true;
+		return false;
 	}
 	Mix_VolumeMusic((UINT32)music_volume*128/31);
 
@@ -685,51 +776,49 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 	return true;
 }
 
-void I_StopDigSong(void)
+void I_StopSong(void)
 {
-	if (midimode)
-		return;
 #ifdef HAVE_LIBGME
 	if (gme)
 	{
 		Mix_HookMusic(NULL, NULL);
-		gme_delete(gme);
-		gme = NULL;
 		current_track = -1;
-		return;
 	}
 #endif
-	if (!music)
-		return;
-	Mix_HookMusicFinished(NULL);
-	Mix_FreeMusic(music);
-	music = NULL;
+	if (music)
+	{
+		Mix_HookMusicFinished(NULL);
+		Mix_HaltMusic();
+	}
 }
 
-void I_SetDigMusicVolume(UINT8 volume)
+void I_PauseSong(void)
 {
-	music_volume = volume;
-	if (midimode || !music)
-		return;
-	Mix_VolumeMusic((UINT32)volume*128/31);
+	Mix_PauseMusic();
+	songpaused = true;
 }
 
-boolean I_SetSongSpeed(float speed)
+void I_ResumeSong(void)
 {
-	if (speed > 250.0f)
-		speed = 250.0f; //limit speed up to 250x
-#ifdef HAVE_LIBGME
-	if (gme)
-	{
-		SDL_LockAudio();
-		gme_set_tempo(gme, speed);
-		SDL_UnlockAudio();
-		return true;
-	}
-#else
-	(void)speed;
+	Mix_ResumeMusic();
+	songpaused = false;
+}
+
+void I_SetMusicVolume(UINT8 volume)
+{
+	if (!I_SongPlaying())
+		return;
+
+#ifdef _WIN32
+	if (I_SongType() == MU_MID)
+		// HACK: Until we stop using native MIDI,
+		// disable volume changes
+		music_volume = 31;
+	else
 #endif
-	return false;
+		music_volume = volume;
+
+	Mix_VolumeMusic((UINT32)music_volume*128/31);
 }
 
 boolean I_SetSongTrack(int track)
@@ -763,79 +852,4 @@ boolean I_SetSongTrack(int track)
 	return false;
 }
 
-//
-// MIDI Music
-//
-
-FUNCMATH void I_InitMIDIMusic(void)
-{
-}
-
-void I_ShutdownMIDIMusic(void)
-{
-	if (!midimode || !music)
-		return;
-	Mix_FreeMusic(music);
-	music = NULL;
-}
-
-void I_SetMIDIMusicVolume(UINT8 volume)
-{
-	// HACK: Until we stop using native MIDI,
-	// disable volume changes
-	(void)volume;
-	midi_volume = 31;
-	//midi_volume = volume;
-
-	if (!midimode || !music)
-		return;
-	Mix_VolumeMusic((UINT32)midi_volume*128/31);
-}
-
-INT32 I_RegisterSong(void *data, size_t len)
-{
-	music = Mix_LoadMUS_RW(SDL_RWFromMem(data, len), SDL_FALSE);
-	if (!music)
-	{
-		CONS_Alert(CONS_ERROR, "Mix_LoadMUS_RW: %s\n", Mix_GetError());
-		return -1;
-	}
-	return 1337;
-}
-
-boolean I_PlaySong(INT32 handle, boolean looping)
-{
-	(void)handle;
-
-	midimode = true;
-
-	if (Mix_PlayMusic(music, looping ? -1 : 0) == -1)
-	{
-		CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
-		return false;
-	}
-
-	Mix_VolumeMusic((UINT32)midi_volume*128/31);
-	return true;
-}
-
-void I_StopSong(INT32 handle)
-{
-	if (!midimode || !music)
-		return;
-
-	(void)handle;
-	Mix_HaltMusic();
-}
-
-void I_UnRegisterSong(INT32 handle)
-{
-	if (!midimode || !music)
-		return;
-
-	(void)handle;
-	Mix_FreeMusic(music);
-	music = NULL;
-}
-
-#endif
+#endif
\ No newline at end of file
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index cd7ced7cab1eed7886af073f1c187b40ee18fd7e..4347b35b22b2e07682e5ced0e89bd76636366a04 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -214,8 +214,11 @@ void OglSdlFinishUpdate(boolean waitvbl)
 	HWR_DrawScreenFinalTexture(sdlw, sdlh);
 	SDL_GL_SwapWindow(window);
 
-	SetModelView(realwidth, realheight);
-	SetStates();
+	GClipRect(0, 0, realwidth, realheight, NZCLIP_PLANE);
+
+	// Sryder:	We need to draw the final screen texture again into the other buffer in the original position so that
+	//			effects that want to take the old screen can do so after this
+	HWR_DrawScreenFinalTexture(realwidth, realheight);
 }
 
 EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette, RGBA_t *pgamma)
diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c
index 1a2cabd23b1845feeea81907b10b9ffe02e05456..9f8a3e29d53f59621f3994cca1279f0f475b5103 100644
--- a/src/sdl/sdl_sound.c
+++ b/src/sdl/sdl_sound.c
@@ -194,8 +194,8 @@ static srb2audio_t localdata;
 static void Snd_LockAudio(void) //Alam: Lock audio data and uninstall audio callback
 {
 	if (Snd_Mutex) SDL_LockMutex(Snd_Mutex);
-	else if (nosound) return;
-	else if (nomidimusic && nodigimusic
+	else if (sound_disabled) return;
+	else if (midi_disabled && digital_disabled
 #ifdef HW3SOUND
 	         && hws_mode == HWS_DEFAULT_MODE
 #endif
@@ -208,8 +208,8 @@ static void Snd_LockAudio(void) //Alam: Lock audio data and uninstall audio call
 static void Snd_UnlockAudio(void) //Alam: Unlock audio data and reinstall audio callback
 {
 	if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
-	else if (nosound) return;
-	else if (nomidimusic && nodigimusic
+	else if (sound_disabled) return;
+	else if (midi_disabled && digital_disabled
 #ifdef HW3SOUND
 	         && hws_mode == HWS_DEFAULT_MODE
 #endif
@@ -493,7 +493,7 @@ static inline void I_SetChannels(void)
 
 	INT32 *steptablemid = steptable + 128;
 
-	if (nosound)
+	if (sound_disabled)
 		return;
 
 	// This table provides step widths for pitch parameters.
@@ -604,12 +604,13 @@ void I_FreeSfx(sfxinfo_t * sfx)
 // Pitching (that is, increased speed of playback)
 //  is set, but currently not used by mixing.
 //
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
 {
 	(void)priority;
 	(void)pitch;
+	(void)channel;
 
-	if (nosound)
+	if (sound_disabled)
 		return 0;
 
 	if (S_sfx[id].data == NULL) return -1;
@@ -989,7 +990,7 @@ FUNCINLINE static ATTRINLINE void I_UpdateStream16M(Uint8 *stream, int len)
 	if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
 }
 
-#ifdef HAVE_LIBGME
+#if 0 //#ifdef HAVE_LIBGME
 static void I_UpdateSteamGME(Music_Emu *emu, INT16 *stream, int len, UINT8 looping)
 {
 	#define GME_BUFFER_LEN 44100*2048
@@ -1049,14 +1050,16 @@ static void SDLCALL I_UpdateStream(void *userdata, Uint8 *stream, int len)
 	else if (audio.channels == 2 && audio.format == AUDIO_S16SYS)
 	{
 		I_UpdateStream16S(stream, len);
-#ifdef HAVE_LIBGME
-		if (userdata)
-		{
-			srb2audio_t *sa_userdata = userdata;
-			if (!sa_userdata->gme_pause)
-				I_UpdateSteamGME(sa_userdata->gme_emu, (INT16 *)stream, len/4, sa_userdata->gme_loop);
-		}
-#endif
+
+		// Crashes! But no matter; this build doesn't play music anyway...
+// #ifdef HAVE_LIBGME
+// 		if (userdata)
+// 		{
+// 			srb2audio_t *sa_userdata = userdata;
+// 			if (!sa_userdata->gme_pause)
+// 				I_UpdateSteamGME(sa_userdata->gme_emu, (INT16 *)stream, len/4, sa_userdata->gme_loop);
+// 		}
+// #endif
 
 	}
 }
@@ -1136,7 +1139,7 @@ static INT32 Init3DSDriver(const char *soName)
 
 void I_ShutdownSound(void)
 {
-	if (nosound || !sound_started)
+	if (sound_disabled || !sound_started)
 		return;
 
 	CONS_Printf("I_ShutdownSound: ");
@@ -1150,7 +1153,7 @@ void I_ShutdownSound(void)
 	}
 #endif
 
-	if (nomidimusic && nodigimusic)
+	if (midi_disabled && digital_disabled)
 		SDL_CloseAudio();
 	CONS_Printf("%s", M_GetText("shut down\n"));
 	sound_started = false;
@@ -1170,7 +1173,7 @@ void I_StartupSound(void)
 	const char *sdrv_name = NULL;
 #endif
 #ifndef HAVE_MIXER
-	nomidimusic = nodigimusic = true;
+	midi_disabled = digital_disabled = true;
 #endif
 
 	memset(channels, 0, sizeof (channels)); //Alam: Clean it
@@ -1180,12 +1183,6 @@ void I_StartupSound(void)
 	audio.callback = I_UpdateStream;
 	audio.userdata = &localdata;
 
-	if (dedicated)
-	{
-		nosound = nomidimusic = nodigimusic = true;
-		return;
-	}
-
 	// Configure sound device
 	CONS_Printf("I_StartupSound:\n");
 
@@ -1219,7 +1216,7 @@ void I_StartupSound(void)
 		audio.samples /= 2;
 	}
 
-	if (nosound)
+	if (sound_disabled)
 		return;
 
 #ifdef HW3SOUND
@@ -1267,7 +1264,7 @@ void I_StartupSound(void)
 		{
 			snddev_t            snddev;
 
-			//nosound = true;
+			//sound_disabled = true;
 			//I_AddExitFunc(I_ShutdownSound);
 			snddev.bps = 16;
 			snddev.sample_rate = audio.freq;
@@ -1294,7 +1291,7 @@ void I_StartupSound(void)
 	if (!musicStarted && SDL_OpenAudio(&audio, &audio) < 0)
 	{
 		CONS_Printf("%s", M_GetText(" couldn't open audio with desired format\n"));
-		nosound = true;
+		sound_disabled = true;
 		return;
 	}
 	else
@@ -1319,13 +1316,11 @@ void I_StartupSound(void)
 // MUSIC API.
 //
 
-void I_ShutdownMIDIMusic(void)
-{
-	nomidimusic = false;
-	if (nodigimusic) I_ShutdownMusic();
-}
+/// ------------------------
+//  MUSIC SYSTEM
+/// ------------------------
 
-#ifdef HAVE_LIBGME
+#if 0 //#ifdef HAVE_LIBGME
 static void I_ShutdownGMEMusic(void)
 {
 	Snd_LockAudio();
@@ -1336,394 +1331,127 @@ static void I_ShutdownGMEMusic(void)
 }
 #endif
 
-void I_ShutdownDigMusic(void)
-{
-	nodigimusic = false;
-	if (nomidimusic) I_ShutdownMusic();
-}
-
-#ifdef HAVE_MIXER
-static boolean LoadSong(void *data, size_t lumplength, size_t selectpos)
+void I_InitMusic(void)
 {
-	FILE *midfile;
-	const char *tempname;
-#ifdef USE_RWOPS
-	if (canuseRW)
-	{
-		SDL_RWops *SDLRW;
-		void *olddata = Smidi[selectpos]; //quick shortcut to set
-
-		Z_Free(olddata); //free old memory
-		Smidi[selectpos] = NULL;
-
-		if (!data)
-			return olddata != NULL; //was there old data?
-
-		SDLRW = SDL_RWFromConstMem(data, (int)lumplength); //new RWops from Z_zone
-		if (!SDLRW) //ERROR while making RWops!
-		{
-			CONS_Printf(M_GetText("Couldn't load music lump: %s\n"), SDL_GetError());
-			Z_Free(data);
-			return false;
-		}
-
-		music[selectpos] = Mix_LoadMUS_RW(SDLRW); // new Mix_Chuck from RWops
-		if (music[selectpos])
-			Smidi[selectpos] = data; //all done
-		else //ERROR while making Mix_Chuck
-		{
-			CONS_Printf(M_GetText("Couldn't load music data: %s\n"), Mix_GetError());
-			Z_Free(data);
-			SDL_RWclose(SDLRW);
-			Smidi[selectpos] = NULL;
-		}
-		return true;
-	}
-#endif
-	tempname = va("%s/%s", MIDI_PATH, fmidi[selectpos]);
-
-	if (!data)
-	{
-		if (FIL_FileExists(tempname))
-			return unlink(tempname)+1;
-#ifdef MIDI_PATH2
-		else if (FIL_FileExists(tempname = va("%s/%s", MIDI_PATH2, fmidi[selectpos])))
-			return unlink(tempname)+1;
-#endif
-		else
-			return false;
-	}
-
-	midfile = fopen(tempname, "wb");
-
-#ifdef MIDI_PATH2
-	if (!midfile)
-	{
-		tempname = va("%s/%s", MIDI_PATH2, fmidi[selectpos]);
-		midfile = fopen(tempname, "wb");
-	}
+#if 0 //#ifdef HAVE_LIBGME
+	I_AddExitFunc(I_ShutdownGMEMusic);
 #endif
+}
 
-	if (!midfile)
-	{
-		CONS_Printf(M_GetText("Couldn't open file %s to write music in\n"), tempname);
-		Z_Free(data);
-		return false;
-	}
-
-	if (fwrite(data, lumplength, 1, midfile) == 0)
-	{
-		CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, strerror(ferror(midfile)));
-		Z_Free(data);
-		fclose(midfile);
-		return false;
-	}
-
-	fclose(midfile);
+void I_ShutdownMusic(void) { }
 
-	Z_Free(data);
+/// ------------------------
+//  MUSIC PROPERTIES
+/// ------------------------
 
-	music[selectpos] = Mix_LoadMUS(tempname);
-	if (!music[selectpos]) //ERROR while making Mix_Chuck
-	{
-		CONS_Printf(M_GetText("Couldn't load music file %s: %s\n"), tempname, Mix_GetError());
-		return false;
-	}
-	return true;
+musictype_t I_SongType(void)
+{
+	return MU_NONE;
 }
-#endif
 
+boolean I_SongPlaying(void)
+{
+	return false;
+}
 
-void I_ShutdownMusic(void)
+boolean I_SongPaused(void)
 {
-#ifdef HAVE_MIXER
-	if ((nomidimusic && nodigimusic) || !musicStarted)
-		return;
+	return false;
+}
 
-	CONS_Printf("%s", M_GetText("I_ShutdownMusic: "));
+/// ------------------------
+//  MUSIC EFFECTS
+/// ------------------------
 
-	I_UnRegisterSong(0);
-	I_StopDigSong();
-	Mix_CloseAudio();
-#ifdef MIX_INIT
-	Mix_Quit();
-#endif
-	CONS_Printf("%s", M_GetText("shut down\n"));
-	musicStarted = SDL_FALSE;
-	if (Msc_Mutex)
-		SDL_DestroyMutex(Msc_Mutex);
-	Msc_Mutex = NULL;
-#endif
+boolean I_SetSongSpeed(float speed)
+{
+	(void)speed;
+	return false;
 }
 
-void I_InitMIDIMusic(void)
+/// ------------------------
+//  MUSIC PLAYBACK
+/// ------------------------
+
+#if 0 //#ifdef HAVE_LIBGME
+static void I_StopGME(void)
 {
-	if (nodigimusic) I_InitMusic();
+	Snd_LockAudio();
+	gme_seek(localdata.gme_emu, 0);
+	Snd_UnlockAudio();
 }
 
-void I_InitDigMusic(void)
+static void I_PauseGME(void)
 {
-	if (nomidimusic) I_InitMusic();
+	localdata.gme_pause = true;
 }
 
-void I_InitMusic(void)
+static void I_ResumeGME(void)
 {
-#ifdef HAVE_MIXER
-	char ad[100];
-	SDL_version MIXcompiled;
-	const SDL_version *MIXlinked;
-#ifdef MIXER_INIT
-	const int mixstart = MIX_INIT_OGG;
-	int mixflags;
-#endif
-#endif
-#ifdef HAVE_LIBGME
-	I_AddExitFunc(I_ShutdownGMEMusic);
-#endif
-
-	if ((nomidimusic && nodigimusic) || dedicated)
-		return;
-
-#ifdef HAVE_MIXER
-	MIX_VERSION(&MIXcompiled)
-	MIXlinked = Mix_Linked_Version();
-	I_OutputMsg("Compiled for SDL_mixer version: %d.%d.%d\n",
-	            MIXcompiled.major, MIXcompiled.minor, MIXcompiled.patch);
-#ifdef MIXER_POS
-	if (MIXlinked->major == 1 && MIXlinked->minor == 2 && MIXlinked->patch < 7)
-		canlooping = SDL_FALSE;
-#endif
-#ifdef USE_RWOPS
-	if (M_CheckParm("-noRW"))
-		canuseRW = SDL_FALSE;
-#endif
-	I_OutputMsg("Linked with SDL_mixer version: %d.%d.%d\n",
-	            MIXlinked->major, MIXlinked->minor, MIXlinked->patch);
-	if (audio.freq < 44100 && !M_CheckParm ("-freq")) //I want atleast 44Khz
-	{
-		audio.samples = (Uint16)(audio.samples*(INT32)(44100/audio.freq));
-		audio.freq = 44100; //Alam: to keep it around the same XX ms
-	}
-
-	if (sound_started
-#ifdef HW3SOUND
-		&& hws_mode == HWS_DEFAULT_MODE
-#endif
-		)
-	{
-		I_OutputMsg("Temp Shutdown of SDL Audio System");
-		SDL_CloseAudio();
-		I_OutputMsg(" Done\n");
-	}
-
-	CONS_Printf("%s", M_GetText("I_InitMusic:"));
-
-#ifdef MIXER_INIT
-	mixflags = Mix_Init(mixstart);
-	if ((mixstart & MIX_INIT_FLAC) != (mixflags & MIX_INIT_FLAC))
-	{
-		CONS_Printf("%s", M_GetText(" Unable to load FLAC support\n"));
-	}
-	if ((mixstart & MIX_INIT_MOD ) != (mixflags & MIX_INIT_MOD ))
-	{
-		CONS_Printf("%s", M_GetText(" Unable to load MOD support\n"));
-	}
-	if ((mixstart & MIX_INIT_MP3 ) != (mixflags & MIX_INIT_MP3 ))
-	{
-		CONS_Printf("%s", M_GetText(" Unable to load MP3 support\n"));
-	}
-	if ((mixstart & MIX_INIT_OGG ) != (mixflags & MIX_INIT_OGG ))
-	{
-		CONS_Printf("%s", M_GetText(" Unable to load OGG support\n"));
-	}
-#endif
-
-	if (Mix_OpenAudio(audio.freq, audio.format, audio.channels, audio.samples) < 0) //open_music(&audio)
-	{
-		CONS_Printf(M_GetText(" Unable to open music: %s\n"), Mix_GetError());
-		nomidimusic = nodigimusic = true;
-		if (sound_started
-#ifdef HW3SOUND
-			&& hws_mode == HWS_DEFAULT_MODE
-#endif
-			)
-		{
-			if (SDL_OpenAudio(&audio, NULL) < 0) //retry
-			{
-				CONS_Printf("%s", M_GetText(" couldn't open audio with desired format\n"));
-				nosound = true;
-				sound_started = false;
-			}
-			else
-			{
-				CONS_Printf(M_GetText(" Starting with audio driver : %s\n"), SDL_AudioDriverName(ad, (int)sizeof ad));
-			}
-		}
-		return;
-	}
-	else
-		CONS_Printf(M_GetText(" Starting up with audio driver : %s with SDL_Mixer\n"), SDL_AudioDriverName(ad, (int)sizeof ad));
-
-	samplecount = audio.samples;
-	CV_SetValue(&cv_samplerate, audio.freq);
-	if (sound_started
-#ifdef HW3SOUND
-		&& hws_mode == HWS_DEFAULT_MODE
-#endif
-		)
-		I_OutputMsg(" Reconfigured SDL Audio System");
-	else I_OutputMsg(" Configured SDL_Mixer System");
-	I_OutputMsg(" with %d samples/slice at %ikhz(%dms buffer)\n", samplecount, audio.freq/1000, (INT32) ((audio.samples * 1000.0f) / audio.freq));
-	Mix_SetPostMix(audio.callback, audio.userdata);  // after mixing music, add sound effects
-	Mix_Resume(-1);
-	CONS_Printf("%s", M_GetText("Music initialized\n"));
-	musicStarted = SDL_TRUE;
-	Msc_Mutex = SDL_CreateMutex();
-#endif
+	localdata.gme_pause = false;
 }
+#endif
 
-boolean I_PlaySong(INT32 handle, boolean looping)
+boolean I_LoadSong(char *data, size_t len)
 {
-	(void)handle;
-#ifdef HAVE_MIXER
-	if (nomidimusic || !musicStarted || !music[handle])
-		return false;
+	return false;
+}
 
-#ifdef MIXER_POS
-	if (canlooping)
-		Mix_HookMusicFinished(NULL);
-#endif
+void I_UnloadSong(void) { }
 
-	if (Mix_FadeInMusic(music[handle], looping ? -1 : 0, MIDIfade) == -1)
-		CONS_Printf(M_GetText("Couldn't play song because %s\n"), Mix_GetError());
-	else
-	{
-		Mix_VolumeMusic(musicvol);
-		return true;
-	}
-#else
+boolean I_PlaySong(boolean looping)
+{
 	(void)looping;
-#endif
 	return false;
 }
 
-static void I_PauseGME(void)
+void I_StopSong(void)
 {
-#ifdef HAVE_LIBGME
-	localdata.gme_pause = true;
+#if 0 //#ifdef HAVE_LIBGME
+	I_StopGME();
 #endif
 }
 
-void I_PauseSong(INT32 handle)
+void I_PauseSong(void)
 {
-	(void)handle;
+#if 0 //#ifdef HAVE_LIBGME
 	I_PauseGME();
-#ifdef HAVE_MIXER
-	if ((nomidimusic && nodigimusic) || !musicStarted)
-		return;
-
-	Mix_PauseMusic();
-	//I_StopSong(handle);
-#endif
-}
-
-static void I_ResumeGME(void)
-{
-#ifdef HAVE_LIBGME
-	localdata.gme_pause = false;
 #endif
 }
 
-void I_ResumeSong(INT32 handle)
+void I_ResumeSong(void)
 {
-	(void)handle;
+#if 0
 	I_ResumeGME();
-#ifdef HAVE_MIXER
-	if ((nomidimusic && nodigimusic) || !musicStarted)
-		return;
-
-	Mix_VolumeMusic(musicvol);
-	Mix_ResumeMusic();
-	//I_PlaySong(handle, true);
-#endif
-}
-
-void I_StopSong(INT32 handle)
-{
-	(void)handle;
-#ifdef HAVE_MIXER
-	if (nomidimusic || !musicStarted)
-		return;
-	Mix_FadeOutMusic(MIDIfade);
 #endif
 }
 
-void I_UnRegisterSong(INT32 handle)
+void I_SetMusicVolume(UINT8 volume)
 {
-#ifdef HAVE_MIXER
-
-	if (nomidimusic || !musicStarted)
-		return;
-
-	Mix_HaltMusic();
-	while (Mix_PlayingMusic())
-		;
-
-	if (music[handle])
-		Mix_FreeMusic(music[handle]);
-	music[handle] = NULL;
-	LoadSong(NULL, 0, handle);
-#else
-	(void)handle;
-#endif
+	(void)volume;
 }
 
-INT32 I_RegisterSong(void *data, size_t len)
+boolean I_SetSongTrack(int track)
 {
-#ifdef HAVE_MIXER
-	if (nomidimusic || !musicStarted)
-		return false;
-
-	if (!LoadSong(data, len, 0))
-		return false;
-
-	if (music[0])
-		return true;
-
-	CONS_Printf(M_GetText("Couldn't load MIDI: %s\n"), Mix_GetError());
-#else
-	(void)len;
-	(void)data;
-#endif
+	(void)track;
 	return false;
 }
 
-void I_SetMIDIMusicVolume(UINT8 volume)
-{
-#ifdef HAVE_MIXER
-	if ((nomidimusic && nodigimusic) || !musicStarted)
-		return;
-
-	if (Msc_Mutex) SDL_LockMutex(Msc_Mutex);
-	musicvol = volume * 2;
-	if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
-	Mix_VolumeMusic(musicvol);
-#else
-	(void)volume;
-#endif
-}
+/// ------------------------
+//  MUSIC LOADING AND CLEANUP
+//  \todo Split logic between loading and playing,
+//        then move to Playback section
+/// ------------------------
 
-#ifdef HAVE_LIBGME
+#if 0 //#ifdef HAVE_LIBGME
 static void I_CleanupGME(void *userdata)
 {
 	Z_Free(userdata);
 }
-#endif
 
 static boolean I_StartGMESong(const char *musicname, boolean looping)
 {
-#ifdef HAVE_LIBGME
-	XBOXSTATIC char filename[9];
+	char filename[9];
 	void *data;
 	lumpnum_t lumpnum;
 	size_t lumplength;
@@ -1768,240 +1496,7 @@ static boolean I_StartGMESong(const char *musicname, boolean looping)
 	Snd_UnlockAudio();
 
 	return true;
-#else
-	(void)musicname;
-	(void)looping;
-#endif
-	return false;
-}
-
-boolean I_StartDigSong(const char *musicname, boolean looping)
-{
-#ifdef HAVE_MIXER
-	XBOXSTATIC char filename[9];
-	void *data;
-	lumpnum_t lumpnum;
-	size_t lumplength;
-#endif
-
-	if(I_StartGMESong(musicname, looping))
-		return true;
-
-#ifdef HAVE_MIXER
-	if (nodigimusic)
-		return false;
-
-	snprintf(filename, sizeof filename, "o_%s", musicname);
-
-	lumpnum = W_CheckNumForName(filename);
-
-	I_StopDigSong();
-
-	if (lumpnum == LUMPERROR)
-	{
-		// Alam_GBC: like in win32/win_snd.c: Graue 02-29-2004: don't worry about missing music, there might still be a MIDI
-		//I_OutputMsg("Music lump %s not found!\n", filename);
-		return false; // No music found. Oh well!
-	}
-	else
-		lumplength = W_LumpLength(lumpnum);
-
-	data = W_CacheLumpNum(lumpnum, PU_MUSIC);
-
-	if (Msc_Mutex) SDL_LockMutex(Msc_Mutex);
-
-#ifdef MIXER_POS
-	if (canlooping && (loopingDig = looping) == SDL_TRUE && strcmp(data, "OggS")  == 0)
-		looping = false; // Only on looping Ogg files, will we will do our own looping
-
-	// Scan the Ogg Vorbis file for the COMMENT= field for a custom
-	// loop point
-	if (!looping && loopingDig)
-	{
-		size_t scan;
-		const char *dataum = data;
-		XBOXSTATIC char looplength[64];
-		UINT32 loopstart = 0;
-		UINT8 newcount = 0;
-
-		Mix_HookMusicFinished(I_FinishMusic);
-
-		for (scan = 0; scan < lumplength; scan++)
-		{
-			if (*dataum++ == 'C'){
-			if (*dataum++ == 'O'){
-			if (*dataum++ == 'M'){
-			if (*dataum++ == 'M'){
-			if (*dataum++ == 'E'){
-			if (*dataum++ == 'N'){
-			if (*dataum++ == 'T'){
-			if (*dataum++ == '='){
-			if (*dataum++ == 'L'){
-			if (*dataum++ == 'O'){
-			if (*dataum++ == 'O'){
-			if (*dataum++ == 'P'){
-			if (*dataum++ == 'P'){
-			if (*dataum++ == 'O'){
-			if (*dataum++ == 'I'){
-			if (*dataum++ == 'N'){
-			if (*dataum++ == 'T'){
-			if (*dataum++ == '=')
-			{
-
-				while (*dataum != 1 && newcount != 63)
-					looplength[newcount++] = *dataum++;
-
-				looplength[newcount] = '\0';
-
-				loopstart = atoi(looplength);
-
-			}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-			else
-				dataum--;}
-		}
-
-		if (loopstart > 0)
-		{
-			loopstartDig = (double)((44.1l+loopstart) / 44100.0l); //8 PCM chucks off and PCM to secs
-//#ifdef PARANOIA
-			//I_OutputMsg("I_StartDigSong: setting looping point to %ul PCMs(%f seconds)\n", loopstart, loopstartDig);
-//#endif
-		}
-		else
-		{
-			looping = true; // loopingDig true, but couldn't find start loop point
-		}
-	}
-	else
-		loopstartDig = 0.0l;
-#else
-	if (looping && strcmp(data, "OggS")  == 0)
-		I_OutputMsg("I_StartDigSong: SRB2 was not compiled with looping music support(no Mix_FadeInMusicPos)\n");
-#endif
-
-	if (!LoadSong(data, lumplength, 1))
-	{
-		if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
-		return false;
-	}
-
-	// Note: LoadSong() frees the data. Let's make sure
-	// we don't try to use the data again.
-	data = NULL;
-
-	if (Mix_FadeInMusic(music[1], looping ? -1 : 0, Digfade) == -1)
-	{
-		if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
-		I_OutputMsg("I_StartDigSong: Couldn't play song %s because %s\n", musicname, Mix_GetError());
-		return false;
-	}
-	Mix_VolumeMusic(musicvol);
-
-	if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
-	return true;
-#else
-	(void)looping;
-	(void)musicname;
-	return false;
-#endif
-}
-
-static void I_StopGME(void)
-{
-#ifdef HAVE_LIBGME
-	Snd_LockAudio();
-	gme_seek(localdata.gme_emu, 0);
-	Snd_UnlockAudio();
-#endif
 }
-
-void I_StopDigSong(void)
-{
-	I_StopGME();
-#ifdef HAVE_MIXER
-	if (nodigimusic)
-		return;
-
-#ifdef MIXER_POS
-	if (canlooping)
-		Mix_HookMusicFinished(NULL);
-#endif
-
-	Mix_HaltMusic();
-	while (Mix_PlayingMusic())
-		;
-
-	if (music[1])
-		Mix_FreeMusic(music[1]);
-	music[1] = NULL;
-	LoadSong(NULL, 0, 1);
 #endif
-}
-
-void I_SetDigMusicVolume(UINT8 volume)
-{
-	I_SetMIDIMusicVolume(volume);
-}
 
-boolean I_SetSongSpeed(float speed)
-{
-
-	(void)speed;
-	return false;
-}
-
-boolean I_SetSongTrack(int track)
-{
-	(void)track;
-	return false;
-}
-
-#ifdef MIXER_POS
-static void SDLCALL I_FinishMusic(void)
-{
-	if (!music[1])
-		return;
-	else if (Msc_Mutex) SDL_LockMutex(Msc_Mutex);
-//		I_OutputMsg("I_FinishMusic: Loopping song to %g seconds\n", loopstartDig);
-
-	if (Mix_FadeInMusicPos(music[1], loopstartDig ? 0 : -1, Digfade, loopstartDig) == 0)
-		Mix_VolumeMusic(musicvol);
-	else
-		I_OutputMsg("I_FinishMusic: Couldn't loop song because %s\n", Mix_GetError());
-
-	if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
-}
-#endif
-#endif //HAVE_SDL
+#endif //HAVE_SDL
\ No newline at end of file
diff --git a/src/sdl12/hwsym_sdl.c b/src/sdl12/hwsym_sdl.c
index 54f5da3a083da6d9b3b9159b059389cbc7bc8271..49340138f46bc5a98223f8895fd175b18ccad18d 100644
--- a/src/sdl12/hwsym_sdl.c
+++ b/src/sdl12/hwsym_sdl.c
@@ -100,6 +100,7 @@ void *hwSym(const char *funcName,void *handle)
 #ifdef SHUFFLE
 	GETFUNC(PostImgRedraw);
 #endif //SHUFFLE
+	GETFUNC(FlushScreenTextures);
 	GETFUNC(StartScreenWipe);
 	GETFUNC(EndScreenWipe);
 	GETFUNC(DoScreenWipe);
diff --git a/src/sdl12/i_cdmus.c b/src/sdl12/i_cdmus.c
index 1eeac370b25d27d438fb532087f4a3458c1762b0..b3490592eebcc9208ad788a0d7b7aa5a65558135 100644
--- a/src/sdl12/i_cdmus.c
+++ b/src/sdl12/i_cdmus.c
@@ -60,7 +60,7 @@ void SDL_SYS_CDQuit(void)
 
 UINT8 cdaudio_started = 0;   // for system startup/shutdown
 
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 #ifndef NOSDLCD
diff --git a/src/sdl12/i_video.c b/src/sdl12/i_video.c
index 197924edacceed81f86529616221bb649e0b80ae..349e06cbab345d3ca064bf1e6ce169b669706a77 100644
--- a/src/sdl12/i_video.c
+++ b/src/sdl12/i_video.c
@@ -1972,6 +1972,7 @@ void I_StartupGraphics(void)
 #ifdef SHUFFLE
 		HWD.pfnPostImgRedraw    = hwSym("PostImgRedraw",NULL);
 #endif
+		HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL);
 		HWD.pfnStartScreenWipe  = hwSym("StartScreenWipe",NULL);
 		HWD.pfnEndScreenWipe    = hwSym("EndScreenWipe",NULL);
 		HWD.pfnDoScreenWipe     = hwSym("DoScreenWipe",NULL);
diff --git a/src/sdl12/mixer_sound.c b/src/sdl12/mixer_sound.c
index 542a6716989793b0b3452a9825ef190ea95e585b..daf09ab911eb940208e3ff65655344769c396468 100644
--- a/src/sdl12/mixer_sound.c
+++ b/src/sdl12/mixer_sound.c
@@ -376,10 +376,10 @@ void I_FreeSfx(sfxinfo_t *sfx)
 	sfx->data = NULL;
 }
 
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
 {
 	UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127
-	INT32 handle = Mix_PlayChannel(-1, S_sfx[id].data, 0);
+	INT32 handle = Mix_PlayChannel(channel, S_sfx[id].data, 0);
 	Mix_Volume(handle, volume);
 	Mix_SetPanning(handle, min((UINT16)(0xff-sep)<<1, 0xff), min((UINT16)(sep)<<1, 0xff));
 	(void)pitch; // Mixer can't handle pitch
diff --git a/src/sdl12/sdl_sound.c b/src/sdl12/sdl_sound.c
index 6ba83104ee81033a0f9bb4935ecf25adfda1115e..01a27153e8c2941607ca8b206d2e02023a50119d 100644
--- a/src/sdl12/sdl_sound.c
+++ b/src/sdl12/sdl_sound.c
@@ -621,10 +621,11 @@ void I_FreeSfx(sfxinfo_t * sfx)
 // Pitching (that is, increased speed of playback)
 //  is set, but currently not used by mixing.
 //
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
 {
 	(void)priority;
 	(void)pitch;
+	(void)channel;
 
 	if (nosound)
 		return 0;
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 3562a9b713ef11bfec43436917ca56afbfa700bb..72e0b6b94c882881db6a7f7de6f616c287722817 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -210,17 +210,17 @@ void ST_doPaletteStuff(void)
 	else
 		palette = 0;
 
+#ifdef HWRENDER
+	if (rendermode == render_opengl)
+		palette = 0; // No flashpals here in OpenGL
+#endif
+
 	palette = min(max(palette, 0), 13);
 
 	if (palette != st_palette)
 	{
 		st_palette = palette;
 
-#ifdef HWRENDER
-		if (rendermode == render_opengl)
-			HWR_SetPaletteColor(0);
-		else
-#endif
 		if (rendermode != render_none)
 		{
 			V_SetPaletteLump(GetPalette()); // Reset the palette
diff --git a/src/v_video.c b/src/v_video.c
index cc81cedbc0acce13d4c0c8d0cb5756da3e91556c..802a4d388a943876d8f398a1523fe69c263a0e6d 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -418,7 +418,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
 		if (scrn & V_FLIP)
 		{
 			flip = true;
-			x -= FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<<FRACBITS, pscale);
+			x -= FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<<FRACBITS, pscale) + 1;
 		}
 		else
 			x -= FixedMul(SHORT(patch->leftoffset)<<FRACBITS, pscale);
@@ -446,37 +446,38 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
 		y = FixedMul(y,dupy<<FRACBITS);
 		x >>= FRACBITS;
 		y >>= FRACBITS;
-		desttop += (y*vid.width) + x;
 
 		// Center it if necessary
 		if (!(scrn & V_SCALEPATCHMASK))
 		{
+			// if it's meant to cover the whole screen, black out the rest
+			if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT)
+			{
+				column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0]));
+				source = (const UINT8 *)(column) + 3;
+				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
+			}
 			if (vid.width != BASEVIDWIDTH * dupx)
 			{
 				// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
 				// so center this imaginary screen
 				if (scrn & V_SNAPTORIGHT)
-					desttop += (vid.width - (BASEVIDWIDTH * dupx));
+					x += (vid.width - (BASEVIDWIDTH * dupx));
 				else if (!(scrn & V_SNAPTOLEFT))
-					desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
+					x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
 			}
 			if (vid.height != BASEVIDHEIGHT * dupy)
 			{
 				// same thing here
 				if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM))
-					desttop += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)) * vid.width;
+					y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy));
 				else if (scrn & V_SNAPTOBOTTOM)
-					desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
+					y += (vid.height - (BASEVIDHEIGHT * dupy));
 				else if (!(scrn & V_SNAPTOTOP))
-					desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
-			}
-			// if it's meant to cover the whole screen, black out the rest
-			if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT)
-			{
-				column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0]));
-				source = (const UINT8 *)(column) + 3;
-				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
+					y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
 			}
+
+			desttop += (y*vid.width) + x;
 		}
 	}
 
@@ -583,36 +584,37 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
 		y = FixedMul(y,dupy<<FRACBITS);
 		x >>= FRACBITS;
 		y >>= FRACBITS;
-		desttop += (y*vid.width) + x;
 
 		// Center it if necessary
 		if (!(scrn & V_SCALEPATCHMASK))
 		{
+			// if it's meant to cover the whole screen, black out the rest
+			if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT)
+			{
+				column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0]));
+				source = (const UINT8 *)(column) + 3;
+				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
+			}
 			if (vid.width != BASEVIDWIDTH * dupx)
 			{
 				// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
 				// so center this imaginary screen
 				if (scrn & V_SNAPTORIGHT)
-					desttop += (vid.width - (BASEVIDWIDTH * dupx));
+					x += (vid.width - (BASEVIDWIDTH * dupx));
 				else if (!(scrn & V_SNAPTOLEFT))
-					desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
+					x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
 			}
 			if (vid.height != BASEVIDHEIGHT * dupy)
 			{
 				// same thing here
 				if (scrn & V_SNAPTOBOTTOM)
-					desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
+					y += (vid.height - (BASEVIDHEIGHT * dupy));
 				else if (!(scrn & V_SNAPTOTOP))
-					desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
-			}
-			// if it's meant to cover the whole screen, black out the rest
-			if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT)
-			{
-				column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0]));
-				source = (const UINT8 *)(column) + 3;
-				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
+					y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
 			}
 		}
+
+		desttop += (y*vid.width) + x;
 	}
 
 	for (col = sx<<FRACBITS; (col>>FRACBITS) < SHORT(patch->width) && (col>>FRACBITS) < w; col += colfrac, ++x, desttop++)
@@ -651,14 +653,10 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
 //
 void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor)
 {
-	if (skins[skinnum].flags & SF_HIRES
-#ifdef HWRENDER
-//	|| (rendermode != render_soft && rendermode != render_none)
-#endif
-	)
-		V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE));
+	if (skinnum < 0 || skinnum >= numskins || (skins[skinnum].flags & SF_HIRES))
+		V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); // Draw a star
 	else
-	{
+	{ // Find front angle of the first waiting frame of the character's actual sprites
 		spriteframe_t *sprframe = &skins[skinnum].spritedef.spriteframes[2 & FF_FRAMEMASK];
 		patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
 		const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE);
@@ -776,7 +774,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
 
 		if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
 		{ // Clear the entire screen, from dest to deststop. Yes, this really works.
-			memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
+			memset(screens[0], (c&255), vid.width * vid.height * vid.bpp);
 			return;
 		}
 
@@ -831,7 +829,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
 	c &= 255;
 
 	for (;(--h >= 0) && dest < deststop; dest += vid.width)
-		memset(dest, (UINT8)(c&255), w * vid.bpp);
+		memset(dest, c, w * vid.bpp);
 }
 
 //
@@ -937,14 +935,6 @@ void V_DrawPatchFill(patch_t *pat)
 	INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
 	INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz;
 
-#ifdef HWRENDER
-	if (rendermode == render_opengl)
-	{
-		pw = FixedMul(SHORT(pat->width)*FRACUNIT, vid.fdupx)>>FRACBITS;
-		ph = FixedMul(SHORT(pat->height)*FRACUNIT, vid.fdupy)>>FRACBITS;
-	}
-#endif
-
 	for (x = 0; x < vid.width; x += pw)
 	{
 		for (y = 0; y < vid.height; y += ph)
@@ -1137,7 +1127,7 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
 //
 void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
 {
-	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0;
+	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0;
 	const char *ch = string;
 	INT32 charflags = 0;
 	const UINT8 *colormap = NULL;
@@ -1153,7 +1143,12 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth = vid.width;
 	}
 	else
+	{
 		dupx = dupy = 1;
+		scrwidth = vid.width/vid.dupx;
+		left = (scrwidth - BASEVIDWIDTH)/2;
+		scrwidth -= left;
+	}
 
 	charflags = (option & V_CHARCOLORMASK);
 
@@ -1214,9 +1209,9 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
 		else
 			w = SHORT(hu_font[c]->width) * dupx;
 
-		if (cx + w > scrwidth)
+		if (cx > scrwidth)
 			break;
-		if (cx < 0) //left boundary check
+		if (cx+left + w < 0) //left boundary check
 		{
 			cx += w;
 			continue;
@@ -1247,7 +1242,7 @@ void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string
 //
 void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
 {
-	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0;
+	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0;
 	const char *ch = string;
 	INT32 charflags = 0;
 	const UINT8 *colormap = NULL;
@@ -1263,7 +1258,12 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth = vid.width;
 	}
 	else
+	{
 		dupx = dupy = 1;
+		scrwidth = vid.width/vid.dupx;
+		left = (scrwidth - BASEVIDWIDTH)/2;
+		scrwidth -= left;
+	}
 
 	charflags = (option & V_CHARCOLORMASK);
 
@@ -1322,9 +1322,9 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
 		}
 		else
 			w = SHORT(hu_font[c]->width) * dupx / 2;
-		if (cx + w > scrwidth)
+		if (cx > scrwidth)
 			break;
-		if (cx < 0) //left boundary check
+		if (cx+left + w < 0) //left boundary check
 		{
 			cx += w;
 			continue;
@@ -1349,7 +1349,7 @@ void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *s
 //
 void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
 {
-	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH;
+	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0;
 	const char *ch = string;
 	INT32 charflags = 0;
 	const UINT8 *colormap = NULL;
@@ -1365,7 +1365,12 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth = vid.width;
 	}
 	else
+	{
 		dupx = dupy = 1;
+		scrwidth = vid.width/vid.dupx;
+		left = (scrwidth - BASEVIDWIDTH)/2;
+		scrwidth -= left;
+	}
 
 	charflags = (option & V_CHARCOLORMASK);
 
@@ -1422,9 +1427,9 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
 		else
 			w = (SHORT(tny_font[c]->width) * dupx);
 
-		if (cx + w > scrwidth)
+		if (cx > scrwidth)
 			break;
-		if (cx < 0) //left boundary check
+		if (cx+left + w < 0) //left boundary check
 		{
 			cx += w;
 			continue;
@@ -1447,7 +1452,7 @@ void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *st
 void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
 {
 	fixed_t cx = x, cy = y;
-	INT32 w, c, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0;
+	INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
 	const char *ch = string;
 	INT32 spacewidth = 4, charwidth = 0;
 
@@ -1461,7 +1466,12 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
 		scrwidth = vid.width;
 	}
 	else
+	{
 		dupx = dupy = 1;
+		scrwidth = vid.width/vid.dupx;
+		left = (scrwidth - BASEVIDWIDTH)/2;
+		scrwidth -= left;
+	}
 
 	switch (option & V_SPACINGMASK)
 	{
@@ -1515,9 +1525,9 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
 		else
 			w = SHORT(hu_font[c]->width) * dupx;
 
-		if ((cx>>FRACBITS) + w > scrwidth)
+		if ((cx>>FRACBITS) > scrwidth)
 			break;
-		if (cx < 0) //left boundary check
+		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
 		{
 			cx += w<<FRACBITS;
 			continue;
@@ -1617,7 +1627,7 @@ void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string)
 		}
 
 		w = SHORT(cred_font[c]->width) * dupx;
-		if ((cx>>FRACBITS) + w > scrwidth)
+		if ((cx>>FRACBITS) > scrwidth)
 			break;
 
 		V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT);
@@ -1653,7 +1663,7 @@ INT32 V_CreditStringWidth(const char *string)
 //
 void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
 {
-	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH;
+	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0;
 	const char *ch = string;
 
 	if (option & V_NOSCALESTART)
@@ -1663,7 +1673,12 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth = vid.width;
 	}
 	else
+	{
 		dupx = dupy = 1;
+		scrwidth = vid.width/vid.dupx;
+		left = (scrwidth - BASEVIDWIDTH)/2;
+		scrwidth -= left;
+	}
 
 	for (;;)
 	{
@@ -1685,11 +1700,10 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
 		}
 
 		w = SHORT(lt_font[c]->width) * dupx;
-		if (cx + w > scrwidth)
+		if (cx > scrwidth)
 			break;
+		if (cx+left + w < 0) //left boundary check
 
-		//left boundary check
-		if (cx < 0)
 		{
 			cx += w;
 			continue;
diff --git a/src/w_wad.c b/src/w_wad.c
index 3a8285593e81cf067750712cce9468a57fce771c..3f0082a164d1618843c16d57288a01196cafb197 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -194,16 +194,21 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum)
 		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
 			if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
 			{	// shameless copy+paste of code from LUA_LoadLump
-				char *name = malloc(strlen(wadfiles[wadnum]->filename)+10);
+				size_t len = strlen(wadfiles[wadnum]->filename);
+				char *name = malloc(len+10);
+
 				strcpy(name, wadfiles[wadnum]->filename);
-				if (!fasticmp(&name[strlen(name) - 4], ".soc")) {
+				if (!fasticmp(&name[len - 4], ".soc")) {
 					// If it's not a .soc file, copy the lump name in too.
-					name[strlen(wadfiles[wadnum]->filename)] = '|';
-					M_Memcpy(name+strlen(wadfiles[wadnum]->filename)+1, lump_p->name, 8);
-					name[strlen(wadfiles[wadnum]->filename)+9] = '\0';
+					name[len] = '|';
+					M_Memcpy(name+len+1, lump_p->name, 8);
+					name[len+9] = '\0';
 				}
+
 				CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
 				DEH_LoadDehackedLumpPwad(wadnum, lump);
+
+				free(name);
 			}
 			else if (memcmp(lump_p->name,"MAINCFG",8)==0) // Check for MAINCFG
 			{
diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c
index 4ac1506e5993ac139455a57c0a162d7a2e393fc7..2586b84405649d431e673d1f7c8e4bb3a4d27a9c 100644
--- a/src/win32/win_cd.c
+++ b/src/win32/win_cd.c
@@ -161,7 +161,7 @@ static BOOL wasPlaying;
 //static INT     cdVolume = 0;          // current cd volume (0-31)
 
 // 0-31 like Music & Sfx, though CD hardware volume is 0-255.
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 // allow Update for next/loop track
 // some crap cd drivers take up to
@@ -471,7 +471,7 @@ void I_PlayCD(UINT8 nTrack, UINT8 bLooping)
 	//faB: stop MIDI music, MIDI music will restart if volume is upped later
 	cv_digmusicvolume.value = 0;
 	cv_midimusicvolume.value = 0;
-	I_StopSong (0);
+	I_StopSong();
 
 	//faB: I don't use the notify message, I'm trying to minimize the delay
 	mciPlay.dwCallback = (DWORD)((size_t)hWndMain);
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index 8fa4d17f73c8857f49b4a3ab0ca9a8ae69ea9381..c9b3fba4eea522aec31a6e956387939cdc7665b0 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -117,6 +117,7 @@ static loadfunc_t hwdFuncTable[] = {
 #ifdef SHUFFLE
 	{"PostImgRedraw@4",     &hwdriver.pfnPostImgRedraw},
 #endif
+	{"FlushScreenTextures@0",&hwdriver.pfnFlushScreenTextures},
 	{"StartScreenWipe@0",   &hwdriver.pfnStartScreenWipe},
 	{"EndScreenWipe@0",     &hwdriver.pfnEndScreenWipe},
 	{"DoScreenWipe@4",      &hwdriver.pfnDoScreenWipe},
@@ -147,6 +148,7 @@ static loadfunc_t hwdFuncTable[] = {
 #ifdef SHUFFLE
 	{"PostImgRedraw",       &hwdriver.pfnPostImgRedraw},
 #endif
+	{"FlushScreenTextures"},&hwdriver.pfnFlushScreenTextures},
 	{"StartScreenWipe",     &hwdriver.pfnStartScreenWipe},
 	{"EndScreenWipe",       &hwdriver.pfnEndScreenWipe},
 	{"DoScreenWipe",        &hwdriver.pfnDoScreenWipe},
diff --git a/src/win32/win_main.c b/src/win32/win_main.c
index 6c774f5576dad667e64f990b2082df815049b563..bfe620a4343e88a45d8389005ba10df86aa409f3 100644
--- a/src/win32/win_main.c
+++ b/src/win32/win_main.c
@@ -110,9 +110,9 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
 
 			// pause music when alt-tab
 			if (appActive  && !paused)
-				I_ResumeSong(0);
+				I_ResumeSong();
 			else if (!paused)
-				I_PauseSong(0);
+				I_PauseSong();
 			{
 				HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
 				DWORD mode;
diff --git a/src/win32/win_snd.c b/src/win32/win_snd.c
index f168f1fe35efae4e483dd417142515f1849fe734..1e1b062f8a14fd9ad00a87b146d3f1402367575e 100644
--- a/src/win32/win_snd.c
+++ b/src/win32/win_snd.c
@@ -17,17 +17,13 @@
 #include "gme/gme.h"
 #define GME_TREBLE 5.0
 #define GME_BASS 1.0
-#ifdef HAVE_PNG /// TODO: compile with zlib support without libpng
-
-#define HAVE_ZLIB
 
+#ifdef HAVE_ZLIB
 #ifndef _MSC_VER
-#ifndef _WII
 #ifndef _LARGEFILE64_SOURCE
 #define _LARGEFILE64_SOURCE
 #endif
 #endif
-#endif
 
 #ifndef _LFS64_LARGEFILE
 #define _LFS64_LARGEFILE
@@ -38,13 +34,12 @@
 #endif
 
 #include "zlib.h"
-#endif
-#endif
+#endif // HAVE_ZLIB
+#endif // HAVE_LIBGME
 
 static FMOD_SYSTEM *fsys;
 static FMOD_SOUND *music_stream;
 static FMOD_CHANNEL *music_channel;
-static boolean midimode;
 
 static UINT8 music_volume, midi_volume, sfx_volume;
 static INT32 current_track;
@@ -357,12 +352,13 @@ void I_FreeSfx(sfxinfo_t *sfx)
 	sfx->data = NULL;
 }
 
-INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
+INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
 {
 	FMOD_SOUND *sound;
 	FMOD_CHANNEL *chan;
 	INT32 i;
 	float frequency;
+	(void)channel;
 
 	sound = (FMOD_SOUND *)S_sfx[id].data;
 	I_Assert(sound != NULL);
@@ -442,9 +438,9 @@ void I_SetSfxVolume(UINT8 volume)
 	sfx_volume = volume;
 }
 
-//
-// MUSIC
-//
+/// ------------------------
+//  MUSIC SYSTEM
+/// ------------------------
 
 void I_InitMusic(void)
 {
@@ -452,53 +448,111 @@ void I_InitMusic(void)
 
 void I_ShutdownMusic(void)
 {
-	I_ShutdownDigMusic();
-	I_ShutdownMIDIMusic();
+	I_StopSong();
 }
 
-void I_PauseSong(INT32 handle)
-{
-	UNREFERENCED_PARAMETER(handle);
-	if (music_stream)
-		FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, true));
-}
+/// ------------------------
+//  MUSIC PROPERTIES
+/// ------------------------
 
-void I_ResumeSong(INT32 handle)
+musictype_t I_SongType(void)
 {
-	UNREFERENCED_PARAMETER(handle);
-	if (music_stream)
-		FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, false));
+#ifdef HAVE_LIBGME
+	if (gme)
+		return MU_GME;
+#endif
+
+	if (!music_stream)
+		return MU_NONE;
+
+	FMOD_SOUND_TYPE type;
+	if (FMOD_Sound_GetFormat(music_stream, &type, NULL, NULL, NULL) == FMOD_OK)
+	{
+		switch(type)
+		{
+			case FMOD_SOUND_TYPE_WAV:
+				return MU_WAV;
+			case FMOD_SOUND_TYPE_MOD:
+				return MU_MOD;
+			case FMOD_SOUND_TYPE_MIDI:
+				return MU_MID;
+			case FMOD_SOUND_TYPE_OGGVORBIS:
+				return MU_OGG;
+			case FMOD_SOUND_TYPE_MPEG:
+				return MU_MP3;
+			case FMOD_SOUND_TYPE_FLAC:
+				return MU_FLAC;
+			default:
+				return MU_NONE;
+		}
+	}
+	else
+		return MU_NONE;
 }
 
-void I_InitDigMusic(void)
+boolean I_SongPlaying(void)
 {
+	return (boolean)music_stream;
 }
 
-void I_ShutdownDigMusic(void)
+boolean I_SongPaused(void)
 {
-	if (!midimode)
-		I_StopDigSong();
+	boolean fmpaused = false;
+	if (music_stream)
+		FMOD_Channel_GetPaused(music_channel, &fmpaused);
+	return fmpaused;
 }
 
-boolean I_StartDigSong(const char *musicname, boolean looping)
+/// ------------------------
+//  MUSIC EFFECTS
+/// ------------------------
+
+boolean I_SetSongSpeed(float speed)
 {
-	char *data;
-	size_t len;
-	FMOD_CREATESOUNDEXINFO fmt;
-	lumpnum_t lumpnum = W_CheckNumForName(va("O_%s",musicname));
+	FMOD_RESULT e;
+	float frequency;
+	if (!music_stream)
+		return false;
+	if (speed > 250.0f)
+		speed = 250.0f; //limit speed up to 250x
 
-	if (lumpnum == LUMPERROR)
+#ifdef HAVE_LIBGME
+	// Try to set GME speed
+	if (gme)
 	{
-		lumpnum = W_CheckNumForName(va("D_%s",musicname));
-		if (lumpnum == LUMPERROR)
-			return false;
-		midimode = true;
+		gme_set_tempo(gme, speed);
+		return true;
+	}
+#endif
+
+	// Try to set Mod/Midi speed
+	e = FMOD_Sound_SetMusicSpeed(music_stream, speed);
+
+	if (e == FMOD_ERR_FORMAT)
+	{
+		// Just change pitch instead for Ogg/etc.
+		FMR(FMOD_Sound_GetDefaults(music_stream, &frequency, NULL, NULL, NULL));
+		FMR_MUSIC(FMOD_Channel_SetFrequency(music_channel, speed*frequency));
 	}
 	else
-		midimode = false;
+		FMR_MUSIC(e);
 
-	data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC);
-	len = W_LumpLength(lumpnum);
+	return true;
+}
+
+/// ------------------------
+//  MUSIC PLAYBACK
+/// ------------------------
+
+boolean I_LoadSong(char *data, size_t len)
+{
+	FMOD_CREATESOUNDEXINFO fmt;
+	FMOD_RESULT e;
+	FMOD_TAG tag;
+	unsigned int loopstart, loopend;
+
+	if (gme || music_stream)
+		I_UnloadSong();
 
 	memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO));
 	fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
@@ -533,8 +587,6 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 					gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
 					Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around
 					Z_Free(data); // We don't need this, either.
-					gme_start_track(gme, 0);
-					current_track = 0;
 					gme_set_equalizer(gme,&gmeq);
 					fmt.format = FMOD_SOUND_FORMAT_PCM16;
 					fmt.defaultfrequency = 44100;
@@ -543,10 +595,7 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 					fmt.decodebuffersize = (44100 * 2) / 35;
 					fmt.pcmreadcallback = GMEReadCallback;
 					fmt.userdata = gme;
-					FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER | (looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream));
-					FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel));
-					FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
-					FMR(FMOD_Channel_SetPriority(music_channel, 0));
+					FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER, &fmt, &music_stream));
 					return true;
 				}
 			}
@@ -605,8 +654,6 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 	{
 		gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
 		Z_Free(data); // We don't need this anymore.
-		gme_start_track(gme, 0);
-		current_track = 0;
 		gme_set_equalizer(gme,&gmeq);
 		fmt.format = FMOD_SOUND_FORMAT_PCM16;
 		fmt.defaultfrequency = 44100;
@@ -615,149 +662,153 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 		fmt.decodebuffersize = (44100 * 2) / 35;
 		fmt.pcmreadcallback = GMEReadCallback;
 		fmt.userdata = gme;
-		FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER | (looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream));
-		FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel));
-		FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
-		FMR(FMOD_Channel_SetPriority(music_channel, 0));
+		FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER, &fmt, &music_stream));
 		return true;
 	}
 #endif
 
 	fmt.length = len;
+
+	e = FMOD_System_CreateStream(fsys, data, FMOD_OPENMEMORY_POINT, &fmt, &music_stream);
+	if (e != FMOD_OK)
 	{
-		FMOD_RESULT e = FMOD_System_CreateStream(fsys, data, FMOD_OPENMEMORY_POINT|(looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream);
-		if (e != FMOD_OK)
-		{
-			if (e == FMOD_ERR_FORMAT)
-				CONS_Alert(CONS_WARNING, "Failed to play music lump %s due to invalid format.\n", W_CheckNameForNum(lumpnum));
-			else
-				FMR(e);
-			return false;
-		}
+		if (e == FMOD_ERR_FORMAT)
+			CONS_Alert(CONS_WARNING, "Failed to play music lump due to invalid format.\n");
+		else
+			FMR(e);
+		return false;
 	}
-	FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel));
-	if (midimode)
-		FMR(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0));
-	else
-		FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
-	FMR(FMOD_Channel_SetPriority(music_channel, 0));
-	current_track = 0;
 
 	// Try to find a loop point in streaming music formats (ogg, mp3)
-	if (looping)
+
+	// A proper LOOPPOINT is its own tag, stupid.
+	e = FMOD_Sound_GetTag(music_stream, "LOOPPOINT", 0, &tag);
+	if (e != FMOD_ERR_TAGNOTFOUND)
 	{
-		FMOD_RESULT e;
-		FMOD_TAG tag;
-		unsigned int loopstart, loopend;
+		FMR(e);
+		loopstart = atoi((char *)tag.data); // assumed to be a string data tag.
+		FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM));
+		if (loopstart > 0)
+			FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM));
+		return true;
+	}
 
-		// A proper LOOPPOINT is its own tag, stupid.
-		e = FMOD_Sound_GetTag(music_stream, "LOOPPOINT", 0, &tag);
-		if (e != FMOD_ERR_TAGNOTFOUND)
+	// Use LOOPMS for time in miliseconds.
+	e = FMOD_Sound_GetTag(music_stream, "LOOPMS", 0, &tag);
+	if (e != FMOD_ERR_TAGNOTFOUND)
+	{
+		FMR(e);
+		loopstart = atoi((char *)tag.data); // assumed to be a string data tag.
+		FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_MS, &loopend, FMOD_TIMEUNIT_PCM));
+		if (loopstart > 0)
+			FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_MS, loopend, FMOD_TIMEUNIT_PCM));
+		return true;
+	}
+
+	// Try to fetch it from the COMMENT tag, like A.J. Freda
+	e = FMOD_Sound_GetTag(music_stream, "COMMENT", 0, &tag);
+	if (e != FMOD_ERR_TAGNOTFOUND)
+	{
+		char *loopText;
+		// Handle any errors that arose, first
+		FMR(e);
+		// Figure out where the number starts
+		loopText = strstr((char *)tag.data,"LOOPPOINT=");
+		if (loopText != NULL)
 		{
-			FMR(e);
-			loopstart = atoi((char *)tag.data); // assumed to be a string data tag.
+			// Skip the "LOOPPOINT=" part.
+			loopText += 10;
+			// Convert it to our looppoint
+			// FMOD seems to ensure the tag is properly NULL-terminated.
+			// atoi will stop when it reaches anything that's not a number.
+			loopstart = atoi(loopText);
+			// Now do the rest like above
 			FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM));
 			if (loopstart > 0)
 				FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM));
-			return true;
-		}
-
-		// Use LOOPMS for time in miliseconds.
-		e = FMOD_Sound_GetTag(music_stream, "LOOPMS", 0, &tag);
-		if (e != FMOD_ERR_TAGNOTFOUND)
-		{
-			FMR(e);
-			loopstart = atoi((char *)tag.data); // assumed to be a string data tag.
-			FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_MS, &loopend, FMOD_TIMEUNIT_PCM));
-			if (loopstart > 0)
-				FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_MS, loopend, FMOD_TIMEUNIT_PCM));
-			return true;
-		}
-
-		// Try to fetch it from the COMMENT tag, like A.J. Freda
-		e = FMOD_Sound_GetTag(music_stream, "COMMENT", 0, &tag);
-		if (e != FMOD_ERR_TAGNOTFOUND)
-		{
-			char *loopText;
-			// Handle any errors that arose, first
-			FMR(e);
-			// Figure out where the number starts
-			loopText = strstr((char *)tag.data,"LOOPPOINT=");
-			if (loopText != NULL)
-			{
-				// Skip the "LOOPPOINT=" part.
-				loopText += 10;
-				// Convert it to our looppoint
-				// FMOD seems to ensure the tag is properly NULL-terminated.
-				// atoi will stop when it reaches anything that's not a number.
-				loopstart = atoi(loopText);
-				// Now do the rest like above
-				FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM));
-				if (loopstart > 0)
-					FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM));
-			}
-			return true;
 		}
+		return true;
 	}
 
-	// No special loop point, but we're playing so it's all good.
+	// No special loop point
 	return true;
 }
 
-void I_StopDigSong(void)
+void I_UnloadSong(void)
 {
-	if (music_stream)
-		FMR(FMOD_Sound_Release(music_stream));
-	music_stream = NULL;
+	I_StopSong();
 #ifdef HAVE_LIBGME
 	if (gme)
+	{
 		gme_delete(gme);
-	gme = NULL;
+		gme = NULL;
+	}
 #endif
-	current_track = -1;
-}
-
-void I_SetDigMusicVolume(UINT8 volume)
-{
-	// volume is 0 to 31.
-	music_volume = volume;
-	if (!midimode && music_stream)
-		FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, volume / 31.0));
+	if (music_stream)
+	{
+		FMR(FMOD_Sound_Release(music_stream));
+		music_stream = NULL;
+	}
 }
 
-boolean I_SetSongSpeed(float speed)
+boolean I_PlaySong(boolean looping)
 {
-	FMOD_RESULT e;
-	float frequency;
-	if (!music_stream)
-		return false;
-	if (speed > 250.0f)
-		speed = 250.0f; //limit speed up to 250x
-
 #ifdef HAVE_LIBGME
-	// Try to set GME speed
 	if (gme)
 	{
-		gme_set_tempo(gme, speed);
+		gme_start_track(gme, 0);
+		current_track = 0;
+		FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel));
+		FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
+		FMR(FMOD_Channel_SetPriority(music_channel, 0));
 		return true;
 	}
 #endif
 
-	// Try to set Mod/Midi speed
-	e = FMOD_Sound_SetMusicSpeed(music_stream, speed);
-
-	if (e == FMOD_ERR_FORMAT)
-	{
-		// Just change pitch instead for Ogg/etc.
-		FMR(FMOD_Sound_GetDefaults(music_stream, &frequency, NULL, NULL, NULL));
-		FMR_MUSIC(FMOD_Channel_SetFrequency(music_channel, speed*frequency));
-	}
+	FMR(FMOD_Sound_SetMode(music_stream, (looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF)));
+	FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel));
+	if (I_SongType() != MU_MID)
+		FMR(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0));
 	else
-		FMR_MUSIC(e);
+		FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
+	FMR(FMOD_Channel_SetPriority(music_channel, 0));
+	current_track = 0;
 
 	return true;
 }
 
+void I_StopSong(void)
+{
+	if (music_channel)
+		FMR_MUSIC(FMOD_Channel_Stop(music_channel));
+}
+
+void I_PauseSong(void)
+{
+	if (music_channel)
+		FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, true));
+}
+
+void I_ResumeSong(void)
+{
+	if (music_channel)
+		FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, false));
+}
+
+void I_SetMusicVolume(UINT8 volume)
+{
+	if (!music_channel)
+		return;
+
+	// volume is 0 to 31.
+	if (I_SongType() == MU_MID)
+		music_volume = 31; // windows bug hack
+	else
+		music_volume = volume;
+
+	FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
+}
+
 boolean I_SetSongTrack(INT32 track)
 {
 	if (track != current_track) // If the track's already playing, then why bother?
@@ -802,62 +853,3 @@ boolean I_SetSongTrack(INT32 track)
 	}
 	return false;
 }
-
-//
-// Fuck MIDI. ... Okay fine, you can have your silly D_-only mode.
-//
-
-void I_InitMIDIMusic(void)
-{
-}
-
-void I_ShutdownMIDIMusic(void)
-{
-	if (midimode)
-		I_StopSong(0);
-}
-
-void I_SetMIDIMusicVolume(UINT8 volume)
-{
-	// volume is 0 to 31.
-	midi_volume = volume;
-	if (midimode && music_stream)
-		FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, volume / 31.0));
-}
-
-INT32 I_RegisterSong(void *data, size_t len)
-{
-	FMOD_CREATESOUNDEXINFO fmt;
-	memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO));
-	fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
-	fmt.length = len;
-	FMR(FMOD_System_CreateStream(fsys, (char *)data, FMOD_OPENMEMORY_POINT, &fmt, &music_stream));
-	return 1337;
-}
-
-boolean I_PlaySong(INT32 handle, boolean looping)
-{
-	if (1337 == handle)
-	{
-		midimode = true;
-		if (looping)
-			FMR(FMOD_Sound_SetMode(music_stream, FMOD_LOOP_NORMAL));
-		FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel));
-		FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0));
-		FMR_MUSIC(FMOD_Channel_SetPriority(music_channel, 0));
-	}
-	return true;
-}
-
-void I_StopSong(INT32 handle)
-{
-	I_UnRegisterSong(handle);
-}
-
-void I_UnRegisterSong(INT32 handle)
-{
-	UNREFERENCED_PARAMETER(handle);
-	if (music_stream)
-		FMR(FMOD_Sound_Release(music_stream));
-	music_stream = NULL;
-}
diff --git a/src/win32ce/win_cd.c b/src/win32ce/win_cd.c
index 2b1a8be9a4321255c0ce2e9e89d32b044d54deeb..940f59ff2205575ddd38e791baa1ab1e09b2c012 100644
--- a/src/win32ce/win_cd.c
+++ b/src/win32ce/win_cd.c
@@ -159,7 +159,7 @@ static boolean wasPlaying;
 //static int     cdVolume = 0;          // current cd volume (0-31)
 
 // 0-31 like Music & Sfx, though CD hardware volume is 0-255.
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 // allow Update for next/loop track
 // some crap cd drivers take up to
diff --git a/src/win32ce/win_snd.c b/src/win32ce/win_snd.c
index f9c6521786717c45fabd620a54a500295e82a708..14ce4add4dd42f0b42d42d1f82122acbf35cc211 100644
--- a/src/win32ce/win_snd.c
+++ b/src/win32ce/win_snd.c
@@ -538,7 +538,8 @@ INT32 I_StartSound (sfxenum_t      id,
                   INT32          vol,
                   INT32          sep,
                   INT32          pitch,
-                  INT32          priority)
+                  INT32          priority,
+				  INT32          channel)
 {
 	HRESULT     hr;
 	LPDIRECTSOUNDBUFFER     dsbuffer;
@@ -549,6 +550,7 @@ INT32 I_StartSound (sfxenum_t      id,
 #ifdef SURROUND
 	LPDIRECTSOUNDBUFFER     dssurround;
 #endif
+	(void)channel;
 
 	if (nosound)
 		return -1;