Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TrueColor: implement optional tablified translucency #1233

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions src/crispy.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static crispy_t crispy_s = {
#ifdef CRISPY_TRUECOLOR
.smoothlight = 1,
.truecolor = 1,
.truecolorblend = 1,
#endif
.vsync = 1,
.widescreen = 1, // match screen by default
Expand Down
1 change: 1 addition & 0 deletions src/crispy.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ typedef struct
int translucency;
#ifdef CRISPY_TRUECOLOR
int truecolor;
int truecolorblend;
#endif
int uncapped;
int vsync;
Expand Down
1 change: 1 addition & 0 deletions src/doom/d_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ void D_BindVariables(void)
M_BindIntVariable("crispy_translucency", &crispy->translucency);
#ifdef CRISPY_TRUECOLOR
M_BindIntVariable("crispy_truecolor", &crispy->truecolor);
M_BindIntVariable("crispy_truecolorblend", &crispy->truecolorblend);
#endif
M_BindIntVariable("crispy_uncapped", &crispy->uncapped);
M_BindIntVariable("crispy_vsync", &crispy->vsync);
Expand Down
6 changes: 6 additions & 0 deletions src/doom/r_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,12 @@ void R_InitData (void)
R_InitHSVColors ();
#ifndef CRISPY_TRUECOLOR
R_InitTranMap(); // [crispy] prints a mark itself
#else
// [crispy] Initialize blending maps for tablified additive and
// overlay translucency, used by TrueColor renderer.
R_InitBlendMaps(doom);
// [crispy] Set pointers to blending functions.
R_InitBlendQuality();
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion src/doom/r_things.c
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ void R_ProjectSprite (mobj_t* thing)
// [crispy] translucent sprites
if (thing->flags & MF_TRANSLUCENT)
{
vis->blendfunc = (thing->frame & FF_FULLBRIGHT) ? I_BlendAdd : I_BlendOverTranmap;
vis->blendfunc = (thing->frame & FF_FULLBRIGHT) ? I_BlendAddFunc : I_BlendOverTranmap;
}
#endif
}
Expand Down
1 change: 1 addition & 0 deletions src/heretic/d_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ void D_BindVariables(void)
M_BindIntVariable("crispy_soundmono", &crispy->soundmono);
#ifdef CRISPY_TRUECOLOR
M_BindIntVariable("crispy_truecolor", &crispy->truecolor);
M_BindIntVariable("crispy_truecolorblend", &crispy->truecolorblend);
#endif
M_BindIntVariable("crispy_uncapped", &crispy->uncapped);
M_BindIntVariable("crispy_vsync", &crispy->vsync);
Expand Down
7 changes: 7 additions & 0 deletions src/heretic/r_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,13 @@ void R_InitData(void)
R_InitColormaps();
// [crispy] Initialize color translation and color string tables.
R_InitHSVColors();
#ifdef CRISPY_TRUECOLOR
// [crispy] Initialize blending maps for tablified
// overlay translucency (normal and "alt"), used by TrueColor renderer.
R_InitBlendMaps(heretic);
// [crispy] Set pointers to blending functions.
R_InitBlendQuality();
#endif
}


Expand Down
1 change: 1 addition & 0 deletions src/hexen/h2_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ void D_BindVariables(void)
M_BindIntVariable("crispy_soundmono", &crispy->soundmono);
#ifdef CRISPY_TRUECOLOR
M_BindIntVariable("crispy_truecolor", &crispy->truecolor);
M_BindIntVariable("crispy_truecolorblend", &crispy->truecolorblend);
#endif
M_BindIntVariable("crispy_smoothlight", &crispy->smoothlight);
M_BindIntVariable("crispy_smoothscaling", &crispy->smoothscaling);
Expand Down
7 changes: 7 additions & 0 deletions src/hexen/r_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,13 @@ void R_InitData(void)
#endif
// [crispy] initialize color translation and color string tables
R_InitHSVColors();
#ifdef CRISPY_TRUECOLOR
// [crispy] Initialize blending maps for tablified overlay
// translucency (normal and "alt"), used by TrueColor renderer.
R_InitBlendMaps(hexen);
// [crispy] Set pointers to blending functions.
R_InitBlendQuality();
#endif
}

