From 55dab6d3d31043bfc162896f07651288032d3198 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Sat, 11 Jan 2020 22:18:06 +0100
Subject: [PATCH] - hooked up the high color texture colorization code.

Not tested and probably still not working correctly, the entire feature was a nearly impenetrable mess of convoluted code. This definitely needs verification with multiple mods using it.
---
 source/blood/src/view.cpp                     | 36 +++++------
 source/build/include/hightile.h               | 18 ++----
 source/build/src/hightile.cpp                 | 14 ++---
 source/build/src/mdsprite.cpp                 |  2 -
 source/build/src/polymost.cpp                 | 35 +++--------
 source/build/src/voxmodel.cpp                 |  3 -
 source/duke3d/src/screens.cpp                 | 24 +++----
 source/glbackend/gl_renderstate.h             |  3 +
 source/glbackend/gl_shader.cpp                |  3 +
 source/glbackend/gl_shader.h                  |  4 ++
 source/glbackend/gl_texture.cpp               | 19 +++++-
 source/glbackend/glbackend.cpp                |  3 +
 source/glbackend/glbackend.h                  |  8 ++-
 source/rr/src/screens.cpp                     | 24 +++----
 wadsrc/static/engine/shaders/glsl/polymost.fp | 63 +++++++++++--------
 15 files changed, 131 insertions(+), 128 deletions(-)

diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp
index e8ca71404..87a1b9c97 100644
--- a/source/blood/src/view.cpp
+++ b/source/blood/src/view.cpp
@@ -2877,29 +2877,29 @@ void UpdateDacs(int nPalette, bool bNoTint)
         {
         case 0:
         default:
-            tint->r = 255;
-            tint->g = 255;
-            tint->b = 255;
+            tint->tint.r = 255;
+            tint->tint.g = 255;
+            tint->tint.b = 255;
             break;
         case 1:
-            tint->r = 132;
-            tint->g = 164;
-            tint->b = 255;
+            tint->tint.r = 132;
+            tint->tint.g = 164;
+            tint->tint.b = 255;
             break;
         case 2:
-            tint->r = 255;
-            tint->g = 126;
-            tint->b = 105;
+            tint->tint.r = 255;
+            tint->tint.g = 126;
+            tint->tint.b = 105;
             break;
         case 3:
-            tint->r = 162;
-            tint->g = 186;
-            tint->b = 15;
+            tint->tint.r = 162;
+            tint->tint.g = 186;
+            tint->tint.b = 15;
             break;
         case 4:
-            tint->r = 255;
-            tint->g = 255;
-            tint->b = 255;
+            tint->tint.r = 255;
+            tint->tint.g = 255;
+            tint->tint.b = 255;
             break;
         }
         if (!bNoTint)
@@ -3709,9 +3709,9 @@ void viewSetCrosshairColor(int32_t r, int32_t g, int32_t b)
 #ifdef USE_OPENGL
     // XXX: this makes us also load all hightile textures tinted with the crosshair color!
     polytint_t & crosshairtint = hictinting[CROSSHAIR_PAL];
-    crosshairtint.r = CrosshairColors.r;
-    crosshairtint.g = CrosshairColors.g;
-    crosshairtint.b = CrosshairColors.b;
+    crosshairtint.tint.r = CrosshairColors.r;
+    crosshairtint.tint.g = CrosshairColors.g;
+    crosshairtint.tint.b = CrosshairColors.b;
     crosshairtint.f = HICTINT_USEONART | HICTINT_GRAYSCALE;
 #endif
     tileInvalidate(kCrosshairTile, -1, -1);
diff --git a/source/build/include/hightile.h b/source/build/include/hightile.h
index 8168cd669..c3e26e24f 100644
--- a/source/build/include/hightile.h
+++ b/source/build/include/hightile.h
@@ -1,21 +1,16 @@
 #ifndef HIGHTILE_PRIV_H
 #define HIGHTILE_PRIV_H
 
+#include "palentry.h"
+
 typedef struct {
     polytintflags_t f;
-    uint8_t r, g, b;
-    uint8_t sr, sg, sb;
+    PalEntry tint;
+    PalEntry shade;
 } polytint_t;
 
 extern polytint_t hictinting[MAXPALOOKUPS];
 
