diff --git a/src/doomdef.h b/src/doomdef.h
index 676c86e0d68b8c844c6edf042804f3a68589b048..1f28f7a80e0a1a553ed5bc0f9075e23732d844f4 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -620,8 +620,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 ///      	SRB2CB itself ported this from PrBoom+
 #define NEWCLIP
 
+/// PNG support
 #ifndef HAVE_PNG
 #define NO_PNG_LUMPS
 #endif
 
+/// Render flats on walls
+#define WALLFLATS
+
 #endif // __DOOMDEF__
diff --git a/src/p_spec.c b/src/p_spec.c
index 7fcdfd1e3eb1faae57794285909679ff64016589..9ab50d9476263a8e99f37b5ced38ef0963f54257 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -464,7 +464,7 @@ 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->u.texture.num != 0 && foundflats->u.texture.num != -1)
+		if ((anims[animnum].istexture) && (foundflats->type == LEVELFLAT_TEXTURE)
 			&& ((UINT16)foundflats->u.texture.num >= startflatnum && (UINT16)foundflats->u.texture.num <= endflatnum))
 		{
 			foundflats->u.texture.basenum = startflatnum;
diff --git a/src/r_data.c b/src/r_data.c
index fa5e5c43b52473099c619a8ec9927529cfaf55ff..ac98aae77778fdcd40b65d98a68efab3e85d1ca5 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -456,6 +456,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 	texture_t *texture;
 	texpatch_t *patch;
 	patch_t *realpatch;
+	UINT8 *pdata;
 	int x, x1, x2, i, width, height;
 	size_t blocksize;
 	column_t *patchcol;
@@ -483,14 +484,17 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 		wadnum = patch->wad;
 		lumpnum = patch->lump;
 		lumplength = W_LumpLengthPwad(wadnum, lumpnum);
-		realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); // can't use W_CachePatchNumPwad because OpenGL
+		pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
+		realpatch = (patch_t *)pdata;
 
 #ifndef NO_PNG_LUMPS
 		if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
-			realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false);
 			goto multipatch;
-		}
+#endif
+
+#ifdef WALLFLATS
+		if (texture->type == TEXTURETYPE_FLAT)
+			goto multipatch;
 #endif
 
 		// Check the patch for holes.
@@ -582,6 +586,11 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 #ifndef NO_PNG_LUMPS
 		if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
 			realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false);
+		else
+#endif
+#ifdef WALLFLATS
+		if (texture->type == TEXTURETYPE_FLAT)
+			realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false);
 #endif
 
 		x1 = patch->originx;
@@ -773,6 +782,39 @@ void R_LoadTextures(void)
 		{
 			numtextures += (UINT32)(texend - texstart);
 		}
+
+#ifdef WALLFLATS
+		// Count flats
+		if (wadfiles[w]->type == RET_PK3)
+		{
+			texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
+			texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
+		}
+		else
+		{
+			texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0);
+			texend = W_CheckNumForNamePwad("F_END", (UINT16)w, 0);
+		}
+
+		if (texstart == INT16_MAX || texend == INT16_MAX)
+			continue;
+
+		texstart++; // Do not count the first marker
+
+		// PK3s have subfolders, so we can't just make a simple sum
+		if (wadfiles[w]->type == RET_PK3)
+		{
+			for (j = texstart; j < texend; j++)
+			{
+				if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it
+					numtextures++;
+			}
+		}
+		else // Add all the textures between F_START and F_END
+		{
+			numtextures += (UINT32)(texend - texstart);
+		}
+#endif
 	}
 
 	// If no textures found by this point, bomb out
@@ -866,6 +908,8 @@ void R_LoadTextures(void)
 				texture->width = SHORT(patchlump->width);
 				texture->height = SHORT(patchlump->height);
 			}
+
+			texture->type = TEXTURETYPE_SINGLEPATCH;
 			texture->patchcount = 1;
 			texture->holes = false;
 			texture->flip = 0;
@@ -884,6 +928,106 @@ void R_LoadTextures(void)
 			textureheight[i] = texture->height << FRACBITS;
 			i++;
 		}
