fabiangreffrath / crispy-doom

Crispy Doom is a limit-removing enhanced-resolution Doom source port based on Chocolate Doom.
https://fabiangreffrath.github.io/crispy-homepage
GNU General Public License v2.0
807 stars 132 forks source link

Hexen: add true color support #1145

Closed JNechaevsky closed 10 months ago

JNechaevsky commented 10 months ago

Almost a carbon copy of Doom and Heretic code with few exceptions. At the moment of writing this PR, all rendering initials and nominals should be formed, and despite of massive changes this is an easy part. Hard part is:

JNechaevsky commented 10 months ago

Looks like we're on our own with Hexen palettes. I can't properly read Slade's approach for color blending, and we need just two magical RGB+alpha variables, not whole blending formula.

It's not that hard to replicate GZDoom approach, like by using substruction of extra palette idexes's zero color from original zero index one. But... Such approach is not really looks like vanilla, let's have a look:

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/d7c5ec54-554b-4703-8ab6-b01b86796a51)

And what I have achieved. Left part of the screenshot is paletted render, right is true color. There is barely notable dark line, so click to enlarge.

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/c980f449-3ceb-4a20-b432-3e5353533ff2)

Not sure if I can get 100% identical to vanilla colors, but at least I can do my best to replicate them as close as possible.

kitchen-ace commented 10 months ago

Looks like we're on our own with Hexen palettes.

I don't know if it helps but doomwiki describes the additional Hexen palettes:

https://doomwiki.org/wiki/PLAYPAL#Hexen

JNechaevsky commented 10 months ago

🥲... It will help a lot, thank you! I was using slightly different technique by picking tinted color from 14-27 palette's 0 (black) color and then spent hours by fine-tuning values and comparing to paletted render. According to the article, Wraithverge and Bloodscourge using different colors for every palette which is not good to keep things clear here, as we need exactly one pane for such colors, alpha value will do the rest, but ice and notably poison must get another revision.

kitchen-ace commented 10 months ago

It will help a lot, thank you! I was using slightly different technique by picking tinted color from 14-27 palette's 0 (black) color and then spent hours by fine-tuning values and comparing to paletted render.

Agh, sorry I couldn't reply earlier!

JNechaevsky commented 10 months ago

Small experiment with emulating FOGMAP in true color. It's slightly different from original table, but at least gives more or less decent colors.

Before:

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/357cc5b6-f2dd-43fa-bba4-23915f2dcbb2)

And after:

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/c4ac1e9f-f900-44f2-b5ca-68e2f08e524b)
fabiangreffrath commented 10 months ago

Looks good, much better than expected!

JNechaevsky commented 10 months ago

Thank you! In current implementation it looks like this: image ...while vanilla table is: image

I.e. we have more smooth linear fading. Fortunately, Raven did foggy maps with keeping light levels in mind, so we still have a more or less proper view, except we can see slightly farther. I think it is possible replicate vanilla table more accurately, but it needs some patience for playing with for verctors in colormap generating. Value 147 is not a magic number, it's fading color or original FOGMAP:

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/437ffb6d-9f3b-4a6e-9798-80d0d5e6688c)

Remaining things to do:

P.S. It's a miracle, but vanilla bug with missing first palette in various effects is a godsend here. Should it doesn't happen, we'll Doom rad suit palette (index 13) for lesser poison effect in Hexen! 😱

JNechaevsky commented 10 months ago

"Alt" TINTTAB was easy. Paletted:

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/db4e2781-d3cf-4bef-bb30-c26600650ce6)

And True color:

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/c1929592-1398-4f2d-a644-17a13bcc5a0c)

Before trying to make a final step with finale screen, I need to revisit patch drawing functions, as things gets more complicated. Turns out, we have not 2, but 3 different translucency levels for Raven games. Let's see original code...

🤯 Function Code What does it do
1 V_DrawShadowedPatch *dest2 = tinttable[((*dest2) << 8)]; translucent shadow
2 V_DrawTLPatch *dest = tinttable[*dest + ((*source++) << 8)]; translucent sprite, less opaque
3 V_DrawAltTLPatch *dest = tinttable[((*dest) << 8) + *source++]; translucent sprite, more opaque
fabiangreffrath commented 10 months ago
  • Fading in/out on finale screens. Not sure it is possible to replicate this trick on true color, but we still can use I_BlendDark for such purposes