-static inline void globaltinting_apply(float *color)
-{
-    color[0] *= (float)globalr * (1.f/255.f);
-    color[1] *= (float)globalg * (1.f/255.f);
-    color[2] *= (float)globalb * (1.f/255.f);
-}
-
 
 // replacement flags
 enum
@@ -39,11 +34,8 @@ enum
     HICTINT_BLEND_HARDLIGHT = 3<<6,
 
     HICTINT_BLENDMASK = 64|128,
-
+    HICTINT_ALWAYSUSEART = 256,
     HICTINT_PRECOMPUTED = HICTINT_COLORIZE | HICTINT_BLENDMASK,
-    HICTINT_IN_MEMORY = HICTINT_PRECOMPUTED | HICTINT_GRAYSCALE | HICTINT_INVERT,
-
-    HICTINT_MEMORY_COMBINATIONS = 1<<5,
 };
 
 #endif
diff --git a/source/build/src/hightile.cpp b/source/build/src/hightile.cpp
index 8708850f2..a2d6a7ded 100644
--- a/source/build/src/hightile.cpp
+++ b/source/build/src/hightile.cpp
@@ -24,7 +24,7 @@ void hicinit(void)
     for (i=0; i<MAXPALOOKUPS; i++)  	// all tints should be 100%
     {
         polytint_t & tint = hictinting[i];
-        tint.r = tint.g = tint.b = 0xff;
+        tint.tint = 0xffffff;
         tint.f = 0;
     }
 }
@@ -41,12 +41,12 @@ void hicsetpalettetint(int32_t palnum, char r, char g, char b, char sr, char sg,
     if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return;
 
     polytint_t & tint = hictinting[palnum];
-    tint.r = r;
-    tint.g = g;
-    tint.b = b;
-    tint.sr = sr;
-    tint.sg = sg;
-    tint.sb = sb;
+    tint.tint.r = r;
+    tint.tint.g = g;
+    tint.tint.b = b;
+    tint.shade.r = sr;
+    tint.shade.g = sg;
+    tint.shade.b = sb;
     tint.f = effect;
 }
 
diff --git a/source/build/src/mdsprite.cpp b/source/build/src/mdsprite.cpp
index 6e3dd2059..4ff6a24b8 100644
--- a/source/build/src/mdsprite.cpp
+++ b/source/build/src/mdsprite.cpp
@@ -1591,8 +1591,6 @@ static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr)
 
     // tinting
     pc[0] = pc[1] = pc[2] = ((float)numshades - min(max((globalshade * hw_shadescale) + m->shadeoff, 0.f), (float)numshades)) / (float)numshades;
-	auto h = hictinting[globalpal];
-	GLInterface.SetTinting(h.f, PalEntry(h.sr, h.sg, h.sb), PalEntry(h.r, h.g, h.b));
 
     pc[3] = (tspr->cstat&2) ? glblend[tspr->blend].def[!!(tspr->cstat&512)].alpha : 1.0f;
     pc[3] *= 1.0f - sext->alpha;
diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp
index e61f006c1..9b42e38de 100644
--- a/source/build/src/polymost.cpp
+++ b/source/build/src/polymost.cpp
@@ -532,7 +532,6 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32
 	else if (drawpoly_trepeat) sampleroverride = SamplerClampX;
 	else sampleroverride = SamplerClampXY;
 
-
 	bool success = GLInterface.SetTexture(globalpicnum, TileFiles.tiles[globalpicnum], globalpal, method, sampleroverride);
 	if (!success)
 	{
@@ -560,16 +559,6 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32
 		GLInterface.SetNpotEmulation(false, 1.f, 0.f);
     }
 
-    vec2f_t hacksc = { 1.f, 1.f };
-
-#if 0
-    if (pth->flags & PTH_HIGHTILE)
-    {
-        hacksc = pth->scale;
-        tsiz = pth->siz;
-    }
-#endif
-
     vec2_t tsiz2 = tsiz;
 
 
