diff --git a/src/p_setup.c b/src/p_setup.c
index 1061dbd0c371143559e45494097b57e533a232cf..97bace8608a05668cc17d5b177ba7a2dcdf82a46 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -564,8 +564,11 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
 
 		// store the flat lump number
 		levelflat->lumpnum = R_GetFlatNumForName(flatname);
-		// Lactozilla
 		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);
diff --git a/src/p_setup.h b/src/p_setup.h
index eda6066d350da2663d8f5bf790a201c456c6c89a..824584be7b3cd6ba4e38b37474619c482e301a63 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -36,20 +36,22 @@ 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
+	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;
 
-	// Lactozilla
+	// for patchflats
 	UINT8 *flatpatch;
-	UINT16 width, height;
-	fixed_t topoffset, leftoffset;
-	INT32 texturenum;
 
 #ifdef ESLOPE
+	// rescaled version of the above
 	UINT8 *resizedflat;
 	UINT16 resizedwidth, resizedheight;
 #endif
diff --git a/src/p_spec.c b/src/p_spec.c
index 60d78432407a1399e8110cd92761712f5dacc4d3..7fe18eec12e22e2f785187979c8e7422b5f7ade9 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -584,7 +584,19 @@ static inline void P_FindAnimatedFlat(INT32 animnum)
 	for (i = 0; i < numlevelflats; i++, foundflats++)
 	{
 		// is that levelflat from the flat anim sequence ?
-		if (foundflats->lumpnum >= startflatnum && foundflats->lumpnum <= endflatnum)
+		if ((anims[animnum].istexture) && (foundflats->texturenum != 0 && foundflats->texturenum != -1)
+			&& ((UINT16)foundflats->texturenum >= startflatnum && (UINT16)foundflats->texturenum <= endflatnum))
+		{
+			foundflats->basetexturenum = startflatnum;
+			foundflats->animseq = foundflats->texturenum - startflatnum;
+			foundflats->numpics = endflatnum - startflatnum + 1;
+			foundflats->speed = anims[animnum].speed;
+
+			CONS_Debug(DBG_SETUP, "animflat: #%03d name:%.8s animseq:%d numpics:%d speed:%d\n",
+					atoi(sizeu1(i)), foundflats->name, foundflats->animseq,
+					foundflats->numpics,foundflats->speed);
+		}
+		else if (foundflats->lumpnum >= startflatnum && foundflats->lumpnum <= endflatnum)
 		{
 			foundflats->baselumpnum = startflatnum;
 			foundflats->animseq = foundflats->lumpnum - startflatnum;
@@ -608,10 +620,7 @@ void P_SetupLevelFlatAnims(void)
 
 	// the original game flat anim sequences
 	for (i = 0; anims[i].istexture != -1; i++)
-	{
-		if (!anims[i].istexture)
-			P_FindAnimatedFlat(i);
-	}
+		P_FindAnimatedFlat(i);
 }
 
 //
@@ -4794,9 +4803,12 @@ 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);
 			// update the levelflat lump number
-			foundflats->lumpnum = foundflats->baselumpnum +
-				((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
+			else if (foundflats->baselumpnum != LUMPERROR)
+				foundflats->lumpnum = foundflats->baselumpnum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
 		}
 	}
 }
diff --git a/src/r_data.c b/src/r_data.c
index 00d8de6295ed9d980aa9e78df8742211aae3999f..4157a885001c7f5a44ed589538103cffb7222603 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -98,6 +98,7 @@ INT32 numtextures = 0; // total number of textures found,
 // size of following tables
 
 texture_t **textures = NULL;
+textureflat_t *texflats = NULL;
 static UINT32 **texturecolumnofs; // column offset lookup table for each texture
 static UINT8 **texturecache; // graphics data for each generated full-size texture
 
@@ -395,6 +396,7 @@ void R_LoadTextures(void)
 		}
 		Z_Free(texturetranslation);
 		Z_Free(textures);
+		Z_Free(texflats);
 	}
 
 	// Load patches and textures.
@@ -440,6 +442,7 @@ void R_LoadTextures(void)
 	// Allocate memory and initialize to 0 for all the textures we are initialising.
 	// There are actually 5 buffers allocated in one for convenience.
 	textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL);
+	texflats = Z_Calloc((numtextures * sizeof(*texflats)), PU_STATIC, NULL);
 
 	// Allocate texture column offset table.
 	texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *)));
