) this.
Well, if anyone wanted a retro 8-bit mode, here it is. Set d3d_disp_sw_cc to 2 and extract (
) cc-8bit-palette.7z to the game install directory. Alternatively, put the code below in shaders/cc.fx. The former is just the latter compiled using the fxc compiler. The latter may take some time to compile when switching to the game - not just when starting a mission, but even after just visiting a menu screen, it seems. Please note that especially in TDP with set_tex_filter 0, the difference to full 24-bit color may be surprisingly subtle.
Anyone who's better at HLSL than I am (not a high bar), feel free to fix this mess.
Code:
// Palettize to 8-bit palette (DARKPAL.PCX).
static const float3 LUMINANCE_VECTOR = float3(0.2125, 0.7154, 0.0721);
float g_fGamma;
float g_fSaturation;
float g_fContrast;
float g_fBrightness;
float4 g_fColorFilter;
float2 g_fScreenSize;
// the frame texture
sampler s0 : register(s0);
float4 pal[64] = {
{ 0x000000, 0xdddddd, 0xb6b6b6, 0x969696, }, { 0x7c7c7c, 0x666666, 0x545454, 0x454545, },
{ 0x393939, 0x2f2f2f, 0x272727, 0x202020, }, { 0x1a1a1a, 0x161616, 0x121212, 0x0f0f0f, },
{ 0x0c0c0c, 0x0a0a0a, 0x080808, 0x060606, }, { 0x050505, 0x040404, 0x030303, 0x7a8449, },
{ 0x707a43, 0x65703d, 0x5b6536, 0x0087fe, }, { 0x007df2, 0x0073e6, 0x0069da, 0x005fce, },
{ 0xb18c82, 0xa38178, 0x96776e, 0x886c64, }, { 0x7b615a, 0x6d5650, 0x604c46, 0x52413c, },
{ 0x443632, 0x372b28, 0x29211e, 0x1c1614, }, { 0x0e0b0a, 0xa30202, 0x980202, 0x8e0202, },
{ 0x830202, 0x780101, 0x6d0101, 0x630101, }, { 0x580101, 0x4d0101, 0x380101, 0x220000, },
{ 0x0d0000, 0x083015, 0x072b13, 0x062510, }, { 0x05200e, 0x041a0b, 0x031509, 0x020f06, },
{ 0x8e6d43, 0x87683f, 0x81623c, 0x7a5d38, }, { 0x735734, 0x6d5231, 0x664c2d, 0x60472a, },
{ 0x573f25, 0x4d3820, 0x44301a, 0x3a2915, }, { 0x312110, 0x3e1210, 0x3a110f, 0x36100e, },
{ 0x320e0d, 0x2e0d0c, 0x2a0c0b, 0x260b0a, }, { 0x220a09, 0x1d0807, 0x180606, 0x120504, },
{ 0x0d0303, 0x321d46, 0x2d1a3f, 0x271736, }, { 0x20132c, 0x1a1023, 0x140c1b, 0x0e0912, },
{ 0xee9a47, 0xde9042, 0xcf863e, 0xbf7c39, }, { 0xaf7134, 0xa0672f, 0x905d2b, 0x815326, },
{ 0x714922, 0x613f1d, 0x513519, 0x412b14, }, { 0x312110, 0x312110, 0x2e1f0f, 0x2b1d0e, },
{ 0x271a0d, 0x24180c, 0x21160b, 0x1e140a, }, { 0x1b1209, 0x170f07, 0x140d06, 0x110b05, },
{ 0x0a0603, 0xffffbd, 0xffb510, 0xffad52, }, { 0xffff7b, 0xf1e657, 0xe4ce34, 0xd6b510, },
{ 0x8c7b5a, 0x867555, 0x7f6e4f, 0x79684a, }, { 0x726145, 0x6c5b40, 0x65543a, 0x5c4c33, },
{ 0x54432c, 0x4b3b25, 0x42321e, 0x3a2a17, }, { 0x312110, 0x505b30, 0x4b552d, 0x464f2a, },
{ 0x404927, 0x3b4423, 0x363e20, 0x31381d, }, { 0x2c321a, 0x262c17, 0x212614, 0x1c2011, },
{ 0x171b0d, 0xad10b5, 0x9c29ad, 0xb51894, }, { 0x9400c6, 0x6300ad, 0x4a0080, 0x310052, },
{ 0x6d7787, 0x666f7e, 0x5f6775, 0x575f6c, }, { 0x505764, 0x494f5a, 0x424752, 0x3b4048, },
{ 0x33373e, 0x2b2e34, 0x222529, 0x1a1c1f, }, { 0x121315, 0x5a3139, 0x542e35, 0x4e2b31, },
{ 0x48272e, 0x42242a, 0x3c2126, 0x361e22, }, { 0x311b1f, 0x2b171b, 0x231316, 0x1b0e11, },
{ 0x130a0c, 0xe71821, 0xce2118, 0xff8c18, }, { 0xd97415, 0xb25c12, 0x8c440f, 0x652c0c, },
{ 0x6d5370, 0x664e69, 0x5e4760, 0x564158, }, { 0x4d3b4e, 0x463546, 0x3d2e3d, 0x352835, },
{ 0x2d222d, 0x241b24, 0x1c151c, 0x130e13, }, { 0x0b080b, 0x9c4a4a, 0xa86161, 0xb57777, },
{ 0xc18e8e, 0xcea5a5, 0xdabbbb, 0xe6d2d2, }, { 0xf3e8e8, 0xffffff, 0x0055c2, 0x004bb6, },
{ 0x0041a2, 0xb5bdff, 0x8c8ce7, 0x9cadef, }, { 0x7e9de2, 0x5f8ed4, 0x417ec7, 0x226eb9, },
{ 0xded684, 0xcfc87b, 0xc1ba73, 0xb2ac6a, }, { 0xa49e61, 0x959058, 0x878250, 0x746f44, },
{ 0x605c39, 0x4d4a2d, 0x393721, 0x262416, }, { 0x12110a, 0x74959d, 0x97b0b6, 0xbacace, },
{ 0xdce5e7, 0xffffff, 0x3a5b4b, 0x466e57, }, { 0x538063, 0x5f936f, 0x6ba57b, 0x00378d, },
{ 0x002d79, 0x002364, 0x001950, 0x000f3b, }, { 0x0000ff, 0x0000ff, 0xff00ff, 0x000000, },
};
float3 getPal(int i)
{
float pc;
switch (i%4) {
case 0: pc = pal[i/4].x; break;
case 1: pc = pal[i/4].y; break;
case 2: pc = pal[i/4].z; break;
case 3: pc = pal[i/4].w; break;
}
return float3(floor(pc/(1<<16)), fmod(floor(pc/(1<<8)), 256.0), fmod(pc, 256.0)) / 255.0;
}
float3 palettize(float3 vColor)
{
float3 cd, s, pc;
float d2, sd2 = 10;
[loop] for (int c = 0; c < 64; c++) {
pc = getPal(c);
cd = vColor.rgb - pc;
d2 = cd.r*cd.r+cd.g*cd.g+cd.b*cd.b;
if (d2 < sd2) {
s = pc;
sd2 = d2;
}
}
[loop] for (int c = 64; c < 128; c++) {
pc = getPal(c);
cd = vColor.rgb - pc;
d2 = cd.r*cd.r+cd.g*cd.g+cd.b*cd.b;
if (d2 < sd2) {
s = pc;
sd2 = d2;
}
}
[loop] for (int c = 128; c < 192; c++) {
pc = getPal(c);
cd = vColor.rgb - pc;
d2 = cd.r*cd.r+cd.g*cd.g+cd.b*cd.b;
if (d2 < sd2) {
s = pc;
sd2 = d2;
}
}
[loop] for (int c = 192; c < 256; c++) {
pc = getPal(c);
cd = vColor.rgb - pc;
d2 = cd.r*cd.r+cd.g*cd.g+cd.b*cd.b;
if (d2 < sd2) {
s = pc;
sd2 = d2;
}
}
return s;
}
float4 SatGammaPS(in float2 uv : TEXCOORD0, uniform int bDoSat, uniform int bDoGamma, uniform int bDoContrBright) : COLOR
{
float4 vColor = tex2D(s0, uv);
vColor.xyz = palettize(vColor.xyz);
if (bDoSat)
{
float lumi = dot(vColor.xyz, LUMINANCE_VECTOR);
vColor.xyz = lerp(lumi.xxx, vColor.xyz, g_fSaturation) * g_fColorFilter.xyz;
}
if (bDoGamma)
{
vColor.xyz = pow(vColor.xyz, g_fGamma);
}
if (bDoContrBright)
{
vColor.xyz = saturate(vColor.xyz * g_fContrast + g_fBrightness);
}
return vColor;
}
// apply saturation/color filter, brightness/contrast and gamma
technique TeqBrSatGamma
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(1, 1, 1);
}
}
// apply brightness/contrast and gamma
technique TeqBrGamma
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(0, 1, 1);
}
}
// apply brightness/contrast and saturation/color
technique TeqBrSat
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(1, 0, 1);
}
}
// apply saturation/color filter and gamma
technique TeqSatGamma
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(1, 1, 0);
}
}
// apply only gamma
technique TeqGamma
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(0, 1, 0);
}
}
// apply only brightness/contrast
technique TeqBr
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(0, 0, 1);
}
}
// apply only saturation/color
technique TeqSat
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(1, 0, 0);
}
}
// plain copy
technique TeqCopy
{
pass P0
{
PixelShader = compile ps_3_0 SatGammaPS(0, 0, 0);
}
}