@@ -580,28 +569,18 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32
 
     float pc[4];
 
-	polytint_t const& tint = hictinting[globalpal];
-    // This makes no sense.
-    pc[0] = 1.f;// (1.f - (tint.sr * (1.f / 255.f))) + (tint.sr * (1.f / 255.f));
-	pc[1] = 1.f;// (1.f - (tint.sg * (1.f / 255.f))) + (tint.sg * (1.f / 255.f));
-	pc[2] = 1.f;// (1.f - (tint.sb * (1.f / 255.f))) + (tint.sb * (1.f / 255.f));
-
-    // spriteext full alpha control
-    pc[3] = float_trans(method & DAMETH_MASKPROPS, drawpoly_blend) * (1.f - drawpoly_alpha);
-
-    // tinting
-	auto& h = hictinting[globalpal];
-
-	GLInterface.SetTinting(h.f, PalEntry(h.sr, h.sg, h.sb), PalEntry(h.r, h.g, h.b));
-
-    globaltinting_apply(pc);
+    // The shade rgb from the tint is ignored here.
+    pc[0] = (float)globalr * (1.f / 255.f);
+    pc[1] = (float)globalg * (1.f / 255.f);
+    pc[2] = (float)globalb * (1.f / 255.f);
+  	pc[3] = float_trans(method & DAMETH_MASKPROPS, drawpoly_blend) * (1.f - drawpoly_alpha);
 
     if (skyzbufferhack_pass)
         pc[3] = 0.01f;
 
     GLInterface.SetColor(pc[0], pc[1], pc[2], pc[3]);
 
-    vec2f_t const scale = { 1.f / tsiz2.x * hacksc.x, 1.f / tsiz2.y * hacksc.y };
+    vec2f_t const scale = { 1.f / tsiz2.x, 1.f / tsiz2.y };
 	auto data = GLInterface.AllocVertices(npoints);
 	auto vt = data.second;
 	for (bssize_t i = 0; i < npoints; ++i, vt++)
@@ -3237,7 +3216,7 @@ void polymost_drawrooms()
 	// This is a global setting for the entire scene, so let's do it here, right at the start.
 	auto& hh = hictinting[MAXPALOOKUPS - 1];
 	// This sets a tinting color for global palettes, e.g. water or slime - only used for hires replacements (also an option for low-resource hardware where duplicating the textures may be problematic.)
-	GLInterface.SetBasepalTint(PalEntry(hh.r, hh.g, hh.b));
+	GLInterface.SetBasepalTint(hh.tint);
 
 
     polymost_outputGLDebugMessage(3, "polymost_drawrooms()");
diff --git a/source/build/src/voxmodel.cpp b/source/build/src/voxmodel.cpp
index 6abefb81d..af5789e13 100644
--- a/source/build/src/voxmodel.cpp
+++ b/source/build/src/voxmodel.cpp
@@ -1082,9 +1082,6 @@ int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr)
 
     pc[0] = pc[1] = pc[2] = ((float)numshades - min(max((globalshade * hw_shadescale) + m->shadeoff, 0.f), (float)numshades)) / (float)numshades;
 
