mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-12-18 08:01:36 +00:00
7fbd07e586
Added classic rendering mode to closer emulate software renderer visuals in visual mode
496 lines
No EOL
13 KiB
GLSL
Executable file
496 lines
No EOL
13 KiB
GLSL
Executable file
uniforms
|
|
{
|
|
mat4 world;
|
|
mat4 view;
|
|
mat4 projection;
|
|
mat4 modelnormal;
|
|
vec4 campos;
|
|
|
|
vec4 highlightcolor;
|
|
vec4 stencilColor;
|
|
float desaturation;
|
|
|
|
vec4 fogsettings;
|
|
vec4 fogcolor;
|
|
vec4 sectorfogcolor;
|
|
vec4 vertexColor;
|
|
|
|
sampler2D texture1;
|
|
sampler2D texture2;
|
|
sampler2D texture3;
|
|
|
|
// classic lighting related
|
|
int drawPaletted;
|
|
ivec2 colormapSize;
|
|
int lightLevel;
|
|
|
|
// dynamic light related
|
|
vec4 lightPosAndRadius[64];
|
|
vec4 lightOrientation[64]; // this is a vector that points in light's direction
|
|
vec2 light2Radius[64]; // this is used with spotlights
|
|
vec4 lightColor[64];
|
|
float ignoreNormals;
|
|
float lightsEnabled;
|
|
|
|
// Slope handle length
|
|
float slopeHandleLength;
|
|
|
|
}
|
|
|
|
functions
|
|
{
|
|
vec4 getColorMappedColor(int entry, int depth)
|
|
{
|
|
vec2 uv = vec2((float(entry) + 0.5) / colormapSize.x, (float(depth) + 0.5) / colormapSize.y);
|
|
vec4 colormapColor = texture(texture2, uv);
|
|
return colormapColor;
|
|
}
|
|
|
|
int classicLightLevelToColorMapOffset(int lightLevel, vec3 position, vec3 normal)
|
|
{
|
|
const int LIGHTLEVELS = 16;
|
|
const int LIGHTSEGSHIFT = 4;
|
|
const int NUMCOLORMAPS = 32;
|
|
const int MAXLIGHTSCALE = 48;
|
|
const int DISTMAP = 2;
|
|
|
|
int scaledLightLevel = lightLevel >> LIGHTSEGSHIFT;
|
|
|
|
bool isFlat = abs(dot(normal, vec3(0, 0, 1))) > 1e-3;
|
|
|
|
if (abs(dot(normal, vec3(0, 1, 0))) < 1e-3)
|
|
{
|
|
scaledLightLevel++;
|
|
}
|
|
else if (abs(dot(normal, vec3(1, 0, 0))) < 1e-3)
|
|
{
|
|
scaledLightLevel--;
|
|
}
|
|
|
|
int level;
|
|
float dist = distance(position, campos.xyz);
|
|
|
|
if (!isFlat)
|
|
{
|
|
int startmap = int(((LIGHTLEVELS-1-scaledLightLevel)*2)*NUMCOLORMAPS/LIGHTLEVELS);
|
|
|
|
// same calculation as Eternity Engine
|
|
int index = int(2560.0 / dist);
|
|
if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1;
|
|
level = startmap - index / DISTMAP;
|
|
}
|
|
else
|
|
{
|
|
// same calculation as Eternity Engine
|
|
float startmap = 2.0 * (30.0 - lightLevel / 8.0f);
|
|
level = int(startmap - (1280.0f / dist)) + 1;
|
|
}
|
|
|
|
|
|
if (level < 0) level = 0;
|
|
if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS - 1;
|
|
return level;
|
|
}
|
|
|
|
// This adds fog color to current pixel color
|
|
vec4 getFogColor(vec3 PosW, vec4 color)
|
|
{
|
|
float fogdist = max(16.0, distance(PosW, campos.xyz));
|
|
float fogfactor = exp2(campos.w * fogdist);
|
|
|
|
color.rgb = mix(sectorfogcolor.rgb, color.rgb, fogfactor);
|
|
return color;
|
|
}
|
|
|
|
vec4 desaturate(vec4 texel)
|
|
{
|
|
float gray = (texel.r * 0.3 + texel.g * 0.56 + texel.b * 0.14);
|
|
return vec4(mix(texel.rgb, vec3(gray), desaturation), texel.a);
|
|
}
|
|
|
|
vec3 getOneDynLightContribution(vec3 PosW, vec3 Normal, vec3 light, vec4 lColor, vec4 lPosAndRadius, vec4 lOrientation, vec2 l2Radius)
|
|
{
|
|
|
|
//is face facing away from light source?
|
|
// update 01.02.2017: offset the equation by 3px back to try to emulate GZDoom's broken visibility check.
|
|
float diffuseContribution = dot(Normal, normalize(lPosAndRadius.xyz - PosW + Normal * 3.0));
|
|
if (diffuseContribution < 0.0 && (ignoreNormals == 0 || (lColor.a > 0.979 && lColor.a < 0.981))) // attenuated light and facing away
|
|
return light;
|
|
|
|
diffuseContribution = max(diffuseContribution, 0.0); // to make sure
|
|
|
|
//is pixel in light range?
|
|
float dist = distance(PosW, lPosAndRadius.xyz);
|
|
|
|
if (dist > lPosAndRadius.w)
|
|
return light;
|
|
|
|
float power = 1.0;
|
|
power *= max(lPosAndRadius.w - dist, 0.0) / lPosAndRadius.w;
|
|
|
|
if (lOrientation.w > 0.5)
|
|
{
|
|
vec3 lightDirection = normalize(lPosAndRadius.xyz - PosW);
|
|
float cosDir = dot(lightDirection, lOrientation.xyz);
|
|
float df = smoothstep(l2Radius.y, l2Radius.x, cosDir);
|
|
power *= df;
|
|
}
|
|
|
|
if (lColor.a > 0.979 && lColor.a < 0.981) // attenuated light 98%
|
|
power *= diffuseContribution;
|
|
|
|
// for w/e reason GZDoom also does this
|
|
power *= lColor.a;
|
|
|
|
if (lColor.a >= 1)
|
|
return light.rgb - lColor.rgb * power;
|
|
|
|
return light.rgb + lColor.rgb * power;
|
|
|
|
}
|
|
|
|
vec4 getDynLightContribution(vec4 tcolor, vec4 baselight, vec3 PosW, vec3 Normal)
|
|
{
|
|
vec3 light = vec3(0, 0, 0);
|
|
vec3 addlight = vec3(0, 0, 0);
|
|
|
|
if (lightsEnabled != 0)
|
|
{
|
|
for (int i = 0; i < 64; i++)
|
|
{
|
|
if (lightColor[i].a == 0)
|
|
break;
|
|
if (lightColor[i].a < 0.4) // additive
|
|
addlight = getOneDynLightContribution(PosW, Normal, addlight, lightColor[i], lightPosAndRadius[i], lightOrientation[i], light2Radius[i]);
|
|
else light = getOneDynLightContribution(PosW, Normal, light, lightColor[i], lightPosAndRadius[i], lightOrientation[i], light2Radius[i]);
|
|
}
|
|
}
|
|
|
|
return vec4(tcolor.rgb*(baselight.rgb+light)+addlight, tcolor.a*baselight.a);
|
|
}
|
|
}
|
|
|
|
shader world3d_main
|
|
{
|
|
in
|
|
{
|
|
vec3 Position;
|
|
vec4 Color;
|
|
vec2 TextureCoordinate;
|
|
vec3 Normal;
|
|
}
|
|
|
|
v2f
|
|
{
|
|
vec4 Color;
|
|
vec2 UV;
|
|
vec3 PosW;
|
|
vec3 Normal;
|
|
vec4 viewpos;
|
|
}
|
|
|
|
out
|
|
{
|
|
vec4 FragColor;
|
|
}
|
|
|
|
vertex
|
|
{
|
|
v2f.viewpos = view * world * vec4(in.Position, 1.0);
|
|
gl_Position = projection * v2f.viewpos;
|
|
v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
|
|
v2f.Color = in.Color;
|
|
v2f.UV = in.TextureCoordinate;
|
|
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
|
|
}
|
|
|
|
fragment
|
|
{
|
|
vec4 tcolor = texture(texture1, v2f.UV);
|
|
tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
|
|
tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal);
|
|
out.FragColor = desaturate(tcolor);
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
shader world3d_fullbright extends world3d_main
|
|
{
|
|
fragment
|
|
{
|
|
vec4 tcolor = texture(texture1, v2f.UV);
|
|
tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
|
|
tcolor.a *= v2f.Color.a;
|
|
out.FragColor = tcolor;
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
shader world3d_main_highlight extends world3d_main
|
|
{
|
|
fragment
|
|
{
|
|
vec4 tcolor = texture(texture1, v2f.UV);
|
|
tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
|
|
tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal);
|
|
if (tcolor.a == 0.0)
|
|
{
|
|
out.FragColor = tcolor;
|
|
}
|
|
else
|
|
{
|
|
// Blend texture color and vertex color
|
|
vec4 ncolor = desaturate(tcolor);
|
|
|
|
out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (ncolor.rgb - 0.4 * highlightcolor.a), max(v2f.Color.a + 0.25, 0.5));
|
|
}
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
shader world3d_fullbright_highlight extends world3d_fullbright
|
|
{
|
|
fragment
|
|
{
|
|
vec4 tcolor = texture(texture1, v2f.UV);
|
|
tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
|
|
if(tcolor.a == 0.0)
|
|
{
|
|
out.FragColor = tcolor;
|
|
}
|
|
else
|
|
{
|
|
// Blend texture color and vertex color
|
|
vec4 ncolor = tcolor * v2f.Color;
|
|
|
|
out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (tcolor.rgb - 0.4 * highlightcolor.a), max(v2f.Color.a + 0.25, 0.5));
|
|
}
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
shader world3d_vertex_color extends world3d_main
|
|
{
|
|
fragment
|
|
{
|
|
out.FragColor = v2f.Color;
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
shader world3d_main_vertexcolor extends world3d_main
|
|
{
|
|
vertex
|
|
{
|
|
v2f.viewpos = view * world * vec4(in.Position, 1.0);
|
|
gl_Position = projection * v2f.viewpos;
|
|
v2f.Color = vertexColor;
|
|
v2f.UV = in.TextureCoordinate;
|
|
}
|
|
}
|
|
|
|
shader world3d_constant_color extends world3d_main_vertexcolor
|
|
{
|
|
fragment
|
|
{
|
|
out.FragColor = vertexColor;
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0f) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
// world3d_main_highlight with vertex program from world3d_vertexcolor
|
|
// to-do: rewrite into a function
|
|
shader world3d_highlight_vertexcolor extends world3d_main_highlight
|
|
{
|
|
vertex
|
|
{
|
|
v2f.viewpos = view * world * vec4(in.Position, 1.0);
|
|
gl_Position = projection * v2f.viewpos;
|
|
v2f.Color = vertexColor;
|
|
v2f.UV = in.TextureCoordinate;
|
|
}
|
|
}
|
|
|
|
shader world3d_main_fog extends world3d_main
|
|
{
|
|
fragment
|
|
{
|
|
vec4 tcolor = texture(texture1, v2f.UV);
|
|
tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
|
|
tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal);
|
|
if (tcolor.a == 0.0)
|
|
{
|
|
out.FragColor = tcolor;
|
|
}
|
|
else
|
|
{
|
|
out.FragColor = desaturate(getFogColor(v2f.PosW, tcolor));
|
|
}
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
shader world3d_main_highlight_fog extends world3d_main_fog
|
|
{
|
|
fragment
|
|
{
|
|
vec4 tcolor = texture(texture1, v2f.UV);
|
|
tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
|
|
tcolor = vec4(getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal).rgb, tcolor.a);
|
|
if (tcolor.a == 0.0)
|
|
{
|
|
out.FragColor = tcolor;
|
|
}
|
|
else
|
|
{
|
|
// Blend texture color and vertex color
|
|
vec4 ncolor = desaturate(getFogColor(v2f.PosW, tcolor));
|
|
|
|
out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (ncolor.rgb - 0.4 * highlightcolor.a), max(ncolor.a + 0.25, 0.5));
|
|
}
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
|
|
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
|
|
}
|
|
}
|
|
|
|
// world3d_fog, but with vertex shader from customvertexcolor_fog
|
|
// to-do: rewrite into a function
|
|
shader world3d_main_fog_vertexcolor extends world3d_main_fog
|
|
{
|
|
vertex
|
|
{
|
|
v2f.viewpos = view * world * vec4(in.Position, 1.0);
|
|
gl_Position = projection * v2f.viewpos;
|
|
v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
|
|
v2f.Color = vertexColor;
|
|
v2f.UV = in.TextureCoordinate;
|
|
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
|
|
}
|
|
}
|
|
|
|
shader world3d_main_highlight_fog_vertexcolor extends world3d_main_highlight_fog
|
|
{
|
|
vertex
|
|
{
|
|
v2f.viewpos = view * world * vec4(in.Position, 1.0);
|
|
gl_Position = projection * v2f.viewpos;
|
|
v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
|
|
v2f.Color = vertexColor;
|
|
v2f.UV = in.TextureCoordinate;
|
|
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
|
|
}
|
|
}
|
|
|
|
// Slope handle shader
|
|
shader world3d_slope_handle extends world3d_vertex_color
|
|
{
|
|
vertex
|
|
{
|
|
v2f.viewpos = view * world * vec4(in.Position.x * slopeHandleLength, in.Position.y, in.Position.z, 1.0);
|
|
gl_Position = projection * v2f.viewpos;
|
|
v2f.Color = in.Color * vertexColor;
|
|
v2f.UV = in.TextureCoordinate;
|
|
}
|
|
}
|
|
|
|
|
|
shader world3d_classic extends world3d_main
|
|
{
|
|
fragment
|
|
{
|
|
vec4 pcolor;
|
|
|
|
if (bool(drawPaletted))
|
|
{
|
|
vec4 color = texture(texture1, v2f.UV);
|
|
int entry = int(color.r * 255);
|
|
float alpha = color.a;
|
|
int colorMapOffset = classicLightLevelToColorMapOffset(lightLevel, v2f.PosW, v2f.Normal);
|
|
pcolor = getColorMappedColor(entry, colorMapOffset);
|
|
pcolor.a = alpha;
|
|
}
|
|
else
|
|
{
|
|
pcolor = texture(texture1, v2f.UV);
|
|
}
|
|
|
|
out.FragColor = pcolor;
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
shader world3d_classic_highlight extends world3d_main
|
|
{
|
|
fragment
|
|
{
|
|
vec4 pcolor;
|
|
|
|
if (bool(drawPaletted))
|
|
{
|
|
vec4 color = texture(texture1, v2f.UV);
|
|
int entry = int(color.r * 255);
|
|
float alpha = color.a;
|
|
int modifiedLightLevel = max(lightLevel, 128);
|
|
int colorMapOffset = classicLightLevelToColorMapOffset(modifiedLightLevel, v2f.PosW, v2f.Normal);
|
|
pcolor = getColorMappedColor(entry, colorMapOffset);
|
|
pcolor.a = alpha;
|
|
}
|
|
else
|
|
{
|
|
pcolor = texture(texture1, v2f.UV);
|
|
}
|
|
|
|
out.FragColor = pcolor;
|
|
|
|
if (pcolor.a > 0.0)
|
|
{
|
|
out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (pcolor.rgb - 0.4 * highlightcolor.a), max(pcolor.a + 0.25, 0.5));
|
|
}
|
|
|
|
#if defined(ALPHA_TEST)
|
|
if (out.FragColor.a < 0.5) discard;
|
|
#endif
|
|
}
|
|
} |