@@ -1015,10 +1018,10 @@ lumpnum_t R_GetFlatNumForName(const char *name)
 		lump = LUMPERROR;
 	}
 
-	// Lactozilla
+	// Detect textures
 	if (lump == LUMPERROR)
 	{
-		// Scan wad files backwards so patched flats take preference.
+		// Scan wad files backwards so patched textures take preference.
 		for (i = numwadfiles - 1; i >= 0; i--)
 		{
 			switch (wadfiles[i]->type)
@@ -1683,7 +1686,6 @@ boolean R_CheckIfPatch(lumpnum_t lump)
 	return result;
 }
 
-// Lactozilla
 void R_FlatPatch(patch_t *patch, UINT8 *flat)
 {
 	fixed_t col, ofs;
diff --git a/src/r_data.h b/src/r_data.h
index 8cb41cd2ff36ec2a351ebd5141da6631bfb0bfd0..855daa06dbeb41797ad02505482b497746a8030f 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -48,8 +48,20 @@ typedef struct
 	texpatch_t patches[0];
 } texture_t;
 
+typedef struct
+{
+	UINT8 *flat;
+	INT16 width, height;
+
+#ifdef ESLOPE
+	UINT8 *resizedflat;
+	INT16 resizedwidth, resizedheight;
+#endif
+} textureflat_t;
+
 // all loaded and prepared textures from the start of the game
 extern texture_t **textures;
+extern textureflat_t *texflats;
 
 extern INT32 *texturewidth;
 extern fixed_t *textureheight; // needed for texture pegging
@@ -94,7 +106,6 @@ const char *R_ColormapNameForNum(INT32 num);
 
 boolean R_CheckIfPatch(lumpnum_t lump);
 
-// Lactozilla
 void R_FlatPatch(patch_t *patch, UINT8 *flat);
 void R_FlatTexture(size_t tex, UINT8 *flat);
 void R_CropFlat(UINT8 *srcflat, UINT8 *destflat,
diff --git a/src/r_plane.c b/src/r_plane.c
index 91b4f5f2c452e32e8fdc43f4fbe72fb53a0d7e99..01d0fdd37887e54c939680b8ebbf5e8c1297c82d 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -653,96 +653,191 @@ void R_DrawPlanes(void)
 #endif
 }
 
-// Lactozilla
+boolean R_CheckPowersOfTwo(void)
+{
+	return (ds_powersoftwo = ((!((ds_flatwidth & (ds_flatwidth - 1)) || (ds_flatheight & (ds_flatheight - 1)))) && (ds_flatwidth == ds_flatheight)));
+}
+
+void R_CheckFlatLength(size_t size)
+{
+	switch (size)
+	{
+		case 4194304: // 2048x2048 lump
+			nflatmask = 0x3FF800;
+			nflatxshift = 21;
+			nflatyshift = 10;
+			nflatshiftup = 5;
+			ds_flatwidth = ds_flatheight = 2048;
+			break;
+		case 1048576: // 1024x1024 lump
+			nflatmask = 0xFFC00;
+			nflatxshift = 22;
+			nflatyshift = 12;
+			nflatshiftup = 6;
+			ds_flatwidth = ds_flatheight = 1024;
+			break;
+		case 262144:// 512x512 lump
+			nflatmask = 0x3FE00;
+			nflatxshift = 23;
+			nflatyshift = 14;
+			nflatshiftup = 7;
+			ds_flatwidth = ds_flatheight = 512;
+			break;
+		case 65536: // 256x256 lump
+			nflatmask = 0xFF00;
+			nflatxshift = 24;
+			nflatyshift = 16;
+			nflatshiftup = 8;
+			ds_flatwidth = ds_flatheight = 256;
+			break;
+		case 16384: // 128x128 lump
+			nflatmask = 0x3F80;
+			nflatxshift = 25;
+			nflatyshift = 18;
+			nflatshiftup = 9;
+			ds_flatwidth = ds_flatheight = 128;
+			break;
+		case 1024: // 32x32 lump
+			nflatmask = 0x3E0;
+			nflatxshift = 27;
+			nflatyshift = 22;
+			nflatshiftup = 11;
+			ds_flatwidth = ds_flatheight = 32;
+			break;
+		default: // 64x64 lump
+			nflatmask = 0xFC0;
+			nflatxshift = 26;
+			nflatyshift = 20;
+			nflatshiftup = 10;
+			ds_flatwidth = ds_flatheight = 64;
+			break;
+	}
+}
+
 static void R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture)
 {
+	textureflat_t *texflat = &texflats[levelflat->texturenum];
 	patch_t *patch = NULL;
+	UINT8 *tex;
+	boolean texturechanged = (leveltexture ? (levelflat->texturenum != levelflat->lasttexturenum) : false);
 
-	if (levelflat->flatpatch == NULL)
+	// Check if the texture changed.
+	if (leveltexture && (!texturechanged))
+	{
+		if (texflat != NULL && texflat->flat)
+		{
+			ds_source = texflat->flat;
+			ds_flatwidth = texflat->width;
+			ds_flatheight = texflat->height;
+			texturechanged = false;
+		}
+		else
+			texturechanged = true;
+	}
+
+	// If the texture changed, or the patch doesn't exist, convert either of them to a flat.
+	if (levelflat->flatpatch == NULL || texturechanged)
 	{
 #ifdef ESLOPE
 		INT32 resizewidth, resizeheight, newresize;
 		INT32 checkresizewidth, checkresizeheight;
 #endif // ESLOPE
 
-		if (!leveltexture)
+		if (leveltexture)
+		{
+			texture_t *texture = textures[levelflat->texturenum];
+			texflat->width = ds_flatwidth = texture->width;
+			texflat->height = ds_flatheight = texture->height;
+
+			texflat->flat = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL);
+			memset(texflat->flat, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight);
+			R_FlatTexture(levelflat->texturenum, texflat->flat);
+
+			ds_source = texflat->flat;
+		}
+		else
 		{
 			patch = (patch_t *)ds_source;
 			levelflat->width = ds_flatwidth = patch->width;
 			levelflat->height = ds_flatheight = patch->height;
 
-			levelflat->flatpatch = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL);
-			memset(levelflat->flatpatch, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight);
-			R_FlatPatch(patch, levelflat->flatpatch);
-
 			levelflat->topoffset = patch->topoffset * FRACUNIT;
 			levelflat->leftoffset = patch->leftoffset * FRACUNIT;
-		}
-		else
-		{
-			texture_t *texture = textures[levelflat->texturenum];
-			levelflat->width = ds_flatwidth = texture->width;
-			levelflat->height = ds_flatheight = texture->height;
 
 			levelflat->flatpatch = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL);
 			memset(levelflat->flatpatch, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight);
