From 7b58eab332b2877db0b92bb6ad2370f8b2d36490 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Sun, 26 Mar 2017 05:28:27 +0200
Subject: [PATCH 1/4] - fix softpoly light visibility bug

---
 src/polyrenderer/drawers/poly_drawer32_sse2.h | 3 ++-
 src/polyrenderer/drawers/poly_drawer8.h       | 3 ++-
 src/polyrenderer/scene/poly_decal.cpp         | 4 ++--
 src/polyrenderer/scene/poly_light.cpp         | 6 ++++++
 src/polyrenderer/scene/poly_light.h           | 8 +++++---
 src/polyrenderer/scene/poly_particle.cpp      | 4 ++--
 src/polyrenderer/scene/poly_plane.cpp         | 8 ++++----
 src/polyrenderer/scene/poly_scene.cpp         | 2 +-
 src/polyrenderer/scene/poly_sky.cpp           | 2 +-
 src/polyrenderer/scene/poly_sprite.cpp        | 4 ++--
 src/polyrenderer/scene/poly_wall.cpp          | 2 +-
 src/polyrenderer/scene/poly_wallsprite.cpp    | 4 ++--
 12 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h
index c86d3bc934..0e7fe0b0e5 100644
--- a/src/polyrenderer/drawers/poly_drawer32_sse2.h
+++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h
@@ -108,8 +108,9 @@ public:
 
 		// Light
 		uint32_t light = args->uniforms->light;
-		float shade = (64.0f - (light * 255 / 256 + 12.0f) * 32.0f / 128.0f) / 32.0f;
+		float shade = 2.0f - (light + 12.0f) / 128.0f;
 		float globVis = args->uniforms->globvis * (1.0f / 32.0f);
+		light += (light >> 7); // 255 -> 256
 
 		// Sampling stuff
 		uint32_t color = args->uniforms->color;
diff --git a/src/polyrenderer/drawers/poly_drawer8.h b/src/polyrenderer/drawers/poly_drawer8.h
index 6535f48529..974a454ab5 100644
--- a/src/polyrenderer/drawers/poly_drawer8.h
+++ b/src/polyrenderer/drawers/poly_drawer8.h
@@ -69,8 +69,9 @@ public:
 
 		// Light
 		uint32_t light = args->uniforms->light;
-		float shade = (64.0f - (light * 255 / 256 + 12.0f) * 32.0f / 128.0f) / 32.0f;
+		float shade = 2.0f - (light + 12.0f) / 128.0f;
 		float globVis = args->uniforms->globvis * (1.0f / 32.0f);
+		light += light >> 7; // 255 -> 256
 
 		// Sampling stuff
 		uint32_t color = args->uniforms->color;
diff --git a/src/polyrenderer/scene/poly_decal.cpp b/src/polyrenderer/scene/poly_decal.cpp
index 0759ac64d4..21f7281d44 100644
--- a/src/polyrenderer/scene/poly_decal.cpp
+++ b/src/polyrenderer/scene/poly_decal.cpp
@@ -140,12 +140,12 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
 	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
 	{
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 		args.uniforms.flags |= TriUniforms::fixed_light;
 	}
 	else
 	{
-		args.uniforms.light = (uint32_t)((front->lightlevel + actualextralight) / 255.0f * 256.0f);
+		args.uniforms.light = front->lightlevel + actualextralight;
 	}
 	args.uniforms.subsectorDepth = subsectorDepth;
 
diff --git a/src/polyrenderer/scene/poly_light.cpp b/src/polyrenderer/scene/poly_light.cpp
index 5de6756d7e..92c74e4695 100644
--- a/src/polyrenderer/scene/poly_light.cpp
+++ b/src/polyrenderer/scene/poly_light.cpp
@@ -25,6 +25,7 @@
 #include "doomdef.h"
 #include "sbar.h"
 #include "poly_light.h"
+#include "polyrenderer/poly_renderer.h"
 
 fixed_t PolyLightVisibility::LightLevelToShade(int lightlevel, bool foggy)
 {
@@ -41,3 +42,8 @@ fixed_t PolyLightVisibility::LightLevelToShade(int lightlevel, bool foggy)
 		return (NUMCOLORMAPS * 2 * FRACUNIT) - ((lightlevel + 12) * (FRACUNIT*NUMCOLORMAPS / 128));
 	}
 }
+
+double PolyLightVisibility::FocalTangent()
+{
+	return PolyRenderer::Instance()->Viewwindow.FocalTangent;
+}
diff --git a/src/polyrenderer/scene/poly_light.h b/src/polyrenderer/scene/poly_light.h
index 9644387e71..dcb397cb82 100644
--- a/src/polyrenderer/scene/poly_light.h
+++ b/src/polyrenderer/scene/poly_light.h
@@ -31,9 +31,9 @@ typedef swrenderer::CameraLight PolyCameraLight;
 class PolyLightVisibility
 {
 public:
-	double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
-	double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
-	double ParticleGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : (WallVisibility * 0.5); }
+	double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : WallVisibility / FocalTangent(); }
+	double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : WallVisibility / FocalTangent(); }
+	double ParticleGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : WallVisibility * 0.5 / FocalTangent(); }
 
 	// The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros
 	double WallVis(double screenZ, bool foggy) const { return WallGlobVis(foggy) / screenZ; }
@@ -43,6 +43,8 @@ public:
 	static fixed_t LightLevelToShade(int lightlevel, bool foggy);
 
 private:
+	static double FocalTangent();
+
 	// 1706 is the value for walls on 1080p 16:9 displays.
 	double WallVisibility = 1706.0;
 	bool NoLightFade = false;
diff --git a/src/polyrenderer/scene/poly_particle.cpp b/src/polyrenderer/scene/poly_particle.cpp
index 8d09be467f..37f9783081 100644
--- a/src/polyrenderer/scene/poly_particle.cpp
+++ b/src/polyrenderer/scene/poly_particle.cpp
@@ -78,12 +78,12 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipP
 
 	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
 	{
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 		args.uniforms.flags = TriUniforms::fixed_light | TriUniforms::nearest_filter;
 	}
 	else
 	{
-		args.uniforms.light = (uint32_t)((sub->sector->lightlevel + actualextralight) / 255.0f * 256.0f);
+		args.uniforms.light = sub->sector->lightlevel + actualextralight;
 		args.uniforms.flags = TriUniforms::nearest_filter;
 	}
 	args.uniforms.subsectorDepth = subsectorDepth;
diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp
index 03ea75b37a..4b616910d5 100644
--- a/src/polyrenderer/scene/poly_plane.cpp
+++ b/src/polyrenderer/scene/poly_plane.cpp
@@ -113,9 +113,9 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c
 
 	PolyDrawArgs args;
 	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy); // .SlopePlaneGlobVis(foggy) * 48.0f;
-	args.uniforms.light = (uint32_t)(lightlevel / 255.0f * 256.0f);
+	args.uniforms.light = lightlevel;
 	if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 	args.uniforms.flags = TriUniforms::nearest_filter;
 	args.uniforms.subsectorDepth = subsectorDepth;
 
@@ -295,9 +295,9 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 
 	PolyDrawArgs args;
 	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);// ->SlopePlaneGlobVis(foggy) * 48.0f;
-	args.uniforms.light = (uint32_t)(frontsector->lightlevel / 255.0f * 256.0f);
+	args.uniforms.light = frontsector->lightlevel;
 	if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 	args.uniforms.flags = TriUniforms::nearest_filter;
 	args.uniforms.subsectorDepth = isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth;
 
diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp
index f3a0b28879..79f7631cf8 100644
--- a/src/polyrenderer/scene/poly_scene.cpp
+++ b/src/polyrenderer/scene/poly_scene.cpp
@@ -253,7 +253,7 @@ void RenderPolyScene::RenderPortals(int portalDepth)
 		args.mode = TriangleDrawMode::Fan;
 		args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
 		args.uniforms.color = 0;
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 		args.uniforms.flags = TriUniforms::fixed_light;
 		args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
 
diff --git a/src/polyrenderer/scene/poly_sky.cpp b/src/polyrenderer/scene/poly_sky.cpp
index 3be38e4813..b30ba69a8f 100644
--- a/src/polyrenderer/scene/poly_sky.cpp
+++ b/src/polyrenderer/scene/poly_sky.cpp
@@ -58,7 +58,7 @@ void PolySkyDome::Render(const TriMatrix &worldToClip)
 
 	PolyDrawArgs args;
 	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-	args.uniforms.light = 256;
+	args.uniforms.light = 255;
 	args.uniforms.flags = TriUniforms::nearest_filter;
 	args.uniforms.subsectorDepth = RenderPolyScene::SkySubsectorDepth;
 	args.objectToClip = &objectToClip;
diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp
index 6e3c8c86c2..a2ead5d764 100644
--- a/src/polyrenderer/scene/poly_sprite.cpp
+++ b/src/polyrenderer/scene/poly_sprite.cpp
@@ -143,12 +143,12 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla
 	args.uniforms.flags = TriUniforms::nearest_filter;
 	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
 	{
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 		args.uniforms.flags |= TriUniforms::fixed_light;
 	}
 	else
 	{
-		args.uniforms.light = (uint32_t)((thing->Sector->lightlevel + actualextralight) / 255.0f * 256.0f);
+		args.uniforms.light = thing->Sector->lightlevel + actualextralight;
 	}
 	args.uniforms.subsectorDepth = subsectorDepth;
 
diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp
index abbfd15f88..96b3ecc626 100644
--- a/src/polyrenderer/scene/poly_wall.cpp
+++ b/src/polyrenderer/scene/poly_wall.cpp
@@ -249,7 +249,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane
 
 	PolyDrawArgs args;
 	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-	args.uniforms.light = (uint32_t)(GetLightLevel() / 255.0f * 256.0f);
+	args.uniforms.light = GetLightLevel();
 	args.uniforms.flags = TriUniforms::nearest_filter;
 	args.uniforms.subsectorDepth = SubsectorDepth;
 	args.objectToClip = &worldToClip;
diff --git a/src/polyrenderer/scene/poly_wallsprite.cpp b/src/polyrenderer/scene/poly_wallsprite.cpp
index 75227c2557..509a5e8dac 100644
--- a/src/polyrenderer/scene/poly_wallsprite.cpp
+++ b/src/polyrenderer/scene/poly_wallsprite.cpp
@@ -103,12 +103,12 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &cli
 	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
 	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
 	{
-		args.uniforms.light = 256;
+		args.uniforms.light = 255;
 		args.uniforms.flags = TriUniforms::fixed_light | TriUniforms::nearest_filter;
 	}
 	else
 	{
-		args.uniforms.light = (uint32_t)((thing->Sector->lightlevel + actualextralight) / 255.0f * 256.0f);
+		args.uniforms.light = thing->Sector->lightlevel + actualextralight;
 		args.uniforms.flags = TriUniforms::nearest_filter;
 	}
 	args.uniforms.subsectorDepth = subsectorDepth;

From ffc90f16abb77f3357a1d59fc8d32065e2aaf9b4 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Sun, 26 Mar 2017 10:10:55 +0200
Subject: [PATCH 2/4] - Simplify the PolyDrawArgs interface

---
 src/polyrenderer/drawers/poly_draw_args.cpp   |  93 +++++++-----
 src/polyrenderer/drawers/poly_draw_args.h     | 133 ++++++++++++++----
 src/polyrenderer/drawers/poly_drawer32_sse2.h |  34 +++--
 src/polyrenderer/drawers/poly_drawer8.h       |  23 ++-
 src/polyrenderer/drawers/poly_triangle.cpp    |  86 ++++-------
 src/polyrenderer/drawers/poly_triangle.h      |   4 +-
 src/polyrenderer/drawers/screen_triangle.cpp  |  10 +-
 src/polyrenderer/drawers/screen_triangle.h    |  38 +----
 src/polyrenderer/scene/poly_decal.cpp         |  54 ++-----
 src/polyrenderer/scene/poly_particle.cpp      |  55 ++------
 src/polyrenderer/scene/poly_plane.cpp         |  75 ++++------
 src/polyrenderer/scene/poly_scene.cpp         |  69 ++++-----
 src/polyrenderer/scene/poly_sky.cpp           |  39 ++---
 src/polyrenderer/scene/poly_sprite.cpp        | 116 ++++-----------
 src/polyrenderer/scene/poly_wall.cpp          |  50 +++----
 src/polyrenderer/scene/poly_wallsprite.cpp    |  37 ++---
 16 files changed, 373 insertions(+), 543 deletions(-)

diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp
index d8f93d3881..e647b203a5 100644
--- a/src/polyrenderer/drawers/poly_draw_args.cpp
+++ b/src/polyrenderer/drawers/poly_draw_args.cpp
@@ -39,21 +39,21 @@
 
 void PolyDrawArgs::SetClipPlane(float a, float b, float c, float d)
 {
-	clipPlane[0] = a;
-	clipPlane[1] = b;
-	clipPlane[2] = c;
-	clipPlane[3] = d;
+	mClipPlane[0] = a;
+	mClipPlane[1] = b;
+	mClipPlane[2] = c;
+	mClipPlane[3] = d;
 }
 
 void PolyDrawArgs::SetTexture(FTexture *texture)
 {
-	textureWidth = texture->GetWidth();
-	textureHeight = texture->GetHeight();
+	mTextureWidth = texture->GetWidth();
+	mTextureHeight = texture->GetHeight();
 	if (PolyRenderer::Instance()->RenderTarget->IsBgra())
-		texturePixels = (const uint8_t *)texture->GetPixelsBgra();
+		mTexturePixels = (const uint8_t *)texture->GetPixelsBgra();
 	else
-		texturePixels = texture->GetPixels();
-	translation = nullptr;
+		mTexturePixels = texture->GetPixels();
+	mTranslation = nullptr;
 }
 
 void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, bool forcePal)
@@ -64,22 +64,22 @@ void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, bool fo
 		if (table != nullptr && !table->Inactive)
 		{
 			if (PolyRenderer::Instance()->RenderTarget->IsBgra())
-				translation = (uint8_t*)table->Palette;
+				mTranslation = (uint8_t*)table->Palette;
 			else
-				translation = table->Remap;
+				mTranslation = table->Remap;
 
-			textureWidth = texture->GetWidth();
-			textureHeight = texture->GetHeight();
-			texturePixels = texture->GetPixels();
+			mTextureWidth = texture->GetWidth();
+			mTextureHeight = texture->GetHeight();
+			mTexturePixels = texture->GetPixels();
 			return;
 		}
 	}
 	
 	if (forcePal)
 	{
-		textureWidth = texture->GetWidth();
-		textureHeight = texture->GetHeight();
-		texturePixels = texture->GetPixels();
+		mTextureWidth = texture->GetWidth();
+		mTextureHeight = texture->GetHeight();
+		mTexturePixels = texture->GetPixels();
 	}
 	else
 	{
@@ -87,21 +87,48 @@ void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, bool fo
 	}
 }
 
