From e15ffd2bc8a76ede6ce15973b52ba78bc6bd17ca Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Sun, 20 Oct 2019 20:21:22 -0700
Subject: [PATCH] Optimize texture/patch/png/flat flat caching

SIGSEGV in the case where you have a TEXTURES entry, but no texture or flat,
has been fixed.

Missing flats for now yield a HOM instead of REDFLR as well.

OpenGL also doesn't work yet. And I'm too tired for now to bother with it.
---
 src/p_setup.c | 159 ++++++++++++++++++++++++++++----------------------
 src/p_setup.h |  39 +++++++++++--
 src/p_spec.c  |  22 +++----
 src/r_data.c  |  42 -------------
 src/r_plane.c |  85 ++++++++++++++-------------
 5 files changed, 179 insertions(+), 168 deletions(-)

diff --git a/src/p_setup.c b/src/p_setup.c
index c83c8cd5ce..ffd8de33ff 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -546,52 +546,110 @@ size_t P_PrecacheLevelFlats(void)
 	//SoM: 4/18/2000: New flat code to make use of levelflats.
 	for (i = 0; i < numlevelflats; i++)
 	{
-		lump = levelflats[i].lumpnum;
-		if (devparm)
-			flatmemory += W_LumpLength(lump);
-		R_GetFlat(lump);
+		if (levelflats[i].type == LEVELFLAT_FLAT)
+		{
+			lump = levelflats[i].u.flat.lumpnum;
+			if (devparm)
+				flatmemory += W_LumpLength(lump);
+			R_GetFlat(lump);
+		}
 	}
 	return flatmemory;
 }
 
