diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp
index 692dd10ca..82fdec808 100644
--- a/src/gl/renderer/gl_renderer.cpp
+++ b/src/gl/renderer/gl_renderer.cpp
@@ -486,7 +486,6 @@ public:
 
 void FGLRenderer::Draw2D(F2DDrawer *drawer)
 {
-	F2DDrawer::EDrawType lasttype = F2DDrawer::DrawTypeTriangles;
 	auto &vertices = drawer->mVertices;
 	auto &indices = drawer->mIndices;
 	auto &commands = drawer->mData;
diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp
index cbd827f72..1609b784f 100644
--- a/src/v_2ddrawer.cpp
+++ b/src/v_2ddrawer.cpp
@@ -140,7 +140,19 @@ bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor,
 			parms.fillcolor.r = 255 - parms.fillcolor.r;
 			parms.fillcolor.g = 255 - parms.fillcolor.g;
 			parms.fillcolor.b = 255 - parms.fillcolor.b;
+			style.Flags &= ~STYLEF_InvertSource;
 		}
+		if (parms.desaturate > 0)
+		{
+			// Desaturation can also be computed here without having to do it in the shader.
+			auto gray = parms.fillcolor.Luminance();
+			auto notgray = 255 - gray;
+			parms.fillcolor.r = uint8_t((parms.fillcolor.r * notgray + gray * 255) / 255);
+			parms.fillcolor.g = uint8_t((parms.fillcolor.g * notgray + gray * 255) / 255);
+			parms.fillcolor.b = uint8_t((parms.fillcolor.b * notgray + gray * 255) / 255);
+			parms.desaturate = 0;
+		}
+
 		// Set up the color mod to replace the color from the image data.
 		vertexcolor.r = parms.fillcolor.r;
 		vertexcolor.g = parms.fillcolor.g;
@@ -236,6 +248,8 @@ void F2DDrawer::SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcol
 
 void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms)
 {
+	if (parms.style.BlendOp == STYLEOP_None) return;	// not supposed to be drawn.
+
 	double xscale = parms.destwidth / parms.texwidth;
 	double yscale = parms.destheight / parms.texheight;
 	double x = parms.x - parms.left * xscale;
diff --git a/src/v_video.h b/src/v_video.h
index b4a2485c2..cee9d63d5 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -79,7 +79,7 @@ enum
 	DTA_DestWidth,		// width of area to draw to
 	DTA_DestHeight,		// height of area to draw to
 	DTA_Alpha,			// alpha value for translucency
-	DTA_FillColor,		// color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers)
+	DTA_FillColor,		// color to stencil onto the destination
 	DTA_TranslationIndex, // translation table to recolor the source
 	DTA_AlphaChannel,	// bool: the source is an alpha channel; used with DTA_FillColor
 	DTA_Clean,			// bool: scale texture size and position by CleanXfac and CleanYfac
diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp
index 44ddcc7b3..1f02752eb 100644
--- a/src/win32/fb_d3d9.cpp
+++ b/src/win32/fb_d3d9.cpp
@@ -161,26 +161,25 @@ const char *const D3DFB::ShaderNames[D3DFB::NUM_SHADERS] =
 {
 	"NormalColor.pso",
 	"NormalColorPal.pso",
+	"NormalColorD.pso",
+	"NormalColorPalD.pso",
 	"NormalColorInv.pso",
 	"NormalColorPalInv.pso",
+	"NormalColorOpaq.pso",
+	"NormalColorPalOpaq.pso",
+	"NormalColorInvOpaq.pso",
+	"NormalColorPalInvOpaq.pso",
 
-	"RedToAlpha.pso",
-	"RedToAlphaInv.pso",
+	"AlphaTex.pso",
+	"PalAlphaTex.pso",
+	"Stencil.pso",
+	"PalStencil.pso",
 
 	"VertexColor.pso",
 
 	"SpecialColormap.pso",
 	"SpecialColorMapPal.pso",
 
-	"InGameColormap.pso",
-	"InGameColormapDesat.pso",
-	"InGameColormapInv.pso",
-	"InGameColormapInvDesat.pso",
-	"InGameColormapPal.pso",
-	"InGameColormapPalDesat.pso",
-	"InGameColormapPalInv.pso",
-	"InGameColormapPalInvDesat.pso",
-
 	"BurnWipe.pso",
 	"GammaCorrection.pso",
 };
@@ -474,7 +473,7 @@ bool D3DFB::CreateResources()
 	{
 		return false;
 	}
-	if (!CreateVertexes())
+	if (!CreateVertexes(NUM_VERTS, NUM_INDEXES))
 	{
 		return false;
 	}
@@ -610,7 +609,7 @@ bool D3DFB::Reset ()
 		}
 	}
 	LOG("Device was reset\n");
-	if (!CreateFBTexture() || !CreateVertexes())
+	if (!CreateFBTexture() || !CreateVertexes(NUM_VERTS, NUM_INDEXES))
 	{
 		return false;
 	}
@@ -775,19 +774,19 @@ bool D3DFB::CreatePaletteTexture ()
 //
 //==========================================================================
 