-			R_FlatTexture(levelflat->texturenum, levelflat->flatpatch);
+			R_FlatPatch(patch, levelflat->flatpatch);
 
-			levelflat->topoffset = levelflat->leftoffset = 0;
+			ds_source = levelflat->flatpatch;
 		}
-		ds_source = levelflat->flatpatch;
 
-		// If GZDoom has the same limitation then I'm not even going to bother.
-		// Crop the texture.
 #ifdef ESLOPE
-		// Scale up to nearest power of 2
-		resizewidth = resizeheight = 1;
-		while (resizewidth < levelflat->width)
-			resizewidth <<= 1;
-		while (resizeheight < levelflat->height)
-			resizeheight <<= 1;
-
-		// Scale down to fit in 2048x2048
-		if (resizewidth > 2048)
-			resizewidth = 2048;
-		if (resizeheight > 2048)
-			resizeheight = 2048;
-
-		// A single pixel difference is negligible.
-		checkresizewidth = levelflat->width - 1;
-		if (checkresizewidth & (checkresizewidth - 1))
+		// Crop the flat, if necessary.
+		if (!R_CheckPowersOfTwo())
 		{
-			checkresizewidth += 2;
+			// Scale up to nearest power of 2
+			resizewidth = resizeheight = 1;
+			while (resizewidth < ds_flatwidth)
+				resizewidth <<= 1;
+			while (resizeheight < ds_flatheight)
+				resizeheight <<= 1;
+
+			// Scale down to fit in 2048x2048
+			if (resizewidth > 2048)
+				resizewidth = 2048;
+			if (resizeheight > 2048)
+				resizeheight = 2048;
+
+			// A single pixel difference is negligible.
+			checkresizewidth = ds_flatwidth - 1;
 			if (checkresizewidth & (checkresizewidth - 1))
 			{
-				while (resizewidth > levelflat->width)
-					resizewidth >>= 1;
+				checkresizewidth += 2;
+				if (checkresizewidth & (checkresizewidth - 1))
+				{
+					while (resizewidth > ds_flatwidth)
+						resizewidth >>= 1;
+				}
+				else
+					resizewidth = checkresizewidth;
 			}
 			else
 				resizewidth = checkresizewidth;
-		}
-		else
-			resizewidth = checkresizewidth;
 
