TTLG|Thief|Bioshock|System Shock|Deus Ex|Mobile
Page 1 of 2 12 LastLast
Results 1 to 25 of 27

Thread: Faux 8-bit mode with NewDark + shader

  1. #1
    Member
    Registered: Nov 2001
    Location: Sunny Finland

    Faux 8-bit mode with NewDark + shader

    EDIT: TL;DR: Go straight to this post, and maybe also 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);
         }
    }
    Last edited by jermi; 6th Jul 2020 at 11:14.

  2. #2
    Member
    Registered: Apr 2011
    Well, it definitely works! Here's a so-retro-it's-anachronistic Thief 2 screenshot:

  3. #3
    Member
    Registered: Apr 2011
    Location: Montpellier, France
    Ooooh, I need to try that!

  4. #4
    New Member
    Registered: Apr 2018
    Dude, TG looks amazing - the Bonehoard so sinister again. Was only a second's delay so yeah, I'm never switching this off.

    (Oh and never mind my registration date, I've been lurking 20 years. This needed to be commented on. )

  5. #5
    Well, this is something. Was this the right way to play TG all along? (Those are the ESRGAN textures, if you're wondering)



  6. #6
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Seems like doing a nearest-color search on the original Thief software palette for every pixel of the screen would have quite the performance impact. Is it really noticeably different from just banging each pixel down to RGB333 or something like that?

    EDIT: Yeah, this drags my frame rate down from a solid 60FPS to 30FPS. Just quantizing the color gamut runs a lot faster, though of course it's only an approximation of the palettized effect.
    Code:
    // Quantize displayed colors
    
    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 SatGammaPS(in float2 uv : TEXCOORD0, uniform int bDoSat, uniform int bDoGamma, uniform int bDoContrBright) : COLOR
    {
         float4 vColor = tex2D(s0, uv);
         vColor.x = round(vColor.x * 16.0) / 16.0;
         vColor.y = round(vColor.y * 16.0) / 16.0;
         vColor.z = round(vColor.z * 16.0) / 16.0;
    
         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);
         }
    }
    This quantizes the output to the equivalent of RGB444, aka 12-bit color. Since shaders represent colors as floats, there's no need to stick to bit multiples, so the "roughness" can be adjusted to whatever degree you like. And each channel doesn't have to be quantized the same, so you could tweak it to give more resolution to the reds and greens of the Thief palette and less to blues.

    And now enjoy some really retro System Shock 2.

    Last edited by ZylonBane; 27th Jun 2020 at 15:43.

  7. #7
    Member
    Registered: Nov 2001
    Location: Sunny Finland
    I was mostly just figuring out if it's even possible to do exact palettization. Doing a per-pixel linear search through a 256-color palette is of course slow - but not necessarily too slow. On my machine, this shader drops the frame rate from 240+ to around 105 at the start of "Bafford's" on a FullHD screen.

    Quantization is unlikely to be a good approximation of a palette. That's kind of the whole point of having a palette in the first place. But I'm not here to promote palettization or anything like that, just showing that it's possible. For the record, I never played in 8-bit mode, so I don't really even know how this compares.

  8. #8
    Member
    Registered: Aug 2009
    Location: thiefgold.com
    Quote Originally Posted by jermi View Post
    Well, if anyone wanted a retro 8-bit mode, here it is.
    That one doesn't look much different than full colour, and it kills my framerate.

    I think Zylonbane nailed it, there's maybe some small tweaks (the colour transition on these banners looks a bit weird), but otherwise this is Old Dark software mode to a tee, well done!




  9. #9
    Member
    Registered: Aug 2009
    Location: thiefgold.com
    This is jermi's version for comparison. It still looks interesting, like a slightly desaturated full colour mode, but it's impossible to play


  10. #10
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    I'm glad you like it, but it literally doesn't look like software mode to a tee, since software mode forced every pixel to map to one of the 256 palette colors. What my code does is basically run a posterization filter on the screen. Maybe Jermi's filter doesn't look as "bad" as you were expecting because the Thief software palette was very well optimized for its assets.

  11. #11
    Member
    Registered: Feb 2012
    Location: Russia
    Is there is a way to port this to ReShade?

  12. #12
    Member
    Registered: Nov 2001
    Location: Sunny Finland
    I'm guessing yes.

  13. #13
    Member
    Registered: Oct 2001
    Location: Inside at last...
    Oh my God, finally!

    I've always thought the original bland look of the first game was the most creepy and loved it for it. The 3d Acceleration had removed almost all of it, expecially in Thief 2.

    So is this working? For both Thief 1 and Thief 2?

    And by the way, Zylon, that SS2 with the retro-look looks sweet! I don't see any framerate drops...

  14. #14
    I also think Zylon's shader gets closer to the feel of software mode (I managed to experience how it really looks like with the legacy exe. Don't know how to make the image to stop stretching, though), and it doesn't tank performance, too.
    jermi's shader framedrops really vary depending on the size of the mission, and if it's a huge FM with effects (like Scarlet Cascabel)... whew. Still feels better than the choppy nature of software mode, but I can hear my GPU fan working it out to render it.
    Last edited by Taffingtaffer; 5th Jul 2020 at 11:17.

  15. #15
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Quote Originally Posted by Fallen+Keeper View Post
    So is this working? For both Thief 1 and Thief 2?
    As I'm sure you should be well aware, under NewDark both Thief 1 and 2 use the exact same engine.

  16. #16
    Keyla the Otter
    Registered: Mar 2009
    Location: USA
    I remember playing Thief in software mode prior to 2000. If this gets a proper release, I will definitely grab it and play it.

  17. #17
    Member
    Registered: Aug 2009
    Location: thiefgold.com
    Quote Originally Posted by Taffingtaffer View Post
    I also think Zylon's shader gets closer to the feel of software mode (I managed to experience how it really looks like with the legacy exe.
    I don't know how you guys are able to use the Old Dark exe, but it won't work for me no matter what I do (compatibility modes, &c), either won't run, or gets to the menu, and crashes when I start or load a game.

    I'm definitely curious to try Old Dark and compare it to the shader, I'm pretty certain Zylonbane's shader replicates it perfectly from what I remember, but need to confirm

  18. #18
    Quote Originally Posted by Azaran View Post
    I don't know how you guys are able to use the Old Dark exe, but it won't work for me no matter what I do (compatibility modes, &c), either won't run, or gets to the menu, and crashes when I start or load a game.

    I'm definitely curious to try Old Dark and compare it to the shader, I'm pretty certain Zylonbane's shader replicates it perfectly from what I remember, but need to confirm
    Didn't work for me either with my previous TFix Full installation. Haven't tried the legacy exes after reinstalling TFix Full, but I made two separate, fresh Thief Gold folders, one with just TFix Lite, and the other with GoldtoDark mod and TFix Lite. A fresh installation already comes with a no_ddfix exe (at least the Steam release), so you don't need taking it out of TFix Full. The DDFix .dll and .ini are a bit outdated, so download the last version, if you want.

    There are a few things to take in mind with TFix Lite, though:

    - Extract TFix Lite to clean instalation
    - Leave install.cfg like this:

    install_path .\
    language english
    resname_base .\RES
    load_path .\
    script_module_path .\
    movie_path .\MOVIES

    - Copy sq_scripts folder from TFix full, place it in the root directory, add the following to the top of gamesys.dml,
    under #script "script-t1":

    #script squirrel

    And this to the bottom:

    ObjProp -2099 "Scripts"
    {
    "Script 3" VictoryCheckAux
    }

  19. #19
    Member
    Registered: Nov 2001
    Location: Sunny Finland
    Take two. I also can't get TDP to run in software mode, so I'm using OldDark DromEd 1.37 "solid world" view as a reference.

    Based on a look at the leaked code, the software renderer quantizes lightmaps to 4 bits (16 levels). After seeing that, and also looking at the TDP palette in HSV, I figured that the best simple approximation is to just quantize the HSV value component. So that's what this shader does, along with a couple of other simple tricks.

    • Extract cc-faux-8bit-sw-mode.7z into the game install directory.
    • Put these is cam_ext.cfg:
      Code:
      d3d_disp_sw_cc 2
      disable_32bit_fampal
      tex_filter_mode 0
      mipmap_bias -1.0



  20. #20
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Quote Originally Posted by Azaran View Post
    I'm definitely curious to try Old Dark and compare it to the shader, I'm pretty certain Zylonbane's shader replicates it perfectly from what I remember, but need to confirm
    As I already explained, it DOES NOT. At best, it replicates your memory of how it looked.

  21. #21
    Yeah, this looks pretty close, with the plus of having actual black darkness and not that green shadow from DirectX 6. I'm not sure why the window's orange tone get lighter with Akven's ESRGAN pack, though.

    No shader


    Shader


    This aside, it looks great and performs well. I can't believe how flat the game looked before.
    Last edited by Taffingtaffer; 5th Jul 2020 at 14:33.

  22. #22
    Member
    Registered: Oct 2001
    Location: Inside at last...
    I need to try it pronto.

  23. #23
    Member
    Registered: Oct 2001
    Location: Inside at last...
    Quote Originally Posted by Taffingtaffer View Post
    Yeah, this looks pretty close, with the plus of having actual black darkness and not that green shadow from DirectX 6. I'm not sure why the window's orange tone get lighter with Akven's ESRGAN pack, though.

    No shader


    Shader


    This aside, it looks great and performs well. I can't believe how BEAUTIFUL the game looked before.
    There.... I fixed it for ya....

  24. #24
    Member
    Registered: Nov 2001
    Location: Sunny Finland
    I thought this mod had been done at least once before, but I can't find it, so I made my own. This is faux software mode water. To install, extract thief-faux-swwater.7z to your mod_path. Again, I can't get TDP to run in software mode, so I don't really know how this compares.

    It's so ugly it's almost cute.


  25. #25
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Looks pretty accurate to me.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •