Blend modes revision

This changes how blend modes render, and includes fixes.
This commit is contained in:
Jaime Ita Passos 2021-03-30 17:03:05 -03:00
parent df9b5c4312
commit eece82c481
7 changed files with 156 additions and 64 deletions

View File

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -216,14 +216,13 @@ enum EPolyFlags
PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pixels are discarded (holes in texture)
PF_Translucent = 0x00000002, // Poly is transparent, alpha = level of transparency
PF_Environment = 0x00000004, // Poly should be drawn environment mapped. (Hurdler: used for text drawing)
PF_Additive = 0x00000008, // Additive color blending
PF_AdditiveSource = 0x00000010, // Source blending factor is additive. This is the opposite of regular additive blending.
PF_Subtractive = 0x00000020, // Subtractive color blending
PF_ReverseSubtract = 0x00000040, // Reverse subtract, used in wall splats (decals)
PF_Multiplicative = 0x00000080, // Multiplicative color blending
PF_Additive = 0x00000008, // Source blending factor is additive.
PF_Subtractive = 0x00000010, // Subtractive color blending
PF_ReverseSubtract = 0x00000020, // Reverse subtract, used in wall splats (decals)
PF_Multiplicative = 0x00000040, // Multiplicative color blending
PF_Fog = 0x20000000, // Fog blocks
PF_NoAlphaTest = 0x40000000, // Disables alpha testing
PF_Blending = (PF_Masked|PF_Translucent|PF_Environment|PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Fog) & ~PF_NoAlphaTest,
PF_Blending = (PF_Masked|PF_Translucent|PF_Environment|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Fog) & ~PF_NoAlphaTest,
// other flag bits
PF_Occlude = 0x00000100, // Updates the depth buffer

View File

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -35,7 +35,7 @@
#define DL_HIGH_QUALITY
//#define STATICLIGHT //Hurdler: TODO!
#define LIGHTMAPFLAGS (PF_Modulated|PF_AdditiveSource)
#define LIGHTMAPFLAGS (PF_Modulated|PF_Additive)
#ifdef ALAM_LIGHTING
static dynlights_t view_dynlights[2]; // 2 players in splitscreen mode
@ -1056,7 +1056,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr)
HWR_GetPic(coronalumpnum); /// \todo use different coronas
HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_Corona | PF_NoDepthTest);
HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Corona | PF_NoDepthTest);
}
}
#endif
@ -1144,7 +1144,7 @@ void HWR_DrawCoronas(void)
light[3].y = cy+size*1.33f;
light[3].s = 0.0f; light[3].t = 1.0f;
HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_NoDepthTest | PF_Corona);
HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_NoDepthTest | PF_Corona);
}
}
#endif

View File

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -706,6 +706,8 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 ast)
{
switch (ast)
{
case AST_COPY:
return PF_Masked;
case AST_ADD:
return PF_Additive;
case AST_SUBTRACT:
@ -744,7 +746,7 @@ UINT8 HWR_GetTranstableAlpha(INT32 transtablenum)
FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf)
{
if (!transtablenum)
if (!transtablenum || style == AST_COPY)
{
pSurf->PolyColor.s.alpha = 0xff;
return PF_Masked;
@ -3813,8 +3815,6 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
else if (spr->mobj->frame & FF_TRANSMASK)
{
INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT;
if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS)
return;
blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf);
}
else
@ -4240,8 +4240,6 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
else if (spr->mobj->frame & FF_TRANSMASK)
{
INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT;
if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS)
return;
blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf);
}
else
@ -4354,9 +4352,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
if (spr->mobj->frame & FF_TRANSMASK)
{
INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT;
if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS)
return;
blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf);
blend = HWR_SurfaceBlend(AST_TRANSLUCENT, trans, &Surf);
}
else
{
@ -4935,6 +4931,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->spritexscale < 1 || thing->spriteyscale < 1)
return;
// Visibility check by the blend mode.
if (thing->frame & FF_TRANSMASK)
{
if (!R_BlendLevelVisible(thing->blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT))
return;
}
dispoffset = thing->info->dispoffset;
this_scale = FIXED_TO_FLOAT(thing->scale);
@ -5321,6 +5324,13 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
unsigned rot = 0;
UINT8 flip;
// Visibility check by the blend mode.
if (thing->frame & FF_TRANSMASK)
{
if (!R_BlendLevelVisible(thing->blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT))
return;
}
// transform the origin point
tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(thing->y) - gl_viewy;
@ -5354,7 +5364,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
return;
#endif
sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
// use single rotation for all views
lumpoff = sprframe->lumpid[0];
@ -6510,7 +6520,7 @@ void HWR_DoPostProcessor(player_t *player)
Surf.PolyColor.s.alpha = 0xc0; // match software mode
HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_AdditiveSource|PF_NoTexture|PF_NoDepthTest);
HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest);
}
// Capture the screen for intermission and screen waving