-		checkresizeheight = levelflat->height - 1;
-		if (checkresizeheight & (checkresizeheight - 1))
-		{
-			checkresizeheight += 2;
+			checkresizeheight = ds_flatheight - 1;
 			if (checkresizeheight & (checkresizeheight - 1))
 			{
-				while (resizeheight > levelflat->height)
-					resizeheight >>= 1;
+				checkresizeheight += 2;
+				if (checkresizeheight & (checkresizeheight - 1))
+				{
+					while (resizeheight > ds_flatheight)
+						resizeheight >>= 1;
+				}
+				else
+					resizeheight = checkresizeheight;
 			}
 			else
 				resizeheight = checkresizeheight;
-		}
-		else
-			resizeheight = checkresizeheight;
 
-		levelflat->resizedwidth = levelflat->resizedheight = (newresize = min(resizewidth, resizeheight));
-		levelflat->resizedflat = Z_Malloc(newresize * newresize, PU_LEVEL, NULL);
-		memset(levelflat->resizedflat, TRANSPARENTPIXEL, newresize * newresize);
-		R_CropFlat(levelflat->flatpatch, levelflat->resizedflat, levelflat->width, levelflat->height, min(resizewidth, newresize), min(resizeheight, newresize), newresize, newresize);
+			// Find smallest size.
+			newresize = min(resizewidth, resizeheight);
+
+			// Allocate texture.
+			tex = Z_Malloc(newresize * newresize, PU_LEVEL, NULL);
+			memset(tex, TRANSPARENTPIXEL, newresize * newresize);
+			R_CropFlat(ds_source, tex, ds_flatwidth, ds_flatheight, min(resizewidth, newresize), min(resizeheight, newresize), newresize, newresize);
+
+			if (leveltexture)
+			{
+				texflat->resizedflat = tex;
+				texflat->resizedwidth = texflat->resizedheight = newresize;
+			}
+			else
+			{
+				levelflat->resizedflat = tex;
+				levelflat->resizedwidth = levelflat->resizedheight = newresize;
+			}
+		}
 #endif // ESLOPE
 	}
 	else
@@ -758,58 +853,26 @@ static void R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture)
 #ifdef ESLOPE
 	if (currentplane->slope)
 	{
-		ds_source = levelflat->resizedflat;
-		ds_flatwidth = levelflat->resizedwidth;
-		ds_flatheight = levelflat->resizedheight;
-
-		// uuuuuuuhhhhhhhh.......................
-		switch (ds_flatwidth * ds_flatheight)
+		if (R_CheckPowersOfTwo())
 		{
-			case 4194304: // 2048x2048 lump
-				nflatmask = 0x3FF800;
-				nflatxshift = 21;
-				nflatyshift = 10;
-				nflatshiftup = 5;
-				break;
-			case 1048576: // 1024x1024 lump
-				nflatmask = 0xFFC00;
-				nflatxshift = 22;
-				nflatyshift = 12;
-				nflatshiftup = 6;
-				break;
-			case 262144:// 512x512 lump
-				nflatmask = 0x3FE00;
-				nflatxshift = 23;
-				nflatyshift = 14;
-				nflatshiftup = 7;
-				break;
-			case 65536: // 256x256 lump
-				nflatmask = 0xFF00;
-				nflatxshift = 24;
-				nflatyshift = 16;
-				nflatshiftup = 8;
-				break;
-			case 16384: // 128x128 lump
-				nflatmask = 0x3F80;
-				nflatxshift = 25;
-				nflatyshift = 18;
-				nflatshiftup = 9;
-				break;
-			case 1024: // 32x32 lump
-				nflatmask = 0x3E0;
-				nflatxshift = 27;
-				nflatyshift = 22;
-				nflatshiftup = 11;
-				break;
-			default: // 64x64 lump
-				nflatmask = 0xFC0;
-				nflatxshift = 26;
-				nflatyshift = 20;
-				nflatshiftup = 10;
-				break;
+			if (leveltexture)
+			{
+				ds_source = texflat->resizedflat;
+				ds_flatwidth = texflat->resizedwidth;
+				ds_flatheight = texflat->resizedheight;
+			}
+			else
+			{
+				ds_source = levelflat->resizedflat;
+				ds_flatwidth = levelflat->resizedwidth;
+				ds_flatheight = levelflat->resizedheight;
+			}
 		}
+		R_CheckFlatLength(ds_flatwidth * ds_flatheight);
 	}
 #endif // ESLOPE
