From d87251f8537fe622ca5bbf0c2b42692eeff23a1a Mon Sep 17 00:00:00 2001
From: MascaraSnake <jonassauer27@gmail.com>
Date: Sat, 7 Dec 2019 09:51:09 +0100
Subject: [PATCH 01/52] Rename SDURF to SURF and CastleBot FaceStabber to
 Lance-a-Bot for maximum pun

---
 extras/conf/SRB2-22.cfg | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg
index e31402a6c..aa7e76eb0 100644
--- a/extras/conf/SRB2-22.cfg
+++ b/extras/conf/SRB2-22.cfg
@@ -3292,7 +3292,7 @@ thingtypes
 		}
 		102
 		{
-			title = "Stupid Dumb Unnamed RoboFish";
+			title = "Stupid Unnamed RoboFish";
 			sprite = "FISHA0";
 			width = 8;
 			height = 28;
@@ -3389,14 +3389,14 @@ thingtypes
 		}
 		118
 		{
-			title = "CastleBot FaceStabber";
+			title = "Lance-a-Bot";
 			sprite = "CBFSA1";
 			width = 32;
 			height = 72;
 		}
 		1113
 		{
-			title = "Suspicious FaceStabber Statue";
+			title = "Suspicious Lance-a-Bot Statue";
 			sprite = "CBBSA1";
 			width = 32;
 			height = 72;
@@ -5006,7 +5006,7 @@ thingtypes
 		{
 			arrow = 1;
 			blocking = 2;
-			title = "FaceStabber Statue";
+			title = "Lance-a-Bot Statue";
 			sprite = "CBBSA1";
 			width = 32;
 			height = 72;

From 2775d5f52f64e713cc4c4d2530055d9c51b4d032 Mon Sep 17 00:00:00 2001
From: MascaraSnake <jonassauer27@gmail.com>
Date: Sat, 7 Dec 2019 06:46:37 -0500
Subject: [PATCH 02/52] SDURF to SURF turned out to be contentious.

---
 extras/conf/SRB2-22.cfg | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg
index aa7e76eb0..5bc48211c 100644
--- a/extras/conf/SRB2-22.cfg
+++ b/extras/conf/SRB2-22.cfg
@@ -3292,7 +3292,7 @@ thingtypes
 		}
 		102
 		{
-			title = "Stupid Unnamed RoboFish";
+			title = "Stupid Dumb Unnamed RoboFish";
 			sprite = "FISHA0";
 			width = 8;
 			height = 28;

From cadaecbfcf6263f427a3ba2a5a92387bc7b77414 Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Sat, 7 Dec 2019 15:47:18 -0800
Subject: [PATCH 03/52] memset this or the stupid masterserver (used to) show
 garbage bytes

Also for security I guess...
---
 src/d_clisrv.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 188304fda..7b6c35eb6 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -1301,6 +1301,8 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
 
 	M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
 
+	memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle);
+
 	if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl)
 	{
 		char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle;
@@ -1319,8 +1321,6 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
 	else
 		strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32);
 
-	netbuffer->u.serverinfo.maptitle[32] = '\0';
-
 	if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
 		netbuffer->u.serverinfo.iszone = 1;
 	else

From e9e0683d5efa1c21b0da5d698acd124421c90c42 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sat, 7 Dec 2019 23:46:05 -0300
Subject: [PATCH 04/52] Cleanup FreeMipmapColormap

---
 src/hardware/hw_cache.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 328e623bd..fced24566 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -776,22 +776,36 @@ static void FreeMipmapColormap(INT32 patchnum, void *patch)
 {
 	GLPatch_t* const pat = patch;
 	(void)patchnum; //unused
-	while (pat->mipmap && pat->mipmap->nextcolormap) // The mipmap must be valid, obviously
+
+	// The patch must be valid, obviously
+	if (!pat)
+		return;
+
+	// The mipmap must be valid, obviously
+	while (pat->mipmap)
 	{
 		// Confusing at first, but pat->mipmap->nextcolormap
 		// at the beginning of the loop is the first colormap
-		// from the linked list of colormaps
-		GLMipmap_t *next = pat->mipmap;
-		if (!next) // No mipmap in this patch, break out of loop.
+		// from the linked list of colormaps.
+		GLMipmap_t *next = NULL;
+
+		// No mipmap in this patch, break out of the loop.
+		if (!pat->mipmap)
 			break;
-		// Set the first colormap
-		// to the one that comes after it
-		next = next->nextcolormap;
+
+		// No colormap mipmap either.
+		if (!pat->mipmap->nextcolormap)
+			break;
+
+		// Set the first colormap to the one that comes after it.
+		next = pat->mipmap->nextcolormap;
 		pat->mipmap->nextcolormap = next->nextcolormap;
-		// Free image data from memory
+
+		// Free image data from memory.
 		if (next->grInfo.data)
 			Z_Free(next->grInfo.data);
-		// Free the old colormap from memory
+
+		// Free the old colormap from memory.
 		free(next);
 	}
 }

From 40b862967d3a4aef3cca63a10f6399ce1c7af47c Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sat, 7 Dec 2019 23:55:28 -0300
Subject: [PATCH 05/52] Just in case?

---
 src/hardware/hw_main.c | 4 ++++
 src/hardware/hw_md2.c  | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 51c976973..c770448e6 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6172,6 +6172,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 
 	//04/01/2000: Hurdler: added for T&L
 	//                     It should replace all other gr_viewxxx when finished
+	memset(&atransform, 0x00, sizeof(FTransform));
+
 	atransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 
@@ -6390,6 +6392,8 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 
 	//04/01/2000: Hurdler: added for T&L
 	//                     It should replace all other gr_viewxxx when finished
+	memset(&atransform, 0x00, sizeof(FTransform));
+
 	atransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 9d9171cea..9245d7fc2 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -915,6 +915,8 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 	if (spr->precip)
 		return;
 
+	memset(&p, 0x00, sizeof(FTransform));
+
 	// MD2 colormap fix
 	// colormap test
 	if (spr->mobj->subsector)

From bc60a0a8876124b152084f5d45f03bece7e58ff2 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 01:54:03 -0300
Subject: [PATCH 06/52] Make some things clearer here.

---
 src/hardware/hw_cache.c | 43 +++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index fced24566..e19bd8331 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -760,15 +760,15 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm
 //             CACHING HANDLING
 // =================================================
 
-static size_t gr_numtextures;
-static GLTexture_t *gr_textures; // for ALL Doom textures
-static GLTexture_t *gr_textures2;
+static size_t gr_numtextures; // Texture count
+static GLTexture_t *gr_textures; // For all textures
+static GLTexture_t *gr_flats; // For all (texture) flats, as normal flats don't need to be cached
 
 void HWR_InitTextureCache(void)
 {
 	gr_numtextures = 0;
 	gr_textures = NULL;
-	gr_textures2 = NULL;
+	gr_flats = NULL;
 }
 
 // Callback function for HWR_FreeTextureCache.
@@ -831,10 +831,10 @@ void HWR_FreeTextureCache(void)
 	// texturecache info, we can free it
 	if (gr_textures)
 		free(gr_textures);
-	if (gr_textures2)
-		free(gr_textures2);
+	if (gr_flats)
+		free(gr_flats);
 	gr_textures = NULL;
-	gr_textures2 = NULL;
+	gr_flats = NULL;
 	gr_numtextures = 0;
 }
 
@@ -848,13 +848,15 @@ void HWR_PrepLevelCache(size_t pnumtextures)
 	// we must free it since numtextures changed
 	HWR_FreeTextureCache();
 
+	// Why not Z_Malloc?
 	gr_numtextures = pnumtextures;
-	gr_textures = calloc(pnumtextures, sizeof (*gr_textures));
-	if (gr_textures == NULL)
-		I_Error("3D can't alloc gr_textures");
-	gr_textures2 = calloc(pnumtextures, sizeof (*gr_textures2));
-	if (gr_textures2 == NULL)
-		I_Error("3D can't alloc gr_textures2");
+	gr_textures = calloc(gr_numtextures, sizeof(*gr_textures));
+	gr_flats = calloc(gr_numtextures, sizeof(*gr_flats));
+
+	// Doesn't tell you which it _is_, but hopefully
+	// should never ever happen (right?!)
+	if ((gr_textures == NULL) || (gr_flats == NULL))
+		I_Error("HWR_PrepLevelCache: ran out of memory for OpenGL textures. Sad!");
 }
 
 void HWR_SetPalette(RGBA_t *palette)
@@ -887,11 +889,16 @@ GLTexture_t *HWR_GetTexture(INT32 tex)
 	if ((unsigned)tex >= gr_numtextures)
 		I_Error("HWR_GetTexture: tex >= numtextures\n");
 #endif
+
+	// Every texture in memory, stored in the
+	// hardware renderer's bit depth format. Wow!
 	grtex = &gr_textures[tex];
 
+	// Generate texture if missing from the cache
 	if (!grtex->mipmap.grInfo.data && !grtex->mipmap.downloaded)
 		HWR_GenerateTexture(tex, grtex);
 
+	// Tell the hardware driver to bind the current texture to the flat's mipmap
 	HWD.pfnSetTexture(&grtex->mipmap);
 
 	// The system-memory data can be purged now.
@@ -1003,13 +1010,19 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 		if ((unsigned)texturenum >= gr_numtextures)
 			I_Error("HWR_GetLevelFlat: texturenum >= numtextures\n");
 #endif
+
+		// Who knows?
 		if (texturenum == 0 || texturenum == -1)
 			return;
-		grtex = &gr_textures2[texturenum];
 
+		// Every texture in memory, stored as a 8-bit flat. Wow!
+		grtex = &gr_flats[texturenum];
+
+		// Generate flat if missing from the cache
 		if (!grtex->mipmap.grInfo.data && !grtex->mipmap.downloaded)
 			HWR_CacheTextureAsFlat(&grtex->mipmap, texturenum);
 
+		// Tell the hardware driver to bind the current texture to the flat's mipmap
 		HWD.pfnSetTexture(&grtex->mipmap);
 
 		// The system-memory data can be purged now.
@@ -1033,6 +1046,7 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch)
 		HWR_MakePatch(patch, gpatch, grmip, true);
 
 		// You can't free rawpatch for some reason?
+		// (Obviously I can't, sprite rotation needs that...)
 		if (!gpatch->rawpatch)
 			Z_Free(patch);
 	}
@@ -1060,7 +1074,6 @@ void HWR_GetPatch(GLPatch_t *gpatch)
 
 		// this is inefficient.. but the hardware patch in heap is purgeable so it should
 		// not fragment memory, and besides the REAL cache here is the hardware memory
-		// You can't free rawpatch for some reason?
 		if (!gpatch->rawpatch)
 			Z_Free(ptr);
 	}

From 964978a33759cae86721eddb9bb9085ff1567e2c Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 02:25:53 -0300
Subject: [PATCH 07/52] Delete md2_transform

---
 src/hardware/r_opengl/r_opengl.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 25bcf153b..fbb5d9efe 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -85,7 +85,6 @@ static GLboolean MipMap = GL_FALSE;
 static GLint min_filter = GL_LINEAR;
 static GLint mag_filter = GL_LINEAR;
 static GLint anisotropic_filter = 0;
-static FTransform  md2_transform;
 
 const GLubyte *gl_extensions = NULL;
 
@@ -2226,8 +2225,6 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
 	if (stransform)
 	{
 		boolean fovx90;
-		// keep a trace of the transformation for md2
-		memcpy(&md2_transform, stransform, sizeof (md2_transform));
 
 #ifdef USE_FTRANSFORM_MIRROR
 		// mirroring from Kart

From ce61b17117b887b2825ce6360c5b9aa9320ddbbc Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 02:27:51 -0300
Subject: [PATCH 08/52] Update hw_main.c

---
 src/hardware/hw_main.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index c770448e6..db4990436 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -5941,7 +5941,7 @@ static void HWR_DrawSkyBackground(player_t *player)
 {
 	if (cv_grskydome.value)
 	{
-		FTransform transform;
+		FTransform dometransform;
 		const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
 		postimg_t *type;
 
@@ -5950,27 +5950,27 @@ static void HWR_DrawSkyBackground(player_t *player)
 		else
 			type = &postimgtype;
 
-		memset(&transform, 0x00, sizeof(FTransform));
+		memset(&dometransform, 0x00, sizeof(FTransform));
 
 		//04/01/2000: Hurdler: added for T&L
 		//                     It should replace all other gr_viewxxx when finished
-		transform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
-		transform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
+		dometransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
+		dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 
 		if (*type == postimg_flip)
-			transform.flip = true;
+			dometransform.flip = true;
 		else
-			transform.flip = false;
+			dometransform.flip = false;
 
-		transform.scalex = 1;
-		transform.scaley = (float)vid.width/vid.height;
-		transform.scalez = 1;
-		transform.fovxangle = fpov; // Tails
-		transform.fovyangle = fpov; // Tails
-		transform.splitscreen = splitscreen;
+		dometransform.scalex = 1;
+		dometransform.scaley = (float)vid.width/vid.height;
+		dometransform.scalez = 1;
+		dometransform.fovxangle = fpov; // Tails
+		dometransform.fovyangle = fpov; // Tails
+		dometransform.splitscreen = splitscreen;
 
 		HWR_GetTexture(texturetranslation[skytexture]);
-		HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, transform);
+		HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform);
 	}
 	else
 	{

From cc12496e9c3fce929546640bbe2c1b35056d7a86 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 03:23:37 -0300
Subject: [PATCH 09/52] Optimize mipmaps

---
 src/hardware/hw_cache.c | 22 ++++++++++++----------
 src/hardware/hw_glob.h  |  1 +
 src/hardware/hw_main.c  |  1 +
 src/hardware/hw_main.h  |  2 +-
 src/p_setup.c           | 20 +++++++++++---------
 src/r_data.c            |  9 +++++++++
 6 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index e19bd8331..aef97e817 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -804,15 +804,17 @@ static void FreeMipmapColormap(INT32 patchnum, void *patch)
 		// Free image data from memory.
 		if (next->grInfo.data)
 			Z_Free(next->grInfo.data);
+		next->grInfo.data = NULL;
 
-		// Free the old colormap from memory.
+		// Free the old colormap mipmap from memory.
 		free(next);
 	}
 }
 
-void HWR_FreeTextureCache(void)
+void HWR_FreeMipmapCache(void)
 {
 	INT32 i;
+
 	// free references to the textures
 	HWD.pfnClearMipMapCache();
 
@@ -822,10 +824,15 @@ void HWR_FreeTextureCache(void)
 	Z_FreeTag(PU_HWRCACHE_UNLOCKED);
 
 	// Alam: free the Z_Blocks before freeing it's users
-
 	// free all patch colormaps after each level: must be done after ClearMipMapCache!
 	for (i = 0; i < numwadfiles; i++)
 		M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);
+}
+
+void HWR_FreeTextureCache(void)
+{
+	// free references to the textures
+	HWR_FreeMipmapCache();
 
 	// now the heap don't have any 'user' pointing to our
 	// texturecache info, we can free it
@@ -838,13 +845,8 @@ void HWR_FreeTextureCache(void)
 	gr_numtextures = 0;
 }
 
-void HWR_PrepLevelCache(size_t pnumtextures)
+void HWR_LoadTextures(size_t pnumtextures)
 {
-	// problem: the mipmap cache management hold a list of mipmaps.. but they are
-	//           reallocated on each level..
-	//sub-optimal, but 1) just need re-download stuff in hardware cache VERY fast
-	//   2) sprite/menu stuff mixed with level textures so can't do anything else
-
 	// we must free it since numtextures changed
 	HWR_FreeTextureCache();
 
@@ -856,7 +858,7 @@ void HWR_PrepLevelCache(size_t pnumtextures)
 	// Doesn't tell you which it _is_, but hopefully
 	// should never ever happen (right?!)
 	if ((gr_textures == NULL) || (gr_flats == NULL))
-		I_Error("HWR_PrepLevelCache: ran out of memory for OpenGL textures. Sad!");
+		I_Error("HWR_LoadTextures: ran out of memory for OpenGL textures. Sad!");
 }
 
 void HWR_SetPalette(RGBA_t *palette)
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 69cf8bf46..d25f6cefd 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -100,6 +100,7 @@ void HWR_FreePolyPool(void);
 // --------
 void HWR_InitTextureCache(void);
 void HWR_FreeTextureCache(void);
+void HWR_FreeMipmapCache(void);
 void HWR_FreeExtraSubsectors(void);
 
 void HWR_GetLevelFlat(levelflat_t *levelflat);
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index db4990436..5baf89e6c 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6687,6 +6687,7 @@ void HWR_Shutdown(void)
 	CONS_Printf("HWR_Shutdown()\n");
 	HWR_FreeExtraSubsectors();
 	HWR_FreePolyPool();
+	HWR_FreeMipmapCache();
 	HWR_FreeTextureCache();
 	HWD.pfnFlushScreenTextures();
 }
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index e19c557d0..3ff7e98c9 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -47,7 +47,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale
 void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap);
 void HWR_CreatePlanePolygons(INT32 bspnum);
 void HWR_CreateStaticLightmaps(INT32 bspnum);
-void HWR_PrepLevelCache(size_t pnumtextures);
+void HWR_LoadTextures(size_t pnumtextures);
 void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color);
 void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength);
 void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor);	// Lat: separate flags from color since color needs to be an uint to work right.
diff --git a/src/p_setup.c b/src/p_setup.c
index 673a9024e..d38a78bc8 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3019,8 +3019,17 @@ boolean P_SetupLevel(boolean skipprecip)
 		P_SpawnPrecipitation();
 
 #ifdef HWRENDER // not win32 only 19990829 by Kin
-	if (rendermode != render_soft && rendermode != render_none)
+	if (rendermode == render_opengl)
 	{
+		// Lactozilla (December 8, 2019)
+		// Level setup used to free EVERY mipmap from memory.
+		// Even mipmaps that aren't related to level textures.
+		// Presumably, the hardware render code used to store textures as level data.
+		// Meaning, they had memory allocated and marked with the PU_LEVEL tag.
+		// Now, only mipmaps that AREN'T level textures are freed between levels.
+		// Level textures are only reloaded after R_LoadTextures, which is
+		// when the texture list is loaded.
+		HWR_FreeMipmapCache();
 #ifdef ALAM_LIGHTING
 		// BP: reset light between levels (we draw preview frame lights on current frame)
 		HWR_ResetLights();
@@ -3203,14 +3212,6 @@ boolean P_SetupLevel(boolean skipprecip)
 	// Fab : 19-07-98 : start cd music for this level (note: can be remapped)
 	I_PlayCD((UINT8)(gamemap), false);
 
-	// preload graphics
-#ifdef HWRENDER // not win32 only 19990829 by Kin
-	if (rendermode != render_soft && rendermode != render_none)
-	{
-		HWR_PrepLevelCache(numtextures);
-	}
-#endif
-
 	P_MapEnd();
 
 	// Remove the loading shit from the screen
@@ -3540,6 +3541,7 @@ boolean P_AddWadFile(const char *wadfilename)
 
 #ifdef HWRENDER
 	HWR_ReloadModels();
+	HWR_FreeMipmapCache();
 #endif
 
 	// reload status bar (warning should have valid player!)
diff --git a/src/r_data.c b/src/r_data.c
index 5611ee6f8..c3f3bf8ff 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -32,6 +32,10 @@
 #include <malloc.h> // alloca(sizeof)
 #endif
 
+#ifdef HWRENDER
+#include "hardware/hw_main.h" // HWR_LoadTextures
+#endif
+
 #if defined(_MSC_VER)
 #pragma pack(1)
 #endif
@@ -872,6 +876,11 @@ void R_LoadTextures(void)
 			i++;
 		}
 	}
+
+#ifdef HWRENDER
+	if (rendermode == render_opengl)
+		HWR_LoadTextures(numtextures);
+#endif
 }
 
 static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)

From d8a804febcf730104917d03d9836378571a1863a Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 04:15:25 -0300
Subject: [PATCH 10/52] LMFAOOOOOOOOOOOOOOOOOOOOOOOO

---
 src/hardware/hw_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 5baf89e6c..583a877fc 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -3431,7 +3431,7 @@ static void HWR_AddPolyObjectPlanes(void)
 			{
 				HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic]);
 				HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
-				                          (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->floorpic],
+				                          (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->ceilingpic],
 				                          polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap));
 			}
 		}

From 4c808cb7e2c12f5f9c003c98746ffdb7a4331508 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 04:32:25 -0300
Subject: [PATCH 11/52] Actually don't even call HWR_FreeMipmapCache between
 levels because I feel like it's futile outside of PWAD loading

---
 src/p_setup.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/p_setup.c b/src/p_setup.c
index d38a78bc8..186947060 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3026,10 +3026,8 @@ boolean P_SetupLevel(boolean skipprecip)
 		// Even mipmaps that aren't related to level textures.
 		// Presumably, the hardware render code used to store textures as level data.
 		// Meaning, they had memory allocated and marked with the PU_LEVEL tag.
-		// Now, only mipmaps that AREN'T level textures are freed between levels.
 		// Level textures are only reloaded after R_LoadTextures, which is
 		// when the texture list is loaded.
-		HWR_FreeMipmapCache();
 #ifdef ALAM_LIGHTING
 		// BP: reset light between levels (we draw preview frame lights on current frame)
 		HWR_ResetLights();

From d74f2a003b5cb4cd9520ff596fc5b6404393f22b Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 04:40:29 -0300
Subject: [PATCH 12/52] HWR_FreeMipmapCache already calls HWR_FreeMipmapCache
 indirectly (done by calling HWR_LoadTextures, which in turn calls
 HWR_FreeTextureCache)

---
 src/p_setup.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/p_setup.c b/src/p_setup.c
index 186947060..bb6c34c0a 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3539,7 +3539,6 @@ boolean P_AddWadFile(const char *wadfilename)
 
 #ifdef HWRENDER
 	HWR_ReloadModels();
-	HWR_FreeMipmapCache();
 #endif
 
 	// reload status bar (warning should have valid player!)

From 25464c867a57d479b292098ff0a1c377706c724c Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 21:10:14 -0300
Subject: [PATCH 13/52] Translate the French

---
 src/hardware/r_opengl/r_opengl.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index fbb5d9efe..9a80c0e36 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -723,8 +723,8 @@ void Flush(void)
 
 	while (gr_cachehead)
 	{
-		// ceci n'est pas du tout necessaire vu que tu les a charger normalement et
-		// donc il sont dans ta liste !
+		// this is not necessary at all, because you have loaded them normally,
+		// and so they already are in your list!
 #if 0
 		//Hurdler: 25/04/2000: now support colormap in hardware mode
 		FTextureInfo    *tmp = gr_cachehead->nextskin;
@@ -1296,11 +1296,11 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
 
 		pTexInfo->nextmipmap = NULL;
 		if (gr_cachetail)
-		{ // insertion en fin de liste
+		{ // insertion at the tail
 			gr_cachetail->nextmipmap = pTexInfo;
 			gr_cachetail = pTexInfo;
 		}
-		else // initialisation de la liste
+		else // initialization of the linked list
 			gr_cachetail = gr_cachehead =  pTexInfo;
 	}
 }

From c6769e72205a5e5d1ff579c8a1ec422d3d0dfee2 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 22:12:56 -0300
Subject: [PATCH 14/52] Die

---
 src/hardware/hw_cache.c         |  9 +-------
 src/hardware/hw_drv.h           |  4 ++--
 src/hardware/hw_main.h          |  3 ---
 src/hardware/r_opengl/ogl_win.c |  8 +++----
 src/m_menu.c                    | 37 +--------------------------------
 src/r_main.c                    |  3 ---
 src/sdl/ogl_sdl.c               | 12 +++++------
 src/sdl/ogl_sdl.h               |  2 +-
 src/v_video.c                   | 19 +----------------
 src/win32/win_dll.c             |  4 ++--
 10 files changed, 17 insertions(+), 84 deletions(-)

diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index aef97e817..44fc7600e 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -863,14 +863,7 @@ void HWR_LoadTextures(size_t pnumtextures)
 
 void HWR_SetPalette(RGBA_t *palette)
 {
-	//Hudler: 16/10/99: added for OpenGL gamma correction
-	RGBA_t gamma_correction = {0x7F7F7F7F};
-
-	//Hurdler 16/10/99: added for OpenGL gamma correction
-	gamma_correction.s.red   = (UINT8)cv_grgammared.value;
-	gamma_correction.s.green = (UINT8)cv_grgammagreen.value;
-	gamma_correction.s.blue  = (UINT8)cv_grgammablue.value;
-	HWD.pfnSetPalette(palette, &gamma_correction);
+	HWD.pfnSetPalette(palette);
 
 	// hardware driver will flush there own cache if cache is non paletized
 	// now flush data texture cache so 32 bit texture are recomputed
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index aed1611f1..3e9f149ca 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -40,9 +40,9 @@ EXPORT void HWRAPI(Shutdown) (void);
 EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes);
 #endif
 #if defined (PURESDL) || defined (macintosh)
-EXPORT void HWRAPI(SetPalette) (INT32 *, RGBA_t *gamma);
+EXPORT void HWRAPI(SetPalette) (INT32 *);
 #else
-EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal, RGBA_t *pgamma);
+EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal);
 #endif
 EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
 EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 3ff7e98c9..96ff62cff 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -89,9 +89,6 @@ extern consvar_t cv_grfog;
 extern consvar_t cv_grfogcolor;
 extern consvar_t cv_grfogdensity;
 extern consvar_t cv_grsoftwarefog;
-extern consvar_t cv_grgammared;
-extern consvar_t cv_grgammagreen;
-extern consvar_t cv_grgammablue;
 extern consvar_t cv_grfiltermode;
 extern consvar_t cv_granisotropicmode;
 extern consvar_t cv_grcorrecttricks;
diff --git a/src/hardware/r_opengl/ogl_win.c b/src/hardware/r_opengl/ogl_win.c
index 562afe998..90376f276 100644
--- a/src/hardware/r_opengl/ogl_win.c
+++ b/src/hardware/r_opengl/ogl_win.c
@@ -564,15 +564,15 @@ EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl)
 //                  : in OpenGL, we store values for conversion of paletted graphics when
 //                  : they are downloaded to the 3D card.
 // -----------------+
-EXPORT void HWRAPI(SetPalette) (RGBA_t *pal, RGBA_t *gamma)
+EXPORT void HWRAPI(SetPalette) (RGBA_t *pal)
 {
 	INT32 i;
 
 	for (i = 0; i < 256; i++)
 	{
-		myPaletteData[i].s.red   = (UINT8)MIN((pal[i].s.red*gamma->s.red)/127,     255);
-		myPaletteData[i].s.green = (UINT8)MIN((pal[i].s.green*gamma->s.green)/127, 255);
-		myPaletteData[i].s.blue  = (UINT8)MIN((pal[i].s.blue*gamma->s.blue)/127,   255);
+		myPaletteData[i].s.red   = pal[i].s.red;
+		myPaletteData[i].s.green = pal[i].s.green;
+		myPaletteData[i].s.blue  = pal[i].s.blue;
 		myPaletteData[i].s.alpha = pal[i].s.alpha;
 	}
 
diff --git a/src/m_menu.c b/src/m_menu.c
index e367041e0..8ed85f501 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -309,7 +309,7 @@ static void M_ChangeControl(INT32 choice);
 // Video & Sound
 menu_t OP_VideoOptionsDef, OP_VideoModeDef, OP_ColorOptionsDef;
 #ifdef HWRENDER
-menu_t OP_OpenGLOptionsDef, OP_OpenGLFogDef, OP_OpenGLColorDef;
+menu_t OP_OpenGLOptionsDef, OP_OpenGLFogDef;
 #endif
 menu_t OP_SoundOptionsDef;
 menu_t OP_SoundAdvancedDef;
@@ -355,7 +355,6 @@ static void M_DrawScreenshotMenu(void);
 static void M_DrawMonitorToggles(void);
 #ifdef HWRENDER
 static void M_OGL_DrawFogMenu(void);
-static void M_OGL_DrawColorMenu(void);
 #endif
 #ifndef NONET
 static void M_DrawScreenshotMenu(void);
@@ -1314,7 +1313,6 @@ static menuitem_t OP_OpenGLOptionsMenu[] =
 	{IT_SUBMENU|IT_STRING,      NULL, "Lighting...",     &OP_OpenGLLightingDef,     100},
 #endif
 	{IT_SUBMENU|IT_STRING,      NULL, "Fog...",          &OP_OpenGLFogDef,          110},
-	{IT_SUBMENU|IT_STRING,      NULL, "Gamma...",        &OP_OpenGLColorDef,        120},
 };
 
 #ifdef ALAM_LIGHTING
