More blend image updates

- Allow the translations that don't make use a blend image to work without requiring a blend image to be present
- Fix TC_RAINBOW not working properly
- TC_METALSONIC now remaps the _blend image to SKINCOLOR_COBALT, then inverts all of the blue, replicating how it works in Software

(cherry picked from commit 74d7f256a7849d0c829177614b37089e2446f86b)
This commit is contained in:
Sally Cochenour 2019-12-29 16:36:53 -05:00
parent 1871d01de6
commit 3191c365de

View file

@ -654,12 +654,12 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
UINT16 w = gpatch->width, h = gpatch->height; UINT16 w = gpatch->width, h = gpatch->height;
UINT32 size = w*h; UINT32 size = w*h;
RGBA_t *image, *blendimage, *cur, blendcolor; RGBA_t *image, *blendimage, *cur, blendcolor;
UINT8 i;
UINT8 translation[16]; // First the color index UINT8 translation[16]; // First the color index
UINT8 cutoff[16]; // Brightness cutoff before using the next color UINT8 cutoff[16]; // Brightness cutoff before using the next color
UINT8 translen = 0; UINT8 translen = 0;
UINT8 i;
blendcolor = V_GetColor(0); // initialize
memset(translation, 0, sizeof(translation)); memset(translation, 0, sizeof(translation));
memset(cutoff, 0, sizeof(cutoff)); memset(cutoff, 0, sizeof(cutoff));
@ -685,7 +685,10 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
image = gpatch->mipmap->grInfo.data; image = gpatch->mipmap->grInfo.data;
blendimage = blendgpatch->mipmap->grInfo.data; blendimage = blendgpatch->mipmap->grInfo.data;
blendcolor = V_GetColor(0); // initialize
// TC_METALSONIC includes an actual skincolor translation, on top of its flashing.
if (skinnum == TC_METALSONIC)
color = SKINCOLOR_COBALT;
if (color != SKINCOLOR_NONE) if (color != SKINCOLOR_NONE)
{ {
@ -721,7 +724,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
if (skinnum == TC_BOSS) if (skinnum == TC_BOSS)
{ {
// Turn everything below a certain threshold white // Turn everything below a certain threshold white
if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue <= 82) if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue < 127)
{ {
// Lactozilla: Invert the colors // Lactozilla: Invert the colors
cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue); cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue);
@ -735,53 +738,6 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
cur->s.alpha = image->s.alpha; cur->s.alpha = image->s.alpha;
} }
else if (skinnum == TC_METALSONIC)
{
// Turn everything below a certain blue threshold white
if (image->s.red == 0 && image->s.green == 0 && image->s.blue <= 82)
{
cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue);
}
else
{
cur->s.red = image->s.red;
cur->s.green = image->s.green;
cur->s.blue = image->s.blue;
}
cur->s.alpha = image->s.alpha;
}
else if (skinnum == TC_DASHMODE)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
}
else
{
UINT8 ialpha = 255 - blendimage->s.alpha, balpha = blendimage->s.alpha;
RGBA_t icolor = *image, bcolor;
memset(&bcolor, 0x00, sizeof(RGBA_t));
if (blendimage->s.alpha)
{
bcolor.s.blue = 0;
bcolor.s.red = 255;
bcolor.s.green = (blendimage->s.red + blendimage->s.green + blendimage->s.blue) / 3;
}
if (image->s.alpha && image->s.red > image->s.green << 1) // this is pretty arbitrary, but it works well for Metal Sonic
{
icolor.s.red = image->s.blue;
icolor.s.blue = image->s.red;
}
cur->s.red = (ialpha * icolor.s.red + balpha * bcolor.s.red)/255;
cur->s.green = (ialpha * icolor.s.green + balpha * bcolor.s.green)/255;
cur->s.blue = (ialpha * icolor.s.blue + balpha * bcolor.s.blue)/255;
cur->s.alpha = image->s.alpha;
}
}
else if (skinnum == TC_ALLWHITE) else if (skinnum == TC_ALLWHITE)
{ {
// Turn everything white // Turn everything white
@ -790,208 +746,268 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
} }
else else
{ {
UINT16 brightness; // Everything below requires a blend image
if (blendimage == NULL)
{
cur->rgba = image->rgba;
goto skippixel;
}
I_Assert(translen > 0); // Metal Sonic dash mode
if (skinnum == TC_DASHMODE)
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
if (skinnum == TC_RAINBOW)
{ {
if (image->s.alpha == 0 && blendimage->s.alpha == 0) if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{ {
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba; cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
} }
else else
{ {
UINT16 imagebright, blendbright; UINT8 ialpha = 255 - blendimage->s.alpha, balpha = blendimage->s.alpha;
SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue); RGBA_t icolor = *image, bcolor;
SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway memset(&bcolor, 0x00, sizeof(RGBA_t));
brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
if (blendimage->s.alpha)
{
bcolor.s.blue = 0;
bcolor.s.red = 255;
bcolor.s.green = (blendimage->s.red + blendimage->s.green + blendimage->s.blue) / 3;
}
if (image->s.alpha && image->s.red > image->s.green << 1) // this is pretty arbitrary, but it works well for Metal Sonic
{
icolor.s.red = image->s.blue;
icolor.s.blue = image->s.red;
}
cur->s.red = (ialpha * icolor.s.red + balpha * bcolor.s.red)/255;
cur->s.green = (ialpha * icolor.s.green + balpha * bcolor.s.green)/255;
cur->s.blue = (ialpha * icolor.s.blue + balpha * bcolor.s.blue)/255;
cur->s.alpha = image->s.alpha;
} }
} }
else else
{ {
if (blendimage->s.alpha == 0) // All settings that use skincolors!
UINT16 brightness;
if (translen <= 0)
{ {
cur->rgba = image->rgba; cur->rgba = image->rgba;
cur++; image++; blendimage++; goto skippixel;
continue; }
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
if (skinnum == TC_RAINBOW)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
cur->rgba = image->rgba;
goto skippixel;
}
else
{
UINT16 imagebright, blendbright;
SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
}
} }
else else
{ {
SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue); if (blendimage->s.alpha == 0)
}
}
// Calculate a sort of "gradient" for the skincolor
// (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...)
{
RGBA_t nextcolor;
UINT8 firsti, secondi, mul, mulmax;
INT32 r, g, b;
// Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors.
// Ensue horrible mess.
if (skinnum == TC_RAINBOW)
{
UINT16 brightdif = 256;
UINT8 colorbrightnesses[16];
INT32 compare, m, d;
// Ignore pure white & pitch black
if (brightness > 253 || brightness < 2)
{ {
cur->rgba = image->rgba; cur->rgba = image->rgba;
cur++; image++; blendimage++; goto skippixel; // for metal sonic blend
continue;
} }
else
firsti = 0;
mul = 0;
mulmax = 1;
for (i = 0; i < translen; i++)
{ {
RGBA_t tempc = V_GetColor(translation[i]); SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
} }
}
for (i = 0; i < translen; i++) // Calculate a sort of "gradient" for the skincolor
// (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...)
{
RGBA_t nextcolor;
UINT8 firsti, secondi, mul, mulmax;
INT32 r, g, b;
// Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors.
// Ensue horrible mess.
if (skinnum == TC_RAINBOW)
{ {
if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is) UINT16 brightdif = 256;
continue; UINT8 colorbrightnesses[16];
INT32 compare, m, d;
compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness)); // Ignore pure white & pitch black
if (brightness > 253 || brightness < 2)
if (compare < brightdif)
{ {
brightdif = (UINT16)compare; cur->rgba = image->rgba;
firsti = i; // best matching color that's equal brightness or darker cur++; image++; blendimage++;
continue;
} }
}
secondi = firsti+1; // next color in line firsti = 0;
if (secondi >= translen)
{
m = (INT16)brightness; // - 0;
d = (INT16)colorbrightnesses[firsti]; // - 0;
}
else
{
m = (INT16)brightness - (INT16)colorbrightnesses[secondi];
d = (INT16)colorbrightnesses[firsti] - (INT16)colorbrightnesses[secondi];
}
if (m >= d)
m = d-1;
// calculate the "gradient" multiplier based on how close this color is to the one next in line
if (m <= 0 || d <= 0)
{
mul = 0; mul = 0;
mulmax = 1;
for (i = 0; i < translen; i++)
{
RGBA_t tempc = V_GetColor(translation[i]);
SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
}
for (i = 0; i < translen; i++)
{
if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is)
continue;
compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness));
if (compare < brightdif)
{
brightdif = (UINT16)compare;
firsti = i; // best matching color that's equal brightness or darker
}
}
secondi = firsti+1; // next color in line
if (secondi >= translen)
{
m = (INT16)brightness; // - 0;
d = (INT16)colorbrightnesses[firsti]; // - 0;
}
else
{
m = (INT16)brightness - (INT16)colorbrightnesses[secondi];
d = (INT16)colorbrightnesses[firsti] - (INT16)colorbrightnesses[secondi];
}
if (m >= d)
m = d-1;
mulmax = 16;
// calculate the "gradient" multiplier based on how close this color is to the one next in line
if (m <= 0 || d <= 0)
mul = 0;
else
mul = (mulmax-1) - ((m * mulmax) / d);
} }
else else
{ {
// Just convert brightness to a skincolor value, use distance to next position to find the gradient multipler
firsti = 0;
for (i = 1; i < translen; i++)
{
if (brightness >= cutoff[i])
break;
firsti = i;
}
secondi = firsti+1;
mulmax = cutoff[firsti]; mulmax = cutoff[firsti];
if (secondi < translen) if (secondi < translen)
mulmax -= cutoff[secondi]; mulmax -= cutoff[secondi];
mul = (mulmax-1) - ((m * mulmax) / d); mul = cutoff[firsti] - brightness;
} }
blendcolor = V_GetColor(translation[firsti]);
if (mul > 0) // If it's 0, then we only need the first color.
{
if (secondi >= translen) // blend to black
nextcolor = V_GetColor(31);
else
nextcolor = V_GetColor(translation[secondi]);
// Find difference between points
r = (INT32)(nextcolor.s.red - blendcolor.s.red);
g = (INT32)(nextcolor.s.green - blendcolor.s.green);
b = (INT32)(nextcolor.s.blue - blendcolor.s.blue);
// Find the gradient of the two points
r = ((mul * r) / mulmax);
g = ((mul * g) / mulmax);
b = ((mul * b) / mulmax);
// Add gradient value to color
blendcolor.s.red += r;
blendcolor.s.green += g;
blendcolor.s.blue += b;
}
}
if (skinnum == TC_RAINBOW)
{
UINT32 tempcolor;
UINT16 colorbright;
SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
if (colorbright == 0)
colorbright = 1; // no dividing by 0 please
tempcolor = (brightness * blendcolor.s.red) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = (brightness * blendcolor.s.green) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = (brightness * blendcolor.s.blue) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
} }
else else
{ {
// Just convert brightness to a skincolor value, use distance to next position to find the gradient multipler // Color strength depends on image alpha
firsti = 0; INT32 tempcolor;
for (i = 1; i < translen; i++) tempcolor = ((image->s.red * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.red * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = ((image->s.green * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.green * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = ((image->s.blue * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.blue * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
skippixel:
// *Now* we can do Metal Sonic's flashing
if (skinnum == TC_METALSONIC)
{
// Blend dark blue into white
if (cur->s.alpha > 0 && cur->s.red == 0 && cur->s.green == 0 && cur->s.blue < 255 && cur->s.blue > 31)
{ {
if (brightness >= cutoff[i]) // Sal: Invert non-blue
break; cur->s.red = cur->s.green = (255 - cur->s.blue);
firsti = i; cur->s.blue = 255;
} }
secondi = firsti+1; cur->s.alpha = image->s.alpha;
mulmax = cutoff[firsti];
if (secondi < translen)
mulmax -= cutoff[secondi];
mul = cutoff[firsti] - brightness;
} }
blendcolor = V_GetColor(translation[firsti]);
if (mul > 0) // If it's 0, then we only need the first color.
{
if (secondi >= translen) // blend to black
nextcolor = V_GetColor(31);
else
nextcolor = V_GetColor(translation[secondi]);
// Find difference between points
r = (INT32)(nextcolor.s.red - blendcolor.s.red);
g = (INT32)(nextcolor.s.green - blendcolor.s.green);
b = (INT32)(nextcolor.s.blue - blendcolor.s.blue);
// Find the gradient of the two points
r = ((mul * r) / mulmax);
g = ((mul * g) / mulmax);
b = ((mul * b) / mulmax);
// Add gradient value to color
blendcolor.s.red += r;
blendcolor.s.green += g;
blendcolor.s.blue += b;
}
}
if (skinnum == TC_RAINBOW)
{
UINT32 tempcolor;
UINT16 colorbright;
SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
if (colorbright == 0)
colorbright = 1; // no dividing by 0 please
tempcolor = (brightness * blendcolor.s.red) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = (brightness * blendcolor.s.green) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = (brightness * blendcolor.s.blue) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
else
{
// Color strength depends on image alpha
INT32 tempcolor;
tempcolor = ((image->s.red * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.red * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = ((image->s.green * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.green * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = ((image->s.blue * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.blue * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
} }
} }
cur++; image++; blendimage++; cur++; image++;
if (blendimage != NULL)
blendimage++;
} }
return; return;
@ -1030,6 +1046,14 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
// If here, the blended texture has not been created // If here, the blended texture has not been created
// So we create it // So we create it
if ((blendgpatch && blendgpatch->mipmap->grInfo.format)
&& (gpatch->width != blendgpatch->width || gpatch->height != blendgpatch->height))
{
// Blend image exists, but it's bad.
HWD.pfnSetTexture(gpatch->mipmap);
return;
}
//BP: WARNING: don't free it manually without clearing the cache of harware renderer //BP: WARNING: don't free it manually without clearing the cache of harware renderer
// (it have a liste of mipmap) // (it have a liste of mipmap)
// this malloc is cleared in HWR_FreeTextureCache // this malloc is cleared in HWR_FreeTextureCache
@ -1273,50 +1297,44 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
if (gpatch && gpatch->mipmap->grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture if (gpatch && gpatch->mipmap->grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
{ {
if (md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format INT32 skinnum = INT32_MAX;
&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
{
INT32 skinnum = INT32_MAX;
if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized)
skinnum = TC_ALLWHITE;
else if (spr->mobj->type == MT_METALSONIC_BATTLE)
skinnum = TC_METALSONIC;
else
skinnum = TC_BOSS;
}
else if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE)
{
if (spr->mobj->colorized)
skinnum = TC_RAINBOW;
else if (spr->mobj->player && spr->mobj->player->dashmode >= DASHMODE_THRESHOLD
&& (spr->mobj->player->charflags & SF_DASHMODE)
&& ((leveltime/2) & 1))
{
if (spr->mobj->player->charflags & SF_MACHINE)
skinnum = TC_DASHMODE;
else
skinnum = TC_RAINBOW;
}
else if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
skinnum = (INT32)((skin_t*)spr->mobj->skin-skins);
else
skinnum = TC_DEFAULT;
}
// Translation or skin number found if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
if (skinnum != INT32_MAX) {
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color); if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized)
skinnum = TC_ALLWHITE;
else if (spr->mobj->type == MT_METALSONIC_BATTLE)
skinnum = TC_METALSONIC;
else else
skinnum = TC_BOSS;
}
else if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE)
{
if (spr->mobj->colorized)
skinnum = TC_RAINBOW;
else if (spr->mobj->player && spr->mobj->player->dashmode >= DASHMODE_THRESHOLD
&& (spr->mobj->player->charflags & SF_DASHMODE)
&& ((leveltime/2) & 1))
{ {
// Sorry nothing if (spr->mobj->player->charflags & SF_MACHINE)
HWD.pfnSetTexture(gpatch->mipmap); skinnum = TC_DASHMODE;
else
skinnum = TC_RAINBOW;
} }
else if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
skinnum = (INT32)((skin_t*)spr->mobj->skin-skins);
else
skinnum = TC_DEFAULT;
}
// Translation or skin number found
if (skinnum != INT32_MAX)
{
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
} }
else else
{ {
// This is safe, since we know the texture has been downloaded // Sorry nothing
HWD.pfnSetTexture(gpatch->mipmap); HWD.pfnSetTexture(gpatch->mipmap);
} }
} }