-	auto& h = hictinting[globalpal];
-	GLInterface.SetTinting(h.f, PalEntry(h.sr, h.sg, h.sb), PalEntry(h.r, h.g, h.b));
-
     if (!shadowHack)
     {
         pc[3] = (tspr->cstat & 2) ? glblend[tspr->blend].def[!!(tspr->cstat & 512)].alpha : 1.0f;
diff --git a/source/duke3d/src/screens.cpp b/source/duke3d/src/screens.cpp
index 328e87ca5..5436ed35f 100644
--- a/source/duke3d/src/screens.cpp
+++ b/source/duke3d/src/screens.cpp
@@ -166,9 +166,9 @@ void G_SetCrosshairColor(int32_t r, int32_t g, int32_t b)
 #ifdef USE_OPENGL
     // XXX: this makes us also load all hightile textures tinted with the crosshair color!
     polytint_t & crosshairtint = hictinting[CROSSHAIR_PAL];
-    crosshairtint.r = CrosshairColors.r;
-    crosshairtint.g = CrosshairColors.g;
-    crosshairtint.b = CrosshairColors.b;
+    crosshairtint.tint.r = CrosshairColors.r;
+    crosshairtint.tint.g = CrosshairColors.g;
+    crosshairtint.tint.b = CrosshairColors.b;
     crosshairtint.f = HICTINT_USEONART | HICTINT_GRAYSCALE;
 #endif
     tileInvalidate(CROSSHAIR, -1, -1);
@@ -761,23 +761,23 @@ void G_DisplayRest(int32_t smoothratio)
 
         if (pp->palette == WATERPAL)
         {
-            fstint.r = 224;
-            fstint.g = 192;
-            fstint.b = 255;
+            fstint.tint.r = 224;
+            fstint.tint.g = 192;
+            fstint.tint.b = 255;
             fstint.f = 0;
         }
         else if (pp->palette == SLIMEPAL)
         {
-            fstint.r = 208;
-            fstint.g = 255;
-            fstint.b = 192;
+            fstint.tint.r = 208;
+            fstint.tint.g = 255;
+            fstint.tint.b = 192;
             fstint.f = 0;
         }
         else
         {
-            fstint.r = 255;
-            fstint.g = 255;
-            fstint.b = 255;
+            fstint.tint.r = 255;
+            fstint.tint.g = 255;
+            fstint.tint.b = 255;
             fstint.f = 0;
         }
     }
diff --git a/source/glbackend/gl_renderstate.h b/source/glbackend/gl_renderstate.h
index 4f623e672..997bea5bf 100644
--- a/source/glbackend/gl_renderstate.h
+++ b/source/glbackend/gl_renderstate.h
@@ -35,6 +35,7 @@ enum PRSFlags
 	RF_HICTINT_BLEND_Overlay = 0x100000,
 	RF_HICTINT_BLEND_Hardlight = 0x200000,
 	RF_HICTINT_BLENDMASK = RF_HICTINT_BLEND_Screen | RF_HICTINT_BLEND_Overlay | RF_HICTINT_BLEND_Hardlight,
+	RF_HICTINT_MASK = 0x3f0000,
 
 	STF_BLEND = 1,
 	STF_COLORMASK = 2,
@@ -68,6 +69,8 @@ struct PolymostRenderState
 	bool AlphaTest = true;
 	float Color[4] = { 1,1,1,1 };
 	short matrixIndex[NUMMATRICES] = { -1,-1,-1,-1,-1 };
+	PalEntry fullscreenTint = 0xffffff, hictint = 0, hictint_overlay = 0xffffff;
+	int hictint_flags = 0;
 
 	int StateFlags = STF_COLORMASK|STF_DEPTHMASK;
 	FRenderStyle Style{};
