diff --git a/src/common/utility/palette.cpp b/src/common/utility/palette.cpp index 5518b7235..0e4b67d4a 100644 --- a/src/common/utility/palette.cpp +++ b/src/common/utility/palette.cpp @@ -39,6 +39,7 @@ #include "files.h" #include "filesystem.h" #include "printf.h" +#include "templates.h" /****************************/ /* Palette management stuff */ @@ -694,3 +695,130 @@ int V_GetColor(const uint32_t* palette, FScanner& sc) return V_GetColor(palette, sc.String, &scc); } +//========================================================================== +// +// Special colormaps +// +//========================================================================== + + +TArray SpecialColormaps; + +// These default tables are needed for texture composition. +static FSpecialColormapParameters SpecialColormapParms[] = +{ + // Doom invulnerability is an inverted grayscale. + // Strife uses it when firing the Sigil + { { 1, 1, 1 }, { 0, 0, 0 } }, + + // Heretic invulnerability is a golden shade. + { { 0, 0, 0 }, { 1.5, 0.75, 0 }, }, + + // [BC] Build the Doomsphere colormap. It is red! + { { 0, 0, 0 }, { 1.5, 0, 0 } }, + + // [BC] Build the Guardsphere colormap. It's a greenish-white kind of thing. + { { 0, 0, 0 }, { 1.25, 1.5, 1 } }, + + // Build a blue colormap. + { { 0, 0, 0 }, { 0, 0, 1.5 } }, + + // Repeated to get around the overridability of the other one + { { 1, 1, 1 }, { 0, 0, 0 } }, + +}; + +//========================================================================== +// +// +// +//========================================================================== + +void UpdateSpecialColormap(PalEntry* BaseColors, unsigned int index, float r1, float g1, float b1, float r2, float g2, float b2) +{ + assert(index < SpecialColormaps.Size()); + + FSpecialColormap* cm = &SpecialColormaps[index]; + cm->ColorizeStart[0] = float(r1); + cm->ColorizeStart[1] = float(g1); + cm->ColorizeStart[2] = float(b1); + cm->ColorizeEnd[0] = float(r2); + cm->ColorizeEnd[1] = float(g2); + cm->ColorizeEnd[2] = float(b2); + + r2 -= r1; + g2 -= g1; + b2 -= b1; + r1 *= 255; + g1 *= 255; + b1 *= 255; + + if (BaseColors) // only create this table if needed + { + for (int c = 0; c < 256; c++) + { + double intensity = (BaseColors[c].r * 77 + + BaseColors[c].g * 143 + + BaseColors[c].b * 37) / 256.0; + + PalEntry pe = PalEntry(std::min(255, int(r1 + intensity * r2)), + std::min(255, int(g1 + intensity * g2)), + std::min(255, int(b1 + intensity * b2))); + + cm->Colormap[c] = BestColor((uint32_t*)BaseColors, pe.r, pe.g, pe.b); + } + } + + // This table is used by the texture composition code + for (int i = 0; i < 256; i++) + { + cm->GrayscaleToColor[i] = PalEntry(std::min(255, int(r1 + i * r2)), + std::min(255, int(g1 + i * g2)), + std::min(255, int(b1 + i * b2))); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +int AddSpecialColormap(PalEntry *BaseColors, float r1, float g1, float b1, float r2, float g2, float b2) +{ + // Clamp these in range for the hardware shader. + r1 = clamp(r1, 0.0f, 2.0f); + g1 = clamp(g1, 0.0f, 2.0f); + b1 = clamp(b1, 0.0f, 2.0f); + r2 = clamp(r2, 0.0f, 2.0f); + g2 = clamp(g2, 0.0f, 2.0f); + b2 = clamp(b2, 0.0f, 2.0f); + + for (unsigned i = 1; i < SpecialColormaps.Size(); i++) + { + // Avoid precision issues here when trying to find a proper match. + if (fabs(SpecialColormaps[i].ColorizeStart[0] - r1) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeStart[1] - g1) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeStart[2] - b1) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeEnd[0] - r2) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeEnd[1] - g2) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeEnd[2] - b2) < FLT_EPSILON) + { + return i; // The map already exists + } + } + + UpdateSpecialColormap(BaseColors, SpecialColormaps.Reserve(1), r1, g1, b1, r2, g2, b2); + return SpecialColormaps.Size() - 1; +} + +void InitSpecialColormaps(PalEntry *pe) +{ + for (unsigned i = 0; i < countof(SpecialColormapParms); ++i) + { + AddSpecialColormap(pe, SpecialColormapParms[i].Start[0], SpecialColormapParms[i].Start[1], + SpecialColormapParms[i].Start[2], SpecialColormapParms[i].End[0], + SpecialColormapParms[i].End[1], SpecialColormapParms[i].End[2]); + } +} + diff --git a/src/common/utility/palutil.h b/src/common/utility/palutil.h index 089f53526..84e0f7d78 100644 --- a/src/common/utility/palutil.h +++ b/src/common/utility/palutil.h @@ -29,3 +29,33 @@ FString V_GetColorStringByName(const char* name, FScriptPosition* sc = nullptr); // Tries to get color by name, then by string int V_GetColor(const uint32_t* palette, const char* str, FScriptPosition* sc = nullptr); int V_GetColor(const uint32_t* palette, FScanner& sc); + +enum +{ + NOFIXEDCOLORMAP = -1, + INVERSECOLORMAP, // the inverse map is used explicitly in a few places. + GOLDCOLORMAP, + REDCOLORMAP, + GREENCOLORMAP, + BLUECOLORMAP, + REALINVERSECOLORMAP, +}; + +struct FSpecialColormapParameters +{ + float Start[3], End[3]; +}; + +struct FSpecialColormap +{ + float ColorizeStart[3]; + float ColorizeEnd[3]; + uint8_t Colormap[256]; + PalEntry GrayscaleToColor[256]; +}; + +extern TArray SpecialColormaps; + +int AddSpecialColormap(PalEntry *pe, float r1, float g1, float b1, float r2, float g2, float b2); +void InitSpecialColormaps(PalEntry* pe); +void UpdateSpecialColormap(PalEntry* BaseColors, unsigned int index, float r1, float g1, float b1, float r2, float g2, float b2); diff --git a/src/gamedata/textures/bitmap.cpp b/src/gamedata/textures/bitmap.cpp index 37579a8f7..2e9a32883 100644 --- a/src/gamedata/textures/bitmap.cpp +++ b/src/gamedata/textures/bitmap.cpp @@ -33,9 +33,27 @@ */ #include "bitmap.h" -#include "r_data/r_translate.h" -#include "r_data/colormaps.h" +#include "palutil.h" +uint8_t IcePalette[16][3] = +{ + { 10, 8, 18 }, + { 15, 15, 26 }, + { 20, 16, 36 }, + { 30, 26, 46 }, + { 40, 36, 57 }, + { 50, 46, 67 }, + { 59, 57, 78 }, + { 69, 67, 88 }, + { 79, 77, 99 }, + { 89, 87,109 }, + { 99, 97,120 }, + { 109,107,130 }, + { 118,118,141 }, + { 128,128,151 }, + { 138,138,162 }, + { 148,148,172 } +}; //=========================================================================== // diff --git a/src/gamedata/textures/multipatchtexturebuilder.cpp b/src/gamedata/textures/multipatchtexturebuilder.cpp index da71656c8..33017eb59 100644 --- a/src/gamedata/textures/multipatchtexturebuilder.cpp +++ b/src/gamedata/textures/multipatchtexturebuilder.cpp @@ -474,13 +474,13 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar if (part.Translation != NULL) delete part.Translation; part.Translation = NULL; part.Blend = 0; - static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL }; + static const char *maps[] = { "gold", "red", "green", "blue", "inverse", NULL }; sc.MustGetString(); match = sc.MatchString(maps); if (match >= 0) { - part.Blend = BLEND_SPECIALCOLORMAP1 + match; + part.Blend = BLEND_SPECIALCOLORMAP1 + match + 1; } else if (sc.Compare("ICE")) { @@ -528,7 +528,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar b1 = (float)sc.Float; if (!sc.CheckString(",")) { - part.Blend = AddSpecialColormap(0, 0, 0, r1, g1, b1); + part.Blend = AddSpecialColormap(GPalette.BaseColors, 0, 0, 0, r1, g1, b1); } else { @@ -540,7 +540,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar sc.MustGetStringName(","); sc.MustGetFloat(); b2 = (float)sc.Float; - part.Blend = AddSpecialColormap(r1, g1, b1, r2, g2, b2); + part.Blend = AddSpecialColormap(GPalette.BaseColors, r1, g1, b1, r2, g2, b2); } } else if (sc.Compare("Blend")) diff --git a/src/r_data/colormaps.cpp b/src/r_data/colormaps.cpp index 65f1b8e32..ece9245fa 100644 --- a/src/r_data/colormaps.cpp +++ b/src/r_data/colormaps.cpp @@ -62,114 +62,13 @@ CUSTOM_CVAR(Color, cl_custominvulmapcolor2, 0xa6a67a, CVAR_ARCHIVE|CVAR_NOINITCA TArray fakecmaps; -TArray SpecialColormaps; uint8_t DesaturateColormap[31][256]; -struct FSpecialColormapParameters -{ - float Start[3], End[3]; -}; - -static FSpecialColormapParameters SpecialColormapParms[] = -{ - // Doom invulnerability is an inverted grayscale. - // Strife uses it when firing the Sigil - { { 1, 1, 1 }, { 0, 0, 0 } }, - - // Heretic invulnerability is a golden shade. - { { 0, 0, 0 }, { 1.5, 0.75, 0 }, }, - - // [BC] Build the Doomsphere colormap. It is red! - { { 0, 0, 0 }, { 1.5, 0, 0 } }, - - // [BC] Build the Guardsphere colormap. It's a greenish-white kind of thing. - { { 0, 0, 0 }, { 1.25, 1.5, 1 } }, - - // Build a blue colormap. - { { 0, 0, 0 }, { 0, 0, 1.5 } }, -}; static void FreeSpecialLights(); -//========================================================================== -// -// -// -//========================================================================== - -static void UpdateSpecialColormap(unsigned int index, float r1, float g1, float b1, float r2, float g2, float b2); - -int AddSpecialColormap(float r1, float g1, float b1, float r2, float g2, float b2) -{ - // Clamp these in range for the hardware shader. - r1 = clamp(r1, 0.0f, 2.0f); - g1 = clamp(g1, 0.0f, 2.0f); - b1 = clamp(b1, 0.0f, 2.0f); - r2 = clamp(r2, 0.0f, 2.0f); - g2 = clamp(g2, 0.0f, 2.0f); - b2 = clamp(b2, 0.0f, 2.0f); - - for(unsigned i=0; iColorizeStart[0] = float(r1); - cm->ColorizeStart[1] = float(g1); - cm->ColorizeStart[2] = float(b1); - cm->ColorizeEnd[0] = float(r2); - cm->ColorizeEnd[1] = float(g2); - cm->ColorizeEnd[2] = float(b2); - - r2 -= r1; - g2 -= g1; - b2 -= b1; - r1 *= 255; - g1 *= 255; - b1 *= 255; - - for (int c = 0; c < 256; c++) - { - double intensity = (GPalette.BaseColors[c].r * 77 + - GPalette.BaseColors[c].g * 143 + - GPalette.BaseColors[c].b * 37) / 256.0; - - PalEntry pe = PalEntry( MIN(255, int(r1 + intensity*r2)), - MIN(255, int(g1 + intensity*g2)), - MIN(255, int(b1 + intensity*b2))); - - cm->Colormap[c] = ColorMatcher.Pick(pe); - } - - // This table is used by the texture composition code - for(int i = 0;i < 256; i++) - { - cm->GrayscaleToColor[i] = PalEntry( MIN(255, int(r1 + i*r2)), - MIN(255, int(g1 + i*g2)), - MIN(255, int(b1 + i*b2))); - } -} - //========================================================================== // // R_DeinitColormaps @@ -267,13 +166,9 @@ void R_InitColormaps (bool allowCustomColormap) } // build default special maps (e.g. invulnerability) + InitSpecialColormaps(GPalette.BaseColors); + R_UpdateInvulnerabilityColormap(); - for (unsigned i = 0; i < countof(SpecialColormapParms); ++i) - { - AddSpecialColormap(SpecialColormapParms[i].Start[0], SpecialColormapParms[i].Start[1], - SpecialColormapParms[i].Start[2], SpecialColormapParms[i].End[0], - SpecialColormapParms[i].End[1], SpecialColormapParms[i].End[2]); - } // desaturated colormaps. These are used for texture composition for(int m = 0; m < 31; m++) { @@ -339,32 +234,24 @@ uint32_t R_BlendForColormap (uint32_t map) void R_UpdateInvulnerabilityColormap() { - float r1, g1, b1, r2, g2, b2; - // some of us really don't like Doom's idea of an invulnerability sphere colormap // this hack will override that if (cl_customizeinvulmap) { uint32_t color1 = cl_custominvulmapcolor1; uint32_t color2 = cl_custominvulmapcolor2; - r1 = (float)((color1 & 0xff0000) >> 16) / 128.f; - g1 = (float)((color1 & 0x00ff00) >> 8) / 128.f; - b1 = (float)((color1 & 0x0000ff) >> 0) / 128.f; - r2 = (float)((color2 & 0xff0000) >> 16) / 128.f; - g2 = (float)((color2 & 0x00ff00) >> 8) / 128.f; - b2 = (float)((color2 & 0x0000ff) >> 0) / 128.f; + float r1 = (float)((color1 & 0xff0000) >> 16) / 128.f; + float g1 = (float)((color1 & 0x00ff00) >> 8) / 128.f; + float b1 = (float)((color1 & 0x0000ff) >> 0) / 128.f; + float r2 = (float)((color2 & 0xff0000) >> 16) / 128.f; + float g2 = (float)((color2 & 0x00ff00) >> 8) / 128.f; + float b2 = (float)((color2 & 0x0000ff) >> 0) / 128.f; + UpdateSpecialColormap(GPalette.BaseColors, 0, r1, g1, b1, r2, g2, b2); } else { - FSpecialColormapParameters &defaultColors = SpecialColormapParms[0]; - r1 = defaultColors.Start[0]; - g1 = defaultColors.Start[1]; - b1 = defaultColors.Start[2]; - r2 = defaultColors.End[0]; - g2 = defaultColors.End[1]; - b2 = defaultColors.End[2]; + SpecialColormaps[INVERSECOLORMAP] = SpecialColormaps[REALINVERSECOLORMAP]; } - UpdateSpecialColormap(0, r1, g1, b1, r2, g2, b2); } diff --git a/src/r_data/colormaps.h b/src/r_data/colormaps.h index 90927f525..4d7bbd5f4 100644 --- a/src/r_data/colormaps.h +++ b/src/r_data/colormaps.h @@ -97,23 +97,6 @@ struct FColormapStyle float FadeLevel; }; -enum -{ - NOFIXEDCOLORMAP = -1, - INVERSECOLORMAP, // the inverse map is used explicitly in a few places. -}; - - -struct FSpecialColormap -{ - float ColorizeStart[3]; - float ColorizeEnd[3]; - uint8_t Colormap[256]; - PalEntry GrayscaleToColor[256]; -}; - -extern TArray SpecialColormaps; - // some utility functions to store special colormaps in powerup blends #define SPECIALCOLORMAP_MASK 0x00b60000 @@ -123,10 +106,6 @@ inline uint32_t MakeSpecialColormap(int index) return index | SPECIALCOLORMAP_MASK; } -int AddSpecialColormap(float r1, float g1, float b1, float r2, float g2, float b2); - - - extern uint8_t DesaturateColormap[31][256]; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index db74848b2..143e77993 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -271,7 +271,7 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player) int cm = CM_DEFAULT; if (cplayer->extralight == INT_MIN) { - cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP; + cm = CM_FIRSTSPECIALCOLORMAP + REALINVERSECOLORMAP; Viewpoint.extralight = 0; FullbrightFlags = Fullbright; // This does never set stealth vision. diff --git a/src/rendering/swrenderer/scene/r_light.cpp b/src/rendering/swrenderer/scene/r_light.cpp index 2a8fd5c75..dea748350 100644 --- a/src/rendering/swrenderer/scene/r_light.cpp +++ b/src/rendering/swrenderer/scene/r_light.cpp @@ -87,7 +87,7 @@ namespace swrenderer // [RH] Inverse light for shooting the Sigil if (fixedcolormap == nullptr && viewpoint.extralight == INT_MIN) { - fixedcolormap = &SpecialSWColormaps[INVERSECOLORMAP]; + fixedcolormap = &SpecialSWColormaps[REALINVERSECOLORMAP]; viewpoint.extralight = 0; } } diff --git a/src/rendering/swrenderer/things/r_playersprite.cpp b/src/rendering/swrenderer/things/r_playersprite.cpp index 36cf89f19..8ce25cba9 100644 --- a/src/rendering/swrenderer/things/r_playersprite.cpp +++ b/src/rendering/swrenderer/things/r_playersprite.cpp @@ -377,7 +377,7 @@ namespace swrenderer if (visstyle.Invert) { - vis.Light.BaseColormap = &SpecialSWColormaps[INVERSECOLORMAP]; + vis.Light.BaseColormap = &SpecialSWColormaps[REALINVERSECOLORMAP]; vis.Light.ColormapNum = 0; noaccel = true; } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 3eb02d2ca..d6988516d 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1276,7 +1276,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) PROP_FLOAT_PARM(r, 0); PROP_FLOAT_PARM(g, 1); PROP_FLOAT_PARM(b, 2); - BlendColor = MakeSpecialColormap(AddSpecialColormap(0, 0, 0, r, g, b)); + BlendColor = MakeSpecialColormap(AddSpecialColormap(GPalette.BaseColors, 0, 0, 0, r, g, b)); } else if (PROP_PARM_COUNT == 6) { @@ -1286,7 +1286,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) PROP_FLOAT_PARM(r2, 3); PROP_FLOAT_PARM(g2, 4); PROP_FLOAT_PARM(b2, 5); - BlendColor = MakeSpecialColormap(AddSpecialColormap(r1, g1, b1, r2, g2, b2)); + BlendColor = MakeSpecialColormap(AddSpecialColormap(GPalette.BaseColors, r1, g1, b1, r2, g2, b2)); } else {