-void PolyDrawArgs::SetColormap(FSWColormap *base_colormap)
+void PolyDrawArgs::SetLight(FSWColormap *base_colormap, uint32_t lightlevel, double globVis, bool fixed)
 {
-	uniforms.light_red = base_colormap->Color.r * 256 / 255;
-	uniforms.light_green = base_colormap->Color.g * 256 / 255;
-	uniforms.light_blue = base_colormap->Color.b * 256 / 255;
-	uniforms.light_alpha = base_colormap->Color.a * 256 / 255;
-	uniforms.fade_red = base_colormap->Fade.r;
-	uniforms.fade_green = base_colormap->Fade.g;
-	uniforms.fade_blue = base_colormap->Fade.b;
-	uniforms.fade_alpha = base_colormap->Fade.a;
-	uniforms.desaturate = MIN(abs(base_colormap->Desaturate), 255) * 255 / 256;
-	bool simple_shade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0);
-	if (simple_shade)
-		uniforms.flags |= TriUniforms::simple_shade;
-	else
-		uniforms.flags &= ~TriUniforms::simple_shade;
-	colormaps = base_colormap->Maps;
+	mGlobVis = (float)globVis;
+
+	PolyCameraLight *cameraLight = PolyCameraLight::Instance();
+	if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
+	{
+		lightlevel = cameraLight->FixedLightLevel() >= 0 ? cameraLight->FixedLightLevel() : 255;
+		fixed = true;
+	}
+
+	mLight = clamp<uint32_t>(lightlevel, 0, 255);
+	mFixedLight = fixed;
+	mLightRed = base_colormap->Color.r * 256 / 255;
+	mLightGreen = base_colormap->Color.g * 256 / 255;
+	mLightBlue = base_colormap->Color.b * 256 / 255;
+	mLightAlpha = base_colormap->Color.a * 256 / 255;
+	mFadeRed = base_colormap->Fade.r;
+	mFadeGreen = base_colormap->Fade.g;
+	mFadeBlue = base_colormap->Fade.b;
+	mFadeAlpha = base_colormap->Fade.a;
+	mDesaturate = MIN(abs(base_colormap->Desaturate), 255) * 255 / 256;
+	mSimpleShade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0);
+	mColormaps = base_colormap->Maps;
+}
+
+void PolyDrawArgs::SetColor(uint32_t bgra, uint8_t palindex)
+{
+	if (PolyRenderer::Instance()->RenderTarget->IsBgra())
+	{
+		mColor = bgra;
+	}
+	else
+	{
+		mColor = palindex;
+	}
+}
+
+void PolyDrawArgs::DrawArray(const TriVertex *vertices, int vcount, PolyDrawMode mode)
+{
+	mVertices = vertices;
+	mVertexCount = vcount;
+	mDrawMode = mode;
+	PolyRenderer::Instance()->DrawQueue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
 }
diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h
index bf38ffab9e..84645adef2 100644
--- a/src/polyrenderer/drawers/poly_draw_args.h
+++ b/src/polyrenderer/drawers/poly_draw_args.h
@@ -27,43 +27,114 @@
 #include "screen_triangle.h"
 
 class FTexture;
-
-enum class TriangleDrawMode
-{
-	Normal,
-	Fan,
-	Strip
-};
-
-struct TriDrawTriangleArgs;
 struct TriMatrix;
 