@@ -1334,13 +1332,6 @@ static menuitem_t OP_OpenGLFogMenu[] =
 	{IT_STRING|IT_CVAR,       NULL, "Fog density", &cv_grfogdensity, 30},
 	{IT_STRING|IT_CVAR,       NULL, "Software Fog",&cv_grsoftwarefog,40},
 };
-
-static menuitem_t OP_OpenGLColorMenu[] =
-{
-	{IT_STRING|IT_CVAR|IT_CV_SLIDER, NULL, "red",   &cv_grgammared,   10},
-	{IT_STRING|IT_CVAR|IT_CV_SLIDER, NULL, "green", &cv_grgammagreen, 20},
-	{IT_STRING|IT_CVAR|IT_CV_SLIDER, NULL, "blue",  &cv_grgammablue,  30},
-};
 #endif
 
 static menuitem_t OP_SoundOptionsMenu[] =
@@ -2027,18 +2018,6 @@ menu_t OP_OpenGLFogDef =
 	0,
 	NULL
 };
-menu_t OP_OpenGLColorDef =
-{
-	MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12) + (MN_OP_OPENGL_COLOR << 18),
-	"M_VIDEO",
-	sizeof (OP_OpenGLColorMenu)/sizeof (menuitem_t),
-	&OP_OpenGLOptionsDef,
-	OP_OpenGLColorMenu,
-	M_OGL_DrawColorMenu,
-	60, 40,
-	0,
-	NULL
-};
 #endif
 menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE(
 	MN_OP_MAIN + (MN_OP_DATA << 6),
@@ -11931,20 +11910,6 @@ static void M_OGL_DrawFogMenu(void)
 			my + currentMenu->menuitems[FOG_COLOR_ITEM].alphaKey, '_' | 0x80,false);
 }
 
-// =====================
-// M_OGL_DrawColorMenu()
-// =====================
-static void M_OGL_DrawColorMenu(void)
-{
-	INT32 mx, my;
-
-	mx = currentMenu->x;
-	my = currentMenu->y;
-	M_DrawGenericMenu(); // use generic drawer for cursor, items and title
-	V_DrawString(mx, my + currentMenu->menuitems[0].alphaKey - 10,
-		V_YELLOWMAP, "Gamma correction");
-}
-
 //===================
 // M_HandleFogColor()
 //===================
diff --git a/src/r_main.c b/src/r_main.c
index dd1243868..541360025 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1211,9 +1211,6 @@ void R_RegisterEngineStuff(void)
 
 #ifdef HWRENDER
 	// GL-specific Commands
-	CV_RegisterVar(&cv_grgammablue);
-	CV_RegisterVar(&cv_grgammagreen);
-	CV_RegisterVar(&cv_grgammared);
 	CV_RegisterVar(&cv_grfovchange);
 	CV_RegisterVar(&cv_grfog);
 	CV_RegisterVar(&cv_grfogcolor);
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index dd58aa99c..66980f1ad 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -222,17 +222,15 @@ void OglSdlFinishUpdate(boolean waitvbl)
 	HWR_DrawScreenFinalTexture(realwidth, realheight);
 }
 
-EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette, RGBA_t *pgamma)
+EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette)
 {
-	INT32 i = -1;
-	UINT32 redgamma = pgamma->s.red, greengamma = pgamma->s.green,
-		bluegamma = pgamma->s.blue;
+	INT32 i;
 
 	for (i = 0; i < 256; i++)
 	{
-		myPaletteData[i].s.red   = (UINT8)MIN((palette[i].s.red   * redgamma)  /127, 255);
-		myPaletteData[i].s.green = (UINT8)MIN((palette[i].s.green * greengamma)/127, 255);
-		myPaletteData[i].s.blue  = (UINT8)MIN((palette[i].s.blue  * bluegamma) /127, 255);
+		myPaletteData[i].s.red   = palette[i].s.red;
+		myPaletteData[i].s.green = palette[i].s.green;
+		myPaletteData[i].s.blue  = palette[i].s.blue;
 		myPaletteData[i].s.alpha = palette[i].s.alpha;
 	}
 	Flush();
diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h
index 293c45116..88d7d0b6c 100644
--- a/src/sdl/ogl_sdl.h
+++ b/src/sdl/ogl_sdl.h
@@ -31,5 +31,5 @@ extern Uint16      realwidth;
 extern Uint16      realheight;
 
 #ifdef _CREATE_DLL_
-EXPORT void HWRAPI( OglSdlSetPalette ) (RGBA_t *palette, RGBA_t *pgamma);
+EXPORT void HWRAPI( OglSdlSetPalette ) (RGBA_t *palette);
 #endif
diff --git a/src/v_video.c b/src/v_video.c
index 0e741df9f..25cbccee2 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -85,11 +85,9 @@ static void CV_constextsize_OnChange(void);
 consvar_t cv_constextsize = {"con_textsize", "Medium", CV_SAVE|CV_CALL, constextsize_cons_t, CV_constextsize_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
 #ifdef HWRENDER
-static void CV_Gammaxxx_ONChange(void);
 // Saved hardware mode variables
 // - You can change them in software,
 // but they won't do anything.
-static CV_PossibleValue_t grgamma_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}};
 static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
 
@@ -97,12 +95,7 @@ consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, N
 consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grsoftwarefog = {"gr_softwarefog", "Off", CV_SAVE, grsoftwarefog_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grgammared = {"gr_gammared", "127", CV_SAVE|CV_CALL, grgamma_cons_t,
-                           CV_Gammaxxx_ONChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grgammagreen = {"gr_gammagreen", "127", CV_SAVE|CV_CALL, grgamma_cons_t,
-                             CV_Gammaxxx_ONChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grgammablue = {"gr_gammablue", "127", CV_SAVE|CV_CALL, grgamma_cons_t,
-                            CV_Gammaxxx_ONChange, 0, NULL, NULL, 0, 0, NULL};
+
 #ifdef ALAM_LIGHTING
 consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grstaticlighting  = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -473,16 +466,6 @@ static void CV_palette_OnChange(void)
 	V_SetPalette(0);
 }
 
-// change the palette directly to see the change
-#ifdef HWRENDER
-static void CV_Gammaxxx_ONChange(void)
-{
-	if (rendermode != render_soft && rendermode != render_none)
-		V_SetPalette(0);
-}
-#endif
-
-
 #if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
 void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
 	size_t destrowbytes);
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index 5378bb52f..986eb32dc 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -98,7 +98,7 @@ static loadfunc_t hwdFuncTable[] = {
 	{"Init@4",              &hwdriver.pfnInit},
 	{"Shutdown@0",          &hwdriver.pfnShutdown},
 	{"GetModeList@8",       &hwdriver.pfnGetModeList},
-	{"SetPalette@8",        &hwdriver.pfnSetPalette},
+	{"SetPalette@4",        &hwdriver.pfnSetPalette},
 	{"FinishUpdate@4",      &hwdriver.pfnFinishUpdate},
 	{"Draw2DLine@12",       &hwdriver.pfnDraw2DLine},
 	{"DrawPolygon@16",      &hwdriver.pfnDrawPolygon},
@@ -110,7 +110,7 @@ static loadfunc_t hwdFuncTable[] = {
 	{"GClipRect@20",        &hwdriver.pfnGClipRect},
 	{"ClearMipMapCache@0",  &hwdriver.pfnClearMipMapCache},
 	{"SetSpecialState@8",   &hwdriver.pfnSetSpecialState},
-	{"DrawModel@16",          &hwdriver.pfnDrawModel},
+	{"DrawModel@16",        &hwdriver.pfnDrawModel},
 	{"SetTransform@4",      &hwdriver.pfnSetTransform},
 	{"GetTextureUsed@0",    &hwdriver.pfnGetTextureUsed},
 	{"GetRenderVersion@0",  &hwdriver.pfnGetRenderVersion},

From 5c02bc59dbd6670a6100035e8dbd10f4e1ac7198 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 22:28:13 -0300
Subject: [PATCH 15/52] Speed up level loading Don't flush every texture just
 because the palette MAY have changed

---
 src/hardware/r_opengl/ogl_win.c | 17 ++++++-----------
 src/sdl/ogl_sdl.c               | 13 +++++--------
 2 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/src/hardware/r_opengl/ogl_win.c b/src/hardware/r_opengl/ogl_win.c
index 90376f276..e4a71734b 100644
--- a/src/hardware/r_opengl/ogl_win.c
+++ b/src/hardware/r_opengl/ogl_win.c
@@ -566,18 +566,13 @@ EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl)
 // -----------------+
 EXPORT void HWRAPI(SetPalette) (RGBA_t *pal)
 {
-	INT32 i;
-
-	for (i = 0; i < 256; i++)
-	{
-		myPaletteData[i].s.red   = pal[i].s.red;
-		myPaletteData[i].s.green = pal[i].s.green;
-		myPaletteData[i].s.blue  = pal[i].s.blue;
-		myPaletteData[i].s.alpha = pal[i].s.alpha;
-	}
-
+	size_t palsize = (sizeof(RGBA_t) * 256);
 	// on a palette change, you have to reload all of the textures
-	Flush();
+	if (memcmp(&myPaletteData, pal, palsize))
+	{
+		memcpy(&myPaletteData, pal, palsize);
+		Flush();
+	}
 }
 
 #endif
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index 66980f1ad..6c0dd35a5 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -224,16 +224,13 @@ void OglSdlFinishUpdate(boolean waitvbl)
 
 EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette)
 {
-	INT32 i;
-
-	for (i = 0; i < 256; i++)
+	size_t palsize = (sizeof(RGBA_t) * 256);
+	// on a palette change, you have to reload all of the textures
+	if (memcmp(&myPaletteData, palette, palsize))
 	{
-		myPaletteData[i].s.red   = palette[i].s.red;
-		myPaletteData[i].s.green = palette[i].s.green;
-		myPaletteData[i].s.blue  = palette[i].s.blue;
-		myPaletteData[i].s.alpha = palette[i].s.alpha;
+		memcpy(&myPaletteData, palette, palsize);
+		Flush();
 	}
-	Flush();
 }
 
 #endif //HWRENDER

From 4d83db5bb2e4e61f643a83b265fca8dd4e3c1027 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sun, 8 Dec 2019 22:31:59 -0300
Subject: [PATCH 16/52] Die, Apple!

---
 src/hardware/hw_drv.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index 3e9f149ca..3314fb015 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -39,11 +39,7 @@ EXPORT void HWRAPI(Shutdown) (void);
 #ifdef _WINDOWS
 EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes);
 #endif
-#if defined (PURESDL) || defined (macintosh)
-EXPORT void HWRAPI(SetPalette) (INT32 *);
-#else
 EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal);
-#endif
 EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
 EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
 EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags);

From 9ab00049dcaefee2aa872d26602e13bf6a08ab44 Mon Sep 17 00:00:00 2001
From: Steel Titanium <steeltitanium1@gmail.com>
Date: Tue, 10 Dec 2019 12:53:15 -0500
Subject: [PATCH 17/52] appveyor: Forgot to change version to 2.2.0

---
 appveyor.yml | 290 +++++++++++++++++++++++++--------------------------
 1 file changed, 145 insertions(+), 145 deletions(-)

diff --git a/appveyor.yml b/appveyor.yml
index d58976fd5..90ee0048a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,145 +1,145 @@
-version: 2.1.25.{branch}-{build}
-os: MinGW
-
-environment:
- CC: ccache
- CCACHE_CC: i686-w64-mingw32-gcc
- CCACHE_CC_64: x86_64-w64-mingw32-gcc
- WINDRES: windres
- # c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead
- MINGW_SDK: c:\msys64\mingw32
- # c:\msys64 x86_64 has gcc 8.2.0, so use c:\mingw-w64 7.3.0 instead
- MINGW_SDK_64: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64
- CFLAGS: -Wall -W -Werror -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3 -Wno-tautological-compare -Wno-error=suggest-attribute=noreturn
- NASM_ZIP: nasm-2.12.01
- NASM_URL: http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip
- UPX_ZIP: upx391w
- UPX_URL: http://upx.sourceforge.net/download/upx391w.zip
- CCACHE_EXE: ccache.exe
- CCACHE_URL: http://alam.srb2.org/ccache.exe
- CCACHE_COMPRESS: true
- CCACHE_DIR: C:\Users\appveyor\.ccache
- # Disable UPX by default. The user can override this in their Appveyor project settings
- NOUPX: 1
- ##############################
- # DEPLOYER VARIABLES
- # DPL_ENABLED=1 builds installers for branch names starting with `deployer`.
- # DPL_TAG_ENABLED=1 will also build installers for release tags. DPL_ENABLED=1 must also be set.
- # Set these in the Appveyor project settings
- ##############################
- DPL_ENABLED: 0
- DPL_TAG_ENABLED: 0
- DPL_INSTALLER_NAME: SRB2-v2123
- # Asset handling is barebones vs. Travis Deployer. We operate on 7z only.
- # Include the README files and the OpenGL batch in the main and patch archives.
- # The x86/x64 archives contain the DLL binaries.
- ASSET_ARCHIVE_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-assets.7z
- ASSET_ARCHIVE_PATCH_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-patch-assets.7z
- ASSET_ARCHIVE_X86_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-x86-assets.7z
- ASSET_ARCHIVE_X64_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-x64-assets.7z
- ASSET_ARCHIVE_OPTIONAL_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-optional-assets.7z
- # This is overridden to 1 for release tag builds
- ASSET_FILES_OPTIONAL_GET: 0
- # For patches, also include the X86/X64 DLLs.
- PACKAGE_PATCH_DLL_GET: 0
- # Delete all asset downloads so they can be redownloaded
- ASSET_CLEAN: 0
-
-cache:
-- nasm-2.12.01.zip
-- upx391w.zip
-- ccache.exe
-- C:\Users\appveyor\.ccache
-- C:\Users\appveyor\srb2_cache
-
-install:
-- if [%CONFIGURATION%] == [SDL64] ( set "X86_64=1" )
-- if [%CONFIGURATION%] == [SDL64] ( set "CONFIGURATION=SDL" )
-- if [%CONFIGURATION%] == [DD64] ( set "X86_64=1" )
-- if [%CONFIGURATION%] == [DD64] ( set "CONFIGURATION=DD" )
-- if [%X86_64%] == [1] ( set "MINGW_SDK=%MINGW_SDK_64%" )
-- if [%X86_64%] == [1] ( set "CCACHE_CC=%CCACHE_CC_64%" )
-
-- if not exist "%NASM_ZIP%.zip" appveyor DownloadFile "%NASM_URL%" -FileName "%NASM_ZIP%.zip"
-- 7z x -y "%NASM_ZIP%.zip" -o%TMP% >null
-- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%NASM_ZIP%" "%MINGW_SDK%\bin" nasm.exe || exit 0
-
-- if not exist "%UPX_ZIP%.zip" appveyor DownloadFile "%UPX_URL%" -FileName "%UPX_ZIP%.zip"
-- 7z x -y "%UPX_ZIP%.zip" -o%TMP% >null
-- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%UPX_ZIP%" "%MINGW_SDK%\bin" upx.exe || exit 0
-
-- if not exist "%CCACHE_EXE%" appveyor DownloadFile "%CCACHE_URL%" -FileName "%CCACHE_EXE%"
-- ccache -M 99M
-- xcopy /Y /V /I ccache.exe "%MINGW_SDK%\bin"
-
-configuration:
-- SDL
-- SDL64
-- DD
-- DD64
-
-matrix:
-  allow_failures:
-    - configuration: DD
-    - configuration: DD64
-
-before_build:
-- set "Path=%MINGW_SDK%\bin;%Path%"
-- if [%X86_64%] == [1] ( x86_64-w64-mingw32-gcc --version ) else ( i686-w64-mingw32-gcc --version )
-- mingw32-make --version
-- if not [%X86_64%] == [1] ( nasm -v )
-- if not [%NOUPX%] == [1] ( upx -V )
-- ccache -V
-- ccache -s
-- if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" )
-- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 GCC73=1 NOOBJDUMP=1 %NOUPX%"
-- if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" )
-- set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1"
-
-build_script:
-- cmd: mingw32-make.exe %SRB2_MFLAGS% clean
-- cmd: mingw32-make.exe %SRB2_MFLAGS% ERRORMODE=1 -k
-
-after_build:
-- if [%X86_64%] == [1] (
-    set "BUILD_PATH=bin\Mingw64\Release"
-  ) else (
-    set "BUILD_PATH=bin\Mingw\Release"
-  )
-- if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" )
-- ccache -s
-- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
-- cmd: set /P GITSHORT=<%TMP%/gitshort.txt
-- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
-- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
-- cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore
-- appveyor PushArtifact %BUILD_ARCHIVE%
-- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
-- appveyor PushArtifact %BUILDSARCHIVE%
-##############################
-# DEPLOYER SCRIPT
-##############################
-- if [%DPL_ENABLED%] == [1] ( call "deployer\appveyor\deployer.bat" )
-
-test: off
-
-#deploy:
-#  - provider: FTP
-#    protocol: ftps
-#    host:
-#      secure: NsLJEPIBvmwCOj8Tg8RoRQ==
-#    username:
-#      secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
-#    password:
-#      secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
-#    folder: appveyor
-#    application:
-#    active_mode: false
-#    on:
-#      branch: master
-#      appveyor_repo_tag: true
-
-
-on_finish:
-#- cmd: echo xfreerdp /u:appveyor /cert-ignore +clipboard /v:<ip>:<port>
-#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+version: 2.2.0.{branch}-{build}
+os: MinGW
+
+environment:
+ CC: ccache
+ CCACHE_CC: i686-w64-mingw32-gcc
+ CCACHE_CC_64: x86_64-w64-mingw32-gcc
+ WINDRES: windres
+ # c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead
+ MINGW_SDK: c:\msys64\mingw32
+ # c:\msys64 x86_64 has gcc 8.2.0, so use c:\mingw-w64 7.3.0 instead
+ MINGW_SDK_64: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64
+ CFLAGS: -Wall -W -Werror -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3 -Wno-tautological-compare -Wno-error=suggest-attribute=noreturn
+ NASM_ZIP: nasm-2.12.01
+ NASM_URL: http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip
+ UPX_ZIP: upx391w
+ UPX_URL: http://upx.sourceforge.net/download/upx391w.zip
+ CCACHE_EXE: ccache.exe
+ CCACHE_URL: http://alam.srb2.org/ccache.exe
+ CCACHE_COMPRESS: true
+ CCACHE_DIR: C:\Users\appveyor\.ccache
+ # Disable UPX by default. The user can override this in their Appveyor project settings
+ NOUPX: 1
+ ##############################
+ # DEPLOYER VARIABLES
+ # DPL_ENABLED=1 builds installers for branch names starting with `deployer`.
+ # DPL_TAG_ENABLED=1 will also build installers for release tags. DPL_ENABLED=1 must also be set.
+ # Set these in the Appveyor project settings
+ ##############################
+ DPL_ENABLED: 0
+ DPL_TAG_ENABLED: 0
+ DPL_INSTALLER_NAME: SRB2-v2123
+ # Asset handling is barebones vs. Travis Deployer. We operate on 7z only.
+ # Include the README files and the OpenGL batch in the main and patch archives.
+ # The x86/x64 archives contain the DLL binaries.
+ ASSET_ARCHIVE_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-assets.7z
+ ASSET_ARCHIVE_PATCH_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-patch-assets.7z
+ ASSET_ARCHIVE_X86_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-x86-assets.7z
+ ASSET_ARCHIVE_X64_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-x64-assets.7z
+ ASSET_ARCHIVE_OPTIONAL_PATH: https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-optional-assets.7z
+ # This is overridden to 1 for release tag builds
+ ASSET_FILES_OPTIONAL_GET: 0
+ # For patches, also include the X86/X64 DLLs.
+ PACKAGE_PATCH_DLL_GET: 0
+ # Delete all asset downloads so they can be redownloaded
+ ASSET_CLEAN: 0
+
+cache:
+- nasm-2.12.01.zip
+- upx391w.zip
+- ccache.exe
+- C:\Users\appveyor\.ccache
+- C:\Users\appveyor\srb2_cache
+
+install:
+- if [%CONFIGURATION%] == [SDL64] ( set "X86_64=1" )
+- if [%CONFIGURATION%] == [SDL64] ( set "CONFIGURATION=SDL" )
+- if [%CONFIGURATION%] == [DD64] ( set "X86_64=1" )
+- if [%CONFIGURATION%] == [DD64] ( set "CONFIGURATION=DD" )
+- if [%X86_64%] == [1] ( set "MINGW_SDK=%MINGW_SDK_64%" )
+- if [%X86_64%] == [1] ( set "CCACHE_CC=%CCACHE_CC_64%" )
+
+- if not exist "%NASM_ZIP%.zip" appveyor DownloadFile "%NASM_URL%" -FileName "%NASM_ZIP%.zip"
+- 7z x -y "%NASM_ZIP%.zip" -o%TMP% >null
+- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%NASM_ZIP%" "%MINGW_SDK%\bin" nasm.exe || exit 0
+
+- if not exist "%UPX_ZIP%.zip" appveyor DownloadFile "%UPX_URL%" -FileName "%UPX_ZIP%.zip"
+- 7z x -y "%UPX_ZIP%.zip" -o%TMP% >null
+- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%UPX_ZIP%" "%MINGW_SDK%\bin" upx.exe || exit 0
+
+- if not exist "%CCACHE_EXE%" appveyor DownloadFile "%CCACHE_URL%" -FileName "%CCACHE_EXE%"
+- ccache -M 99M
+- xcopy /Y /V /I ccache.exe "%MINGW_SDK%\bin"
+
+configuration:
+- SDL
+- SDL64
+- DD
+- DD64
+
+matrix:
+  allow_failures:
+    - configuration: DD
+    - configuration: DD64
+
+before_build:
+- set "Path=%MINGW_SDK%\bin;%Path%"
+- if [%X86_64%] == [1] ( x86_64-w64-mingw32-gcc --version ) else ( i686-w64-mingw32-gcc --version )
+- mingw32-make --version
+- if not [%X86_64%] == [1] ( nasm -v )
+- if not [%NOUPX%] == [1] ( upx -V )
+- ccache -V
+- ccache -s
+- if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" )
+- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 GCC73=1 NOOBJDUMP=1 %NOUPX%"
+- if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" )
+- set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1"
+
+build_script:
+- cmd: mingw32-make.exe %SRB2_MFLAGS% clean
+- cmd: mingw32-make.exe %SRB2_MFLAGS% ERRORMODE=1 -k
+
+after_build:
+- if [%X86_64%] == [1] (
+    set "BUILD_PATH=bin\Mingw64\Release"
+  ) else (
+    set "BUILD_PATH=bin\Mingw\Release"
+  )
+- if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" )
+- ccache -s
+- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
+- cmd: set /P GITSHORT=<%TMP%/gitshort.txt
+- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
+- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
+- cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore
+- appveyor PushArtifact %BUILD_ARCHIVE%
+- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
+- appveyor PushArtifact %BUILDSARCHIVE%
+##############################
+# DEPLOYER SCRIPT
+##############################
+- if [%DPL_ENABLED%] == [1] ( call "deployer\appveyor\deployer.bat" )
+
+test: off
+
+#deploy:
+#  - provider: FTP
+#    protocol: ftps
+#    host:
+#      secure: NsLJEPIBvmwCOj8Tg8RoRQ==
+#    username:
+#      secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
+#    password:
+#      secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
+#    folder: appveyor
+#    application:
+#    active_mode: false
+#    on:
+#      branch: master
+#      appveyor_repo_tag: true
+
+
+on_finish:
+#- cmd: echo xfreerdp /u:appveyor /cert-ignore +clipboard /v:<ip>:<port>
+#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

From f51253a0a8ade242e4fa085ab76230d5dae2705a Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Tue, 10 Dec 2019 17:01:19 -0300
Subject: [PATCH 18/52] Tilted water

---
 src/r_draw.c  |   3 +-
 src/r_draw.h  |   6 +-
 src/r_draw8.c | 285 +++++++++++++++++++++++++++++++++++++++++++-------
 src/r_plane.c | 233 +++++++++++++++++++++++++----------------
 4 files changed, 397 insertions(+), 130 deletions(-)

diff --git a/src/r_draw.c b/src/r_draw.c
index db64805a4..ec53d79fc 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -107,7 +107,8 @@ UINT8 *ds_transmap; // one of the translucency tables
 
 #ifdef ESLOPE
 pslope_t *ds_slope; // Current slope being used
-floatv3_t ds_su, ds_sv, ds_sz; // Vectors for... stuff?
+floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff?
+floatv3_t *ds_sup, *ds_svp, *ds_szp;
 float focallengthf, zeroheight;
 #endif
 
diff --git a/src/r_draw.h b/src/r_draw.h
index d033f221d..392eb3827 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -68,7 +68,8 @@ typedef struct {
 } floatv3_t;
 
 extern pslope_t *ds_slope; // Current slope being used
-extern floatv3_t ds_su, ds_sv, ds_sz; // Vectors for... stuff?
+extern floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff?
+extern floatv3_t *ds_sup, *ds_svp, *ds_szp;
 extern float focallengthf, zeroheight;
 #endif
 
@@ -163,6 +164,9 @@ void R_DrawSpan_8(void);
 void R_CalcTiltedLighting(fixed_t start, fixed_t end);
 void R_DrawTiltedSpan_8(void);
 void R_DrawTiltedTranslucentSpan_8(void);
+#ifndef NOWATER
+void R_DrawTiltedTranslucentWaterSpan_8(void);
+#endif
 void R_DrawTiltedSplat_8(void);
 #endif
 void R_DrawSplat_8(void);
diff --git a/src/r_draw8.c b/src/r_draw8.c
index 11cdd5dca..609ce6d5c 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -692,22 +692,22 @@ void R_DrawTiltedSpan_8(void)
 	double endz, endu, endv;
 	UINT32 stepu, stepv;
 
-	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
 	// Lighting is simple. It's just linear interpolation from start to end
 	{
 		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
 		float lightstart, lightend;
 
-		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightend = (iz + ds_szp->x*width) * planelightfloat;
 		lightstart = iz * planelightfloat;
 
 		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
 		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
 	}
 
-	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
-	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
+	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
 
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 	source = ds_source;
@@ -743,9 +743,9 @@ void R_DrawTiltedSpan_8(void)
 		else
 			*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
 		dest++;
-		iz += ds_sz.x;
-		uz += ds_su.x;
-		vz += ds_sv.x;
+		iz += ds_szp->x;
+		uz += ds_sup->x;
+		vz += ds_svp->x;
 	} while (--width >= 0);
 #else
 #define SPANSIZE 16
@@ -755,9 +755,9 @@ void R_DrawTiltedSpan_8(void)
 	startu = uz*startz;
 	startv = vz*startz;
 
-	izstep = ds_sz.x * SPANSIZE;
-	uzstep = ds_su.x * SPANSIZE;
-	vzstep = ds_sv.x * SPANSIZE;
+	izstep = ds_szp->x * SPANSIZE;
+	uzstep = ds_sup->x * SPANSIZE;
+	vzstep = ds_svp->x * SPANSIZE;
 	//x1 = 0;
 	width++;
 