//=============================================================================
Expand Down
163 changes: 158 additions & 5 deletions src/i_truecolor.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,100 @@ typedef union
};
} tcpixel_t;

// [JN] LUTs to store precomputed values for all possible 512 color combinations
static uint32_t blendAddLUT[512][512]; // Additive blending
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good already, thank you! Do you think we could get away with only two arrays, a "main" one and an "alt" one (which would be additive in Doom)?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this:

diff --git a/src/i_truecolor.c b/src/i_truecolor.c
index 21f9128b..b3b4b95a 100644
--- a/src/i_truecolor.c
+++ b/src/i_truecolor.c
@@ -38,9 +38,8 @@ typedef union
 } tcpixel_t;
 
 // [JN] LUTs to store precomputed values for all possible 512 color combinations
-static uint32_t blendAddLUT[512][512];      // Additive blending
 static uint32_t blendOverLUT[512][512];     // Overlay blending
-static uint32_t blendOverAltLUT[512][512];  // Overlay "alt" blending
+static uint32_t blendAltLUT[512][512];      // Additive blending (Doom), Overlay "alt" blending
 
 const uint32_t (*I_BlendAddFunc) (const uint32_t bg_i, const uint32_t fg_i);
 const uint32_t (*I_BlendOverFunc) (const uint32_t bg_i, const uint32_t fg_i, const int amount);
@@ -104,23 +103,28 @@ void R_InitBlendMaps (GameMission_t mission)
             fg.g = ((fg_index >> 3) & 0x07) << 5;
             fg.b = (fg_index & 0x07) << 5;
 
-            // Additive blending calculation
-            retAdd.r = MIN(bg.r + fg.r, 0xFFU);
-            retAdd.g = MIN(bg.g + fg.g, 0xFFU);
-            retAdd.b = MIN(bg.b + fg.b, 0xFFU);
-            blendAddLUT[bg_index][fg_index] = retAdd.i;
-
             // Overlay blending calculation
             retOver.r = (overlay_alpha * fg.r + (0xFFU - overlay_alpha) * bg.r) >> 8;
             retOver.g = (overlay_alpha * fg.g + (0xFFU - overlay_alpha) * bg.g) >> 8;
             retOver.b = (overlay_alpha * fg.b + (0xFFU - overlay_alpha) * bg.b) >> 8;
             blendOverLUT[bg_index][fg_index] = retOver.i;
 
-            // Overlay "alt" blending calculation
-            retOver.r = (overlay_alt_alpha * fg.r + (0xFFU - overlay_alt_alpha) * bg.r) >> 8;
-            retOver.g = (overlay_alt_alpha * fg.g + (0xFFU - overlay_alt_alpha) * bg.g) >> 8;
-            retOver.b = (overlay_alt_alpha * fg.b + (0xFFU - overlay_alt_alpha) * bg.b) >> 8;
-            blendOverAltLUT[bg_index][fg_index] = retOver.i;
+            if (overlay_alt_alpha == 0)
+            {
+                // Additive blending calculation
+                retAdd.r = MIN(bg.r + fg.r, 0xFFU);
+                retAdd.g = MIN(bg.g + fg.g, 0xFFU);
+                retAdd.b = MIN(bg.b + fg.b, 0xFFU);
+                blendAltLUT[bg_index][fg_index] = retAdd.i;
+            }
+            else
+            {
+                // Overlay "alt" blending calculation
+                retOver.r = (overlay_alt_alpha * fg.r + (0xFFU - overlay_alt_alpha) * bg.r) >> 8;
+                retOver.g = (overlay_alt_alpha * fg.g + (0xFFU - overlay_alt_alpha) * bg.g) >> 8;
+                retOver.b = (overlay_alt_alpha * fg.b + (0xFFU - overlay_alt_alpha) * bg.b) >> 8;
+                blendAltLUT[bg_index][fg_index] = retOver.i;
+            }
         }
     }
 }