+enum class PolyDrawMode
+{
+	Triangles,
+	TriangleFan,
+	TriangleStrip
+};
+
 class PolyDrawArgs
 {
 public:
-	TriUniforms uniforms;
-	const TriMatrix *objectToClip = nullptr;
-	const TriVertex *vinput = nullptr;
-	int vcount = 0;
-	TriangleDrawMode mode = TriangleDrawMode::Normal;
-	bool ccw = false;
-	// bool stencilTest = true; // Always true for now
-	bool subsectorTest = false;
-	bool writeStencil = true;
-	bool writeColor = true;
-	bool writeSubsector = true;
-	const uint8_t *texturePixels = nullptr;
-	int textureWidth = 0;
-	int textureHeight = 0;
-	const uint8_t *translation = nullptr;
-	uint8_t stenciltestvalue = 0;
-	uint8_t stencilwritevalue = 0;
-	const uint8_t *colormaps = nullptr;
-	float clipPlane[4];
-	TriBlendMode blendmode = TriBlendMode::Copy;
-
 	void SetClipPlane(float a, float b, float c, float d);
 	void SetTexture(FTexture *texture);
 	void SetTexture(FTexture *texture, uint32_t translationID, bool forcePal = false);
-	void SetColormap(FSWColormap *base_colormap);
+	void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed);
+	void SetSubsectorDepth(uint32_t subsectorDepth) { mSubsectorDepth = subsectorDepth; }
+	void SetSubsectorDepthTest(bool enable) { mSubsectorTest = enable; }
+	void SetStencilTestValue(uint8_t stencilTestValue) { mStencilTestValue = stencilTestValue; }
+	void SetWriteColor(bool enable) { mWriteColor = enable; }
+	void SetWriteStencil(bool enable, uint8_t stencilWriteValue = 0) { mWriteStencil = enable; mStencilWriteValue = stencilWriteValue; }
+	void SetWriteSubsectorDepth(bool enable) { mWriteSubsector = enable; }
+	void SetFaceCullCCW(bool counterclockwise) { mFaceCullCCW = counterclockwise; }
+	void SetStyle(TriBlendMode blendmode, double srcalpha = 1.0, double destalpha = 1.0) { mBlendMode = blendmode; mSrcAlpha = (uint32_t)(srcalpha * 256.0 + 0.5); mDestAlpha = (uint32_t)(destalpha * 256.0 + 0.5); }
+	void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; }
+	void SetColor(uint32_t bgra, uint8_t palindex);
+	void DrawArray(const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
+
+	const TriMatrix *ObjectToClip() const { return mObjectToClip; }
+	const float *ClipPlane() const { return mClipPlane; }
+
+	const TriVertex *Vertices() const { return mVertices; }
+	int VertexCount() const { return mVertexCount; }
+	PolyDrawMode DrawMode() const { return mDrawMode; }
+
+	bool FaceCullCCW() const { return mFaceCullCCW; }
+	bool WriteColor() const { return mWriteColor; }
+
+	const uint8_t *TexturePixels() const { return mTexturePixels; }
+	int TextureWidth() const { return mTextureWidth; }
+	int TextureHeight() const { return mTextureHeight; }
+	const uint8_t *Translation() const { return mTranslation; }
+
+	bool WriteStencil() const { return mWriteStencil; }
+	uint8_t StencilTestValue() const { return mStencilTestValue; }
+	uint8_t StencilWriteValue() const { return mStencilWriteValue; }
+
+	bool SubsectorTest() const { return mSubsectorTest; }
+	bool WriteSubsector() const { return mWriteSubsector; }
+	uint32_t SubsectorDepth() const { return mSubsectorDepth; }
+
+	TriBlendMode BlendMode() const { return mBlendMode; }
+	uint32_t Color() const { return mColor; }
+	uint32_t SrcAlpha() const { return mSrcAlpha; }
+	uint32_t DestAlpha() const { return mDestAlpha; }
+
+	float GlobVis() const { return mGlobVis; }
+	uint32_t Light() const { return mLight; }
+	const uint8_t *BaseColormap() const { return mColormaps; }
+	uint16_t ShadeLightAlpha() const { return mLightAlpha; }
+	uint16_t ShadeLightRed() const { return mLightRed; }
+	uint16_t ShadeLightGreen() const { return mLightGreen; }
+	uint16_t ShadeLightBlue() const { return mLightBlue; }
+	uint16_t ShadeFadeAlpha() const { return mFadeAlpha; }
+	uint16_t ShadeFadeRed() const { return mFadeRed; }
+	uint16_t ShadeFadeGreen() const { return mFadeGreen; }
+	uint16_t ShadeFadeBlue() const { return mFadeBlue; }
+	uint16_t ShadeDesaturate() const { return mDesaturate; }
+
+	bool SimpleShade() const { return mSimpleShade; }
+	bool NearestFilter() const { return mNearestFilter; }
+	bool FixedLight() const { return mFixedLight; }
+
+private:
+	const TriMatrix *mObjectToClip = nullptr;
+	const TriVertex *mVertices = nullptr;
+	int mVertexCount = 0;
+	PolyDrawMode mDrawMode = PolyDrawMode::Triangles;
+	bool mFaceCullCCW = false;
+	bool mSubsectorTest = false;
+	bool mWriteStencil = true;
+	bool mWriteColor = true;
+	bool mWriteSubsector = true;
+	const uint8_t *mTexturePixels = nullptr;
+	int mTextureWidth = 0;
+	int mTextureHeight = 0;
+	const uint8_t *mTranslation = nullptr;
+	uint8_t mStencilTestValue = 0;
+	uint8_t mStencilWriteValue = 0;
+	const uint8_t *mColormaps = nullptr;
+	float mClipPlane[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+	TriBlendMode mBlendMode = TriBlendMode::Copy;
+	uint32_t mLight = 0;
+	uint32_t mSubsectorDepth = 0;
+	uint32_t mColor = 0;
+	uint32_t mSrcAlpha = 0;
+	uint32_t mDestAlpha = 0;
+	uint16_t mLightAlpha = 0;
+	uint16_t mLightRed = 0;
+	uint16_t mLightGreen = 0;
+	uint16_t mLightBlue = 0;
+	uint16_t mFadeAlpha = 0;
+	uint16_t mFadeRed = 0;
+	uint16_t mFadeGreen = 0;
+	uint16_t mFadeBlue = 0;
+	uint16_t mDesaturate = 0;
+	float mGlobVis = 0.0f;
+	bool mSimpleShade = true;
+	bool mNearestFilter = true;
+	bool mFixedLight = false;
 };
diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h
index 0e7fe0b0e5..a3568b6c1e 100644
--- a/src/polyrenderer/drawers/poly_drawer32_sse2.h
+++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h
@@ -32,12 +32,11 @@ public:
 	{
 		using namespace TriScreenDrawerModes;
 
-		auto flags = args->uniforms->flags;
-		bool is_simple_shade = (flags & TriUniforms::simple_shade) == TriUniforms::simple_shade;
+		bool is_simple_shade = args->uniforms->SimpleShade();
 
 		if (SamplerT::Mode == (int)Samplers::Texture)
 		{
-			bool is_nearest_filter = (flags & TriUniforms::nearest_filter) == TriUniforms::nearest_filter;
+			bool is_nearest_filter = args->uniforms->NearestFilter();
 
 			if (is_simple_shade)
 			{
@@ -79,11 +78,10 @@ public:
 		int startX = thread->StartX;
 		int startY = thread->StartY;
 
-		auto flags = args->uniforms->flags;
-		bool is_fixed_light = (flags & TriUniforms::fixed_light) == TriUniforms::fixed_light;
+		bool is_fixed_light = args->uniforms->FixedLight();
 		uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff;
-		uint32_t srcalpha = args->uniforms->srcalpha;
-		uint32_t destalpha = args->uniforms->destalpha;
+		uint32_t srcalpha = args->uniforms->SrcAlpha();
+		uint32_t destalpha = args->uniforms->DestAlpha();
 
 		// Calculate gradients
 		const TriVertex &v1 = *args->v1;
@@ -107,17 +105,17 @@ public:
 		int pitch = args->pitch;
 
 		// Light
-		uint32_t light = args->uniforms->light;
+		uint32_t light = args->uniforms->Light();
 		float shade = 2.0f - (light + 12.0f) / 128.0f;
-		float globVis = args->uniforms->globvis * (1.0f / 32.0f);
+		float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f);
 		light += (light >> 7); // 255 -> 256
 
 		// Sampling stuff
-		uint32_t color = args->uniforms->color;
-		const uint32_t * RESTRICT translation = (const uint32_t *)args->translation;
-		const uint32_t * RESTRICT texPixels = (const uint32_t *)args->texturePixels;
-		uint32_t texWidth = args->textureWidth;
-		uint32_t texHeight = args->textureHeight;
+		uint32_t color = args->uniforms->Color();
+		const uint32_t * RESTRICT translation = (const uint32_t *)args->uniforms->Translation();
+		const uint32_t * RESTRICT texPixels = (const uint32_t *)args->uniforms->TexturePixels();
+		uint32_t texWidth = args->uniforms->TextureWidth();
+		uint32_t texHeight = args->uniforms->TextureHeight();
 		uint32_t oneU, oneV;
 		if (SamplerT::Mode != (int)Samplers::Fill)
 		{
@@ -135,10 +133,10 @@ public:
 		int desaturate;
 		if (ShadeModeT::Mode == (int)ShadeMode::Advanced)
 		{
-			inv_desaturate = _mm_setr_epi16(256, 256 - args->uniforms->desaturate, 256 - args->uniforms->desaturate, 256 - args->uniforms->desaturate, 256, 256 - args->uniforms->desaturate, 256 - args->uniforms->desaturate, 256 - args->uniforms->desaturate);
-			shade_fade = _mm_set_epi16(args->uniforms->fade_alpha, args->uniforms->fade_red, args->uniforms->fade_green, args->uniforms->fade_blue, args->uniforms->fade_alpha, args->uniforms->fade_red, args->uniforms->fade_green, args->uniforms->fade_blue);
-			shade_light = _mm_set_epi16(args->uniforms->light_alpha, args->uniforms->light_red, args->uniforms->light_green, args->uniforms->light_blue, args->uniforms->light_alpha, args->uniforms->light_red, args->uniforms->light_green, args->uniforms->light_blue);
-			desaturate = args->uniforms->desaturate;
+			inv_desaturate = _mm_setr_epi16(256, 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256, 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate());
+			shade_fade = _mm_set_epi16(args->uniforms->ShadeFadeAlpha(), args->uniforms->ShadeFadeRed(), args->uniforms->ShadeFadeGreen(), args->uniforms->ShadeFadeBlue(), args->uniforms->ShadeFadeAlpha(), args->uniforms->ShadeFadeRed(), args->uniforms->ShadeFadeGreen(), args->uniforms->ShadeFadeBlue());
+			shade_light = _mm_set_epi16(args->uniforms->ShadeLightAlpha(), args->uniforms->ShadeLightRed(), args->uniforms->ShadeLightGreen(), args->uniforms->ShadeLightBlue(), args->uniforms->ShadeLightAlpha(), args->uniforms->ShadeLightRed(), args->uniforms->ShadeLightGreen(), args->uniforms->ShadeLightBlue());
+			desaturate = args->uniforms->ShadeDesaturate();
 		}
 		else
 		{
diff --git a/src/polyrenderer/drawers/poly_drawer8.h b/src/polyrenderer/drawers/poly_drawer8.h
index 974a454ab5..2ae40e5247 100644
--- a/src/polyrenderer/drawers/poly_drawer8.h
+++ b/src/polyrenderer/drawers/poly_drawer8.h
@@ -39,12 +39,11 @@ public:
 		int startX = thread->StartX;
 		int startY = thread->StartY;
 
-		auto flags = args->uniforms->flags;
-		bool is_fixed_light = (flags & TriUniforms::fixed_light) == TriUniforms::fixed_light;
+		bool is_fixed_light = args->uniforms->FixedLight();
 		uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff;
-		auto colormaps = args->colormaps;
-		uint32_t srcalpha = args->uniforms->srcalpha;
-		uint32_t destalpha = args->uniforms->destalpha;
+		auto colormaps = args->uniforms->BaseColormap();
+		uint32_t srcalpha = args->uniforms->SrcAlpha();
+		uint32_t destalpha = args->uniforms->DestAlpha();
 
 		// Calculate gradients
 		const TriVertex &v1 = *args->v1;
@@ -68,17 +67,17 @@ public:
 		int pitch = args->pitch;
 
 		// Light
-		uint32_t light = args->uniforms->light;
+		uint32_t light = args->uniforms->Light();
 		float shade = 2.0f - (light + 12.0f) / 128.0f;
-		float globVis = args->uniforms->globvis * (1.0f / 32.0f);
+		float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f);
 		light += light >> 7; // 255 -> 256
 
 		// Sampling stuff
-		uint32_t color = args->uniforms->color;
-		const uint8_t * RESTRICT translation = args->translation;
-		const uint8_t * RESTRICT texPixels = args->texturePixels;
-		uint32_t texWidth = args->textureWidth;
-		uint32_t texHeight = args->textureHeight;
+		uint32_t color = args->uniforms->Color();
+		const uint8_t * RESTRICT translation = args->uniforms->Translation();
+		const uint8_t * RESTRICT texPixels = args->uniforms->TexturePixels();
+		uint32_t texWidth = args->uniforms->TextureWidth();
+		uint32_t texHeight = args->uniforms->TextureHeight();
 
 		for (int i = 0; i < numSpans; i++)
 		{
diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp
index fa4b8b98c1..d07102f1ea 100644
--- a/src/polyrenderer/drawers/poly_triangle.cpp
+++ b/src/polyrenderer/drawers/poly_triangle.cpp
@@ -80,35 +80,35 @@ void PolyTriangleDrawer::toggle_mirror()
 	mirror = !mirror;
 }
 
-void PolyTriangleDrawer::draw(const PolyDrawArgs &args)
+bool PolyTriangleDrawer::is_mirror()
 {
-	PolyRenderer::Instance()->DrawQueue->Push<DrawPolyTrianglesCommand>(args, mirror);
+	return mirror;
 }
 
 void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadData *thread)
 {
-	if (drawargs.vcount < 3)
+	if (drawargs.VertexCount() < 3)
 		return;
 
 	PolyDrawFuncPtr drawfuncs[4];
 	int num_drawfuncs = 0;
 	
-	drawfuncs[num_drawfuncs++] = drawargs.subsectorTest ? &ScreenTriangle::SetupSubsector : &ScreenTriangle::SetupNormal;
+	drawfuncs[num_drawfuncs++] = drawargs.SubsectorTest() ? &ScreenTriangle::SetupSubsector : &ScreenTriangle::SetupNormal;
 
 	if (!r_debug_trisetup) // For profiling how much time is spent in setup vs drawal
 	{
-		int bmode = (int)drawargs.blendmode;
+		int bmode = (int)drawargs.BlendMode();
 
-		if (drawargs.writeColor && drawargs.texturePixels)
+		if (drawargs.WriteColor() && drawargs.TexturePixels())
 			drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriDraw32[bmode] : ScreenTriangle::TriDraw8[bmode];
-		else if (drawargs.writeColor)
+		else if (drawargs.WriteColor())
 			drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriFill32[bmode] : ScreenTriangle::TriFill8[bmode];
 	}
 
-	if (drawargs.writeStencil)
+	if (drawargs.WriteStencil())
 		drawfuncs[num_drawfuncs++] = &ScreenTriangle::StencilWrite;
 
-	if (drawargs.writeSubsector)
+	if (drawargs.WriteSubsector())
 		drawfuncs[num_drawfuncs++] = &ScreenTriangle::SubsectorWrite;
 
 	TriDrawTriangleArgs args;
@@ -118,53 +118,44 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
 	args.clipright = dest_width;
 	args.cliptop = 0;
 	args.clipbottom = dest_height;
-	args.texturePixels = drawargs.texturePixels;
-	args.textureWidth = drawargs.textureWidth;
-	args.textureHeight = drawargs.textureHeight;
-	args.translation = drawargs.translation;
-	args.uniforms = &drawargs.uniforms;
-	args.stencilTestValue = drawargs.stenciltestvalue;
-	args.stencilWriteValue = drawargs.stencilwritevalue;
+	args.uniforms = &drawargs;
 	args.stencilPitch = PolyStencilBuffer::Instance()->BlockWidth();
 	args.stencilValues = PolyStencilBuffer::Instance()->Values();
 	args.stencilMasks = PolyStencilBuffer::Instance()->Masks();
 	args.subsectorGBuffer = PolySubsectorGBuffer::Instance()->Values();
-	args.colormaps = drawargs.colormaps;
-	args.RGB256k = RGB256k.All;
-	args.BaseColors = (const uint8_t *)GPalette.BaseColors;
 
-	bool ccw = drawargs.ccw;
-	const TriVertex *vinput = drawargs.vinput;
-	int vcount = drawargs.vcount;
+	bool ccw = drawargs.FaceCullCCW();
+	const TriVertex *vinput = drawargs.Vertices();
+	int vcount = drawargs.VertexCount();
 
 	ShadedTriVertex vert[3];
-	if (drawargs.mode == TriangleDrawMode::Normal)
+	if (drawargs.DrawMode() == PolyDrawMode::Triangles)
 	{
 		for (int i = 0; i < vcount / 3; i++)
 		{
 			for (int j = 0; j < 3; j++)
-				vert[j] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
+				vert[j] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
 			draw_shaded_triangle(vert, ccw, &args, thread, drawfuncs, num_drawfuncs);
 		}
 	}
-	else if (drawargs.mode == TriangleDrawMode::Fan)
+	else if (drawargs.DrawMode() == PolyDrawMode::TriangleFan)
 	{
-		vert[0] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
-		vert[1] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
+		vert[0] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
+		vert[1] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
 		for (int i = 2; i < vcount; i++)
 		{
-			vert[2] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
+			vert[2] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
 			draw_shaded_triangle(vert, ccw, &args, thread, drawfuncs, num_drawfuncs);
 			vert[1] = vert[2];
 		}
 	}
-	else // TriangleDrawMode::Strip
+	else // TriangleDrawMode::TriangleStrip
 	{
-		vert[0] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
-		vert[1] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
+		vert[0] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
+		vert[1] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
 		for (int i = 2; i < vcount; i++)
 		{
-			vert[2] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
+			vert[2] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
 			draw_shaded_triangle(vert, ccw, &args, thread, drawfuncs, num_drawfuncs);
 			vert[0] = vert[1];
 			vert[1] = vert[2];
@@ -448,7 +439,7 @@ DrawPolyTrianglesCommand::DrawPolyTrianglesCommand(const PolyDrawArgs &args, boo
 	: args(args)
 {
 	if (mirror)
-		this->args.ccw = !this->args.ccw;
+		this->args.SetFaceCullCCW(!this->args.FaceCullCCW());
 }
 
 void DrawPolyTrianglesCommand::Execute(DrawerThread *thread)
@@ -461,32 +452,3 @@ void DrawPolyTrianglesCommand::Execute(DrawerThread *thread)
 
 	PolyTriangleDrawer::draw_arrays(args, &thread_data);
 }
-
-FString DrawPolyTrianglesCommand::DebugInfo()
-{
-	FString blendmodestr;
-	switch (args.blendmode)
-	{
-	default: blendmodestr = "Unknown"; break;
-	case TriBlendMode::Copy: blendmodestr = "Copy"; break;
-	case TriBlendMode::AlphaBlend: blendmodestr = "AlphaBlend"; break;
-	case TriBlendMode::AddSolid: blendmodestr = "AddSolid"; break;
-	case TriBlendMode::Add: blendmodestr = "Add"; break;
-	case TriBlendMode::Sub: blendmodestr = "Sub"; break;
-	case TriBlendMode::RevSub: blendmodestr = "RevSub"; break;
-	case TriBlendMode::Stencil: blendmodestr = "Stencil"; break;
-	case TriBlendMode::Shaded: blendmodestr = "Shaded"; break;
-	case TriBlendMode::TranslateCopy: blendmodestr = "TranslateCopy"; break;
-	case TriBlendMode::TranslateAlphaBlend: blendmodestr = "TranslateAlphaBlend"; break;
-	case TriBlendMode::TranslateAdd: blendmodestr = "TranslateAdd"; break;
-	case TriBlendMode::TranslateSub: blendmodestr = "TranslateSub"; break;
-	case TriBlendMode::TranslateRevSub: blendmodestr = "TranslateRevSub"; break;
-	case TriBlendMode::AddSrcColorOneMinusSrcColor: blendmodestr = "AddSrcColorOneMinusSrcColor"; break;
-	}
-
-	FString info;
-	info.Format("DrawPolyTriangles: blend mode = %s, color = %d, light = %d, textureWidth = %d, textureHeight = %d, texture = %s, translation = %s, colormaps = %s",
-		blendmodestr.GetChars(), args.uniforms.color, args.uniforms.light, args.textureWidth, args.textureHeight,
-		args.texturePixels ? "ptr" : "null", args.translation ? "ptr" : "null", args.colormaps ? "ptr" : "null");
-	return info;
-}
diff --git a/src/polyrenderer/drawers/poly_triangle.h b/src/polyrenderer/drawers/poly_triangle.h
index a52faa3266..d3019fc36a 100644
--- a/src/polyrenderer/drawers/poly_triangle.h
+++ b/src/polyrenderer/drawers/poly_triangle.h
@@ -40,8 +40,8 @@ class PolyTriangleDrawer
 {
 public:
 	static void set_viewport(int x, int y, int width, int height, DCanvas *canvas);
-	static void draw(const PolyDrawArgs &args);
 	static void toggle_mirror();
+	static bool is_mirror();
 
 private:
 	static ShadedTriVertex shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v);
@@ -66,7 +66,7 @@ public:
 	DrawPolyTrianglesCommand(const PolyDrawArgs &args, bool mirror);
 
 	void Execute(DrawerThread *thread) override;
-	FString DebugInfo() override;
+	FString DebugInfo() override { return "DrawPolyTriangles"; }
 
 private:
 	PolyDrawArgs args;
diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp
index 37a14c0628..ab0928d0ee 100644
--- a/src/polyrenderer/drawers/screen_triangle.cpp
+++ b/src/polyrenderer/drawers/screen_triangle.cpp
@@ -52,7 +52,7 @@ void ScreenTriangle::SetupNormal(const TriDrawTriangleArgs *args, WorkerThreadDa
 	int stencilPitch = args->stencilPitch;
 	uint8_t * RESTRICT stencilValues = args->stencilValues;
 	uint32_t * RESTRICT stencilMasks = args->stencilMasks;
-	uint8_t stencilTestValue = args->stencilTestValue;
+	uint8_t stencilTestValue = args->uniforms->StencilTestValue();
 	
 	TriFullSpan * RESTRICT span = thread->FullSpans;
 	TriPartialBlock * RESTRICT partial = thread->PartialBlocks;
@@ -389,10 +389,10 @@ void ScreenTriangle::SetupSubsector(const TriDrawTriangleArgs *args, WorkerThrea
 	int stencilPitch = args->stencilPitch;
 	uint8_t * RESTRICT stencilValues = args->stencilValues;
 	uint32_t * RESTRICT stencilMasks = args->stencilMasks;
-	uint8_t stencilTestValue = args->stencilTestValue;
+	uint8_t stencilTestValue = args->uniforms->StencilTestValue();
 
 	uint32_t * RESTRICT subsectorGBuffer = args->subsectorGBuffer;
-	uint32_t subsectorDepth = args->uniforms->subsectorDepth;
+	uint32_t subsectorDepth = args->uniforms->SubsectorDepth();
 	int32_t pitch = args->pitch;
 
 	TriFullSpan * RESTRICT span = thread->FullSpans;
@@ -800,7 +800,7 @@ void ScreenTriangle::StencilWrite(const TriDrawTriangleArgs *args, WorkerThreadD
 {
 	uint8_t * RESTRICT stencilValues = args->stencilValues;
 	uint32_t * RESTRICT stencilMasks = args->stencilMasks;
-	uint32_t stencilWriteValue = args->stencilWriteValue;
+	uint32_t stencilWriteValue = args->uniforms->StencilWriteValue();
 	uint32_t stencilPitch = args->stencilPitch;
 
 	int numSpans = thread->NumFullSpans;
@@ -869,7 +869,7 @@ void ScreenTriangle::StencilWrite(const TriDrawTriangleArgs *args, WorkerThreadD
 void ScreenTriangle::SubsectorWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
 {
 	uint32_t * RESTRICT subsectorGBuffer = args->subsectorGBuffer;
-	uint32_t subsectorDepth = args->uniforms->subsectorDepth;
+	uint32_t subsectorDepth = args->uniforms->SubsectorDepth();
 	int pitch = args->pitch;
 
 	int numSpans = thread->NumFullSpans;
diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h
index 470029c841..81d7cdb68e 100644
--- a/src/polyrenderer/drawers/screen_triangle.h
+++ b/src/polyrenderer/drawers/screen_triangle.h
@@ -26,6 +26,7 @@
 #include <vector>
 
 class FString;
+class PolyDrawArgs;
 
 struct TriFullSpan
 {
@@ -67,32 +68,6 @@ struct TriVertex
 	float varying[NumVarying];
 };
 
-struct TriUniforms
-{
-	uint32_t light;
-	uint32_t subsectorDepth;
-	uint32_t color;
-	uint32_t srcalpha;
-	uint32_t destalpha;
-	uint16_t light_alpha;
-	uint16_t light_red;
-	uint16_t light_green;
-	uint16_t light_blue;
-	uint16_t fade_alpha;
-	uint16_t fade_red;
-	uint16_t fade_green;
-	uint16_t fade_blue;
-	uint16_t desaturate;
-	float globvis;
-	uint32_t flags;
-	enum Flags
-	{
-		simple_shade = 1,
-		nearest_filter = 2,
-		fixed_light = 4
-	};
-};
-
 struct TriDrawTriangleArgs
 {
 	uint8_t *dest;
@@ -104,20 +79,11 @@ struct TriDrawTriangleArgs
 	int32_t clipright;
 	int32_t cliptop;
 	int32_t clipbottom;
-	const uint8_t *texturePixels;
-	uint32_t textureWidth;
-	uint32_t textureHeight;
-	const uint8_t *translation;
-	const TriUniforms *uniforms;
 	uint8_t *stencilValues;
 	uint32_t *stencilMasks;
 	int32_t stencilPitch;
-	uint8_t stencilTestValue;
-	uint8_t stencilWriteValue;
 	uint32_t *subsectorGBuffer;
-	const uint8_t *colormaps;
-	const uint8_t *RGB256k;
-	const uint8_t *BaseColors;
+	const PolyDrawArgs *uniforms;
 };
 
 enum class TriBlendMode
diff --git a/src/polyrenderer/scene/poly_decal.cpp b/src/polyrenderer/scene/poly_decal.cpp
index 21f7281d44..cf49bc0b16 100644
--- a/src/polyrenderer/scene/poly_decal.cpp
+++ b/src/polyrenderer/scene/poly_decal.cpp
@@ -130,49 +130,21 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 	}
 
 	bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT;
-
-	PolyCameraLight *cameraLight = PolyCameraLight::Instance();
+	int lightlevel = fullbrightSprite ? 255 : front->lightlevel + actualextralight;
 
 	PolyDrawArgs args;
-	args.uniforms.flags = TriUniforms::nearest_filter;
-	args.SetColormap(GetColorTable(front->Colormap));
+	args.SetLight(GetColorTable(front->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite);
 	args.SetTexture(tex, decal->Translation, true);
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-	{
-		args.uniforms.light = 255;
-		args.uniforms.flags |= TriUniforms::fixed_light;
-	}
-	else
-	{
-		args.uniforms.light = front->lightlevel + actualextralight;
-	}
-	args.uniforms.subsectorDepth = subsectorDepth;
-
-	if (PolyRenderer::Instance()->RenderTarget->IsBgra())
-	{
-		args.uniforms.color = 0xff000000 | decal->AlphaColor;
-	}
-	else
-	{
-		args.uniforms.color = ((uint32_t)decal->AlphaColor) >> 24;
-	}
-	
-	args.uniforms.srcalpha = (uint32_t)(decal->Alpha * 256.0 + 0.5);
-	args.uniforms.destalpha = 256 - args.uniforms.srcalpha;
-
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = 4;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = true;
-	args.stenciltestvalue = stencilValue;
-	args.stencilwritevalue = stencilValue;
-	//mode = R_SetPatchStyle (decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor);
+	args.SetSubsectorDepth(subsectorDepth);
+	args.SetColor(0xff000000 | decal->AlphaColor, decal->AlphaColor >> 24);
+	args.SetStyle(TriBlendMode::Shaded, decal->Alpha, 1.0 - decal->Alpha); // R_SetPatchStyle (decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor);
+	args.SetTransform(&worldToClip);
+	args.SetFaceCullCCW(true);
+	args.SetStencilTestValue(stencilValue);
+	args.SetWriteStencil(true, stencilValue);
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
-	args.blendmode = TriBlendMode::Shaded;
-	args.subsectorTest = true;
-	args.writeStencil = false;
-	args.writeSubsector = false;
-	PolyTriangleDrawer::draw(args);
+	args.SetSubsectorDepthTest(true);
+	args.SetWriteStencil(false);
+	args.SetWriteSubsectorDepth(false);
+	args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 }
diff --git a/src/polyrenderer/scene/poly_particle.cpp b/src/polyrenderer/scene/poly_particle.cpp
index 37f9783081..eb6fc3c95a 100644
--- a/src/polyrenderer/scene/poly_particle.cpp
+++ b/src/polyrenderer/scene/poly_particle.cpp
@@ -68,51 +68,20 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipP
 		vertices[i].varying[1] = (float)(1.0f - offsets[i].second);
 	}
 
-	// int color = (particle->color >> 24) & 0xff; // pal index, I think
 	bool fullbrightSprite = particle->bright != 0;
-	PolyCameraLight *cameraLight = PolyCameraLight::Instance();
+	int lightlevel = fullbrightSprite ? 255 : sub->sector->lightlevel + actualextralight;
 
 	PolyDrawArgs args;
-
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.ParticleGlobVis(foggy);
-
-	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-	{
-		args.uniforms.light = 255;
-		args.uniforms.flags = TriUniforms::fixed_light | TriUniforms::nearest_filter;
-	}
-	else
-	{
-		args.uniforms.light = sub->sector->lightlevel + actualextralight;
-		args.uniforms.flags = TriUniforms::nearest_filter;
-	}
-	args.uniforms.subsectorDepth = subsectorDepth;
-
-	uint32_t alpha = (uint32_t)clamp(particle->alpha * 255.0f + 0.5f, 0.0f, 255.0f);
-
-	if (PolyRenderer::Instance()->RenderTarget->IsBgra())
-	{
-		args.uniforms.color = (alpha << 24) | (particle->color & 0xffffff);
-	}
-	else
-	{
-		args.uniforms.color = ((uint32_t)particle->color) >> 24;
-		args.uniforms.srcalpha = alpha;
-		args.uniforms.destalpha = 255 - alpha;
-	}
-
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = 4;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = true;
-	args.stenciltestvalue = stencilValue;
-	args.stencilwritevalue = stencilValue;
-	args.SetColormap(GetColorTable(sub->sector->Colormap));
+	args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.ParticleGlobVis(foggy), fullbrightSprite);
+	args.SetSubsectorDepth(subsectorDepth);
+	args.SetSubsectorDepthTest(true);
+	args.SetColor(particle->color | 0xff000000, particle->color >> 24);
+	args.SetStyle(TriBlendMode::AlphaBlend, particle->alpha, 1.0 - particle->alpha);
+	args.SetTransform(&worldToClip);
+	args.SetFaceCullCCW(true);
+	args.SetStencilTestValue(stencilValue);
+	args.SetWriteStencil(false);
+	args.SetWriteSubsectorDepth(false);
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
-	args.subsectorTest = true;
-	args.writeStencil = false;
-	args.writeSubsector = false;
-	args.blendmode = TriBlendMode::AlphaBlend;
-	PolyTriangleDrawer::draw(args);
+	args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 }
diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp
index 4b616910d5..5ae891bfd8 100644
--- a/src/polyrenderer/scene/poly_plane.cpp
+++ b/src/polyrenderer/scene/poly_plane.cpp
@@ -111,16 +111,7 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c
 
 	UVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex);
 
-	PolyDrawArgs args;
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy); // .SlopePlaneGlobVis(foggy) * 48.0f;
-	args.uniforms.light = lightlevel;
-	if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-		args.uniforms.light = 255;
-	args.uniforms.flags = TriUniforms::nearest_filter;
-	args.uniforms.subsectorDepth = subsectorDepth;
-
 	TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(sub->numlines);
-
 	if (ceiling)
 	{
 		for (uint32_t i = 0; i < sub->numlines; i++)
@@ -138,18 +129,17 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c
 		}
 	}
 
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = sub->numlines;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = true;
-	args.stenciltestvalue = stencilValue;
-	args.stencilwritevalue = stencilValue + 1;
+	PolyDrawArgs args;
+	args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
+	args.SetSubsectorDepth(subsectorDepth);
+	args.SetTransform(&worldToClip);
+	args.SetStyle(TriBlendMode::Copy);
+	args.SetFaceCullCCW(true);
+	args.SetStencilTestValue(stencilValue);
+	args.SetWriteStencil(true, stencilValue + 1);
 	args.SetTexture(tex);
-	args.SetColormap(GetColorTable(sub->sector->Colormap));
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
-	args.blendmode = TriBlendMode::Copy;
-	PolyTriangleDrawer::draw(args);
+	args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
 }
 
 void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
@@ -291,16 +281,6 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 
 	UVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex);
 
-	PolyCameraLight *cameraLight = PolyCameraLight::Instance();
-
-	PolyDrawArgs args;
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);// ->SlopePlaneGlobVis(foggy) * 48.0f;
-	args.uniforms.light = frontsector->lightlevel;
-	if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-		args.uniforms.light = 255;
-	args.uniforms.flags = TriUniforms::nearest_filter;
-	args.uniforms.subsectorDepth = isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth;
-
 	TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(sub->numlines);
 
 	if (ceiling)
@@ -320,37 +300,36 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 		}
 	}
 
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = sub->numlines;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = ccw;
-	args.stenciltestvalue = stencilValue;
-	args.stencilwritevalue = stencilValue + 1;
-	args.SetColormap(GetColorTable(frontsector->Colormap, frontsector->SpecialColors[ceiling]));
+	PolyDrawArgs args;
+	args.SetLight(GetColorTable(frontsector->Colormap, frontsector->SpecialColors[ceiling]), frontsector->lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
+	args.SetSubsectorDepth(isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth);
+	args.SetTransform(&worldToClip);
+	args.SetFaceCullCCW(ccw);
+	args.SetStencilTestValue(stencilValue);
+	args.SetWriteStencil(true, stencilValue + 1);
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
 
 	if (!isSky)
 	{
 		args.SetTexture(tex);
-		args.blendmode = TriBlendMode::Copy;
-		PolyTriangleDrawer::draw(args);
+		args.SetStyle(TriBlendMode::Copy);
+		args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
 	}
 	else
 	{
 		if (portal)
 		{
-			args.stencilwritevalue = polyportal->StencilValue;
-			polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth });
+			args.SetWriteStencil(true, polyportal->StencilValue);
+			polyportal->Shape.push_back({ vertices, (int)sub->numlines, ccw, subsectorDepth });
 		}
 		else
 		{
-			args.stencilwritevalue = 255;
+			args.SetWriteStencil(true, 255);
 		}
 
