diff --git a/src/r_draw.c b/src/r_draw.c
index 86f7e488c8502516cc4f36bb04b7a516385fc5ed..feb4693bb4a9ab995a099b003caf6a40e8e610f5 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -74,7 +74,7 @@ UINT8 *dc_transmap; // one of the translucency tables
 UINT8 *dc_translation;
 
 struct r_lightlist_s *dc_lightlist = NULL;
-INT32 dc_numlights = 0, dc_maxlights, dc_texheight;
+INT32 dc_numlights = 0, dc_maxlights, dc_texheight, dc_postlength;
 
 // =========================================================================
 //                      SPAN DRAWING CODE STUFF
diff --git a/src/r_draw.h b/src/r_draw.h
index 1a828312a7a922353a3ff5b969908dc61dcf0ee6..77588d7dede09edf30463c1cd749b268724a6882 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -41,8 +41,7 @@ extern UINT8 *dc_translation;
 extern struct r_lightlist_s *dc_lightlist;
 extern INT32 dc_numlights, dc_maxlights;
 
-//Fix TUTIFRUTI
-extern INT32 dc_texheight;
+extern INT32 dc_texheight, dc_postlength;
 
 // -----------------------
 // SPAN DRAWING CODE STUFF
@@ -154,8 +153,10 @@ void R_VideoErase(size_t ofs, INT32 count);
 // -----------------
 
 void R_DrawColumn_8(void);
+void R_DrawColumnClamped_8(void);
 void R_DrawShadeColumn_8(void);
 void R_DrawTranslucentColumn_8(void);
+void R_DrawTranslucentColumnClamped_8(void);
 void R_DrawDropShadowColumn_8(void);
 void R_DrawTranslatedColumn_8(void);
 void R_DrawTranslatedTranslucentColumn_8(void);
diff --git a/src/r_draw8.c b/src/r_draw8.c
index 99fb71e289343034bc6327314da0e64b0d687dab..735127f88d12daafc0161ea080195ce66d4b3db1 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -100,6 +100,98 @@ void R_DrawColumn_8(void)
 	}
 }
 
+/**	\brief The R_DrawColumnClamped_8 function
+	Same as R_DrawColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions)
+*/
+void R_DrawColumnClamped_8(void)
+{
+	INT32 count;
+	UINT8 *dest;
+	fixed_t frac;
+	fixed_t fracstep;
+
+	count = dc_yh - dc_yl;
+
+	if (count < 0) // Zero length, column does not exceed a pixel.
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
+		return;
+#endif
+
+	// Framebuffer destination address.
+	dest = &topleft[dc_yl*vid.width + dc_x];
+
+	count++;
+
+	// Determine scaling, which is the only mapping to be done.
+	fracstep = dc_iscale;
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
+
+	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
+	// This is as fast as it gets.
+	{
+		const UINT8 *source = dc_source;
+		const lighttable_t *colormap = dc_colormap;
+		INT32 heightmask = dc_texheight-1;
+		INT32 idx;
+		if (dc_texheight & heightmask)   // not a power of 2 -- killough
+		{
+			heightmask++;
+			heightmask <<= FRACBITS;
+
+			if (frac < 0)
+				while ((frac += heightmask) <  0);
+			else
+				while (frac >= heightmask)
+					frac -= heightmask;
+
+			do
+			{
+				// Re-map color indices from wall texture column
+				//  using a lighting/special effects LUT.
+				// heightmask is the Tutti-Frutti fix
+				idx = frac>>FRACBITS;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+				dest += vid.width;
+
+				// Avoid overflow.
+				if (fracstep > 0x7FFFFFFF - frac)
+					frac += fracstep - heightmask;
+				else
+					frac += fracstep;
+
+				while (frac >= heightmask)
+					frac -= heightmask;
+			} while (--count);
+		}
+		else
+		{
+			while ((count -= 2) >= 0) // texture height is a power of 2
+			{
+				idx = (frac>>FRACBITS) & heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+				dest += vid.width;
+				frac += fracstep;
+				idx = (frac>>FRACBITS) & heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+				dest += vid.width;
+				frac += fracstep;
+			}
+			if (count & 1)
+			{
+				idx = (frac>>FRACBITS) & heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+			}
+		}
+	}
+}
+
 /**	\brief The R_DrawShadeColumn_8 function
 	Experiment to make software go faster. Taken from the Boom source
 */