diff --git a/source/glbackend/gl_shader.cpp b/source/glbackend/gl_shader.cpp
index d8fba3470..256732a98 100644
--- a/source/glbackend/gl_shader.cpp
+++ b/source/glbackend/gl_shader.cpp
@@ -144,6 +144,9 @@ bool PolymostShader::Load(const char * name, const char * vert_prog, const char
     Brightness.Init(hShader, "u_brightness");
 	FogColor.Init(hShader, "u_fogColor");
 	AlphaThreshold.Init(hShader, "u_alphaThreshold");
+	TintModulate.Init(hShader, "u_tintModulate");
+	TintOverlay.Init(hShader, "u_tintOverlay");
+	TintFlags.Init(hShader, "u_tintFlags");
 
     RotMatrix.Init(hShader, "u_rotMatrix");
 	ModelMatrix.Init(hShader, "u_modelMatrix");
diff --git a/source/glbackend/gl_shader.h b/source/glbackend/gl_shader.h
index 03cbeabfa..538958f37 100644
--- a/source/glbackend/gl_shader.h
+++ b/source/glbackend/gl_shader.h
@@ -45,6 +45,10 @@ public:
     FBufferedUniform1f Brightness;
 	FBufferedUniform1f AlphaThreshold;
 	FBufferedUniformPalEntry FogColor;
+	FBufferedUniformPalEntry TintModulate;
+	FBufferedUniformPalEntry TintOverlay;
+	FBufferedUniform1i TintFlags;
+
 
 	FUniformMatrix4f   RotMatrix;
 	FUniformMatrix4f   ModelMatrix;
diff --git a/source/glbackend/gl_texture.cpp b/source/glbackend/gl_texture.cpp
index ff963c068..1b36948c2 100644
--- a/source/glbackend/gl_texture.cpp
+++ b/source/glbackend/gl_texture.cpp
@@ -164,24 +164,37 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int
 	int lookuppal = 0;
 	VSMatrix texmat;
 
-	auto rep = hw_hightile? tex->FindReplacement(palette) : nullptr;
+	auto& h = hictinting[palette];
+	bool applytint = false;
+	auto rep = (hw_hightile && !(h.f & HICTINT_ALWAYSUSEART)) ? tex->FindReplacement(palette) : nullptr;
 	if (rep)
 	{
 		// Hightile replacements have only one texture representation and it is always the base.
 		tex = rep->faces[0];
 		TextureType = TT_HICREPLACE;
+		if (rep->palnum != palette || (h.f & HICTINT_APPLYOVERALTPAL)) applytint = true;
 	}
 	else
 	{
 		// Only look up the palette if we really want to use it (i.e. when creating a true color texture of an ART tile.)
 		if (TextureType == TT_TRUECOLOR)
 		{
-			/*lookuppal = palmanager.LookupPalette(usepalette, usepalswap, true);
-			if (lookuppal< 0)*/ lookuppal = palmanager.LookupPalette(usepalette, usepalswap, false, g_nontransparent255);
+			// Tinting is not used on indexed textures
+			if (h.f & (HICTINT_ALWAYSUSEART | HICTINT_USEONART))
+			{
+				applytint = true;
+				if (!(h.f & HICTINT_APPLYOVERPALSWAP)) usepalswap = 0;
+			}
+			lookuppal = palmanager.LookupPalette(usepalette, usepalswap, false, g_nontransparent255);
 		}
 
 	}
 
+	// This is intentionally the same value for both parameters. The shader does not use the same uniform for modulation and overlay colors.
+	if (applytint) GLInterface.SetTinting(h.f, h.tint, h.tint);
+	else GLInterface.SetTinting(-1, 0xffffff, 0xffffff);
+
+
 	// Load the main texture
 	auto mtex = LoadTexture(tex, TextureType, lookuppal);
 	if (mtex)
diff --git a/source/glbackend/glbackend.cpp b/source/glbackend/glbackend.cpp
index 6f5dcd9cd..3a3b91192 100644
--- a/source/glbackend/glbackend.cpp
+++ b/source/glbackend/glbackend.cpp
@@ -481,6 +481,9 @@ void PolymostRenderState::Apply(PolymostShader* shader, GLState &oldState)
 	shader->AlphaThreshold.Set(AlphaTest ? AlphaThreshold : -1.f);
 	shader->Brightness.Set(Brightness);
 	shader->FogColor.Set(FogColor);
+	shader->TintFlags.Set(hictint_flags);
+	shader->TintModulate.Set(hictint);
+	shader->TintOverlay.Set(hictint_overlay);
 	if (matrixIndex[Matrix_View] != -1)
 		shader->RotMatrix.Set(matrixArray[matrixIndex[Matrix_View]].get());
 	if (matrixIndex[Matrix_Projection] != -1)
diff --git a/source/glbackend/glbackend.h b/source/glbackend/glbackend.h
index 07467658d..6446d0a79 100644
--- a/source/glbackend/glbackend.h
+++ b/source/glbackend/glbackend.h
@@ -520,14 +520,16 @@ public:
 		renderState.Brightness = 8.f / (brightness + 8.f);
 	}
 
-	void SetTinting(int flags, PalEntry color, PalEntry modulateColor)
+	void SetTinting(int flags, PalEntry color, PalEntry overlayColor)
 	{
-		// not yet implemented.
+		renderState.hictint = color;
+		renderState.hictint_overlay = overlayColor;
+		renderState.hictint_flags = flags;
 	}
 
 	void SetBasepalTint(PalEntry color)
 	{
-		// not yet implemented - only relevant for hires replacements.
+		renderState.fullscreenTint = color;
 	}
 
 	int GetPaletteIndex(PalEntry* palette)