-bool D3DFB::CreateVertexes ()
+bool D3DFB::CreateVertexes (int numverts, int numindices)
 {
-	VertexPos = -1;
-	IndexPos = -1;
-	QuadBatchPos = -1;
-	BatchType = BATCH_None;
-	if (FAILED(D3DDevice->CreateVertexBuffer(sizeof(FBVERTEX)*NUM_VERTS, 
+	SAFE_RELEASE(VertexBuffer);
+	SAFE_RELEASE(IndexBuffer);
+	NumVertices = numverts;
+	NumIndices = numindices;
+	if (FAILED(D3DDevice->CreateVertexBuffer(sizeof(FBVERTEX)*numverts, 
 		D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_FBVERTEX, D3DPOOL_DEFAULT, &VertexBuffer, NULL)))
 	{
 		return false;
 	}
-	if (FAILED(D3DDevice->CreateIndexBuffer(sizeof(uint16_t)*NUM_INDEXES,
-		D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &IndexBuffer, NULL)))
+	if (FAILED(D3DDevice->CreateIndexBuffer(sizeof(uint16_t)*numindices,
+		D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &IndexBuffer, NULL)))
 	{
 		return false;
 	}
@@ -913,7 +912,7 @@ void D3DFB::Update ()
 		if (InScene)
 		{
 			DrawRateStuff();
-			EndBatch();		// Make sure all batched primitives are drawn.
+			EndQuadBatch();		// Make sure all batched primitives are drawn.
 			In2D = 0;
 			Flip();
 		}
@@ -1787,76 +1786,190 @@ FNativePalette *D3DFB::CreatePalette(FRemapTable *remap)
 
 //==========================================================================
 //
-// D3DFB :: BeginLineBatch
+// D3DFB :: Draw2D
 //
 //==========================================================================
 
-void D3DFB::BeginLineBatch()
+static D3DBLENDOP OpToD3D(int op)
 {
-	if (In2D < 2 || !InScene || BatchType == BATCH_Lines)
+	switch (op)
 	{
-		return;
+		// STYLEOP_None can never get here.
+	default:
+		return D3DBLENDOP_ADD;
+	case STYLEOP_Sub:
+		return D3DBLENDOP_SUBTRACT;
+	case STYLEOP_RevSub:
+		return D3DBLENDOP_REVSUBTRACT;
 	}
-	EndQuadBatch();		// Make sure all quads have been drawn first.
-	VertexBuffer->Lock(0, 0, (void **)&VertexData, D3DLOCK_DISCARD);
-	VertexPos = 0;
-	BatchType = BATCH_Lines;
 }
 
-//==========================================================================
-//
-// D3DFB :: EndLineBatch
-//
-//==========================================================================
 
-void D3DFB::EndLineBatch()
+void D3DFB::Draw2D()
 {
-	if (In2D < 2 || !InScene || BatchType != BATCH_Lines)
+	auto &vertices = m2DDrawer.mVertices;
+	auto &indices = m2DDrawer.mIndices;
+	auto &commands = m2DDrawer.mData;
+
+	auto vc = vertices.Size();
+	auto ic = indices.Size();
+	if (vc > NumVertices || ic > NumIndices)
 	{
-		return;
+		// We got more vertices than the current buffer can take so resize it.
+		if (!CreateVertexes(MAX(vc, NumVertices), MAX(ic, NumIndices)))
+		{
+			I_FatalError("Unable to resize vertex buffer");
+		}
+	}
+	IndexBuffer->Lock(0, 0, (void **)&IndexData, D3DLOCK_DISCARD);
+	memcpy(IndexData, &indices[0], sizeof(*IndexData) * ic);
+	IndexBuffer->Unlock();
+	VertexBuffer->Lock(0, 0, (void **)&VertexData, D3DLOCK_DISCARD);
+	auto yoffs = GatheringWipeScreen ? 0.5f : 0.5f - LBOffset;
+
+	for (auto &vt : vertices)
+	{
+		VertexData->x = vt.x;
+		VertexData->y = vt.y + yoffs;
+		VertexData->z = vt.z;
+		VertexData->rhw = 1;
+		VertexData->color0 = vt.color0;
+		VertexData->color1 = 0;
+		VertexData->tu = vt.u;
+		VertexData->tv = vt.v;
 	}
 	VertexBuffer->Unlock();
-	if (VertexPos > 0)
+	D3DDevice->SetStreamSource(0, VertexBuffer, 0, sizeof(FBVERTEX));
+	D3DDevice->SetIndices(IndexBuffer);
+
+	D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
+	D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
+	bool uv_wrapped = false;
+	bool scissoring = false;
+	EnableAlphaTest(true);
+
+	for (auto &cmd : commands)
 	{
-		SetPixelShader(Shaders[SHADER_VertexColor]);
-		SetAlphaBlend(D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
-		D3DDevice->SetStreamSource(0, VertexBuffer, 0, sizeof(FBVERTEX));
-		D3DDevice->DrawPrimitive(D3DPT_LINELIST, 0, VertexPos / 2);
+		//Set blending mode
+		SetAlphaBlend(OpToD3D(cmd.mRenderStyle.BlendOp), GetStyleAlpha(cmd.mRenderStyle.SrcAlpha), GetStyleAlpha(cmd.mRenderStyle.DestAlpha));
+		int index = -1;
+
+		if (cmd.mTexture == nullptr)
+		{
+			index = SHADER_VertexColor;
+		}
+		else
+		{
+			// set texture wrapping
+			bool uv_should_wrap = !!(cmd.mFlags & F2DDrawer::DTF_Wrap);
+			if (uv_wrapped != uv_should_wrap)
+			{
+				DWORD mode = uv_should_wrap ? D3DTADDRESS_WRAP : D3DTADDRESS_BORDER;
+				uv_wrapped = uv_should_wrap;
+				D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, mode);
+				D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, mode);
+			}
+
+			auto textype = cmd.mTexture->GetFormat();	// This never returns TEX_Gray.
+			if (cmd.mTranslation) textype = TEX_Pal;	// Translation requires a paletted texture, regardless of the source format.
+
+			if (cmd.mFlags & F2DDrawer::DTF_SpecialColormap)
+			{
+				index = textype == TEX_Pal ? SHADER_SpecialColormapPal : SHADER_SpecialColormap;
+				SetConstant(PSCONST_Color1, cmd.mColor1.r / 510.f, cmd.mColor1.g / 510.f, cmd.mColor1.b / 510.f, 0);
+				SetConstant(PSCONST_Color2, cmd.mColor1.r / 510.f, cmd.mColor1.g / 510.f, cmd.mColor1.b / 510.f, 0);
+			}
+			else
+			{
+				SetConstant(PSCONST_Desaturation, cmd.mDesaturate / 255.f, (255 - cmd.mDesaturate) / 255.f, 0, 0);
+				SetConstant(PSCONST_Color1, cmd.mColor1.r / 255.f, cmd.mColor1.g / 255.f, cmd.mColor1.b / 255.f, 0);
+				switch (cmd.mDrawMode)
+				{
+				default:
+				case F2DDrawer::DTM_Normal:
+					if (cmd.mDesaturate) index = textype == TEX_Pal ? SHADER_NormalColorPalD : SHADER_NormalColorD;
+					else  index = textype == TEX_Pal ? SHADER_NormalColorPal : SHADER_NormalColor;
+					break;
+
+				case F2DDrawer::DTM_Invert:
+					index = textype == TEX_Pal ? SHADER_NormalColorPalInv : SHADER_NormalColorInv;
+					break;
+
+				case F2DDrawer::DTM_InvertOpaque:
+					index = textype == TEX_Pal ? SHADER_NormalColorPalInvOpaq : SHADER_NormalColorInvOpaq;
+					break;
+
+				case F2DDrawer::DTM_AlphaTexture:
+					index = textype == TEX_Pal ? SHADER_PalAlphaTex : SHADER_AlphaTex;
+					break;
+
+				case F2DDrawer::DTM_Opaque:
+					index = textype == TEX_Pal ? SHADER_NormalColorPalOpaq : SHADER_NormalColorOpaq;
+					break;
+
+				case F2DDrawer::DTM_Stencil:
+					index = textype == TEX_Pal ? SHADER_PalStencil : SHADER_Stencil;
+					break;
+
+				}
+			}
+
+			auto tex = cmd.mTexture;
+			D3DTex *d3dtex = static_cast<D3DTex *>(tex->GetNative(textype, uv_should_wrap));
+			if (d3dtex == nullptr) continue;
+			SetTexture(0, d3dtex->Tex);
+
+			if (textype == TEX_Pal)
+			{
+				if (!cmd.mTranslation)
+				{
+					SetPaletteTexture(PaletteTexture, 256, BorderColor);
+				}
+				else
+				{
+					auto ptex = static_cast<D3DPal*>(cmd.mTranslation->GetNative());
+					if (ptex != nullptr)
+					{
+						SetPaletteTexture(ptex->Tex, ptex->RoundedPaletteSize, ptex->BorderColor);
+					}
+				}
+			}
+		}
+		if (index == -1) continue;
+		SetPixelShader(Shaders[index]);
+
+		if (cmd.mFlags & F2DDrawer::DTF_Scissor)
+		{
+			scissoring = true;
+			RECT scissor = { cmd.mScissor[0], cmd.mScissor[1] + LBOffsetI, cmd.mScissor[2], cmd.mScissor[3] + LBOffsetI };
+			D3DDevice->SetScissorRect(&scissor);
+			D3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+		}
+		else if (scissoring) D3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
+
+		switch (cmd.mType)
+		{
+		case F2DDrawer::DrawTypeTriangles:
+			D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, cmd.mVertIndex, cmd.mVertCount);
+			break;
+
+		case F2DDrawer::DrawTypeLines:
+			D3DDevice->DrawPrimitive(D3DPT_LINELIST, cmd.mVertIndex, cmd.mVertCount);
+			break;
+
+		case F2DDrawer::DrawTypePoints:
+			D3DDevice->DrawPrimitive(D3DPT_POINTLIST, cmd.mVertIndex, cmd.mVertCount);
+			break;
+
+		}
+	}
+	if (uv_wrapped)
+	{
+		D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
+		D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
 	}
-	VertexPos = -1;
-	BatchType = BATCH_None;
 }
 
-
-//==========================================================================
-//
-// D3DFB :: DrawPixel
-//
-//==========================================================================
-
-#if 0
-void D3DFB::DrawPixel(int x, int y, int palcolor, uint32_t color)
-{
-	if (In2D < 2)
-	{
-		Super::DrawPixel(x, y, palcolor, color);
-		return;
-	}
-	if (!InScene)
-	{
-		return;
-	}
-	FBVERTEX pt =
-	{
-		float(x), float(y), 0, 1, color
-	};
-	EndBatch();		// Draw out any batched operations.
-	SetPixelShader(Shaders[SHADER_VertexColor]);
-	SetAlphaBlend(D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
-	D3DDevice->DrawPrimitiveUP(D3DPT_POINTLIST, 1, &pt, sizeof(FBVERTEX));
-}
-#endif
-
 //==========================================================================
 //
 // D3DFB :: CheckQuadBatch
@@ -1867,11 +1980,7 @@ void D3DFB::DrawPixel(int x, int y, int palcolor, uint32_t color)
 
 void D3DFB::CheckQuadBatch(int numtris, int numverts)
 {
-	if (BatchType == BATCH_Lines)
-	{
-		EndLineBatch();
-	}
-	else if (QuadBatchPos == MAX_QUAD_BATCH ||
+	if (QuadBatchPos == MAX_QUAD_BATCH ||
 		VertexPos + numverts > NUM_VERTS ||
 		IndexPos + numtris * 3 > NUM_INDEXES)
 	{
@@ -1897,7 +2006,6 @@ void D3DFB::BeginQuadBatch()
 	{
 		return;
 	}
-	EndLineBatch();		// Make sure all lines have been drawn first.
 	VertexBuffer->Lock(0, 0, (void **)&VertexData, D3DLOCK_DISCARD);
 	IndexBuffer->Lock(0, 0, (void **)&IndexData, D3DLOCK_DISCARD);
 	VertexPos = 0;
@@ -1911,6 +2019,7 @@ void D3DFB::BeginQuadBatch()
 // D3DFB :: EndQuadBatch
 //
 // Draws all the quads that have been batched up.
+// This is still needed by the wiper and has been stripped off everything unneeded.
 //
 //==========================================================================
 
@@ -1932,8 +2041,6 @@ void D3DFB::EndQuadBatch()
 	}
 	D3DDevice->SetStreamSource(0, VertexBuffer, 0, sizeof(FBVERTEX));
 	D3DDevice->SetIndices(IndexBuffer);
-	bool uv_wrapped = false;
-	bool uv_should_wrap;
 	int indexpos, vertpos;
 
 	indexpos = vertpos = 0;
@@ -1959,81 +2066,17 @@ void D3DFB::EndQuadBatch()
 			{
 				break;
 			}
-			if (quad->ShaderNum == BQS_InGameColormap && (quad->Flags & BQF_Desaturated) && quad->Desat != q2->Desat)
-			{
-				break;
-			}
 			indexpos += q2->NumTris * 3;
 			vertpos += q2->NumVerts;
 		}
 
-		// Set the palette (if one)
-		if ((quad->Flags & BQF_Paletted) == BQF_GamePalette)
-		{
-			SetPaletteTexture(PaletteTexture, 256, BorderColor);
-		}
-		else if ((quad->Flags & BQF_Paletted) == BQF_CustomPalette)
-		{
-			assert(quad->Palette != NULL);
-			SetPaletteTexture(quad->Palette->Tex, quad->Palette->RoundedPaletteSize, quad->Palette->BorderColor);
-		}
-
 		// Set the alpha blending
-		SetAlphaBlend(D3DBLENDOP(quad->BlendOp), D3DBLEND(quad->SrcBlend), D3DBLEND(quad->DestBlend));
+		SetAlphaBlend(D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO);
 
 		// Set the alpha test
-		EnableAlphaTest(!(quad->Flags & BQF_DisableAlphaTest));
+		EnableAlphaTest(false);
 
-		// Set the pixel shader
-		if (quad->ShaderNum == BQS_PalTex)
-		{
-			SetPixelShader(Shaders[(quad->Flags & BQF_InvertSource) ?
-				SHADER_NormalColorPalInv : SHADER_NormalColorPal]);
-		}
-		else if (quad->ShaderNum == BQS_Plain)
-		{
-			SetPixelShader(Shaders[(quad->Flags & BQF_InvertSource) ?
-				SHADER_NormalColorInv : SHADER_NormalColor]);
-		}
-		else if (quad->ShaderNum == BQS_RedToAlpha)
-		{
-			SetPixelShader(Shaders[(quad->Flags & BQF_InvertSource) ?
-				SHADER_RedToAlphaInv : SHADER_RedToAlpha]);
-		}
-		else if (quad->ShaderNum == BQS_ColorOnly)
-		{
-			SetPixelShader(Shaders[SHADER_VertexColor]);
-		}
-		else if (quad->ShaderNum == BQS_SpecialColormap)
-		{
-			int select;
-
-			select = !!(quad->Flags & BQF_Paletted);
-			SetPixelShader(Shaders[SHADER_SpecialColormap + select]);
-		}
-		else if (quad->ShaderNum == BQS_InGameColormap)
-		{
-			int select;
-
-			select = !!(quad->Flags & BQF_Desaturated);
-			select |= !!(quad->Flags & BQF_InvertSource) << 1;
-			select |= !!(quad->Flags & BQF_Paletted) << 2;
-			if (quad->Flags & BQF_Desaturated)
-			{
-				SetConstant(PSCONST_Desaturation, quad->Desat / 255.f, (255 - quad->Desat) / 255.f, 0, 0);
-			}
-			SetPixelShader(Shaders[SHADER_InGameColormap + select]);
-		}
-
-		// Set the texture clamp addressing mode
-		uv_should_wrap = !!(quad->Flags & BQF_WrapUV);
-		if (uv_wrapped != uv_should_wrap)
-		{
-			DWORD mode = uv_should_wrap ? D3DTADDRESS_WRAP : D3DTADDRESS_BORDER;
-			uv_wrapped = uv_should_wrap;
-			D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, mode);
-			D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, mode);
-		}
+		SetPixelShader(Shaders[SHADER_NormalColor]);
 
 		// Set the texture
 		if (quad->Texture != NULL)
@@ -2050,11 +2093,6 @@ void D3DFB::EndQuadBatch()
 			/*4 * i, 4 * (j - i), 6 * i, 2 * (j - i)*/);
 		i = j;
 	}
