* Made it possible to perform palette calculations in gamma-corrected space. Now used by:

* Blend tables generated by the game.
    * The Color Cube accessibility tool.
* Fixed another stupid typo that got in the way of FF_BLENDMASK working.
* Some minor adjustments for code cleanliness.
This commit is contained in:
toaster 2021-04-01 19:28:01 +01:00
parent 8b63908820
commit e27506c660
6 changed files with 70 additions and 66 deletions

View file

@ -418,7 +418,7 @@ static void md2_loadTexture(md2_t *model)
size = w*h; size = w*h;
while (size--) while (size--)
{ {
V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); V_CubeApply(image);
image++; image++;
} }
} }

View file

@ -50,11 +50,11 @@
/// \brief shift for FF_BLENDMASK /// \brief shift for FF_BLENDMASK
#define FF_BLENDSHIFT 12 #define FF_BLENDSHIFT 12
/// \brief preshifted blend flags minus 1 as effects don't distinguish between AST_COPY and AST_TRANSLUCENT /// \brief preshifted blend flags minus 1 as effects don't distinguish between AST_COPY and AST_TRANSLUCENT
#define FF_ADD ((AST_ADD-1)<<RF_BLENDSHIFT) #define FF_ADD ((AST_ADD-1)<<FF_BLENDSHIFT)
#define FF_SUBTRACT ((AST_SUBTRACT-1)<<RF_BLENDSHIFT) #define FF_SUBTRACT ((AST_SUBTRACT-1)<<FF_BLENDSHIFT)
#define FF_REVERSESUBTRACT ((AST_REVERSESUBTRACT-1)<<RF_BLENDSHIFT) #define FF_REVERSESUBTRACT ((AST_REVERSESUBTRACT-1)<<FF_BLENDSHIFT)
#define FF_MODULATE ((AST_MODULATE-1)<<RF_BLENDSHIFT) #define FF_MODULATE ((AST_MODULATE-1)<<FF_BLENDSHIFT)
#define FF_OVERLAY ((AST_OVERLAY-1)<<RF_BLENDSHIFT) #define FF_OVERLAY ((AST_OVERLAY-1)<<FF_BLENDSHIFT)
/// \brief Frame flags: 0 = no trans(opaque), 1-15 = transl. table /// \brief Frame flags: 0 = no trans(opaque), 1-15 = transl. table
#define FF_TRANSMASK 0xf0000 #define FF_TRANSMASK 0xf0000

View file

@ -206,20 +206,25 @@ void R_GenerateBlendTables(void)
void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt) void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt)
{ {
INT16 bg, fg; INT16 bg, fg;
RGBA_t backrgba, frontrgba, result;
if (table == NULL) if (table == NULL)
I_Error("R_GenerateTranslucencyTable: input table was NULL!"); I_Error("R_GenerateTranslucencyTable: input table was NULL!");
for (bg = 0; bg < 0xFF; bg++) for (bg = 0; bg <= 0xFF; bg++)
{ {
for (fg = 0; fg < 0xFF; fg++) backrgba = pGammaCorrectedPalette[bg];
for (fg = 0; fg <= 0xFF; fg++)
{ {
RGBA_t backrgba = V_GetMasterColor(bg); frontrgba = pGammaCorrectedPalette[fg];
RGBA_t frontrgba = V_GetMasterColor(fg);
RGBA_t result;
result.rgba = ASTBlendPixel(backrgba, frontrgba, style, blendamt); #if 0 // perfect implementation
result.rgba = V_GammaEncode(ASTBlendPixel(backrgba, frontrgba, style, blendamt));
table[((fg * 0x100) + bg)] = NearestPaletteColor(result.s.red, result.s.green, result.s.blue, pMasterPalette); table[((fg * 0x100) + bg)] = NearestPaletteColor(result.s.red, result.s.green, result.s.blue, pMasterPalette);
#else // performance scrabbler
result.rgba = ASTBlendPixel(backrgba, frontrgba, style, blendamt);
table[((fg * 0x100) + bg)] = NearestPaletteColor(result.s.red, result.s.green, result.s.blue, pGammaCorrectedPalette);
#endif
} }
} }
} }