diff --git a/source/rr/src/screens.cpp b/source/rr/src/screens.cpp
index 1528248c4..ab47de266 100644
--- a/source/rr/src/screens.cpp
+++ b/source/rr/src/screens.cpp
@@ -159,9 +159,9 @@ void G_SetCrosshairColor(int32_t r, int32_t g, int32_t b)
 #ifdef USE_OPENGL
     // XXX: this makes us also load all hightile textures tinted with the crosshair color!
     polytint_t & crosshairtint = hictinting[CROSSHAIR_PAL];
-    crosshairtint.r = CrosshairColors.r;
-    crosshairtint.g = CrosshairColors.g;
-    crosshairtint.b = CrosshairColors.b;
+    crosshairtint.tint.r = CrosshairColors.r;
+    crosshairtint.tint.g = CrosshairColors.g;
+    crosshairtint.tint.b = CrosshairColors.b;
     crosshairtint.f = HICTINT_USEONART | HICTINT_GRAYSCALE;
 #endif
     tileInvalidate(CROSSHAIR, -1, -1);
@@ -759,23 +759,23 @@ void G_DisplayRest(int32_t smoothratio)
 
         if (pp->palette == WATERPAL)
         {
-            fstint.r = 224;
-            fstint.g = 192;
-            fstint.b = 255;
+            fstint.tint.r = 224;
+            fstint.tint.g = 192;
+            fstint.tint.b = 255;
             fstint.f = 0;
         }
         else if (pp->palette == SLIMEPAL)
         {
-            fstint.r = 208;
-            fstint.g = 255;
-            fstint.b = 192;
+            fstint.tint.r = 208;
+            fstint.tint.g = 255;
+            fstint.tint.b = 192;
             fstint.f = 0;
         }
         else
         {
-            fstint.r = 255;
-            fstint.g = 255;
-            fstint.b = 255;
+            fstint.tint.r = 255;
+            fstint.tint.g = 255;
+            fstint.tint.b = 255;
             fstint.f = 0;
         }
     }
diff --git a/wadsrc/static/engine/shaders/glsl/polymost.fp b/wadsrc/static/engine/shaders/glsl/polymost.fp
index ff1d73a7a..adbb2dc29 100644
--- a/wadsrc/static/engine/shaders/glsl/polymost.fp
+++ b/wadsrc/static/engine/shaders/glsl/polymost.fp
@@ -9,12 +9,12 @@ const int RF_NPOTEmulation = 32;
 const int RF_ShadeInterpolate = 64;
 const int RF_FogDisabled = 128;
 
-const int RF_HICTINT_Grayscale = 0x10000;
-const int RF_HICTINT_Invert = 0x20000;
-const int RF_HICTINT_Colorize = 0x40000;
-const int RF_HICTINT_BLEND_Screen = 0x80000;
-const int RF_HICTINT_BLEND_Overlay = 0x100000;
-const int RF_HICTINT_BLEND_Hardlight = 0x200000;
+const int RF_HICTINT_Grayscale = 0x1;
+const int RF_HICTINT_Invert = 0x2;
+const int RF_HICTINT_Colorize = 0x4;
+const int RF_HICTINT_BLEND_Screen = 64;
+const int RF_HICTINT_BLEND_Overlay = 128;
+const int RF_HICTINT_BLEND_Hardlight = 192;
 const int RF_HICTINT_BLENDMASK = RF_HICTINT_BLEND_Screen | RF_HICTINT_BLEND_Overlay | RF_HICTINT_BLEND_Hardlight;
 
 
@@ -36,6 +36,9 @@ uniform float u_visFactor;
 uniform int u_flags;
 uniform float u_alphaThreshold;
 
+uniform vec4 u_tintOverlay, u_tintModulate;
+uniform int u_tintFlags;
+
 uniform float u_npotEmulationFactor;
 uniform float u_npotEmulationXOffset;
 uniform float u_brightness;