-// Auxiliary function. Find a flat in the active wad files,
-// allocate an id for it, and set the levelflat (to speedup search)
-INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
+/*
+levelflat refers to an array of level flats,
+or NULL if we want to allocate it now.
+*/
+static INT32
+Ploadflat (levelflat_t *levelflat, const char *flatname)
 {
-	size_t i;
-
-	// Scan through the already found flats, break if it matches.
-	for (i = 0; i < numlevelflats; i++, levelflat++)
-		if (strnicmp(levelflat->name, flatname, 8) == 0)
-			break;
+	UINT8         buffer[8];
 
-	// If there is no match, make room for a new flat.
-	if (i == numlevelflats)
-	{
-		// Store the name.
-		strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
-		strupr(levelflat->name);
+	lumpnum_t    flatnum;
+	int       texturenum;
 
-		// store the flat lump number
-		levelflat->lumpnum = R_GetFlatNumForName(flatname);
-		levelflat->texturenum = R_CheckTextureNumForName(flatname);
-		levelflat->lasttexturenum = levelflat->texturenum;
+	size_t i;
 
-		levelflat->baselumpnum = LUMPERROR;
-		levelflat->basetexturenum = -1;
+	if (levelflat)
+	{
+		// Scan through the already found flats, return if it matches.
+		for (i = 0; i < numlevelflats; i++)
+		{
+			if (strnicmp(levelflat[i].name, flatname, 8) == 0)
+				return i;
+		}
+	}
 
 #ifndef ZDEBUG
-		CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
+	CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
 #endif
 
-		numlevelflats++;
+	if (numlevelflats >= MAXLEVELFLATS)
+		I_Error("Too many flats in level\n");
 
-		if (numlevelflats >= MAXLEVELFLATS)
-			I_Error("Too many flats in level\n");
+	if (levelflat)
+		levelflat += numlevelflats;
+	else
+	{
+		// allocate new flat memory
+		levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
+		levelflat  = levelflats + numlevelflats;
 	}
 
-	// level flat id
-	return (INT32)i;
+	// Store the name.
+	strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
+	strupr(levelflat->name);
+
+	/* If we can't find a flat, try looking for a texture! */
+	if (( flatnum = R_GetFlatNumForName(flatname) ) == LUMPERROR)
+	{
+		if (( texturenum = R_CheckTextureNumForName(flatname) ) == -1)
+		{
+			/* we can handle REDWALL later */
+			levelflat->type = LEVELFLAT_NONE;
+		}
+		else
+		{
+			levelflat->type = LEVELFLAT_TEXTURE;
+			levelflat->u.texture.    num = texturenum;
+			levelflat->u.texture.lastnum = texturenum;
+			/* start out unanimated */
+			levelflat->u.texture.basenum = -1;
+		}
+	}
+	else
+	{
+		/* This could be a flat, patch, or PNG. */
+		if (R_CheckIfPatch(flatnum))
+			levelflat->type = LEVELFLAT_PATCH;
+		else
+		{
+#ifndef NO_PNG_LUMPS
+			/*
+			Only need eight bytes for PNG headers.
+			FIXME: Put this elsewhere.
+			*/
+			W_ReadLumpHeader(flatnum, buffer, 8, 0);
+			if (R_IsLumpPNG(buffer, W_LumpLength(flatnum)))
+				levelflat->type = LEVELFLAT_PNG;
+			else
+#endif/*NO_PNG_LUMPS*/
+				levelflat->type = LEVELFLAT_FLAT;/* phew */
+		}
+
+		levelflat->u.flat.    lumpnum = flatnum;
+		levelflat->u.flat.baselumpnum = LUMPERROR;
+	}
+
+	return ( numlevelflats++ );
+}
+
+// Auxiliary function. Find a flat in the active wad files,
+// allocate an id for it, and set the levelflat (to speedup search)
+INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
+{
+	return Ploadflat(levelflat, flatname);
 }
 
 // help function for Lua and $$$.sav reading
@@ -600,44 +658,7 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
 //
 INT32 P_AddLevelFlatRuntime(const char *flatname)
 {
-	size_t i;
-	levelflat_t *levelflat = levelflats;
-
-	//
-	//  first scan through the already found flats
-	//
-	for (i = 0; i < numlevelflats; i++, levelflat++)
-		if (strnicmp(levelflat->name,flatname,8)==0)
-			break;
-
-	// that flat was already found in the level, return the id
-	if (i == numlevelflats)
-	{
-		// allocate new flat memory
-		levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
-		levelflat = levelflats+i;
-
-		// store the name
-		strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
-		strupr(levelflat->name);
-
-		// store the flat lump number
-		levelflat->lumpnum = R_GetFlatNumForName(flatname);
-		levelflat->texturenum = R_CheckTextureNumForName(flatname);
-		levelflat->lasttexturenum = levelflat->texturenum;
-
-		levelflat->baselumpnum = LUMPERROR;
-		levelflat->basetexturenum = -1;
-
-#ifndef ZDEBUG
-		CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
-#endif
-
-		numlevelflats++;
-	}
-
-	// level flat id
-	return (INT32)i;
+	return Ploadflat(0, flatname);
 }
 
 // help function for $$$.sav checking
diff --git a/src/p_setup.h b/src/p_setup.h
index 7e3a149eb8..d8787073b0 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -30,20 +30,51 @@ extern boolean levelloading;
 extern UINT8 levelfadecol;
 
 extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame
+
+/* for levelflat type */
+enum
+{
+	LEVELFLAT_NONE,/* HOM time my friend */
+	LEVELFLAT_FLAT,
+	LEVELFLAT_PATCH,
+#ifndef NO_PNG_LUMPS
+	LEVELFLAT_PNG,
+#endif
+	LEVELFLAT_TEXTURE,
+};
+
 //
 // MAP used flats lookup table
 //
 typedef struct
 {
 	char name[9]; // resource name from wad
-	lumpnum_t lumpnum; // lump number of the flat
-	INT32 texturenum, lasttexturenum; // texture number of the flat
+
+	UINT8  type;
+	union
+	{
+		struct
+		{
+			lumpnum_t     lumpnum; // lump number of the flat
+			// for flat animation
+			lumpnum_t baselumpnum;
+		}
+		flat;
+		struct
+		{
+			INT32             num;
+			INT32         lastnum; // texture number of the flat
+			// for flat animation
+			INT32         basenum;
+		}
+		texture;
+	}
+	u;
+
 	UINT16 width, height;
 	fixed_t topoffset, leftoffset;
 
 	// for flat animation
-	lumpnum_t baselumpnum;
-	INT32 basetexturenum;
 	INT32 animseq; // start pos. in the anim sequence
 	INT32 numpics;
 	INT32 speed;
diff --git a/src/p_spec.c b/src/p_spec.c
index ebee50a45d..3c987ac688 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -464,11 +464,11 @@ static inline void P_FindAnimatedFlat(INT32 animnum)
 	for (i = 0; i < numlevelflats; i++, foundflats++)
 	{
 		// is that levelflat from the flat anim sequence ?
-		if ((anims[animnum].istexture) && (foundflats->texturenum != 0 && foundflats->texturenum != -1)
-			&& ((UINT16)foundflats->texturenum >= startflatnum && (UINT16)foundflats->texturenum <= endflatnum))
+		if ((anims[animnum].istexture) && (foundflats->u.texture.num != 0 && foundflats->u.texture.num != -1)
+			&& ((UINT16)foundflats->u.texture.num >= startflatnum && (UINT16)foundflats->u.texture.num <= endflatnum))
 		{
-			foundflats->basetexturenum = startflatnum;
-			foundflats->animseq = foundflats->texturenum - startflatnum;
+			foundflats->u.texture.basenum = startflatnum;
+			foundflats->animseq = foundflats->u.texture.num - startflatnum;
 			foundflats->numpics = endflatnum - startflatnum + 1;
 			foundflats->speed = anims[animnum].speed;
 
@@ -476,10 +476,10 @@ static inline void P_FindAnimatedFlat(INT32 animnum)
 					atoi(sizeu1(i)), foundflats->name, foundflats->animseq,
 					foundflats->numpics,foundflats->speed);
 		}
-		else if (foundflats->lumpnum >= startflatnum && foundflats->lumpnum <= endflatnum)
+		else if (foundflats->u.flat.lumpnum >= startflatnum && foundflats->u.flat.lumpnum <= endflatnum)
 		{
-			foundflats->baselumpnum = startflatnum;
-			foundflats->animseq = foundflats->lumpnum - startflatnum;
+			foundflats->u.flat.baselumpnum = startflatnum;
+			foundflats->animseq = foundflats->u.flat.lumpnum - startflatnum;
 			foundflats->numpics = endflatnum - startflatnum + 1;
 			foundflats->speed = anims[animnum].speed;
 
@@ -5578,11 +5578,11 @@ void P_UpdateSpecials(void)
 		if (foundflats->speed) // it is an animated flat
 		{
 			// update the levelflat texture number
-			if (foundflats->basetexturenum != -1)
-				foundflats->texturenum = foundflats->basetexturenum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
+			if (foundflats->u.texture.basenum != -1)
+				foundflats->u.texture.num = foundflats->u.texture.basenum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
 			// update the levelflat lump number
-			else if (foundflats->baselumpnum != LUMPERROR)
-				foundflats->lumpnum = foundflats->baselumpnum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
+			else if (foundflats->u.flat.baselumpnum != LUMPERROR)
+				foundflats->u.flat.lumpnum = foundflats->u.flat.baselumpnum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
 		}
 	}
 }
diff --git a/src/r_data.c b/src/r_data.c
index f1d19a219f..610568d8fe 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1446,48 +1446,6 @@ lumpnum_t R_GetFlatNumForName(const char *name)
 		lump = LUMPERROR;
 	}
 