@@ -833,9 +833,9 @@ void R_DrawTiltedSpan_8(void)
 		else
 		{
 			double left = width;
-			iz += ds_sz.x * left;
-			uz += ds_su.x * left;
-			vz += ds_sv.x * left;
+			iz += ds_szp->x * left;
+			uz += ds_sup->x * left;
+			vz += ds_svp->x * left;
 
 			endz = 1.f/iz;
 			endu = uz*endz;
@@ -896,22 +896,22 @@ void R_DrawTiltedTranslucentSpan_8(void)
 	double endz, endu, endv;
 	UINT32 stepu, stepv;
 
-	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
 	// Lighting is simple. It's just linear interpolation from start to end
 	{
 		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
 		float lightstart, lightend;
 
-		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightend = (iz + ds_szp->x*width) * planelightfloat;
 		lightstart = iz * planelightfloat;
 
 		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
 		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
 	}
 
-	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
-	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
+	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
 
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 	source = ds_source;
@@ -946,9 +946,9 @@ void R_DrawTiltedTranslucentSpan_8(void)
 		else
 			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 		dest++;
-		iz += ds_sz.x;
-		uz += ds_su.x;
-		vz += ds_sv.x;
+		iz += ds_szp->x;
+		uz += ds_sup->x;
+		vz += ds_svp->x;
 	} while (--width >= 0);
 #else
 #define SPANSIZE 16
@@ -958,9 +958,9 @@ void R_DrawTiltedTranslucentSpan_8(void)
 	startu = uz*startz;
 	startv = vz*startz;
 
-	izstep = ds_sz.x * SPANSIZE;
-	uzstep = ds_su.x * SPANSIZE;
-	vzstep = ds_sv.x * SPANSIZE;
+	izstep = ds_szp->x * SPANSIZE;
+	uzstep = ds_sup->x * SPANSIZE;
+	vzstep = ds_svp->x * SPANSIZE;
 	//x1 = 0;
 	width++;
 
@@ -1036,9 +1036,9 @@ void R_DrawTiltedTranslucentSpan_8(void)
 		else
 		{
 			double left = width;
-			iz += ds_sz.x * left;
-			uz += ds_su.x * left;
-			vz += ds_sv.x * left;
+			iz += ds_szp->x * left;
+			uz += ds_sup->x * left;
+			vz += ds_svp->x * left;
 
 			endz = 1.f/iz;
 			endu = uz*endz;
@@ -1079,6 +1079,213 @@ void R_DrawTiltedTranslucentSpan_8(void)
 #endif
 }
 
+#ifndef NOWATER
+/**	\brief The R_DrawTiltedTranslucentWaterSpan_8 function
+	Like DrawTiltedTranslucentSpan, but for water
+*/
+void R_DrawTiltedTranslucentWaterSpan_8(void)
+{
+	// x1, x2 = ds_x1, ds_x2
+	int width = ds_x2 - ds_x1;
+	double iz, uz, vz;
+	UINT32 u, v;
+	int i;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+	UINT8 *dsrc;
+
+	double startz, startu, startv;
+	double izstep, uzstep, vzstep;
+	double endz, endu, endv;
+	UINT32 stepu, stepv;
+
+	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
+
+	// Lighting is simple. It's just linear interpolation from start to end
+	{
+		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
+		float lightstart, lightend;
+
+		lightend = (iz + ds_szp->x*width) * planelightfloat;
+		lightstart = iz * planelightfloat;
+
+		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
+		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
+	}
+
+	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
+	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
+	source = ds_source;
+	//colormap = ds_colormap;
+
+#if 0	// The "perfect" reference version of this routine. Pretty slow.
+		// Use it only to see how things are supposed to look.
+	i = 0;
+	do
+	{
+		double z = 1.f/iz;
+		u = (INT64)(uz*z) + viewx;
+		v = (INT64)(vz*z) + viewy;
+
+		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+		if (!ds_powersoftwo)
+		{
+			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+			// Carefully align all of my Friends.
+			if (x < 0)
+				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+			if (y < 0)
+				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+			x %= ds_flatwidth;
+			y %= ds_flatheight;
+
+			*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++);
+		}
+		else
+			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dsrc++);
+		dest++;
+		iz += ds_szp->x;
+		uz += ds_sup->x;
+		vz += ds_svp->x;
+	} while (--width >= 0);
+#else
+#define SPANSIZE 16
+#define INVSPAN	0.0625f
+
+	startz = 1.f/iz;
+	startu = uz*startz;
+	startv = vz*startz;
+
+	izstep = ds_szp->x * SPANSIZE;
+	uzstep = ds_sup->x * SPANSIZE;
+	vzstep = ds_svp->x * SPANSIZE;
+	//x1 = 0;
+	width++;
+
+	while (width >= SPANSIZE)
+	{
+		iz += izstep;
+		uz += uzstep;
+		vz += vzstep;
+
+		endz = 1.f/iz;
+		endu = uz*endz;
+		endv = vz*endz;
+		stepu = (INT64)((endu - startu) * INVSPAN);
+		stepv = (INT64)((endv - startv) * INVSPAN);
+		u = (INT64)(startu) + viewx;
+		v = (INT64)(startv) + viewy;
+
+		for (i = SPANSIZE-1; i >= 0; i--)
+		{
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			if (!ds_powersoftwo)
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++);
+			}
+			else
+				*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dsrc++);
+			dest++;
+			u += stepu;
+			v += stepv;
+		}
+		startu = endu;
+		startv = endv;
+		width -= SPANSIZE;
+	}
+	if (width > 0)
+	{
+		if (width == 1)
+		{
+			u = (INT64)(startu);
+			v = (INT64)(startv);
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			if (!ds_powersoftwo)
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++);
+			}
+			else
+				*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dsrc++);
+		}
+		else
+		{
+			double left = width;
+			iz += ds_szp->x * left;
+			uz += ds_sup->x * left;
+			vz += ds_svp->x * left;
+
+			endz = 1.f/iz;
+			endu = uz*endz;
+			endv = vz*endz;
+			left = 1.f/left;
+			stepu = (INT64)((endu - startu) * left);
+			stepv = (INT64)((endv - startv) * left);
+			u = (INT64)(startu) + viewx;
+			v = (INT64)(startv) + viewy;
+
+			for (; width != 0; width--)
+			{
+				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+				if (!ds_powersoftwo)
+				{
+					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+					// Carefully align all of my Friends.
+					if (x < 0)
+						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+					if (y < 0)
+						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+					x %= ds_flatwidth;
+					y %= ds_flatheight;
+
+					*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++);
+				}
+				else
+					*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dsrc++);
+				dest++;
+				u += stepu;
+				v += stepv;
+			}
+		}
+	}
+#endif
+}
+#endif // NOWATER
+
 void R_DrawTiltedSplat_8(void)
 {
 	// x1, x2 = ds_x1, ds_x2
@@ -1098,22 +1305,22 @@ void R_DrawTiltedSplat_8(void)
 	double endz, endu, endv;
 	UINT32 stepu, stepv;
 
-	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
 	// Lighting is simple. It's just linear interpolation from start to end
 	{
 		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
 		float lightstart, lightend;
 
-		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightend = (iz + ds_szp->x*width) * planelightfloat;
 		lightstart = iz * planelightfloat;
 
 		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
 		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
 	}
 
-	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
-	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
+	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
 
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 	source = ds_source;
@@ -1153,9 +1360,9 @@ void R_DrawTiltedSplat_8(void)
 			*dest = colormap[val];
 
 		dest++;
-		iz += ds_sz.x;
-		uz += ds_su.x;
-		vz += ds_sv.x;
+		iz += ds_szp->x;
+		uz += ds_sup->x;
+		vz += ds_svp->x;
 	} while (--width >= 0);
 #else
 #define SPANSIZE 16
@@ -1165,9 +1372,9 @@ void R_DrawTiltedSplat_8(void)
 	startu = uz*startz;
 	startv = vz*startz;
 
-	izstep = ds_sz.x * SPANSIZE;
-	uzstep = ds_su.x * SPANSIZE;
-	vzstep = ds_sv.x * SPANSIZE;
+	izstep = ds_szp->x * SPANSIZE;
+	uzstep = ds_sup->x * SPANSIZE;
+	vzstep = ds_svp->x * SPANSIZE;
 	//x1 = 0;
 	width++;
 
@@ -1247,9 +1454,9 @@ void R_DrawTiltedSplat_8(void)
 		else
 		{
 			double left = width;
-			iz += ds_sz.x * left;
-			uz += ds_su.x * left;
-			vz += ds_sv.x * left;
+			iz += ds_szp->x * left;
+			uz += ds_sup->x * left;
+			vz += ds_svp->x * left;
 
 			endz = 1.f/iz;
 			endu = uz*endz;
diff --git a/src/r_plane.c b/src/r_plane.c
index f96e7950e..97a4ca9f8 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -190,6 +190,15 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
 		ds_xfrac += FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS));
 		ds_yfrac += FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS));
 
+#ifdef ESLOPE
+		if (currentplane->slope)
+		{
+			ds_sup = &ds_su[y];
+			ds_svp = &ds_sv[y];
+			ds_szp = &ds_sz[y];
+		}
+#endif
+
 		if (y+ds_bgofs>=viewheight)
 			ds_bgofs = viewheight-y-1;
 		if (y+ds_bgofs<0)
@@ -833,6 +842,100 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo
 	return flat;
 }
 