-	if (uv_wrapped)
-	{
-		D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
-		D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
-	}
 	QuadBatchPos = -1;
 	VertexPos = -1;
 	IndexPos = -1;
@@ -2068,18 +2106,6 @@ void D3DFB::EndQuadBatch()
 //
 //==========================================================================
 
-void D3DFB::EndBatch()
-{
-	if (BatchType == BATCH_Quads)
-	{
-		EndQuadBatch();
-	}
-	else if (BatchType == BATCH_Lines)
-	{
-		EndLineBatch();
-	}
-}
-
 D3DBLEND D3DFB::GetStyleAlpha(int type)
 {
 	switch (type)
diff --git a/src/win32/fb_d3d9_wipe.cpp b/src/win32/fb_d3d9_wipe.cpp
index 1712011a1..e7f1f1307 100644
--- a/src/win32/fb_d3d9_wipe.cpp
+++ b/src/win32/fb_d3d9_wipe.cpp
@@ -208,7 +208,7 @@ void D3DFB::WipeEndScreen()
 		Begin2D(true);
 	}
 
-	EndBatch();			// Make sure all batched primitives have been drawn.
+	EndQuadBatch();			// Make sure all batched primitives have been drawn.
 
 	// Don't do anything if there is no ending point.
 	if (OldRenderTarget == NULL)