@@ -81,51 +84,56 @@ float grayscale(vec4 color)
 //
 //===========================================================================
 
-vec4 convertColor(vec4 color, int effect, vec3 tint)
+vec4 convertColor(vec4 color)
 {
-#if 0
-
-	if (effect & RF_HICTINT_Grayscale)
+	int effect = u_tintFlags;
+	if ((effect & RF_HICTINT_Grayscale) != 0)
 	{
 		float g = grayscale(color);
 		color = vec4(g, g, g, color.a);
 	}
 
-	if (effect & RF_HICTINT_Invert)
+	if ((effect & RF_HICTINT_Invert) != 0)
 	{
-		color = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b);
+		color = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a);
 	}
 	
 	vec3 tcol = color.rgb * 255.0;	// * 255.0 to make it easier to reuse the integer math.
-	tint *= 255.0;
 
-	if (effect & RF_HICTINT_Colorize)
+	// Much of this looks quite broken by design. Why is this effectively multplied by 4 if the flag is set...? :(
+	if ((effect & RF_HICTINT_Colorize) != 0)
 	{
-		tcol.b = min(((tcol.b) * tint.r) / 64.0, 255.0);
-		tcol.g = min(((tcol.g) * tint.g) / 64.0, 255.0);
-		tcol.r = min(((tcol.r) * tint.b) / 64.0, 255.0);
+		tcol.b = min(((tcol.b) * u_tintModulate.r)* 4, 255.0);
+		tcol.g = min(((tcol.g) * u_tintModulate.g)* 4, 255.0);
+		tcol.r = min(((tcol.r) * u_tintModulate.b)* 4, 255.0);
+	}
+	else
+	{
+		tcol.b = min(((tcol.b) * u_tintModulate.r), 255.0);
+		tcol.g = min(((tcol.g) * u_tintModulate.g), 255.0);
+		tcol.r = min(((tcol.r) * u_tintModulate.b), 255.0);
 	}
 
+	vec4 ov = u_tintOverlay * 255.0;
 	switch (effect & RF_HICTINT_BLENDMASK)
 	{
 		case RF_HICTINT_BLEND_Screen:
-			tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 256.0);
-			tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 256.0);
-			tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 256.0);
+			tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - ov.r)) / 256.0);
+			tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - ov.g)) / 256.0);
+			tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - ov.b)) / 256.0);
 			break;
 		case RF_HICTINT_BLEND_Overlay:
-			tcol.b = tcol.b < 128.0? (tcol.b * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 128.0);
-			tcol.g = tcol.g < 128.0? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0);
-			tcol.r = tcol.r < 128.0? (tcol.r * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 128.0);
+			tcol.b = tcol.b < 128.0? (tcol.b * ov.r) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - ov.r)) / 128.0);
+			tcol.g = tcol.g < 128.0? (tcol.g * ov.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - ov.g)) / 128.0);
+			tcol.r = tcol.r < 128.0? (tcol.r * ov.b) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - ov.b)) / 128.0);
 			break;
 		case RF_HICTINT_BLEND_Hardlight:
-			tcol.b = tint.r < 128.0 ? (tcol.b * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - r)) / 128.0);
-			tcol.g = tint.g < 128.0 ? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - g)) / 128.0);
-			tcol.r = tint.b < 128.0 ? (tcol.r * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - b)) / 128.0);
+			tcol.b = ov.r < 128.0 ? (tcol.b * ov.r) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - ov.r)) / 128.0);
+			tcol.g = ov.g < 128.0 ? (tcol.g * ov.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - ov.g)) / 128.0);
+			tcol.r = ov.b < 128.0 ? (tcol.r * ov.b) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - ov.b)) / 128.0);
 			break;
 	}
 	color.rgb = tcol / 255.0;
-#endif
 	return color;
 }
 
@@ -196,6 +204,7 @@ void main()
 		}
 		else
 		{
+			if (u_tintFlags != -1) color = convertColor(color);
 			color.rgb *= detailColor.rgb;
 			
 			vec3 lightcolor = v_color.rgb;