+// Lactokaiju
+#ifdef ESLOPE
+static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge)
+{
+	// Potentially override other stuff for now cus we're mean. :< But draw a slope plane!
+	// I copied ZDoom's code and adapted it to SRB2... -Red
+	floatv3_t p, m, n;
+	float ang;
+	float vx, vy, vz;
+	// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
+	// use this as a temp var to store P_GetZAt's return value each time
+	fixed_t temp;
+
+	vx = FIXED_TO_FLOAT(pl->viewx+xoffs);
+	vy = FIXED_TO_FLOAT(pl->viewy-yoffs);
+	vz = FIXED_TO_FLOAT(pl->viewz);
+
+	temp = P_GetZAt(pl->slope, pl->viewx, pl->viewy);
+	zeroheight = FIXED_TO_FLOAT(temp);
+
+	// p is the texture origin in view space
+	// Don't add in the offsets at this stage, because doing so can result in
+	// errors if the flat is rotated.
+	ang = ANG2RAD(ANGLE_270 - pl->viewangle);
+	p.x = vx * cos(ang) - vy * sin(ang);
+	p.z = vx * sin(ang) + vy * cos(ang);
+	temp = P_GetZAt(pl->slope, -xoffs, yoffs);
+	p.y = FIXED_TO_FLOAT(temp) - vz;
+
+	// m is the v direction vector in view space
+	ang = ANG2RAD(ANGLE_180 - (pl->viewangle + pl->plangle));
+	m.x = cos(ang);
+	m.z = sin(ang);
+
+	// n is the u direction vector in view space
+	n.x = sin(ang);
+	n.z = -cos(ang);
+
+	ang = ANG2RAD(pl->plangle);
+	temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(sin(ang)), pl->viewy + FLOAT_TO_FIXED(cos(ang)));
+	m.y = FIXED_TO_FLOAT(temp) - zeroheight;
+	temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang)));
+	n.y = FIXED_TO_FLOAT(temp) - zeroheight;
+
+	if (ds_powersoftwo)
+	{
+		m.x /= fudge;
+		m.y /= fudge;
+		m.z /= fudge;
+
+		n.x *= fudge;
+		n.y *= fudge;
+		n.z *= fudge;
+	}
+
+	// Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using.
+#define CROSS(d, v1, v2) \
+d.x = (v1.y * v2.z) - (v1.z * v2.y);\
+d.y = (v1.z * v2.x) - (v1.x * v2.z);\
+d.z = (v1.x * v2.y) - (v1.y * v2.x)
+	CROSS(ds_su[i], p, m);
+	CROSS(ds_sv[i], p, n);
+	CROSS(ds_sz[i], m, n);
+#undef CROSS
+
+	ds_su[i].z *= focallengthf;
+	ds_sv[i].z *= focallengthf;
+	ds_sz[i].z *= focallengthf;
+
+	// Premultiply the texture vectors with the scale factors
+#define SFMULT 65536.f
+	if (ds_powersoftwo)
+	{
+		ds_su[i].x *= (SFMULT * (1<<nflatshiftup));
+		ds_su[i].y *= (SFMULT * (1<<nflatshiftup));
+		ds_su[i].z *= (SFMULT * (1<<nflatshiftup));
+		ds_sv[i].x *= (SFMULT * (1<<nflatshiftup));
+		ds_sv[i].y *= (SFMULT * (1<<nflatshiftup));
+		ds_sv[i].z *= (SFMULT * (1<<nflatshiftup));
+	}
+	else
+	{
+		// I'm essentially multiplying the vectors by FRACUNIT...
+		ds_su[i].x *= SFMULT;
+		ds_su[i].y *= SFMULT;
+		ds_su[i].z *= SFMULT;
+		ds_sv[i].x *= SFMULT;
+		ds_sv[i].y *= SFMULT;
+		ds_sv[i].z *= SFMULT;
+	}
+#undef SFMULT
+}
+#endif // ESLOPE
+
 void R_DrawSinglePlane(visplane_t *pl)
 {
 	UINT8 *flat;
@@ -945,11 +1048,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 		else light = (pl->lightlevel >> LIGHTSEGSHIFT);
 
 #ifndef NOWATER
-		if (pl->ffloor->flags & FF_RIPPLE
-#ifdef ESLOPE
-				&& !pl->slope
-#endif
-			)
+		if (pl->ffloor->flags & FF_RIPPLE)
 		{
 			INT32 top, bottom;
 
@@ -1045,25 +1144,18 @@ void R_DrawSinglePlane(visplane_t *pl)
 		light = 0;
 
 #ifdef ESLOPE
-	if (pl->slope) {
-		// Potentially override other stuff for now cus we're mean. :< But draw a slope plane!
-		// I copied ZDoom's code and adapted it to SRB2... -Red
-		floatv3_t p, m, n;
-		float ang;
-		float vx, vy, vz;
-		float fudge = 0;
-		// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
-		// use this as a temp var to store P_GetZAt's return value each time
-		fixed_t temp;
-
+	if (pl->slope)
+	{
+		float fudgecanyon = 0;
 		angle_t hack = (pl->plangle & (ANGLE_90-1));
 
 		yoffs *= 1;
 
 		if (ds_powersoftwo)
 		{
+			fixed_t temp;
 			// Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red
-			fudge = ((1<<nflatshiftup)+1.0f)/(1<<nflatshiftup);
+			fudgecanyon = ((1<<nflatshiftup)+1.0f)/(1<<nflatshiftup);
 			if (hack)
 			{
 				/*
@@ -1105,89 +1197,52 @@ void R_DrawSinglePlane(visplane_t *pl)
 				xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
 				yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
 			}
-			xoffs = (fixed_t)(xoffs*fudge);
-			yoffs = (fixed_t)(yoffs/fudge);
+			xoffs = (fixed_t)(xoffs*fudgecanyon);
+			yoffs = (fixed_t)(yoffs/fudgecanyon);
 		}
 
-		vx = FIXED_TO_FLOAT(pl->viewx+xoffs);
-		vy = FIXED_TO_FLOAT(pl->viewy-yoffs);
-		vz = FIXED_TO_FLOAT(pl->viewz);
+		ds_sup = &ds_su[0];
+		ds_svp = &ds_sv[0];
+		ds_szp = &ds_sz[0];
 
-		temp = P_GetZAt(pl->slope, pl->viewx, pl->viewy);
-		zeroheight = FIXED_TO_FLOAT(temp);
-
-		// p is the texture origin in view space
-		// Don't add in the offsets at this stage, because doing so can result in
-		// errors if the flat is rotated.
-		ang = ANG2RAD(ANGLE_270 - pl->viewangle);
-		p.x = vx * cos(ang) - vy * sin(ang);
-		p.z = vx * sin(ang) + vy * cos(ang);
-		temp = P_GetZAt(pl->slope, -xoffs, yoffs);
-		p.y = FIXED_TO_FLOAT(temp) - vz;
-
-		// m is the v direction vector in view space
-		ang = ANG2RAD(ANGLE_180 - (pl->viewangle + pl->plangle));
-		m.x = cos(ang);
-		m.z = sin(ang);
-
-		// n is the u direction vector in view space
-		n.x = sin(ang);
-		n.z = -cos(ang);
-
-		ang = ANG2RAD(pl->plangle);
-		temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(sin(ang)), pl->viewy + FLOAT_TO_FIXED(cos(ang)));
-		m.y = FIXED_TO_FLOAT(temp) - zeroheight;
-		temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang)));
-		n.y = FIXED_TO_FLOAT(temp) - zeroheight;
-
-		if (ds_powersoftwo)
+#ifndef NOWATER
+		if (itswater)
 		{
-			m.x /= fudge;
-			m.y /= fudge;
-			m.z /= fudge;
+			INT32 i;
+			fixed_t rxoffs = xoffs;
+			fixed_t ryoffs = yoffs;
 
-			n.x *= fudge;
-			n.y *= fudge;
-			n.z *= fudge;
-		}
+			R_PlaneBounds(pl);
 
-		// Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using.
-#define CROSS(d, v1, v2) \
-   d.x = (v1.y * v2.z) - (v1.z * v2.y);\
-   d.y = (v1.z * v2.x) - (v1.x * v2.z);\
-   d.z = (v1.x * v2.y) - (v1.y * v2.x)
-		CROSS(ds_su, p, m);
-		CROSS(ds_sv, p, n);
-		CROSS(ds_sz, m, n);
-#undef CROSS
+			for (i = pl->high; i < pl->low; i++)
+			{
+				// Fuck it
+				fixed_t plheight = abs(P_GetZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz);
+				fixed_t distance = FixedMul(plheight, yslope[i]);
+				const INT32 yay = (wtofs + (distance>>9) ) & 8191;
+				// ripples da water texture
+				ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS;
+				angle = (pl->viewangle + pl->plangle)>>ANGLETOFINESHIFT;
 
-		ds_su.z *= focallengthf;
-		ds_sv.z *= focallengthf;
-		ds_sz.z *= focallengthf;
+				angle = (angle + 2048) & 8191;  // 90 degrees
+				xoffs = rxoffs + FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS));
+				yoffs = ryoffs + FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS));
 
-		// Premultiply the texture vectors with the scale factors
-#define SFMULT 65536.f
-		if (ds_powersoftwo)
-		{
-			ds_su.x *= (SFMULT * (1<<nflatshiftup));
-			ds_su.y *= (SFMULT * (1<<nflatshiftup));
-			ds_su.z *= (SFMULT * (1<<nflatshiftup));
-			ds_sv.x *= (SFMULT * (1<<nflatshiftup));
-			ds_sv.y *= (SFMULT * (1<<nflatshiftup));
-			ds_sv.z *= (SFMULT * (1<<nflatshiftup));
+				R_SlopeVectors(pl, i, fudgecanyon);
+			}
+
+			xoffs = rxoffs;
+			yoffs = ryoffs;
 		}
 		else
-		{
-			// I'm essentially multiplying the vectors by FRACUNIT...
-			ds_su.x *= SFMULT;
-			ds_su.y *= SFMULT;
-			ds_su.z *= SFMULT;
-			ds_sv.x *= SFMULT;
-			ds_sv.y *= SFMULT;
-			ds_sv.z *= SFMULT;
-		}
-#undef SFMULT
+#endif
+			R_SlopeVectors(pl, 0, fudgecanyon);
 
+#ifndef NOWATER
+		if ((spanfunc == R_DrawTranslucentWaterSpan_8) || (spanfunc == R_DrawTranslucentSpan_8))
+			spanfunc = R_DrawTiltedTranslucentWaterSpan_8;
+		else
+#endif
 		if (spanfunc == R_DrawTranslucentSpan_8)
 			spanfunc = R_DrawTiltedTranslucentSpan_8;
 		else if (spanfunc == splatfunc)

From 07316fc5bd81e986295cb1b7c00a9a709f5f05d3 Mon Sep 17 00:00:00 2001
From: GoldenTails <milestailsprower101n2@gmail.com>
Date: Tue, 10 Dec 2019 23:55:52 -0600
Subject: [PATCH 19/52] Stop characters from being able to activate their
 abilities when doing a shield ability!

Fixes #61.
---
 src/p_user.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/p_user.c b/src/p_user.c
index ea42a2c36..d409f6bcd 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -5273,7 +5273,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 			player->secondjump = 0;
 			player->pflags &= ~PF_THOKKED;
 		}
-		else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag))
+		else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag) || player->pflags & PF_SHIELDABILITY)
 			;
 		/*else if (P_SuperReady(player))
 		{

From dedd5527dadd2827a2468ab70ff732eddd7c8bd3 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Wed, 11 Dec 2019 11:35:34 -0300
Subject: [PATCH 20/52] Restore portal culling code that went gone by pure
 accident

---
 src/r_bsp.c    | 8 ++++++++
 src/r_main.c   | 2 ++
 src/r_portal.c | 1 +
 src/r_portal.h | 1 +
 4 files changed, 12 insertions(+)

diff --git a/src/r_bsp.c b/src/r_bsp.c
index 2fcaf9e43..51d9bd3fd 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -1378,5 +1378,13 @@ void R_RenderBSPNode(INT32 bspnum)
 		bspnum = bsp->children[side^1];
 	}
 
+	// PORTAL CULLING
+	if (portalcullsector) {
+		sector_t *sect = subsectors[bspnum & ~NF_SUBSECTOR].sector;
+		if (sect != portalcullsector)
+			return;
+		portalcullsector = NULL;
+	}
+
 	R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
 }
diff --git a/src/r_main.c b/src/r_main.c
index dd1243868..c21d339aa 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1008,11 +1008,13 @@ static void R_PortalFrame(portal_t *portal)
 	if (portal->clipline != -1)
 	{
 		portalclipline = &lines[portal->clipline];
+		portalcullsector = portalclipline->frontsector;
 		viewsector = portalclipline->frontsector;
 	}
 	else
 	{
 		portalclipline = NULL;
+		portalcullsector = NULL;
 		viewsector = R_PointInSubsector(viewx, viewy)->sector;
 	}
 }
diff --git a/src/r_portal.c b/src/r_portal.c
index 8995eaac4..576b606ec 100644
--- a/src/r_portal.c
+++ b/src/r_portal.c
@@ -26,6 +26,7 @@ UINT8 portalrender;			/**< When rendering a portal, it establishes the depth of
 portal_t *portal_base, *portal_cap;
 
 line_t *portalclipline;
+sector_t *portalcullsector;
 INT32 portalclipstart, portalclipend;
 
 boolean portalline; // is curline a portal seg?
diff --git a/src/r_portal.h b/src/r_portal.h
index 5990d1959..c46ddfdab 100644
--- a/src/r_portal.h
+++ b/src/r_portal.h
@@ -45,6 +45,7 @@ extern portal_t* portal_cap;
 extern UINT8 portalrender;
 
 extern line_t *portalclipline;
+extern sector_t *portalcullsector;
 extern INT32 portalclipstart, portalclipend;
 
 void Portal_InitList	(void);

From be13f463f025ff9187003283179f3df66e986fd7 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Wed, 11 Dec 2019 12:36:54 -0300
Subject: [PATCH 21/52] Update r_plane.c

---
 src/r_plane.c | 49 +++++++++++++++++++++++++++----------------------
 1 file changed, 27 insertions(+), 22 deletions(-)

diff --git a/src/r_plane.c b/src/r_plane.c
index 97a4ca9f8..aa7f9c6d1 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -135,6 +135,21 @@ INT32 ds_waterofs;
 
 static INT32 wtofs=0;
 static boolean itswater;
+static fixed_t ripple_xfrac;
+static fixed_t ripple_yfrac;
+
+static void R_PlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight)
+{
+	fixed_t distance = FixedMul(plheight, yslope[y]);
+	const INT32 yay = (wtofs + (distance>>9) ) & 8191;
+	// ripples da water texture
+	angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT;
+	ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS;
+
+	angle = (angle + 2048) & 8191;  // 90 degrees
+	ripple_xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS));
+	ripple_yfrac = FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS));
+}
 #endif
 
 void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
@@ -181,14 +196,8 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
 #ifndef NOWATER
 	if (itswater)
 	{
-		const INT32 yay = (wtofs + (distance>>9) ) & 8191;
-		// ripples da water texture
-		ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS;
-		angle = (currentplane->viewangle + currentplane->plangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
-
-		angle = (angle + 2048) & 8191;  // 90 degrees
-		ds_xfrac += FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS));
-		ds_yfrac += FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS));
+		// Needed for ds_bgofs
+		R_PlaneRipple(currentplane, y, planeheight);
 
 #ifdef ESLOPE
 		if (currentplane->slope)
@@ -197,7 +206,12 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
 			ds_svp = &ds_sv[y];
 			ds_szp = &ds_sz[y];
 		}
+		else
 #endif
+		{
+			ds_xfrac += ripple_xfrac;
+			ds_yfrac += ripple_yfrac;
+		}
 
 		if (y+ds_bgofs>=viewheight)
 			ds_bgofs = viewheight-y-1;
@@ -842,7 +856,6 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo
 	return flat;
 }
 
-// Lactokaiju
 #ifdef ESLOPE
 static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge)
 {
@@ -924,7 +937,7 @@ d.z = (v1.x * v2.y) - (v1.y * v2.x)
 	}
 	else
 	{
-		// I'm essentially multiplying the vectors by FRACUNIT...
+		// Lactozilla: I'm essentially multiplying the vectors by FRACUNIT...
 		ds_su[i].x *= SFMULT;
 		ds_su[i].y *= SFMULT;
 		ds_su[i].z *= SFMULT;
@@ -1209,6 +1222,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 		if (itswater)
 		{
 			INT32 i;
+			fixed_t plheight = abs(P_GetZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz);
 			fixed_t rxoffs = xoffs;
 			fixed_t ryoffs = yoffs;
 
@@ -1216,18 +1230,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 			for (i = pl->high; i < pl->low; i++)
 			{
-				// Fuck it
-				fixed_t plheight = abs(P_GetZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz);
-				fixed_t distance = FixedMul(plheight, yslope[i]);
-				const INT32 yay = (wtofs + (distance>>9) ) & 8191;
-				// ripples da water texture
-				ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS;
-				angle = (pl->viewangle + pl->plangle)>>ANGLETOFINESHIFT;
-
-				angle = (angle + 2048) & 8191;  // 90 degrees
-				xoffs = rxoffs + FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS));
-				yoffs = ryoffs + FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS));
-
+				R_PlaneRipple(pl, i, plheight);
+				xoffs = rxoffs + ripple_xfrac;
+				yoffs = ryoffs + ripple_yfrac;
 				R_SlopeVectors(pl, i, fudgecanyon);
 			}
 

From 8a70759e0a2aec24d69a5db8a16322d7f1858a6e Mon Sep 17 00:00:00 2001
From: lachwright <lachlanwright17@gmail.com>
Date: Thu, 12 Dec 2019 01:27:41 +0800
Subject: [PATCH 22/52] Add TC_DASHMODE color shader

---
 src/hardware/hw_md2.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 9d9171cea..61afee0ab 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -729,6 +729,39 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 			cur++; image++; blendimage++;
 		}
 	}
+	else if (skinnum == TC_DASHMODE)
+	{
+		while (size--)
+		{
+			if (image->s.alpha == 0 && blendimage->s.alpha == 0)
+			{
+				// Don't bother with blending the pixel if the alpha of the blend pixel is 0
+				cur->rgba = image->rgba;
+			}
+			else
+			{
+				UINT8 ialpha = 255 - blendimage->s.alpha, balpha = blendimage->s.alpha;
+				RGBA_t icolor = *image, bcolor;
+
+				if (blendimage->s.alpha)
+				{
+					bcolor.s.blue = 0;
+					bcolor.s.red = 255;
+					bcolor.s.green = (blendimage->s.red + blendimage->s.green + blendimage->s.blue) / 3;
+				}
+				if (image->s.alpha && image->s.red > image->s.green << 1) // this is pretty arbitrary, but it works well for Metal Sonic
+				{
+					icolor.s.red = image->s.blue;
+					icolor.s.blue = image->s.red;
+				}
+				cur->s.red = (ialpha * icolor.s.red + balpha * bcolor.s.red)/255;
+				cur->s.green = (ialpha * icolor.s.green + balpha * bcolor.s.green)/255;
+				cur->s.blue = (ialpha * icolor.s.blue + balpha * bcolor.s.blue)/255;
+				cur->s.alpha = image->s.alpha;
+			}
+			cur++; image++; blendimage++;
+		}
+	}
 	else
 	{
 		while (size--)

From ea129f701c86f87daa7355e6f031d0633951cdfa Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Wed, 11 Dec 2019 22:45:47 -0300
Subject: [PATCH 23/52] Fix Ploadflat closing the game with "Too many flats in
 level" error message

---
 src/p_setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/p_setup.c b/src/p_setup.c
index 3c45509ee..8a927d65a 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -672,7 +672,7 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
 //
 INT32 P_AddLevelFlatRuntime(const char *flatname)
 {
-	return Ploadflat(0, flatname);
+	return Ploadflat(levelflats, flatname);
 }
 
 // help function for $$$.sav checking

From 792750ee48159323896b75c24fe54ceea6acab98 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 16:48:37 -0300
Subject: [PATCH 24/52] Add HWD_SET_MODEL_LIGHTING state

---
 src/hardware/hw_defs.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 965f06980..979093dc8 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -220,11 +220,10 @@ typedef struct FSurfaceInfo FSurfaceInfo;
 //Hurdler: added for backward compatibility
 enum hwdsetspecialstate
 {
-	HWD_SET_FOG_TABLE = 1,
+	HWD_SET_MODEL_LIGHTING = 1,
 	HWD_SET_FOG_MODE,
 	HWD_SET_FOG_COLOR,
 	HWD_SET_FOG_DENSITY,
-	HWD_SET_FOV,
 	HWD_SET_TEXTUREFILTERMODE,
 	HWD_SET_TEXTUREANISOTROPICMODE,
 	HWD_NUMSTATE

From 08e3caf9bb92bab973696fcb4c6aab4ef1c01eec Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 16:53:31 -0300
Subject: [PATCH 25/52] Remove unused cvars

---
 src/hardware/hw_main.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 583a877fc..0a38894de 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -108,9 +108,6 @@ boolean drawsky = true;
 #ifndef NEWCLIP
 static consvar_t cv_grclipwalls = {"gr_clipwalls", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
-//development variables for diverse uses
-static consvar_t cv_gralpha = {"gr_alpha", "160", 0, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_grbeta = {"gr_beta", "0", 0, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grfov = {"gr_fov", "90", CV_FLOAT|CV_CALL, grfov_cons_t, CV_grFov_OnChange, 0, NULL, NULL, 0, 0, NULL};
@@ -122,7 +119,7 @@ consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_c
                              CV_filtermode_ONChange, 0, NULL, NULL, 0, 0, NULL};
 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", "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};
 
@@ -2477,7 +2474,7 @@ static cliprange_t     gr_solidsegs[MAXSEGS];
 static void printsolidsegs(void)
 {
 	cliprange_t *       start;
-	if (!hw_newend || cv_grbeta.value != 2)
+	if (!hw_newend)
 		return;
 	for (start = gr_solidsegs;start != hw_newend;start++)
 	{
@@ -6627,16 +6624,10 @@ void HWR_AddCommands(void)
 static inline void HWR_AddEngineCommands(void)
 {
 	// engine state variables
-	//CV_RegisterVar(&cv_grzbuffer);
 #ifndef NEWCLIP
 	CV_RegisterVar(&cv_grclipwalls);
 #endif
 
-	// engine development mode variables
-	// - usage may vary from version to version..
-	CV_RegisterVar(&cv_gralpha);
-	CV_RegisterVar(&cv_grbeta);
-
 	// engine commands
 	COM_AddCommand("gr_stats", Command_GrStats_f);
 }

From b7c7529e75a07b7a0e4e689ebdb81d289dd607be Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 17:06:04 -0300
Subject: [PATCH 26/52] Don't reset the FOV

---
 src/p_setup.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/src/p_setup.c b/src/p_setup.c
index 0a3c85521..4ee74195f 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3182,11 +3182,6 @@ boolean P_SetupLevel(boolean skipprecip)
 		if (!cv_analog2.changed)
 			CV_SetValue(&cv_analog2, 0);
 
-#ifdef HWRENDER
-		if (rendermode != render_soft && rendermode != render_none)
-			CV_Set(&cv_grfov, cv_grfov.defaultvalue);
-#endif
-
 		displayplayer = consoleplayer; // Start with your OWN view, please!
 	}
 

From bf520b9e333318142d043b8421a9a5639102fcf2 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 17:30:19 -0300
Subject: [PATCH 27/52] Please, for the love of God, Jesus and Bastet, ADD
 EVERY OPENGL COMMAND REGARDLESS OF THE FREAKING
 RENDERER!!!!!!!!!!!!!!!!!!!!!!!!!!!

---
 src/d_main.c           |   7 ++
 src/hardware/hw_main.c | 152 +++++++++++++++++++++++++----------------
 src/r_main.c           |  23 -------
 src/v_video.c          |  26 -------
 4 files changed, 100 insertions(+), 108 deletions(-)

diff --git a/src/d_main.c b/src/d_main.c
index 397406293..ef6502aec 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1193,6 +1193,13 @@ void D_SRB2Main(void)
 	CONS_Printf("I_StartupGraphics()...\n");
 	I_StartupGraphics();
 
+#ifdef HWRENDER
+	// Lactozilla: Add every hardware mode CVAR and CCMD.
+	// Has to be done before the configuration file loads,
+	// but after the OpenGL library loads.
+	HWR_AddCommands();
+#endif
+
 	//--------------------------------------------------------- CONSOLE
 	// setup loading screen
 	SCR_Startup();
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 0a38894de..4eb15e1ea 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -85,59 +85,8 @@ static void HWR_RenderTransparentWalls(void);
 static void HWR_FoggingOn(void);
 static UINT32 atohex(const char *s);
 
-static void CV_filtermode_ONChange(void);
-static void CV_anisotropic_ONChange(void);
-static void CV_FogDensity_ONChange(void);
-static void CV_grFov_OnChange(void);
-// ==========================================================================
-//                                          3D ENGINE COMMANDS & CONSOLE VARS
-// ==========================================================================
-
-static CV_PossibleValue_t grfov_cons_t[] = {{0, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}};
-static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
-	{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
-	{HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
-	{HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
-	{HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"},
-	{0, NULL}};
-CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
-
 boolean drawsky = true;
 
-// needs fix: walls are incorrectly clipped one column less
-#ifndef NEWCLIP
-static consvar_t cv_grclipwalls = {"gr_clipwalls", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-#endif
-
-consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grfov = {"gr_fov", "90", CV_FLOAT|CV_CALL, grfov_cons_t, CV_grFov_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsigned,
-                             CV_FogDensity_ONChange, 0, NULL, NULL, 0, 0, NULL};
-
-// Unfortunately, this can no longer be saved..
-consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_cons_t,
-                             CV_filtermode_ONChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
-                             CV_anisotropic_ONChange, 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)
-{
-	HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value);
-}
-
-static void CV_filtermode_ONChange(void)
-{
-	HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value);
-}
-
-static void CV_anisotropic_ONChange(void)
-{
-	HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value);
-}
-
 /*
  * lookuptable for lightvalues
  * calculated as follow:
@@ -2470,6 +2419,8 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks
 static cliprange_t *   hw_newend;
 static cliprange_t     gr_solidsegs[MAXSEGS];
 
+// needs fix: walls are incorrectly clipped one column less
+static consvar_t cv_grclipwalls = {"gr_clipwalls", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 static void printsolidsegs(void)
 {
@@ -6585,13 +6536,6 @@ static void HWR_FoggingOn(void)
 //                                                         3D ENGINE COMMANDS
 // ==========================================================================
 
-
-static void CV_grFov_OnChange(void)
-{
-	if ((netgame || multiplayer) && !cv_debug && cv_grfov.value != 90*FRACUNIT)
-		CV_Set(&cv_grfov, cv_grfov.defaultvalue);
-}
-
 static void Command_GrStats_f(void)
 {
 	Z_CheckHeap(9875); // debug
@@ -6609,14 +6553,104 @@ static void Command_GrStats_f(void)
 // --------------------------------------------------------------------------
 // Add hardware engine commands & consvars
 // --------------------------------------------------------------------------
+static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}};
+static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
+
+static void CV_grfiltermode_OnChange(void);
+static void CV_granisotropic_OnChange(void);
+static void CV_grfogdensity_OnChange(void);
+static void CV_grfov_OnChange(void);
+
+static CV_PossibleValue_t grfov_cons_t[] = {{0, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}};
+static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
+	{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
+	{HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
+	{HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
+	{HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"},
+	{0, NULL}};
+CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
+
+consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grsoftwarefog = {"gr_softwarefog", "Off", CV_SAVE, grsoftwarefog_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+#ifdef ALAM_LIGHTING
+consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grstaticlighting  = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL};
+#endif
+
+consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grfov = {"gr_fov", "90", CV_FLOAT|CV_CALL, grfov_cons_t, CV_grfov_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsigned,
+                             CV_grfogdensity_OnChange, 0, NULL, NULL, 0, 0, NULL};
+
+consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_cons_t,
+                             CV_grfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
+                             CV_granisotropic_OnChange, 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_grfogdensity_OnChange(void)
+{
+	if (rendermode == render_opengl)
+		HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value);
+}
+
+static void CV_grfiltermode_OnChange(void)
+{
+	if (rendermode == render_opengl)
+		HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value);
+}
+
+static void CV_granisotropic_OnChange(void)
+{
+	if (rendermode == render_opengl)
+		HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value);
+}
+
+static void CV_grfov_OnChange(void)
+{
+	if ((netgame || multiplayer) && !cv_debug && cv_grfov.value != 90*FRACUNIT)
+		CV_Set(&cv_grfov, cv_grfov.defaultvalue);
+}
+
 //added by Hurdler: console varibale that are saved
 void HWR_AddCommands(void)
 {
-	CV_RegisterVar(&cv_grrounddown);
+	CV_RegisterVar(&cv_grfovchange);
 	CV_RegisterVar(&cv_grfov);
+
 	CV_RegisterVar(&cv_grfogdensity);
+	CV_RegisterVar(&cv_grfogcolor);
+	CV_RegisterVar(&cv_grfog);
+	CV_RegisterVar(&cv_grsoftwarefog);
+
+#ifdef ALAM_LIGHTING
+	CV_RegisterVar(&cv_grstaticlighting);
+	CV_RegisterVar(&cv_grdynamiclighting);
+	CV_RegisterVar(&cv_grcoronasize);
+	CV_RegisterVar(&cv_grcoronas);
+#endif
+
+	CV_RegisterVar(&cv_grmodelinterpolation);
+	CV_RegisterVar(&cv_grmodels);
+	CV_RegisterVar(&cv_grskydome);
+	CV_RegisterVar(&cv_grspritebillboarding);
+
 	CV_RegisterVar(&cv_grfiltermode);
 	CV_RegisterVar(&cv_granisotropicmode);
+	CV_RegisterVar(&cv_grrounddown);
 	CV_RegisterVar(&cv_grcorrecttricks);
 	CV_RegisterVar(&cv_grsolvetjoin);
 }
diff --git a/src/r_main.c b/src/r_main.c
index 541360025..a710daf3b 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1208,27 +1208,4 @@ void R_RegisterEngineStuff(void)
 	CV_RegisterVar(&cv_maxportals);
 
 	CV_RegisterVar(&cv_movebob);
-
-#ifdef HWRENDER
-	// GL-specific Commands
-	CV_RegisterVar(&cv_grfovchange);
-	CV_RegisterVar(&cv_grfog);
-	CV_RegisterVar(&cv_grfogcolor);
-	CV_RegisterVar(&cv_grsoftwarefog);
-#ifdef ALAM_LIGHTING
-	CV_RegisterVar(&cv_grstaticlighting);
-	CV_RegisterVar(&cv_grdynamiclighting);
-	CV_RegisterVar(&cv_grcoronas);
-	CV_RegisterVar(&cv_grcoronasize);
-#endif
-	CV_RegisterVar(&cv_grmodelinterpolation);
-	CV_RegisterVar(&cv_grmodels);
-	CV_RegisterVar(&cv_grspritebillboarding);
-	CV_RegisterVar(&cv_grskydome);
-#endif
-
-#ifdef HWRENDER
-	if (rendermode != render_soft && rendermode != render_none)
-		HWR_AddCommands();
-#endif
 }
diff --git a/src/v_video.c b/src/v_video.c
index 25cbccee2..1c5cbbc0a 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -84,32 +84,6 @@ static CV_PossibleValue_t constextsize_cons_t[] = {
 static void CV_constextsize_OnChange(void);
 consvar_t cv_constextsize = {"con_textsize", "Medium", CV_SAVE|CV_CALL, constextsize_cons_t, CV_constextsize_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
-#ifdef HWRENDER
-// Saved hardware mode variables
-// - You can change them in software,
-// but they won't do anything.
-static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}};
-static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
-
-consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grsoftwarefog = {"gr_softwarefog", "Off", CV_SAVE, grsoftwarefog_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-#ifdef ALAM_LIGHTING
-consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grstaticlighting  = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL};
-#endif
-
-consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-#endif
-
 // local copy of the palette for V_GetColor()
 RGBA_t *pLocalPalette = NULL;
 RGBA_t *pMasterPalette = NULL;

From db61d1a705acd3390dfdf4d4c542357d2081d7f8 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 17:35:41 -0300
Subject: [PATCH 28/52] Remove HWR_AddEngineCommands

---
 src/hardware/hw_main.c | 28 ----------------------------
 1 file changed, 28 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 4eb15e1ea..a42e43928 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6536,23 +6536,6 @@ static void HWR_FoggingOn(void)
 //                                                         3D ENGINE COMMANDS
 // ==========================================================================
 
-static void Command_GrStats_f(void)
-{
-	Z_CheckHeap(9875); // debug
-
-	CONS_Printf(M_GetText("Patch info headers: %7s kb\n"), sizeu1(Z_TagUsage(PU_HWRPATCHINFO)>>10));
-	CONS_Printf(M_GetText("3D Texture cache  : %7s kb\n"), sizeu1(Z_TagUsage(PU_HWRCACHE)>>10));
-	CONS_Printf(M_GetText("Plane polygon     : %7s kb\n"), sizeu1(Z_TagUsage(PU_HWRPLANE)>>10));
-}
-
-
-// **************************************************************************
-//                                                            3D ENGINE SETUP
-// **************************************************************************
-
-// --------------------------------------------------------------------------
-// Add hardware engine commands & consvars
-// --------------------------------------------------------------------------
 static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}};
 static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
 
@@ -6653,17 +6636,10 @@ void HWR_AddCommands(void)
 	CV_RegisterVar(&cv_grrounddown);
 	CV_RegisterVar(&cv_grcorrecttricks);
 	CV_RegisterVar(&cv_grsolvetjoin);
-}
 
-static inline void HWR_AddEngineCommands(void)
-{
-	// engine state variables
 #ifndef NEWCLIP
 	CV_RegisterVar(&cv_grclipwalls);
 #endif
-
-	// engine commands
-	COM_AddCommand("gr_stats", Command_GrStats_f);
 }
 
 
@@ -6686,12 +6662,8 @@ void HWR_Startup(void)
 	{
 		CONS_Printf("HWR_Startup()...\n");
 		HWR_InitPolyPool();
-		// add console cmds & vars
-		HWR_AddEngineCommands();
 		HWR_InitTextureCache();
-
 		HWR_InitModels();
-
 #ifdef ALAM_LIGHTING
 		HWR_InitLight();
 #endif

From f077d173011379e39e82f4467d857ab9a015df2b Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 17:37:55 -0300
Subject: [PATCH 29/52] Save filtering mode and anisotropic mode cvars to
 config

---
 src/hardware/hw_main.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index a42e43928..09ace5682 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6562,7 +6562,7 @@ consvar_t cv_grsoftwarefog = {"gr_softwarefog", "Off", CV_SAVE, grsoftwarefog_co
 consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grstaticlighting  = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
 
 consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -6576,9 +6576,9 @@ consvar_t cv_grfov = {"gr_fov", "90", CV_FLOAT|CV_CALL, grfov_cons_t, CV_grfov_O
 consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsigned,
                              CV_grfogdensity_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
-consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_cons_t,
+consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, grfiltermode_cons_t,
                              CV_grfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
+consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_SAVE|CV_CALL, granisotropicmode_cons_t,
                              CV_granisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
 consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};

From a4b0195430c78ebb98f83656457d305d4c54551d Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 17:48:29 -0300
Subject: [PATCH 30/52] Model lighting

---
 src/hardware/hw_main.c           | 10 ++++++++++
 src/hardware/r_opengl/r_opengl.c | 32 ++++++++++++++++++--------------
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 09ace5682..07a666066 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6539,6 +6539,7 @@ static void HWR_FoggingOn(void)
 static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}};
 static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
 
+static void CV_grmodellighting_OnChange(void);
 static void CV_grfiltermode_OnChange(void);
 static void CV_granisotropic_OnChange(void);
 static void CV_grfogdensity_OnChange(void);
@@ -6567,6 +6568,7 @@ consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL, 0,
 
 consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_grmodellighting_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
 consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -6584,6 +6586,12 @@ consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_SAVE|CV_CALL, gr
 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_grmodellighting_OnChange(void)
+{
+	if (rendermode == render_opengl)
+		HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_grmodellighting.value);
+}
+
 static void CV_grfogdensity_OnChange(void)
 {
 	if (rendermode == render_opengl)
@@ -6626,8 +6634,10 @@ void HWR_AddCommands(void)
 	CV_RegisterVar(&cv_grcoronas);
 #endif
 
+	CV_RegisterVar(&cv_grmodellighting);
 	CV_RegisterVar(&cv_grmodelinterpolation);
 	CV_RegisterVar(&cv_grmodels);
+
 	CV_RegisterVar(&cv_grskydome);
 	CV_RegisterVar(&cv_grspritebillboarding);
 
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 16c1ad010..129bf5678 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -85,6 +85,7 @@ static GLboolean MipMap = GL_FALSE;
 static GLint min_filter = GL_LINEAR;
 static GLint mag_filter = GL_LINEAR;
 static GLint anisotropic_filter = 0;
+static boolean model_lighting = true;
 
 const GLubyte *gl_extensions = NULL;
 
@@ -1658,16 +1659,9 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
 {
 	switch (IdState)
 	{
-
-#if 0
-		case 77:
-		{
-			//08/01/00: Hurdler this is a test for mirror
-			if (!Value)
-				ClearBuffer(false, true, 0); // clear depth buffer
+		case HWD_SET_MODEL_LIGHTING:
+			model_lighting = Value;
 			break;
-		}
-#endif
 
 		case HWD_SET_FOG_COLOR:
 		{
@@ -1680,6 +1674,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
 			pglFogfv(GL_FOG_COLOR, fogcolor);
 			break;
 		}
+
 		case HWD_SET_FOG_DENSITY:
 			pglFogf(GL_FOG_DENSITY, Value*1200/(500*1000000.0f));
 			break;
@@ -2044,16 +2039,25 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 	}
 #endif
 
-	pglLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+	if (model_lighting)
+	{
+		pglLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+		pglShadeModel(GL_SMOOTH);
+	}
 
-	pglShadeModel(GL_SMOOTH);
 	if (color)
 	{
 #ifdef GL_LIGHT_MODEL_AMBIENT
-		pglEnable(GL_LIGHTING);
-		pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
-		pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
+		if (model_lighting)
+		{
+			pglEnable(GL_LIGHTING);
+			pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
+			pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
+		}
+		else
 #endif
+			pglColor4ubv((GLubyte*)color);
+
 		if (color[3] < 255)
 			SetBlend(PF_Translucent|PF_Modulated|PF_Clip);
 		else

From 58a08504c8cbbed5851c637b1533ed3816f593b3 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 17:48:43 -0300
Subject: [PATCH 31/52] Make gr_spritebillboarding on by default sorry not
 sorry Azeon

---
 src/hardware/hw_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 07a666066..cc181733c 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6570,7 +6570,7 @@ consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, N
 consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_grmodellighting_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
-consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};

From 3bebfb279e020ee14432df552920546dacdd0615 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 18:28:05 -0300
Subject: [PATCH 32/52] Fix gr_anisotropicmode

---
 src/hardware/hw_main.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index cc181733c..1e1935c44 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6580,7 +6580,7 @@ consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsig
 
 consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, grfiltermode_cons_t,
                              CV_grfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_SAVE|CV_CALL, granisotropicmode_cons_t,
+consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
                              CV_granisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
 consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -6642,7 +6642,6 @@ void HWR_AddCommands(void)
 	CV_RegisterVar(&cv_grspritebillboarding);
 
 	CV_RegisterVar(&cv_grfiltermode);
-	CV_RegisterVar(&cv_granisotropicmode);
 	CV_RegisterVar(&cv_grrounddown);
 	CV_RegisterVar(&cv_grcorrecttricks);
 	CV_RegisterVar(&cv_grsolvetjoin);
@@ -6652,6 +6651,10 @@ void HWR_AddCommands(void)
 #endif
 }
 
+void HWR_AddSessionCommands(void)
+{
+	CV_RegisterVar(&cv_granisotropicmode);
+}
 
 // --------------------------------------------------------------------------
 // Setup the hardware renderer
@@ -6672,6 +6675,7 @@ void HWR_Startup(void)
 	{
 		CONS_Printf("HWR_Startup()...\n");
 		HWR_InitPolyPool();
+		HWR_AddSessionCommands();
 		HWR_InitTextureCache();
 		HWR_InitModels();
 #ifdef ALAM_LIGHTING

From 55f3f27b55802589062de99aad4318e08e58354d Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Thu, 12 Dec 2019 14:00:13 -0800
Subject: [PATCH 33/52] Fix NOHW warnings

---
 src/dehacked.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/dehacked.c b/src/dehacked.c
index bcf842c8d..175c1fcfa 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -242,6 +242,7 @@ INT32 flags;         Bits = 3232              MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|M
 INT32 raisestate;    Respawn frame = 32       S_NULL          // raisestate
                                          }, */
 
+#ifdef HWRENDER
 static INT32 searchvalue(const char *s)
 {
 	while (s[0] != '=' && s[0])
@@ -255,7 +256,6 @@ static INT32 searchvalue(const char *s)
 	}
 }
 
-#ifdef HWRENDER
 static float searchfvalue(const char *s)
 {
 	while (s[0] != '=' && s[0])
@@ -886,7 +886,9 @@ static void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 	char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
 	char *word, *word2;
 	char *tmp;
+#ifdef HWRENDER
 	INT32 value;
+#endif
 	char *lastline;
 	INT32 skinnumbers[MAXSKINS];
 	INT32 foundskins = 0;
@@ -947,9 +949,9 @@ static void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 					break;
 			}
 			strupr(word);
+#ifdef HWRENDER
 			value = atoi(word2); // used for numerical settings
 
-#ifdef HWRENDER
 			if (fastcmp(word, "LIGHTTYPE"))
 			{
 				if (sprite2)

From 6c3111d809c4e9237fb8bbf4b579b80f66e6f0ca Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 19:54:47 -0300
Subject: [PATCH 34/52] Stop crashing with models because someone keeps freeing
 those tags

---
 src/hardware/hw_md2.c | 10 +++++-----
 src/z_zone.h          |  1 +
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 9245d7fc2..8f8e7c333 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -239,7 +239,7 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_
 
 	{
 		png_uint_32 i, pitch = png_get_rowbytes(png_ptr, png_info_ptr);
-		png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRCACHE, &grpatch->mipmap->grInfo.data);
+		png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRMODELTEXTURE, &grpatch->mipmap->grInfo.data);
 		png_bytepp row_pointers = png_malloc(png_ptr, height * sizeof (png_bytep));
 		for (i = 0; i < height; i++)
 			row_pointers[i] = PNG_image + i*pitch;
@@ -313,7 +313,7 @@ static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h,
 
 	pw = *w = header.xmax - header.xmin + 1;
 	ph = *h = header.ymax - header.ymin + 1;
-	image = Z_Malloc(pw*ph*4, PU_HWRCACHE, &grpatch->mipmap->grInfo.data);
+	image = Z_Malloc(pw*ph*4, PU_HWRMODELTEXTURE, &grpatch->mipmap->grInfo.data);
 
 	if (fread(palette, sizeof (UINT8), PALSIZE, file) != PALSIZE)
 	{
@@ -661,7 +661,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 	Z_Free(grmip->grInfo.data);
 	grmip->grInfo.data = NULL;
 
-	cur = Z_Malloc(size*4, PU_HWRCACHE, &grmip->grInfo.data);
+	cur = Z_Malloc(size*4, PU_HWRMODELTEXTURE, &grmip->grInfo.data);
 	memset(cur, 0x00, size*4);
 
 	image = gpatch->mipmap->grInfo.data;
@@ -794,7 +794,7 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
 			if (grmip->downloaded && grmip->grInfo.data)
 			{
 				HWD.pfnSetTexture(grmip); // found the colormap, set it to the correct texture
-				Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
+				Z_ChangeTag(grmip->grInfo.data, PU_HWRMODELTEXTURE);
 				return;
 			}
 		}
@@ -816,7 +816,7 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
 	HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color);
 
 	HWD.pfnSetTexture(newmip);
-	Z_ChangeTag(newmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
+	Z_ChangeTag(newmip->grInfo.data, PU_HWRMODELTEXTURE);
 }
 
 #define NORMALFOG 0x00000000
diff --git a/src/z_zone.h b/src/z_zone.h
index 67da1f7e8..635c334cf 100644
--- a/src/z_zone.h
+++ b/src/z_zone.h
@@ -46,6 +46,7 @@ enum
 
 	PU_HWRPATCHINFO          = 21, // Hardware GLPatch_t struct for OpenGL texture cache
 	PU_HWRPATCHCOLMIPMAP     = 22, // Hardware GLMipmap_t struct colormap variation of patch
+	PU_HWRMODELTEXTURE       = 23, // Hardware model texture
 
 	PU_HWRCACHE              = 48, // static until unlocked
 	PU_CACHE                 = 49, // static until unlocked

From 08d4a36f6381c25ffc48b7aa76c1b00ad401fb00 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 21:22:36 -0300
Subject: [PATCH 35/52] Texture blending port

Co-authored-by: TehRealSalt <tehrealsalt@gmail.com>
---
 src/hardware/hw_md2.c | 285 +++++++++++++++++++++++++++++++-----------
 1 file changed, 209 insertions(+), 76 deletions(-)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 8f8e7c333..7e2b2d3fc 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -637,15 +637,18 @@ spritemd2found:
 // 0.7152 to green
 // 0.0722 to blue
 #define SETBRIGHTNESS(brightness,r,g,b) \
-	brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
+	brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000))
 
 static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color)
 {
-	UINT8 i;
 	UINT16 w = gpatch->width, h = gpatch->height;
 	UINT32 size = w*h;
 	RGBA_t *image, *blendimage, *cur, blendcolor;
 
+	// vanilla port
+	UINT8 translation[16];
+	memset(translation, 0, sizeof(translation));
+
 	if (grmip->width == 0)
 	{
 
@@ -658,113 +661,243 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 		grmip->grInfo.format = GR_RGBA;
 	}
 
-	Z_Free(grmip->grInfo.data);
-	grmip->grInfo.data = NULL;
+	if (grmip->grInfo.data)
+	{
+		Z_Free(grmip->grInfo.data);
+		grmip->grInfo.data = NULL;
+	}
 
 	cur = Z_Malloc(size*4, PU_HWRMODELTEXTURE, &grmip->grInfo.data);
 	memset(cur, 0x00, size*4);
 
 	image = gpatch->mipmap->grInfo.data;
 	blendimage = blendgpatch->mipmap->grInfo.data;
+	blendcolor = V_GetColor(0); // initialize
 
-	// Average all of the translation's colors
-	if (color == SKINCOLOR_NONE || color >= MAXTRANSLATIONS)
-		blendcolor = V_GetColor(0xff);
-	else
+	if (color != SKINCOLOR_NONE)
+		memcpy(&translation, &Color_Index[color - 1], 16);
+
+	while (size--)
 	{
-		const UINT8 div = 6;
-		const UINT8 start = 4;
-		UINT32 r, g, b;
-
-		blendcolor = V_GetColor(Color_Index[color-1][start]);
-		r = (UINT32)(blendcolor.s.red*blendcolor.s.red);
-		g = (UINT32)(blendcolor.s.green*blendcolor.s.green);
-		b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue);
-
-		for (i = 1; i < div; i++)
+		if (skinnum == TC_BOSS)
 		{
-			RGBA_t nextcolor = V_GetColor(Color_Index[color-1][start+i]);
-			r += (UINT32)(nextcolor.s.red*nextcolor.s.red);
-			g += (UINT32)(nextcolor.s.green*nextcolor.s.green);
-			b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue);
-		}
-
-		blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<<FRACBITS)>>FRACBITS);
-		blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<<FRACBITS)>>FRACBITS);
-		blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<<FRACBITS)>>FRACBITS);
-	}
-
-	// rainbow support, could theoretically support boss ones too
-	if (skinnum == TC_RAINBOW)
-	{
-		while (size--)
-		{
-			if (image->s.alpha == 0 && blendimage->s.alpha == 0)
+			// Pure black turns into white
+			if (image->s.red == 0 && image->s.green == 0 && image->s.blue == 0)
 			{
-				// Don't bother with blending the pixel if the alpha of the blend pixel is 0
-				cur->rgba = image->rgba;
+				cur->s.red = cur->s.green = cur->s.blue = 255;
 			}
 			else
+			{
+				cur->s.red = image->s.red;
+				cur->s.green = image->s.green;
+				cur->s.blue = image->s.blue;
+			}
+
+			cur->s.alpha = image->s.alpha;
+		}
+		else if (skinnum == TC_METALSONIC)
+		{
+			// Turn everything below a certain blue threshold white
+			if (image->s.red == 0 && image->s.green == 0 && image->s.blue <= 82)
+			{
+				cur->s.red = cur->s.green = cur->s.blue = 255;
+			}
+			else
+			{
+				cur->s.red = image->s.red;
+				cur->s.green = image->s.green;
+				cur->s.blue = image->s.blue;
+			}
+
+			cur->s.alpha = image->s.alpha;
+		}
+		else if (skinnum == TC_ALLWHITE)
+		{
+			// Turn everything white
+			cur->s.red = cur->s.green = cur->s.blue = 255;
+			cur->s.alpha = image->s.alpha;
+		}
+		else
+		{
+			UINT16 brightness;
+
+			// Don't bother with blending the pixel if the alpha of the blend pixel is 0
+			if (skinnum == TC_RAINBOW)
+			{
+				if (image->s.alpha == 0 && blendimage->s.alpha == 0)
+				{
+					cur->rgba = image->rgba;
+					cur++; image++; blendimage++;
+					continue;
+				}
+				else
+				{
+					UINT16 imagebright, blendbright;
+					SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
+					SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
+					// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
+					brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
+				}
+			}
+			else
+			{
+				if (blendimage->s.alpha == 0)
+				{
+					cur->rgba = image->rgba;
+					cur++; image++; blendimage++;
+					continue;
+				}
+				else
+				{
+					SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
+				}
+			}
+
+			// Calculate a sort of "gradient" for the skincolor
+			// (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...)
+			{
+				RGBA_t nextcolor;
+				UINT8 firsti, secondi, mul;
+				UINT32 r, g, b;
+
+				// Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors.
+				// Ensue horrible mess.
+				if (skinnum == TC_RAINBOW)
+				{
+					UINT16 brightdif = 256;
+					UINT8 colorbrightnesses[16];
+					INT32 compare, m, d;
+					UINT8 i;
+
+					// Ignore pure white & pitch black
+					if (brightness > 253 || brightness < 2)
+					{
+						cur->rgba = image->rgba;
+						cur++; image++; blendimage++;
+						continue;
+					}
+
+					firsti = 0;
+					mul = 0;
+
+					for (i = 0; i < 16; i++)
+					{
+						RGBA_t tempc = V_GetColor(translation[i]);
+						SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
+					}
+
+					for (i = 0; i < 16; i++)
+					{
+						if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is)
+							continue;
+						compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness));
+						if (compare < brightdif)
+						{
+							brightdif = (UINT16)compare;
+							firsti = i; // best matching color that's equal brightness or darker
+						}
+					}
+
+					secondi = firsti+1; // next color in line
+					if (secondi == 16)
+					{
+						m = (INT16)brightness; // - 0;
+						d = (INT16)colorbrightnesses[firsti]; // - 0;
+					}
+					else
+					{
+						m = (INT16)brightness - (INT16)colorbrightnesses[secondi];
+						d = (INT16)colorbrightnesses[firsti] - (INT16)colorbrightnesses[secondi];
+					}
+
+					if (m >= d)
+						m = d-1;
+
+					// calculate the "gradient" multiplier based on how close this color is to the one next in line
+					if (m <= 0 || d <= 0)
+						mul = 0;
+					else
+						mul = 15 - ((m * 16) / d);
+				}
+				else
+				{
+					// Thankfully, it's normally way more simple.
+					// Just convert brightness to a skincolor value, use remainder to find the gradient multipler
+					firsti = ((UINT8)(255-brightness) / 16);
+					secondi = firsti+1;
+					mul = ((UINT8)(255-brightness) % 16);
+				}
+
+				blendcolor = V_GetColor(translation[firsti]);
+
+				if (mul > 0 // If it's 0, then we only need the first color.
+					&& translation[firsti] != translation[secondi]) // Some colors have duplicate colors in a row, so let's just save the process
+				{
+					if (secondi == 16) // blend to black
+						nextcolor = V_GetColor(31);
+					else
+						nextcolor = V_GetColor(translation[secondi]);
+
+					// Find difference between points
+					r = (UINT32)(nextcolor.s.red - blendcolor.s.red);
+					g = (UINT32)(nextcolor.s.green - blendcolor.s.green);
+					b = (UINT32)(nextcolor.s.blue - blendcolor.s.blue);
+
+					// Find the gradient of the two points
+					r = ((mul * r) / 16);
+					g = ((mul * g) / 16);
+					b = ((mul * b) / 16);
+
+					// Add gradient value to color
+					blendcolor.s.red += r;
+					blendcolor.s.green += g;
+					blendcolor.s.blue += b;
+				}
+			}
+
+			if (skinnum == TC_RAINBOW)
 			{
 				UINT32 tempcolor;
-				UINT16 imagebright, blendbright, finalbright, colorbright;
-				SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
-				SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
-				// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
-				finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
-				SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
+				UINT16 colorbright;
 
-				tempcolor = (finalbright*blendcolor.s.red)/colorbright;
+				SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
+				if (colorbright == 0)
+					colorbright = 1; // no dividing by 0 please
+
+				tempcolor = (brightness * blendcolor.s.red) / colorbright;
 				tempcolor = min(255, tempcolor);
 				cur->s.red = (UINT8)tempcolor;
-				tempcolor = (finalbright*blendcolor.s.green)/colorbright;
+
+				tempcolor = (brightness * blendcolor.s.green) / colorbright;
 				tempcolor = min(255, tempcolor);
 				cur->s.green = (UINT8)tempcolor;
-				tempcolor = (finalbright*blendcolor.s.blue)/colorbright;
+
+				tempcolor = (brightness * blendcolor.s.blue) / colorbright;
 				tempcolor = min(255, tempcolor);
 				cur->s.blue = (UINT8)tempcolor;
 				cur->s.alpha = image->s.alpha;
 			}