+
+	levelflat->lasttexturenum = levelflat->texturenum;
 }
 
 void R_DrawSinglePlane(visplane_t *pl)
@@ -966,71 +1029,24 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 	currentplane = pl;
 	levelflat = &levelflats[pl->picnum];
+	size = W_LumpLength(levelflat->lumpnum);
 
+	// Check if the flat is actually a texture.
 	if (levelflat->texturenum != 0 && levelflat->texturenum != -1)
 		R_GetPatchFlat(levelflat, true);
+	// Check if the flat is actually a patch.
+	else if (R_CheckIfPatch(levelflat->lumpnum))
+		R_GetPatchFlat(levelflat, false);
+	// Raw flat.
 	else
 	{
 		ds_source = (UINT8 *)W_CacheLumpNum(levelflat->lumpnum, PU_STATIC); // Stay here until Z_ChangeTag
-		size = W_LumpLength(levelflat->lumpnum);
-
-		switch (size)
-		{
-			case 4194304: // 2048x2048 lump
-				nflatmask = 0x3FF800;
-				nflatxshift = 21;
-				nflatyshift = 10;
-				nflatshiftup = 5;
-				ds_flatwidth = ds_flatheight = 2048;
-				break;
-			case 1048576: // 1024x1024 lump
-				nflatmask = 0xFFC00;
-				nflatxshift = 22;
-				nflatyshift = 12;
-				nflatshiftup = 6;
-				ds_flatwidth = ds_flatheight = 1024;
-				break;
-			case 262144:// 512x512 lump
-				nflatmask = 0x3FE00;
-				nflatxshift = 23;
-				nflatyshift = 14;
-				nflatshiftup = 7;
-				ds_flatwidth = ds_flatheight = 512;
-				break;
-			case 65536: // 256x256 lump
-				nflatmask = 0xFF00;
-				nflatxshift = 24;
-				nflatyshift = 16;
-				nflatshiftup = 8;
-				ds_flatwidth = ds_flatheight = 256;
-				break;
-			case 16384: // 128x128 lump
-				nflatmask = 0x3F80;
-				nflatxshift = 25;
-				nflatyshift = 18;
-				nflatshiftup = 9;
-				ds_flatwidth = ds_flatheight = 128;
-				break;
-			case 1024: // 32x32 lump
-				nflatmask = 0x3E0;
-				nflatxshift = 27;
-				nflatyshift = 22;
-				nflatshiftup = 11;
-				ds_flatwidth = ds_flatheight = 32;
-				break;
-			default: // 64x64 lump
-				nflatmask = 0xFC0;
-				nflatxshift = 26;
-				nflatyshift = 20;
-				nflatshiftup = 10;
-				ds_flatwidth = ds_flatheight = 64;
-				break;
-		}
+		R_CheckFlatLength(size);
 	}
 
-	if (R_CheckIfPatch(levelflat->lumpnum))
-		R_GetPatchFlat(levelflat, false);
-	ds_powersoftwo = (!((ds_flatwidth & (ds_flatwidth - 1)) || (ds_flatheight & (ds_flatheight - 1))));
+	// Check if the flat has dimensions that are powers-of-two numbers.
+	if (R_CheckPowersOfTwo())
+		R_CheckFlatLength(ds_flatwidth * ds_flatheight);
 
 	if (light >= LIGHTLEVELS)
 		light = LIGHTLEVELS-1;
diff --git a/src/r_plane.h b/src/r_plane.h
index 6e6a6d49d0522a6aa6b0d9facd35754f5744af14..78aae3fa1532ccde76ce079d9f40e67b919855ac 100644
--- a/src/r_plane.h
+++ b/src/r_plane.h
@@ -94,6 +94,8 @@ void R_PlaneBounds(visplane_t *plane);
 
 // Draws a single visplane.
 void R_DrawSinglePlane(visplane_t *pl);
+void R_CheckFlatLength(size_t size);
+boolean R_CheckPowersOfTwo(void);
 
 typedef struct planemgr_s
 {