@@ -157,7 +161,7 @@ const uint32_t I_BlendAddLow (const uint32_t bg_i, const uint32_t fg_i)
     bg_index = PixelToLUTIndex(bg);
     fg_index = PixelToLUTIndex(fg);
 
-    return blendAddLUT[bg_index][fg_index];
+    return blendAltLUT[bg_index][fg_index];
 }
 
 const uint32_t I_BlendDark (const uint32_t bg_i, const int d)
@@ -214,7 +218,7 @@ const uint32_t I_BlendOverAltLow (const uint32_t bg_i, const uint32_t fg_i, cons
     bg_index = PixelToLUTIndex(bg);
     fg_index = PixelToLUTIndex(fg);
 
-    return blendOverAltLUT[bg_index][fg_index];
+    return blendAltLUT[bg_index][fg_index];
 }
 
 // [crispy] TRANMAP blending emulation, used for Doom

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I was thinking how to divide tablifying per game, but in the end chickened out because of:

  1. Possible hit 512x512 times of checking if/else conditions.
  2. To avoid bloating for loop.

But looks likes it's not that scary, so sure, let's go this way. Most important question for this PR: how should we name menu item? Maybe something like:

  • Translucency quality: 8bit / 32bit (or 8bpp / 32bpp? or low/high?)
  • Blending mode: speed / quality

Hot-switch is fairly simple, we just have to kick R_InitBlendQuality, even post-rendering doesn't seems to be not needed.

Finally, I have an itch that something else could be done. Current implementation helps to improve performance and get higher average framerate in -timedemo runs, but results are not as high as expected. I'm thinking to play around with R_DrawTLColumn by unrolling by four, @rfomin recommending to go farther by turning blending functions to inline's, but it's tricky since we are using function pointers, except for BlendDark for fuzz drawing.

So maybe you can give few recommendations regarding where to think or dig? 🙂

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Translucency quality: 8bit / 32bit (or 8bpp / 32bpp? or low/high?)

That'd be 9bit, strictly speaking. 😉

  • Blending mode: speed / quality

Translucency mode: speed / quality

I'd avoid using the term "blending" if we only call it "translucency" just one line above.

Finally, I have an itch that something else could be done. Current implementation helps to improve performance and get higher average framerate in -timedemo runs, but results are not as high as expected. I'm thinking to play around with R_DrawTLColumn by unrolling by four,

Sure, there's so much left for optimization in Doom's source code.

@rfomin recommending to go farther by turning blending functions to inline's, but it's tricky since we are using function pointers, except for BlendDark for fuzz drawing.

Nope, we cannot inline function pointers, obviously.

I'm fine with the current implementation. Heck, I was even too lazy for the last ~10 years to write the code that you just contributed in this PR. 😁

If you find some code path that could use some further optimization, sure, please feel free to investigate it. But this is probably topic for another PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rfomin recommending to go farther by turning blending functions to inline's, but it's tricky since we are using function pointers, except for BlendDark for fuzz drawing.

Nope, we cannot inline function pointers, obviously.

I suggest making more functions (e.g. R_DrawTLColumnAdd, R_DrawTLColumnOver). Function calls on every pixel are expensive, I checked when implementing Woof's "function factory" (about ~30% performance hit).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dammit... There is just a small difference in performance comparing between 512x512 and 256x256 LUTs. Something really have to be done with column drawing functions.

Just in case, 256x256 LUT code, still much better than just 256 colors:

--- R:/GITHUB/crispy-doom/src/i_truecolor.c	Thu Oct 31 22:15:20 2024
+++ R:/MSYS/home/Julia/crispy-doom/src/i_truecolor.c	Fri Nov  1 23:33:47 2024
@@ -38,8 +38,8 @@
 } tcpixel_t;
 
 // [crispy] LUTs to store precomputed values for all possible 512x512 color combinations
-static uint32_t blendOverLUT[512][512];  // Overlay blending
-static uint32_t blendAltLUT[512][512];   // Additive blending (Doom), Overlay "alt" blending
+static uint32_t blendOverLUT[256][256];  // Overlay blending
+static uint32_t blendAltLUT[256][256];   // Additive blending (Doom), Overlay "alt" blending
 
 const uint32_t (*I_BlendAddFunc) (const uint32_t bg_i, const uint32_t fg_i);
 const uint32_t (*I_BlendOverFunc) (const uint32_t bg_i, const uint32_t fg_i, const int amount);
@@ -90,18 +90,18 @@
     retAdd.a = 0xFFU;
     retOver.a = 0xFFU;
 
-    for (int bg_index = 0; bg_index < 512; ++bg_index)
+    for (int bg_index = 0; bg_index < 256; ++bg_index)
     {
-        for (int fg_index = 0; fg_index < 512; ++fg_index)
+        for (int fg_index = 0; fg_index < 256; ++fg_index)
         {
             // Convert LUT indices back to RGB values with reduced bit depth
-            bg.r = (bg_index >> 6) << 5;
-            bg.g = ((bg_index >> 3) & 0x07) << 5;
-            bg.b = (bg_index & 0x07) << 5;
-
-            fg.r = (fg_index >> 6) << 5;
-            fg.g = ((fg_index >> 3) & 0x07) << 5;
-            fg.b = (fg_index & 0x07) << 5;
+            bg.r = (bg_index >> 5) << 5;
+            bg.g = ((bg_index >> 2) & 0x07) << 5;
+            bg.b = (bg_index & 0x03) << 6;
+
+            fg.r = (fg_index >> 5) << 5;
+            fg.g = ((fg_index >> 2) & 0x07) << 5;
+            fg.b = (fg_index & 0x03) << 6;
 
             // Overlay blending calculation
             retOver.r = (overlay_alpha * fg.r + (0xFFU - overlay_alpha) * bg.r) >> 8;
@@ -130,9 +130,9 @@
 }
 
 // [crispy] Helper function to convert a pixel color to a LUT index
-static inline uint16_t PixelToLUTIndex (const tcpixel_t color)
+static inline uint8_t PixelToLUTIndex (const tcpixel_t color)
 {
-    return ((color.r & 0xE0) << 1) | ((color.g & 0xE0) >> 2) | (color.b >> 5);
+    return ((color.r & 0xE0) | ((color.g & 0xE0) >> 3) | (color.b >> 6));
 }
 
 const uint32_t I_BlendAdd (const uint32_t bg_i, const uint32_t fg_i)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dammit... There is just a small difference in performance comparing between 512x512 and 256x256 LUTs.

Array access time doesn't depend on array size. 🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks, good to know - that's important. I'm playing around with inline-ing, at least for additive blending in R_DrawTLColumn and it actually helps, -timedemo differences before and after inlining are about ~466 w/o inlining and ~522 with inlining.

Looks likes it is have to be done, maybe really in another PR, since we have to divide R_DrawTLColumn to blend/alt functions (and to high/low detail + high/low quality, oh God!), and unlikely I will handle Format Factory approach. Otherwise, this whole idea and implementation is nothing more than cosmetical change with tiny performance improvement.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, tongue was ahead of thoughts. So the idea is put TrueColor TL drawing functions as macroses to i_truecolor.h where we can have inlining without overbloating existing code in r_draw.c of all four games and we don't need to care about tranmap[], tinttab[] and xlatab[] there. This will still require small separating of colfunc pointers for TrueColor only, but in theory, this will do the trick.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't overload this PR, though. Let's do one step after the other...

static uint32_t blendOverLUT[512][512]; // Overlay blending
static uint32_t blendOverAltLUT[512][512]; // Overlay "alt" blending

const uint32_t (*I_BlendAddFunc) (const uint32_t bg_i, const uint32_t fg_i);
const uint32_t (*I_BlendOverFunc) (const uint32_t bg_i, const uint32_t fg_i, const int amount);
const uint32_t (*I_BlendOverAltFunc) (const uint32_t bg_i, const uint32_t fg_i, const int amount);

// [JN] Different blending alpha values for different games
#define OVERLAY_ALPHA_TRANMAP 0xA8 // Doom: TRANMAP, 168 (66% opacity)
#define OVERLAY_ALPHA_TINTTAB 0x60 // Raven: TINTTAB, 96 (38% opacity)
#define OVERLAY_ALPHA_TINTTABALT 0x8E // Raven: TINTTAB, 142 (56% opacity, "Alt")
#define OVERLAY_ALPHA_XLATAB 0xC0 // Strife: XLATAB, 192 (75% opacity)
#define OVERLAY_ALPHA_XLATABALT 0x40 // Strife: XLATAB, 64 (25% opacity, "Alt")


// [JN] Initialize blending maps for tablified additive and overlay translucency
void R_InitBlendMaps (GameMission_t mission)
{
tcpixel_t bg, fg;
tcpixel_t retAdd, retOver;
uint8_t overlay_alpha, overlay_alt_alpha;

// Define different alpha values for different games
switch (mission)
{
default: // Doom and derivatives
{
overlay_alpha = OVERLAY_ALPHA_TRANMAP;
overlay_alt_alpha = 0; // "alt" blending is not used
break;
}

case heretic:
case hexen:
{
overlay_alpha = OVERLAY_ALPHA_TINTTAB;
overlay_alt_alpha = OVERLAY_ALPHA_TINTTABALT;
break;
}

case strife:
{
overlay_alpha = OVERLAY_ALPHA_XLATAB;
overlay_alt_alpha = OVERLAY_ALPHA_XLATABALT;
break;
}
}

// Shortcut: these variables are always same in tablified approach
retAdd.a = 0xFFU;
retOver.a = 0xFFU;

for (int bg_index = 0; bg_index < 512; ++bg_index)
{
for (int fg_index = 0; fg_index < 512; ++fg_index)
{
// Convert LUT indices back to RGB values with reduced bit depth
bg.r = (bg_index >> 6) << 5;
bg.g = ((bg_index >> 3) & 0x07) << 5;
bg.b = (bg_index & 0x07) << 5;

fg.r = (fg_index >> 6) << 5;
fg.g = ((fg_index >> 3) & 0x07) << 5;
fg.b = (fg_index & 0x07) << 5;

// Additive blending calculation
retAdd.r = MIN(bg.r + fg.r, 0xFFU);
retAdd.g = MIN(bg.g + fg.g, 0xFFU);
retAdd.b = MIN(bg.b + fg.b, 0xFFU);
blendAddLUT[bg_index][fg_index] = retAdd.i;

// Overlay blending calculation
retOver.r = (overlay_alpha * fg.r + (0xFFU - overlay_alpha) * bg.r) >> 8;
retOver.g = (overlay_alpha * fg.g + (0xFFU - overlay_alpha) * bg.g) >> 8;
retOver.b = (overlay_alpha * fg.b + (0xFFU - overlay_alpha) * bg.b) >> 8;
blendOverLUT[bg_index][fg_index] = retOver.i;

// Overlay "alt" blending calculation
retOver.r = (overlay_alt_alpha * fg.r + (0xFFU - overlay_alt_alpha) * bg.r) >> 8;
fabiangreffrath marked this conversation as resolved.
Show resolved Hide resolved
retOver.g = (overlay_alt_alpha * fg.g + (0xFFU - overlay_alt_alpha) * bg.g) >> 8;
retOver.b = (overlay_alt_alpha * fg.b + (0xFFU - overlay_alt_alpha) * bg.b) >> 8;
blendOverAltLUT[bg_index][fg_index] = retAdd.i;
fabiangreffrath marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

// [JN] Helper function to convert a pixel color to a LUT index
static inline uint16_t PixelToLUTIndex (const tcpixel_t color)
{
return ((color.r & 0xE0) << 1) | ((color.g & 0xE0) >> 2) | (color.b >> 5);
}

const uint32_t I_BlendAdd (const uint32_t bg_i, const uint32_t fg_i)
{
tcpixel_t bg, fg, ret;
Expand All @@ -52,6 +146,20 @@ const uint32_t I_BlendAdd (const uint32_t bg_i, const uint32_t fg_i)
return ret.i;
}

const uint32_t I_BlendAddLow (const uint32_t bg_i, const uint32_t fg_i)
{
tcpixel_t bg, fg;
uint16_t bg_index, fg_index;

bg.i = bg_i;
fg.i = fg_i;

bg_index = PixelToLUTIndex(bg);
fg_index = PixelToLUTIndex(fg);

return blendAddLUT[bg_index][fg_index];
}

const uint32_t I_BlendDark (const uint32_t bg_i, const int d)
{
tcpixel_t bg, ret;
Expand Down Expand Up @@ -81,34 +189,79 @@ const uint32_t I_BlendOver (const uint32_t bg_i, const uint32_t fg_i, const int
return ret.i;
}

const uint32_t I_BlendOverLow (const uint32_t bg_i, const uint32_t fg_i, const int amount)
{
tcpixel_t bg, fg;
uint16_t bg_index, fg_index;

bg.i = bg_i;
fg.i = fg_i;

bg_index = PixelToLUTIndex(bg);
fg_index = PixelToLUTIndex(fg);

return blendOverLUT[bg_index][fg_index];
}

const uint32_t I_BlendOverAltLow (const uint32_t bg_i, const uint32_t fg_i, const int amount)
{
tcpixel_t bg, fg;
uint16_t bg_index, fg_index;

bg.i = bg_i;
fg.i = fg_i;

bg_index = PixelToLUTIndex(bg);
fg_index = PixelToLUTIndex(fg);

return blendOverAltLUT[bg_index][fg_index];
}

// [crispy] TRANMAP blending emulation, used for Doom
const uint32_t I_BlendOverTranmap (const uint32_t bg, const uint32_t fg)
{
return I_BlendOver(bg, fg, 0xA8); // 168 (66% opacity)
return I_BlendOverFunc(bg, fg, OVERLAY_ALPHA_TRANMAP);
}

// [crispy] TINTTAB blending emulation, used for Heretic and Hexen
const uint32_t I_BlendOverTinttab (const uint32_t bg, const uint32_t fg)
{
return I_BlendOver(bg, fg, 0x60); // 96 (38% opacity)
return I_BlendOverFunc(bg, fg, OVERLAY_ALPHA_TINTTAB);
}

// [crispy] More opaque ("Alt") TINTTAB blending emulation, used for Hexen's MF_ALTSHADOW drawing
const uint32_t I_BlendOverAltTinttab (const uint32_t bg, const uint32_t fg)
{
return I_BlendOver(bg, fg, 0x8E); // 142 (56% opacity)
return I_BlendOverAltFunc(bg, fg, OVERLAY_ALPHA_TINTTABALT);
}

// [crispy] More opaque XLATAB blending emulation, used for Strife
const uint32_t I_BlendOverXlatab (const uint32_t bg, const uint32_t fg)
{
return I_BlendOver(bg, fg, 0xC0); // 192 (75% opacity)
return I_BlendOverFunc(bg, fg, OVERLAY_ALPHA_XLATAB);
}

// [crispy] Less opaque ("Alt") XLATAB blending emulation, used for Strife
const uint32_t I_BlendOverAltXlatab (const uint32_t bg, const uint32_t fg)
{
return I_BlendOver(bg, fg, 0x40); // 64 (25% opacity)
return I_BlendOverAltFunc(bg, fg, OVERLAY_ALPHA_XLATABALT);
}

// [JN] Set pointers to blending functions.
void R_InitBlendQuality (void)
{
if (crispy->truecolorblend)
{
I_BlendAddFunc = I_BlendAdd;
I_BlendOverFunc = I_BlendOver;
I_BlendOverAltFunc = I_BlendOver;
}
else
{
I_BlendAddFunc = I_BlendAddLow;
I_BlendOverFunc = I_BlendOverLow;
I_BlendOverAltFunc = I_BlendOverAltLow;
}
}

#endif
6 changes: 6 additions & 0 deletions src/i_truecolor.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@
#ifdef CRISPY_TRUECOLOR

#include <stdint.h>
#include "d_mode.h" // GameMission_t

extern const uint32_t (*blendfunc) (const uint32_t fg, const uint32_t bg);

extern void R_InitBlendMaps (GameMission_t mission);
extern void R_InitBlendQuality (void);
extern const uint32_t (*I_BlendAddFunc) (const uint32_t bg_i, const uint32_t fg_i);
extern const uint32_t (*I_BlendOverFunc) (const uint32_t bg_i, const uint32_t fg_i, const int amount);

const uint32_t I_BlendAdd (const uint32_t bg_i, const uint32_t fg_i);
const uint32_t I_BlendDark (const uint32_t bg_i, const int d);
const uint32_t I_BlendOver (const uint32_t bg_i, const uint32_t fg_i, const int amount);
Expand Down
8 changes: 8 additions & 0 deletions src/m_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2606,6 +2606,14 @@ static default_t extra_defaults_list[] =
//

CONFIG_VARIABLE_INT(crispy_truecolor),

//!
// @game doom heretic hexen strife
//
// Quality of translucency in true-color rendering.
//

CONFIG_VARIABLE_INT(crispy_truecolorblend),
#endif

//!
Expand Down
1 change: 1 addition & 0 deletions src/setup/compatibility.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ void BindCompatibilityVariables(void)
M_BindIntVariable("crispy_translucency", &crispy->translucency);
#ifdef CRISPY_TRUECOLOR
M_BindIntVariable("crispy_truecolor", &crispy->truecolor);
M_BindIntVariable("crispy_truecolorblend", &crispy->truecolorblend);
#endif
M_BindIntVariable("crispy_uncapped", &crispy->uncapped);
M_BindIntVariable("crispy_vsync", &crispy->vsync);
Expand Down
1 change: 1 addition & 0 deletions src/strife/d_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ void D_BindVariables(void)
M_BindIntVariable("crispy_soundmono", &crispy->soundmono);
#ifdef CRISPY_TRUECOLOR
M_BindIntVariable("crispy_truecolor", &crispy->truecolor);
M_BindIntVariable("crispy_truecolorblend", &crispy->truecolorblend);
#endif
M_BindIntVariable("crispy_uncapped", &crispy->uncapped);
M_BindIntVariable("crispy_vsync", &crispy->vsync);
Expand Down
7 changes: 7 additions & 0 deletions src/strife/r_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,13 @@ void R_InitData (void)
// R_InitColormaps ();
// [crispy] Initialize color translation and color string tables.
R_InitHSVColors ();
#ifdef CRISPY_TRUECOLOR
// [crispy] Initialize blending maps for tablified overlay
// translucency (normal and "alt"), used by TrueColor renderer.
R_InitBlendMaps(strife);
// [crispy] Set pointers to blending functions.
R_InitBlendQuality();
#endif
}


Expand Down
Loading