-
-			cur++; image++; blendimage++;
-		}
-	}
-	else
-	{
-		while (size--)
-		{
-			if (blendimage->s.alpha == 0)
-			{
-				// Don't bother with blending the pixel if the alpha of the blend pixel is 0
-				cur->rgba = image->rgba;
-			}
 			else
 			{
+				// Color strength depends on image alpha
 				INT32 tempcolor;
-				INT16 tempmult, tempalpha;
-				tempalpha = -(abs(blendimage->s.red-127)-127)*2;
-				if (tempalpha > 255)
-					tempalpha = 255;
-				else if (tempalpha < 0)
-					tempalpha = 0;
 
-				tempmult = (blendimage->s.red-127)*2;
-				if (tempmult > 255)
-					tempmult = 255;
-				else if (tempmult < 0)
-					tempmult = 0;
-
-				tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
+				tempcolor = ((image->s.red * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.red * blendimage->s.alpha) / 255);
+				tempcolor = min(255, tempcolor);
 				cur->s.red = (UINT8)tempcolor;
-				tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
+
+				tempcolor = ((image->s.green * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.green * blendimage->s.alpha) / 255);
+				tempcolor = min(255, tempcolor);
 				cur->s.green = (UINT8)tempcolor;
-				tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
+
+				tempcolor = ((image->s.blue * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.blue * blendimage->s.alpha) / 255);
+				tempcolor = min(255, tempcolor);
 				cur->s.blue = (UINT8)tempcolor;
 				cur->s.alpha = image->s.alpha;
 			}
-
-			cur++; image++; blendimage++;
 		}
+
+		cur++; image++; blendimage++;
 	}
 
 	return;

From d80bfb4e940c6b57770ecdc071068df058cf608c Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 21:23:55 -0300
Subject: [PATCH 36/52] =?UTF-8?q?PU=5FHWRCACHE=5FUNLOCKED=20bmomento=20br?=
 =?UTF-8?q?=C3=B3der?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/hardware/hw_md2.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 7e2b2d3fc..77cdfa0d3 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -397,7 +397,6 @@ static void md2_loadTexture(md2_t *model)
 #endif
 	}
 	HWD.pfnSetTexture(grpatch->mipmap);
-	HWR_UnlockCachedPatch(grpatch);
 }
 
 // -----------------+
@@ -453,7 +452,6 @@ static void md2_loadBlendTexture(md2_t *model)
 #endif
 	}
 	HWD.pfnSetTexture(grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary
-	HWR_UnlockCachedPatch(grpatch);
 
 	Z_Free(filename);
 }

From af3cf936830a14f789898ec773898e3c7620bf41 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 21:41:13 -0300
Subject: [PATCH 37/52] grafik designe is m passion

---
 src/hardware/hw_main.h |  1 +
 src/m_menu.c           | 27 ++++++++++++++++-----------
 2 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 96ff62cff..ce0e66b4d 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -85,6 +85,7 @@ extern consvar_t cv_grcoronasize;
 extern consvar_t cv_grfov;
 extern consvar_t cv_grmodels;
 extern consvar_t cv_grmodelinterpolation;
+extern consvar_t cv_grmodellighting;
 extern consvar_t cv_grfog;
 extern consvar_t cv_grfogcolor;
 extern consvar_t cv_grfogdensity;
diff --git a/src/m_menu.c b/src/m_menu.c
index 8ed85f501..f20a8e22e 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -1299,20 +1299,25 @@ static menuitem_t OP_ColorOptionsMenu[] =
 #ifdef HWRENDER
 static menuitem_t OP_OpenGLOptionsMenu[] =
 {
-	{IT_STRING|IT_CVAR,         NULL, "Models",              &cv_grmodels,             10},
-	{IT_STRING|IT_CVAR,         NULL, "Model interpolation", &cv_grmodelinterpolation, 20},
+	{IT_HEADER, NULL, "3D Models", NULL, 0},
+	{IT_STRING|IT_CVAR,         NULL, "Models",              &cv_grmodels,             12},
+	{IT_STRING|IT_CVAR,         NULL, "Model interpolation", &cv_grmodelinterpolation, 22},
+	{IT_STRING|IT_CVAR,         NULL, "Model lighting",      &cv_grmodellighting, 32},
 
-	{IT_STRING|IT_CVAR,         NULL, "Field of view",   &cv_grfov,            40},
-	{IT_STRING|IT_CVAR,         NULL, "Quality",         &cv_scr_depth,        50},
-	{IT_STRING|IT_CVAR,         NULL, "Texture Filter",  &cv_grfiltermode,     60},
-	{IT_STRING|IT_CVAR,         NULL, "Anisotropic",     &cv_granisotropicmode,70},
-#if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)))
-	{IT_STRING|IT_CVAR,         NULL, "Fullscreen",      &cv_fullscreen,       80},
-#endif
+	{IT_HEADER, NULL, "General", NULL, 51},
+	{IT_STRING|IT_CVAR,         NULL, "Field of view",   &cv_grfov,            62},
+	{IT_STRING|IT_CVAR,         NULL, "Quality",         &cv_scr_depth,        72},
+	{IT_STRING|IT_CVAR,         NULL, "Texture Filter",  &cv_grfiltermode,     82},
+	{IT_STRING|IT_CVAR,         NULL, "Anisotropic",     &cv_granisotropicmode,92},
+
+	{IT_HEADER, NULL, "Miscellaneous", NULL, 111},
+	{IT_SUBMENU|IT_STRING,      NULL, "Fog...",          &OP_OpenGLFogDef,          123},
 #ifdef ALAM_LIGHTING
-	{IT_SUBMENU|IT_STRING,      NULL, "Lighting...",     &OP_OpenGLLightingDef,     100},
+	{IT_SUBMENU|IT_STRING,      NULL, "Lighting...",     &OP_OpenGLLightingDef,     133},
+#endif
+#if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)))
+	{IT_STRING|IT_CVAR,         NULL, "Fullscreen",      &cv_fullscreen,            143},
 #endif
-	{IT_SUBMENU|IT_STRING,      NULL, "Fog...",          &OP_OpenGLFogDef,          110},
 };
 
 #ifdef ALAM_LIGHTING

From ff348fb60ab62edd90d5bbc4357732e183e37c61 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 21:43:19 -0300
Subject: [PATCH 38/52] Add missing prototype, ugh

---
 src/hardware/hw_main.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index ce0e66b4d..e46aa9801 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -57,6 +57,7 @@ UINT8 *HWR_GetScreenshot(void);
 boolean HWR_Screenshot(const char *pathname);
 
 void HWR_AddCommands(void);
+void HWR_AddSessionCommands(void);
 void HWR_CorrectSWTricks(void);
 void transform(float *cx, float *cy, float *cz);
 FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);

From 01399c70760f7b0ae7ecdb396ebd4ffb9fb41caf Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 21:52:59 -0300
Subject: [PATCH 39/52] Update hw_main.c

---
 src/hardware/hw_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 1e1935c44..51bc1cec0 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6570,7 +6570,7 @@ consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, N
 consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_grmodellighting_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
-consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};

From 08794559f06c929fc107c909a8a631cabe83fd41 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 22:26:28 -0300
Subject: [PATCH 40/52] Fix TC_ blending

---
 src/hardware/hw_data.h |  1 +
 src/hardware/hw_md2.c  | 32 ++++++++++++++++++++------------
 2 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h
index ef57426a4..f525e041f 100644
--- a/src/hardware/hw_data.h
+++ b/src/hardware/hw_data.h
@@ -48,6 +48,7 @@ struct GLMipmap_s
 
 	struct GLMipmap_s    *nextcolormap;
 	const UINT8          *colormap;
+	INT32                tcindex;
 
 	// opengl
 	struct GLMipmap_s *nextmipmap; // opengl : liste of all texture in opengl driver
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 77cdfa0d3..467f35ec4 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -649,7 +649,6 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 
 	if (grmip->width == 0)
 	{
-
 		grmip->width = gpatch->width;
 		grmip->height = gpatch->height;
 
@@ -679,10 +678,11 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 	{
 		if (skinnum == TC_BOSS)
 		{
-			// Pure black turns into white
-			if (image->s.red == 0 && image->s.green == 0 && image->s.blue == 0)
+			// Turn everything below a certain threshold white
+			if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue <= 82)
 			{
-				cur->s.red = cur->s.green = cur->s.blue = 255;
+				// Lactozilla: Invert the colors
+				cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue);
 			}
 			else
 			{
@@ -908,19 +908,19 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
 	// mostly copied from HWR_GetMappedPatch, hence the similarities and comment
 	GLMipmap_t *grmip, *newmip;
 
-	if (colormap == colormaps || colormap == NULL)
+	if ((colormap == colormaps || colormap == NULL) && (skinnum > TC_DEFAULT))
 	{
 		// Don't do any blending
 		HWD.pfnSetTexture(gpatch->mipmap);
 		return;
 	}
 
-	// search for the mimmap
+	// search for the mipmap
 	// skip the first (no colormap translated)
 	for (grmip = gpatch->mipmap; grmip->nextcolormap; )
 	{
 		grmip = grmip->nextcolormap;
-		if (grmip->colormap == colormap)
+		if (grmip->colormap == colormap || grmip->tcindex == skinnum)
 		{
 			if (grmip->downloaded && grmip->grInfo.data)
 			{
@@ -943,6 +943,7 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
 		I_Error("%s: Out of memory", "HWR_GetMappedPatch");
 	grmip->nextcolormap = newmip;
 	newmip->colormap = colormap;
+	newmip->tcindex = skinnum;
 
 	HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color);
 
@@ -1167,11 +1168,10 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 
 		if (gpatch && gpatch->mipmap->grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
 		{
-			if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE &&
-				md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format
+			if (md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format
 				&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
 			{
-				INT32 skinnum = TC_DEFAULT;
+				INT32 skinnum = INT32_MAX;
 				if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
 				{
 					if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized)
@@ -1181,7 +1181,7 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 					else
 						skinnum = TC_BOSS;
 				}
-				else if (spr->mobj->color)
+				else if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE)
 				{
 					if (spr->mobj->colorized)
 						skinnum = TC_RAINBOW;
@@ -1199,7 +1199,15 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 					else
 						skinnum = TC_DEFAULT;
 				}
-				HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
+
+				// Translation or skin number found
+				if (skinnum != INT32_MAX)
+					HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
+				else
+				{
+					// Sorry nothing
+					HWD.pfnSetTexture(gpatch->mipmap);
+				}
 			}
 			else
 			{

From ca83bafae8fba68a376b5640ab39fa583c709c97 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 22:32:19 -0300
Subject: [PATCH 41/52] Initialise the variable, obviously

---
 src/hardware/hw_md2.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 105321e8d..b329e4097 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -721,6 +721,8 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 				UINT8 ialpha = 255 - blendimage->s.alpha, balpha = blendimage->s.alpha;
 				RGBA_t icolor = *image, bcolor;
 
+				memset(&bcolor, 0x00, sizeof(RGBA_t));
+
 				if (blendimage->s.alpha)
 				{
 					bcolor.s.blue = 0;

From 228b29e23b5efb466845c37514d409decd8ddfb7 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 22:53:19 -0300
Subject: [PATCH 42/52] HWR_AllowModel

---
 src/hardware/hw_main.c | 10 ++++++++--
 src/hardware/hw_md2.c  | 27 ++++++++++++++++++++++-----
 src/hardware/hw_md2.h  |  2 +-
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 51bc1cec0..6ef48f222 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -5368,14 +5368,20 @@ static void HWR_DrawSprites(void)
 					if (!cv_grmodels.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_DrawModel(spr);
+					{
+						if (!HWR_DrawModel(spr))
+							HWR_DrawSprite(spr);
+					}
 				}
 				else
 				{
 					if (!cv_grmodels.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
 						HWR_DrawSprite(spr);
 					else
-						HWR_DrawModel(spr);
+					{
+						if (!HWR_DrawModel(spr))
+							HWR_DrawSprite(spr);
+					}
 				}
 		}
 	}
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index b329e4097..f857b11b8 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -985,6 +985,16 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
 #define NORMALFOG 0x00000000
 #define FADEFOG 0x19000000
 
+static boolean HWR_AllowModel(mobj_t *mobj)
+{
+	// Signpost overlay. Not needed.
+	if (mobj->state-states == S_PLAY_SIGN)
+		return false;
+
+	// Otherwise, render the model.
+	return true;
+}
+
 static boolean HWR_CanInterpolateModel(mobj_t *mobj, model_t *model)
 {
 	if (cv_grmodelinterpolation.value == 2) // Always interpolate
@@ -1060,7 +1070,7 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
 // HWR_DrawModel
 //
 
-void HWR_DrawModel(gr_vissprite_t *spr)
+boolean HWR_DrawModel(gr_vissprite_t *spr)
 {
 	FSurfaceInfo Surf;
 
@@ -1073,10 +1083,10 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 	UINT8 color[4];
 
 	if (!cv_grmodels.value)
-		return;
+		return false;
 
 	if (spr->precip)
-		return;
+		return false;
 
 	memset(&p, 0x00, sizeof(FTransform));
 
@@ -1166,7 +1176,7 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 		}
 
 		if (md2->error)
-			return; // we already failed loading this before :(
+			return false; // we already failed loading this before :(
 		if (!md2->model)
 		{
 			//CONS_Debug(DBG_RENDER, "Loading model... (%s)", sprnames[spr->mobj->sprite]);
@@ -1182,9 +1192,14 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 			{
 				//CONS_Debug(DBG_RENDER, " FAILED\n");
 				md2->error = true; // prevent endless fail
-				return;
+				return false;
 			}
 		}
+
+		// Lactozilla: Disallow certain models from rendering
+		if (!HWR_AllowModel(spr->mobj))
+			return false;
+
 		//HWD.pfnSetBlend(blend); // This seems to actually break translucency?
 		finalscale = md2->scale;
 		//Hurdler: arf, I don't like that implementation at all... too much crappy
@@ -1416,6 +1431,8 @@ void HWR_DrawModel(gr_vissprite_t *spr)
 
 		HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, color);
 	}
+
+	return true;
 }
 
 #endif //HWRENDER
diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h
index a5f5fc117..6f5985a44 100644
--- a/src/hardware/hw_md2.h
+++ b/src/hardware/hw_md2.h
@@ -45,8 +45,8 @@ extern md2_t md2_models[NUMSPRITES];
 extern md2_t md2_playermodels[MAXSKINS];
 
 void HWR_InitModels(void);
-void HWR_DrawModel(gr_vissprite_t *spr);
 void HWR_AddPlayerModel(INT32 skin);
 void HWR_AddSpriteModel(size_t spritenum);
+boolean HWR_DrawModel(gr_vissprite_t *spr);
 
 #endif // _HW_MD2_H_

From 4e814cd4248889b39407b957ad28f9b43f6cd5a4 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 23:18:39 -0300
Subject: [PATCH 43/52] FINALLY, COLORCUBIUM

---
 src/hardware/hw_md2.c | 12 +++++++
 src/v_video.c         | 74 +++++++++++++++++++++++--------------------
 src/v_video.h         |  2 ++
 3 files changed, 54 insertions(+), 34 deletions(-)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index f857b11b8..13ba007ee 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -373,6 +373,9 @@ static void md2_loadTexture(md2_t *model)
 	if (!grpatch->mipmap->downloaded && !grpatch->mipmap->grInfo.data)
 	{
 		int w = 0, h = 0;
+		UINT32 size;
+		RGBA_t *image;
+
 #ifdef HAVE_PNG
 		grpatch->mipmap->grInfo.format = PNG_Load(filename, &w, &h, grpatch);
 		if (grpatch->mipmap->grInfo.format == 0)
@@ -389,6 +392,15 @@ static void md2_loadTexture(md2_t *model)
 		grpatch->mipmap->width = (UINT16)w;
 		grpatch->mipmap->height = (UINT16)h;
 
+		// Lactozilla: Apply colour cube
+		image = grpatch->mipmap->grInfo.data;
+		size = w*h;
+		while (size--)
+		{
+			V_CubeApply(&image->s.red, &image->s.green, &image->s.blue);
+			image++;
+		}
+
 #ifdef GLIDE_API_COMPATIBILITY
 		// not correct!
 		grpatch->mipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_256;
diff --git a/src/v_video.c b/src/v_video.c
index 1c5cbbc0a..ea1d1169e 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -95,6 +95,7 @@ Please check it out if you're trying to maintain this.
 toast 18/04/17
 */
 float Cubepal[2][2][2][3];
+boolean Cubeapply = false;
 
 // returns whether to apply cube, selectively avoiding expensive operations
 static boolean InitCube(void)
@@ -310,7 +311,7 @@ const UINT8 correctiontable[256] =
 // keep a copy of the palette so that we can get the RGB value for a color index at any time.
 static void LoadPalette(const char *lumpname)
 {
-	boolean cube = InitCube();
+	Cubeapply = InitCube();
 	lumpnum_t lumpnum = W_GetNumForName(lumpname);
 	size_t i, palsize = W_LumpLength(lumpnum)/3;
 	UINT8 *pal;
@@ -336,43 +337,48 @@ static void LoadPalette(const char *lumpname)
 		pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF;
 
 		// lerp of colour cubing! if you want, make it smoother yourself
-		if (cube)
-		{
-			float working[4][3];
-			float linear;
-			UINT8 q;
+		V_CubeApply(&pLocalPalette[i].s.red, &pLocalPalette[i].s.green, &pLocalPalette[i].s.blue);
+	}
+}
 
-			linear = (pLocalPalette[i].s.red/255.0);
+void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue)
+{
+	float working[4][3];
+	float linear;
+	UINT8 q;
+
+	if (!Cubeapply)
+		return;
+
+	linear = (*red/255.0);
 #define dolerp(e1, e2) ((1 - linear)*e1 + linear*e2)
-			for (q = 0; q < 3; q++)
-			{
-				working[0][q] = dolerp(Cubepal[0][0][0][q], Cubepal[1][0][0][q]);
-				working[1][q] = dolerp(Cubepal[0][1][0][q], Cubepal[1][1][0][q]);
-				working[2][q] = dolerp(Cubepal[0][0][1][q], Cubepal[1][0][1][q]);
-				working[3][q] = dolerp(Cubepal[0][1][1][q], Cubepal[1][1][1][q]);
-			}
-			linear = (pLocalPalette[i].s.green/255.0);
-			for (q = 0; q < 3; q++)
-			{
-				working[0][q] = dolerp(working[0][q], working[1][q]);
-				working[1][q] = dolerp(working[2][q], working[3][q]);
-			}
-			linear = (pLocalPalette[i].s.blue/255.0);
-			for (q = 0; q < 3; q++)
-			{
-				working[0][q] = 255*dolerp(working[0][q], working[1][q]);
-				if (working[0][q] > 255.0)
-					working[0][q] = 255.0;
-				else if (working[0][q]  < 0.0)
-					working[0][q] = 0.0;
-			}
+	for (q = 0; q < 3; q++)
+	{
+		working[0][q] = dolerp(Cubepal[0][0][0][q], Cubepal[1][0][0][q]);
+		working[1][q] = dolerp(Cubepal[0][1][0][q], Cubepal[1][1][0][q]);
+		working[2][q] = dolerp(Cubepal[0][0][1][q], Cubepal[1][0][1][q]);
+		working[3][q] = dolerp(Cubepal[0][1][1][q], Cubepal[1][1][1][q]);
+	}
+	linear = (*green/255.0);
+	for (q = 0; q < 3; q++)
+	{
+		working[0][q] = dolerp(working[0][q], working[1][q]);
+		working[1][q] = dolerp(working[2][q], working[3][q]);
+	}
+	linear = (*blue/255.0);
+	for (q = 0; q < 3; q++)
+	{
+		working[0][q] = 255*dolerp(working[0][q], working[1][q]);
+		if (working[0][q] > 255.0)
+			working[0][q] = 255.0;
+		else if (working[0][q]  < 0.0)
+			working[0][q] = 0.0;
+	}
 #undef dolerp
 
-			pLocalPalette[i].s.red = (UINT8)(working[0][0]);
-			pLocalPalette[i].s.green = (UINT8)(working[0][1]);
-			pLocalPalette[i].s.blue = (UINT8)(working[0][2]);
-		}
-	}
+	*red = (UINT8)(working[0][0]);
+	*green = (UINT8)(working[0][1]);
+	*blue = (UINT8)(working[0][2]);
 }
 
 const char *R_GetPalname(UINT16 num)
diff --git a/src/v_video.h b/src/v_video.h
index 81f410f40..2434fec81 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -48,6 +48,8 @@ const char *GetPalette(void);
 extern RGBA_t *pLocalPalette;
 extern RGBA_t *pMasterPalette;
 
+void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
+
 // Retrieve the ARGB value from a palette color index
 #define V_GetColor(color) (pLocalPalette[color&0xFF])
 

From b0ffe7ed700cf82085729b2bfc988c83917619eb Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 23:30:09 -0300
Subject: [PATCH 44/52] Update v_video.c

---
 src/v_video.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/v_video.c b/src/v_video.c
index ea1d1169e..dad8e8513 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -337,7 +337,8 @@ static void LoadPalette(const char *lumpname)
 		pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF;
 
 		// lerp of colour cubing! if you want, make it smoother yourself
-		V_CubeApply(&pLocalPalette[i].s.red, &pLocalPalette[i].s.green, &pLocalPalette[i].s.blue);
+		if (Cubeapply)
+			V_CubeApply(&pLocalPalette[i].s.red, &pLocalPalette[i].s.green, &pLocalPalette[i].s.blue);
 	}
 }
 