Yes, you should be able to incrementally fade in/out the finale screens if you draw the fullscreen patch as usual and then brush over each pixel with I_BlendDark() as in your menu shading code. You just need to adjust the second argument passed to I_BlendDark() each time FadePic() is called.

JNechaevsky commented 10 months ago

I've done exactly this way. 🙂 After few hours of experiments, I finally got less diff + possible framerate safe approach. Framerate safe means: we have to rely on finale tics, not to framerate tics, just in case one day framerate becomes uncapped in any states. The result is nearly 1:1 to vanilla, except colors are more smooth while fading. Durations seems to be also almost same, but probably differs just for few frames.

Ah yes, such approach is also safer than vanilla one, since we not touching palette at all.

Here it is, in full quality. Video compression probably will destroy some colors a little bit, so I highly recommend to download video or check it out in the game. https://drive.google.com/file/d/1V2OXl4wHTfnmqVhMx7ZBZOvf5M_m0Kui/view?usp=sharing

fabiangreffrath commented 10 months ago

Looks great, congratulations to this achievement and thank you very much for your work on this!

JNechaevsky commented 10 months ago

It is my highest pleasure to do this! Wish I say "we won!", but I can't, there are two nitpicks remaining:

1) I'm not very satisfied with I_BlendDark calling on finale screens. It is working fine, but such blending is CPU-expensive, especially when covering whole screen area. We are capped at 35 fps there, but it's probably worth to don't be that lavish, i.e. call blending function only while fading is happened. I need to experiment more. 2) When true color is compiled in but disabled as config option, brightest white color becomes screwed up. My first though it was a problem of HSV coloring (not happening in Crispy), but can be notified on finale screens: screenshot 1 and screenshot 2, testing sprite I'm using, replaced Fighter's gloves: white.zip

After farther investigation, I have found that color gets broken on normal maps (screenshot, VISIT01), but not on foggy ones (screenshot, VISIT08). Something wrong must be here, but if colormaps aren't generated on level loading, bright color levels will be screwed up even more (screenshot).

JNechaevsky commented 10 months ago

Looks likes it's not a true color code issue at all, it's a mistake made by Raven Software. Have a look at Hexen's PLAYPAL. See? Last one color (255, bottom-right) is white.

![image](https://github.com/fabiangreffrath/crispy-doom/assets/21193394/023b6aff-3a74-4055-af0b-cadbe1dcb18a)

Now have a look at original COLORMAP. Last one color (most-right) is BLACK! image

And now to FOGMAP, where last one color is proper white: image

That's must be the cause. The only possible way must be to forcefully swap black 255 color with white color somehow. If no check for modified COLORMAP will be performed, it's another "one step back" for true color's compatibility with custom colormaps. But it's already in "few steps back" condition...

JNechaevsky commented 10 months ago

Completely mindless, but do the trick. Even no need to call V_GetPaletteIndex(playpal, 255, 255, 255).

    for (c = 0; c <= NUMCOLORMAPS; c++)
    {
        for (i = 0; i < 256; i++)
        {
            if (i == 255)
            {
            r = 255; g = 255; b = 255;  // [JN] THANKS, COME AGAIN !!!
            }
            else
            {
            r = gamma2table[crispy->gamma][playpal[3 * colormap[c * 256 + i] + 0]] & ~3;
            g = gamma2table[crispy->gamma][playpal[3 * colormap[c * 256 + i] + 1]] & ~3;
            b = gamma2table[crispy->gamma][playpal[3 * colormap[c * 256 + i] + 2]] & ~3;
            }

            colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b;
        }
    }
fabiangreffrath commented 10 months ago

If you want to be a bit "more correct", instead of taking palette value i as base color, take the palette color that colormaps[i] from the COLORMAP lump points to as base color.

fabiangreffrath commented 10 months ago

TODOs left for Doom and Heretic:

fabiangreffrath commented 10 months ago

Possible optimization:

JNechaevsky commented 10 months ago

I have to do a couple of conclusions. Nothing special really, just a few thoughts for the record.

Common

Shoudn't be a real problem, as @kitchen-ace suggested that there no real mods which is using custom colormaps, and I know only one mod at all - Caldera, appeared many years ago in Chocolate tracker. And good thing nowadays we have a different port for such purposes, which is allowing to use RBG values for sector lighting and hardware fog instead of that colormap's ancient technology... Ancient technology which we have to hold dear and handle with care to provide backwards compatibility and vanilla look&feel in general.

f_finale.c

i_video.c