-		args.writeColor = false;
-		args.writeSubsector = false;
-		PolyTriangleDrawer::draw(args);
+		args.SetWriteColor(false);
+		args.SetWriteSubsectorDepth(false);
+		args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
 
 		for (uint32_t i = 0; i < sub->numlines; i++)
 		{
@@ -414,13 +393,11 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 				wallvert[3] = PlaneVertex(line->v1, skyHeight, transform);
 			}
 
-			args.vinput = wallvert;
-			args.vcount = 4;
-			PolyTriangleDrawer::draw(args);
+			args.DrawArray(wallvert, 4, PolyDrawMode::TriangleFan);
 			
 			if (portal)
 			{
-				polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth });
+				polyportal->Shape.push_back({ wallvert, 4, ccw, subsectorDepth });
 			}
 		}
 	}
diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp
index 79f7631cf8..2ea63f4397 100644
--- a/src/polyrenderer/scene/poly_scene.cpp
+++ b/src/polyrenderer/scene/poly_scene.cpp
@@ -249,40 +249,33 @@ void RenderPolyScene::RenderPortals(int portalDepth)
 	else // Fill with black
 	{
 		PolyDrawArgs args;
-		args.objectToClip = &WorldToClip;
-		args.mode = TriangleDrawMode::Fan;
-		args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-		args.uniforms.color = 0;
-		args.uniforms.light = 255;
-		args.uniforms.flags = TriUniforms::fixed_light;
+		args.SetTransform(&WorldToClip);
+		args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(foggy), true);
+		args.SetColor(0, 0);
 		args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
+		args.SetStyle(TriBlendMode::Copy);
 
 		for (auto &portal : SectorPortals)
 		{
-			args.stenciltestvalue = portal->StencilValue;
-			args.stencilwritevalue = portal->StencilValue + 1;
+			args.SetStencilTestValue(portal->StencilValue);
+			args.SetWriteStencil(true, portal->StencilValue + 1);
 			for (const auto &verts : portal->Shape)
 			{
-				args.vinput = verts.Vertices;
-				args.vcount = verts.Count;
-				args.ccw = verts.Ccw;
-				args.uniforms.subsectorDepth = verts.SubsectorDepth;
-				args.blendmode = TriBlendMode::Copy;
-				PolyTriangleDrawer::draw(args);
+				args.SetFaceCullCCW(verts.Ccw);
+				args.SetSubsectorDepth(verts.SubsectorDepth);
+				args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
 			}
 		}
 
 		for (auto &portal : LinePortals)
 		{
-			args.stenciltestvalue = portal->StencilValue;
-			args.stencilwritevalue = portal->StencilValue + 1;
+			args.SetStencilTestValue(portal->StencilValue);
+			args.SetWriteStencil(true, portal->StencilValue + 1);
 			for (const auto &verts : portal->Shape)
 			{
-				args.vinput = verts.Vertices;
-				args.vcount = verts.Count;
-				args.ccw = verts.Ccw;
-				args.uniforms.subsectorDepth = verts.SubsectorDepth;
-				PolyTriangleDrawer::draw(args);
+				args.SetFaceCullCCW(verts.Ccw);
+				args.SetSubsectorDepth(verts.SubsectorDepth);
+				args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
 			}
 		}
 	}
@@ -298,19 +291,16 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
 			portal->RenderTranslucent(portalDepth + 1);
 		
 			PolyDrawArgs args;
-			args.objectToClip = &WorldToClip;
-			args.mode = TriangleDrawMode::Fan;
-			args.stenciltestvalue = portal->StencilValue + 1;
-			args.stencilwritevalue = StencilValue + 1;
+			args.SetTransform(&WorldToClip);
+			args.SetStencilTestValue(portal->StencilValue + 1);
+			args.SetWriteStencil(true, StencilValue + 1);
 			args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
 			for (const auto &verts : portal->Shape)
 			{
-				args.vinput = verts.Vertices;
-				args.vcount = verts.Count;
-				args.ccw = verts.Ccw;
-				args.uniforms.subsectorDepth = verts.SubsectorDepth;
-				args.writeColor = false;
-				PolyTriangleDrawer::draw(args);
+				args.SetFaceCullCCW(verts.Ccw);
+				args.SetSubsectorDepth(verts.SubsectorDepth);
+				args.SetWriteColor(false);
+				args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
 			}
 		}
 
@@ -320,19 +310,16 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
 			portal->RenderTranslucent(portalDepth + 1);
 		
 			PolyDrawArgs args;
-			args.objectToClip = &WorldToClip;
-			args.mode = TriangleDrawMode::Fan;
-			args.stenciltestvalue = portal->StencilValue + 1;
-			args.stencilwritevalue = StencilValue + 1;
+			args.SetTransform(&WorldToClip);
+			args.SetStencilTestValue(portal->StencilValue + 1);
+			args.SetWriteStencil(true, StencilValue + 1);
 			args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
 			for (const auto &verts : portal->Shape)
 			{
-				args.vinput = verts.Vertices;
-				args.vcount = verts.Count;
-				args.ccw = verts.Ccw;
-				args.uniforms.subsectorDepth = verts.SubsectorDepth;
-				args.writeColor = false;
-				PolyTriangleDrawer::draw(args);
+				args.SetFaceCullCCW(verts.Ccw);
+				args.SetSubsectorDepth(verts.SubsectorDepth);
+				args.SetWriteColor(false);
+				args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
 			}
 		}
 	}
