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
This commit is contained in:
Sally Cochenour 2019-12-29 16:36:53 -05:00
parent dcc7426d1d
commit 74d7f256a7

View file

@ -654,12 +654,12 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
UINT16 w = gpatch->width, h = gpatch->height;
UINT32 size = w*h;
RGBA_t *image, *blendimage, *cur, blendcolor;
UINT8 i;
UINT8 translation[16]; // First the color index
UINT8 cutoff[16]; // Brightness cutoff before using the next color
UINT8 translen = 0;
UINT8 i;
blendcolor = V_GetColor(0); // initialize
memset(translation, 0, sizeof(translation));
memset(cutoff, 0, sizeof(cutoff));
@ -685,7 +685,10 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
image = gpatch->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)
{
@ -721,7 +724,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
if (skinnum == TC_BOSS)
{
// 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
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;
}
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)
{
// Turn everything white
@ -790,208 +746,268 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
}
else
{
UINT16 brightness;
// Everything below requires a blend image
if (blendimage == NULL)
{
cur->rgba = image->rgba;
goto skippixel;
}
I_Assert(translen > 0);
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
if (skinnum == TC_RAINBOW)
// Metal Sonic dash mode
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;
cur++; image++; blendimage++;
continue;
}
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;
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 (blendimage->s.alpha == 0)
// All settings that use skincolors!
UINT16 brightness;
if (translen <= 0)
{
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
goto skippixel;
}
// 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
{
SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
}
}
// 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)
if (blendimage->s.alpha == 0)
{
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
goto skippixel; // for metal sonic blend
}
firsti = 0;
mul = 0;
mulmax = 1;
for (i = 0; i < translen; i++)
else
{
RGBA_t tempc = V_GetColor(translation[i]);
SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
}
}
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)
continue;
UINT16 brightdif = 256;
UINT8 colorbrightnesses[16];
INT32 compare, m, d;
compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness));
if (compare < brightdif)
// Ignore pure white & pitch black
if (brightness > 253 || brightness < 2)
{
brightdif = (UINT16)compare;
firsti = i; // best matching color that's equal brightness or darker
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
}
}
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;
// calculate the "gradient" multiplier based on how close this color is to the one next in line
if (m <= 0 || d <= 0)
{
firsti = 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
{
// 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];
if (secondi < translen)
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
{
// Just convert brightness to a skincolor value, use distance to next position to find the gradient multipler
firsti = 0;
// Color strength depends on image alpha
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])
break;
firsti = i;
// Sal: Invert non-blue
cur->s.red = cur->s.green = (255 - cur->s.blue);
cur->s.blue = 255;
}
secondi = firsti+1;
mulmax = cutoff[firsti];
if (secondi < translen)
mulmax -= cutoff[secondi];
mul = cutoff[firsti] - brightness;
cur->s.alpha = image->s.alpha;
}
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;
@ -1030,6 +1046,14 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
// If here, the blended texture has not been created
// 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
// (it have a liste of mipmap)
// this malloc is cleared in HWR_FreeTextureCache
@ -1269,50 +1293,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 (md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format
&& 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;
}
INT32 skinnum = INT32_MAX;
// Translation or skin number found
if (skinnum != INT32_MAX)
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
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))
{
// Sorry nothing
HWD.pfnSetTexture(gpatch->mipmap);
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 (skinnum != INT32_MAX)
{
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
}
else
{
// This is safe, since we know the texture has been downloaded
// Sorry nothing
HWD.pfnSetTexture(gpatch->mipmap);
}
}