-	// Detect textures
-	if (lump == LUMPERROR)
-	{
-		// Scan wad files backwards so patched textures take preference.
-		for (i = numwadfiles - 1; i >= 0; i--)
-		{
-			switch (wadfiles[i]->type)
-			{
-			case RET_WAD:
-				if ((start = W_CheckNumForNamePwad("TX_START", (UINT16)i, 0)) == INT16_MAX)
-					continue;
-				if ((end = W_CheckNumForNamePwad("TX_END", (UINT16)i, start)) == INT16_MAX)
-					continue;
-				break;
-			case RET_PK3:
-				if ((start = W_CheckNumForFolderStartPK3("Textures/", i, 0)) == INT16_MAX)
-					continue;
-				if ((end = W_CheckNumForFolderEndPK3("Textures/", i, start)) == INT16_MAX)
-					continue;
-				break;
-			default:
-				continue;
-			}
-
-			// Now find lump with specified name in that range.
-			lump = W_CheckNumForNamePwad(name, (UINT16)i, start);
-			if (lump < end)
-			{
-				lump += (i<<16); // found it, in our constraints
-				break;
-			}
-			lump = LUMPERROR;
-		}
-	}
-
-	if (lump == LUMPERROR)
-	{
-		if (strcmp(name, SKYFLATNAME))
-			CONS_Debug(DBG_SETUP, "R_GetFlatNumForName: Could not find flat %.8s\n", name);
-		lump = W_CheckNumForName("REDFLR");
-	}
-
 	return lump;
 }
 