@@ -212,6 +304,90 @@ void R_DrawTranslucentColumn_8(void)
 	}
 }
 
+/**	\brief The R_DrawTranslucentColumnClamped_8 function
+	Same as R_DrawTranslucentColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions)
+*/
+void R_DrawTranslucentColumnClamped_8(void)
+{
+	INT32 count;
+	UINT8 *dest;
+	fixed_t frac, fracstep;
+
+	count = dc_yh - dc_yl + 1;
+
+	if (count <= 0) // Zero length, column does not exceed a pixel.
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
+		I_Error("R_DrawTranslucentColumnClamped_8: %d to %d at %d", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = &topleft[dc_yl*vid.width + dc_x];
+
+	// Looks familiar.
+	fracstep = dc_iscale;
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
+
+	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
+	// This is as fast as it gets.
+	{
+		const UINT8 *source = dc_source;
+		const UINT8 *transmap = dc_transmap;
+		const lighttable_t *colormap = dc_colormap;
+		INT32 heightmask = dc_texheight - 1;
+		INT32 idx;
+		if (dc_texheight & heightmask)
+		{
+			heightmask++;
+			heightmask <<= FRACBITS;
+
+			if (frac < 0)
+				while ((frac += heightmask) < 0)
+					;
+			else
+				while (frac >= heightmask)
+					frac -= heightmask;
+
+			do
+			{
+				// Re-map color indices from wall texture column
+				// using a lighting/special effects LUT.
+				// heightmask is the Tutti-Frutti fix
+				idx = frac>>FRACBITS;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+				dest += vid.width;
+				if ((frac += fracstep) >= heightmask)
+					frac -= heightmask;
+			}
+			while (--count);
+		}
+		else
+		{
+			while ((count -= 2) >= 0) // texture height is a power of 2
+			{
+				idx = (frac>>FRACBITS)&heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+				dest += vid.width;
+				frac += fracstep;
+				idx = (frac>>FRACBITS)&heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+				dest += vid.width;
+				frac += fracstep;
+			}
+			if (count & 1)
+			{
+				idx = (frac>>FRACBITS)&heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+			}
+		}
+	}
+}
+
 // Hack: A cut-down copy of R_DrawTranslucentColumn_8 that does not read texture
 // data since something about calculating the texture reading address for drop shadows is broken.
 // dc_texturemid and dc_iscale get wrong values for drop shadows, however those are not strictly
diff --git a/src/r_segs.c b/src/r_segs.c
index 19fdcfca782f7b0b5a02b759d32f152f6b6d3c21..75c95aa9345702b3dd989e57c3f2f20cc1499096 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -563,6 +563,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	fixed_t wall_scalex, wall_scaley;
 	UINT8 vertflip;
 	unsigned lengthcol;
+	boolean fog = false;
+	boolean fuzzy = false;
 
 	void (*colfunc_2s) (column_t *, unsigned);
 
@@ -576,8 +578,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
 	sidedef = R_GetFFloorSide(curline->linedef, pfloor, pfloor->target);
 
-	colfunc = colfuncs[BASEDRAWFUNC];
-
 	if (pfloor->master->flags & ML_TFERLINE)
 	{
 		line_t *newline = R_GetFFloorLine(curline->linedef, pfloor, pfloor->target);
@@ -595,7 +595,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 	if (pfloor->fofflags & FOF_TRANSLUCENT)
 	{
-		boolean fuzzy = true;
+		fuzzy = true;
 
 		// Hacked up support for alpha value in software mode Tails 09-24-2002
 		// ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021
@@ -608,17 +608,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0)
 				fuzzy = false; // Opaque
 		}
-
-		if (fuzzy)
-			colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 	}
 	else if (pfloor->fofflags & FOF_FOG)
+	{
 		colfunc = colfuncs[COLDRAWFUNC_FOG];
+		fog = true;
+	}
 
 	range = max(ds->x2-ds->x1, 1);
-	//SoM: Moved these up here so they are available for my lightlist calculations
-	rw_scalestep = ds->scalestep;
-	spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
 
 	dc_numlights = 0;
 	if (frontsector->numlights)
@@ -721,9 +718,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		// Get correct light level!
 		if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
 			lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
-		else if (pfloor->fofflags & FOF_FOG)
+		else if (fog)
 			lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