diff --git a/src/polyrenderer/scene/poly_sky.cpp b/src/polyrenderer/scene/poly_sky.cpp
index b30ba69a8f..a38845ebec 100644
--- a/src/polyrenderer/scene/poly_sky.cpp
+++ b/src/polyrenderer/scene/poly_sky.cpp
@@ -38,7 +38,6 @@ PolySkyDome::PolySkyDome()
 void PolySkyDome::Render(const TriMatrix &worldToClip)
 {
 	FTextureID sky1tex, sky2tex;
-	bool foggy = false;
 	if ((level.flags & LEVEL_SWAPSKIES) && !(level.flags & LEVEL_DOUBLESKY))
 		sky1tex = sky2texture;
 	else
@@ -57,14 +56,11 @@ void PolySkyDome::Render(const TriMatrix &worldToClip)
 	int rc = mRows + 1;
 
 	PolyDrawArgs args;
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-	args.uniforms.light = 255;
-	args.uniforms.flags = TriUniforms::nearest_filter;
-	args.uniforms.subsectorDepth = RenderPolyScene::SkySubsectorDepth;
-	args.objectToClip = &objectToClip;
-	args.stenciltestvalue = 255;
-	args.stencilwritevalue = 1;
-	args.SetColormap(&NormalLight);
+	args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(false), true);
+	args.SetSubsectorDepth(RenderPolyScene::SkySubsectorDepth);
+	args.SetTransform(&objectToClip);
+	args.SetStencilTestValue(255);
+	args.SetWriteStencil(true, 1);
 	args.SetClipPlane(0.0f, 0.0f, 0.0f, 0.0f);
 
 	RenderCapColorRow(args, frontskytex, 0, false);
@@ -84,28 +80,21 @@ void PolySkyDome::Render(const TriMatrix &worldToClip)
 
 void PolySkyDome::RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor)
 {
-	args.vinput = &mVertices[mPrimStart[row]];
-	args.vcount = mPrimStart[row + 1] - mPrimStart[row];
-	args.mode = TriangleDrawMode::Strip;
-	args.ccw = false;
-	args.uniforms.color = capcolor;
-	args.blendmode = TriBlendMode::Skycap;
-	PolyTriangleDrawer::draw(args);
+	args.SetFaceCullCCW(false);
+	args.SetColor(capcolor, 0);
+	args.SetStyle(TriBlendMode::Skycap);
+	args.DrawArray(&mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip);
 }
 
 void PolySkyDome::RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap)
 {
 	uint32_t solid = skytex->GetSkyCapColor(bottomCap);
-	if (!PolyRenderer::Instance()->RenderTarget->IsBgra())
-		solid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)];
+	uint8_t palsolid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)];
 
-	args.vinput = &mVertices[mPrimStart[row]];
-	args.vcount = mPrimStart[row + 1] - mPrimStart[row];
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = bottomCap;
-	args.uniforms.color = solid;
-	args.blendmode = TriBlendMode::Copy;
-	PolyTriangleDrawer::draw(args);
+	args.SetFaceCullCCW(bottomCap);
+	args.SetColor(solid, palsolid);
+	args.SetStyle(TriBlendMode::Copy);
+	args.DrawArray(&mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleFan);
 }
 
 void PolySkyDome::CreateDome()
diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp
index a2ead5d764..ff3303ea06 100644
--- a/src/polyrenderer/scene/poly_sprite.cpp
+++ b/src/polyrenderer/scene/poly_sprite.cpp
@@ -136,136 +136,80 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla
 	}
 
 	bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
-	PolyCameraLight *cameraLight = PolyCameraLight::Instance();
+	int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
 
 	PolyDrawArgs args;
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
-	args.uniforms.flags = TriUniforms::nearest_filter;
-	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-	{
-		args.uniforms.light = 255;
-		args.uniforms.flags |= TriUniforms::fixed_light;
-	}
-	else
-	{
-		args.uniforms.light = thing->Sector->lightlevel + actualextralight;
-	}
-	args.uniforms.subsectorDepth = subsectorDepth;
-
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = 4;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = true;
-	args.stenciltestvalue = stencilValue;
-	args.stencilwritevalue = stencilValue;
+	args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite);
+	args.SetSubsectorDepth(subsectorDepth);
+	args.SetTransform(&worldToClip);
+	args.SetFaceCullCCW(true);
+	args.SetStencilTestValue(stencilValue);
+	args.SetWriteStencil(true, stencilValue);
 	args.SetTexture(tex, thing->Translation);
-	args.SetColormap(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true));
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
 
-	TriBlendMode blendmode;
-	
 	if (thing->RenderStyle == LegacyRenderStyles[STYLE_Normal] ||
 		 (r_drawfuzz == 0 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
 	{
-		args.uniforms.destalpha = 0;
-		args.uniforms.srcalpha = 256;
-		blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, 1.0, 0.0);
 	}
-	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add] && fullbrightSprite && thing->Alpha == 1.0 && args.translation == nullptr)
+	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add] && fullbrightSprite && thing->Alpha == 1.0 && !args.Translation())
 	{
-		args.uniforms.destalpha = 256;
-		args.uniforms.srcalpha = 256;
-		blendmode = TriBlendMode::AddSrcColorOneMinusSrcColor;
+		args.SetStyle(TriBlendMode::AddSrcColorOneMinusSrcColor, 1.0, 1.0);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add])
 	{
-		args.uniforms.destalpha = (uint32_t)(1.0 * 256);
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, thing->Alpha, 1.0);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Subtract])
 	{
-		args.uniforms.destalpha = (uint32_t)(1.0 * 256);
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		blendmode = args.translation ? TriBlendMode::TranslateRevSub : TriBlendMode::RevSub;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateRevSub : TriBlendMode::RevSub, thing->Alpha, 1.0);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_SoulTrans])
 	{
-		args.uniforms.destalpha = (uint32_t)(256 - transsouls * 256);
-		args.uniforms.srcalpha = (uint32_t)(transsouls * 256);
-		blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, transsouls, 1.0 - transsouls);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Fuzzy] ||
 		 (r_drawfuzz == 2 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
 	{	// NYI - Fuzzy - for now, just a copy of "Shadow"
-		args.uniforms.destalpha = 160;
-		args.uniforms.srcalpha = 0;
-		blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, 0.0, 160 / 255.0);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Shadow] ||
 		 (r_drawfuzz == 1 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
 	{
-		args.uniforms.destalpha = 160;
-		args.uniforms.srcalpha = 0;
-		blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, 0.0, 160 / 255.0);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_TranslucentStencil])
 	{
-		args.uniforms.destalpha = (uint32_t)(256 - thing->Alpha * 256);
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		args.uniforms.color = 0xff000000 | thing->fillcolor;
-		blendmode = TriBlendMode::Stencil;
+		args.SetColor(0xff000000 | thing->fillcolor, thing->fillcolor >> 24);
+		args.SetStyle(TriBlendMode::Stencil, thing->Alpha, 1.0 - thing->Alpha);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_AddStencil])
 	{
-		args.uniforms.destalpha = 256;
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		args.uniforms.color = 0xff000000 | thing->fillcolor;
-		blendmode = TriBlendMode::Stencil;
+		args.SetColor(0xff000000 | thing->fillcolor, thing->fillcolor >> 24);
+		args.SetStyle(TriBlendMode::Stencil, thing->Alpha, 1.0 - thing->Alpha);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Shaded])
 	{
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		args.uniforms.destalpha = 256 - args.uniforms.srcalpha;
-		args.uniforms.color = 0;
-		blendmode = TriBlendMode::Shaded;
+		args.SetColor(0, 0);
+		args.SetStyle(TriBlendMode::Shaded, thing->Alpha, 1.0 - thing->Alpha);
+		args.SetTexture(tex, thing->Translation, true);
 	}
 	else if (thing->RenderStyle == LegacyRenderStyles[STYLE_AddShaded])
 	{
-		args.uniforms.destalpha = 256;
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		args.uniforms.color = 0;
-		blendmode = TriBlendMode::Shaded;
+		args.SetColor(0, 0);
+		args.SetStyle(TriBlendMode::Shaded, thing->Alpha, 1.0 - thing->Alpha);
+		args.SetTexture(tex, thing->Translation, true);
 	}
 	else
 	{
-		args.uniforms.destalpha = (uint32_t)(256 - thing->Alpha * 256);
-		args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
-		blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
+		args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, thing->Alpha, 1.0 - thing->Alpha);
 	}
 	
-	if (blendmode == TriBlendMode::Shaded)
-	{
-		args.SetTexture(tex, thing->Translation, true);
-	}
-	
-	if (!PolyRenderer::Instance()->RenderTarget->IsBgra())
-	{
-		uint32_t r = (args.uniforms.color >> 16) & 0xff;
-		uint32_t g = (args.uniforms.color >> 8) & 0xff;
-		uint32_t b = args.uniforms.color & 0xff;
-		args.uniforms.color = RGB32k.RGB[r >> 3][g >> 3][b >> 3];
-
-		if (blendmode == TriBlendMode::Sub) // Sub crashes in pal mode for some weird reason.
-			blendmode = TriBlendMode::Add;
-	}
-
-	args.subsectorTest = true;
-	args.writeSubsector = false;
-	args.writeStencil = false;
-	args.blendmode = blendmode;
-	PolyTriangleDrawer::draw(args);
+	args.SetSubsectorDepthTest(true);
+	args.SetWriteSubsectorDepth(false);
+	args.SetWriteStencil(false);
+	args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 }
 
 bool RenderPolySprite::IsThingCulled(AActor *thing)
diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp
index 96b3ecc626..8164d71ef0 100644
--- a/src/polyrenderer/scene/poly_wall.cpp
+++ b/src/polyrenderer/scene/poly_wall.cpp
@@ -248,32 +248,23 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane
 	}
 
 	PolyDrawArgs args;
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-	args.uniforms.light = GetLightLevel();
-	args.uniforms.flags = TriUniforms::nearest_filter;
-	args.uniforms.subsectorDepth = SubsectorDepth;
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = 4;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = true;
-	args.stenciltestvalue = StencilValue;
-	args.stencilwritevalue = StencilValue + 1;
+	args.SetLight(GetColorTable(Line->frontsector->Colormap, Line->frontsector->SpecialColors[sector_t::walltop]), GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
+	args.SetSubsectorDepth(SubsectorDepth);
+	args.SetTransform(&worldToClip);
+	args.SetFaceCullCCW(true);
+	args.SetStencilTestValue(StencilValue);
+	args.SetWriteStencil(true, StencilValue + 1);
 	if (tex)
 		args.SetTexture(tex);
-	args.SetColormap(GetColorTable(Line->frontsector->Colormap, Line->frontsector->SpecialColors[sector_t::walltop]));
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
 
-	//if (Side && Side->lighthead)
-	//	args.uniforms.light = 255; // Make walls touched by a light fullbright!
-
 	if (Polyportal)
 	{
-		args.stencilwritevalue = Polyportal->StencilValue;
-		args.writeColor = false;
-		args.writeSubsector = false;
-		PolyTriangleDrawer::draw(args);
-		Polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, args.uniforms.subsectorDepth });
+		args.SetWriteStencil(true, Polyportal->StencilValue);
+		args.SetWriteColor(false);
+		args.SetWriteSubsectorDepth(false);
+		args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
+		Polyportal->Shape.push_back({ vertices, 4, true, SubsectorDepth });
 
 		angle_t angle1, angle2;
 		if (cull.GetAnglesForLine(v1.X, v1.Y, v2.X, v2.Y, angle1, angle2))
@@ -281,21 +272,16 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane
 	}
 	else if (!Masked)
 	{
-		args.blendmode = TriBlendMode::Copy;
-		PolyTriangleDrawer::draw(args);
+		args.SetStyle(TriBlendMode::Copy);
+		args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 	}
 	else
 	{
-		args.uniforms.destalpha = (Line->flags & ML_ADDTRANS) ? 256 : (uint32_t)(256 - Line->alpha * 256);
-		args.uniforms.srcalpha = (uint32_t)(Line->alpha * 256);
-		args.subsectorTest = true;
-		args.writeSubsector = false;
-		args.writeStencil = false;
-		if (args.uniforms.destalpha == 0 && args.uniforms.srcalpha == 256)
-			args.blendmode = TriBlendMode::AlphaBlend;
-		else
-			args.blendmode = TriBlendMode::Add;
-		PolyTriangleDrawer::draw(args);
+		args.SetStyle((Line->flags & ML_ADDTRANS) ? TriBlendMode::Add : TriBlendMode::AlphaBlend, Line->alpha, 1.0);
+		args.SetSubsectorDepthTest(true);
+		args.SetWriteSubsectorDepth(true);
+		args.SetWriteStencil(false);
+		args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 	}
 
 	RenderPolyDecal::RenderWallDecals(worldToClip, clipPlane, LineSeg, SubsectorDepth, StencilValue);
diff --git a/src/polyrenderer/scene/poly_wallsprite.cpp b/src/polyrenderer/scene/poly_wallsprite.cpp
index 509a5e8dac..9e4e2498ca 100644
--- a/src/polyrenderer/scene/poly_wallsprite.cpp
+++ b/src/polyrenderer/scene/poly_wallsprite.cpp
@@ -97,35 +97,18 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &cli
 	}
 
 	bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
-	PolyCameraLight *cameraLight = PolyCameraLight::Instance();
+	int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
 
 	PolyDrawArgs args;
-	args.uniforms.globvis = (float)PolyRenderer::Instance()->Light.WallGlobVis(foggy);
-	if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
-	{
-		args.uniforms.light = 255;
-		args.uniforms.flags = TriUniforms::fixed_light | TriUniforms::nearest_filter;
-	}
-	else
-	{
-		args.uniforms.light = thing->Sector->lightlevel + actualextralight;
-		args.uniforms.flags = TriUniforms::nearest_filter;
-	}
-	args.uniforms.subsectorDepth = subsectorDepth;
-
-	args.objectToClip = &worldToClip;
-	args.vinput = vertices;
-	args.vcount = 4;
-	args.mode = TriangleDrawMode::Fan;
-	args.ccw = true;
-	args.stenciltestvalue = stencilValue;
-	args.stencilwritevalue = stencilValue;
+	args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite);
+	args.SetTransform(&worldToClip);
+	args.SetFaceCullCCW(true);
+	args.SetStencilTestValue(stencilValue);
 	args.SetTexture(tex);
-	args.SetColormap(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true));
 	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
-	args.subsectorTest = true;
-	args.writeSubsector = false;
-	args.writeStencil = false;
-	args.blendmode = TriBlendMode::AlphaBlend;
-	PolyTriangleDrawer::draw(args);
+	args.SetSubsectorDepthTest(true);
+	args.SetWriteSubsectorDepth(false);
+	args.SetWriteStencil(false);
+	args.SetStyle(TriBlendMode::AlphaBlend);
+	args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 }