From fa58c1fb26e11f4ee2fd3d363ede6160628a2a4d Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Fri, 13 Dec 2019 12:26:47 -0300
Subject: [PATCH 45/52] stuff

---
 src/r_draw.h   |  3 --
 src/r_draw8.c  |  4 +--
 src/r_plane.c  | 49 ++++++++++++++++---------------
 src/r_segs.c   | 50 ++++++++++++++++----------------
 src/r_splats.c |  2 +-
 src/r_things.c | 30 +++++++------------
 src/screen.c   | 78 +++++++++++++++++++++++++++-----------------------
 src/screen.h   | 54 +++++++++++++++++++++++++---------
 8 files changed, 146 insertions(+), 124 deletions(-)

diff --git a/src/r_draw.h b/src/r_draw.h
index d033f221d..d7a098f32 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -138,19 +138,16 @@ void R_DrawViewBorder(void);
 // -----------------
 
 void R_DrawColumn_8(void);
-#define R_DrawWallColumn_8	R_DrawColumn_8
 void R_DrawShadeColumn_8(void);
 void R_DrawTranslucentColumn_8(void);
 
 #ifdef USEASM
 void ASMCALL R_DrawColumn_8_ASM(void);
-#define R_DrawWallColumn_8_ASM	R_DrawColumn_8_ASM
 void ASMCALL R_DrawShadeColumn_8_ASM(void);
 void ASMCALL R_DrawTranslucentColumn_8_ASM(void);
 void ASMCALL R_Draw2sMultiPatchColumn_8_ASM(void);
 
 void ASMCALL R_DrawColumn_8_MMX(void);
-#define R_DrawWallColumn_8_MMX	R_DrawColumn_8_MMX
 
 void ASMCALL R_Draw2sMultiPatchColumn_8_MMX(void);
 void ASMCALL R_DrawSpan_8_MMX(void);
diff --git a/src/r_draw8.c b/src/r_draw8.c
index 11cdd5dca..db9bc4c3c 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -1880,7 +1880,7 @@ void R_DrawColumnShadowed_8(void)
 
 		if (dc_yh > realyh)
 			dc_yh = realyh;
-		basecolfunc();		// R_DrawColumn_8 for the appropriate architecture
+		(colfuncs[BASEDRAWFUNC])();		// R_DrawColumn_8 for the appropriate architecture
 		if (solid)
 			dc_yl = bheight;
 		else
@@ -1890,5 +1890,5 @@ void R_DrawColumnShadowed_8(void)
 	}
 	dc_yh = realyh;
 	if (dc_yl <= realyh)
-		walldrawerfunc();		// R_DrawWallColumn_8 for the appropriate architecture
+		(colfuncs[BASEDRAWFUNC])();		// R_DrawWallColumn_8 for the appropriate architecture
 }
diff --git a/src/r_plane.c b/src/r_plane.c
index f96e7950e..8c644700e 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -587,8 +587,7 @@ void R_DrawPlanes(void)
 
 	// Note: are these two lines really needed?
 	// R_DrawSinglePlane and R_DrawSkyPlane do span/column drawer resets themselves anyway
-	spanfunc = basespanfunc;
-	wallcolfunc = walldrawerfunc;
+	spanfunc = spanfuncs[BASEDRAWFUNC];
 
 	for (i = 0; i < MAXVISPLANES; i++, pl++)
 	{
@@ -622,7 +621,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
 
 	// Reset column drawer function (note: couldn't we just call walldrawerfunc directly?)
 	// (that is, unless we'll need to switch drawers in future for some reason)
-	wallcolfunc = walldrawerfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 
 	// use correct aspect ratio scale
 	dc_iscale = skyscale;
@@ -648,7 +647,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
 			dc_source =
 				R_GetColumn(texturetranslation[skytexture],
 					-angle); // get negative of angle for each column to display sky correct way round! --Monster Iestyn 27/01/18
-			wallcolfunc();
+			colfunc();
 		}
 	}
 }
@@ -856,11 +855,11 @@ void R_DrawSinglePlane(visplane_t *pl)
 #ifndef NOWATER
 	itswater = false;
 #endif
-	spanfunc = basespanfunc;
+	spanfunc = spanfuncs[BASEDRAWFUNC];
 
 #ifdef POLYOBJECTS_PLANES
 	if (pl->polyobj && pl->polyobj->translucency != 0) {
-		spanfunc = R_DrawTranslucentSpan_8;
+		spanfunc = spanfuncs[SPANDRAWFUNC_TRANS];
 
 		// Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red)
 		if (pl->polyobj->translucency >= 10)
@@ -868,10 +867,10 @@ void R_DrawSinglePlane(visplane_t *pl)
 		else if (pl->polyobj->translucency > 0)
 			ds_transmap = transtables + ((pl->polyobj->translucency-1)<<FF_TRANSSHIFT);
 		else // Opaque, but allow transparent flat pixels
-			spanfunc = splatfunc;
+			spanfunc = spanfuncs[SPANDRAWFUNC_SPLAT];
 
 #ifdef SHITPLANESPARENCY
-		if ((spanfunc == splatfunc) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
+		if ((spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT]) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
 #else
 		if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2))
 #endif
@@ -902,7 +901,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 		if (pl->ffloor->flags & FF_TRANSLUCENT)
 		{
-			spanfunc = R_DrawTranslucentSpan_8;
+			spanfunc = spanfuncs[SPANDRAWFUNC_TRANS];
 
 			// Hacked up support for alpha value in software mode Tails 09-24-2002
 			if (pl->ffloor->alpha < 12)
@@ -926,10 +925,10 @@ void R_DrawSinglePlane(visplane_t *pl)
 			else if (pl->ffloor->alpha < 243)
 				ds_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT);
 			else // Opaque, but allow transparent flat pixels
-				spanfunc = splatfunc;
+				spanfunc = spanfuncs[SPANDRAWFUNC_SPLAT];
 
 #ifdef SHITPLANESPARENCY
-			if ((spanfunc == splatfunc) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
+			if ((spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT]) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
 #else
 			if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2))
 #endif
@@ -939,7 +938,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 		}
 		else if (pl->ffloor->flags & FF_FOG)
 		{
-			spanfunc = R_DrawFogSpan_8;
+			spanfunc = spanfuncs[SPANDRAWFUNC_FOG];
 			light = (pl->lightlevel >> LIGHTSEGSHIFT);
 		}
 		else light = (pl->lightlevel >> LIGHTSEGSHIFT);
@@ -954,9 +953,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 			INT32 top, bottom;
 
 			itswater = true;
-			if (spanfunc == R_DrawTranslucentSpan_8)
+			if (spanfunc == spanfuncs[SPANDRAWFUNC_TRANS])
 			{
-				spanfunc = R_DrawTranslucentWaterSpan_8;
+				spanfunc = spanfuncs[SPANDRAWFUNC_WATER];
 
 				// Copy the current scene, ugh
 				top = pl->high-8;
@@ -1007,8 +1006,8 @@ void R_DrawSinglePlane(visplane_t *pl)
 			R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum));
 			// Raw flats always have dimensions that are powers-of-two numbers.
 			ds_powersoftwo = true;
-			if (spanfunc == basespanfunc)
-				spanfunc = mmxspanfunc;
+			if (spanfunc == spanfuncs[BASEDRAWFUNC])
+				spanfunc = spanfuncs[SPANDRAWFUNC_MMX];
 			break;
 		default:
 			switch (type)
@@ -1033,8 +1032,8 @@ void R_DrawSinglePlane(visplane_t *pl)
 			if (R_CheckPowersOfTwo())
 			{
 				R_CheckFlatLength(ds_flatwidth * ds_flatheight);
-				if (spanfunc == basespanfunc)
-					spanfunc = mmxspanfunc;
+				if (spanfunc == spanfuncs[BASEDRAWFUNC])
+					spanfunc = spanfuncs[SPANDRAWFUNC_MMX];
 			}
 	}
 
@@ -1188,12 +1187,12 @@ void R_DrawSinglePlane(visplane_t *pl)
 		}
 #undef SFMULT
 
-		if (spanfunc == R_DrawTranslucentSpan_8)
-			spanfunc = R_DrawTiltedTranslucentSpan_8;
-		else if (spanfunc == splatfunc)
-			spanfunc = R_DrawTiltedSplat_8;
+		if (spanfunc == spanfuncs[SPANDRAWFUNC_TRANS])
+			spanfunc = spanfuncs[SPANDRAWFUNC_TILTEDTRANS];
+		else if (spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT])
+			spanfunc = spanfuncs[SPANDRAWFUNC_TILTEDSPLAT];
 		else
-			spanfunc = R_DrawTiltedSpan_8;
+			spanfunc = spanfuncs[SPANDRAWFUNC_TILTED];
 
 		planezlight = scalelight[light];
 	} else
@@ -1240,11 +1239,11 @@ a 'smoothing' of the texture while
 using the palette colors.
 */
 #ifdef QUINCUNX
-	if (spanfunc == R_DrawSpan_8)
+	if (spanfunc == spanfuncs[BASEDRAWFUNC])
 	{
 		INT32 i;
 		ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT);
-		spanfunc = R_DrawTranslucentSpan_8;
+		spanfunc = spanfuncs[SPANDRAWFUNC_TRANS];
 		for (i=0; i<4; i++)
 		{
 			xoffs = pl->xoffs;
diff --git a/src/r_segs.c b/src/r_segs.c
index d22a706ac..29120ebb8 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -177,20 +177,20 @@ static void R_DrawWallSplats(void)
 		switch (splat->flags & SPLATDRAWMODE_MASK)
 		{
 			case SPLATDRAWMODE_OPAQUE:
-				colfunc = basecolfunc;
+				colfunc = colfuncs[BASEDRAWFUNC];
 				break;
 			case SPLATDRAWMODE_TRANS:
 				if (!cv_translucency.value)
-					colfunc = basecolfunc;
+					colfunc = colfuncs[BASEDRAWFUNC];
 				else
 				{
 					dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
-					colfunc = fuzzcolfunc;
+					colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 				}
 
 				break;
 			case SPLATDRAWMODE_SHADE:
-				colfunc = shadecolfunc;
+				colfunc = colfuncs[COLDRAWFUNC_SHADE];
 				break;
 		}
 
@@ -226,7 +226,7 @@ static void R_DrawWallSplats(void)
 		}
 	} // next splat
 
-	colfunc = basecolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 }
 
 #endif //WALLSPLATS
@@ -270,10 +270,10 @@ static void R_Render2sidedMultiPatchColumn(column_t *column)
 	{
 		dc_source = (UINT8 *)column + 3;
 
-		if (colfunc == wallcolfunc)
-			twosmultipatchfunc();
-		else if (colfunc == fuzzcolfunc)
-			twosmultipatchtransfunc();
+		if (colfunc == colfuncs[BASEDRAWFUNC])
+			(colfuncs[COLDRAWFUNC_TWOSMULTIPATCH])();
+		else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
+			(colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS])();
 		else
 			colfunc();
 	}
@@ -327,15 +327,15 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 		case 907:
 		case 908:
 			dc_transmap = transtables + ((ldef->special-900)<<FF_TRANSSHIFT);
-			colfunc = fuzzcolfunc;
+			colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 			break;
 		case 909:
-			colfunc = R_DrawFogColumn_8;
+			colfunc = colfuncs[COLDRAWFUNC_FOG];
 			windowtop = frontsector->ceilingheight;
 			windowbottom = frontsector->floorheight;
 			break;
 		default:
-			colfunc = wallcolfunc;
+			colfunc = colfuncs[BASEDRAWFUNC];
 			break;
 	}
 
@@ -345,7 +345,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 			return;
 
 		dc_transmap = transtables + ((curline->polyseg->translucency-1)<<FF_TRANSSHIFT);
-		colfunc = fuzzcolfunc;
+		colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 	}
 
 #ifdef ESLOPE
@@ -419,7 +419,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 
 			if (rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->fog))
 				lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
-			else if (colfunc == fuzzcolfunc)
+			else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
 				lightnum = LIGHTLEVELS - 1;
 			else
 				lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
@@ -436,7 +436,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	}
 	else
 	{
-		if (colfunc == fuzzcolfunc)
+		if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
 		{
 			if (frontsector->extra_colormap && frontsector->extra_colormap->fog)
 				lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
@@ -446,7 +446,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 		else
 			lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
 
-		if (colfunc == R_DrawFogColumn_8
+		if (colfunc == colfuncs[COLDRAWFUNC_FOG]
 			|| (frontsector->extra_colormap && frontsector->extra_colormap->fog))
 			;
 		else if (curline->v1->y == curline->v2->y)
@@ -718,7 +718,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 			spryscale += rw_scalestep;
 		}
 	}
-	colfunc = wallcolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 }
 
 // Loop through R_DrawMaskedColumn calls
@@ -789,7 +789,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
 	texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
 
-	colfunc = wallcolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 
 	if (pfloor->master->flags & ML_TFERLINE)
 	{
@@ -827,10 +827,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			fuzzy = false; // Opaque
 
 		if (fuzzy)
-			colfunc = fuzzcolfunc;
+			colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 	}
 	else if (pfloor->flags & FF_FOG)
-		colfunc = R_DrawFogColumn_8;
+		colfunc = colfuncs[COLDRAWFUNC_FOG];
 
 #ifdef ESLOPE
 	range = max(ds->x2-ds->x1, 1);
@@ -965,7 +965,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
 		else if (pfloor->flags & FF_FOG)
 			lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
-		else if (colfunc == fuzzcolfunc)
+		else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
 			lightnum = LIGHTLEVELS-1;
 		else
 			lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)
@@ -1297,7 +1297,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			spryscale += rw_scalestep;
 		}
 	}
-	colfunc = wallcolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 
 #undef CLAMPMAX
 #undef CLAMPMIN
@@ -1530,7 +1530,7 @@ static void R_RenderSegLoop (void)
 				else
 					dc_lightlist[i].rcolormap = xwalllights[pindex];
 
-				colfunc = R_DrawColumnShadowed_8;
+				colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
 			}
 		}
 
@@ -1736,6 +1736,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	memset(&segright, 0x00, sizeof(segright));
 #endif
 
+	colfunc = colfuncs[BASEDRAWFUNC];
+
 	if (ds_p == drawsegs+maxdrawsegs)
 	{
 		size_t curpos = curdrawsegs - drawsegs;
@@ -3186,7 +3188,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	else
 #endif
 		R_RenderSegLoop();
-	colfunc = wallcolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 
 	if (portalline) // if curline is a portal, set portalrender for drawseg
 		ds_p->portalpass = portalrender+1;
diff --git a/src/r_splats.c b/src/r_splats.c
index 1b4b939a5..414e93eb6 100644
--- a/src/r_splats.c
+++ b/src/r_splats.c
@@ -512,7 +512,7 @@ static void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, UINT8 *pTe
 			ds_x1 = x1;
 			ds_x2 = x2;
 			ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT);
-			splatfunc();
+			(spanfuncs[SPANDRAWFUNC_SPLAT])();
 		}
 
 		// reset for next calls to edge rasterizer
diff --git a/src/r_things.c b/src/r_things.c
index 3ba104ccd..aa2a73515 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -653,11 +653,7 @@ void R_DrawMaskedColumn(column_t *column)
 			// quick fix... something more proper should be done!!!
 			if (ylookup[dc_yl])
 				colfunc();
-			else if (colfunc == R_DrawColumn_8
-#ifdef USEASM
-			|| colfunc == R_DrawColumn_8_ASM || colfunc == R_DrawColumn_8_MMX
-#endif
-			)
+			else if (colfunc == colfuncs[COLDRAWFUNC_BASE])
 			{
 				static INT32 first = 1;
 				if (first)
@@ -724,11 +720,7 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
 			// Still drawn by R_DrawColumn.
 			if (ylookup[dc_yl])
 				colfunc();
-			else if (colfunc == R_DrawColumn_8
-#ifdef USEASM
-			|| colfunc == R_DrawColumn_8_ASM || colfunc == R_DrawColumn_8_MMX
-#endif
-			)
+			else if (colfunc == colfuncs[COLDRAWFUNC_BASE])
 			{
 				static INT32 first = 1;
 				if (first)
@@ -776,12 +768,12 @@ static void R_DrawVisSprite(vissprite_t *vis)
 		if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto
 	}
 
-	colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
+	colfunc = colfuncs[BASEDRAWFUNC]; // hack: this isn't resetting properly somewhere.
 	dc_colormap = vis->colormap;
 	if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
 	{
 		// translate certain pixels to white
-		colfunc = transcolfunc;
+		colfunc = colfuncs[COLDRAWFUNC_TRANS];
 		if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
 			dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
 		else if (vis->mobj->type == MT_METALSONIC_BATTLE)
@@ -791,7 +783,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
 	}
 	else if (vis->mobj->color && vis->transmap) // Color mapping
 	{
-		colfunc = transtransfunc;
+		colfunc = colfuncs[COLDRAWFUNC_TRANSTRANS];
 		dc_transmap = vis->transmap;
 		if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
 			dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
@@ -815,13 +807,13 @@ static void R_DrawVisSprite(vissprite_t *vis)
 	}
 	else if (vis->transmap)
 	{
-		colfunc = fuzzcolfunc;
+		colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 		dc_transmap = vis->transmap;    //Fab : 29-04-98: translucency table
 	}
 	else if (vis->mobj->color)
 	{
 		// translate green skin to another color
-		colfunc = transcolfunc;
+		colfunc = colfuncs[COLDRAWFUNC_TRANS];
 
 		// New colormap stuff for skins Tails 06-07-2002
 		if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
@@ -846,7 +838,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
 	}
 	else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome.
 	{
-		colfunc = transcolfunc;
+		colfunc = colfuncs[COLDRAWFUNC_TRANS];
 		dc_translation = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE);
 	}
 
@@ -926,7 +918,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
 		spryscale += vis->scalestep;
 	}
 
-	colfunc = basecolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 	dc_hires = 0;
 
 	vis->x1 = x1;
@@ -956,7 +948,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
 
 	if (vis->transmap)
 	{
-		colfunc = fuzzcolfunc;
+		colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 		dc_transmap = vis->transmap;    //Fab : 29-04-98: translucency table
 	}
 
@@ -992,7 +984,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
 		R_DrawMaskedColumn(column);
 	}
 
-	colfunc = basecolfunc;
+	colfunc = colfuncs[BASEDRAWFUNC];
 }
 
 //
diff --git a/src/screen.c b/src/screen.c
index 3c4b2bc62..5c88d8471 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -41,20 +41,11 @@
 // --------------------------------------------
 // assembly or c drawer routines for 8bpp/16bpp
 // --------------------------------------------
-void (*wallcolfunc)(void); // new wall column drawer to draw posts >128 high
-void (*colfunc)(void); // standard column, up to 128 high posts
+void (*colfunc)(void);
+void (*colfuncs[COLDRAWFUNC_MAX])(void);
 
-void (*basecolfunc)(void);
-void (*fuzzcolfunc)(void); // standard fuzzy effect column drawer
-void (*transcolfunc)(void); // translation column drawer
-void (*shadecolfunc)(void); // smokie test..
-void (*spanfunc)(void); // span drawer, use a 64x64 tile
-void (*mmxspanfunc)(void); // span drawer in MMX assembly
-void (*splatfunc)(void); // span drawer w/ transparency
-void (*basespanfunc)(void); // default span func for color mode
-void (*transtransfunc)(void); // translucent translated column drawer
-void (*twosmultipatchfunc)(void); // for cols with transparent pixels
-void (*twosmultipatchtransfunc)(void); // for cols with transparent pixels AND translucency
+void (*spanfunc)(void);
+void (*spanfuncs[SPANDRAWFUNC_MAX])(void);
 
 // ------------------
 // global video state
@@ -113,36 +104,53 @@ void SCR_SetMode(void)
 	//
 	if (true)//vid.bpp == 1) //Always run in 8bpp. todo: remove all 16bpp code?
 	{
-		spanfunc = basespanfunc = mmxspanfunc = R_DrawSpan_8;
-		splatfunc = R_DrawSplat_8;
-		transcolfunc = R_DrawTranslatedColumn_8;
-		transtransfunc = R_DrawTranslatedTranslucentColumn_8;
+		colfuncs[BASEDRAWFUNC] = R_DrawColumn_8;
+		spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8;
+
+		colfunc = colfuncs[BASEDRAWFUNC];
+		spanfunc = spanfuncs[BASEDRAWFUNC];
+
+		colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8;
+		colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn_8;
+		colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8;
+		colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed_8;
+		colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn_8;
+		colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8;
+		colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn_8;
+		colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn_8;
+
+		spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_8;
+		spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat_8;
+		spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_8;
+		spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
+		spanfuncs[SPANDRAWFUNC_MMX] = spanfuncs[BASEDRAWFUNC];
+#ifndef NOWATER
+		spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8;
+#endif
+#ifdef ESLOPE
+		spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8;
+		spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8;
+		spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8;
+#endif
+
 
-		colfunc = basecolfunc = R_DrawColumn_8;
-		shadecolfunc = R_DrawShadeColumn_8;
-		fuzzcolfunc = R_DrawTranslucentColumn_8;
-		walldrawerfunc = R_DrawWallColumn_8;
-		twosmultipatchfunc = R_Draw2sMultiPatchColumn_8;
-		twosmultipatchtransfunc = R_Draw2sMultiPatchTranslucentColumn_8;
 #ifdef RUSEASM
 		if (R_ASM)
 		{
 			if (R_MMX)
 			{
-				colfunc = basecolfunc = R_DrawColumn_8_MMX;
-				//shadecolfunc = R_DrawShadeColumn_8_ASM;
-				//fuzzcolfunc = R_DrawTranslucentColumn_8_ASM;
-				walldrawerfunc = R_DrawWallColumn_8_MMX;
-				twosmultipatchfunc = R_Draw2sMultiPatchColumn_8_MMX;
-				mmxspanfunc = R_DrawSpan_8_MMX;
+				colfuncs[BASEDRAWFUNC] = R_DrawColumn_8_MMX;
+				//colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
+				//colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
+				colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_MMX;
+				spanfuncs[SPANDRAWFUNC_MMX] = R_DrawSpan_8_MMX;
 			}
 			else
 			{
-				colfunc = basecolfunc = R_DrawColumn_8_ASM;
-				//shadecolfunc = R_DrawShadeColumn_8_ASM;
-				//fuzzcolfunc = R_DrawTranslucentColumn_8_ASM;
-				walldrawerfunc = R_DrawWallColumn_8_ASM;
-				twosmultipatchfunc = R_Draw2sMultiPatchColumn_8_ASM;
+				colfuncs[BASEDRAWFUNC] = R_DrawColumn_8_ASM;
+				//colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
+				//colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
+				colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_ASM;
 			}
 		}
 #endif
@@ -166,8 +174,6 @@ void SCR_SetMode(void)
 		CONS_Alert(CONS_WARNING, M_GetText("Resolution is not aspect-correct!\nUse a multiple of %dx%d\n"), BASEVIDWIDTH, BASEVIDHEIGHT);
 */
 
-	wallcolfunc = walldrawerfunc;
-
 	// set the apprpriate drawer for the sky (tall or INT16)
 	setmodeneeded = 0;
 }
diff --git a/src/screen.h b/src/screen.h
index 4a41e5879..ffed931fa 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -110,19 +110,48 @@ extern vmode_t specialmodes[NUMSPECIALMODES];
 // color mode dependent drawer function pointers
 // ---------------------------------------------
 
-extern void (*wallcolfunc)(void);
+#define BASEDRAWFUNC 0
+
+enum
+{
+	COLDRAWFUNC_BASE = BASEDRAWFUNC,
+	COLDRAWFUNC_FUZZY,
+	COLDRAWFUNC_TRANS,
+	COLDRAWFUNC_SHADE,
+	COLDRAWFUNC_SHADOWED,
+	COLDRAWFUNC_TRANSTRANS,
+	COLDRAWFUNC_TWOSMULTIPATCH,
+	COLDRAWFUNC_TWOSMULTIPATCHTRANS,
+	COLDRAWFUNC_FOG,
+
+	COLDRAWFUNC_MAX
+};
+
 extern void (*colfunc)(void);
-extern void (*basecolfunc)(void);
-extern void (*fuzzcolfunc)(void);
-extern void (*transcolfunc)(void);
-extern void (*shadecolfunc)(void);
+extern void (*colfuncs[COLDRAWFUNC_MAX])(void);
+
+enum
+{
+	SPANDRAWFUNC_BASE = BASEDRAWFUNC,
+	SPANDRAWFUNC_MMX,
+	SPANDRAWFUNC_TRANS,
+	SPANDRAWFUNC_SPLAT,
+	SPANDRAWFUNC_TRANSSPLAT,
+	SPANDRAWFUNC_FOG,
+#ifndef NOWATER
+	SPANDRAWFUNC_WATER,
+#endif
+#ifdef ESLOPE
+	SPANDRAWFUNC_TILTED,
+	SPANDRAWFUNC_TILTEDTRANS,
+	SPANDRAWFUNC_TILTEDSPLAT,
+#endif
+
+	SPANDRAWFUNC_MAX
+};
+
 extern void (*spanfunc)(void);
-extern void (*basespanfunc)(void);
-extern void (*mmxspanfunc)(void);
-extern void (*splatfunc)(void);
-extern void (*transtransfunc)(void);
-extern void (*twosmultipatchfunc)(void);
-extern void (*twosmultipatchtransfunc)(void);
+extern void (*spanfuncs[SPANDRAWFUNC_MAX])(void);
 
 // -----
 // CPUID
@@ -148,9 +177,6 @@ extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_fu
 // wait for page flipping to end or not
 extern consvar_t cv_vidwait;
 
-// quick fix for tall/short skies, depending on bytesperpixel
-extern void (*walldrawerfunc)(void);
-
 // Change video mode, only at the start of a refresh.
 void SCR_SetMode(void);
 // Recalc screen size dependent stuff

From 672027996952ff7f7b26ddc01fbf69a521e5a04e Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Fri, 13 Dec 2019 13:11:56 -0300
Subject: [PATCH 46/52] Separate non-powers-of-two draw routines into its own
 file

---
 src/r_draw.c                           |   1 +
 src/r_draw.h                           |  63 +-
 src/r_draw8.c                          | 874 ++++++++-----------------
 src/r_draw8_npo2.c                     | 845 ++++++++++++++++++++++++
 src/r_plane.c                          |  47 +-
 src/screen.c                           |  16 +
 src/screen.h                           |   1 +
 src/sdl/Srb2SDL-vc10.vcxproj           |   3 +
 src/sdl/Srb2SDL-vc10.vcxproj.filters   |   3 +
 src/win32/Srb2win-vc10.vcxproj         |   3 +
 src/win32/Srb2win-vc10.vcxproj.filters |   3 +
 11 files changed, 1224 insertions(+), 635 deletions(-)
 create mode 100644 src/r_draw8_npo2.c

diff --git a/src/r_draw.c b/src/r_draw.c
index db64805a4..5c91f87e8 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -960,6 +960,7 @@ void R_DrawViewBorder(void)
 // ==========================================================================
 
 #include "r_draw8.c"
+#include "r_draw8_npo2.c"
 
 // ==========================================================================
 //                   INCLUDE 16bpp DRAWING CODE HERE
diff --git a/src/r_draw.h b/src/r_draw.h
index d7a098f32..95ab80ed2 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -140,6 +140,44 @@ void R_DrawViewBorder(void);
 void R_DrawColumn_8(void);
 void R_DrawShadeColumn_8(void);
 void R_DrawTranslucentColumn_8(void);
