mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-14 06:31:07 +00:00
95b264bdb6
* Feature-complete isometric mode fork. * Dithered transparency condition tweaks. * Dithered transparency for non-corpse monsters only (and missiles). * SpectatorCamera vertical shift. * Including math.h in hw_sprites.cpp to keep visual studio happy (it couldn't find M_SQRT2 definition). * Defining MY_SQRT2 in hw_sprites.cpp to keep visual studio happy (it couldn't find M_SQRT2 definition). * Defining MY_SQRT2 in r_utility.cpp also to keep visual studio happy. * retrigger checks * Have correct sprite angle-frame face the camera with orthographic projection enabled. * Dithered Transparency now works properly on 3D floors. Moved that dither-trans flag setting code within hw_bsp.cpp to handle double-processing of linedefs. Added helper functions to FRenderViewpoint class 'bool IsOrtho()' and 'bool IsAllowedOoB()' to clean up checks everywhere in the code. * Fixed indents. Added bbox property to subsector struct and use it instead of BSP nodes and Clippers (creating a bbox around viewpoint and checking for overlap) in orthographic mode when no fog of war is active. Turns out to be much faster. Though you need really big maps (Winter's Fury MAP01) to see a difference in fps. * Non-linux checks don't like uint. Changed to unsigned int. * Small change of a float to camera.zs. Ignore for testing. Should make no difference. * Update actor.h to remain mergeable RF2_NOMIPMAP was introduced, so I had to displace RF_ISOMETRICSPRITES to next bit.
571 lines
14 KiB
GLSL
571 lines
14 KiB
GLSL
|
|
varying vec4 vTexCoord;
|
|
varying vec4 vColor;
|
|
varying vec4 pixelpos;
|
|
varying vec3 glowdist;
|
|
varying vec3 gradientdist;
|
|
varying vec4 vWorldNormal;
|
|
varying vec4 vEyeNormal;
|
|
|
|
#ifdef NO_CLIPDISTANCE_SUPPORT
|
|
varying vec4 ClipDistanceA;
|
|
varying vec4 ClipDistanceB;
|
|
#endif
|
|
|
|
|
|
struct Material
|
|
{
|
|
vec4 Base;
|
|
vec4 Bright;
|
|
vec4 Glow;
|
|
vec3 Normal;
|
|
vec3 Specular;
|
|
float Glossiness;
|
|
float SpecularLevel;
|
|
};
|
|
|
|
vec4 Process(vec4 color);
|
|
vec4 ProcessTexel();
|
|
Material ProcessMaterial(); // note that this is deprecated. Use SetupMaterial!
|
|
void SetupMaterial(inout Material mat);
|
|
vec4 ProcessLight(Material mat, vec4 color);
|
|
vec3 ProcessMaterialLight(Material material, vec3 color);
|
|
vec2 GetTexCoord();
|
|
|
|
// These get Or'ed into uTextureMode because it only uses its 3 lowermost bits.
|
|
//const int TEXF_Brightmap = 0x10000;
|
|
//const int TEXF_Detailmap = 0x20000;
|
|
//const int TEXF_Glowmap = 0x40000;
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// Color to grayscale
|
|
//
|
|
//===========================================================================
|
|
|
|
float grayscale(vec4 color)
|
|
{
|
|
return dot(color.rgb, vec3(0.3, 0.56, 0.14));
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Desaturate a color
|
|
//
|
|
//===========================================================================
|
|
|
|
vec4 dodesaturate(vec4 texel, float factor)
|
|
{
|
|
if (factor != 0.0)
|
|
{
|
|
float gray = grayscale(texel);
|
|
return mix (texel, vec4(gray,gray,gray,texel.a), factor);
|
|
}
|
|
else
|
|
{
|
|
return texel;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Desaturate a color
|
|
//
|
|
//===========================================================================
|
|
|
|
vec4 desaturate(vec4 texel)
|
|
{
|
|
#if (DEF_DO_DESATURATE == 1)
|
|
return dodesaturate(texel, uDesaturationFactor);
|
|
#else
|
|
return texel;
|
|
#endif
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Texture tinting code originally from JFDuke but with a few more options
|
|
//
|
|
//===========================================================================
|
|
|
|
const int Tex_Blend_Alpha = 1;
|
|
const int Tex_Blend_Screen = 2;
|
|
const int Tex_Blend_Overlay = 3;
|
|
const int Tex_Blend_Hardlight = 4;
|
|
|
|
vec4 ApplyTextureManipulation(vec4 texel)
|
|
{
|
|
// Step 1: desaturate according to the material's desaturation factor.
|
|
texel = dodesaturate(texel, uTextureModulateColor.a);
|
|
|
|
// Step 2: Invert if requested // TODO FIX
|
|
//if ((blendflags & 8) != 0)
|
|
//{
|
|
// texel.rgb = vec3(1.0 - texel.r, 1.0 - texel.g, 1.0 - texel.b);
|
|
//}
|
|
|
|
// Step 3: Apply additive color
|
|
texel.rgb += uTextureAddColor.rgb;
|
|
|
|
// Step 4: Colorization, including gradient if set.
|
|
texel.rgb *= uTextureModulateColor.rgb;
|
|
|
|
// Before applying the blend the value needs to be clamped to [0..1] range.
|
|
texel.rgb = clamp(texel.rgb, 0.0, 1.0);
|
|
|
|
// Step 5: Apply a blend. This may just be a translucent overlay or one of the blend modes present in current Build engines.
|
|
#if (DEF_BLEND_FLAGS != 0)
|
|
|
|
vec3 tcol = texel.rgb * 255.0; // * 255.0 to make it easier to reuse the integer math.
|
|
vec4 tint = uTextureBlendColor * 255.0;
|
|
|
|
#if (DEF_BLEND_FLAGS == 1)
|
|
|
|
tcol.b = tcol.b * (1.0 - uTextureBlendColor.a) + tint.b * uTextureBlendColor.a;
|
|
tcol.g = tcol.g * (1.0 - uTextureBlendColor.a) + tint.g * uTextureBlendColor.a;
|
|
tcol.r = tcol.r * (1.0 - uTextureBlendColor.a) + tint.r * uTextureBlendColor.a;
|
|
|
|
#elif (DEF_BLEND_FLAGS == 2) // Tex_Blend_Screen:
|
|
tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 256.0);
|
|
tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 256.0);
|
|
tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 256.0);
|
|
|
|
#elif (DEF_BLEND_FLAGS == 3) // Tex_Blend_Overlay:
|
|
|
|
tcol.b = tcol.b < 128.0? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0);
|
|
tcol.g = tcol.g < 128.0? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0);
|
|
tcol.r = tcol.r < 128.0? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0);
|
|
|
|
#elif (DEF_BLEND_FLAGS == 4) // Tex_Blend_Hardlight:
|
|
|
|
tcol.b = tint.b < 128.0 ? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0);
|
|
tcol.g = tint.g < 128.0 ? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0);
|
|
tcol.r = tint.r < 128.0 ? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0);
|
|
|
|
#endif
|
|
|
|
texel.rgb = tcol / 255.0;
|
|
|
|
#endif
|
|
|
|
return texel;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// This function is common for all (non-special-effect) fragment shaders
|
|
//
|
|
//===========================================================================
|
|
|
|
vec4 getTexel(vec2 st)
|
|
{
|
|
vec4 texel = texture2D(tex, st);
|
|
|
|
#if (DEF_TEXTURE_MODE == 1)
|
|
|
|
texel.rgb = vec3(1.0,1.0,1.0);
|
|
|
|
#elif (DEF_TEXTURE_MODE == 2)// TM_OPAQUE
|
|
|
|
texel.a = 1.0;
|
|
|
|
#elif (DEF_TEXTURE_MODE == 3)// TM_INVERSE
|
|
|
|
texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, texel.a);
|
|
|
|
#elif (DEF_TEXTURE_MODE == 4)// TM_ALPHATEXTURE
|
|
|
|
float gray = grayscale(texel);
|
|
texel = vec4(1.0, 1.0, 1.0, gray*texel.a);
|
|
|
|
#elif (DEF_TEXTURE_MODE == 5)// TM_CLAMPY
|
|
|
|
if (st.t < 0.0 || st.t > 1.0)
|
|
{
|
|
texel.a = 0.0;
|
|
}
|
|
|
|
#elif (DEF_TEXTURE_MODE == 6)// TM_OPAQUEINVERSE
|
|
|
|
texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, 1.0);
|
|
|
|
|
|
#elif (DEF_TEXTURE_MODE == 7)//TM_FOGLAYER
|
|
|
|
return texel;
|
|
|
|
#endif
|
|
|
|
// Apply the texture modification colors.
|
|
#if (DEF_BLEND_FLAGS != 0)
|
|
|
|
// only apply the texture manipulation if it contains something.
|
|
texel = ApplyTextureManipulation(texel);
|
|
|
|
#endif
|
|
|
|
// Apply the Doom64 style material colors on top of everything from the texture modification settings.
|
|
// This may be a bit redundant in terms of features but the data comes from different sources so this is unavoidable.
|
|
|
|
texel.rgb += uAddColor.rgb;
|
|
|
|
#if (DEF_USE_OBJECT_COLOR_2 == 1)
|
|
texel *= mix(uObjectColor, uObjectColor2, gradientdist.z);
|
|
#else
|
|
texel *= uObjectColor;
|
|
#endif
|
|
|
|
// Last but not least apply the desaturation from the sector's light.
|
|
return desaturate(texel);
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// Doom software lighting equation
|
|
//
|
|
//===========================================================================
|
|
|
|
#define DOOMLIGHTFACTOR 232.0
|
|
|
|
float R_DoomLightingEquation_OLD(float light)
|
|
{
|
|
// z is the depth in view space, positive going into the screen
|
|
float z = pixelpos.w;
|
|
|
|
|
|
/* L in the range 0 to 63 */
|
|
float L = light * 63.0/31.0;
|
|
|
|
float min_L = clamp(36.0/31.0 - L, 0.0, 1.0);
|
|
|
|
// Fix objects getting totally black when close.
|
|
if (z < 0.0001)
|
|
z = 0.0001;
|
|
|
|
float scale = 1.0 / z;
|
|
float index = (59.0/31.0 - L) - (scale * DOOMLIGHTFACTOR/31.0 - DOOMLIGHTFACTOR/31.0);
|
|
|
|
// Result is the normalized colormap index (0 bright .. 1 dark)
|
|
return clamp(index, min_L, 1.0) / 32.0;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Doom software lighting equation
|
|
//
|
|
//===========================================================================
|
|
float R_DoomLightingEquation(float light)
|
|
{
|
|
// z is the depth in view space, positive going into the screen
|
|
float z;
|
|
|
|
#if (DEF_FOG_RADIAL == 1)
|
|
z = distance(pixelpos.xyz, uCameraPos.xyz);
|
|
#else
|
|
z = pixelpos.w;
|
|
#endif
|
|
|
|
#if (DEF_BUILD_LIGHTING == 1) // gl_lightmode 5: Build software lighting emulation.
|
|
// This is a lot more primitive than Doom's lighting...
|
|
float numShades = float(uPalLightLevels);
|
|
float curshade = (1.0 - light) * (numShades - 1.0);
|
|
float visibility = max(uGlobVis * uLightFactor * abs(z), 0.0);
|
|
float shade = clamp((curshade + visibility), 0.0, numShades - 1.0);
|
|
return clamp(shade * uLightDist, 0.0, 1.0);
|
|
#endif
|
|
|
|
float colormap = R_ZDoomColormap(light, z); // ONLY Software mode, vanilla not yet working
|
|
|
|
#if (DEF_BANDED_SW_LIGHTING == 1)
|
|
colormap = floor(colormap) + 0.5;
|
|
#endif
|
|
|
|
// Result is the normalized colormap index (0 bright .. 1 dark)
|
|
return clamp(colormap, 0.0, 31.0) / 32.0;
|
|
}
|
|
|
|
|
|
float shadowAttenuation(vec4 lightpos, float lightcolorA)
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
|
|
float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle)
|
|
{
|
|
vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz);
|
|
float cosDir = dot(lightDirection, spotdir);
|
|
return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir);
|
|
}
|
|
|
|
vec3 ApplyNormalMap(vec2 texcoord)
|
|
{
|
|
return normalize(vWorldNormal.xyz);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Sets the common material properties.
|
|
//
|
|
//===========================================================================
|
|
|
|
void SetMaterialProps(inout Material material, vec2 texCoord)
|
|
{
|
|
|
|
#ifdef NPOT_EMULATION
|
|
|
|
#if (DEF_NPOT_EMULATION == 1)
|
|
float period = floor(texCoord.t / uNpotEmulation.y);
|
|
texCoord.s += uNpotEmulation.x * floor(mod(texCoord.t, uNpotEmulation.y));
|
|
texCoord.t = period + mod(texCoord.t, uNpotEmulation.y);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
material.Base = getTexel(texCoord.st);
|
|
material.Normal = ApplyNormalMap(texCoord.st);
|
|
|
|
#if (DEF_TEXTURE_FLAGS & 0x1)
|
|
material.Bright = texture2D(brighttexture, texCoord.st);
|
|
#endif
|
|
|
|
#if (DEF_TEXTURE_FLAGS & 0x2)
|
|
{
|
|
vec4 Detail = texture2D(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z;
|
|
material.Base *= Detail;
|
|
}
|
|
#endif
|
|
|
|
#if (DEF_TEXTURE_FLAGS & 0x4)
|
|
{
|
|
material.Glow = texture2D(glowtexture, texCoord.st);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Calculate light
|
|
//
|
|
// It is important to note that the light color is not desaturated
|
|
// due to ZDoom's implementation weirdness. Everything that's added
|
|
// on top of it, e.g. dynamic lights and glows are, though, because
|
|
// the objects emitting these lights are also.
|
|
//
|
|
// This is making this a bit more complicated than it needs to
|
|
// because we can't just desaturate the final fragment color.
|
|
//
|
|
//===========================================================================
|
|
|
|
vec4 getLightColor(Material material, float fogdist, float fogfactor)
|
|
{
|
|
vec4 color = vColor;
|
|
|
|
#if (DEF_USE_U_LIGHT_LEVEL == 1)
|
|
{
|
|
float newlightlevel = 1.0 - R_DoomLightingEquation(uLightLevel);
|
|
color.rgb *= newlightlevel;
|
|
}
|
|
#else
|
|
{
|
|
|
|
#if (DEF_FOG_ENABLED == 1) && (DEF_FOG_COLOURED == 0)
|
|
{
|
|
// brightening around the player for light mode 2
|
|
if (fogdist < uLightDist)
|
|
{
|
|
color.rgb *= uLightFactor - (fogdist / uLightDist) * (uLightFactor - 1.0);
|
|
}
|
|
|
|
//
|
|
// apply light diminishing through fog equation
|
|
//
|
|
color.rgb = mix(vec3(0.0, 0.0, 0.0), color.rgb, fogfactor);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// handle glowing walls
|
|
//
|
|
#if (DEF_USE_GLOW_TOP_COLOR)
|
|
if (glowdist.x < uGlowTopColor.a)
|
|
{
|
|
color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if (DEF_USE_GLOW_BOTTOM_COLOR)
|
|
if (glowdist.y < uGlowBottomColor.a)
|
|
{
|
|
color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb;
|
|
}
|
|
#endif
|
|
|
|
color = min(color, 1.0);
|
|
|
|
// these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set.
|
|
#ifndef LEGACY_USER_SHADER
|
|
//
|
|
// apply glow
|
|
//
|
|
color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a);
|
|
|
|
//
|
|
// apply brightmaps
|
|
//
|
|
color.rgb = min(color.rgb + material.Bright.rgb, 1.0);
|
|
#endif
|
|
|
|
//
|
|
// apply other light manipulation by custom shaders, default is a NOP.
|
|
//
|
|
color = ProcessLight(material, color);
|
|
|
|
//
|
|
// apply dynamic lights
|
|
//
|
|
return vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Applies colored fog
|
|
//
|
|
//===========================================================================
|
|
|
|
vec4 applyFog(vec4 frag, float fogfactor)
|
|
{
|
|
return vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Main shader routine
|
|
//
|
|
//===========================================================================
|
|
|
|
void main()
|
|
{
|
|
|
|
//if (ClipDistanceA.x < 0.0 || ClipDistanceA.y < 0.0 || ClipDistanceA.z < 0.0 || ClipDistanceA.w < 0.0 || ClipDistanceB.x < 0.0) discard;
|
|
|
|
#ifndef LEGACY_USER_SHADER
|
|
Material material;
|
|
|
|
material.Base = vec4(0.0);
|
|
material.Bright = vec4(0.0);
|
|
material.Glow = vec4(0.0);
|
|
material.Normal = vec3(0.0);
|
|
material.Specular = vec3(0.0);
|
|
material.Glossiness = 0.0;
|
|
material.SpecularLevel = 0.0;
|
|
SetupMaterial(material);
|
|
#else
|
|
Material material = ProcessMaterial();
|
|
#endif
|
|
vec4 frag = material.Base;
|
|
|
|
#ifndef NO_ALPHATEST
|
|
if (frag.a <= uAlphaThreshold) discard;
|
|
#endif
|
|
|
|
#ifdef DITHERTRANS
|
|
int index = (int(pixelpos.x) % 2) * 2 + int(pixelpos.y) % 2;
|
|
if (index != 2) discard;
|
|
#endif
|
|
|
|
#if (DEF_FOG_2D == 0) // check for special 2D 'fog' mode.
|
|
{
|
|
float fogdist = 0.0;
|
|
float fogfactor = 0.0;
|
|
|
|
//
|
|
// calculate fog factor
|
|
//
|
|
#if (DEF_FOG_ENABLED == 1)
|
|
{
|
|
#if (DEF_FOG_RADIAL == 0)
|
|
fogdist = max(16.0, pixelpos.w);
|
|
#else
|
|
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
|
|
#endif
|
|
|
|
fogfactor = exp2 (uFogDensity * fogdist);
|
|
}
|
|
#endif
|
|
|
|
#if (DEF_TEXTURE_MODE != 7)
|
|
{
|
|
frag = getLightColor(material, fogdist, fogfactor);
|
|
|
|
//
|
|
// colored fog
|
|
//
|
|
#if (DEF_FOG_ENABLED == 1) && (DEF_FOG_COLOURED == 1)
|
|
{
|
|
frag = applyFog(frag, fogfactor);
|
|
}
|
|
#endif
|
|
}
|
|
#else
|
|
{
|
|
frag = vec4(uFogColor.rgb, (1.0 - fogfactor) * frag.a * 0.75 * vColor.a);
|
|
}
|
|
#endif
|
|
}
|
|
#else
|
|
{
|
|
#if (DEF_TEXTURE_MODE == 7)
|
|
{
|
|
float gray = grayscale(frag);
|
|
vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2.0;
|
|
frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a);
|
|
}
|
|
#endif
|
|
|
|
frag = frag * ProcessLight(material, vColor);
|
|
frag.rgb = frag.rgb + uFogColor.rgb;
|
|
}
|
|
#endif // (DEF_2D_FOG == 0)
|
|
|
|
#if (DEF_USE_COLOR_MAP == 1) // This mostly works but doesn't look great because of the blending.
|
|
{
|
|
frag.rgb = clamp(pow(frag.rgb, vec3(uFixedColormapStart.a)), 0.0, 1.0);
|
|
if (uFixedColormapRange.a == 0.0)
|
|
{
|
|
float gray = (frag.r * 0.3 + frag.g * 0.56 + frag.b * 0.14);
|
|
vec4 cm = uFixedColormapStart + gray * uFixedColormapRange;
|
|
frag.rgb = clamp(cm.rgb, 0.0, 1.0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
gl_FragColor = frag;
|
|
|
|
//gl_FragColor = vec4(0.8, 0.2, 0.5, 1);
|
|
|
|
}
|