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 & 7) != 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 & 7) == 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 & 7) == 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 & 7) == 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 & 7) == 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) { #ifndef PALETTE_EMULATION // 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; #else return 0.0; // with palette emulation we do not want real lighting. #endif } 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 #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; 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 = vec4(frag.rgb * uDynLightColor.a, frag.a); // apply a global fade factor. }