+void R_DrawTranslatedColumn_8(void);
+void R_DrawTranslatedTranslucentColumn_8(void);
+void R_Draw2sMultiPatchColumn_8(void);
+void R_Draw2sMultiPatchTranslucentColumn_8(void);
+void R_DrawFogColumn_8(void);
+void R_DrawColumnShadowed_8(void);
+
+void R_DrawSpan_8(void);
+void R_DrawSplat_8(void);
+void R_DrawTranslucentSpan_8(void);
+void R_DrawTranslucentSplat_8(void);
+#ifdef ESLOPE
+void R_DrawTiltedSpan_8(void);
+void R_DrawTiltedTranslucentSpan_8(void);
+void R_DrawTiltedSplat_8(void);
+void R_CalcTiltedLighting(fixed_t start, fixed_t end);
+extern INT32 tiltlighting[MAXVIDWIDTH];
+#endif
+#ifndef NOWATER
+void R_DrawTranslucentWaterSpan_8(void);
+extern INT32 ds_bgofs;
+extern INT32 ds_waterofs;
+#endif
+void R_DrawFogSpan_8(void);
+
+// Lactozilla: Non-powers-of-two
+void R_DrawSpan_NPO2_8(void);
+void R_DrawTranslucentSpan_NPO2_8(void);
+void R_DrawSplat_NPO2_8(void);
+void R_DrawTranslucentSplat_NPO2_8(void);
+#ifdef ESLOPE
+void R_DrawTiltedSpan_NPO2_8(void);
+void R_DrawTiltedTranslucentSpan_NPO2_8(void);
+void R_DrawTiltedSplat_NPO2_8(void);
+#endif
+#ifndef NOWATER
+void R_DrawTranslucentWaterSpan_NPO2_8(void);
+#endif
 
 #ifdef USEASM
 void ASMCALL R_DrawColumn_8_ASM(void);
@@ -153,31 +191,6 @@ void ASMCALL R_Draw2sMultiPatchColumn_8_MMX(void);
 void ASMCALL R_DrawSpan_8_MMX(void);
 #endif
 
-void R_DrawTranslatedColumn_8(void);
-void R_DrawTranslatedTranslucentColumn_8(void);
-void R_DrawSpan_8(void);
-#ifdef ESLOPE
-void R_CalcTiltedLighting(fixed_t start, fixed_t end);
-void R_DrawTiltedSpan_8(void);
-void R_DrawTiltedTranslucentSpan_8(void);
-void R_DrawTiltedSplat_8(void);
-#endif
-void R_DrawSplat_8(void);
-void R_DrawTranslucentSplat_8(void);
-void R_DrawTranslucentSpan_8(void);
-void R_Draw2sMultiPatchColumn_8(void);
-void R_Draw2sMultiPatchTranslucentColumn_8(void);
-void R_DrawFogSpan_8(void);
-void R_DrawFogColumn_8(void);
-void R_DrawColumnShadowed_8(void);
-
-#ifndef NOWATER
-void R_DrawTranslucentWaterSpan_8(void);
-
-extern INT32 ds_bgofs;
-extern INT32 ds_waterofs;
-#endif
-
 // ------------------
 // 16bpp DRAWING CODE
 // ------------------
diff --git a/src/r_draw8.c b/src/r_draw8.c
index db9bc4c3c..a6a400945 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -562,11 +562,8 @@ void R_DrawSpan_8 (void)
 	// bit per power of two (obviously)
 	// Ok, because I was able to eliminate the variable spot below, this function is now FASTER
 	// than the original span renderer. Whodathunkit?
-	if (ds_powersoftwo)
-	{
-		xposition <<= nflatshiftup; yposition <<= nflatshiftup;
-		xstep <<= nflatshiftup; ystep <<= nflatshiftup;
-	}
+	xposition <<= nflatshiftup; yposition <<= nflatshiftup;
+	xstep <<= nflatshiftup; ystep <<= nflatshiftup;
 
 	source = ds_source;
 	colormap = ds_colormap;
@@ -575,82 +572,58 @@ void R_DrawSpan_8 (void)
 	if (dest+8 > deststop)
 		return;
 
-	if (!ds_powersoftwo)
+	while (count >= 8)
 	{
-		while (count-- && dest <= deststop)
-		{
-			fixed_t x = (xposition >> FRACBITS);
-			fixed_t y = (yposition >> FRACBITS);
+		// 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[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
 
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+		dest[1] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
 
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
+		dest[2] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
 
-			*dest++ = colormap[source[((y * ds_flatwidth) + x)]];
-			xposition += xstep;
-			yposition += ystep;
-		}
+		dest[3] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[4] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[5] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[6] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[7] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest += 8;
+		count -= 8;
 	}
-	else
+	while (count-- && dest <= deststop)
 	{
-		while (count >= 8)
-		{
-			// 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[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[1] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[2] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[3] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[4] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[5] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[6] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[7] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest += 8;
-			count -= 8;
-		}
-		while (count-- && dest <= deststop)
-		{
-			*dest++ = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
-			xposition += xstep;
-			yposition += ystep;
-		}
+		*dest++ = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]];
+		xposition += xstep;
+		yposition += ystep;
 	}
 }
 
 #ifdef ESLOPE
 // R_CalcTiltedLighting
 // Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly.
-static INT32 tiltlighting[MAXVIDWIDTH];
+INT32 tiltlighting[MAXVIDWIDTH];
 void R_CalcTiltedLighting(fixed_t start, fixed_t end)
 {
 	// ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version
@@ -724,24 +697,7 @@ void R_DrawTiltedSpan_8(void)
 
 		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
 
-		if (!ds_powersoftwo)
-		{
-			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
-
-			*dest = colormap[source[((y * ds_flatwidth) + x)]];
-		}
-		else
-			*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+		*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
 		dest++;
 		iz += ds_sz.x;
 		uz += ds_su.x;
@@ -778,24 +734,7 @@ void R_DrawTiltedSpan_8(void)
 		for (i = SPANSIZE-1; i >= 0; i--)
 		{
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			if (!ds_powersoftwo)
-			{
-				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-				// Carefully align all of my Friends.
-				if (x < 0)
-					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-				if (y < 0)
-					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-				x %= ds_flatwidth;
-				y %= ds_flatheight;
-
-				*dest = colormap[source[((y * ds_flatwidth) + x)]];
-			}
-			else
-				*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
 			dest++;
 			u += stepu;
 			v += stepv;
@@ -811,24 +750,7 @@ void R_DrawTiltedSpan_8(void)
 			u = (INT64)(startu);
 			v = (INT64)(startv);
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			if (!ds_powersoftwo)
-			{
-				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-				// Carefully align all of my Friends.
-				if (x < 0)
-					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-				if (y < 0)
-					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-				x %= ds_flatwidth;
-				y %= ds_flatheight;
-
-				*dest = colormap[source[((y * ds_flatwidth) + x)]];
-			}
-			else
-				*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
 		}
 		else
 		{
@@ -849,24 +771,7 @@ void R_DrawTiltedSpan_8(void)
 			for (; width != 0; width--)
 			{
 				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-				if (!ds_powersoftwo)
-				{
-					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-					// Carefully align all of my Friends.
-					if (x < 0)
-						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-					if (y < 0)
-						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-					x %= ds_flatwidth;
-					y %= ds_flatheight;
-
-					*dest = colormap[source[((y * ds_flatwidth) + x)]];
-				}
-				else
-					*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+				*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
 				dest++;
 				u += stepu;
 				v += stepv;
@@ -927,24 +832,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 		v = (INT64)(vz*z) + viewy;
 
 		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-		if (!ds_powersoftwo)
-		{
-			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
-
-			*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
-		}
-		else
-			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
+		*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 		dest++;
 		iz += ds_sz.x;
 		uz += ds_su.x;
@@ -981,24 +869,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 		for (i = SPANSIZE-1; i >= 0; i--)
 		{
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			if (!ds_powersoftwo)
-			{
-				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-				// Carefully align all of my Friends.
-				if (x < 0)
-					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-				if (y < 0)
-					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-				x %= ds_flatwidth;
-				y %= ds_flatheight;
-
-				*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
-			}
-			else
-				*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
+			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 			dest++;
 			u += stepu;
 			v += stepv;
@@ -1014,24 +885,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 			u = (INT64)(startu);
 			v = (INT64)(startv);
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			if (!ds_powersoftwo)
-			{
-				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-				// Carefully align all of my Friends.
-				if (x < 0)
-					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-				if (y < 0)
-					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-				x %= ds_flatwidth;
-				y %= ds_flatheight;
-
-				*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
-			}
-			else
-				*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
+			*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 		}
 		else
 		{
@@ -1052,24 +906,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 			for (; width != 0; width--)
 			{
 				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-				if (!ds_powersoftwo)
-				{
-					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-					// Carefully align all of my Friends.
-					if (x < 0)
-						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-					if (y < 0)
-						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-					x %= ds_flatwidth;
-					y %= ds_flatheight;
-
-					*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
-				}
-				else
-					*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
+				*dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest);
 				dest++;
 				u += stepu;
 				v += stepv;
@@ -1130,25 +967,7 @@ void R_DrawTiltedSplat_8(void)
 
 		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
 
-		if (!ds_powersoftwo)
-		{
-			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
-
-			val = source[((y * ds_flatwidth) + x)];
-		}
-		else
-			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
-
+		val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
 			*dest = colormap[val];
 
@@ -1188,24 +1007,7 @@ void R_DrawTiltedSplat_8(void)
 		for (i = SPANSIZE-1; i >= 0; i--)
 		{
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			if (!ds_powersoftwo)
-			{
-				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-				// Carefully align all of my Friends.
-				if (x < 0)
-					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-				if (y < 0)
-					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-				x %= ds_flatwidth;
-				y %= ds_flatheight;
-
-				val = source[((y * ds_flatwidth) + x)];
-			}
-			else
-				val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
+			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 			if (val != TRANSPARENTPIXEL)
 				*dest = colormap[val];
 			dest++;
@@ -1223,24 +1025,7 @@ void R_DrawTiltedSplat_8(void)
 			u = (INT64)(startu);
 			v = (INT64)(startv);
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			if (!ds_powersoftwo)
-			{
-				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-				// Carefully align all of my Friends.
-				if (x < 0)
-					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-				if (y < 0)
-					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-				x %= ds_flatwidth;
-				y %= ds_flatheight;
-
-				val = source[((y * ds_flatwidth) + x)];
-			}
-			else
-				val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
+			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 			if (val != TRANSPARENTPIXEL)
 				*dest = colormap[val];
 		}
@@ -1264,24 +1049,6 @@ void R_DrawTiltedSplat_8(void)
 			{
 				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
 				val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
-				if (!ds_powersoftwo)
-				{
-					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
-					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
-
-					// Carefully align all of my Friends.
-					if (x < 0)
-						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-					if (y < 0)
-						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
-
-					x %= ds_flatwidth;
-					y %= ds_flatheight;
-
-					val = source[((y * ds_flatwidth) + x)];
-				}
-				else
-					val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 				if (val != TRANSPARENTPIXEL)
 					*dest = colormap[val];
 				dest++;
@@ -1321,125 +1088,95 @@ void R_DrawSplat_8 (void)
 	// bit per power of two (obviously)
 	// Ok, because I was able to eliminate the variable spot below, this function is now FASTER
 	// than the original span renderer. Whodathunkit?
-	if (ds_powersoftwo)
-	{
-		xposition <<= nflatshiftup; yposition <<= nflatshiftup;
-		xstep <<= nflatshiftup; ystep <<= nflatshiftup;
-	}
+	xposition <<= nflatshiftup; yposition <<= nflatshiftup;
+	xstep <<= nflatshiftup; ystep <<= nflatshiftup;
 
 	source = ds_source;
 	colormap = ds_colormap;
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 
-	if (!ds_powersoftwo)
+	while (count >= 8)
 	{
-		while (count-- && dest <= deststop)
-		{
-			fixed_t x = (xposition >> FRACBITS);
-			fixed_t y = (yposition >> FRACBITS);
+		// 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!
+		//
+		// <Callum> 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size)
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[0] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
 
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[1] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
 
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[2] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
 
-			val = source[((y * ds_flatwidth) + x)];
-			if (val != TRANSPARENTPIXEL)
-				*dest = colormap[val];
-			dest++;
-			xposition += xstep;
-			yposition += ystep;
-		}
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[3] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
+
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[4] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
+
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[5] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
+
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[6] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
+
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		val &= 4194303;
+		val = source[val];
+		if (val != TRANSPARENTPIXEL)
+			dest[7] = colormap[val];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest += 8;
+		count -= 8;
 	}
-	else
+	while (count-- && dest <= deststop)
 	{
-		while (count >= 8)
-		{
-			// 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!
-			//
-			// <Callum> 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size)
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[0] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[1] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[2] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[3] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[4] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[5] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[6] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			val &= 4194303;
-			val = source[val];
-			if (val != TRANSPARENTPIXEL)
-				dest[7] = colormap[val];
-			xposition += xstep;
-			yposition += ystep;
-
-			dest += 8;
-			count -= 8;
-		}
-		while (count-- && dest <= deststop)
-		{
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				*dest = colormap[val];
-			dest++;
-			xposition += xstep;
-			yposition += ystep;
-		}
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			*dest = colormap[val];
+		dest++;
+		xposition += xstep;
+		yposition += ystep;
 	}
 }
 
@@ -1470,112 +1207,82 @@ void R_DrawTranslucentSplat_8 (void)
 	// bit per power of two (obviously)
 	// Ok, because I was able to eliminate the variable spot below, this function is now FASTER
 	// than the original span renderer. Whodathunkit?
-	if (ds_powersoftwo)
-	{
-		xposition <<= nflatshiftup; yposition <<= nflatshiftup;
-		xstep <<= nflatshiftup; ystep <<= nflatshiftup;
-	}
+	xposition <<= nflatshiftup; yposition <<= nflatshiftup;
+	xstep <<= nflatshiftup; ystep <<= nflatshiftup;
 
 	source = ds_source;
 	colormap = ds_colormap;
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 
-	if (!ds_powersoftwo)
+	while (count >= 8)
 	{
-		while (count-- && dest <= deststop)
-		{
-			fixed_t x = (xposition >> FRACBITS);
-			fixed_t y = (yposition >> FRACBITS);
+		// 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!
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[0] = *(ds_transmap + (colormap[val] << 8) + dest[0]);
+		xposition += xstep;
+		yposition += ystep;
 
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[1] = *(ds_transmap + (colormap[val] << 8) + dest[1]);
+		xposition += xstep;
+		yposition += ystep;
 
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[2] = *(ds_transmap + (colormap[val] << 8) + dest[2]);
+		xposition += xstep;
+		yposition += ystep;
 
-			val = source[((y * ds_flatwidth) + x)];
-			if (val != TRANSPARENTPIXEL)
-				*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
-			dest++;
-			xposition += xstep;
-			yposition += ystep;
-		}
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[3] = *(ds_transmap + (colormap[val] << 8) + dest[3]);
+		xposition += xstep;
+		yposition += ystep;
+
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[4] = *(ds_transmap + (colormap[val] << 8) + dest[4]);
+		xposition += xstep;
+		yposition += ystep;
+
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[5] = *(ds_transmap + (colormap[val] << 8) + dest[5]);
+		xposition += xstep;
+		yposition += ystep;
+
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[6] = *(ds_transmap + (colormap[val] << 8) + dest[6]);
+		xposition += xstep;
+		yposition += ystep;
+
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			dest[7] = *(ds_transmap + (colormap[val] << 8) + dest[7]);
+		xposition += xstep;
+		yposition += ystep;
+
+		dest += 8;
+		count -= 8;
 	}
-	else
+	while (count-- && dest <= deststop)
 	{
-		while (count >= 8)
-		{
-			// 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!
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[0] = *(ds_transmap + (colormap[val] << 8) + dest[0]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[1] = *(ds_transmap + (colormap[val] << 8) + dest[1]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[2] = *(ds_transmap + (colormap[val] << 8) + dest[2]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[3] = *(ds_transmap + (colormap[val] << 8) + dest[3]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[4] = *(ds_transmap + (colormap[val] << 8) + dest[4]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[5] = *(ds_transmap + (colormap[val] << 8) + dest[5]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[6] = *(ds_transmap + (colormap[val] << 8) + dest[6]);
-			xposition += xstep;
-			yposition += ystep;
-
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				dest[7] = *(ds_transmap + (colormap[val] << 8) + dest[7]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest += 8;
-			count -= 8;
-		}
-		while (count-- && dest <= deststop)
-		{
-			val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
-			if (val != TRANSPARENTPIXEL)
-				*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
-			dest++;
-			xposition += xstep;
-			yposition += ystep;
-		}
+		val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)];
+		if (val != TRANSPARENTPIXEL)
+			*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
+		dest++;
+		xposition += xstep;
+		yposition += ystep;
 	}
 }
 
 /**	\brief The R_DrawTranslucentSpan_8 function
-	Draws the actual span with translucent.
+	Draws the actual span with translucency.
 */
 void R_DrawTranslucentSpan_8 (void)
 {
@@ -1601,109 +1308,76 @@ void R_DrawTranslucentSpan_8 (void)
 	// bit per power of two (obviously)
 	// Ok, because I was able to eliminate the variable spot below, this function is now FASTER
 	// than the original span renderer. Whodathunkit?
-	if (ds_powersoftwo)
-	{
-		xposition <<= nflatshiftup; yposition <<= nflatshiftup;
-		xstep <<= nflatshiftup; ystep <<= nflatshiftup;
-	}
+	xposition <<= nflatshiftup; yposition <<= nflatshiftup;
+	xstep <<= nflatshiftup; ystep <<= nflatshiftup;
 
 	source = ds_source;
 	colormap = ds_colormap;
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 
-	if (!ds_powersoftwo)
+	while (count >= 8)
 	{
-		while (count-- && dest <= deststop)
-		{
-			fixed_t x = (xposition >> FRACBITS);
-			fixed_t y = (yposition >> FRACBITS);
+		// 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] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[0]);
+		xposition += xstep;
+		yposition += ystep;
 
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+		dest[1] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[1]);
+		xposition += xstep;
+		yposition += ystep;
 
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
+		dest[2] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[2]);
+		xposition += xstep;
+		yposition += ystep;
 
-			val = ((y * ds_flatwidth) + x);
-			*dest = *(ds_transmap + (colormap[source[val]] << 8) + *dest);
-			dest++;
-			xposition += xstep;
-			yposition += ystep;
-		}
+		dest[3] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[3]);
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[4] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[4]);
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[5] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[5]);
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[6] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[6]);
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[7] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[7]);
+		xposition += xstep;
+		yposition += ystep;
+
+		dest += 8;
+		count -= 8;
 	}
-	else
+	while (count-- && dest <= deststop)
 	{
-		while (count >= 8)
-		{
-			// 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] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[0]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[1] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[1]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[2] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[2]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[3] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[3]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[4] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[4]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[5] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[5]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[6] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[6]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest[7] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[7]);
-			xposition += xstep;
-			yposition += ystep;
-
-			dest += 8;
-			count -= 8;
-		}
-		while (count-- && dest <= deststop)
-		{
-			val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
-			*dest = *(ds_transmap + (colormap[source[val]] << 8) + *dest);
-			dest++;
-			xposition += xstep;
-			yposition += ystep;
-		}
+		val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
+		*dest = *(ds_transmap + (colormap[source[val]] << 8) + *dest);
+		dest++;
+		xposition += xstep;
+		yposition += ystep;
 	}
 }
 
 #ifndef NOWATER
 void R_DrawTranslucentWaterSpan_8(void)
 {
-	fixed_t xposition;
-	fixed_t yposition;
-	fixed_t xstep, ystep;
+	UINT32 xposition;
+	UINT32 yposition;
+	UINT32 xstep, ystep;
 
 	UINT8 *source;
 	UINT8 *colormap;
 	UINT8 *dest;
 	UINT8 *dsrc;
-	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
 
-	size_t count = (ds_x2 - ds_x1 + 1);
-
-	xposition = ds_xfrac; yposition = (ds_yfrac + ds_waterofs);
-	xstep = ds_xstep; ystep = ds_ystep;
+	size_t count;
 
 	// SoM: we only need 6 bits for the integer part (0 thru 63) so the rest
 	// can be used for the fraction part. This allows calculation of the memory address in the
@@ -1712,46 +1386,60 @@ void R_DrawTranslucentWaterSpan_8(void)
 	// bit per power of two (obviously)
 	// Ok, because I was able to eliminate the variable spot below, this function is now FASTER
 	// than the original span renderer. Whodathunkit?
-	if (ds_powersoftwo)
-	{
-		xposition <<= nflatshiftup; yposition <<= nflatshiftup;
-		xstep <<= nflatshiftup; ystep <<= nflatshiftup;
-	}
+	xposition = ds_xfrac << nflatshiftup; yposition = (ds_yfrac + ds_waterofs) << nflatshiftup;
+	xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup;
 
 	source = ds_source;
 	colormap = ds_colormap;
 	dest = ylookup[ds_y] + columnofs[ds_x1];
 	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
+	count = ds_x2 - ds_x1 + 1;
 
-	if (!ds_powersoftwo)
+	while (count >= 8)
 	{
-		while (count-- && dest <= deststop)
-		{
-			fixed_t x = (xposition >> FRACBITS);
-			fixed_t y = (yposition >> FRACBITS);
+		// 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) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
 
-			// Carefully align all of my Friends.
-			if (x < 0)
-				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
-			if (y < 0)
-				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+		dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
 
-			x %= ds_flatwidth;
-			y %= ds_flatheight;
+		dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
 
-			*dest++ = colormap[*(ds_transmap + (source[((y * ds_flatwidth) + x)] << 8) + *dsrc++)];
-			xposition += xstep;
-			yposition += ystep;
-		}
+		dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
+
+		dest += 8;
+		count -= 8;
 	}
-	else
+	while (count--)
 	{
-		while (count-- && dest <= deststop)
-		{
-			*dest++ = colormap[*(ds_transmap + (source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)] << 8) + *dsrc++)];
-			xposition += xstep;
-			yposition += ystep;
-		}
+		*dest++ = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
 	}
 }
 #endif
diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c
new file mode 100644
index 000000000..3ed6acd00
--- /dev/null
+++ b/src/r_draw8_npo2.c
@@ -0,0 +1,845 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2019 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  r_draw8_npo2.c
+/// \brief 8bpp span drawer functions (for non-powers-of-two flat dimensions)
+/// \note  no includes because this is included as part of r_draw.c
+
+// ==========================================================================
+// SPANS
+// ==========================================================================
+
+/**	\brief The R_DrawSpan_NPO2_8 function
+	Draws the actual span.
+*/
+void R_DrawSpan_NPO2_8 (void)
+{
+	fixed_t xposition;
+	fixed_t yposition;
+	fixed_t xstep, ystep;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
+
+	size_t count = (ds_x2 - ds_x1 + 1);
+
+	xposition = ds_xfrac; yposition = ds_yfrac;
+	xstep = ds_xstep; ystep = ds_ystep;
+
+	source = ds_source;
+	colormap = ds_colormap;
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+
+	if (dest+8 > deststop)
+		return;
+
+	while (count-- && dest <= deststop)
+	{
+		fixed_t x = (xposition >> FRACBITS);
+		fixed_t y = (yposition >> FRACBITS);
+
+		// Carefully align all of my Friends.
+		if (x < 0)
+			x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+		if (y < 0)
+			y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+		x %= ds_flatwidth;
+		y %= ds_flatheight;
+
+		*dest++ = colormap[source[((y * ds_flatwidth) + x)]];
+		xposition += xstep;
+		yposition += ystep;
+	}
+}
+
+#ifdef ESLOPE
+/**	\brief The R_DrawTiltedSpan_NPO2_8 function
+	Draw slopes! Holy sheit!
+*/
+void R_DrawTiltedSpan_NPO2_8(void)
+{
+	// x1, x2 = ds_x1, ds_x2
+	int width = ds_x2 - ds_x1;
+	double iz, uz, vz;
+	UINT32 u, v;
+	int i;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+
+	double startz, startu, startv;
+	double izstep, uzstep, vzstep;
+	double endz, endu, endv;
+	UINT32 stepu, stepv;
+
+	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+
+	// Lighting is simple. It's just linear interpolation from start to end
+	{
+		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
+		float lightstart, lightend;
+
+		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightstart = iz * planelightfloat;
+
+		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
+		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
+	}
+
+	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
+	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	source = ds_source;
+	//colormap = ds_colormap;
+
+#if 0	// The "perfect" reference version of this routine. Pretty slow.
+		// Use it only to see how things are supposed to look.
+	i = 0;
+	do
+	{
+		double z = 1.f/iz;
+		u = (INT64)(uz*z) + viewx;
+		v = (INT64)(vz*z) + viewy;
+
+		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+
+		// Lactozilla: Non-powers-of-two
+		{
+			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+			// Carefully align all of my Friends.
+			if (x < 0)
+				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+			if (y < 0)
+				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+			x %= ds_flatwidth;
+			y %= ds_flatheight;
+
+			*dest = colormap[source[((y * ds_flatwidth) + x)]];
+		}
+		dest++;
+		iz += ds_sz.x;
+		uz += ds_su.x;
+		vz += ds_sv.x;
+	} while (--width >= 0);
+#else
+#define SPANSIZE 16
+#define INVSPAN	0.0625f
+
+	startz = 1.f/iz;
+	startu = uz*startz;
+	startv = vz*startz;
+
+	izstep = ds_sz.x * SPANSIZE;
+	uzstep = ds_su.x * SPANSIZE;
+	vzstep = ds_sv.x * SPANSIZE;
+	//x1 = 0;
+	width++;
+
+	while (width >= SPANSIZE)
+	{
+		iz += izstep;
+		uz += uzstep;
+		vz += vzstep;
+
+		endz = 1.f/iz;
+		endu = uz*endz;
+		endv = vz*endz;
+		stepu = (INT64)((endu - startu) * INVSPAN);
+		stepv = (INT64)((endv - startv) * INVSPAN);
+		u = (INT64)(startu) + viewx;
+		v = (INT64)(startv) + viewy;
+
+		for (i = SPANSIZE-1; i >= 0; i--)
+		{
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			// Lactozilla: Non-powers-of-two
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				*dest = colormap[source[((y * ds_flatwidth) + x)]];
+			}
+			dest++;
+			u += stepu;
+			v += stepv;
+		}
+		startu = endu;
+		startv = endv;
+		width -= SPANSIZE;
+	}
+	if (width > 0)
+	{
+		if (width == 1)
+		{
+			u = (INT64)(startu);
+			v = (INT64)(startv);
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			// Lactozilla: Non-powers-of-two
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				*dest = colormap[source[((y * ds_flatwidth) + x)]];
+			}
+		}
+		else
+		{
+			double left = width;
+			iz += ds_sz.x * left;
+			uz += ds_su.x * left;
+			vz += ds_sv.x * left;
+
+			endz = 1.f/iz;
+			endu = uz*endz;
+			endv = vz*endz;
+			left = 1.f/left;
+			stepu = (INT64)((endu - startu) * left);
+			stepv = (INT64)((endv - startv) * left);
+			u = (INT64)(startu) + viewx;
+			v = (INT64)(startv) + viewy;
+
+			for (; width != 0; width--)
+			{
+				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+				// Lactozilla: Non-powers-of-two
+				{
+					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+					// Carefully align all of my Friends.
+					if (x < 0)
+						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+					if (y < 0)
+						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+					x %= ds_flatwidth;
+					y %= ds_flatheight;
+
+					*dest = colormap[source[((y * ds_flatwidth) + x)]];
+				}
+				dest++;
+				u += stepu;
+				v += stepv;
+			}
+		}
+	}
+#endif
+}
+
+/**	\brief The R_DrawTiltedTranslucentSpan_NPO2_8 function
+	Like DrawTiltedSpan_NPO2, but translucent
+*/
+void R_DrawTiltedTranslucentSpan_NPO2_8(void)
+{
+	// x1, x2 = ds_x1, ds_x2
+	int width = ds_x2 - ds_x1;
+	double iz, uz, vz;
+	UINT32 u, v;
+	int i;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+
+	double startz, startu, startv;
+	double izstep, uzstep, vzstep;
+	double endz, endu, endv;
+	UINT32 stepu, stepv;
+
+	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+
+	// Lighting is simple. It's just linear interpolation from start to end
+	{
+		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
+		float lightstart, lightend;
+
+		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightstart = iz * planelightfloat;
+
+		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
+		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
+	}
+
+	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
+	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	source = ds_source;
+	//colormap = ds_colormap;
+
+#if 0	// The "perfect" reference version of this routine. Pretty slow.
+		// Use it only to see how things are supposed to look.
+	i = 0;
+	do
+	{
+		double z = 1.f/iz;
+		u = (INT64)(uz*z) + viewx;
+		v = (INT64)(vz*z) + viewy;
+
+		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+		// Lactozilla: Non-powers-of-two
+		{
+			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+			// Carefully align all of my Friends.
+			if (x < 0)
+				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+			if (y < 0)
+				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+			x %= ds_flatwidth;
+			y %= ds_flatheight;
+
+			*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
+		}
+		dest++;
+		iz += ds_sz.x;
+		uz += ds_su.x;
+		vz += ds_sv.x;
+	} while (--width >= 0);
+#else
+#define SPANSIZE 16
+#define INVSPAN	0.0625f
+
+	startz = 1.f/iz;
+	startu = uz*startz;
+	startv = vz*startz;
+
+	izstep = ds_sz.x * SPANSIZE;
+	uzstep = ds_su.x * SPANSIZE;
+	vzstep = ds_sv.x * SPANSIZE;
+	//x1 = 0;
+	width++;
+
+	while (width >= SPANSIZE)
+	{
+		iz += izstep;
+		uz += uzstep;
+		vz += vzstep;
+
+		endz = 1.f/iz;
+		endu = uz*endz;
+		endv = vz*endz;
+		stepu = (INT64)((endu - startu) * INVSPAN);
+		stepv = (INT64)((endv - startv) * INVSPAN);
+		u = (INT64)(startu) + viewx;
+		v = (INT64)(startv) + viewy;
+
+		for (i = SPANSIZE-1; i >= 0; i--)
+		{
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			// Lactozilla: Non-powers-of-two
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
+			}
+			dest++;
+			u += stepu;
+			v += stepv;
+		}
+		startu = endu;
+		startv = endv;
+		width -= SPANSIZE;
+	}
+	if (width > 0)
+	{
+		if (width == 1)
+		{
+			u = (INT64)(startu);
+			v = (INT64)(startv);
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			// Lactozilla: Non-powers-of-two
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
+			}
+		}
+		else
+		{
+			double left = width;
+			iz += ds_sz.x * left;
+			uz += ds_su.x * left;
+			vz += ds_sv.x * left;
+
+			endz = 1.f/iz;
+			endu = uz*endz;
+			endv = vz*endz;
+			left = 1.f/left;
+			stepu = (INT64)((endu - startu) * left);
+			stepv = (INT64)((endv - startv) * left);
+			u = (INT64)(startu) + viewx;
+			v = (INT64)(startv) + viewy;
+
+			for (; width != 0; width--)
+			{
+				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+				// Lactozilla: Non-powers-of-two
+				{
+					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+					// Carefully align all of my Friends.
+					if (x < 0)
+						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+					if (y < 0)
+						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+					x %= ds_flatwidth;
+					y %= ds_flatheight;
+
+					*dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest);
+				}
+				dest++;
+				u += stepu;
+				v += stepv;
+			}
+		}
+	}
+#endif
+}
+
+void R_DrawTiltedSplat_NPO2_8(void)
+{
+	// x1, x2 = ds_x1, ds_x2
+	int width = ds_x2 - ds_x1;
+	double iz, uz, vz;
+	UINT32 u, v;
+	int i;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+
+	UINT8 val;
+
+	double startz, startu, startv;
+	double izstep, uzstep, vzstep;
+	double endz, endu, endv;
+	UINT32 stepu, stepv;
+
+	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+
+	// Lighting is simple. It's just linear interpolation from start to end
+	{
+		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
+		float lightstart, lightend;
+
+		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightstart = iz * planelightfloat;
+
+		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
+		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
+	}
+
+	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
+	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	source = ds_source;
+	//colormap = ds_colormap;
+
+#if 0	// The "perfect" reference version of this routine. Pretty slow.
+		// Use it only to see how things are supposed to look.
+	i = 0;
+	do
+	{
+		double z = 1.f/iz;
+		u = (INT64)(uz*z) + viewx;
+		v = (INT64)(vz*z) + viewy;
+
+		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+
+		// Lactozilla: Non-powers-of-two
+		{
+			fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+			fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+			// Carefully align all of my Friends.
+			if (x < 0)
+				x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+			if (y < 0)
+				y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+			x %= ds_flatwidth;
+			y %= ds_flatheight;
+
+			val = source[((y * ds_flatwidth) + x)];
+		}
+
+		if (val != TRANSPARENTPIXEL)
+			*dest = colormap[val];
+
+		dest++;
+		iz += ds_sz.x;
+		uz += ds_su.x;
+		vz += ds_sv.x;
+	} while (--width >= 0);
+#else
+#define SPANSIZE 16
+#define INVSPAN	0.0625f
+
+	startz = 1.f/iz;
+	startu = uz*startz;
+	startv = vz*startz;
+
+	izstep = ds_sz.x * SPANSIZE;
+	uzstep = ds_su.x * SPANSIZE;
+	vzstep = ds_sv.x * SPANSIZE;
+	//x1 = 0;
+	width++;
+
+	while (width >= SPANSIZE)
+	{
+		iz += izstep;
+		uz += uzstep;
+		vz += vzstep;
+
+		endz = 1.f/iz;
+		endu = uz*endz;
+		endv = vz*endz;
+		stepu = (INT64)((endu - startu) * INVSPAN);
+		stepv = (INT64)((endv - startv) * INVSPAN);
+		u = (INT64)(startu) + viewx;
+		v = (INT64)(startv) + viewy;
+
+		for (i = SPANSIZE-1; i >= 0; i--)
+		{
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			// Lactozilla: Non-powers-of-two
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				val = source[((y * ds_flatwidth) + x)];
+			}
+			if (val != TRANSPARENTPIXEL)
+				*dest = colormap[val];
+			dest++;
+			u += stepu;
+			v += stepv;
+		}
+		startu = endu;
+		startv = endv;
+		width -= SPANSIZE;
+	}
+	if (width > 0)
+	{
+		if (width == 1)
+		{
+			u = (INT64)(startu);
+			v = (INT64)(startv);
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			// Lactozilla: Non-powers-of-two
+			{
+				fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+				fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+				// Carefully align all of my Friends.
+				if (x < 0)
+					x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+				if (y < 0)
+					y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+				x %= ds_flatwidth;
+				y %= ds_flatheight;
+
+				val = source[((y * ds_flatwidth) + x)];
+			}
+			if (val != TRANSPARENTPIXEL)
+				*dest = colormap[val];
+		}
+		else
+		{
+			double left = width;
+			iz += ds_sz.x * left;
+			uz += ds_su.x * left;
+			vz += ds_sv.x * left;
+
+			endz = 1.f/iz;
+			endu = uz*endz;
+			endv = vz*endz;
+			left = 1.f/left;
+			stepu = (INT64)((endu - startu) * left);
+			stepv = (INT64)((endv - startv) * left);
+			u = (INT64)(startu) + viewx;
+			v = (INT64)(startv) + viewy;
+
+			for (; width != 0; width--)
+			{
+				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+				val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
+				// Lactozilla: Non-powers-of-two
+				{
+					fixed_t x = (((fixed_t)u-viewx) >> FRACBITS);
+					fixed_t y = (((fixed_t)v-viewy) >> FRACBITS);
+
+					// Carefully align all of my Friends.
+					if (x < 0)
+						x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+					if (y < 0)
+						y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+					x %= ds_flatwidth;
+					y %= ds_flatheight;
+
+					val = source[((y * ds_flatwidth) + x)];
+				}
+				if (val != TRANSPARENTPIXEL)
+					*dest = colormap[val];
+				dest++;
+				u += stepu;
+				v += stepv;
+			}
+		}
+	}
+#endif
+}
+#endif // ESLOPE
+
+/**	\brief The R_DrawSplat_NPO2_8 function
+	Just like R_DrawSpan_NPO2_8, but skips transparent pixels.
+*/
+void R_DrawSplat_NPO2_8 (void)
+{
+	fixed_t xposition;
+	fixed_t yposition;
+	fixed_t xstep, ystep;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
+
+	size_t count = (ds_x2 - ds_x1 + 1);
+	UINT32 val;
+
+	xposition = ds_xfrac; yposition = ds_yfrac;
+	xstep = ds_xstep; ystep = ds_ystep;
+
+	source = ds_source;
+	colormap = ds_colormap;
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+
+	while (count-- && dest <= deststop)
+	{
+		fixed_t x = (xposition >> FRACBITS);
+		fixed_t y = (yposition >> FRACBITS);
+
+		// Carefully align all of my Friends.
+		if (x < 0)
+			x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+		if (y < 0)
+			y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+		x %= ds_flatwidth;
+		y %= ds_flatheight;
+
+		val = source[((y * ds_flatwidth) + x)];
+		if (val != TRANSPARENTPIXEL)
+			*dest = colormap[val];
+		dest++;
+		xposition += xstep;
+		yposition += ystep;
+	}
+}
+
+/**	\brief The R_DrawTranslucentSplat_NPO2_8 function
+	Just like R_DrawSplat_NPO2_8, but is translucent!
+*/
+void R_DrawTranslucentSplat_NPO2_8 (void)
+{
+	fixed_t xposition;
+	fixed_t yposition;
+	fixed_t xstep, ystep;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
+
+	size_t count = (ds_x2 - ds_x1 + 1);
+	UINT32 val;
+
+	xposition = ds_xfrac; yposition = ds_yfrac;
+	xstep = ds_xstep; ystep = ds_ystep;
+
+	source = ds_source;
+	colormap = ds_colormap;
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+
+	while (count-- && dest <= deststop)
+	{
+		fixed_t x = (xposition >> FRACBITS);
+		fixed_t y = (yposition >> FRACBITS);
+
+		// Carefully align all of my Friends.
+		if (x < 0)
+			x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+		if (y < 0)
+			y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+		x %= ds_flatwidth;
+		y %= ds_flatheight;
+
+		val = source[((y * ds_flatwidth) + x)];
+		if (val != TRANSPARENTPIXEL)
+			*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
+		dest++;
+		xposition += xstep;
+		yposition += ystep;
+	}
+}
+
+/**	\brief The R_DrawTranslucentSpan_NPO2_8 function
+	Draws the actual span with translucency.
+*/
+void R_DrawTranslucentSpan_NPO2_8 (void)
+{
+	fixed_t xposition;
+	fixed_t yposition;
+	fixed_t xstep, ystep;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
+
+	size_t count = (ds_x2 - ds_x1 + 1);
+	UINT32 val;
+
+	xposition = ds_xfrac; yposition = ds_yfrac;
+	xstep = ds_xstep; ystep = ds_ystep;
+
+	source = ds_source;
+	colormap = ds_colormap;
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+
+	while (count-- && dest <= deststop)
+	{
+		fixed_t x = (xposition >> FRACBITS);
+		fixed_t y = (yposition >> FRACBITS);
+
+		// Carefully align all of my Friends.
+		if (x < 0)
+			x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+		if (y < 0)
+			y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+		x %= ds_flatwidth;
+		y %= ds_flatheight;
+
+		val = ((y * ds_flatwidth) + x);
+		*dest = *(ds_transmap + (colormap[source[val]] << 8) + *dest);
+		dest++;
+		xposition += xstep;
+		yposition += ystep;
+	}
+}
+
+#ifndef NOWATER
+void R_DrawTranslucentWaterSpan_NPO2_8(void)
+{
+	fixed_t xposition;
+	fixed_t yposition;
+	fixed_t xstep, ystep;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+	UINT8 *dsrc;
+	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
+
+	size_t count = (ds_x2 - ds_x1 + 1);
+
+	xposition = ds_xfrac; yposition = (ds_yfrac + ds_waterofs);
+	xstep = ds_xstep; ystep = ds_ystep;
+
+	source = ds_source;
+	colormap = ds_colormap;
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
+
+	while (count-- && dest <= deststop)
+	{
+		fixed_t x = (xposition >> FRACBITS);
+		fixed_t y = (yposition >> FRACBITS);
+
+		// Carefully align all of my Friends.
+		if (x < 0)
+			x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth);
+		if (y < 0)
+			y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight);
+
+		x %= ds_flatwidth;
+		y %= ds_flatheight;
+
+		*dest++ = colormap[*(ds_transmap + (source[((y * ds_flatwidth) + x)] << 8) + *dsrc++)];
+		xposition += xstep;
+		yposition += ystep;
+	}
+}
+#endif
diff --git a/src/r_plane.c b/src/r_plane.c
index 8c644700e..3745c28be 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -841,6 +841,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 	ffloor_t *rover;
 	levelflat_t *levelflat;
 	int type;
+	int spanfunctype = BASEDRAWFUNC;
 
 	if (!(pl->minx <= pl->maxx))
 		return;
@@ -858,8 +859,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 	spanfunc = spanfuncs[BASEDRAWFUNC];
 
 #ifdef POLYOBJECTS_PLANES
-	if (pl->polyobj && pl->polyobj->translucency != 0) {
-		spanfunc = spanfuncs[SPANDRAWFUNC_TRANS];
+	if (pl->polyobj && pl->polyobj->translucency != 0)
+	{
+		spanfunctype = SPANDRAWFUNC_TRANS;
 
 		// Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red)
 		if (pl->polyobj->translucency >= 10)
@@ -867,10 +869,10 @@ void R_DrawSinglePlane(visplane_t *pl)
 		else if (pl->polyobj->translucency > 0)
 			ds_transmap = transtables + ((pl->polyobj->translucency-1)<<FF_TRANSSHIFT);
 		else // Opaque, but allow transparent flat pixels
-			spanfunc = spanfuncs[SPANDRAWFUNC_SPLAT];
+			spanfunctype = SPANDRAWFUNC_SPLAT;
 
 #ifdef SHITPLANESPARENCY
-		if ((spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT]) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
+		if ((spanfunctype == SPANDRAWFUNC_SPLAT) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
 #else
 		if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2))
 #endif
@@ -901,7 +903,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 		if (pl->ffloor->flags & FF_TRANSLUCENT)
 		{
-			spanfunc = spanfuncs[SPANDRAWFUNC_TRANS];
+			spanfunctype = SPANDRAWFUNC_TRANS;
 
 			// Hacked up support for alpha value in software mode Tails 09-24-2002
 			if (pl->ffloor->alpha < 12)
@@ -925,10 +927,10 @@ void R_DrawSinglePlane(visplane_t *pl)
 			else if (pl->ffloor->alpha < 243)
 				ds_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT);
 			else // Opaque, but allow transparent flat pixels
-				spanfunc = spanfuncs[SPANDRAWFUNC_SPLAT];
+				spanfunctype = SPANDRAWFUNC_SPLAT;
 
 #ifdef SHITPLANESPARENCY
-			if ((spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT]) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
+			if ((spanfunctype == SPANDRAWFUNC_SPLAT) != (pl->extra_colormap && (pl->extra_colormap->fog & 4)))
 #else
 			if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2))
 #endif
@@ -938,7 +940,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 		}
 		else if (pl->ffloor->flags & FF_FOG)
 		{
-			spanfunc = spanfuncs[SPANDRAWFUNC_FOG];
+			spanfunctype = SPANDRAWFUNC_FOG;
 			light = (pl->lightlevel >> LIGHTSEGSHIFT);
 		}
 		else light = (pl->lightlevel >> LIGHTSEGSHIFT);
@@ -953,9 +955,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 			INT32 top, bottom;
 
 			itswater = true;
-			if (spanfunc == spanfuncs[SPANDRAWFUNC_TRANS])
+			if (spanfunctype == SPANDRAWFUNC_TRANS)
 			{
-				spanfunc = spanfuncs[SPANDRAWFUNC_WATER];
+				spanfunctype = SPANDRAWFUNC_WATER;
 
 				// Copy the current scene, ugh
 				top = pl->high-8;
@@ -1032,8 +1034,8 @@ void R_DrawSinglePlane(visplane_t *pl)
 			if (R_CheckPowersOfTwo())
 			{
 				R_CheckFlatLength(ds_flatwidth * ds_flatheight);
-				if (spanfunc == spanfuncs[BASEDRAWFUNC])
-					spanfunc = spanfuncs[SPANDRAWFUNC_MMX];
+				if (spanfunctype == BASEDRAWFUNC)
+					spanfunctype = SPANDRAWFUNC_MMX;
 			}
 	}
 
@@ -1187,12 +1189,12 @@ void R_DrawSinglePlane(visplane_t *pl)
 		}
 #undef SFMULT
 
-		if (spanfunc == spanfuncs[SPANDRAWFUNC_TRANS])
-			spanfunc = spanfuncs[SPANDRAWFUNC_TILTEDTRANS];
-		else if (spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT])
-			spanfunc = spanfuncs[SPANDRAWFUNC_TILTEDSPLAT];
+		if (spanfunctype == SPANDRAWFUNC_TRANS)
+			spanfunctype = SPANDRAWFUNC_TILTEDTRANS;
+		else if (spanfunctype == SPANDRAWFUNC_SPLAT)
+			spanfunctype = SPANDRAWFUNC_TILTEDSPLAT;
 		else
-			spanfunc = spanfuncs[SPANDRAWFUNC_TILTED];
+			spanfunctype = SPANDRAWFUNC_TILTED;
 
 		planezlight = scalelight[light];
 	} else
@@ -1200,6 +1202,17 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 	planezlight = zlight[light];
 
+	// Use the correct span drawer depending on the powers-of-twoness
+	if (!ds_powersoftwo)
+	{
+		if (spanfuncs_npo2[spanfunctype])
+			spanfunc = spanfuncs_npo2[spanfunctype];
+		else
+			spanfunc = spanfuncs[spanfunctype];
+	}
+	else
+		spanfunc = spanfuncs[spanfunctype];
+
 	// set the maximum value for unsigned
 	pl->top[pl->maxx+1] = 0xffff;
 	pl->top[pl->minx-1] = 0xffff;
diff --git a/src/screen.c b/src/screen.c
index 5c88d8471..83421a1cc 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -46,6 +46,7 @@ void (*colfuncs[COLDRAWFUNC_MAX])(void);
 
 void (*spanfunc)(void);
 void (*spanfuncs[SPANDRAWFUNC_MAX])(void);
+void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
 
 // ------------------
 // global video state
@@ -133,6 +134,21 @@ void SCR_SetMode(void)
 		spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8;
 #endif
 
+		// Lactozilla: Non-powers-of-two
+		spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8;
+		spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8;
+		spanfuncs_npo2[SPANDRAWFUNC_SPLAT] = R_DrawSplat_NPO2_8;
+		spanfuncs_npo2[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_NPO2_8;
+		spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed
+		spanfuncs_npo2[SPANDRAWFUNC_MMX] = NULL; // Same
+#ifndef NOWATER
+		spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8;
+#endif
+#ifdef ESLOPE
+		spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8;
+		spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8;
+		spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8;
+#endif
 
 #ifdef RUSEASM
 		if (R_ASM)
diff --git a/src/screen.h b/src/screen.h
index ffed931fa..9a4d48dcf 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -152,6 +152,7 @@ enum
 
 extern void (*spanfunc)(void);
 extern void (*spanfuncs[SPANDRAWFUNC_MAX])(void);
+extern void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
 
 // -----
 // CPUID
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 0d1fa1a4b..b334f6313 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -438,6 +438,9 @@
     <ClCompile Include="..\r_draw8.c">
       <ExcludedFromBuild>true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\r_draw8_npo2.c">
+      <ExcludedFromBuild>true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="..\r_main.c" />
     <ClCompile Include="..\r_plane.c" />
 	<ClCompile Include="..\r_patch.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index cface6377..3f61e8709 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -837,6 +837,9 @@
     <ClCompile Include="..\r_draw8.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
+    <ClCompile Include="..\r_draw8_npo2.c">
+      <Filter>R_Rend</Filter>
+    </ClCompile>
     <ClCompile Include="..\r_main.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 7a79861b3..387d65da9 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -295,6 +295,9 @@
     <ClCompile Include="..\r_draw8.c">
       <ExcludedFromBuild>true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\r_draw8_npo2.c">
+      <ExcludedFromBuild>true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="..\r_main.c" />
     <ClCompile Include="..\r_plane.c" />
     <ClCompile Include="..\r_patch.c" />
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index 3d5c021d4..2f380c473 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -369,6 +369,9 @@
     <ClCompile Include="..\r_draw16.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
+    <ClCompile Include="..\r_draw8_npo2.c">
+      <Filter>R_Rend</Filter>
+    </ClCompile>
     <ClCompile Include="..\r_main.c">
       <Filter>R_Rend</Filter>
     </ClCompile>

From ad776e560c18644d8dadde16aac0dd98fa962633 Mon Sep 17 00:00:00 2001
From: Steel Titanium <steeltitanium1@gmail.com>
Date: Fri, 13 Dec 2019 16:36:33 -0500
Subject: [PATCH 47/52] Rework G_SetCustomExitVars to allow skipstats 2

---
 src/lua_baselib.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index b68d16c2a..018529722 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -2664,23 +2664,17 @@ static int lib_gSetCustomExitVars(lua_State *L)
 	// Supported:
 	//	G_SetCustomExitVars();			[reset to defaults]
 	//	G_SetCustomExitVars(int)		[nextmap override only]
-	//	G_SetCustomExitVars(bool)		[skipstats only]
-	//	G_SetCustomExitVars(int, bool)	[both of the above]
+	//	G_SetCustomExitVars(nil, int)	[skipstats only]
+	//	G_SetCustomExitVars(int, int)	[both of the above]
+
+	nextmapoverride = 0;
+	skipstats = 0;
+
 	if (n >= 1)
 	{
-		if (lua_isnumber(L, 1) || n >= 2)
-		{
-			nextmapoverride = (INT16)luaL_checknumber(L, 1);
-			lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available
-		}
-		skipstats = luaL_optinteger(L, 2, 0);
+		nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
+		skipstats = (INT16)luaL_optinteger(L, 2, 0);
 	}
-	else
-	{
-		nextmapoverride = 0;
-		skipstats = 0;
-	}
-	// ---
 
 	return 0;
 }

From a27a225a81b58acb8443b576885e6bb713949e6d Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Fri, 13 Dec 2019 19:02:36 -0300
Subject: [PATCH 48/52] Remove SPANDRAWFUNC_MMX, as it's not needed anymore.

---
 src/r_plane.c | 6 ------
 src/screen.c  | 4 +---
 src/screen.h  | 1 -
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/src/r_plane.c b/src/r_plane.c
index 3745c28be..1dd487b48 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -1008,8 +1008,6 @@ void R_DrawSinglePlane(visplane_t *pl)
 			R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum));
 			// Raw flats always have dimensions that are powers-of-two numbers.
 			ds_powersoftwo = true;
-			if (spanfunc == spanfuncs[BASEDRAWFUNC])
-				spanfunc = spanfuncs[SPANDRAWFUNC_MMX];
 			break;
 		default:
 			switch (type)
@@ -1032,11 +1030,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 			}
 			// Check if this texture or patch has power-of-two dimensions.
 			if (R_CheckPowersOfTwo())
-			{
 				R_CheckFlatLength(ds_flatwidth * ds_flatheight);
-				if (spanfunctype == BASEDRAWFUNC)
-					spanfunctype = SPANDRAWFUNC_MMX;
-			}
 	}
 
 	if (light >= LIGHTLEVELS)
diff --git a/src/screen.c b/src/screen.c
index 83421a1cc..7a2e1a455 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -124,7 +124,6 @@ void SCR_SetMode(void)
 		spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat_8;
 		spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_8;
 		spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
-		spanfuncs[SPANDRAWFUNC_MMX] = spanfuncs[BASEDRAWFUNC];
 #ifndef NOWATER
 		spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8;
 #endif
@@ -140,7 +139,6 @@ void SCR_SetMode(void)
 		spanfuncs_npo2[SPANDRAWFUNC_SPLAT] = R_DrawSplat_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed
-		spanfuncs_npo2[SPANDRAWFUNC_MMX] = NULL; // Same
 #ifndef NOWATER
 		spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8;
 #endif
@@ -159,7 +157,7 @@ void SCR_SetMode(void)
 				//colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
 				//colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
 				colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_MMX;
-				spanfuncs[SPANDRAWFUNC_MMX] = R_DrawSpan_8_MMX;
+				spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8_MMX;
 			}
 			else
 			{
diff --git a/src/screen.h b/src/screen.h
index 9a4d48dcf..eb0042be6 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -133,7 +133,6 @@ extern void (*colfuncs[COLDRAWFUNC_MAX])(void);
 enum
 {
 	SPANDRAWFUNC_BASE = BASEDRAWFUNC,
-	SPANDRAWFUNC_MMX,
 	SPANDRAWFUNC_TRANS,
 	SPANDRAWFUNC_SPLAT,
 	SPANDRAWFUNC_TRANSSPLAT,

From 7f092b884b7eb0a89a5b86b2a832a925bab22d80 Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Thu, 12 Dec 2019 22:32:19 -0300
Subject: [PATCH 49/52] Initialise the variable, obviously

---
 src/hardware/hw_md2.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 61afee0ab..fea7f50bd 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -743,6 +743,8 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 				UINT8 ialpha = 255 - blendimage->s.alpha, balpha = blendimage->s.alpha;
 				RGBA_t icolor = *image, bcolor;
 
+				memset(&bcolor, 0x00, sizeof(RGBA_t));
+
 				if (blendimage->s.alpha)
 				{
 					bcolor.s.blue = 0;

From 2a22adaa601d71b3abe0180332e05e5a3de330ef Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Sat, 14 Dec 2019 12:55:11 -0800
Subject: [PATCH 50/52] Oops C90

---
 src/v_video.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/v_video.c b/src/v_video.c
index dad8e8513..c6ec22767 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -311,11 +311,12 @@ const UINT8 correctiontable[256] =
 // keep a copy of the palette so that we can get the RGB value for a color index at any time.
 static void LoadPalette(const char *lumpname)
 {
-	Cubeapply = InitCube();
 	lumpnum_t lumpnum = W_GetNumForName(lumpname);
 	size_t i, palsize = W_LumpLength(lumpnum)/3;
 	UINT8 *pal;
 
+	Cubeapply = InitCube();
+
 	Z_Free(pLocalPalette);
 	Z_Free(pMasterPalette);
 

From c1d54007e4f5c8386a6ac02edb5c5259a812c567 Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Sat, 14 Dec 2019 13:30:10 -0800
Subject: [PATCH 51/52] Fix C90 error from NOHW

---
 src/w_wad.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/w_wad.c b/src/w_wad.c
index 801f50edd..950294b1f 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -1516,8 +1516,8 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 #ifdef HWRENDER
 	// Software-only compile cache the data without conversion
 	if (rendermode == render_soft || rendermode == render_none)
-	{
 #endif
+	{
 		lumpcache_t *lumpcache = wadfiles[wad]->patchcache;
 		if (!lumpcache[lump])
 		{
@@ -1551,8 +1551,8 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 			Z_ChangeTag(lumpcache[lump], tag);
 
 		return lumpcache[lump];
-#ifdef HWRENDER
 	}
+#ifdef HWRENDER
 
 	grPatch = HWR_GetCachedGLPatchPwad(wad, lump);
 

From 4d87bcca1375ecf1b91f0a59aa16d83a3345a64a Mon Sep 17 00:00:00 2001
From: Jaime Passos <lazymyuutsu@gmail.com>
Date: Sat, 14 Dec 2019 19:50:40 -0300
Subject: [PATCH 52/52] Move position of R_PlaneRipple in the file so this
 looks more organised

---
 src/r_plane.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/src/r_plane.c b/src/r_plane.c
index 88214d5f7..3214fa23d 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -117,17 +117,10 @@ void R_InitPlanes(void)
 }
 
 //
-// R_MapPlane
+// Water ripple effect!!
+// Needs the height of the plane, and the vertical position of the span.
+// Sets ripple_xfrac and ripple_yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted.
 //
-// Uses global vars:
-//  basexscale
-//  baseyscale
-//  centerx
-//  viewx
-//  viewy
-//  viewsin
-//  viewcos
-//  viewheight
 
 #ifndef NOWATER
 INT32 ds_bgofs;
@@ -152,6 +145,19 @@ static void R_PlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight)
 }
 #endif
 
+//
+// R_MapPlane
+//
+// Uses global vars:
+//  basexscale
+//  baseyscale
+//  centerx
+//  viewx
+//  viewy
+//  viewsin
+//  viewcos
+//  viewheight
+
 void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
 {
 	angle_t angle, planecos, planesin;