diff --git a/src/r_plane.c b/src/r_plane.c
index 34debeea70..8aab50a688 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -753,9 +753,9 @@ static UINT8 *R_GenerateFlat(UINT16 width, UINT16 height)
 static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng)
 {
 	UINT8 *flat;
-	textureflat_t *texflat = &texflats[levelflat->texturenum];
+	textureflat_t *texflat = &texflats[levelflat->u.texture.num];
 	patch_t *patch = NULL;
-	boolean texturechanged = (leveltexture ? (levelflat->texturenum != levelflat->lasttexturenum) : false);
+	boolean texturechanged = (leveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false);
 
 	// Check if the texture changed.
 	if (leveltexture && (!texturechanged))
@@ -777,12 +777,12 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo
 		// Level texture
 		if (leveltexture)
 		{
-			texture_t *texture = textures[levelflat->texturenum];
+			texture_t *texture = textures[levelflat->u.texture.num];
 			texflat->width = ds_flatwidth = texture->width;
 			texflat->height = ds_flatheight = texture->height;
 
 			texflat->flat = R_GenerateFlat(ds_flatwidth, ds_flatheight);
-			R_TextureToFlat(levelflat->texturenum, texflat->flat);
+			R_TextureToFlat(levelflat->u.texture.num, texflat->flat);
 			flat = texflat->flat;
 
 			levelflat->flatpatch = flat;
@@ -796,7 +796,7 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo
 #ifndef NO_PNG_LUMPS
 			if (ispng)
 			{
-				levelflat->flatpatch = R_PNGToFlat(&levelflat->width, &levelflat->height, ds_source, W_LumpLength(levelflat->lumpnum));
+				levelflat->flatpatch = R_PNGToFlat(&levelflat->width, &levelflat->height, ds_source, W_LumpLength(levelflat->u.flat.lumpnum));
 				levelflat->topoffset = levelflat->leftoffset = 0;
 				ds_flatwidth = levelflat->width;
 				ds_flatheight = levelflat->height;
@@ -826,7 +826,7 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo
 	xoffs += levelflat->leftoffset;
 	yoffs += levelflat->topoffset;
 
-	levelflat->lasttexturenum = levelflat->texturenum;
+	levelflat->u.texture.lastnum = levelflat->u.texture.num;
 	return flat;
 }
 
@@ -836,10 +836,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 	INT32 light = 0;
 	INT32 x;
 	INT32 stop, angle;
-	size_t size;
 	ffloor_t *rover;
 	levelflat_t *levelflat;
-	boolean rawflat = false;
+	int type;
 
 	if (!(pl->minx <= pl->maxx))
 		return;
@@ -985,43 +984,45 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 	currentplane = pl;
 	levelflat = &levelflats[pl->picnum];
-	size = W_LumpLength(levelflat->lumpnum);
-	ds_source = (UINT8 *)W_CacheLumpNum(levelflat->lumpnum, PU_STATIC); // Stay here until Z_ChangeTag
 
-	// Check if the flat is actually a wall texture.
-	if (levelflat->texturenum != 0 && levelflat->texturenum != -1)
-		flat = R_GetTextureFlat(levelflat, true, false);
+	/* :james: */
+	type = levelflat->type;
+	switch (type)
+	{
+		case LEVELFLAT_NONE:
+			return;
+		case LEVELFLAT_FLAT:
+			ds_source = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE);
+			R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum));
+			// Raw flats always have dimensions that are powers-of-two numbers.
+			ds_powersoftwo = true;
+			break;
+		default:
+			switch (type)
+			{
+				case LEVELFLAT_TEXTURE:
+					/* Textures get cached differently and don't need ds_source */
+					ds_source = R_GetTextureFlat(levelflat, true, false);
+					break;
+				default:
+					ds_source = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_STATIC);
+					flat      = R_GetTextureFlat(levelflat, false,
 #ifndef NO_PNG_LUMPS
-	// Maybe it's a PNG?!
-	else if (R_IsLumpPNG(ds_source, size))
-		flat = R_GetTextureFlat(levelflat, false, true);
+							( type == LEVELFLAT_PNG )
+#else
+							false
 #endif
-	// Maybe it's just a patch, then?
-	else if (R_CheckIfPatch(levelflat->lumpnum))
-		flat = R_GetTextureFlat(levelflat, false, false);
-	// It's a raw flat.
-	else
-	{
-		rawflat = true;
-		R_CheckFlatLength(size);
-		flat = ds_source;
-	}
-
-	Z_ChangeTag(ds_source, PU_CACHE);
-	ds_source = flat;
-
-	if (ds_source == NULL)
-		return;
-
-	// Raw flats always have dimensions that are powers-of-two numbers.
-	if (rawflat)
-		ds_powersoftwo = true;
-	// Otherwise, check if this texture or patch has such dimensions.
-	else if (R_CheckPowersOfTwo())
-	{
-		R_CheckFlatLength(ds_flatwidth * ds_flatheight);
-		if (spanfunc == basespanfunc)
-			spanfunc = mmxspanfunc;
+					);
+					Z_ChangeTag(ds_source, PU_CACHE);
+					ds_source = flat;
+			}
+			// Check if this texture or patch has power-of-two dimensions.
+			if (R_CheckPowersOfTwo())
+			{
+				R_CheckFlatLength(ds_flatwidth * ds_flatheight);
+				if (spanfunc == basespanfunc)
+					spanfunc = mmxspanfunc;
+			}
 	}
 
 	if (light >= LIGHTLEVELS)
-- 
GitLab