+
+#ifdef WALLFLATS
+		// Yes
+		if (wadfiles[w]->type == RET_PK3)
+		{
+			texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
+			texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
+		}
+		else
+		{
+			texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0);
+			texend = W_CheckNumForNamePwad("F_END", (UINT16)w, 0);
+		}
+
+		if (texstart == INT16_MAX || texend == INT16_MAX)
+			continue;
+
+		texstart++; // Do not count the first marker
+
+		// Work through each lump between the markers in the WAD.
+		for (j = 0; j < (texend - texstart); j++)
+		{
+			UINT8 *flatlump;
+			UINT16 wadnum = (UINT16)w;
+			lumpnum_t lumpnum = texstart + j;
+			size_t lumplength;
+			size_t flatsize = 0;
+
+			if (wadfiles[w]->type == RET_PK3)
+			{
+				if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
+					continue; // If it is then SKIP IT
+			}
+
+			flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
+			lumplength = W_LumpLengthPwad(wadnum, lumpnum);
+
+			switch (lumplength)
+			{
+				case 4194304: // 2048x2048 lump
+					flatsize = 2048;
+					break;
+				case 1048576: // 1024x1024 lump
+					flatsize = 1024;
+					break;
+				case 262144:// 512x512 lump
+					flatsize = 512;
+					break;
+				case 65536: // 256x256 lump
+					flatsize = 256;
+					break;
+				case 16384: // 128x128 lump
+					flatsize = 128;
+					break;
+				case 1024: // 32x32 lump
+					flatsize = 32;
+					break;
+				default: // 64x64 lump
+					flatsize = 64;
+					break;
+			}
+
+			//CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize);
+			texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
+
+			// Set texture properties.
+			M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
+
+#ifndef NO_PNG_LUMPS
+			if (R_IsLumpPNG((UINT8 *)flatlump, lumplength))
+			{
+				INT16 width, height;
+				R_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength);
+				texture->width = width;
+				texture->height = height;
+			}
+			else
+#endif
+				texture->width = texture->height = flatsize;
+
+			texture->type = TEXTURETYPE_FLAT;
+			texture->patchcount = 1;
+			texture->holes = false;
+			texture->flip = 0;
+
+			// Allocate information for the texture's patches.
+			patch = &texture->patches[0];
+
+			patch->originx = patch->originy = 0;
+			patch->wad = (UINT16)w;
+			patch->lump = texstart + j;
+			patch->flip = 0;
+
+			Z_Unlock(flatlump);
+
+			texturewidth[i] = texture->width;
+			textureheight[i] = texture->height << FRACBITS;
+			i++;
+		}
+#endif
 	}
 }
 
@@ -1195,6 +1339,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture)
 			M_Memcpy(resultTexture->name, newTextureName, 8);
 			resultTexture->width = newTextureWidth;
 			resultTexture->height = newTextureHeight;
+			resultTexture->type = TEXTURETYPE_COMPOSITE;
 		}
 		Z_Free(texturesToken);
 		texturesToken = M_GetToken(NULL);
diff --git a/src/r_data.h b/src/r_data.h
index e71d457663e1eabe06a10cb7c4c7911379c87b0c..1d58a7815d77603c94700d5135679f7525f025d4 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -45,6 +45,17 @@ typedef struct
 	enum patchalphastyle style;
 } texpatch_t;
 
+// texture type
+enum
+{
+	TEXTURETYPE_UNKNOWN,
+	TEXTURETYPE_SINGLEPATCH,
+	TEXTURETYPE_COMPOSITE,
+#ifdef WALLFLATS
+	TEXTURETYPE_FLAT,
+#endif
+};
+
 // A maptexturedef_t describes a rectangular texture,
 //  which is composed of one or more mappatch_t structures
 //  that arrange graphic patches.
@@ -52,6 +63,7 @@ typedef struct
 {
 	// Keep name for switch changing, etc.
 	char name[8];
+	UINT8 type; // TEXTURETYPE_
 	INT16 width, height;
 	boolean holes;
 	UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both