View file

@ -1996,10 +1996,7 @@ static void R_ProjectSprite(mobj_t *thing)
vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1); vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1);
} }
if (blendmode != AST_COPY) vis->transmap = R_GetBlendTable(blendmode, trans);
vis->transmap = R_GetBlendTable(blendmode, trans);
else
vis->transmap = NULL;
if (R_ThingIsSemiBright(oldthing)) if (R_ThingIsSemiBright(oldthing))
vis->cut |= SC_SEMIBRIGHT; vis->cut |= SC_SEMIBRIGHT;

View file

@ -88,6 +88,7 @@ consvar_t cv_constextsize = CVAR_INIT ("con_textsize", "Medium", CV_SAVE|CV_CALL
// local copy of the palette for V_GetColor() // local copy of the palette for V_GetColor()
RGBA_t *pLocalPalette = NULL; RGBA_t *pLocalPalette = NULL;
RGBA_t *pMasterPalette = NULL; RGBA_t *pMasterPalette = NULL;
RGBA_t *pGammaCorrectedPalette = NULL;
/* /*
The following was an extremely helpful resource when developing my Colour Cube LUT. The following was an extremely helpful resource when developing my Colour Cube LUT.
@ -285,33 +286,25 @@ static boolean InitCube(void)
return true; return true;
} }
#ifdef BACKWARDSCOMPATCORRECTION UINT32 V_GammaCorrect(UINT32 input, double power)
/* {
So it turns out that the way gamma was implemented previously, the default RGBA_t result;
colour profile of the game was messed up. Since this bad decision has been double linear;
around for a long time, and the intent is to keep the base game looking the
same, I'm not gonna be the one to remove this base modification. result.rgba = input;
toast 20/04/17
... welp yes i am (27/07/19, see the ifdef around it) linear = ((double)result.s.red)/255.0f;
*/ linear = pow(linear, power)*255.0f;
const UINT8 correctiontable[256] = result.s.red = (UINT8)(linear);
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, linear = ((double)result.s.green)/255.0f;
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, linear = pow(linear, power)*255.0f;
33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, result.s.green = (UINT8)(linear);
49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, linear = ((double)result.s.blue)/255.0f;
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, linear = pow(linear, power)*255.0f;
81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96, result.s.blue = (UINT8)(linear);
97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, return result.rgba;
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, }
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
#endif
// keep a copy of the palette so that we can get the RGB value for a color index at any time. // keep a copy of the palette so that we can get the RGB value for a color index at any time.
static void LoadPalette(const char *lumpname) static void LoadPalette(const char *lumpname)
@ -322,33 +315,37 @@ static void LoadPalette(const char *lumpname)
Cubeapply = InitCube(); Cubeapply = InitCube();
Z_Free(pLocalPalette); if (pLocalPalette != pMasterPalette)
Z_Free(pLocalPalette);
Z_Free(pMasterPalette); Z_Free(pMasterPalette);
Z_Free(pGammaCorrectedPalette);
pLocalPalette = Z_Malloc(sizeof (*pLocalPalette)*palsize, PU_STATIC, NULL);
pMasterPalette = Z_Malloc(sizeof (*pMasterPalette)*palsize, PU_STATIC, NULL); pMasterPalette = Z_Malloc(sizeof (*pMasterPalette)*palsize, PU_STATIC, NULL);
if (Cubeapply)
pLocalPalette = Z_Malloc(sizeof (*pLocalPalette)*palsize, PU_STATIC, NULL);
else
pLocalPalette = pMasterPalette;
pGammaCorrectedPalette = Z_Malloc(sizeof (*pGammaCorrectedPalette)*palsize, PU_STATIC, NULL);
pal = W_CacheLumpNum(lumpnum, PU_CACHE); pal = W_CacheLumpNum(lumpnum, PU_CACHE);
for (i = 0; i < palsize; i++) for (i = 0; i < palsize; i++)
{ {
#ifdef BACKWARDSCOMPATCORRECTION pMasterPalette[i].s.red = *pal++;
pMasterPalette[i].s.red = pLocalPalette[i].s.red = correctiontable[*pal++]; pMasterPalette[i].s.green = *pal++;
pMasterPalette[i].s.green = pLocalPalette[i].s.green = correctiontable[*pal++]; pMasterPalette[i].s.blue = *pal++;
pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = correctiontable[*pal++]; pMasterPalette[i].s.alpha = 0xFF;
#else
pMasterPalette[i].s.red = pLocalPalette[i].s.red = *pal++;
pMasterPalette[i].s.green = pLocalPalette[i].s.green = *pal++;
pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = *pal++;
#endif
pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF;
// lerp of colour cubing! if you want, make it smoother yourself pGammaCorrectedPalette[i].rgba = V_GammaDecode(pMasterPalette[i].rgba);
if (Cubeapply)
V_CubeApply(&pLocalPalette[i].s.red, &pLocalPalette[i].s.green, &pLocalPalette[i].s.blue); if (!Cubeapply)
continue;
V_CubeApply(&pGammaCorrectedPalette[i]);
pLocalPalette[i].rgba = V_GammaEncode(pGammaCorrectedPalette[i].rgba);
} }
} }
void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue) void V_CubeApply(RGBA_t *input)
{ {
float working[4][3]; float working[4][3];
float linear; float linear;
@ -357,7 +354,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue)
if (!Cubeapply) if (!Cubeapply)
return; return;
linear = (*red/255.0); linear = ((*input).s.red/255.0);
#define dolerp(e1, e2) ((1 - linear)*e1 + linear*e2) #define dolerp(e1, e2) ((1 - linear)*e1 + linear*e2)
for (q = 0; q < 3; q++) for (q = 0; q < 3; q++)
{ {
@ -366,13 +363,13 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue)
working[2][q] = dolerp(Cubepal[0][0][1][q], Cubepal[1][0][1][q]); working[2][q] = dolerp(Cubepal[0][0][1][q], Cubepal[1][0][1][q]);
working[3][q] = dolerp(Cubepal[0][1][1][q], Cubepal[1][1][1][q]); working[3][q] = dolerp(Cubepal[0][1][1][q], Cubepal[1][1][1][q]);
} }
linear = (*green/255.0); linear = ((*input).s.green/255.0);
for (q = 0; q < 3; q++) for (q = 0; q < 3; q++)
{ {
working[0][q] = dolerp(working[0][q], working[1][q]); working[0][q] = dolerp(working[0][q], working[1][q]);
working[1][q] = dolerp(working[2][q], working[3][q]); working[1][q] = dolerp(working[2][q], working[3][q]);
} }
linear = (*blue/255.0); linear = ((*input).s.blue/255.0);
for (q = 0; q < 3; q++) for (q = 0; q < 3; q++)
{ {
working[0][q] = 255*dolerp(working[0][q], working[1][q]); working[0][q] = 255*dolerp(working[0][q], working[1][q]);
@ -383,9 +380,9 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue)
} }
#undef dolerp #undef dolerp
*red = (UINT8)(working[0][0]); (*input).s.red = (UINT8)(working[0][0]);
*green = (UINT8)(working[0][1]); (*input).s.green = (UINT8)(working[0][1]);
*blue = (UINT8)(working[0][2]); (*input).s.blue = (UINT8)(working[0][2]);
} }
const char *R_GetPalname(UINT16 num) const char *R_GetPalname(UINT16 num)

View file

@ -66,8 +66,13 @@ const char *GetPalette(void);
extern RGBA_t *pLocalPalette; extern RGBA_t *pLocalPalette;
extern RGBA_t *pMasterPalette; extern RGBA_t *pMasterPalette;
extern RGBA_t *pGammaCorrectedPalette;
void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue); UINT32 V_GammaCorrect(UINT32 input, double power);
#define V_GammaDecode(input) V_GammaCorrect(input, 2.2f)
#define V_GammaEncode(input) V_GammaCorrect(input, (1/2.2f))
void V_CubeApply(RGBA_t *input);
// Retrieve the ARGB value from a palette color index // Retrieve the ARGB value from a palette color index
#define V_GetColor(color) (pLocalPalette[color&0xFF]) #define V_GetColor(color) (pLocalPalette[color&0xFF])