View File

@ -1576,12 +1576,11 @@ static void SetBlendMode(FBITFIELD flags)
case PF_Additive & PF_Blending:
case PF_Subtractive & PF_Blending:
case PF_ReverseSubtract & PF_Blending:
pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest
break;
case PF_Environment & PF_Blending:
pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
break;
case PF_AdditiveSource & PF_Blending:
pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest
break;
case PF_Multiplicative & PF_Blending:
pglBlendFunc(GL_DST_COLOR, GL_ZERO);
break;
@ -1620,7 +1619,6 @@ static void SetBlendMode(FBITFIELD flags)
break;
case PF_Translucent & PF_Blending:
case PF_Additive & PF_Blending:
case PF_AdditiveSource & PF_Blending:
case PF_Subtractive & PF_Blending:
case PF_ReverseSubtract & PF_Blending:
case PF_Environment & PF_Blending:
@ -2752,7 +2750,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
fade.alpha = byte2float[Surface->FadeColor.s.alpha];
flags = (Surface->PolyFlags | PF_Modulated);
if (Surface->PolyFlags & (PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative))
if (Surface->PolyFlags & (PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative))
flags |= PF_Occlude;
else if (Surface->PolyColor.s.alpha == 0xFF)
flags |= (PF_Occlude | PF_Masked);