From 28be42675d9f8e21c1e42dc395e7f65b9acbbac7 Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sun, 26 Mar 2017 11:49:23 +0300
Subject: [PATCH 3/4] Fixed build of SDL backend on macOS

---
 src/posix/sdl/i_system.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp
index e00f137a7a..01457c012f 100644
--- a/src/posix/sdl/i_system.cpp
+++ b/src/posix/sdl/i_system.cpp
@@ -84,6 +84,7 @@ int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
 int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
 #endif
 
+double PerfToSec, PerfToMillisec;
 uint32_t LanguageIDs[4];
 	
 int (*I_GetTime) (bool saveMS);

From a12f0862c9db66c7002c1e536311e38677d9cae3 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Sun, 26 Mar 2017 17:12:20 +0200
Subject: [PATCH 4/4] - remove softpoly intersection math class

---
 src/CMakeLists.txt                          |   1 -
 src/polyrenderer/drawers/poly_draw_args.cpp |  10 +-
 src/polyrenderer/drawers/poly_draw_args.h   |  11 +-
 src/polyrenderer/math/poly_intersection.cpp | 235 --------------------
 src/polyrenderer/math/poly_intersection.h   | 179 ---------------
 src/polyrenderer/poly_all.cpp               |   1 -
 src/polyrenderer/poly_renderer.cpp          |   2 +-
 src/polyrenderer/scene/poly_cull.cpp        |  17 +-
 src/polyrenderer/scene/poly_cull.h          |   6 +-
 src/polyrenderer/scene/poly_decal.cpp       |   6 +-
 src/polyrenderer/scene/poly_decal.h         |   6 +-
 src/polyrenderer/scene/poly_particle.cpp    |   4 +-
 src/polyrenderer/scene/poly_particle.h      |   4 +-
 src/polyrenderer/scene/poly_plane.cpp       |  10 +-
 src/polyrenderer/scene/poly_plane.h         |   7 +-
 src/polyrenderer/scene/poly_portal.cpp      |  14 +-
 src/polyrenderer/scene/poly_scene.cpp       |   8 +-
 src/polyrenderer/scene/poly_scene.h         |   5 +-
 src/polyrenderer/scene/poly_sky.cpp         |   2 +-
 src/polyrenderer/scene/poly_sprite.cpp      |   5 +-
 src/polyrenderer/scene/poly_sprite.h        |   4 +-
 src/polyrenderer/scene/poly_wall.cpp        |   8 +-
 src/polyrenderer/scene/poly_wall.h          |   7 +-
 src/polyrenderer/scene/poly_wallsprite.cpp  |   4 +-
 src/polyrenderer/scene/poly_wallsprite.h    |   4 +-
 25 files changed, 59 insertions(+), 501 deletions(-)
 delete mode 100644 src/polyrenderer/math/poly_intersection.cpp
 delete mode 100644 src/polyrenderer/math/poly_intersection.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0100d5c311..3a3efad308 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -872,7 +872,6 @@ set( POLYRENDER_SOURCES
 	polyrenderer/drawers/poly_draw_args.cpp
 	polyrenderer/drawers/screen_triangle.cpp
 	polyrenderer/math/tri_matrix.cpp
-	polyrenderer/math/poly_intersection.cpp
 )
 
 # These files will be flagged as "headers" so that they appear in project files
diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp
index e647b203a5..eaa812dc91 100644
--- a/src/polyrenderer/drawers/poly_draw_args.cpp
+++ b/src/polyrenderer/drawers/poly_draw_args.cpp
@@ -37,12 +37,12 @@
 #include "poly_draw_args.h"
 #include "swrenderer/viewport/r_viewport.h"
 
-void PolyDrawArgs::SetClipPlane(float a, float b, float c, float d)
+void PolyDrawArgs::SetClipPlane(const PolyClipPlane &plane)
 {
-	mClipPlane[0] = a;
-	mClipPlane[1] = b;
-	mClipPlane[2] = c;
-	mClipPlane[3] = d;
+	mClipPlane[0] = plane.A;
+	mClipPlane[1] = plane.B;
+	mClipPlane[2] = plane.C;
+	mClipPlane[3] = plane.D;
 }
 
 void PolyDrawArgs::SetTexture(FTexture *texture)
diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h
index 84645adef2..20c73ec583 100644
--- a/src/polyrenderer/drawers/poly_draw_args.h
+++ b/src/polyrenderer/drawers/poly_draw_args.h
@@ -36,10 +36,19 @@ enum class PolyDrawMode
 	TriangleStrip
 };
 
+class PolyClipPlane
+{
+public:
+	PolyClipPlane() : A(0.0f), B(0.0f), C(0.0f), D(1.0f) { }
+	PolyClipPlane(float a, float b, float c, float d) : A(a), B(b), C(c), D(d) { }
+
+	float A, B, C, D;
+};
+
 class PolyDrawArgs
 {
 public:
-	void SetClipPlane(float a, float b, float c, float d);
+	void SetClipPlane(const PolyClipPlane &plane);
 	void SetTexture(FTexture *texture);
 	void SetTexture(FTexture *texture, uint32_t translationID, bool forcePal = false);
 	void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed);