-		else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
+		else if (fuzzy)
 			lightnum = LIGHTLEVELS-1;
 		else
 			lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)
@@ -751,6 +748,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		vertflip = !vertflip;
 	}
 
+	//SoM: Moved these up here so they are available for my lightlist calculations
+	// Lactozilla: Moved them back down
+	// This uses floating point math now, because the fixed-point imprecisions
+	// become more severe the bigger the texture is scaled.
+	double dwall_scaley = FixedToDouble(wall_scaley);
+	double scalestep = FixedToDouble(ds->scalestep) / dwall_scaley;
+	double yscale = (FixedToDouble(ds->scale1) + (x1 - ds->x1)*scalestep) / dwall_scaley;
+
 	thicksidecol = ffloortexturecolumn;
 
 	wall_offsetx = ds->offsetx + sidedef->offsetx_mid;
@@ -872,15 +877,41 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 						rlight->botheight += rlight->botheightstep;
 				}
 			}
-			spryscale += rw_scalestep;
+			yscale += scalestep;
 			continue;
 		}
 
-		dc_iscale = FixedMul(0xffffffffu / (unsigned)spryscale, wall_scaley);
-
 		// Get data for the column
 		col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS));
 
+		spryscale = DoubleToFixed(yscale);
+
+		// Eh. I tried fixing the scaling artifacts but it still wasn't perfect.
+		// So this checks if the column has gaps in it or not, and if it does, uses a version of the column drawers
+		// that prevents the artifacts from being visible.
+		// Note that if rendering fog then none of this matters because there's no texture mapping to be done
+		if (!fog)
+		{
+			dc_iscale = 0xffffffffu / (unsigned)spryscale;
+
+			// Column has a single post and it matches the texture height, use regular column drawers
+			if (col->num_posts == 1 && col->posts[0].topdelta == 0 && col->posts[0].length == (unsigned)dc_texheight)
+			{
+				if (fuzzy)
+					colfunc = colfuncs[COLDRAWFUNC_FUZZY];
+				else
+					colfunc = colfuncs[BASEDRAWFUNC];
+			}
+			else
+			{
+				// Otherwise use column drawers with extra checks
+				if (fuzzy)
+					colfunc = R_DrawTranslucentColumnClamped_8;
+				else
+					colfunc = R_DrawColumnClamped_8;
+			}
+		}
+
 		// SoM: New code does not rely on R_DrawColumnShadowed_8 which
 		// will (hopefully) put less strain on the stack.
 		if (dc_numlights)
@@ -995,7 +1026,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			if (windowtop < windowbottom)
 				colfunc_2s (col, lengthcol);
 
-			spryscale += rw_scalestep;
+			yscale += scalestep;
 			continue;
 		}
 
@@ -1014,7 +1045,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 		// draw the texture
 		colfunc_2s (col, lengthcol);
-		spryscale += rw_scalestep;
+		yscale += scalestep;
 	}
 	colfunc = colfuncs[BASEDRAWFUNC];
 
diff --git a/src/r_things.c b/src/r_things.c
index c46d8162460e6ac4df025457910f1eae92634628..fb9757a9ae077703433b2ad4bc8a3a1fc166d12b 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -839,8 +839,10 @@ void R_DrawMaskedColumn(column_t *column, unsigned lengthcol)
 	{
 		post_t *post = &column->posts[i];
 
+		dc_postlength = post->length;
+
 		INT32 topscreen = sprtopscreen + spryscale*post->topdelta;
-		INT32 bottomscreen = topscreen + spryscale*post->length;
+		INT32 bottomscreen = topscreen + spryscale*dc_postlength;
 
 		dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
 		dc_yh = (bottomscreen-1)>>FRACBITS;
@@ -909,10 +911,12 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol)
 		if (!post->length)
 			continue;
 
-		topdelta = lengthcol-post->length-post->topdelta;
+		dc_postlength = post->length;
+
+		topdelta = lengthcol-dc_postlength-post->topdelta;
 		topscreen = sprtopscreen + spryscale*topdelta;
-		bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*post->length
-		                                      : sprbotscreen + spryscale*post->length;
+		bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*dc_postlength
+		                                      : sprbotscreen + spryscale*dc_postlength;
 
 		dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
 		dc_yh = (bottomscreen-1)>>FRACBITS;