diff --git a/src/win32/win32swiface.h b/src/win32/win32swiface.h
index 428aafae4..099441736 100644
--- a/src/win32/win32swiface.h
+++ b/src/win32/win32swiface.h
@@ -92,33 +92,36 @@ private:
 	{
 		PSCONST_Desaturation = 1,
 		PSCONST_PaletteMod = 2,
+		PSCONST_Color1 = 3,
+		PSCONST_Color2 = 4,
+		PSCONST_BUFFERED_MAX,
 		PSCONST_Weights = 6,
 		PSCONST_Gamma = 7,
+
 	};
 	enum
 	{
 		SHADER_NormalColor,
 		SHADER_NormalColorPal,
+		SHADER_NormalColorD,
+		SHADER_NormalColorPalD,
 		SHADER_NormalColorInv,
 		SHADER_NormalColorPalInv,
+		SHADER_NormalColorOpaq,
+		SHADER_NormalColorPalOpaq,
+		SHADER_NormalColorInvOpaq,
+		SHADER_NormalColorPalInvOpaq,
 
-		SHADER_RedToAlpha,
-		SHADER_RedToAlphaInv,
+		SHADER_AlphaTex,
+		SHADER_PalAlphaTex,
+		SHADER_Stencil,
+		SHADER_PalStencil,
 
 		SHADER_VertexColor,
 
 		SHADER_SpecialColormap,
 		SHADER_SpecialColormapPal,
 
-		SHADER_InGameColormap,
-		SHADER_InGameColormapDesat,
-		SHADER_InGameColormapInv,
-		SHADER_InGameColormapInvDesat,
-		SHADER_InGameColormapPal,
-		SHADER_InGameColormapPalDesat,
-		SHADER_InGameColormapPalInv,
-		SHADER_InGameColormapPalInvDesat,
-
 		SHADER_BurnWipe,
 		SHADER_GammaCorrection,
 
@@ -134,7 +137,7 @@ private:
 	bool CreateFBTexture();
 	bool CreatePaletteTexture();
 	bool CreateGammaTexture();
-	bool CreateVertexes();
+	bool CreateVertexes(int numv, int numi);
 	void UploadPalette();
 	void UpdateGammaTexture(float igamma);
 	void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync);