diff --git a/src/polyrenderer/math/poly_intersection.cpp b/src/polyrenderer/math/poly_intersection.cpp
deleted file mode 100644
index ed5e8ef438..0000000000
--- a/src/polyrenderer/math/poly_intersection.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-**  Various 3D intersection tests
-**  Copyright (c) 1997-2015 The UICore Team
-**
-**  This software is provided 'as-is', without any express or implied
-**  warranty.  In no event will the authors be held liable for any damages
-**  arising from the use of this software.
-**
-**  Permission is granted to anyone to use this software for any purpose,
-**  including commercial applications, and to alter it and redistribute it
-**  freely, subject to the following restrictions:
-**
-**  1. The origin of this software must not be misrepresented; you must not
-**     claim that you wrote the original software. If you use this software
-**     in a product, an acknowledgment in the product documentation would be
-**     appreciated but is not required.
-**  2. Altered source versions must be plainly marked as such, and must not be
-**     misrepresented as being the original software.
-**  3. This notice may not be removed or altered from any source distribution.
-**
-*/
-
-#include <stdlib.h>
-#include "templates.h"
-#include "doomdef.h"
-#include "poly_intersection.h"
-
-IntersectionTest::Result IntersectionTest::plane_aabb(const Vec4f &plane, const AxisAlignedBoundingBox &aabb)
-{
-	Vec3f center = aabb.center();
-	Vec3f extents = aabb.extents();
-	float e = extents.x * std::abs(plane.x) + extents.y * std::abs(plane.y) + extents.z * std::abs(plane.z);
-	float s = center.x * plane.x + center.y * plane.y + center.z * plane.z + plane.w;
-	if (s - e > 0)
-		return inside;
-	else if (s + e < 0)
-		return outside;
-	else
-		return intersecting;
-}
-
-IntersectionTest::Result IntersectionTest::plane_obb(const Vec4f &plane, const OrientedBoundingBox &obb)
-{
-	Vec3f n(plane);
-	float d = plane.w;
-	float e = obb.extents.x * std::abs(Vec3f::dot(obb.axis_x, n)) + obb.extents.y * std::abs(Vec3f::dot(obb.axis_y, n)) + obb.extents.z * std::abs(Vec3f::dot(obb.axis_z, n));
-	float s = Vec3f::dot(obb.center, n) + d;
-	if (s - e > 0)
-		return inside;
-	else if (s + e < 0)
-		return outside;
-	else
-		return intersecting;
-}
-
-IntersectionTest::OverlapResult IntersectionTest::sphere(const Vec3f &center1, float radius1, const Vec3f &center2, float radius2)
-{
-	Vec3f h = center1 - center2;
-	float square_distance = Vec3f::dot(h, h);
-	float radius_sum = radius1 + radius2;
-	if (square_distance > radius_sum * radius_sum)
-		return disjoint;
-	else
-		return overlap;
-}
-
-IntersectionTest::OverlapResult IntersectionTest::sphere_aabb(const Vec3f &center, float radius, const AxisAlignedBoundingBox &aabb)
-{
-	Vec3f a = aabb.aabb_min - center;
-	Vec3f b = center - aabb.aabb_max;
-	a.x = std::max(a.x, 0.0f);
-	a.y = std::max(a.y, 0.0f);
-	a.z = std::max(a.z, 0.0f);
-	b.x = std::max(b.x, 0.0f);
-	b.y = std::max(b.y, 0.0f);
-	b.z = std::max(b.z, 0.0f);
-	Vec3f e = a + b;
-	float d = Vec3f::dot(e, e);
-	if (d > radius * radius)
-		return disjoint;
-	else
-		return overlap;
-}
-
-IntersectionTest::OverlapResult IntersectionTest::aabb(const AxisAlignedBoundingBox &a, const AxisAlignedBoundingBox &b)
-{
-	if (a.aabb_min.x > b.aabb_max.x || b.aabb_min.x > a.aabb_max.x ||
-		a.aabb_min.y > b.aabb_max.y || b.aabb_min.y > a.aabb_max.y ||
-		a.aabb_min.z > b.aabb_max.z || b.aabb_min.z > a.aabb_max.z)
-	{
-		return disjoint;
-	}
-	else
-	{
-		return overlap;
-	}
-}
-
-IntersectionTest::Result IntersectionTest::frustum_aabb(const FrustumPlanes &frustum, const AxisAlignedBoundingBox &box)
-{
-	bool is_intersecting = false;
-	for (int i = 0; i < 6; i++)
-	{
-		Result result = plane_aabb(frustum.planes[i], box);
-		if (result == outside)
-			return outside;
-		else if (result == intersecting)
-			is_intersecting = true;
-		break;
-	}
-	if (is_intersecting)
-		return intersecting;
-	else
-		return inside;
-}
-
-IntersectionTest::Result IntersectionTest::frustum_obb(const FrustumPlanes &frustum, const OrientedBoundingBox &box)
-{
-	bool is_intersecting = false;
-	for (int i = 0; i < 6; i++)
-	{
-		Result result = plane_obb(frustum.planes[i], box);
-		if (result == outside)
-			return outside;
-		else if (result == intersecting)
-			is_intersecting = true;
-	}
-	if (is_intersecting)
-		return intersecting;
-	else
-		return inside;
-}
-
-IntersectionTest::OverlapResult IntersectionTest::ray_aabb(const Vec3f &ray_start, const Vec3f &ray_end, const AxisAlignedBoundingBox &aabb)
-{
-	Vec3f c = (ray_start + ray_end) * 0.5f;
-	Vec3f w = ray_end - c;
-	Vec3f h = aabb.extents();
-
-	c -= aabb.center();
-
-	Vec3f v(std::abs(w.x), std::abs(w.y), std::abs(w.z));
-
-	if (std::abs(c.x) > v.x + h.x || std::abs(c.y) > v.y + h.y || std::abs(c.z) > v.z + h.z)
-		return disjoint;
-
-	if (std::abs(c.y * w.z - c.z * w.y) > h.y * v.z + h.z * v.y ||
-		std::abs(c.x * w.z - c.z * w.x) > h.x * v.z + h.z * v.x ||
-		std::abs(c.x * w.y - c.y * w.x) > h.x * v.y + h.y * v.x)
-		return disjoint;
-
-	return overlap;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-FrustumPlanes::FrustumPlanes()
-{
-}
-
-FrustumPlanes::FrustumPlanes(const Mat4f &world_to_projection)
-{
-	planes[0] = near_frustum_plane(world_to_projection);
-	planes[1] = far_frustum_plane(world_to_projection);
-	planes[2] = left_frustum_plane(world_to_projection);
-	planes[3] = right_frustum_plane(world_to_projection);
-	planes[4] = top_frustum_plane(world_to_projection);
-	planes[5] = bottom_frustum_plane(world_to_projection);
-}
-
-Vec4f FrustumPlanes::left_frustum_plane(const Mat4f &m)
-{
-	Vec4f plane(
-		m.matrix[3 + 0 * 4] + m.matrix[0 + 0 * 4],
-		m.matrix[3 + 1 * 4] + m.matrix[0 + 1 * 4],
-		m.matrix[3 + 2 * 4] + m.matrix[0 + 2 * 4],
-		m.matrix[3 + 3 * 4] + m.matrix[0 + 3 * 4]);
-	plane /= plane.length3();
-	return plane;
-}
-
-Vec4f FrustumPlanes::right_frustum_plane(const Mat4f &m)
-{
-	Vec4f plane(
-		m.matrix[3 + 0 * 4] - m.matrix[0 + 0 * 4],
-		m.matrix[3 + 1 * 4] - m.matrix[0 + 1 * 4],
-		m.matrix[3 + 2 * 4] - m.matrix[0 + 2 * 4],
-		m.matrix[3 + 3 * 4] - m.matrix[0 + 3 * 4]);
-	plane /= plane.length3();
-	return plane;
-}
-
-Vec4f FrustumPlanes::top_frustum_plane(const Mat4f &m)
-{
-	Vec4f plane(
-		m.matrix[3 + 0 * 4] - m.matrix[1 + 0 * 4],
-		m.matrix[3 + 1 * 4] - m.matrix[1 + 1 * 4],
-		m.matrix[3 + 2 * 4] - m.matrix[1 + 2 * 4],
-		m.matrix[3 + 3 * 4] - m.matrix[1 + 3 * 4]);
-	plane /= plane.length3();
-	return plane;
-}
-
-Vec4f FrustumPlanes::bottom_frustum_plane(const Mat4f &m)
-{
-	Vec4f plane(
-		m.matrix[3 + 0 * 4] + m.matrix[1 + 0 * 4],
-		m.matrix[3 + 1 * 4] + m.matrix[1 + 1 * 4],
-		m.matrix[3 + 2 * 4] + m.matrix[1 + 2 * 4],
-		m.matrix[3 + 3 * 4] + m.matrix[1 + 3 * 4]);
-	plane /= plane.length3();
-	return plane;
-}
-
-Vec4f FrustumPlanes::near_frustum_plane(const Mat4f &m)
-{
-	Vec4f plane(
-		m.matrix[3 + 0 * 4] + m.matrix[2 + 0 * 4],
-		m.matrix[3 + 1 * 4] + m.matrix[2 + 1 * 4],
-		m.matrix[3 + 2 * 4] + m.matrix[2 + 2 * 4],
-		m.matrix[3 + 3 * 4] + m.matrix[2 + 3 * 4]);
-	plane /= plane.length3();
-	return plane;
-}
-
-Vec4f FrustumPlanes::far_frustum_plane(const Mat4f &m)
-{
-	Vec4f plane(
-		m.matrix[3 + 0 * 4] - m.matrix[2 + 0 * 4],
-		m.matrix[3 + 1 * 4] - m.matrix[2 + 1 * 4],
-		m.matrix[3 + 2 * 4] - m.matrix[2 + 2 * 4],
-		m.matrix[3 + 3 * 4] - m.matrix[2 + 3 * 4]);
-	plane /= plane.length3();
-	return plane;
-}
diff --git a/src/polyrenderer/math/poly_intersection.h b/src/polyrenderer/math/poly_intersection.h
deleted file mode 100644
index 438146fce3..0000000000
--- a/src/polyrenderer/math/poly_intersection.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-**  Various 3D intersection tests
-**  Copyright (c) 1997-2015 The UICore Team
-**
-**  This software is provided 'as-is', without any express or implied
-**  warranty.  In no event will the authors be held liable for any damages
-**  arising from the use of this software.
-**
-**  Permission is granted to anyone to use this software for any purpose,
-**  including commercial applications, and to alter it and redistribute it
-**  freely, subject to the following restrictions:
-**
-**  1. The origin of this software must not be misrepresented; you must not
-**     claim that you wrote the original software. If you use this software
-**     in a product, an acknowledgment in the product documentation would be
-**     appreciated but is not required.
-**  2. Altered source versions must be plainly marked as such, and must not be
-**     misrepresented as being the original software.
-**  3. This notice may not be removed or altered from any source distribution.
-**
-*/
-
-#pragma once
-
-#include "polyrenderer/drawers/poly_triangle.h"
-#include <algorithm>
-#include <cmath>
-
-class Vec3f;
-
-class Vec4f
-{
-public:
-	Vec4f() = default;
-	Vec4f(const Vec4f &) = default;
-	Vec4f(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) { }
-	Vec4f(float v) : x(v), y(v), z(v), w(v) { }
-	Vec4f(const Vec3f &xyz, float w);
-
-	static float dot(const Vec4f &a, const Vec4f &b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; }
-	static float dot3(const Vec4f &a, const Vec4f &b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
-	float length3() const { return std::sqrt(dot3(*this, *this)); }
-	float magnitude() const { return std::sqrt(dot(*this, *this)); }
-
-	Vec4f &operator+=(const Vec4f &b) { *this = Vec4f(x + b.x, y + b.y, z + b.z, w + b.w); return *this; }
-	Vec4f &operator-=(const Vec4f &b) { *this = Vec4f(x - b.x, y - b.y, z - b.z, w - b.w); return *this; }
-	Vec4f &operator*=(const Vec4f &b) { *this = Vec4f(x * b.x, y * b.y, z * b.z, w * b.w); return *this; }
-	Vec4f &operator/=(const Vec4f &b) { *this = Vec4f(x / b.x, y / b.y, z / b.z, w / b.w); return *this; }
-	Vec4f &operator+=(float b) { *this = Vec4f(x + b, y + b, z + b, w + b); return *this; }
-	Vec4f &operator-=(float b) { *this = Vec4f(x - b, y - b, z - b, w - b); return *this; }
-	Vec4f &operator*=(float b) { *this = Vec4f(x * b, y * b, z * b, w * b); return *this; }
-	Vec4f &operator/=(float b) { *this = Vec4f(x / b, y / b, z / b, w / b); return *this; }
-
-	float x, y, z, w;
-};
-
-inline bool operator==(const Vec4f &a, const Vec4f &b) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; }
-inline bool operator!=(const Vec4f &a, const Vec4f &b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w == b.w; }
-
-class Vec3f
-{
-public:
-	Vec3f() = default;
-	Vec3f(const Vec3f &) = default;
-	Vec3f(const Vec4f &v) : x(v.x), y(v.y), z(v.z) { }
-	Vec3f(float x, float y, float z) : x(x), y(y), z(z) { }
-	Vec3f(float v) : x(v), y(v), z(v) { }
-
-	static float dot(const Vec3f &a, const Vec3f &b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
-	float length() const { return std::sqrt(dot(*this, *this)); }
-
-	Vec3f &operator+=(const Vec3f &b) { *this = Vec3f(x + b.x, y + b.y, z + b.z); return *this; }
-	Vec3f &operator-=(const Vec3f &b) { *this = Vec3f(x - b.x, y - b.y, z - b.z); return *this; }
-	Vec3f &operator*=(const Vec3f &b) { *this = Vec3f(x * b.x, y * b.y, z * b.z); return *this; }
-	Vec3f &operator/=(const Vec3f &b) { *this = Vec3f(x / b.x, y / b.y, z / b.z); return *this; }
-	Vec3f &operator+=(float b) { *this = Vec3f(x + b, y + b, z + b); return *this; }
-	Vec3f &operator-=(float b) { *this = Vec3f(x - b, y - b, z - b); return *this; }
-	Vec3f &operator*=(float b) { *this = Vec3f(x * b, y * b, z * b); return *this; }
-	Vec3f &operator/=(float b) { *this = Vec3f(x / b, y / b, z / b); return *this; }
-
-	float x, y, z;
-};
-
-inline bool operator==(const Vec3f &a, const Vec3f &b) { return a.x == b.x && a.y == b.y && a.z == b.z; }
-inline bool operator!=(const Vec3f &a, const Vec3f &b) { return a.x != b.x || a.y != b.y || a.z != b.z; }
-
-inline Vec3f operator+(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x + b.x, a.y + b.y, a.z + b.z); }
-inline Vec3f operator-(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x - b.x, a.y - b.y, a.z - b.z); }
-inline Vec3f operator*(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x * b.x, a.y * b.y, a.z * b.z); }
-inline Vec3f operator/(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x / b.x, a.y / b.y, a.z / b.z); }
-
-inline Vec3f operator+(const Vec3f &a, float b) { return Vec3f(a.x + b, a.y + b, a.z + b); }
-inline Vec3f operator-(const Vec3f &a, float b) { return Vec3f(a.x - b, a.y - b, a.z - b); }
-inline Vec3f operator*(const Vec3f &a, float b) { return Vec3f(a.x * b, a.y * b, a.z * b); }
-inline Vec3f operator/(const Vec3f &a, float b) { return Vec3f(a.x / b, a.y / b, a.z / b); }
-
-inline Vec3f operator+(float a, const Vec3f &b) { return Vec3f(a + b.x, a + b.y, a + b.z); }
-inline Vec3f operator-(float a, const Vec3f &b) { return Vec3f(a - b.x, a - b.y, a - b.z); }
-inline Vec3f operator*(float a, const Vec3f &b) { return Vec3f(a * b.x, a * b.y, a * b.z); }
-inline Vec3f operator/(float a, const Vec3f &b) { return Vec3f(a / b.x, a / b.y, a / b.z); }
-
-inline Vec4f::Vec4f(const Vec3f &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { }
-
-typedef TriMatrix Mat4f;
-
-class AxisAlignedBoundingBox
-{
-public:
-	AxisAlignedBoundingBox() : aabb_min(), aabb_max() {}
-	AxisAlignedBoundingBox(const Vec3f &aabb_min, const Vec3f &aabb_max) : aabb_min(aabb_min), aabb_max(aabb_max) { }
-	AxisAlignedBoundingBox(const AxisAlignedBoundingBox &aabb, const Vec3f &barycentric_min, const Vec3f &barycentric_max)
-		: aabb_min(mix(aabb.aabb_min, aabb.aabb_max, barycentric_min)), aabb_max(mix(aabb.aabb_min, aabb.aabb_max, barycentric_max)) { }
-
-	Vec3f center() const { return (aabb_max + aabb_min) * 0.5f; }
-	Vec3f extents() const { return (aabb_max - aabb_min) * 0.5f; }
-
-	Vec3f aabb_min;
-	Vec3f aabb_max;
-
-private:
-	template<typename A, typename B, typename C>
-	inline A mix(A a, B b, C mix)
-	{
-		return a * (C(1) - mix) + b * mix;
-	}
-};
-
-class OrientedBoundingBox
-{
-public:
-	Vec3f center;
-	Vec3f extents;
-	Vec3f axis_x;
-	Vec3f axis_y;
-	Vec3f axis_z;
-};
-
-class FrustumPlanes
-{
-public:
-	FrustumPlanes();
-	explicit FrustumPlanes(const Mat4f &world_to_projection);
-
-	Vec4f planes[6];
-
-private:
-	static Vec4f left_frustum_plane(const Mat4f &matrix);
-	static Vec4f right_frustum_plane(const Mat4f &matrix);
-	static Vec4f top_frustum_plane(const Mat4f &matrix);
-	static Vec4f bottom_frustum_plane(const Mat4f &matrix);
-	static Vec4f near_frustum_plane(const Mat4f &matrix);
-	static Vec4f far_frustum_plane(const Mat4f &matrix);
-};
-
-class IntersectionTest
-{
-public:
-	enum Result
-	{
-		outside,
-		inside,
-		intersecting,
-	};
-
-	enum OverlapResult
-	{
-		disjoint,
-		overlap
-	};
-
-	static Result plane_aabb(const Vec4f &plane, const AxisAlignedBoundingBox &aabb);
-	static Result plane_obb(const Vec4f &plane, const OrientedBoundingBox &obb);
-	static OverlapResult sphere(const Vec3f &center1, float radius1, const Vec3f &center2, float radius2);
-	static OverlapResult sphere_aabb(const Vec3f &center, float radius, const AxisAlignedBoundingBox &aabb);
-	static OverlapResult aabb(const AxisAlignedBoundingBox &a, const AxisAlignedBoundingBox &b);
-	static Result frustum_aabb(const FrustumPlanes &frustum, const AxisAlignedBoundingBox &box);
-	static Result frustum_obb(const FrustumPlanes &frustum, const OrientedBoundingBox &box);
-	static OverlapResult ray_aabb(const Vec3f &ray_start, const Vec3f &ray_end, const AxisAlignedBoundingBox &box);
-};
diff --git a/src/polyrenderer/poly_all.cpp b/src/polyrenderer/poly_all.cpp
index 2ad4b45a45..286dae4cb9 100644
--- a/src/polyrenderer/poly_all.cpp
+++ b/src/polyrenderer/poly_all.cpp
@@ -3,7 +3,6 @@
 #include "drawers/poly_draw_args.cpp"
 #include "drawers/poly_triangle.cpp"
 #include "drawers/screen_triangle.cpp"
-#include "math/poly_intersection.cpp"
 #include "math/tri_matrix.cpp"
 #include "scene/poly_cull.cpp"
 #include "scene/poly_decal.cpp"
diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp
index 2e400975f6..1fb6de710b 100644
--- a/src/polyrenderer/poly_renderer.cpp
+++ b/src/polyrenderer/poly_renderer.cpp
@@ -135,7 +135,7 @@ void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines)
 	ClearBuffers();
 	SetSceneViewport();
 	SetupPerspectiveMatrix();
-	MainPortal.SetViewpoint(WorldToClip, Vec4f(0.0f, 0.0f, 0.0f, 1.0f), GetNextStencilValue());
+	MainPortal.SetViewpoint(WorldToClip, PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f), GetNextStencilValue());
 	MainPortal.Render(0);
 	Skydome.Render(WorldToClip);
 	MainPortal.RenderTranslucent(0);
diff --git a/src/polyrenderer/scene/poly_cull.cpp b/src/polyrenderer/scene/poly_cull.cpp
index 01f157a93f..623b6e9df9 100644
--- a/src/polyrenderer/scene/poly_cull.cpp
+++ b/src/polyrenderer/scene/poly_cull.cpp
@@ -28,10 +28,9 @@
 #include "poly_cull.h"
 #include "polyrenderer/poly_renderer.h"
 