View File

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -198,43 +198,15 @@ void R_InitTranslucencyTables(void)
R_GenerateBlendTables();
}
void R_GenerateBlendTables(void)
{
INT32 i;
for (i = 0; i < NUMBLENDMAPS; i++)
{
if (i == blendtab_modulate)
continue;
blendtables[i] = Z_MallocAlign((NUMTRANSTABLES + 1) * 0x10000, PU_STATIC, NULL, 16);
}
for (i = 0; i <= 9; i++)
{
const size_t offs = (0x10000 * i);
const UINT8 alpha = TRANSTAB_AMTMUL10 * i;
R_GenerateTranslucencyTable(blendtables[blendtab_add] + offs, AST_ADD, alpha);
R_GenerateTranslucencyTable(blendtables[blendtab_subtract] + offs, AST_SUBTRACT, alpha);
R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, AST_REVERSESUBTRACT, alpha);
}
// Modulation blending only requires a single table
blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16);
R_GenerateTranslucencyTable(blendtables[blendtab_modulate], AST_MODULATE, 0);
}
static colorlookup_t transtab_lut;
void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt)
static void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt)
{
INT16 bg, fg;
if (table == NULL)
I_Error("R_GenerateTranslucencyTable: input table was NULL!");
InitColorLUT(&transtab_lut, pMasterPalette, false);
for (bg = 0; bg < 0xFF; bg++)
{
for (fg = 0; fg < 0xFF; fg++)
@ -243,12 +215,117 @@ void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt)
RGBA_t frontrgba = V_GetMasterColor(fg);
RGBA_t result;
result.rgba = ASTBlendPixel(backrgba, frontrgba, style, blendamt);
result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF);
result.rgba = ASTBlendPixel(result, frontrgba, AST_TRANSLUCENT, blendamt);
table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue);
}
}
}
static void R_GenerateSubtractiveTable(UINT8 *table, int style, UINT8 blendamt)
{
INT16 bg, fg;
if (table == NULL)
I_Error("R_GenerateSubtractiveTable: input table was NULL!");
blendamt = 0xFF - blendamt;
if (!blendamt)
{
memset(table, GetColorLUT(&transtab_lut, 0, 0, 0), 0x10000);
return;
}
for (bg = 0; bg < 0xFF; bg++)
{
for (fg = 0; fg < 0xFF; fg++)
{
RGBA_t backrgba = V_GetMasterColor(bg);
RGBA_t frontrgba = V_GetMasterColor(fg);
RGBA_t result;
result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF);
result.s.red = (result.s.red * blendamt) / 0xFF;
result.s.green = (result.s.green * blendamt) / 0xFF;
result.s.blue = (result.s.blue * blendamt) / 0xFF;
table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue);
}
}
}
static void R_GenerateModulationTable(UINT8 *table)
{
INT16 bg, fg;
if (table == NULL)
I_Error("R_GenerateModulationTable: input table was NULL!");
for (bg = 0; bg < 0xFF; bg++)
{
for (fg = 0; fg < 0xFF; fg++)
{
RGBA_t backrgba = V_GetMasterColor(bg);
RGBA_t frontrgba = V_GetMasterColor(fg);
RGBA_t result;
result.rgba = ASTBlendPixel(backrgba, frontrgba, AST_MODULATE, 0);
table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue);
}
}
}
static INT32 R_GetBlendTableCount(INT32 style)
{
INT32 count = NUMTRANSTABLES;
if (style == blendtab_subtract || style == blendtab_reversesubtract)
count++;
return count;
}
static void R_GenerateBlendTableMaps(INT32 tab, INT32 style, void (*genfunc)(UINT8 *, int, UINT8))
{
INT32 i = 0;
for (; i <= R_GetBlendTableCount(tab); i++)
{
const size_t offs = (0x10000 * i);
const UINT16 alpha = min(TRANSTAB_AMTMUL10 * i, 0xFF);
genfunc(blendtables[tab] + offs, style, alpha);
}
}
void R_GenerateBlendTables(void)
{
INT32 i;
for (i = 0; i < NUMBLENDMAPS; i++)
{
if (i == blendtab_modulate)
continue;
blendtables[i] = Z_MallocAlign((R_GetBlendTableCount(i) + 1) * 0x10000, PU_STATIC, NULL, 16);
}
InitColorLUT(&transtab_lut, pMasterPalette, false);
// Additive
R_GenerateBlendTableMaps(blendtab_add, AST_ADD, R_GenerateTranslucencyTable);
// Subtractive
#if 1
R_GenerateBlendTableMaps(blendtab_subtract, AST_SUBTRACT, R_GenerateSubtractiveTable);
#else
R_GenerateBlendTableMaps(blendtab_subtract, AST_SUBTRACT, R_GenerateTranslucencyTable);
#endif
// Reverse subtractive
R_GenerateBlendTableMaps(blendtab_reversesubtract, AST_REVERSESUBTRACT, R_GenerateTranslucencyTable);
// Modulation blending only requires a single table
blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16);
R_GenerateModulationTable(blendtables[blendtab_modulate]);
}
#define ClipBlendLevel(style, trans) max(min((trans), R_GetBlendTableCount(style)+1), 0)
#define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0)
UINT8 *R_GetTranslucencyTable(INT32 alphalevel)
@ -258,7 +335,7 @@ UINT8 *R_GetTranslucencyTable(INT32 alphalevel)
UINT8 *R_GetBlendTable(int style, INT32 alphalevel)
{
size_t offs = (ClipTransLevel(alphalevel) << FF_TRANSSHIFT);
size_t offs = (ClipBlendLevel(style, alphalevel) << FF_TRANSSHIFT);
// Lactozilla: Returns the equivalent to AST_TRANSLUCENT
// if no alpha style matches any of the blend tables.
@ -283,6 +360,13 @@ UINT8 *R_GetBlendTable(int style, INT32 alphalevel)
return NULL;
}
boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel)
{
if (blendmode == AST_COPY || blendmode == AST_SUBTRACT || blendmode == AST_MODULATE)
return true;
return (alphalevel < R_GetBlendTableCount(blendmode));
}
// Define for getting accurate color brightness readings according to how the human eye sees them.
// https://en.wikipedia.org/wiki/Relative_luminance
// 0.2126 to red

View File

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -140,11 +140,12 @@ extern UINT8 *blendtables[NUMBLENDMAPS];
void R_InitTranslucencyTables(void);
void R_GenerateBlendTables(void);
void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt);
UINT8 *R_GetTranslucencyTable(INT32 alphalevel);
UINT8 *R_GetBlendTable(int style, INT32 alphalevel);
boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel);
// Color ramp modification should force a recache
extern UINT8 skincolor_modified[];

View File

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -1803,7 +1803,7 @@ static void R_ProjectSprite(mobj_t *thing)
else if (oldthing->frame & FF_TRANSMASK)
{
trans = (oldthing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT;
if (oldthing->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS)
if (!R_BlendLevelVisible(oldthing->blendmode, trans))
return;
}
else
@ -2199,7 +2199,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
// specific translucency
if (thing->frame & FF_TRANSMASK)
vis->transmap = (thing->frame & FF_TRANSMASK) - 0x10000 + transtables;
vis->transmap = R_GetTranslucencyTable((thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT);
else
vis->transmap = NULL;