@@ -149,14 +152,11 @@ private:
 	void Draw3DPart(bool copy3d);
 	static D3DBLEND GetStyleAlpha(int type);
 	void DoWindowedGamma();
-	void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color);
 	void CheckQuadBatch(int numtris=2, int numverts=4);
 	void BeginQuadBatch();
 	void EndQuadBatch();
-	void BeginLineBatch();
-	void EndLineBatch();
-	void EndBatch();
 	void CopyNextFrontBuffer();
+	void Draw2D() override;
 
 	D3DCAPS9 DeviceCaps;
 
@@ -173,7 +173,7 @@ private:
 	D3DBLENDOP AlphaBlendOp;
 	D3DBLEND AlphaSrcBlend;
 	D3DBLEND AlphaDestBlend;
-	float Constant[3][4];
+	float Constant[PSCONST_BUFFERED_MAX][4];
 	D3DCOLOR CurBorderColor;
 	IDirect3DPixelShader9 *CurPixelShader;
 	IDirect3DTexture9 *Texture[5];
@@ -222,12 +222,17 @@ private:
 	FBVERTEX *VertexData;
 	IDirect3DIndexBuffer9 *IndexBuffer;
 	uint16_t *IndexData;
+
+	// This stuff is still needed for the Wiper (which will be refactored later)
 	BufferedTris *QuadExtra;
 	int VertexPos;
 	int IndexPos;
 	int QuadBatchPos;
 	enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType;
 
+	unsigned int NumVertices = 0;
+	unsigned int NumIndices = 0;
+
 	IDirect3DPixelShader9 *Shaders[NUM_SHADERS];
 	IDirect3DPixelShader9 *GammaShader;
 
diff --git a/wadsrc/static/shaders/d3d/shaders.ps b/wadsrc/static/shaders/d3d/shaders.ps
index 5d53f9bf8..f94082d80 100644
--- a/wadsrc/static/shaders/d3d/shaders.ps
+++ b/wadsrc/static/shaders/d3d/shaders.ps
@@ -3,6 +3,8 @@ sampler1D Palette : register(s1);
 
 float4 Desaturation : register(c1);	// { Desat, 1 - Desat }
 float4 PaletteMod : register(c2);
+float4 Color1 : register(c3);
+float4 Color2 : register(c4);
 float4 Weights : register(c6);		// RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 }
 float4 Gamma : register(c7);
 
@@ -17,14 +19,6 @@ float4 TextureLookup(float2 tex_coord)
 #endif
 }
 