-void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane)
+void PolyCull::CullScene(const TriMatrix &worldToClip, const PolyClipPlane &portalClipPlane)
 {
 	PvsSectors.clear();
-	frustumPlanes = FrustumPlanes(worldToClip);
 	PortalClipPlane = portalClipPlane;
 
 	// Cull front to back
@@ -210,20 +209,6 @@ int PolyCull::PointOnSide(const DVector2 &pos, const node_t *node)
 
 bool PolyCull::CheckBBox(float *bspcoord)
 {
-#if 0 // This doesn't work because it creates gaps in the angle based clipper segment list :(
-	// Start using a quick frustum AABB test:
-
-	AxisAlignedBoundingBox aabb(Vec3f(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM], (float)PolyRenderer::Instance()->Viewpoint.Pos.Z - 1000.0f), Vec3f(bspcoord[BOXRIGHT], bspcoord[BOXTOP], (float)PolyRenderer::Instance()->Viewpoint.Pos.Z + 1000.0f));
-	auto result = IntersectionTest::frustum_aabb(frustumPlanes, aabb);
-	if (result == IntersectionTest::outside)
-		return false;
-
-	// Skip if its in front of the portal:
-
-	if (IntersectionTest::plane_aabb(PortalClipPlane, aabb) == IntersectionTest::outside)
-		return false;
-#endif
-
 	// Occlusion test using solid segments:
 	static const uint8_t checkcoord[12][4] =
 	{
diff --git a/src/polyrenderer/scene/poly_cull.h b/src/polyrenderer/scene/poly_cull.h
index d0430501d9..64e4d57399 100644
--- a/src/polyrenderer/scene/poly_cull.h
+++ b/src/polyrenderer/scene/poly_cull.h
@@ -23,13 +23,12 @@
 #pragma once
 
 #include "polyrenderer/drawers/poly_triangle.h"
-#include "polyrenderer/math/poly_intersection.h"
 
 class PolyCull
 {
 public:
 	void ClearSolidSegments();
-	void CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane);
+	void CullScene(const TriMatrix &worldToClip, const PolyClipPlane &portalClipPlane);
 
 	bool GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const;
 	void MarkSegmentCulled(angle_t angle1, angle_t angle2);
@@ -61,8 +60,7 @@ private:
 	const int SolidCullScale = 3000;
 	bool FirstSkyHeight = true;
 
-	FrustumPlanes frustumPlanes;
-	Vec4f PortalClipPlane;
+	PolyClipPlane PortalClipPlane;
 
 	static angle_t PointToPseudoAngle(double x, double y);
 	static angle_t AngleToPseudo(angle_t ang);
diff --git a/src/polyrenderer/scene/poly_decal.cpp b/src/polyrenderer/scene/poly_decal.cpp
index cf49bc0b16..829f444b6d 100644
--- a/src/polyrenderer/scene/poly_decal.cpp
+++ b/src/polyrenderer/scene/poly_decal.cpp
@@ -31,7 +31,7 @@
 #include "a_sharedglobal.h"
 #include "swrenderer/scene/r_scene.h"
 
-void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const Vec4f &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
+void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
 {
 	if (line->linedef == nullptr && line->sidedef == nullptr)
 		return;
@@ -43,7 +43,7 @@ void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const Vec4f
 	}
 }
 
-void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
+void RenderPolyDecal::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
 {
 	if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid())
 		return;
@@ -142,7 +142,7 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 	args.SetFaceCullCCW(true);
 	args.SetStencilTestValue(stencilValue);
 	args.SetWriteStencil(true, stencilValue);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 	args.SetSubsectorDepthTest(true);
 	args.SetWriteStencil(false);
 	args.SetWriteSubsectorDepth(false);
diff --git a/src/polyrenderer/scene/poly_decal.h b/src/polyrenderer/scene/poly_decal.h
index 48907780a8..a0d676951c 100644
--- a/src/polyrenderer/scene/poly_decal.h
+++ b/src/polyrenderer/scene/poly_decal.h
@@ -24,13 +24,11 @@
 
 #include "polyrenderer/drawers/poly_triangle.h"
 
-class Vec4f;
-
 class RenderPolyDecal
 {
 public:
-	static void RenderWallDecals(const TriMatrix &worldToClip, const Vec4f &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
+	static void RenderWallDecals(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
 
 private:
-	void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
+	void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
 };
diff --git a/src/polyrenderer/scene/poly_particle.cpp b/src/polyrenderer/scene/poly_particle.cpp
index eb6fc3c95a..d4a49334b9 100644
--- a/src/polyrenderer/scene/poly_particle.cpp
+++ b/src/polyrenderer/scene/poly_particle.cpp
@@ -29,7 +29,7 @@
 #include "polyrenderer/poly_renderer.h"
 #include "polyrenderer/scene/poly_light.h"
 
-void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
+void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
 {
 	DVector3 pos = particle->Pos;
 	double psize = particle->size / 8.0;
@@ -82,6 +82,6 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipP
 	args.SetStencilTestValue(stencilValue);
 	args.SetWriteStencil(false);
 	args.SetWriteSubsectorDepth(false);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 	args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
 }
diff --git a/src/polyrenderer/scene/poly_particle.h b/src/polyrenderer/scene/poly_particle.h
index b3b25b996d..e91174591c 100644
--- a/src/polyrenderer/scene/poly_particle.h
+++ b/src/polyrenderer/scene/poly_particle.h
@@ -25,10 +25,8 @@
 #include "polyrenderer/drawers/poly_triangle.h"
 #include "p_effect.h"
 
-class Vec4f;
-
 class RenderPolyParticle
 {
 public:
-	void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
+	void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
 };
diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp
index 5ae891bfd8..d41328d573 100644
--- a/src/polyrenderer/scene/poly_plane.cpp
+++ b/src/polyrenderer/scene/poly_plane.cpp
@@ -33,7 +33,7 @@
 
 EXTERN_CVAR(Int, r_3dfloors)
 
-void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
+void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
 {
 	RenderPolyPlane plane;
 
@@ -91,7 +91,7 @@ void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &cl
 	plane.Render(worldToClip, clipPlane, cull, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals);
 }
 
-void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor)
+void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor)
 {
 	FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture;
 	FTexture *tex = TexMan(picnum);
@@ -138,11 +138,11 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c
 	args.SetStencilTestValue(stencilValue);
 	args.SetWriteStencil(true, stencilValue + 1);
 	args.SetTexture(tex);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 	args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
 }
 
-void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
+void RenderPolyPlane::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
 {
 	const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
 	bool foggy = false;
@@ -307,7 +307,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
 	args.SetFaceCullCCW(ccw);
 	args.SetStencilTestValue(stencilValue);
 	args.SetWriteStencil(true, stencilValue + 1);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 
 	if (!isSky)
 	{
diff --git a/src/polyrenderer/scene/poly_plane.h b/src/polyrenderer/scene/poly_plane.h
index bf844dcc27..ce21925945 100644
--- a/src/polyrenderer/scene/poly_plane.h
+++ b/src/polyrenderer/scene/poly_plane.h
@@ -26,12 +26,11 @@
 
 class PolyDrawSectorPortal;
 class PolyCull;
-class Vec4f;
 
 class RenderPolyPlane
 {
 public:
-	static void RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
+	static void RenderPlanes(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
 
 private:
 	struct UVTransform
@@ -48,7 +47,7 @@ private:
 		float xOffs, yOffs;
 	};
 
-	void Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor);
-	void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
+	void Render3DFloor(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor);
+	void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
 	TriVertex PlaneVertex(vertex_t *v1, double height, const UVTransform &transform);
 };
diff --git a/src/polyrenderer/scene/poly_portal.cpp b/src/polyrenderer/scene/poly_portal.cpp
index f262134552..0e0ffbf38a 100644
--- a/src/polyrenderer/scene/poly_portal.cpp
+++ b/src/polyrenderer/scene/poly_portal.cpp
@@ -45,7 +45,7 @@ void PolyDrawSectorPortal::Render(int portalDepth)
 
 	const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
 
-	Vec4f portalPlane = Vec4f(0.0f);
+	PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f);
 	if (Portal->mType != PORTS_SKYVIEWPOINT)
 	{
 		float minHeight;
@@ -71,17 +71,11 @@ void PolyDrawSectorPortal::Render(int portalDepth)
 
 		if (!first && minHeight > viewpoint.Pos.Z)
 		{
-			portalPlane.x = 0.0f;
-			portalPlane.y = 0.0f;
-			portalPlane.z = 1.0f;
-			portalPlane.w = -minHeight;
+			portalPlane = PolyClipPlane(0.0f, 0.0f, 1.0f, -minHeight);
 		}
 		else if (!first && maxHeight < viewpoint.Pos.Z)
 		{
-			portalPlane.x = 0.0f;
-			portalPlane.y = 0.0f;
-			portalPlane.z = -1.0f;
-			portalPlane.w = maxHeight;
+			portalPlane = PolyClipPlane(0.0f, 0.0f, -1.0f, maxHeight);
 		}
 	}
 
@@ -223,7 +217,7 @@ void PolyDrawLinePortal::Render(int portalDepth)
 	DVector2 planeNormal = (clipLine->v2->fPos() - clipLine->v1->fPos()).Rotated90CW();
 	planeNormal.MakeUnit();
 	double planeD = -(planeNormal | (planePos + planeNormal * 0.001));
-	Vec4f portalPlane((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD);
+	PolyClipPlane portalPlane((float)planeNormal.X, (float)planeNormal.Y, (float)0.0f, (float)planeD);
 
 	RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
 	RenderPortal.SetPortalSegments(Segments);
diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp
index 2ea63f4397..3aeda994ce 100644
--- a/src/polyrenderer/scene/poly_scene.cpp
+++ b/src/polyrenderer/scene/poly_scene.cpp
@@ -43,7 +43,7 @@ RenderPolyScene::~RenderPolyScene()
 {
 }
 
-void RenderPolyScene::SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue)
+void RenderPolyScene::SetViewpoint(const TriMatrix &worldToClip, const PolyClipPlane &portalPlane, uint32_t stencilValue)
 {
 	WorldToClip = worldToClip;
 	StencilValue = stencilValue;
@@ -252,7 +252,7 @@ void RenderPolyScene::RenderPortals(int portalDepth)
 		args.SetTransform(&WorldToClip);
 		args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(foggy), true);
 		args.SetColor(0, 0);
-		args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
+		args.SetClipPlane(PortalPlane);
 		args.SetStyle(TriBlendMode::Copy);
 
 		for (auto &portal : SectorPortals)
@@ -294,7 +294,7 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
 			args.SetTransform(&WorldToClip);
 			args.SetStencilTestValue(portal->StencilValue + 1);
 			args.SetWriteStencil(true, StencilValue + 1);
-			args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
+			args.SetClipPlane(PortalPlane);
 			for (const auto &verts : portal->Shape)
 			{
 				args.SetFaceCullCCW(verts.Ccw);
@@ -313,7 +313,7 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
 			args.SetTransform(&WorldToClip);
 			args.SetStencilTestValue(portal->StencilValue + 1);
 			args.SetWriteStencil(true, StencilValue + 1);
-			args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
+			args.SetClipPlane(PortalPlane);
 			for (const auto &verts : portal->Shape)
 			{
 				args.SetFaceCullCCW(verts.Ccw);
diff --git a/src/polyrenderer/scene/poly_scene.h b/src/polyrenderer/scene/poly_scene.h
index 77c7925c0a..707ee87a3c 100644
--- a/src/polyrenderer/scene/poly_scene.h
+++ b/src/polyrenderer/scene/poly_scene.h
@@ -29,7 +29,6 @@
 #include "doomdata.h"
 #include "r_utility.h"
 #include "polyrenderer/drawers/poly_triangle.h"
-#include "polyrenderer/math/poly_intersection.h"
 #include "poly_wall.h"
 #include "poly_sprite.h"
 #include "poly_wallsprite.h"
@@ -74,7 +73,7 @@ class RenderPolyScene
 public:
 	RenderPolyScene();
 	~RenderPolyScene();
-	void SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue);
+	void SetViewpoint(const TriMatrix &worldToClip, const PolyClipPlane &portalPlane, uint32_t stencilValue);
 	void SetPortalSegments(const std::vector<PolyPortalSegment> &segments);
 	void Render(int portalDepth);
 	void RenderTranslucent(int portalDepth);
@@ -91,7 +90,7 @@ private:
 	void RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
 
 	TriMatrix WorldToClip;
-	Vec4f PortalPlane;
+	PolyClipPlane PortalPlane;
 	uint32_t StencilValue = 0;
 	PolyCull Cull;
 	uint32_t NextSubsectorDepth = 0;
diff --git a/src/polyrenderer/scene/poly_sky.cpp b/src/polyrenderer/scene/poly_sky.cpp
index a38845ebec..374163f967 100644
--- a/src/polyrenderer/scene/poly_sky.cpp
+++ b/src/polyrenderer/scene/poly_sky.cpp
@@ -61,7 +61,7 @@ void PolySkyDome::Render(const TriMatrix &worldToClip)
 	args.SetTransform(&objectToClip);
 	args.SetStencilTestValue(255);
 	args.SetWriteStencil(true, 1);
-	args.SetClipPlane(0.0f, 0.0f, 0.0f, 0.0f);
+	args.SetClipPlane(PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f));
 
 	RenderCapColorRow(args, frontskytex, 0, false);
 	RenderCapColorRow(args, frontskytex, rc, true);
diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp
index ff3303ea06..2a98af7212 100644
--- a/src/polyrenderer/scene/poly_sprite.cpp
+++ b/src/polyrenderer/scene/poly_sprite.cpp
@@ -27,7 +27,6 @@
 #include "r_data/r_translate.h"
 #include "poly_sprite.h"
 #include "polyrenderer/poly_renderer.h"
-#include "polyrenderer/math/poly_intersection.h"
 #include "polyrenderer/scene/poly_light.h"
 
 EXTERN_CVAR(Float, transsouls)
@@ -65,7 +64,7 @@ bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
 	return true;
 }
 
-void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2)
+void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2)
 {
 	DVector2 line[2];
 	if (!GetLine(thing, line[0], line[1]))
@@ -146,7 +145,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla
 	args.SetStencilTestValue(stencilValue);
 	args.SetWriteStencil(true, stencilValue);
 	args.SetTexture(tex, thing->Translation);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 
 	if (thing->RenderStyle == LegacyRenderStyles[STYLE_Normal] ||
 		 (r_drawfuzz == 0 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
diff --git a/src/polyrenderer/scene/poly_sprite.h b/src/polyrenderer/scene/poly_sprite.h
index a61c7f4b5f..e190d9ee6c 100644
--- a/src/polyrenderer/scene/poly_sprite.h
+++ b/src/polyrenderer/scene/poly_sprite.h
@@ -24,12 +24,10 @@
 
 #include "polyrenderer/drawers/poly_triangle.h"
 
-class Vec4f;
-
 class RenderPolySprite
 {
 public:
-	void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2);
+	void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2);
 
 	static bool GetLine(AActor *thing, DVector2 &left, DVector2 &right);
 	static bool IsThingCulled(AActor *thing);
diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp
index 8164d71ef0..263487f709 100644
--- a/src/polyrenderer/scene/poly_wall.cpp
+++ b/src/polyrenderer/scene/poly_wall.cpp
@@ -37,7 +37,7 @@
 
 EXTERN_CVAR(Bool, r_drawmirrors)
 
-bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
+bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
 {
 	PolyDrawLinePortal *polyportal = nullptr;
 	if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
@@ -165,7 +165,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP
 	return polyportal != nullptr;
 }
 
-void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
+void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
 {
 	double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1);
 	double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1);
@@ -198,7 +198,7 @@ void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ce
 	this->floor2 = floor2;
 }
 
-void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull)
+void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull)
 {
 	bool foggy = false;
 	FTexture *tex = GetTexture();
@@ -256,7 +256,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane
 	args.SetWriteStencil(true, StencilValue + 1);
 	if (tex)
 		args.SetTexture(tex);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 
 	if (Polyportal)
 	{
diff --git a/src/polyrenderer/scene/poly_wall.h b/src/polyrenderer/scene/poly_wall.h
index a435201b29..dda2cdc2aa 100644
--- a/src/polyrenderer/scene/poly_wall.h
+++ b/src/polyrenderer/scene/poly_wall.h
@@ -27,16 +27,15 @@
 class PolyTranslucentObject;
 class PolyDrawLinePortal;
 class PolyCull;
-class Vec4f;
 
 class RenderPolyWall
 {
 public:
-	static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
-	static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
+	static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
+	static void Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
 
 	void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
-	void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull);
+	void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull);
 
 	DVector2 v1;
 	DVector2 v2;
diff --git a/src/polyrenderer/scene/poly_wallsprite.cpp b/src/polyrenderer/scene/poly_wallsprite.cpp
index 9e4e2498ca..8108849b9e 100644
--- a/src/polyrenderer/scene/poly_wallsprite.cpp
+++ b/src/polyrenderer/scene/poly_wallsprite.cpp
@@ -29,7 +29,7 @@
 #include "polyrenderer/poly_renderer.h"
 #include "polyrenderer/scene/poly_light.h"
 
-void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
+void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
 {
 	if (RenderPolySprite::IsThingCulled(thing))
 		return;
@@ -105,7 +105,7 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &cli
 	args.SetFaceCullCCW(true);
 	args.SetStencilTestValue(stencilValue);
 	args.SetTexture(tex);
-	args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
+	args.SetClipPlane(clipPlane);
 	args.SetSubsectorDepthTest(true);
 	args.SetWriteSubsectorDepth(false);
 	args.SetWriteStencil(false);
diff --git a/src/polyrenderer/scene/poly_wallsprite.h b/src/polyrenderer/scene/poly_wallsprite.h
index 75a550748e..c0c0005b86 100644
--- a/src/polyrenderer/scene/poly_wallsprite.h
+++ b/src/polyrenderer/scene/poly_wallsprite.h
@@ -24,10 +24,8 @@
 
 #include "polyrenderer/drawers/poly_triangle.h"
 
-class Vec4f;
-
 class RenderPolyWallSprite
 {
 public:
-	void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
+	void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
 };