From 36a1662afb03157e4a01d5f080b1657a75be3658 Mon Sep 17 00:00:00 2001 From: Chearii Date: Sun, 2 Feb 2025 20:37:19 -0500 Subject: [PATCH 1/6] Add blending modes --- src/dehacked.c | 28 +++++ src/f_wipe.c | 2 +- src/hardware/hw_defs.h | 26 ++--- src/hardware/hw_draw.c | 14 ++- src/hardware/hw_main.c | 146 ++++++++++++++++++++---- src/hardware/hw_main.h | 5 +- src/hardware/hw_md2.c | 9 ++ src/hardware/r_opengl/r_opengl.c | 163 ++++++++++++++++---------- src/k_kart.c | 6 +- src/lua_hudlib.c | 23 ++-- src/lua_hudlib_drawlist.c | 19 +++- src/lua_hudlib_drawlist.h | 9 +- src/lua_mobjlib.c | 14 +++ src/m_anigif.c | 11 +- src/p_mobj.c | 1 + src/p_mobj.h | 2 + src/p_pspr.h | 28 ++++- src/p_saveg.c | 1 + src/r_data.c | 107 +++++++++++++++++ src/r_data.h | 3 + src/r_defs.h | 3 + src/r_draw.c | 190 ++++++++++++++++++++++++++++++- src/r_draw.h | 23 +++- src/r_main.c | 4 +- src/r_plane.c | 22 ++-- src/r_segs.c | 24 ++-- src/r_things.c | 84 +++++++++++--- src/r_things.h | 7 ++ src/v_video.c | 72 ++++++++---- src/v_video.h | 36 ++++-- 30 files changed, 872 insertions(+), 210 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index dc4288be5..007324764 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7721,7 +7721,18 @@ struct { {"FF_HORIZONTALFLIP",FF_HORIZONTALFLIP}, {"FF_PAPERSPRITE",FF_PAPERSPRITE}, {"FF_ANIMATE",FF_ANIMATE}, + // brightness + {"FF_BRIGHTMASK",FF_BRIGHTMASK}, {"FF_FULLBRIGHT",FF_FULLBRIGHT}, + {"FF_SEMIBRIGHT",FF_SEMIBRIGHT}, + {"FF_FULLDARK",FF_FULLDARK}, + // blending + {"FF_BLENDMASK",FF_BLENDMASK}, + {"FF_BLENDSHIFT",FF_BRIGHTMASK}, + {"FF_ADD",FF_ADD}, + {"FF_SUBTRACT",FF_SUBTRACT}, + {"FF_REVERSESUBTRACT",FF_REVERSESUBTRACT}, + {"FF_MODULATE",FF_MODULATE}, {"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSSHIFT",FF_TRANSSHIFT}, // new preshifted translucency (used in source) @@ -7757,6 +7768,15 @@ struct { {"tr_trans90",tr_trans90}, {"NUMTRANSMAPS",NUMTRANSMAPS}, + // Alpha styles (blend modes) + {"AST_COPY",AST_COPY}, + {"AST_TRANSLUCENT",AST_TRANSLUCENT}, + {"AST_ADD",AST_ADD}, + {"AST_SUBTRACT",AST_SUBTRACT}, + {"AST_REVERSESUBTRACT",AST_REVERSESUBTRACT}, + {"AST_MODULATE",AST_MODULATE}, + {"AST_OVERLAY",AST_OVERLAY}, + // Type of levels {"TOL_SP",TOL_SP}, {"TOL_COOP",TOL_COOP}, @@ -8121,6 +8141,14 @@ struct { {"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT}, {"V_ALPHASHIFT",V_ALPHASHIFT}, + // Blending + {"V_BLENDSHIFT",V_BLENDSHIFT}, + {"V_BLENDMASK",V_BLENDMASK}, + {"B_ADD",B_ADD}, + {"B_SUBTRACT",B_SUBTRACT}, + {"B_REVERSESUBTRACT",B_REVERSESUBTRACT}, + {"B_MODULATE",B_MODULATE}, + //Kick Reasons {"KR_KICK",KR_KICK}, {"KR_PINGLIMIT",KR_PINGLIMIT}, diff --git a/src/f_wipe.c b/src/f_wipe.c index da5b9dac1..1523ca1d3 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -273,7 +273,7 @@ static void F_DoWipe(fademask_t *fademask) else { // pointer to transtable that this mask would use - transtbl = transtables + ((9 - *mask)< FlatColor PF_NoTexture = 0x00002000, // Disable texture diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index e39398ff2..b2d69861a 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -125,13 +125,14 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) +void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, INT32 bflags) { FOutVector v[4]; FBITFIELD flags; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + UINT8 blendmode = ((bflags & V_BLENDMASK) >> V_BLENDSHIFT); // 3--2 // | /| @@ -286,22 +287,27 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t v[0].t = v[1].t = 0.0f; v[2].t = v[3].t = gpatch->max_t; - flags = PF_Translucent|PF_NoDepthTest; - if (option & V_WRAPX) flags |= PF_ForceWrapX; if (option & V_WRAPY) flags |= PF_ForceWrapY; // clip it since it is used for bunny scroll in doom I + if (blendmode) + flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; + else + flags = PF_Translucent|PF_NoDepthTest; + if (alphalevel) { FSurfaceInfo Surf; Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; + if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[hudtrans]; else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[hudtrans]; else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[hudtrans]; else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; + flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } @@ -455,10 +461,12 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal { FSurfaceInfo Surf; Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; + if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[cv_translucenthud.value]; else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[cv_translucenthud.value]; else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[cv_translucenthud.value]; else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; + flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b02730814..1fd05d947 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -654,7 +654,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool HWR_Lighting(&Surf, lightlevel, planecolormap); - if (PolyFlags & (PF_Translucent|PF_Fog)) + if (PolyFlags & (PF_Translucent|PF_Fog|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Environment)) { Surf.PolyColor.s.alpha = (UINT8)alpha; PolyFlags |= PF_Modulated; @@ -836,20 +836,67 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) } #endif -FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) +FBITFIELD HWR_GetBlendModeFlag(INT32 ast) +{ + switch (ast) + { + case AST_TRANSLUCENT: + return PF_Translucent; + case AST_ADD: + return PF_Additive; + case AST_SUBTRACT: + return PF_Subtractive; + case AST_REVERSESUBTRACT: + return PF_ReverseSubtract; + case AST_MODULATE: + return PF_Multiplicative; + default: + return PF_Masked; + } + + return 0; +} + +UINT8 HWR_GetTranstableAlpha(INT32 transtablenum) { switch (transtablenum) { - case tr_trans10 : pSurf->PolyColor.s.alpha = 0xe6;return PF_Translucent; - case tr_trans20 : pSurf->PolyColor.s.alpha = 0xcc;return PF_Translucent; - case tr_trans30 : pSurf->PolyColor.s.alpha = 0xb3;return PF_Translucent; - case tr_trans40 : pSurf->PolyColor.s.alpha = 0x99;return PF_Translucent; - case tr_trans50 : pSurf->PolyColor.s.alpha = 0x80;return PF_Translucent; - case tr_trans60 : pSurf->PolyColor.s.alpha = 0x66;return PF_Translucent; - case tr_trans70 : pSurf->PolyColor.s.alpha = 0x4c;return PF_Translucent; - case tr_trans80 : pSurf->PolyColor.s.alpha = 0x33;return PF_Translucent; - case tr_trans90 : pSurf->PolyColor.s.alpha = 0x19;return PF_Translucent; + case 0 : return 0xff; + case tr_trans10 : return 0xe6; + case tr_trans20 : return 0xcc; + case tr_trans30 : return 0xb3; + case tr_trans40 : return 0x99; + case tr_trans50 : return 0x80; + case tr_trans60 : return 0x66; + case tr_trans70 : return 0x4c; + case tr_trans80 : return 0x33; + case tr_trans90 : return 0x19; } + + return 0xff; +} + +FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf) +{ + if (!transtablenum || style <= AST_COPY || style >= AST_OVERLAY) + { + pSurf->PolyColor.s.alpha = 0xff; + return PF_Masked; + } + + pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum); + return HWR_GetBlendModeFlag(style); +} + +FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) +{ + if (!transtablenum) + { + pSurf->PolyColor.s.alpha = 0x00; + return PF_Masked; + } + + pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum); return PF_Translucent; } @@ -1067,8 +1114,8 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, if (cutflag & FF_FOG) HWR_AddTransparentWall(wallVerts, Surf, texnum, noencore, PF_Fog|PF_NoTexture|polyflags, true, lightnum, colormap); - else if (cutflag & FF_TRANSLUCENT) - HWR_AddTransparentWall(wallVerts, Surf, texnum, noencore, PF_Translucent|polyflags, false, lightnum, colormap); + else if (polyflags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Environment)) + HWR_AddTransparentWall(wallVerts, Surf, texnum, noencore, polyflags, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, Surf, PF_Masked|polyflags, lightnum, colormap); } @@ -3562,6 +3609,12 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // co-ordinates memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts)); + INT32 blendmode; + if (spr->mobj->frame & FF_BLENDMASK) + blendmode = ((spr->mobj->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = spr->mobj->blendmode; + if (!cv_translucency.value) // translucency disabled { Surf.PolyColor.s.alpha = 0xFF; @@ -3570,10 +3623,13 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + blend = HWR_GetBlendModeFlag(blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + blend = HWR_SurfaceBlend(blendmode, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -3581,7 +3637,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = HWR_GetBlendModeFlag(blendmode)|PF_Occlude; } if (HWR_UseShader()) @@ -3599,8 +3655,10 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) i = 0; temp = FLOAT_TO_FIXED(realtop); - if (spr->mobj->frame & FF_FULLBRIGHT) + if (R_ThingIsFullBright(spr->mobj)) lightlevel = 255; + else if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; for (i = 1; i < sector->numlights; i++) { @@ -3614,6 +3672,9 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) break; } + if (R_ThingIsSemiBright(spr->mobj)) + lightlevel = 128 + (lightlevel>>1); + for (i = 0; i < sector->numlights; i++) { if (endtop < endrealbot && top < realbot) @@ -3832,11 +3893,22 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) UINT8 lightlevel = 255; extracolormap_t *colormap = sector->extra_colormap; - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else if (!(R_ThingIsFullBright(spr->mobj))) lightlevel = min(sector->lightlevel, 255); + if (R_ThingIsSemiBright(spr->mobj)) + lightlevel = 128 + (lightlevel>>1); + HWR_Lighting(&Surf, lightlevel, colormap); + INT32 blendmode; + if (spr->mobj->frame & FF_BLENDMASK) + blendmode = ((spr->mobj->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = spr->mobj->blendmode; + if (!cv_translucency.value) // translucency disabled { Surf.PolyColor.s.alpha = 0xFF; @@ -3845,10 +3917,13 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + blend = HWR_GetBlendModeFlag(blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + blend = HWR_SurfaceBlend(blendmode, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -3856,7 +3931,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = HWR_GetBlendModeFlag(blendmode)|PF_Occlude; } if (HWR_UseShader()) @@ -3946,7 +4021,10 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) HWR_Lighting(&Surf, lightlevel, colormap); if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + blend = HWR_SurfaceBlend(AST_TRANSLUCENT, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -3954,7 +4032,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = HWR_GetBlendModeFlag(AST_TRANSLUCENT)|PF_Occlude; } if (HWR_UseShader()) @@ -4473,6 +4551,19 @@ static void HWR_ProjectSprite(mobj_t *thing) if (interp.spritexscale < 1 || interp.spriteyscale < 1) return; + INT32 blendmode; + if (thing->frame & FF_BLENDMASK) + blendmode = ((thing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = thing->blendmode; + + // Visibility check by the blend mode. + if (thing->frame & FF_TRANSMASK) + { + if (!R_BlendLevelVisible(blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT)) + return; + } + this_scale = FIXED_TO_FLOAT(interp.scale); spritexscale = FIXED_TO_FLOAT(interp.spritexscale); spriteyscale = FIXED_TO_FLOAT(interp.spriteyscale); @@ -4797,6 +4888,13 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp); } + // Visibility check by the blend mode. + if (thing->frame & FF_TRANSMASK) + { + if (!R_BlendLevelVisible(thing->blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT)) + return; + } + this_scale = FIXED_TO_FLOAT(interp.scale); // transform the origin point @@ -5190,7 +5288,7 @@ static void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) for (x = vid.width>>1; x < vid.width; x += pw) { for (y = vid.height>>1; y < vid.height; y += ph) - HWR_DrawStretchyFixedPatch(gpatch, (x)<mobj->flags2 & MF2_SHADOW) + { Surf.PolyColor.s.alpha = 0x40; + Surf.PolyFlags = HWR_GetBlendModeFlag(spr->mobj->blendmode); + } else if (spr->mobj->frame & FF_TRANSMASK) + { HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + Surf.PolyFlags = HWR_SurfaceBlend(spr->mobj->blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + } else + { Surf.PolyColor.s.alpha = 0xFF; + Surf.PolyFlags = 0; + } // dont forget to enabled the depth test because we can't do this like // before: polygons models are not sorted diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 4b98f332d..231f2b01e 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -490,6 +490,10 @@ static PFNglDeleteBuffers pglDeleteBuffers; typedef void (APIENTRY *PFNglColorPointer) (GLint, GLenum, GLsizei, const GLvoid*); static PFNglColorPointer pglColorPointer; +/* 2.0 functions */ +typedef void (APIENTRY * PFNglBlendEquation) (GLenum mode); +static PFNglBlendEquation pglBlendEquation; + /* 1.2 Parms */ /* GL_CLAMP_TO_EDGE_EXT */ #ifndef GL_CLAMP_TO_EDGE @@ -734,6 +738,9 @@ void SetupGLFunc4(void) pglBufferData = GetGLFunc("glBufferData"); pglDeleteBuffers = GetGLFunc("glDeleteBuffers"); pglColorPointer = GetGLFunc("glColorPointer"); + + /* 2.0 funcs */ + pglBlendEquation = GetGLFunc("glBlendEquation"); pglStencilFuncSeparate = GetGLFunc("glStencilFuncSeparate"); pglStencilOpSeparate = GetGLFunc("glStencilOpSeparate"); @@ -1397,7 +1404,11 @@ EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1, pglEnableClientState(GL_TEXTURE_COORD_ARRAY); pglEnable(GL_TEXTURE_2D); } - +// -----------------+ +// SetBlend : Set render mode +// -----------------+ +// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0, +// is it faster when pixels are discarded ? static void Clamp2D(GLenum pname) { pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP); // fallback clamp @@ -1406,57 +1417,95 @@ static void Clamp2D(GLenum pname) #endif } -// -----------------+ -// SetBlend : Set render mode -// -----------------+ -// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0, -// is it faster when pixels are discarded ? +static void SetBlendEquation(GLenum mode) +{ + if (pglBlendEquation) + pglBlendEquation(mode); +} + +static void SetBlendMode(FBITFIELD flags) +{ + // Set blending function + switch (flags) + { + case PF_Translucent & PF_Blending: + pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency + break; + case PF_Masked & PF_Blending: + // Hurdler: does that mean lighting is only made by alpha src? + // it sounds ok, but not for polygonsmooth + pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture + break; + 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_Multiplicative & PF_Blending: + pglBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + case PF_Fog & PF_Fog: + // Sryder: Fog + // multiplies input colour by input alpha, and destination colour by input colour, then adds them + pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); + break; + default: // must be 0, otherwise it's an error + // No blending + pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending + break; + } + + // Set blending equation + switch (flags) + { + case PF_Subtractive & PF_Blending: + SetBlendEquation(GL_FUNC_SUBTRACT); + break; + case PF_ReverseSubtract & PF_Blending: + // good for shadow + // not really but what else ? + SetBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + break; + default: + SetBlendEquation(GL_FUNC_ADD); + break; + } + + // Alpha test + switch (flags) + { + case PF_Masked & PF_Blending: + pglAlphaFunc(GL_GREATER, 0.5f); + break; + case PF_Translucent & PF_Blending: + case PF_Additive & PF_Blending: + case PF_Subtractive & PF_Blending: + case PF_ReverseSubtract & PF_Blending: + case PF_Environment & PF_Blending: + case PF_Multiplicative & PF_Blending: + pglAlphaFunc(GL_NOTEQUAL, 0.0f); + break; + case PF_Fog & PF_Fog: + pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments + break; + default: + pglAlphaFunc(GL_GREATER, 0.5f); + break; + } +} + EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) { FBITFIELD Xor; Xor = CurrentPolyFlags^PolyFlags; - if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible|PF_NoAlphaTest)) + if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible)) { - if (Xor&(PF_Blending)) // if blending mode must be changed - { - switch (PolyFlags & PF_Blending) { - case PF_Translucent & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Masked & PF_Blending: - // Hurdler: does that mean lighting is only made by alpha src? - // it sounds ok, but not for polygonsmooth - pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture - pglAlphaFunc(GL_GREATER, 0.5f); - break; - case PF_Additive & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Environment & PF_Blending: - pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Substractive & PF_Blending: - // good for shadow - // not really but what else ? - pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Fog & PF_Fog: - // Sryder: Fog - // multiplies input colour by input alpha, and destination colour by input colour, then adds them - pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); - pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments - break; - default : // must be 0, otherwise it's an error - // No blending - pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending - pglAlphaFunc(GL_GREATER, 0.5f); - break; - } - } + if (Xor & PF_Blending) // if blending mode must be changed + SetBlendMode(PolyFlags & PF_Blending); + if (Xor & PF_NoAlphaTest) { if (PolyFlags & PF_NoAlphaTest) @@ -1472,7 +1521,8 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) else pglDisable(GL_POLYGON_OFFSET_FILL); } - if (Xor&PF_NoDepthTest) + + if (Xor & PF_NoDepthTest) { if (PolyFlags & PF_NoDepthTest) pglDepthFunc(GL_ALWAYS); //pglDisable(GL_DEPTH_TEST); @@ -1480,25 +1530,25 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) pglDepthFunc(GL_LEQUAL); //pglEnable(GL_DEPTH_TEST); } - if (Xor&PF_RemoveYWrap) + if (Xor & PF_RemoveYWrap) { if (PolyFlags & PF_RemoveYWrap) Clamp2D(GL_TEXTURE_WRAP_T); } - if (Xor&PF_ForceWrapX) + if (Xor & PF_ForceWrapX) { if (PolyFlags & PF_ForceWrapX) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); } - if (Xor&PF_ForceWrapY) + if (Xor & PF_ForceWrapY) { if (PolyFlags & PF_ForceWrapY) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - if (Xor&PF_Modulated) + if (Xor & PF_Modulated) { #if defined (__unix__) || defined (UNIXCOMMON) if (oglflags & GLF_NOTEXENV) @@ -2721,14 +2771,11 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float poly.green = byte2float[Surface->PolyColor.s.green]; poly.blue = byte2float[Surface->PolyColor.s.blue]; poly.alpha = byte2float[Surface->PolyColor.s.alpha]; - - if (poly.alpha < 1) - SetBlend(PF_Translucent|PF_Modulated); - else - SetBlend(PF_Masked|PF_Modulated|PF_Occlude); - + pglColor4ubv((GLubyte*)&Surface->PolyColor.s); + SetBlend((poly.alpha < 1 ? Surface->PolyFlags : (PF_Masked|PF_Occlude))|PF_Modulated); + tint.red = byte2float[Surface->TintColor.s.red]; tint.green = byte2float[Surface->TintColor.s.green]; tint.blue = byte2float[Surface->TintColor.s.blue]; diff --git a/src/k_kart.c b/src/k_kart.c index c27ffec4c..15b649dac 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8851,10 +8851,10 @@ static void K_drawKartSpeedometer(void) if (K_UseColorHud() && xtra_speedo_clr3) //Colourized hud { UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, K_GetHudColor(), GTC_CACHE); - V_DrawStretchyFixedPatch((SPDM_X-1)<patch = patch; item->flags = flags; item->colormap = colormap; + item->blend = blend; } void LUA_HUD_AddDrawScaled( @@ -366,7 +369,8 @@ void LUA_HUD_AddDrawScaled( fixed_t scale, patch_t *patch, INT32 flags, - UINT8 *colormap + UINT8 *colormap, + INT32 blend ) { size_t i = AllocateDrawItem(list); @@ -379,6 +383,7 @@ void LUA_HUD_AddDrawScaled( item->patch = patch; item->flags = flags; item->colormap = colormap; + item->blend = blend; } void LUA_HUD_AddDrawStretched( @@ -389,7 +394,8 @@ void LUA_HUD_AddDrawStretched( fixed_t vscale, patch_t *patch, INT32 flags, - UINT8 *colormap + UINT8 *colormap, + INT32 blend ) { size_t i = AllocateDrawItem(list); @@ -403,6 +409,7 @@ void LUA_HUD_AddDrawStretched( item->patch = patch; item->flags = flags; item->colormap = colormap; + item->blend = blend; } void LUA_HUD_AddDrawNum( @@ -634,17 +641,17 @@ void LUA_HUD_DrawList(huddrawlist_h list) case DI_Draw: if (!item->patch || item->patch == NULL) return; - V_DrawFixedPatch(LERPS(x), LERPS(y), FRACUNIT, item->flags, item->patch, item->colormap); + V_DrawBlendingFixedPatch(LERPS(x), LERPS(y), FRACUNIT, item->flags, item->patch, item->colormap, item->blend); break; case DI_DrawScaled: if (!item->patch || item->patch == NULL) return; - V_DrawFixedPatch(LERPS(x), LERPS(y), LERP(scale), item->flags, item->patch, item->colormap); + V_DrawBlendingFixedPatch(LERPS(x), LERPS(y), LERP(scale), item->flags, item->patch, item->colormap, item->blend); break; case DI_DrawStretched: if (!item->patch || item->patch == NULL) return; - V_DrawStretchyFixedPatch(LERPS(x), LERPS(y), LERP(hscale), LERP(vscale), item->flags, item->patch, item->colormap); + V_DrawStretchyFixedPatch(LERPS(x), LERPS(y), LERP(hscale), LERP(vscale), item->flags, item->patch, item->colormap, item->blend); break; case DI_DrawNum: V_DrawTallNum(LERPS(x), LERPS(y), item->flags, item->num); diff --git a/src/lua_hudlib_drawlist.h b/src/lua_hudlib_drawlist.h index 4354b6f95..4d19bcae2 100644 --- a/src/lua_hudlib_drawlist.h +++ b/src/lua_hudlib_drawlist.h @@ -40,7 +40,8 @@ void LUA_HUD_AddDraw( INT32 y, patch_t *patch, INT32 flags, - UINT8 *colormap + UINT8 *colormap, + INT32 blend ); void LUA_HUD_AddDrawStretched( huddrawlist_h list, @@ -50,7 +51,8 @@ void LUA_HUD_AddDrawStretched( fixed_t vscale, patch_t *patch, INT32 flags, - UINT8 *colormap + UINT8 *colormap, + INT32 blend ); void LUA_HUD_AddDrawScaled( huddrawlist_h list, @@ -59,7 +61,8 @@ void LUA_HUD_AddDrawScaled( fixed_t scale, patch_t *patch, INT32 flags, - UINT8 *colormap + UINT8 *colormap, + INT32 blend ); void LUA_HUD_AddDrawNum( huddrawlist_h list, diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 7385cccf6..13b3a1286 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -52,6 +52,7 @@ int mobj_skin_setter(lua_State *L); int mobj_localskin_getter(lua_State *L); int mobj_localskin_setter(lua_State *L); int mobj_color_setter(lua_State *L); +int mobj_blendmode_setter(lua_State *L); int mobj_bnext_noset(lua_State *L); int mobj_bprev_unimplemented(lua_State *L); int mobj_hnext_setter(lua_State *L); @@ -114,6 +115,7 @@ static const udata_field_t mobj_fields[] = { FIELD(mobj_t, skin, mobj_skin_getter, mobj_skin_setter), FIELD(mobj_t, localskin, mobj_localskin_getter, mobj_localskin_setter), FIELD(mobj_t, color, udatalib_getter_uint8, mobj_color_setter), + FIELD(mobj_t, blendmode, udatalib_getter_int32, mobj_blendmode_setter), FIELD(mobj_t, bnext, udatalib_getter_mobj, mobj_bnext_noset), FIELD(mobj_t, bprev, mobj_bprev_unimplemented, mobj_bprev_unimplemented), FIELD(mobj_t, hnext, udatalib_getter_mobj, mobj_hnext_setter), @@ -476,6 +478,18 @@ int mobj_color_setter(lua_State *L) return 0; } +int mobj_blendmode_setter(lua_State *L) +{ + mobj_t *mo = GETMO(); + + INT32 blendmode = (INT32)luaL_checkinteger(L, 2); + if (blendmode < 0 || blendmode > AST_OVERLAY) + return luaL_error(L, "mobj.blendmode %d out of range (0 - %d).", blendmode, AST_OVERLAY); + mo->blendmode = blendmode; + + return 0; +} + int mobj_hnext_setter(lua_State *L) { mobj_t *mo = GETMO(); diff --git a/src/m_anigif.c b/src/m_anigif.c index 44b5a96c0..05b1f8287 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -32,6 +32,7 @@ consvar_t cv_gif_downscale = {"gif_downscale", "On", CV_SAVE, CV_OnOff, NULL, 0 #ifdef HAVE_ANIGIF static boolean gif_optimize = false; // So nobody can do something dumb static boolean gif_downscale = false; // like changing cvars mid output +static RGBA_t *gif_palette = NULL; static FILE *gif_out = NULL; static INT32 gif_frames = 0; @@ -461,13 +462,15 @@ static size_t gifframe_size = 8192; // converts an RGB frame to a frame with a palette. // #ifdef HWRENDER +static colorlookup_t gif_colorlookup; + static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) { UINT8 r, g, b; size_t src, dest; int x, y; - InitColorLUT(); + InitColorLUT(&gif_colorlookup, gif_palette, true); for (x = 0; x < vid.width; x += scrbuf_downscaleamt) { @@ -479,7 +482,7 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) r = (UINT8)linear[src]; g = (UINT8)linear[src + 1]; b = (UINT8)linear[src + 2]; - scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS]; + scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b); } } } @@ -636,6 +639,10 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); + + // no master palettes in SRB2Kart land + gif_palette = pLocalPalette; + GIF_headwrite(); gif_frames = 0; return 1; diff --git a/src/p_mobj.c b/src/p_mobj.c index ad296c576..a916190a9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9413,6 +9413,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } // Sprite rendering + mobj->blendmode = AST_TRANSLUCENT; mobj->realxscale = mobj->realyscale = mobj->scale; mobj->spritexscale = mobj->realxscale; mobj->spriteyscale = mobj->realyscale; diff --git a/src/p_mobj.h b/src/p_mobj.h index cd7c64dc1..2aecf73b5 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -289,6 +289,7 @@ typedef struct mobj_s UINT32 frame; // frame number, plus bits see p_pspr.h UINT16 anim_duration; // for FF_ANIMATE states + INT32 blendmode; // blend mode fixed_t spritexscale, spriteyscale; fixed_t spritexoffset, spriteyoffset; fixed_t old_spritexscale, old_spriteyscale; @@ -441,6 +442,7 @@ typedef struct precipmobj_s UINT32 frame; // frame number, plus bits see p_pspr.h UINT16 anim_duration; // for FF_ANIMATE states + INT32 blendmode; // blend mode fixed_t spritexscale, spriteyscale; fixed_t spritexoffset, spriteyoffset; fixed_t old_spritexscale, old_spriteyscale; diff --git a/src/p_pspr.h b/src/p_pspr.h index 5ac1d1d84..90cfc40fc 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -41,10 +41,18 @@ #define FF_HORIZONTALFLIP 0x400 /// \brief Frame flags: Thin, paper-like sprite (for collision equivalent, see MF_PAPERCOLLISION) #define FF_PAPERSPRITE 0x800 -/// \brief Frame flags: Simple stateless animation -#define FF_ANIMATE 0x4000 -/// \brief Frame flags: frame always appears full bright -#define FF_FULLBRIGHT 0x8000 + +/// \brief Frame flags: blend types +#define FF_BLENDMASK 0x7000 +/// \brief shift for FF_BLENDMASK +#define FF_BLENDSHIFT 12 +/// \brief preshifted blend flags minus 1 as effects don't distinguish between AST_COPY and AST_TRANSLUCENT +#define FF_ADD ((AST_ADD-1)<mirrored = 0; // Sprite Rendering stuff + mobj->blendmode = AST_TRANSLUCENT; mobj->spritexoffset = 0; mobj->spriteyoffset = 0; mobj->spritexscale = FRACUNIT; diff --git a/src/r_data.c b/src/r_data.c index 98431510d..b88554c9f 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -126,6 +126,113 @@ size_t flatmemory, spritememory, texturememory; // gotta play by 2.2 rules to ge INT16 color8to16[256]; // remap color index to highcolor rgb value INT16 *hicolormaps; // test a 32k colormap remaps high -> high +// Blends two pixels together, using the equation +// that matches the specified alpha style. +UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) +{ + RGBA_t output; + INT16 fullalpha = (alpha - (0xFF - foreground.s.alpha)); + if (style == AST_TRANSLUCENT) + { + if (fullalpha <= 0) + output.rgba = background.rgba; + else + { + // don't go too high + if (fullalpha >= 0xFF) + fullalpha = 0xFF; + alpha = (UINT8)fullalpha; + + // if the background pixel is empty, + // match software and don't blend anything + if (!background.s.alpha) + { + // ...unless the foreground pixel ISN'T actually translucent. + if (alpha == 0xFF) + output.rgba = foreground.rgba; + else + output.rgba = 0; + } + else + { + UINT8 beta = (0xFF - alpha); + output.s.red = ((background.s.red * beta) + (foreground.s.red * alpha)) / 0xFF; + output.s.green = ((background.s.green * beta) + (foreground.s.green * alpha)) / 0xFF; + output.s.blue = ((background.s.blue * beta) + (foreground.s.blue * alpha)) / 0xFF; + output.s.alpha = 0xFF; + } + } + return output.rgba; + } +#define clamp(c) max(min(c, 0xFF), 0x00); + else + { + float falpha = ((float)alpha / 256.0f); + float fr = ((float)foreground.s.red * falpha); + float fg = ((float)foreground.s.green * falpha); + float fb = ((float)foreground.s.blue * falpha); + if (style == AST_ADD) + { + output.s.red = clamp((int)(background.s.red + fr)); + output.s.green = clamp((int)(background.s.green + fg)); + output.s.blue = clamp((int)(background.s.blue + fb)); + } + else if (style == AST_SUBTRACT) + { + output.s.red = clamp((int)(background.s.red - fr)); + output.s.green = clamp((int)(background.s.green - fg)); + output.s.blue = clamp((int)(background.s.blue - fb)); + } + else if (style == AST_REVERSESUBTRACT) + { + output.s.red = clamp((int)((-background.s.red) + fr)); + output.s.green = clamp((int)((-background.s.green) + fg)); + output.s.blue = clamp((int)((-background.s.blue) + fb)); + } + else if (style == AST_MODULATE) + { + fr = ((float)foreground.s.red / 256.0f); + fg = ((float)foreground.s.green / 256.0f); + fb = ((float)foreground.s.blue / 256.0f); + output.s.red = clamp((int)(background.s.red * fr)); + output.s.green = clamp((int)(background.s.green * fg)); + output.s.blue = clamp((int)(background.s.blue * fb)); + } + // just copy the pixel + else if (style == AST_COPY) + output.rgba = foreground.rgba; + + output.s.alpha = 0xFF; + return output.rgba; + } +#undef clamp + return 0; +} + +INT32 ASTTextureBlendingThreshold[2] = {255/11, (10*255/11)}; + +// Blends a pixel for a texture patch. +UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) +{ + // Alpha style set to translucent? + if (style == AST_TRANSLUCENT) + { + // Is the alpha small enough for translucency? + if (alpha <= ASTTextureBlendingThreshold[1]) + { + // Is the patch way too translucent? Don't blend then. + if (alpha < ASTTextureBlendingThreshold[0]) + return background.rgba; + + return ASTBlendPixel(background, foreground, style, alpha); + } + else // just copy the pixel + return foreground.rgba; + } + else + return ASTBlendPixel(background, foreground, style, alpha); +} + // Painfully simple texture id cacheing to make maps load faster. :3 static struct { char name[9]; diff --git a/src/r_data.h b/src/r_data.h index ec1146322..f27dd0822 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -56,6 +56,9 @@ extern INT32 *texturewidthmask; extern fixed_t *textureheight; // needed for texture pegging +UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); +UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); + extern INT16 color8to16[256]; // remap color index to highcolor extern INT16 *hicolormaps; // remap high colors to high colors.. diff --git a/src/r_defs.h b/src/r_defs.h index bc95649bb..7c063505c 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -687,6 +687,9 @@ typedef struct #pragma pack() #endif +// Possible alpha types for a patch. +enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; + typedef enum { SRF_SINGLE = 0, // 0-angle for all rotations diff --git a/src/r_draw.c b/src/r_draw.c index faa9ba638..d41e542a5 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -86,6 +86,7 @@ INT32 dc_sourcelength; #define NUMTRANSTABLES 9 // how many translucency tables are used UINT8 *transtables; // translucency tables +UINT8 *blendtables[NUMBLENDMAPS]; /** \brief R_DrawTransColumn uses this */ @@ -213,11 +214,11 @@ const UINT8 Color_Opposite[MAXSKINCOLORS*2] = CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; -/** \brief The R_InitTranslationTables +#define TRANSTAB_AMTMUL10 (256.0f / 10.0f) - load in color translation tables +/** \brief Initializes the translucency tables used by the Software renderer. */ -void R_InitTranslationTables(void) +void R_InitTranslucencyTables(void) { // Load here the transparency lookup tables 'TINTTAB' // NOTE: the TINTTAB resource MUST BE aligned on 64k for the asm @@ -234,6 +235,189 @@ void R_InitTranslationTables(void) W_ReadLump(W_GetNumForName("TRANS70"), transtables+0x60000); W_ReadLump(W_GetNumForName("TRANS80"), transtables+0x70000); W_ReadLump(W_GetNumForName("TRANS90"), transtables+0x80000); + + R_GenerateBlendTables(); +} + +static colorlookup_t transtab_lut; + +static void BlendTab_Translucent(UINT8 *table, int style, UINT8 blendamt) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("BlendTab_Translucent: input table was NULL!"); + + for (bg = 0; bg < 0xFF; bg++) + { + for (fg = 0; fg < 0xFF; fg++) + { + RGBA_t backrgba = V_GetColor(bg); + RGBA_t frontrgba = V_GetColor(fg); + RGBA_t result; + + 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 BlendTab_Subtractive(UINT8 *table, int style, UINT8 blendamt) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("BlendTab_Subtractive: input table was NULL!"); + + if (blendamt == 0xFF) + { + 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_GetColor(bg); + RGBA_t frontrgba = V_GetColor(fg); + RGBA_t result; + + result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF); + result.s.red = max(0, result.s.red - blendamt); + result.s.green = max(0, result.s.green - blendamt); + result.s.blue = max(0, result.s.blue - blendamt); + + table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); + } + } +} + +static void BlendTab_Modulative(UINT8 *table) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("BlendTab_Modulative: input table was NULL!"); + + for (bg = 0; bg < 0xFF; bg++) + { + for (fg = 0; fg < 0xFF; fg++) + { + RGBA_t backrgba = V_GetColor(bg); + RGBA_t frontrgba = V_GetColor(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 BlendTab_Count[NUMBLENDMAPS] = +{ + NUMTRANSTABLES, // blendtab_add + NUMTRANSTABLES+1, // blendtab_subtract + NUMTRANSTABLES+1, // blendtab_reversesubtract + 1 // blendtab_modulate +}; + +static INT32 BlendTab_FromStyle[] = +{ + 0, // AST_COPY + 0, // AST_TRANSLUCENT + blendtab_add, // AST_ADD + blendtab_subtract, // AST_SUBTRACT + blendtab_reversesubtract, // AST_REVERSESUBTRACT + blendtab_modulate, // AST_MODULATE + 0 // AST_OVERLAY +}; + +static void BlendTab_GenerateMaps(INT32 tab, INT32 style, void (*genfunc)(UINT8 *, int, UINT8)) +{ + INT32 i = 0, num = BlendTab_Count[tab]; + const float amtmul = (256.0f / (float)(NUMTRANSTABLES)); + for (; i < num; i++) + { + const size_t offs = (0x10000 * i); + const UINT16 alpha = min(amtmul * i, 0xFF); + genfunc(blendtables[tab] + offs, style, alpha); + } +} + +void R_GenerateBlendTables(void) +{ + INT32 i; + + for (i = 0; i < NUMBLENDMAPS; i++) + blendtables[i] = Z_MallocAlign(BlendTab_Count[i] * 0x10000, PU_STATIC, NULL, 16); + + InitColorLUT(&transtab_lut, pLocalPalette, false); + + // Additive + BlendTab_GenerateMaps(blendtab_add, AST_ADD, BlendTab_Translucent); + + // Subtractive +#if 1 + BlendTab_GenerateMaps(blendtab_subtract, AST_SUBTRACT, BlendTab_Subtractive); +#else + BlendTab_GenerateMaps(blendtab_subtract, AST_SUBTRACT, BlendTab_Translucent); +#endif + + // Reverse subtractive + BlendTab_GenerateMaps(blendtab_reversesubtract, AST_REVERSESUBTRACT, BlendTab_Translucent); + + // Modulative blending only requires a single table + BlendTab_Modulative(blendtables[blendtab_modulate]); +} + +#define ClipBlendLevel(style, trans) max(min((trans), BlendTab_Count[BlendTab_FromStyle[style]]-1), 0) +#define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0) + +UINT8 *R_GetTranslucencyTable(INT32 alphalevel) +{ + return transtables + (ClipTransLevel(alphalevel-1) << FF_TRANSSHIFT); +} + +UINT8 *R_GetBlendTable(int style, INT32 alphalevel) +{ + size_t offs; + + if (style == AST_COPY || style == AST_OVERLAY) + return NULL; + + offs = (ClipBlendLevel(style, alphalevel) << FF_TRANSSHIFT); + + // Lactozilla: Returns the equivalent to AST_TRANSLUCENT + // if no alpha style matches any of the blend tables. + switch (style) + { + case AST_ADD: + return blendtables[blendtab_add] + offs; + case AST_SUBTRACT: + return blendtables[blendtab_subtract] + offs; + case AST_REVERSESUBTRACT: + return blendtables[blendtab_reversesubtract] + offs; + case AST_MODULATE: + return blendtables[blendtab_modulate]; + default: + break; + } + + // Return a normal translucency table + if (--alphalevel >= 0) + return transtables + (ClipTransLevel(alphalevel) << FF_TRANSSHIFT); + else + return NULL; +} + +boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel) +{ + if (blendmode == AST_COPY || blendmode == AST_SUBTRACT || blendmode == AST_MODULATE || blendmode == AST_OVERLAY) + return true; + + return (alphalevel < BlendTab_Count[BlendTab_FromStyle[blendmode]]); } /** \brief Retrieves a translation colormap from the cache. diff --git a/src/r_draw.h b/src/r_draw.h index 7dbeda7c9..39587a696 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -40,7 +40,6 @@ extern UINT8 dc_hires; extern UINT8 *dc_source; // first pixel in a column // translucency stuff here -extern UINT8 *transtables; // translucency tables, should be (*transtables)[5][256][256] extern UINT8 *dc_transmap; // translation stuff here @@ -117,7 +116,6 @@ extern lumpnum_t viewborderlump[8]; #define TC_BLINK -6 // For item blinking // Initialize color translation tables, for player rendering etc. -void R_InitTranslationTables(void); UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags); UINT8* R_GetLocalTranslationColormap(skin_t *skin, skin_t *localskin, skincolors_t color, UINT8 flags, boolean local); patch_t* R_GetSkinFaceRank(player_t* ply); @@ -126,6 +124,27 @@ patch_t* R_GetSkinFaceMini(player_t* ply); void R_FlushTranslationColormapCache(void); UINT8 R_GetColorByName(const char *name); +extern UINT8 *transtables; // translucency tables, should be (*transtables)[5][256][256] + +enum +{ + blendtab_add, + blendtab_subtract, + blendtab_reversesubtract, + blendtab_modulate, + NUMBLENDMAPS +}; + +extern UINT8 *blendtables[NUMBLENDMAPS]; + +void R_InitTranslucencyTables(void); +void R_GenerateBlendTables(void); + +UINT8 *R_GetTranslucencyTable(INT32 alphalevel); +UINT8 *R_GetBlendTable(int style, INT32 alphalevel); + +boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel); + // Custom player skin translation void R_InitViewBuffer(INT32 width, INT32 height); void R_InitViewBorder(void); diff --git a/src/r_main.c b/src/r_main.c index 1c45d4112..9c90e108f 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1036,8 +1036,8 @@ void R_Init(void) //I_OutputMsg("\nR_InitLightTables"); R_InitLightTables(); - //I_OutputMsg("\nR_InitTranslationTables\n"); - R_InitTranslationTables(); + //I_OutputMsg("\nR_InitTranslucencyTables\n"); + R_InitTranslucencyTables(); R_InitDrawNodes(); diff --git a/src/r_plane.c b/src/r_plane.c index d8d77457f..9b13bb062 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -796,7 +796,7 @@ void R_DrawSinglePlane(visplane_t *pl) if (pl->polyobj->translucency >= 10) return; // Don't even draw it else if (pl->polyobj->translucency > 0) - ds_transmap = transtables + ((pl->polyobj->translucency-1)<polyobj->translucency); else // Opaque, but allow transparent flat pixels spanfunc = splatfunc; @@ -836,23 +836,23 @@ void R_DrawSinglePlane(visplane_t *pl) if (pl->ffloor->alpha < 12) return; // Don't even draw it else if (pl->ffloor->alpha < 38) - ds_transmap = transtables + ((tr_trans90-1)<ffloor->alpha < 64) - ds_transmap = transtables + ((tr_trans80-1)<ffloor->alpha < 89) - ds_transmap = transtables + ((tr_trans70-1)<ffloor->alpha < 115) - ds_transmap = transtables + ((tr_trans60-1)<ffloor->alpha < 140) - ds_transmap = transtables + ((tr_trans50-1)<ffloor->alpha < 166) - ds_transmap = transtables + ((tr_trans40-1)<ffloor->alpha < 192) - ds_transmap = transtables + ((tr_trans30-1)<ffloor->alpha < 217) - ds_transmap = transtables + ((tr_trans20-1)<ffloor->alpha < 243) - ds_transmap = transtables + ((tr_trans10-1)<special-900)<special-899)); colfunc = fuzzcolfunc; break; case 909: @@ -343,7 +343,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (curline->polyseg->translucency >= NUMTRANSMAPS) return; - dc_transmap = transtables + ((curline->polyseg->translucency-1)<polyseg->translucency); colfunc = fuzzcolfunc; } @@ -714,23 +714,23 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (pfloor->alpha < 12) return; // Don't even draw it else if (pfloor->alpha < 38) - dc_transmap = transtables + ((tr_trans90-1)<alpha < 64) - dc_transmap = transtables + ((tr_trans80-1)<alpha < 89) - dc_transmap = transtables + ((tr_trans70-1)<alpha < 115) - dc_transmap = transtables + ((tr_trans60-1)<alpha < 140) - dc_transmap = transtables + ((tr_trans50-1)<alpha < 166) - dc_transmap = transtables + ((tr_trans40-1)<alpha < 192) - dc_transmap = transtables + ((tr_trans30-1)<alpha < 217) - dc_transmap = transtables + ((tr_trans20-1)<alpha < 243) - dc_transmap = transtables + ((tr_trans10-1)<extra_colormap = sector->lightlist[i].extra_colormap; - if (!((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK) || thing->flags2 & MF2_SHADOW) + if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1)))) { lindex = FixedMul(sprite->xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT); @@ -1040,6 +1040,9 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) // Mitigate against negative xscale and arithmetic overflow lindex = CLAMP(lindex, 0, MAXLIGHTSCALE - 1); + if (newsprite->cut & SC_SEMIBRIGHT) + lindex = (MAXLIGHTSCALE/2) + (lindex >>1); + newsprite->colormap = spritelights[lindex]; } } @@ -1138,6 +1141,7 @@ static void R_ProjectSprite(mobj_t *thing) boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); INT32 lindex; + INT32 trans; vissprite_t *vis; @@ -1535,6 +1539,24 @@ static void R_ProjectSprite(mobj_t *thing) return; } + INT32 blendmode; + if (oldthing->frame & FF_BLENDMASK) + blendmode = ((oldthing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = oldthing->blendmode; + + // Determine the translucency value. + if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) + trans = tr_trans80; // because now the translucency is set through FF_TRANSMASK + else if (oldthing->frame & FF_TRANSMASK) + { + trans = (oldthing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; + if (!R_BlendLevelVisible(blendmode, trans)) + return; + } + else + trans = 0; + //SoM: 3/17/2000: Disregard sprites that are out of view.. if (thing->eflags & MFE_VERTICALFLIP) { @@ -1661,6 +1683,18 @@ static void R_ProjectSprite(mobj_t *thing) vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1); } + if ((blendmode != AST_COPY) && cv_translucency.value) + vis->transmap = R_GetBlendTable(blendmode, trans); + else + vis->transmap = NULL; + + if (R_ThingIsFullBright(oldthing) || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) + vis->cut |= SC_FULLBRIGHT; + else if (R_ThingIsSemiBright(oldthing)) + vis->cut |= SC_SEMIBRIGHT; + else if (R_ThingIsFullDark(oldthing)) + vis->cut |= SC_FULLDARK; + //Fab: lumppat is the lump number of the patch to use, this is different // than lumpid for sprites-in-pwad : the graphics are patched #ifdef ROTSPRITE @@ -1670,25 +1704,18 @@ static void R_ProjectSprite(mobj_t *thing) #endif vis->patch = W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); -// -// determine the colormap (lightlevel & special effects) -// - vis->transmap = NULL; + // + // determine the colormap (lightlevel & special effects) + // - // specific translucency - if (!cv_translucency.value) - ; // no translucency - else if (thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) - vis->transmap = transtables + ((tr_trans80-1)<frame & FF_TRANSMASK) - vis->transmap = transtables + (thing->frame & FF_TRANSMASK) - 0x10000; - - if (((thing->frame & FF_FULLBRIGHT) || (thing->flags2 & MF2_SHADOW)) + if ((vis->cut & SC_FULLBRIGHT) && (!vis->extra_colormap || !(vis->extra_colormap->fog & 1))) { // full bright: goggles vis->colormap = colormaps; } + else if (vis->cut & SC_FULLDARK) + vis->colormap = scalelight[0][0]; else { // diminished light @@ -1697,6 +1724,9 @@ static void R_ProjectSprite(mobj_t *thing) // Mitigate against negative xscale and arithmetic overflow lindex = CLAMP(lindex, 0, MAXLIGHTSCALE - 1); + if (vis->cut & SC_SEMIBRIGHT) + lindex = (MAXLIGHTSCALE/2) + (lindex >> 1); + vis->colormap = spritelights[lindex]; } @@ -1738,6 +1768,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) fixed_t this_scale; INT32 dist = 1; + INT32 trans; if (cv_maxinterpdist.value) dist = R_QuickCamDist(thing->x, thing->y); @@ -1838,6 +1869,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; } + // Determine the translucency value. + if (thing->frame & FF_TRANSMASK) + trans = (thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; + else + trans = 0; + //SoM: 3/17/2000: Disregard sprites that are out of view.. gzt = interp.z + FixedMul(spritecachedinfo[lump].topoffset, this_scale); gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale); @@ -1886,8 +1923,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); // specific translucency - if (thing->frame & FF_TRANSMASK) - vis->transmap = (thing->frame & FF_TRANSMASK) - 0x10000 + transtables; + if ((thing->blendmode != AST_COPY) && cv_translucency.value) + vis->transmap = R_GetTranslucencyTable((thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT); else vis->transmap = NULL; @@ -2788,6 +2825,21 @@ boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist) return true; } +boolean R_ThingIsFullBright(mobj_t *thing) +{ + return ((thing->frame & FF_BRIGHTMASK) == FF_FULLBRIGHT); +} + +boolean R_ThingIsSemiBright(mobj_t *thing) +{ + return ((thing->frame & FF_BRIGHTMASK) == FF_SEMIBRIGHT); +} + +boolean R_ThingIsFullDark(mobj_t *thing) +{ + return ((thing->frame & FF_BRIGHTMASK) == FF_FULLDARK); +} + // // R_DrawMasked // diff --git a/src/r_things.h b/src/r_things.h index 898cc7ecd..899400598 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -76,6 +76,10 @@ void R_DrawMasked(void); boolean R_ThingVisible (mobj_t *thing); boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist); +boolean R_ThingIsFullBright (mobj_t *thing); +boolean R_ThingIsSemiBright (mobj_t *thing); +boolean R_ThingIsFullDark (mobj_t *thing); + // ----------- // SKINS STUFF // ----------- @@ -128,6 +132,9 @@ typedef enum SC_BOTTOM = 2, SC_VFLIP = 3, SC_NOTVISIBLE = 4, + SC_FULLBRIGHT = 8, + SC_SEMIBRIGHT = 16, + SC_FULLDARK = 32, SC_CUTMASK = SC_TOP|SC_BOTTOM|SC_NOTVISIBLE, SC_FLAGMASK = ~SC_CUTMASK } spritecut_e; diff --git a/src/v_video.c b/src/v_video.c index d2604b5e8..02a37798e 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -635,10 +635,11 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix } // Draws a patch scaled to arbitrary size. -void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap) +void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, INT32 bflags) { UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); - UINT32 alphalevel = 0; + UINT32 alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT); + UINT32 blendmode = ((bflags & V_BLENDMASK) >> V_BLENDSHIFT); fixed_t col, ofs, colfrac, rowfrac, fdup, vdup; INT32 dupx, dupy; @@ -655,7 +656,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca //if (rendermode != render_soft && !con_startup) // Why? if (rendermode == render_opengl) { - HWR_DrawStretchyFixedPatch((GLPatch_t *)patch, x, y, pscale, vscale, scrn, colormap); + HWR_DrawStretchyFixedPatch((GLPatch_t *)patch, x, y, pscale, vscale, scrn, colormap, bflags); return; } #endif @@ -663,7 +664,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca patchdrawfunc = standardpdraw; v_translevel = NULL; - if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT))) + if (alphalevel || blendmode) { if (alphalevel == 13) alphalevel = hudminusalpha[hudtrans]; @@ -675,9 +676,9 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (alphalevel >= 10) return; // invis - if (alphalevel) + if (alphalevel || blendmode) { - v_translevel = transtables + ((alphalevel-1)<init || memcmp(lut->palette, palette, palsize)) { - for (r = 0; r < CLUTSIZE; r++) - for (g = 0; g < CLUTSIZE; g++) - for (b = 0; b < CLUTSIZE; b++) - colorlookup[r][g][b] = NearestColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS); - clutinit = true; - lastpalette = pLocalPalette; + INT32 i; + + lut->init = true; + memcpy(lut->palette, palette, palsize); + + for (i = 0; i < 0xFFFF; i++) + lut->table[i] = 0xFFFF; + + if (makecolors) + { + UINT8 r, g, b; + + for (r = 0; r < 0xFF; r++) + for (g = 0; g < 0xFF; g++) + for (b = 0; b < 0xFF; b++) + { + i = CLUTINDEX(r, g, b); + if (lut->table[i] == 0xFFFF) + lut->table[i] = NearestPaletteColor(r, g, b, palette); + } + } } } +UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b) +{ + INT32 i = CLUTINDEX(r, g, b); + if (lut->table[i] == 0xFFFF) + lut->table[i] = NearestPaletteColor(r, g, b, lut->palette); + return lut->table[i]; +} + +UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b) +{ + INT32 i = CLUTINDEX(r, g, b); + return lut->table[i]; +} + // V_Init // old software stuff, buffers are allocated at video mode setup // here we set the screens[x] pointers accordingly diff --git a/src/v_video.h b/src/v_video.h index a06760215..6b07bbb65 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -37,17 +37,19 @@ cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, // Allocates buffer screens, call before R_Init. void V_Init(void); -// Taken from my videos-in-SRB2 project -// Generates a color look-up table -// which has up to 64 colors at each channel +// Color look-up table +#define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) -#define COLORBITS 6 -#define SHIFTCOLORBITS (8-COLORBITS) -#define CLUTSIZE (1< Date: Sun, 2 Feb 2025 21:14:48 -0500 Subject: [PATCH 2/6] Prelim: Linedef alpha variable realistically this was just because I'm Lazy this makes figuring out linedef blending less of a brain twister --- src/hardware/hw_main.c | 32 +++--------------------- src/lua_maplib.c | 5 ++++ src/p_setup.c | 13 ++++++++++ src/r_defs.h | 2 ++ src/r_segs.c | 56 ++++++++++++++++++++++++++---------------- src/r_segs.h | 1 + 6 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 1fd05d947..10d3c8c23 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1208,33 +1208,6 @@ static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) // set alpha for transparent walls switch (gl_linedef->special) { - case 900: - blendmode = HWR_TranstableToAlpha(tr_trans10, pSurf); - break; - case 901: - blendmode = HWR_TranstableToAlpha(tr_trans20, pSurf); - break; - case 902: - blendmode = HWR_TranstableToAlpha(tr_trans30, pSurf); - break; - case 903: - blendmode = HWR_TranstableToAlpha(tr_trans40, pSurf); - break; - case 904: - blendmode = HWR_TranstableToAlpha(tr_trans50, pSurf); - break; - case 905: - blendmode = HWR_TranstableToAlpha(tr_trans60, pSurf); - break; - case 906: - blendmode = HWR_TranstableToAlpha(tr_trans70, pSurf); - break; - case 907: - blendmode = HWR_TranstableToAlpha(tr_trans80, pSurf); - break; - case 908: - blendmode = HWR_TranstableToAlpha(tr_trans90, pSurf); - break; // Translucent case 102: case 121: @@ -1255,7 +1228,10 @@ static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) blendmode = PF_Translucent; break; default: - blendmode = PF_Masked; + if (gl_linedef->alpha > 0 && gl_linedef->alpha < FRACUNIT) + blendmode = HWR_TranstableToAlpha(R_GetLinedefTransTable(gl_linedef->alpha), pSurf); + else + blendmode = PF_Masked; break; } } diff --git a/src/lua_maplib.c b/src/lua_maplib.c index a6bca2ff6..c1442b98c 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -94,6 +94,7 @@ enum line_e { line_sidenum, line_frontside, line_backside, + line_alpha, line_slopetype, line_frontsector, line_backsector, @@ -115,6 +116,7 @@ static const char *const line_opt[] = { "sidenum", "frontside", "backside", + "alpha", "slopetype", "frontsector", "backsector", @@ -652,6 +654,9 @@ static int line_get(lua_State *L) return 0; LUA_PushUserdata(L, &sides[line->sidenum[1]], META_SIDE); return 1; + case line_alpha: + lua_pushfixed(L, line->alpha); + return 1; case line_slopetype: switch(line->slopetype) { diff --git a/src/p_setup.c b/src/p_setup.c index ce1dd6efb..751ba94f0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1071,6 +1071,8 @@ static void P_SetupLines(void) ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; + ld->alpha = FRACUNIT; + if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) @@ -1177,6 +1179,17 @@ static void P_LoadLineDefs2(void) M_Memcpy(ld->text+strlen(ld->text)+1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text)+1); } break; + case 900: //Translucent wall (10%) + case 901: //Translucent wall (20%) + case 902: //Translucent wall (30%) + case 903: //Translucent wall (40%) + case 904: //Translucent wall (50%) + case 905: //Translucent wall (60%) + case 906: //Translucent wall (70%) + case 907: //Translucent wall (80%) + case 908: //Translucent wall (90%) + ld->alpha = ((909 - ld->special) << FRACBITS)/10; + break; } } } diff --git a/src/r_defs.h b/src/r_defs.h index 7c063505c..58cd0f1b1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -402,6 +402,8 @@ typedef struct line_s // Visual appearance: sidedefs. UINT16 sidenum[2]; // sidenum[1] will be 0xffff if one-sided + fixed_t alpha; // translucency + UINT8 blendmode; // blendmode fixed_t bbox[4]; // bounding box for the extent of the linedef diff --git a/src/r_segs.c b/src/r_segs.c index 86a1ff1cf..b0cfc494e 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -287,6 +287,28 @@ static void R_Render2sidedMultiPatchColumn(column_t *column) } } +transnum_t R_GetLinedefTransTable(fixed_t alpha) +{ + if (alpha < 9830) + return tr_trans90; + else if (alpha < 16384) + return tr_trans80; + else if (alpha < 22937) + return tr_trans70; + else if (alpha < 29491) + return tr_trans60; + else if (alpha < 36044) + return tr_trans50; + else if (alpha < 42598) + return tr_trans40; + else if (alpha < 49152) + return tr_trans30; + else if (alpha < 55705) + return tr_trans20; + else + return tr_trans10; +} + void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { size_t pindex; @@ -314,28 +336,20 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // hack translucent linedef types (900-909 for transtables 1-9) ldef = curline->linedef; - switch (ldef->special) + if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) { - case 900: - case 901: - case 902: - case 903: - case 904: - case 905: - case 906: - case 907: - case 908: - dc_transmap = R_GetTranslucencyTable((ldef->special-899)); - colfunc = fuzzcolfunc; - break; - case 909: - colfunc = R_DrawFogColumn_8; - windowtop = frontsector->ceilingheight; - windowbottom = frontsector->floorheight; - break; - default: - colfunc = wallcolfunc; - break; + dc_transmap = transtables + ((R_GetLinedefTransTable(ldef->alpha) - 1) << FF_TRANSSHIFT); + colfunc = fuzzcolfunc; + } + else if (ldef->special == 909) + { + colfunc = R_DrawFogColumn_8; + windowtop = frontsector->ceilingheight; + windowbottom = frontsector->floorheight; + } + else + { + colfunc = wallcolfunc; } if (curline->polyseg && curline->polyseg->translucency > 0) diff --git a/src/r_segs.h b/src/r_segs.h index 92d0100e2..006e81279 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -18,6 +18,7 @@ #pragma interface #endif +transnum_t R_GetLinedefTransTable(fixed_t alpha); void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2); void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pffloor); void R_StoreWallRange(INT32 start, INT32 stop); -- 2.54.0 From d39e9447f32463e3e51d09a3250024ed262c3734 Mon Sep 17 00:00:00 2001 From: Chearii Date: Mon, 3 Feb 2025 04:46:27 -0500 Subject: [PATCH 3/6] Add line and FOF blending, fix model and shadow blending also a bit of cleanup in r_things but it's too minor to headline --- src/hardware/hw_main.c | 51 +++++++++++++++++++++++++++++------------- src/hardware/hw_md2.c | 17 ++++++++++---- src/lua_maplib.c | 8 +++++++ src/p_mobj.c | 1 + src/p_setup.c | 38 ++++++++++++++++++++----------- src/p_spec.c | 22 ++++++++++++++++-- src/r_defs.h | 1 + src/r_plane.c | 33 +++++++++------------------ src/r_segs.c | 47 +++++++++++++++++++------------------- src/r_things.c | 7 ------ 10 files changed, 138 insertions(+), 87 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 10d3c8c23..ccd292cf3 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1225,10 +1225,20 @@ static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) case 221: case 253: case 256: - blendmode = PF_Translucent; + if (gl_linedef->blendmode) + blendmode = HWR_SurfaceBlend(gl_linedef->blendmode, R_GetLinedefTransTable(gl_linedef->alpha), pSurf); + else + blendmode = PF_Translucent; break; default: - if (gl_linedef->alpha > 0 && gl_linedef->alpha < FRACUNIT) + if (gl_linedef->blendmode) + { + if (gl_linedef->alpha >= 0 && gl_linedef->alpha < FRACUNIT) + blendmode = HWR_SurfaceBlend(gl_linedef->blendmode, R_GetLinedefTransTable(gl_linedef->alpha), pSurf); + else + blendmode = HWR_GetBlendModeFlag(gl_linedef->blendmode); + } + else if (gl_linedef->alpha >= 0 && gl_linedef->alpha < FRACUNIT) blendmode = HWR_TranstableToAlpha(R_GetLinedefTransTable(gl_linedef->alpha), pSurf); else blendmode = PF_Masked; @@ -1777,7 +1787,9 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope); if (gl_frontsector->numlights) + { HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, &Surf, FF_CUTLEVEL, NULL, 0); + } else // I don't think that solid walls can use translucent linedef types... { if (glTex->mipmap.flags & TF_TRANSPARENT) @@ -1958,7 +1970,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gl_curline); if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, 0, false, &Surf, rover->flags, rover, 0); + HWR_SplitWall(gl_frontsector, wallVerts, 0, false, &Surf, rover->flags, rover, blendmode); else HWR_AddTransparentWall(wallVerts, &Surf, 0, false, blendmode, true, lightnum, colormap); } @@ -1966,14 +1978,14 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { FBITFIELD blendmode = PF_Masked; - if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) + if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { - blendmode = PF_Translucent; + blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; Surf.PolyColor.s.alpha = CLAMP(rover->alpha, 0, 255); } if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, texnum, noencore, &Surf, rover->flags, rover, 0); + HWR_SplitWall(gl_frontsector, wallVerts, texnum, noencore, &Surf, rover->flags, rover, blendmode); else { if (blendmode != PF_Masked) @@ -2073,7 +2085,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gl_curline); if (gl_backsector->numlights) - HWR_SplitWall(gl_backsector, wallVerts, 0, false, &Surf, rover->flags, rover, 0); + HWR_SplitWall(gl_backsector, wallVerts, 0, false, &Surf, rover->flags, rover, blendmode); else HWR_AddTransparentWall(wallVerts, &Surf, 0, false, blendmode, true, lightnum, colormap); } @@ -2081,14 +2093,14 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { FBITFIELD blendmode = PF_Masked; - if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) + if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { - blendmode = PF_Translucent; + blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; Surf.PolyColor.s.alpha = CLAMP(rover->alpha, 0, 255); } if (gl_backsector->numlights) - HWR_SplitWall(gl_backsector, wallVerts, texnum, noencore, &Surf, rover->flags, rover, 0); + HWR_SplitWall(gl_backsector, wallVerts, texnum, noencore, &Surf, rover->flags, rover, blendmode); else { if (blendmode != PF_Masked) @@ -2797,6 +2809,13 @@ static inline void HWR_PortalSubsector(seg_t *line, subsector_t *sub, INT16 coun sub->validcount = validcount; } +static FBITFIELD HWR_RippleBlend(sector_t *sector, ffloor_t *rover, boolean ceiling) +{ + (void)sector; + (void)ceiling; + return /*R_IsRipplePlane(sector, rover, ceiling)*/ (rover->flags & FF_RIPPLE) ? PF_Ripple : 0; +} + // -----------------+ // HWR_Subsector : Determine floor/ceiling planes. // : Add sprites of things in sector. @@ -2981,7 +3000,7 @@ static void HWR_Subsector(size_t num) alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } - else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient + else if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) // SoM: Flags are more efficient { light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); @@ -2990,7 +3009,7 @@ static void HWR_Subsector(size_t num) false, *rover->bottomheight, *gl_frontsector->lightlist[light].lightlevel, - CLAMP(rover->alpha, 0 ,255), rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, + CLAMP(rover->alpha, 0 ,255), rover->master->frontsector, HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), false, gl_frontsector->lightlist[light].extra_colormap); } else @@ -2998,7 +3017,7 @@ static void HWR_Subsector(size_t num) HWR_GetFlat(levelflats[*rover->bottompic].lumpnum, R_NoEncore(gl_frontsector, false)); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); - HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum, + HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum, rover->master->frontsector, 255, gl_frontsector->lightlist[light].extra_colormap); } } @@ -3027,7 +3046,7 @@ static void HWR_Subsector(size_t num) alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } - else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) + else if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); @@ -3036,7 +3055,7 @@ static void HWR_Subsector(size_t num) true, *rover->topheight, *gl_frontsector->lightlist[light].lightlevel, - CLAMP(rover->alpha, 0 ,255), rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, + CLAMP(rover->alpha, 0 ,255), rover->master->frontsector, HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), false, gl_frontsector->lightlist[light].extra_colormap); } else @@ -3044,7 +3063,7 @@ static void HWR_Subsector(size_t num) HWR_GetFlat(levelflats[*rover->toppic].lumpnum, R_NoEncore(gl_frontsector, true)); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); - HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum, + HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum, rover->master->frontsector, 255, gl_frontsector->lightlist[light].extra_colormap); } } diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 5622497dc..1130745aa 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1178,21 +1178,30 @@ void HWR_DrawMD2(gl_vissprite_t *spr) // Apparently people don't like jump frames like that, so back it goes //if (tics > durs) //durs = tics; + + INT32 blendmode; + if (spr->mobj->frame & FF_BLENDMASK) + blendmode = ((spr->mobj->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = spr->mobj->blendmode; + + blendmode = min(AST_MODULATE, blendmode); if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - Surf.PolyFlags = HWR_GetBlendModeFlag(spr->mobj->blendmode); + Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) { HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); - Surf.PolyFlags = HWR_SurfaceBlend(spr->mobj->blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + Surf.PolyFlags = HWR_SurfaceBlend(blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); } else { - Surf.PolyColor.s.alpha = 0xFF; - Surf.PolyFlags = 0; + // this hack is dumb, but the blendmodes refuse to work otherwise + Surf.PolyColor.s.alpha = (blendmode == AST_TRANSLUCENT) ? 0xFF : 0xFE; + Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode); } // dont forget to enabled the depth test because we can't do this like diff --git a/src/lua_maplib.c b/src/lua_maplib.c index c1442b98c..c4718ae90 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -188,6 +188,7 @@ enum ffloor_e { ffloor_next, ffloor_prev, ffloor_alpha, + ffloor_blend, }; static const char *const ffloor_opt[] = { @@ -206,6 +207,7 @@ static const char *const ffloor_opt[] = { "next", "prev", "alpha", + "blend", NULL}; static int ffloor_fields_ref = LUA_NOREF; @@ -1173,6 +1175,9 @@ static int ffloor_get(lua_State *L) case ffloor_alpha: lua_pushinteger(L, ffloor->alpha); return 1; + case ffloor_blend: + lua_pushinteger(L, ffloor->blend); + return 1; } return 0; } @@ -1251,6 +1256,9 @@ static int ffloor_set(lua_State *L) case ffloor_alpha: ffloor->alpha = (INT32)luaL_checkinteger(L, 3); break; + case ffloor_blend: + ffloor->blend = (INT32)luaL_checkinteger(L, 3); + break; } return 0; } diff --git a/src/p_mobj.c b/src/p_mobj.c index a916190a9..ed5f0a578 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9837,6 +9837,7 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) mobj->radius = info->radius; mobj->height = info->height; mobj->flags = info->flags; + mobj->blendmode = AST_TRANSLUCENT; mobj->health = info->spawnhealth; diff --git a/src/p_setup.c b/src/p_setup.c index 751ba94f0..124b57504 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1072,6 +1072,7 @@ static void P_SetupLines(void) ld->dy = v2->y - v1->y; ld->alpha = FRACUNIT; + ld->blendmode = 0; if (!ld->dx) ld->slopetype = ST_VERTICAL; @@ -1179,18 +1180,27 @@ static void P_LoadLineDefs2(void) M_Memcpy(ld->text+strlen(ld->text)+1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text)+1); } break; - case 900: //Translucent wall (10%) - case 901: //Translucent wall (20%) - case 902: //Translucent wall (30%) - case 903: //Translucent wall (40%) - case 904: //Translucent wall (50%) - case 905: //Translucent wall (60%) - case 906: //Translucent wall (70%) - case 907: //Translucent wall (80%) - case 908: //Translucent wall (90%) - ld->alpha = ((909 - ld->special) << FRACBITS)/10; - break; } + + // Set alpha for translucent walls + if (ld->special >= 900 && ld->special < 909) + ld->alpha = ((909 - ld->special) << FRACBITS)/10; + + // Set alpha for additive/subtractive/reverse subtractive walls + if (ld->special >= 910 && ld->special <= 939) + ld->alpha = ((10 - ld->special % 10) << FRACBITS)/10; + + if (ld->special >= 910 && ld->special <= 919) // additive + ld->blendmode = AST_ADD; + + if (ld->special >= 920 && ld->special <= 929) // subtractive + ld->blendmode = AST_SUBTRACT; + + if (ld->special >= 930 && ld->special <= 939) // reverse subtractive + ld->blendmode = AST_REVERSESUBTRACT; + + if (ld->special == 940) // modulate + ld->blendmode = AST_MODULATE; } } @@ -1469,8 +1479,10 @@ static void P_LoadRawSideDefs2(void *data) if (msd->toptexture[0] == '#') { char *col = msd->toptexture; - sd->toptexture = sd->bottomtexture = - ((col[1]-'0')*100 + (col[2]-'0')*10 + col[3]-'0') + 1; + sd->toptexture = + ((col[1]-'0')*100 + (col[2]-'0')*10 + col[3]-'0')+1; + if (col[4]) // extra num for blendmode + sd->toptexture += (col[4]-'0')*1000; sd->midtexture = R_TextureNumForName(msd->midtexture); } else diff --git a/src/p_spec.c b/src/p_spec.c index 997cc437c..518a411eb 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4807,16 +4807,34 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f else th = th->next; } - if (flags & FF_TRANSLUCENT) { if (sides[master->sidenum[0]].toptexture > 0) - ffloor->alpha = sides[master->sidenum[0]].toptexture; // for future reference, "#0" is 1, and "#255" is 256. Be warned + { + // for future reference, "#0" is 1, and "#255" is 256. Be warned + ffloor->alpha = sides[master->sidenum[0]].toptexture; + + if (ffloor->alpha >= 1001) // fourth digit + { + ffloor->blend = (ffloor->alpha/1000)+1; // becomes an AST + ffloor->alpha %= 1000; + } + else + { + ffloor->blend = 0; + } + } else + { ffloor->alpha = 0x80; + ffloor->blend = 0; + } } else + { ffloor->alpha = 0xff; + ffloor->blend = 0; + } ffloor->spawnalpha = ffloor->alpha; // save for netgames diff --git a/src/r_defs.h b/src/r_defs.h index 58cd0f1b1..c3f14236e 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -172,6 +172,7 @@ typedef struct ffloor_s INT32 lastlight; INT32 alpha; + UINT8 blend; // blendmode tic_t norender; // for culling // these are saved for netgames, so do not let Lua touch these! diff --git a/src/r_plane.c b/src/r_plane.c index 9b13bb062..9a3facce2 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -833,28 +833,17 @@ void R_DrawSinglePlane(visplane_t *pl) spanfunc = R_DrawTranslucentSpan_8; // Hacked up support for alpha value in software mode Tails 09-24-2002 - if (pl->ffloor->alpha < 12) - return; // Don't even draw it - else if (pl->ffloor->alpha < 38) - ds_transmap = R_GetTranslucencyTable(tr_trans90); - else if (pl->ffloor->alpha < 64) - ds_transmap = R_GetTranslucencyTable(tr_trans80); - else if (pl->ffloor->alpha < 89) - ds_transmap = R_GetTranslucencyTable(tr_trans70); - else if (pl->ffloor->alpha < 115) - ds_transmap = R_GetTranslucencyTable(tr_trans60); - else if (pl->ffloor->alpha < 140) - ds_transmap = R_GetTranslucencyTable(tr_trans50); - else if (pl->ffloor->alpha < 166) - ds_transmap = R_GetTranslucencyTable(tr_trans40); - else if (pl->ffloor->alpha < 192) - ds_transmap = R_GetTranslucencyTable(tr_trans30); - else if (pl->ffloor->alpha < 217) - ds_transmap = R_GetTranslucencyTable(tr_trans20); - else if (pl->ffloor->alpha < 243) - ds_transmap = R_GetTranslucencyTable(tr_trans10); - else // Opaque, but allow transparent flat pixels - spanfunc = splatfunc; + // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 + // and mercilessly shoved into saturn by chearii 02-02-2025 + { + INT32 trans = (10*((256+12) - pl->ffloor->alpha))/255; + if (trans >= 10) + return; // Don't even draw it + if (pl->ffloor->blend) // additive, (reverse) subtractive, modulative + ds_transmap = R_GetBlendTable(pl->ffloor->blend, trans); + else if (!(ds_transmap = R_GetTranslucencyTable(trans)) || trans == 0) + spanfunc = splatfunc; // Opaque, but allow transparent flat pixels + } #ifdef SHITPLANESPARENCY if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog)) diff --git a/src/r_segs.c b/src/r_segs.c index b0cfc494e..b9c1277ab 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -336,7 +336,19 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // hack translucent linedef types (900-909 for transtables 1-9) ldef = curline->linedef; - if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) + + if (!ldef->alpha) + return; + + if (ldef->blendmode) + { + if (ldef->alpha == NUMTRANSMAPS || ldef->blendmode == AST_MODULATE) + dc_transmap = R_GetBlendTable(ldef->blendmode, 0); + else + dc_transmap = R_GetBlendTable(ldef->blendmode, R_GetLinedefTransTable(ldef->alpha)); + colfunc = fuzzcolfunc; + } + else if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) { dc_transmap = transtables + ((R_GetLinedefTransTable(ldef->alpha) - 1) << FF_TRANSSHIFT); colfunc = fuzzcolfunc; @@ -725,28 +737,17 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) boolean fuzzy = true; // Hacked up support for alpha value in software mode Tails 09-24-2002 - if (pfloor->alpha < 12) - return; // Don't even draw it - else if (pfloor->alpha < 38) - dc_transmap = R_GetTranslucencyTable(tr_trans90); - else if (pfloor->alpha < 64) - dc_transmap = R_GetTranslucencyTable(tr_trans80); - else if (pfloor->alpha < 89) - dc_transmap = R_GetTranslucencyTable(tr_trans70); - else if (pfloor->alpha < 115) - dc_transmap = R_GetTranslucencyTable(tr_trans60); - else if (pfloor->alpha < 140) - dc_transmap = R_GetTranslucencyTable(tr_trans50); - else if (pfloor->alpha < 166) - dc_transmap = R_GetTranslucencyTable(tr_trans40); - else if (pfloor->alpha < 192) - dc_transmap = R_GetTranslucencyTable(tr_trans30); - else if (pfloor->alpha < 217) - dc_transmap = R_GetTranslucencyTable(tr_trans20); - else if (pfloor->alpha < 243) - dc_transmap = R_GetTranslucencyTable(tr_trans10); - else - fuzzy = false; // Opaque + // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 + // and mercilessly shoved into saturn by chearii 02-02-2025 + { + INT32 trans = (10*((256+12) - pfloor->alpha))/255; + if (trans >= 10) + return; // Don't even draw it + if (pfloor->blend) // additive, (reverse) subtractive, modulative + dc_transmap = R_GetBlendTable(pfloor->blend, trans); + else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0) + fuzzy = false; // Opaque + } if (fuzzy) colfunc = fuzzcolfunc; diff --git a/src/r_things.c b/src/r_things.c index 410da8ec3..95b5a66ff 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1768,7 +1768,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) fixed_t this_scale; INT32 dist = 1; - INT32 trans; if (cv_maxinterpdist.value) dist = R_QuickCamDist(thing->x, thing->y); @@ -1869,12 +1868,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; } - // Determine the translucency value. - if (thing->frame & FF_TRANSMASK) - trans = (thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; - else - trans = 0; - //SoM: 3/17/2000: Disregard sprites that are out of view.. gzt = interp.z + FixedMul(spritecachedinfo[lump].topoffset, this_scale); gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale); -- 2.54.0 From ccc1c07930001d973ca7b36686766ec6f79e9238 Mon Sep 17 00:00:00 2001 From: Chearii Date: Tue, 4 Feb 2025 16:34:17 -0500 Subject: [PATCH 4/6] Fix white pixel bug due to oversight many thanks to indev for catching this! --- src/r_draw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/r_draw.c b/src/r_draw.c index d41e542a5..ef4496349 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -248,9 +248,9 @@ static void BlendTab_Translucent(UINT8 *table, int style, UINT8 blendamt) if (table == NULL) I_Error("BlendTab_Translucent: input table was NULL!"); - for (bg = 0; bg < 0xFF; bg++) + for (bg = 0; bg < 0x100; bg++) { - for (fg = 0; fg < 0xFF; fg++) + for (fg = 0; fg < 0x100; fg++) { RGBA_t backrgba = V_GetColor(bg); RGBA_t frontrgba = V_GetColor(fg); @@ -277,9 +277,9 @@ static void BlendTab_Subtractive(UINT8 *table, int style, UINT8 blendamt) return; } - for (bg = 0; bg < 0xFF; bg++) + for (bg = 0; bg < 0x100; bg++) { - for (fg = 0; fg < 0xFF; fg++) + for (fg = 0; fg < 0x100; fg++) { RGBA_t backrgba = V_GetColor(bg); RGBA_t frontrgba = V_GetColor(fg); @@ -302,9 +302,9 @@ static void BlendTab_Modulative(UINT8 *table) if (table == NULL) I_Error("BlendTab_Modulative: input table was NULL!"); - for (bg = 0; bg < 0xFF; bg++) + for (bg = 0; bg < 0x100; bg++) { - for (fg = 0; fg < 0xFF; fg++) + for (fg = 0; fg < 0x100; fg++) { RGBA_t backrgba = V_GetColor(bg); RGBA_t frontrgba = V_GetColor(fg); -- 2.54.0 From 54d73206caf1f82be4c9adcc7596b08311dd8dbb Mon Sep 17 00:00:00 2001 From: Chearii Date: Tue, 4 Mar 2025 19:42:59 -0500 Subject: [PATCH 5/6] Fix ``hw_draw`` gaffe --- src/hardware/hw_draw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index b2d69861a..29e735822 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -287,16 +287,18 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t v[0].t = v[1].t = 0.0f; v[2].t = v[3].t = gpatch->max_t; + // whoops + if (blendmode) + flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; + else + flags = PF_Translucent|PF_NoDepthTest; + if (option & V_WRAPX) flags |= PF_ForceWrapX; if (option & V_WRAPY) flags |= PF_ForceWrapY; // clip it since it is used for bunny scroll in doom I - if (blendmode) - flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; - else - flags = PF_Translucent|PF_NoDepthTest; if (alphalevel) { -- 2.54.0 From 72d94b77ac2bdcc8b00ab3137cb5ede2312cff3d Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 5 Mar 2025 00:08:30 +0100 Subject: [PATCH 6/6] fix blendmode oopsie --- src/hardware/hw_main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index ccd292cf3..c89c6c876 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1085,8 +1085,8 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, if (cutflag & FF_FOG) HWR_AddTransparentWall(wallVerts, Surf, texnum, noencore, PF_Fog|PF_NoTexture|polyflags, true, lightnum, colormap); - else if (cutflag & FF_TRANSLUCENT) - HWR_AddTransparentWall(wallVerts, Surf, texnum, noencore, PF_Translucent|polyflags, false, lightnum, colormap); + else if (polyflags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Environment)) + HWR_AddTransparentWall(wallVerts, Surf, texnum, noencore, polyflags, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, Surf, PF_Masked|polyflags, lightnum, colormap); @@ -1732,7 +1732,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode |= PF_Decal; if (!gl_drawing_stencil && gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, &Surf, (!(blendmode & PF_Masked)) ? FF_TRANSLUCENT : FF_CUTLEVEL, NULL, PF_Decal); + HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, &Surf, (!(blendmode & PF_Masked)) ? FF_TRANSLUCENT : FF_CUTLEVEL, NULL, blendmode); else if (!gl_drawing_stencil && !(blendmode & PF_Masked)) HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, noencore, blendmode, false, lightnum, colormap); else @@ -1956,10 +1956,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[0].s = wallVerts[3].s = cliplow * glTex->scaleX; wallVerts[2].s = wallVerts[1].s = cliphigh * glTex->scaleX; } + FBITFIELD blendmode; + if (rover->flags & FF_FOG) { - FBITFIELD blendmode; - blendmode = PF_Fog|PF_NoTexture; lightnum = rover->master->frontsector->lightlevel; @@ -1976,7 +1976,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom } else { - FBITFIELD blendmode = PF_Masked; + blendmode = PF_Masked; if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { @@ -2071,10 +2071,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[2].s = wallVerts[1].s = cliphigh * glTex->scaleX; } + FBITFIELD blendmode; + if (rover->flags & FF_FOG) { - FBITFIELD blendmode; - blendmode = PF_Fog|PF_NoTexture; lightnum = rover->master->frontsector->lightlevel; @@ -2091,7 +2091,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom } else { - FBITFIELD blendmode = PF_Masked; + blendmode = PF_Masked; if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { -- 2.54.0