From 3af6ae4b377bde0f386593337020139587b90410 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 15 Dec 2018 07:11:28 +0100 Subject: [PATCH] - add vanilla lightmode that behaves exactly as Doom's original light did --- src/g_level.cpp | 5 +- src/hwrenderer/scene/hw_drawinfo.cpp | 2 +- src/hwrenderer/scene/hw_renderstate.cpp | 4 +- src/hwrenderer/scene/hw_renderstate.h | 2 +- src/hwrenderer/scene/hw_skyportal.cpp | 2 +- src/hwrenderer/scene/hw_weapon.cpp | 6 +- src/hwrenderer/utility/hw_lighting.cpp | 8 +-- wadsrc/static/menudef.txt | 1 + wadsrc/static/shaders/glsl/main.fp | 91 +++++++++++++++++++++---- 9 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index fe5477bf6..a5dc609ec 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -123,8 +123,9 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, CVAR_NOINITCALL) CUSTOM_CVAR(Int, gl_lightmode, 3, CVAR_ARCHIVE | CVAR_NOINITCALL) { int newself = self; - if (newself > 4) newself = 8; // use 8 for software lighting to avoid conflicts with the bit mask - if (newself < 0) newself = 0; + if (newself > 8) newself = 16; // use 8 and 16 for software lighting to avoid conflicts with the bit mask + else if (newself > 4) newself = 8; + else if (newself < 0) newself = 0; if (self != newself) self = newself; else if ((level.info == nullptr || level.info->lightmode == -1)) level.lightmode = self; } diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index 35b1836e0..06e962fff 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -388,7 +388,7 @@ void HWViewpointUniforms::SetDefaults() mNormalViewMatrix.loadIdentity(); mViewHeight = viewheight; mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f; - mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8); + mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8) | (static_cast(gl_lightmode) << 16); mClipLine.X = -10000000.0f; mShadowmapFilter = gl_shadowmap_filter; diff --git a/src/hwrenderer/scene/hw_renderstate.cpp b/src/hwrenderer/scene/hw_renderstate.cpp index 5aa8d9c3c..3ead6232d 100644 --- a/src/hwrenderer/scene/hw_renderstate.cpp +++ b/src/hwrenderer/scene/hw_renderstate.cpp @@ -127,7 +127,7 @@ void FRenderState::SetFog(int lightlevel, int rellight, bool fullbright, const F } else { - if ((level.lightmode == 2 || (level.lightmode == 8 && cmap->BlendFactor > 0)) && fogcolor == 0) + if ((level.lightmode == 2 || (level.lightmode >= 8 && cmap->BlendFactor > 0)) && fogcolor == 0) { float light = (float)hw_CalcLightLevel(lightlevel, rellight, false, cmap->BlendFactor); SetShaderLight(light, lightlevel); @@ -148,7 +148,7 @@ void FRenderState::SetFog(int lightlevel, int rellight, bool fullbright, const F SetFog(fogcolor, fogdensity); // Korshun: fullbright fog like in software renderer. - if (level.lightmode == 8 && cmap->BlendFactor == 0 && level.brightfog && fogdensity != 0 && fogcolor != 0) + if (level.lightmode >= 8 && cmap->BlendFactor == 0 && level.brightfog && fogdensity != 0 && fogcolor != 0) { SetSoftLightLevel(255); } diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index f494df34a..e39d25b26 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -326,7 +326,7 @@ public: void SetSoftLightLevel(int llevel, int blendfactor = 0) { - if (level.lightmode == 8 && blendfactor == 0) mLightParms[3] = llevel / 255.f; + if (level.lightmode >= 8 && blendfactor == 0) mLightParms[3] = llevel / 255.f; else mLightParms[3] = -1.f; } diff --git a/src/hwrenderer/scene/hw_skyportal.cpp b/src/hwrenderer/scene/hw_skyportal.cpp index cb04c1e86..83bd7de57 100644 --- a/src/hwrenderer/scene/hw_skyportal.cpp +++ b/src/hwrenderer/scene/hw_skyportal.cpp @@ -165,7 +165,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) // We have no use for Doom lighting special handling here, so disable it for this function. int oldlightmode = ::level.lightmode; - if (::level.lightmode == 8) + if (::level.lightmode >= 8) { ::level.lightmode = 2; state.SetSoftLightLevel(-1); diff --git a/src/hwrenderer/scene/hw_weapon.cpp b/src/hwrenderer/scene/hw_weapon.cpp index 171c28647..7d0a1f3d1 100644 --- a/src/hwrenderer/scene/hw_weapon.cpp +++ b/src/hwrenderer/scene/hw_weapon.cpp @@ -107,7 +107,7 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state) void HWDrawInfo::DrawPlayerSprites(bool hudModelStep, FRenderState &state) { int oldlightmode = level.lightmode; - if (!hudModelStep && level.lightmode == 8) level.lightmode = 2; // Software lighting cannot handle 2D content so revert to lightmode 2 for that. + if (!hudModelStep && level.lightmode >= 8) level.lightmode = 2; // Software lighting cannot handle 2D content so revert to lightmode 2 for that. for (auto &hudsprite : hudsprites) { if ((!!hudsprite.mframe) == hudModelStep) @@ -260,7 +260,7 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po l.lightlevel = hw_CalcLightLevel(l.lightlevel, getExtraLight(), true, 0); - if (level.lightmode == 8 || l.lightlevel < 92) + if (level.lightmode >= 8 || l.lightlevel < 92) { // Korshun: the way based on max possible light level for sector like in software renderer. double min_L = 36.0 / 31.0 - ((l.lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63 @@ -499,7 +499,7 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change // light mode here to draw the weapon sprite. int oldlightmode = level.lightmode; - if (level.lightmode == 8) level.lightmode = 2; + if (level.lightmode >= 8) level.lightmode = 2; for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) { diff --git a/src/hwrenderer/utility/hw_lighting.cpp b/src/hwrenderer/utility/hw_lighting.cpp index 83e2acd7d..cee925b68 100644 --- a/src/hwrenderer/utility/hw_lighting.cpp +++ b/src/hwrenderer/utility/hw_lighting.cpp @@ -88,7 +88,7 @@ int hw_CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor if (lightlevel == 0) return 0; - bool darklightmode = (level.lightmode & 2) || (level.lightmode == 8 && blendfactor > 0); + bool darklightmode = (level.lightmode & 2) || (level.lightmode >= 8 && blendfactor > 0); if (darklightmode && lightlevel < 192 && !weapon) { @@ -130,7 +130,7 @@ PalEntry hw_CalcLightColor(int light, PalEntry pe, int blendfactor) if (blendfactor == 0) { - if (level.lightmode == 8) + if (level.lightmode >= 8) { return pe; } @@ -175,7 +175,7 @@ float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, float density; int lightmode = level.lightmode; - if (lightmode == 8 && blendfactor > 0) lightmode = 2; // The blendfactor feature does not work with software-style lighting. + if (lightmode >= 8 && blendfactor > 0) lightmode = 2; // The blendfactor feature does not work with software-style lighting. if (lightmode & 4) { @@ -190,7 +190,7 @@ float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, else if ((fogcolor.d & 0xffffff) == 0) { // case 2: black fog - if ((lightmode != 8 || blendfactor > 0) && !(level.flags3 & LEVEL3_NOLIGHTFADE)) + if ((lightmode < 8 || blendfactor > 0) && !(level.flags3 & LEVEL3_NOLIGHTFADE)) { density = distfogtable[level.lightmode != 0][hw_ClampLight(lightlevel)]; } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 4026e2bc0..1ff8697b3 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -2105,6 +2105,7 @@ OptionValue "LightingModes" 3, "$OPTVAL_DARK" 4, "$OPTVAL_LEGACY" 8, "$OPTVAL_SOFTWARE" + 16, "$OPTVAL_VANILLA" } OptionValue "Precision" diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 77855a85a..8f5bb1fb6 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -119,17 +119,84 @@ vec4 getTexel(vec2 st) //=========================================================================== // -// Doom lighting equation exactly as calculated by zdoom. +// Vanilla Doom wall colormap equation +// +//=========================================================================== +float R_WallColormap(float lightnum, float z) +{ + // R_ScaleFromGlobalAngle calculation + float projection = 160.0; // projection depends on SCREENBLOCKS!! 160 is the fullscreen value + vec3 line_v1 = pixelpos.xyz; // in vanilla this is the first curline vertex + vec3 line_normal = vWorldNormal.xyz; + float texscale = projection * clamp(dot(normalize(uCameraPos.xyz - line_v1), line_normal), 0.0, 1.0) / z; + + float lightz = clamp(16.0 * texscale, 0.0, 47.0); + + // scalelight[lightnum][lightz] lookup + float startmap = (15.0 - lightnum) * 4.0; + return startmap - lightz * 0.5; +} + +//=========================================================================== +// +// Vanilla Doom plane colormap equation +// +//=========================================================================== +float R_PlaneColormap(float lightnum, float z) +{ + float lightz = clamp(z / 16.0f, 0.0, 127.0); + + // zlight[lightnum][lightz] lookup + float startmap = (15.0 - lightnum) * 4.0; + float scale = 160.0 / (lightz + 1.0); + return startmap - scale * 0.5; +} + +//=========================================================================== +// +// zdoom colormap equation +// +//=========================================================================== +float R_ZDoomColormap(float light, float z) +{ + float L = light * 255.0; + float vis = min(uGlobVis / z, 24.0 / 32.0); + float shade = 2.0 - (L + 12.0) / 128.0; + float lightscale = shade - vis; + return lightscale * 31.0; +} + +float R_DoomColormap(float light, float z) +{ + if ((uPalLightLevels >> 16) == 16) // gl_lightmode 16 + { + float lightnum = clamp(light * 15.0, 0.0, 15.0); + + if (dot(vWorldNormal.xyz, vWorldNormal.xyz) > 0.5) + { + return mix(R_WallColormap(lightnum, z), R_PlaneColormap(lightnum, z), abs(vWorldNormal.y)); + } + else // vWorldNormal is not set on sprites + { + return R_PlaneColormap(lightnum, z); + } + } + else + { + return R_ZDoomColormap(light, z); + } +} + +//=========================================================================== +// +// Doom software lighting equation // //=========================================================================== float R_DoomLightingEquation(float light) { - // L is the integer light level used in the game - float L = light * 255.0; - - // z is the depth in view/eye space, positive going into the screen + // z is the depth in view space, positive going into the screen float z; - if ((uPalLightLevels >> 8) == 2) + if (((uPalLightLevels >> 8) & 0xff) == 2) { z = distance(pixelpos.xyz, uCameraPos.xyz); } @@ -138,17 +205,13 @@ float R_DoomLightingEquation(float light) z = pixelpos.w; } - // The zdoom light equation - float vis = min(uGlobVis / z, 24.0 / 32.0); - float shade = 2.0 - (L + 12.0) / 128.0; - float lightscale; + float colormap = R_DoomColormap(light, z); + if ((uPalLightLevels & 0xff) != 0) - lightscale = float(-floor(-(shade - vis) * 31.0) - 0.5) / 31.0; - else - lightscale = shade - vis; + colormap = floor(colormap) + 0.5; // Result is the normalized colormap index (0 bright .. 1 dark) - return clamp(lightscale, 1.0 - light, 31.0 / 32.0); + return clamp(colormap, 0.0, 31.0) / 32.0; } //===========================================================================