-float4 Invert(float4 rgb)
-{
-#if INVERT
-	rgb.rgb = Weights.www - rgb.xyz;
-#endif
-	return rgb;
-}
-
 float Grayscale(float4 rgb)
 {
 	return dot(rgb.rgb, Weights.rgb);
@@ -32,24 +26,35 @@ float Grayscale(float4 rgb)
 
 float4 SampleTexture(float2 tex_coord)
 {
-	return Invert(TextureLookup(tex_coord));
+	float4 texel = TextureLookup(tex_coord);
+#if INVERT
+	texel.rgb = Weights.www - texel.xyz;
+#endif
+#if OPAQUE
+	texel.a = 1.0;
+#endif
+#if STENCIL
+	texel.rgb = Weights.www;
+#endif
+#if ALPHATEX
+	texel.a *= Grayscale(texel);
+	texel.rgb = Weights.www;
+#endif
+#if DESAT
+	float3 intensity;
+	intensity.rgb = Grayscale(texel) * Desaturation.x;
+	texel.rgb = intensity.rgb + texel.rgb * Desaturation.y;
+#endif
+	return texel;
 }
 
 // Normal color calculation for most drawing modes.
 
-float4 NormalColor(float2 tex_coord : TEXCOORD0, float4 VertexColor : COLOR0, float4 Overlay : COLOR1) : COLOR
+float4 NormalColor(float2 tex_coord : TEXCOORD0, float4 VertexColor : COLOR0) : COLOR
 {
-	return Overlay + SampleTexture(tex_coord) * VertexColor;
+	return Color1 + SampleTexture(tex_coord) * VertexColor;
 }
 
-// Copy the red channel to the alpha channel. Pays no attention to palettes and only works with grayscale textures
-
-float4 RedToAlpha(float2 tex_coord : TEXCOORD0, float4 VertexColor : COLOR0, float4 Overlay : COLOR1) : COLOR
-{
-	float4 color = Invert(tex2D(Image, tex_coord));
-	color.a *= color.r;
-	return Overlay + color * VertexColor;
-}
 
 // Just return the value of c0.
 
@@ -60,41 +65,16 @@ float4 VertexColor(float4 color : COLOR0) : COLOR
 
 // Emulate one of the special colormaps. (Invulnerability, gold, etc.)
 
-float4 SpecialColormap(float2 tex_coord : TEXCOORD0, float4 start : COLOR0, float4 end : COLOR1) : COLOR
+float4 SpecialColormap(float2 tex_coord : TEXCOORD0) : COLOR
 {
 	float4 color = SampleTexture(tex_coord);
-	float4 range = end - start;
+	float4 range = Color2 - Color1;
 	// We can't store values greater than 1.0 in a color register, so we multiply
 	// the final result by 2 and expect the caller to divide the start and end by 2.
-	color.rgb = 2 * (start + Grayscale(color) * range).rgb;
-	// Duplicate alpha semantics of NormalColor.
-	color.a = start.a + color.a * end.a;
+	color.rgb = 2 * (Color1 + Grayscale(color) * range).rgb;
 	return color;
 }
 
-// In-game colormap effect: fade to a particular color and multiply by another, with 
-// optional desaturation of the original color. Desaturation is stored in c1.
-// Fade level is packed int fade.a. Fade.rgb has been premultiplied by alpha.
-// Overall alpha is in color.a.
-float4 InGameColormap(float2 tex_coord : TEXCOORD0, float4 color : COLOR0, float4 fade : COLOR1) : COLOR
-{
-	float4 rgb = SampleTexture(tex_coord);
-
-	// Desaturate
-#if DESAT
-	float3 intensity;
-	intensity.rgb = Grayscale(rgb) * Desaturation.x;
-	rgb.rgb = intensity.rgb + rgb.rgb * Desaturation.y;
-#endif
-
-	// Shade and Alpha
-	rgb = rgb * color;
-
-	// Fade
-	rgb.rgb = rgb.rgb * fade.aaa + fade.rgb;
-
-	return rgb;
-}
 
 // Windowed gamma correction.
 
diff --git a/wadsrc/static/shaders/d3d/sm20/AlphaTex.pso b/wadsrc/static/shaders/d3d/sm20/AlphaTex.pso
new file mode 100644
index 000000000..2dcc640bc
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/AlphaTex.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/BurnWipe.pso b/wadsrc/static/shaders/d3d/sm20/BurnWipe.pso
index b1daa59be..c2a99031f 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/BurnWipe.pso and b/wadsrc/static/shaders/d3d/sm20/BurnWipe.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/GammaCorrection.pso b/wadsrc/static/shaders/d3d/sm20/GammaCorrection.pso
index 92251eb02..8fdeb2e9d 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/GammaCorrection.pso and b/wadsrc/static/shaders/d3d/sm20/GammaCorrection.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormap.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormap.pso
deleted file mode 100644
index 7ef9f5322..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormap.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapDesat.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapDesat.pso
deleted file mode 100644
index 2a87e6e96..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapInv.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapInv.pso
deleted file mode 100644
index 98ff0cc38..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapInv.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapInvDesat.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapInvDesat.pso
deleted file mode 100644
index 3605fb6ba..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapInvDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapPal.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapPal.pso
deleted file mode 100644
index bccbbc004..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapPal.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapPalDesat.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapPalDesat.pso
deleted file mode 100644
index 3f08538b1..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapPalDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapPalInv.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapPalInv.pso
deleted file mode 100644
index 14c602bc4..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapPalInv.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/InGameColormapPalInvDesat.pso b/wadsrc/static/shaders/d3d/sm20/InGameColormapPalInvDesat.pso
deleted file mode 100644
index ac3e5dc67..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/InGameColormapPalInvDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColor.pso b/wadsrc/static/shaders/d3d/sm20/NormalColor.pso
index 530002972..0797f9af1 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/NormalColor.pso and b/wadsrc/static/shaders/d3d/sm20/NormalColor.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorD.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorD.pso
new file mode 100644
index 000000000..909c41140
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/NormalColorD.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorInv.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorInv.pso
index da470159a..b77b0e33f 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/NormalColorInv.pso and b/wadsrc/static/shaders/d3d/sm20/NormalColorInv.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorInvOpaq.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorInvOpaq.pso
new file mode 100644
index 000000000..34ec06995
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/NormalColorInvOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorOpaq.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorOpaq.pso
new file mode 100644
index 000000000..4568a9292
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/NormalColorOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorPal.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorPal.pso
index 57b34eb35..126f92209 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/NormalColorPal.pso and b/wadsrc/static/shaders/d3d/sm20/NormalColorPal.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorPalD.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorPalD.pso
new file mode 100644
index 000000000..a8b99c88a
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/NormalColorPalD.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorPalInv.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorPalInv.pso
index 2c490574c..da4cc5094 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/NormalColorPalInv.pso and b/wadsrc/static/shaders/d3d/sm20/NormalColorPalInv.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorPalInvOpaq.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorPalInvOpaq.pso
new file mode 100644
index 000000000..f7b73e6d0
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/NormalColorPalInvOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/NormalColorPalOpaq.pso b/wadsrc/static/shaders/d3d/sm20/NormalColorPalOpaq.pso
new file mode 100644
index 000000000..1e401a296
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/NormalColorPalOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/PalAlphaTex.pso b/wadsrc/static/shaders/d3d/sm20/PalAlphaTex.pso
new file mode 100644
index 000000000..bde6402dc
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/PalAlphaTex.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/PalStencil.pso b/wadsrc/static/shaders/d3d/sm20/PalStencil.pso
new file mode 100644
index 000000000..789ba95f1
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/PalStencil.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/RedToAlpha.pso b/wadsrc/static/shaders/d3d/sm20/RedToAlpha.pso
deleted file mode 100644
index 10fa58af8..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/RedToAlpha.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/RedToAlphaInv.pso b/wadsrc/static/shaders/d3d/sm20/RedToAlphaInv.pso
deleted file mode 100644
index 792ffbf35..000000000
Binary files a/wadsrc/static/shaders/d3d/sm20/RedToAlphaInv.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm20/SpecialColormap.pso b/wadsrc/static/shaders/d3d/sm20/SpecialColormap.pso
index 24ebb375a..ffcc858bf 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/SpecialColormap.pso and b/wadsrc/static/shaders/d3d/sm20/SpecialColormap.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/SpecialColormapPal.pso b/wadsrc/static/shaders/d3d/sm20/SpecialColormapPal.pso
index b706962aa..8ef66d513 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/SpecialColormapPal.pso and b/wadsrc/static/shaders/d3d/sm20/SpecialColormapPal.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/Stencil.pso b/wadsrc/static/shaders/d3d/sm20/Stencil.pso
new file mode 100644
index 000000000..c0a0fffdd
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm20/Stencil.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/VertexColor.pso b/wadsrc/static/shaders/d3d/sm20/VertexColor.pso
index bd62a1d29..39c678df2 100644
Binary files a/wadsrc/static/shaders/d3d/sm20/VertexColor.pso and b/wadsrc/static/shaders/d3d/sm20/VertexColor.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm20/build.bat b/wadsrc/static/shaders/d3d/sm20/build.bat
index 478337073..b23e9ee79 100644
--- a/wadsrc/static/shaders/d3d/sm20/build.bat
+++ b/wadsrc/static/shaders/d3d/sm20/build.bat
@@ -1,24 +1,28 @@
-fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 /FoNormalColor.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=1 /FoNormalColorInv.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 /FoNormalColorPal.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=1 /FoNormalColorPalInv.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0 /FoNormalColor.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0 /FoNormalColorPal.pso
 
-fxc ..\shaders.ps /Tps_2_0 /O3 /ERedToAlpha -DINVERT=0 /FoRedToAlpha.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /ERedToAlpha -DINVERT=1 /FoRedToAlphaInv.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=1 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorInv.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=1 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalInv.pso
+
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorOpaq.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalOpaq.pso
+
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=1 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorInvOpaq.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=1 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalInvOpaq.pso
+
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=1 -DALPHATEX=0 -DDESAT=0 /FoStencil.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=1 -DALPHATEX=0 -DDESAT=0 /FoPalStencil.pso
+
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=1 -DDESAT=0 /FoAlphaTex.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=1 -DDESAT=0 /FoPalAlphaTex.pso
+
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorD.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalD.pso
 
 fxc ..\shaders.ps /Tps_2_0 /O3 /EVertexColor /FoVertexColor.pso
 
-fxc ..\shaders.ps /Tps_2_0 /O3 /ESpecialColormap -DPALTEX=0 -DINVERT=0 /FoSpecialColormap.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /ESpecialColormap -DPALTEX=1 -DINVERT=0 /FoSpecialColormapPal.pso
-
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=0 -DDESAT=0 /FoInGameColormap.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=0 -DDESAT=1 /FoInGameColormapDesat.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=1 -DDESAT=0 /FoInGameColormapInv.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=1 -DDESAT=1 /FoInGameColormapInvDesat.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=0 -DDESAT=0 /FoInGameColormapPal.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=0 -DDESAT=1 /FoInGameColormapPalDesat.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=1 -DDESAT=0 /FoInGameColormapPalInv.pso
-fxc ..\shaders.ps /Tps_2_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=1 -DDESAT=1 /FoInGameColormapPalInvDesat.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ESpecialColormap -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0  /FoSpecialColormap.pso
+fxc ..\shaders.ps /Tps_2_0 /O3 /ESpecialColormap -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0  /FoSpecialColormapPal.pso
 
 fxc ..\shaders.ps /Tps_2_0 /O3 /EBurnWipe /FoBurnWipe.pso
 
diff --git a/wadsrc/static/shaders/d3d/sm30/AlphaTex.pso b/wadsrc/static/shaders/d3d/sm30/AlphaTex.pso
new file mode 100644
index 000000000..ea21caf83
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/AlphaTex.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/BurnWipe.pso b/wadsrc/static/shaders/d3d/sm30/BurnWipe.pso
index 50e942ab3..f5da9efd4 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/BurnWipe.pso and b/wadsrc/static/shaders/d3d/sm30/BurnWipe.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/GammaCorrection.pso b/wadsrc/static/shaders/d3d/sm30/GammaCorrection.pso
index 662f59f37..41bdb3fda 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/GammaCorrection.pso and b/wadsrc/static/shaders/d3d/sm30/GammaCorrection.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormap.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormap.pso
deleted file mode 100644
index 82f702f84..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormap.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapDesat.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapDesat.pso
deleted file mode 100644
index 44d67d57b..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapInv.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapInv.pso
deleted file mode 100644
index 78d4abc9d..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapInv.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapInvDesat.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapInvDesat.pso
deleted file mode 100644
index 2da2e7b20..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapInvDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapPal.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapPal.pso
deleted file mode 100644
index 8de88be2a..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapPal.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapPalDesat.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapPalDesat.pso
deleted file mode 100644
index ad57fb576..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapPalDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapPalInv.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapPalInv.pso
deleted file mode 100644
index b44f9161c..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapPalInv.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/InGameColormapPalInvDesat.pso b/wadsrc/static/shaders/d3d/sm30/InGameColormapPalInvDesat.pso
deleted file mode 100644
index 151312317..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/InGameColormapPalInvDesat.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColor.pso b/wadsrc/static/shaders/d3d/sm30/NormalColor.pso
index ef03e9885..fbe83fa23 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/NormalColor.pso and b/wadsrc/static/shaders/d3d/sm30/NormalColor.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorD.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorD.pso
new file mode 100644
index 000000000..7c2917619
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/NormalColorD.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorInv.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorInv.pso
index 7215d533d..f0311f4a1 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/NormalColorInv.pso and b/wadsrc/static/shaders/d3d/sm30/NormalColorInv.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorInvOpaq.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorInvOpaq.pso
new file mode 100644
index 000000000..04b199b92
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/NormalColorInvOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorOpaq.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorOpaq.pso
new file mode 100644
index 000000000..e575c71f8
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/NormalColorOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorPal.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorPal.pso
index 5b9e9bc8a..251dbbe1e 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/NormalColorPal.pso and b/wadsrc/static/shaders/d3d/sm30/NormalColorPal.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorPalD.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorPalD.pso
new file mode 100644
index 000000000..5fa38d476
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/NormalColorPalD.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorPalInv.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorPalInv.pso
index 6db894964..7678d1668 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/NormalColorPalInv.pso and b/wadsrc/static/shaders/d3d/sm30/NormalColorPalInv.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorPalInvOpaq.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorPalInvOpaq.pso
new file mode 100644
index 000000000..2330d802d
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/NormalColorPalInvOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/NormalColorPalOpaq.pso b/wadsrc/static/shaders/d3d/sm30/NormalColorPalOpaq.pso
new file mode 100644
index 000000000..b5dd95bc0
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/NormalColorPalOpaq.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/PalAlphaTex.pso b/wadsrc/static/shaders/d3d/sm30/PalAlphaTex.pso
new file mode 100644
index 000000000..f511d4d2d
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/PalAlphaTex.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/PalStencil.pso b/wadsrc/static/shaders/d3d/sm30/PalStencil.pso
new file mode 100644
index 000000000..da7a0ad54
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/PalStencil.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/RedToAlpha.pso b/wadsrc/static/shaders/d3d/sm30/RedToAlpha.pso
deleted file mode 100644
index e8bff75b3..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/RedToAlpha.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/RedToAlphaInv.pso b/wadsrc/static/shaders/d3d/sm30/RedToAlphaInv.pso
deleted file mode 100644
index 85f3d1417..000000000
Binary files a/wadsrc/static/shaders/d3d/sm30/RedToAlphaInv.pso and /dev/null differ
diff --git a/wadsrc/static/shaders/d3d/sm30/SpecialColormap.pso b/wadsrc/static/shaders/d3d/sm30/SpecialColormap.pso
index 5da15158e..1e0dd3502 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/SpecialColormap.pso and b/wadsrc/static/shaders/d3d/sm30/SpecialColormap.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/SpecialColormapPal.pso b/wadsrc/static/shaders/d3d/sm30/SpecialColormapPal.pso
index baa84e797..7260951af 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/SpecialColormapPal.pso and b/wadsrc/static/shaders/d3d/sm30/SpecialColormapPal.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/Stencil.pso b/wadsrc/static/shaders/d3d/sm30/Stencil.pso
new file mode 100644
index 000000000..e864d735e
Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm30/Stencil.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/VertexColor.pso b/wadsrc/static/shaders/d3d/sm30/VertexColor.pso
index 46d2bc3d4..cb7f43bed 100644
Binary files a/wadsrc/static/shaders/d3d/sm30/VertexColor.pso and b/wadsrc/static/shaders/d3d/sm30/VertexColor.pso differ
diff --git a/wadsrc/static/shaders/d3d/sm30/build.bat b/wadsrc/static/shaders/d3d/sm30/build.bat
index 8129659ab..a5b193cfe 100644
--- a/wadsrc/static/shaders/d3d/sm30/build.bat
+++ b/wadsrc/static/shaders/d3d/sm30/build.bat
@@ -1,24 +1,28 @@
-fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 /FoNormalColor.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=1 /FoNormalColorInv.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 /FoNormalColorPal.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=1 /FoNormalColorPalInv.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0 /FoNormalColor.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0 /FoNormalColorPal.pso
 
-fxc ..\shaders.ps /Tps_3_0 /O3 /ERedToAlpha -DINVERT=0 /FoRedToAlpha.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /ERedToAlpha -DINVERT=1 /FoRedToAlphaInv.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=1 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorInv.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=1 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalInv.pso
+
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorOpaq.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalOpaq.pso
+
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=1 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorInvOpaq.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=1 -DOPAQUE=1 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalInvOpaq.pso
+
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=1 -DALPHATEX=0 -DDESAT=0 /FoStencil.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=1 -DALPHATEX=0 -DDESAT=0 /FoPalStencil.pso
+
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=1 -DDESAT=0 /FoAlphaTex.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=1 -DDESAT=0 /FoPalAlphaTex.pso
+
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorD.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ENormalColor -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=1 /FoNormalColorPalD.pso
 
 fxc ..\shaders.ps /Tps_3_0 /O3 /EVertexColor /FoVertexColor.pso
 
-fxc ..\shaders.ps /Tps_3_0 /O3 /ESpecialColormap -DPALTEX=0 -DINVERT=0 /FoSpecialColormap.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /ESpecialColormap -DPALTEX=1 -DINVERT=0 /FoSpecialColormapPal.pso
-
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=0 -DDESAT=0 /FoInGameColormap.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=0 -DDESAT=1 /FoInGameColormapDesat.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=1 -DDESAT=0 /FoInGameColormapInv.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=0 -DINVERT=1 -DDESAT=1 /FoInGameColormapInvDesat.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=0 -DDESAT=0 /FoInGameColormapPal.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=0 -DDESAT=1 /FoInGameColormapPalDesat.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=1 -DDESAT=0 /FoInGameColormapPalInv.pso
-fxc ..\shaders.ps /Tps_3_0 /O3 /EInGameColormap -DPALTEX=1 -DINVERT=1 -DDESAT=1 /FoInGameColormapPalInvDesat.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ESpecialColormap -DPALTEX=0 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0  /FoSpecialColormap.pso
+fxc ..\shaders.ps /Tps_3_0 /O3 /ESpecialColormap -DPALTEX=1 -DINVERT=0 -DOPAQUE=0 -DSTENCIL=0 -DALPHATEX=0 -DDESAT=0  /FoSpecialColormapPal.pso
 
 fxc ..\shaders.ps /Tps_3_0 /O3 /EBurnWipe /FoBurnWipe.pso
 
diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp
index 096db0c8f..4e1dbe5c2 100644
--- a/wadsrc/static/shaders/glsl/main.fp
+++ b/wadsrc/static/shaders/glsl/main.fp
@@ -17,6 +17,17 @@ vec4 ProcessTexel();
 vec4 ProcessLight(vec4 color);
 vec3 ProcessMaterial(vec3 material, vec3 color);
 
+//===========================================================================
+//
+// Color to grayscale
+//
+//===========================================================================
+
+float grayscale(vec4 color)
+{
+	return dot(color.rgb, vec3(0.4, 0.56, 0.14);
+}
+
 //===========================================================================
 //
 // Desaturate a color
@@ -27,7 +38,7 @@ vec4 desaturate(vec4 texel)
 {
 	if (uDesaturationFactor > 0.0)
 	{
-		float gray = (texel.r * 0.3 + texel.g * 0.56 + texel.b * 0.14);	
+		float gray = grayscale(texel);
 		return mix (texel, vec4(gray,gray,gray,texel.a), uDesaturationFactor);
 	}
 	else
@@ -64,7 +75,7 @@ vec4 getTexel(vec2 st)
 			break;
 			
 		case 4:	// TM_REDTOALPHA
-			float gray = (texel.r * 0.3 + texel.g * 0.56 + texel.b * 0.14);	
+			float gray = grayscale(texel);
 			texel = vec4(1.0, 1.0, 1.0, gray*texel.a);
 			break;
 			
@@ -457,7 +468,7 @@ void main()
 		
 		case 1:	// special colormap
 		{
-			float gray = (frag.r * 0.3 + frag.g * 0.56 + frag.b * 0.14);	
+			float gray = grayscale(frag);
 			vec4 cm = uFixedColormapStart + gray * uFixedColormapRange;
 			frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a*vColor.a);
 			break;