diff --git a/CMakeLists.txt b/CMakeLists.txt index 69016ca66..37c4f076e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,6 +191,7 @@ if( ${TARGET_ARCHITECTURE} MATCHES "x86_64" ) endif() option (HAVE_VULKAN "Enable Vulkan support" ON) +option (HAVE_GLES2 "Enable GLES2 support" ON) # no, we're not using external asmjit for now, we made too many modifications to our's. # if the asmjit author uses our changes then we'll update this. @@ -207,10 +208,14 @@ if( MSVC ) # String pooling # Function-level linking # Disable run-time type information + set( ALL_C_FLAGS "/GF /Gy /permissive-" ) + if ( HAVE_VULKAN ) - set( ALL_C_FLAGS "/GF /Gy /permissive- /DHAVE_VULKAN" ) - else() - set( ALL_C_FLAGS "/GF /Gy /permissive-" ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} /DHAVE_VULKAN" ) + endif() + + if ( HAVE_GLES2 ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} /DHAVE_GLES2" ) endif() # Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall @@ -253,12 +258,15 @@ if( MSVC ) string(REPLACE " /GR" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ) else() set( REL_LINKER_FLAGS "" ) + set( ALL_C_FLAGS "-ffp-contract=off" ) + if ( HAVE_VULKAN ) - set( ALL_C_FLAGS "-ffp-contract=off -DHAVE_VULKAN" ) - else() - set( ALL_C_FLAGS "-ffp-contract=off" ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} -DHAVE_VULKAN" ) + endif() + + if ( HAVE_GLES2 ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} -DHAVE_GLES2" ) endif() - set( ALL_C_FLAGS "${ALL_C_FLAGS} -DUSE_OPENGL=1 -DNOASM=1" ) if ( UNIX ) include(CheckSymbolExists) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 636135d16..a486186ab 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -967,6 +967,26 @@ set (VULKAN_SOURCES common/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.cpp ) +if (HAVE_GLES2) + set (GLES_SOURCES + common/rendering/gles/gles_system.cpp + common/rendering/gles/gles_renderer.cpp + common/rendering/gles/gles_framebuffer.cpp + common/rendering/gles/gles_renderstate.cpp + common/rendering/gles/gles_renderbuffers.cpp + common/rendering/gles/gles_postprocess.cpp + common/rendering/gles/gles_postprocessstate.cpp + common/rendering/gles/gles_buffers.cpp + common/rendering/gles/gles_hwtexture.cpp + common/rendering/gles/gles_shader.cpp + common/rendering/gles/gles_shaderprogram.cpp + common/rendering/gles/gles_samplers.cpp + common/rendering/gles/glad/src/glad.c + ) + + set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${GLES_SOURCES}) +endif() + if (HAVE_VULKAN) set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${VULKAN_SOURCES}) endif() @@ -1381,6 +1401,9 @@ include_directories( common/rendering/hwrenderer/data common/rendering/gl_load common/rendering/gl + common/rendering/gles + common/rendering/gles/glad/include + common/rendering/gles/Mali_OpenGL_ES_Emulator/include common/rendering/vulkan/thirdparty common/rendering/polyrenderer/backend common/rendering/polyrenderer/drawers @@ -1546,6 +1569,7 @@ source_group("Common\\Rendering\\Hardware Renderer\\Data" REGULAR_EXPRESSION "^$ source_group("Common\\Rendering\\Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/postprocessing/.+") source_group("Common\\Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gl_load/.+") source_group("Common\\Rendering\\OpenGL Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gl/.+") +source_group("Common\\Rendering\\GLES Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gles/.+") source_group("Common\\Rendering\\Vulkan Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/system/.+") source_group("Common\\Rendering\\Vulkan Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/renderer/.+") source_group("Common\\Rendering\\Vulkan Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/shaders/.+") diff --git a/source/platform/win32/gameres.rc b/source/platform/win32/gameres.rc index 00222f887..7250c8a02 100644 --- a/source/platform/win32/gameres.rc +++ b/source/platform/win32/gameres.rc @@ -27,7 +27,12 @@ BEGIN DEFPUSHBUTTON "&Play Game!",IDOK,8,228,90,14 PUSHBUTTON "E&xit",IDCANCEL,166,228,50,14 CONTROL "&OpenGL",IDC_WELCOME_VULKAN1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,167,41,10 +#ifdef HAVE_VULKAN CONTROL "&Vulkan",IDC_WELCOME_VULKAN2,"Button",BS_AUTORADIOBUTTON,13,177,37,10 +#endif +#ifdef HAVE_GLES2 + CONTROL "OpenGL &ES",IDC_WELCOME_VULKAN4,"Button",BS_AUTORADIOBUTTON,13,187,53,10 +#endif END IDD_CRASHDIALOG DIALOGEX 0, 0, 415, 308 diff --git a/wadsrc/static/shaders_gles/Uniform usage notes.txt b/wadsrc/static/shaders_gles/Uniform usage notes.txt new file mode 100644 index 000000000..cae1bc255 --- /dev/null +++ b/wadsrc/static/shaders_gles/Uniform usage notes.txt @@ -0,0 +1,90 @@ +How can I remove the alpha test discard? + + +MISSING: +All post processing gone +Present shader missing dither +Shadow maps gone +HDR modes gone +Materials gone +gl_satformula does not do anything (remove an 'if' in shader) + +Broken to be fixed: +Texture filtering modes, currently fixed to linear mipmap + + + + + + +-------------------------------------- +uTextureMode + +0xFFFF = +(USES all) + TM_NORMAL = 0, // (r, g, b, a) + TM_STENCIL, // (1, 1, 1, a) + TM_OPAQUE, // (r, g, b, 1) + TM_INVERSE, // (1-r, 1-g, 1-b, a) + TM_ALPHATEXTURE, // (1, 1, 1, r) + TM_CLAMPY, // (r, g, b, (t >= 0.0 && t <= 1.0)? a:0) + TM_INVERTOPAQUE, // (1-r, 1-g, 1-b, 1) + TM_FOGLAYER, // (renders a fog layer in the shape of the active texture) + TM_FIXEDCOLORMAP = TM_FOGLAYER, + +0xF0000 = +(USES all) + TEXF_Brightmap = 0x10000, + TEXF_Detailmap = 0x20000, + TEXF_Glowmap = 0x40000, + + + + + + +uPalLightLevels + +0xFF = + 32 0r 0 or 1 + +0xFF00 = +gl_fogmode : +(USES 2) + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_STANDARD" + 2, "$OPTVAL_RADIAL" + +0xFF0000 +gl_lightmode: +(USES 16, 5) + 0, "$OPTVAL_STANDARD" + 1, "$OPTVAL_BRIGHT" + 2, "$OPTVAL_DOOM" + 3, "$OPTVAL_DARK" + 4, "$OPTVAL_LEGACY" + 5, "$OPTVAL_BUILD" + 8, "$OPTVAL_SOFTWARE" + 16, "$OPTVAL_VANILLA" + + + + + +uTextureAddColor.a -> blendflags +0x7 = +(USES all) +const int Tex_Blend_Alpha = 1; +const int Tex_Blend_Screen = 2; +const int Tex_Blend_Overlay = 3; +const int Tex_Blend_Hardlight = 4; + + +0x8 = +Invert blend bit + + + + +uDesaturationFactor +> 0 diff --git a/wadsrc/static/shaders_gles/glsl/burn.fp b/wadsrc/static/shaders_gles/glsl/burn.fp new file mode 100644 index 000000000..040311711 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/burn.fp @@ -0,0 +1,13 @@ + +varying vec4 vTexCoord; +varying vec4 vColor; + +void main() +{ + vec4 frag = vColor; + + vec4 t1 = texture2D(tex, vTexCoord.xy); + vec4 t2 = texture2D(texture2, vec2(vTexCoord.x, 1.0-vTexCoord.y)); + + gl_FragColor = frag * vec4(t1.r, t1.g, t1.b, t2.a); +} diff --git a/wadsrc/static/shaders_gles/glsl/fogboundary.fp b/wadsrc/static/shaders_gles/glsl/fogboundary.fp new file mode 100644 index 000000000..9a6448bee --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fogboundary.fp @@ -0,0 +1,30 @@ +varying vec4 pixelpos; + +//=========================================================================== +// +// Main shader routine +// +//=========================================================================== + +void main() +{ + float fogdist; + float fogfactor; + + // + // calculate fog factor + // +#if (DEF_FOG_ENABLED == 1) && (DEF_FOG_RADIAL == 0) && (DEF_FOG_COLOURED == 1) // This was uFogEnabled = -1,, TODO check this + { + fogdist = pixelpos.w; + } +#else + { + fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + } +#endif + fogfactor = exp2 (uFogDensity * fogdist); + + gl_FragColor = vec4(uFogColor.rgb, 1.0 - fogfactor); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_defaultlight.fp b/wadsrc/static/shaders_gles/glsl/func_defaultlight.fp new file mode 100644 index 000000000..6738af8f5 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_defaultlight.fp @@ -0,0 +1,5 @@ + +vec4 ProcessLight(Material material, vec4 color) +{ + return color; +} diff --git a/wadsrc/static/shaders_gles/glsl/func_defaultmat.fp b/wadsrc/static/shaders_gles/glsl/func_defaultmat.fp new file mode 100644 index 000000000..35006820c --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_defaultmat.fp @@ -0,0 +1,7 @@ + +void SetupMaterial(inout Material material) +{ + material.Base = ProcessTexel(); + material.Normal = ApplyNormalMap(vTexCoord.st); + material.Bright = texture2D(brighttexture, vTexCoord.st); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_defaultmat2.fp b/wadsrc/static/shaders_gles/glsl/func_defaultmat2.fp new file mode 100644 index 000000000..b2beb254e --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_defaultmat2.fp @@ -0,0 +1,6 @@ + +void SetupMaterial(inout Material material) +{ + vec2 texCoord = GetTexCoord(); + SetMaterialProps(material, texCoord); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_normal.fp b/wadsrc/static/shaders_gles/glsl/func_normal.fp new file mode 100644 index 000000000..49dfadd9a --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_normal.fp @@ -0,0 +1,5 @@ + +void SetupMaterial(inout Material material) +{ + SetMaterialProps(material, vTexCoord.st); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_notexture.fp b/wadsrc/static/shaders_gles/glsl/func_notexture.fp new file mode 100644 index 000000000..9337ad6b1 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_notexture.fp @@ -0,0 +1,6 @@ + +vec4 ProcessTexel() +{ + return desaturate(uObjectColor); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_paletted.fp b/wadsrc/static/shaders_gles/glsl/func_paletted.fp new file mode 100644 index 000000000..8de8f0747 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_paletted.fp @@ -0,0 +1,10 @@ + +vec4 ProcessTexel() +{ + float index = getTexel(vTexCoord.st).r; + index = ((index * 255.0) + 0.5) / 256.0; + vec4 tex = texture2D(texture2, vec2(index, 0.5)); + tex.a = 1.0; + return tex; +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_pbr.fp b/wadsrc/static/shaders_gles/glsl/func_pbr.fp new file mode 100644 index 000000000..49dfadd9a --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_pbr.fp @@ -0,0 +1,5 @@ + +void SetupMaterial(inout Material material) +{ + SetMaterialProps(material, vTexCoord.st); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_spec.fp b/wadsrc/static/shaders_gles/glsl/func_spec.fp new file mode 100644 index 000000000..f2574a521 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_spec.fp @@ -0,0 +1,8 @@ + +void SetupMaterial(inout Material material) +{ + SetMaterialProps(material, vTexCoord.st); + material.Specular = texture2D(speculartexture, vTexCoord.st).rgb; + material.Glossiness = uSpecularMaterial.x; + material.SpecularLevel = uSpecularMaterial.y; +} diff --git a/wadsrc/static/shaders_gles/glsl/func_warp1.fp b/wadsrc/static/shaders_gles/glsl/func_warp1.fp new file mode 100644 index 000000000..dfadf8ada --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_warp1.fp @@ -0,0 +1,19 @@ + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + vec2 offset = vec2(0,0); + + offset.y = sin(pi * 2.0 * (texCoord.x + timer * 0.125)) * 0.1; + offset.x = sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; + + return texCoord + offset; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_warp2.fp b/wadsrc/static/shaders_gles/glsl/func_warp2.fp new file mode 100644 index 000000000..1ee0f7fd0 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_warp2.fp @@ -0,0 +1,20 @@ + + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + vec2 offset = vec2(0.0,0.0); + + offset.y = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.61 + 900.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.36 + 300.0/8192.0)); + offset.x = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.49 + 700.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.49 + 1200.0/8192.0)); + + return texCoord + offset * 0.025; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_warp3.fp b/wadsrc/static/shaders_gles/glsl/func_warp3.fp new file mode 100644 index 000000000..9edea0004 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_warp3.fp @@ -0,0 +1,21 @@ + + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + vec2 offset = vec2(0.0,0.0); + + float siny = sin(pi * 2.0 * (texCoord.y * 2.0 + timer * 0.75)) * 0.03; + offset.y = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.75)) * 0.03; + offset.x = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.45)) * 0.02; + + return texCoord + offset; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_wavex.fp b/wadsrc/static/shaders_gles/glsl/func_wavex.fp new file mode 100644 index 000000000..3b892da9d --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_wavex.fp @@ -0,0 +1,17 @@ + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + + texCoord.x += sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; + + return texCoord; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_jagged.fp b/wadsrc/static/shaders_gles/glsl/fuzz_jagged.fp new file mode 100644 index 000000000..083c22068 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_jagged.fp @@ -0,0 +1,24 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + + vec2 texSplat; + const float pi = 3.14159265358979323846; + texSplat.x = texCoord.x + mod(sin(pi * 2.0 * (texCoord.y + timer * 2.0)),0.1) * 0.1; + texSplat.y = texCoord.y + mod(cos(pi * 2.0 * (texCoord.x + timer * 2.0)),0.1) * 0.1; + + vec4 basicColor = getTexel(texSplat); + + float texX = sin(texCoord.x * 100.0 + timer*5.0); + float texY = cos(texCoord.x * 100.0 + timer*5.0); + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_noise.fp b/wadsrc/static/shaders_gles/glsl/fuzz_noise.fp new file mode 100644 index 000000000..0107ebbd2 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_noise.fp @@ -0,0 +1,20 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + texCoord.x = float( int(texCoord.x * 128.0) ) / 128.0; + texCoord.y = float( int(texCoord.y * 128.0) ) / 128.0; + + float texX = sin(mod(texCoord.x * 100.0 + timer*5.0, 3.489)) + texCoord.x / 4.0; + float texY = cos(mod(texCoord.y * 100.0 + timer*5.0, 3.489)) + texCoord.y / 4.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + float test = mod(timer*2.0+(vX + vY), 0.5); + basicColor.a = basicColor.a * test; + basicColor.rgb = vec3(0.0,0.0,0.0); + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_smooth.fp b/wadsrc/static/shaders_gles/glsl/fuzz_smooth.fp new file mode 100644 index 000000000..3c642c399 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_smooth.fp @@ -0,0 +1,18 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = texCoord.x / 3.0 + 0.66; + float texY = 0.34 - texCoord.y / 3.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_smoothnoise.fp b/wadsrc/static/shaders_gles/glsl/fuzz_smoothnoise.fp new file mode 100644 index 000000000..d446a3d0a --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_smoothnoise.fp @@ -0,0 +1,19 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = sin(mod(texCoord.x * 100.0 + timer*5.0, 3.489)) + texCoord.x / 4.0; + float texY = cos(mod(texCoord.y * 100.0 + timer*5.0, 3.489)) + texCoord.y / 4.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + + float test = mod(timer*2.0+(vX + vY), 0.5); + basicColor.a = basicColor.a * test; + + basicColor.rgb = vec3(0.0,0.0,0.0); + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_smoothtranslucent.fp b/wadsrc/static/shaders_gles/glsl/fuzz_smoothtranslucent.fp new file mode 100644 index 000000000..1b727a1bc --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_smoothtranslucent.fp @@ -0,0 +1,18 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = sin(texCoord.x * 100.0 + timer*5.0); + float texY = cos(texCoord.x * 100.0 + timer*5.0); + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_software.fp b/wadsrc/static/shaders_gles/glsl/fuzz_software.fp new file mode 100644 index 000000000..1edcb0099 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_software.fp @@ -0,0 +1,21 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + texCoord.x = float( int(texCoord.x * 128.0) ) / 128.0; + texCoord.y = float( int(texCoord.y * 128.0) ) / 128.0; + + float texX = texCoord.x / 3.0 + 0.66; + float texY = 0.34 - texCoord.y / 3.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_standard.fp b/wadsrc/static/shaders_gles/glsl/fuzz_standard.fp new file mode 100644 index 000000000..1edcb0099 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_standard.fp @@ -0,0 +1,21 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + texCoord.x = float( int(texCoord.x * 128.0) ) / 128.0; + texCoord.y = float( int(texCoord.y * 128.0) ) / 128.0; + + float texX = texCoord.x / 3.0 + 0.66; + float texY = 0.34 - texCoord.y / 3.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_swirly.fp b/wadsrc/static/shaders_gles/glsl/fuzz_swirly.fp new file mode 100644 index 000000000..266858999 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_swirly.fp @@ -0,0 +1,18 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = sin(texCoord.x * 100.0 + timer*5.0); + float texY = cos(texCoord.x * 100.0 + timer*5.0); + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/main.fp b/wadsrc/static/shaders_gles/glsl/main.fp new file mode 100644 index 000000000..92e77eefe --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/main.fp @@ -0,0 +1,566 @@ + +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, DEF_BLEND_FLAGS); + +#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 + + #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 = frag; + + //gl_FragColor = vec4(0.8, 0.2, 0.5, 1); + +} diff --git a/wadsrc/static/shaders_gles/glsl/main.vp b/wadsrc/static/shaders_gles/glsl/main.vp new file mode 100644 index 000000000..1e87864c1 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/main.vp @@ -0,0 +1,134 @@ + +attribute vec4 aPosition; +attribute vec2 aTexCoord; +attribute vec4 aColor; + +varying vec4 vTexCoord; +varying vec4 vColor; + +#ifndef SIMPLE // we do not need these for simple shaders +attribute vec4 aVertex2; +attribute vec4 aNormal; +attribute vec4 aNormal2; + +varying vec4 pixelpos; +varying vec3 glowdist; +varying vec3 gradientdist; +varying vec4 vWorldNormal; +varying vec4 vEyeNormal; +#endif + +#ifdef NO_CLIPDISTANCE_SUPPORT +varying vec4 ClipDistanceA; +varying vec4 ClipDistanceB; +#endif + +void main() +{ + float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; + + vec2 parmTexCoord; + vec4 parmPosition; + + parmTexCoord = aTexCoord; + parmPosition = aPosition; + + #ifndef SIMPLE + vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor); + #else + vec4 worldcoord = ModelMatrix * parmPosition; + #endif + + vec4 eyeCoordPos = ViewMatrix * worldcoord; + + #ifdef HAS_UNIFORM_VERTEX_DATA + if ((useVertexData & 1) == 0) + vColor = uVertexColor; + else + vColor = aColor; + #else + vColor = aColor; + #endif + + #ifndef SIMPLE + pixelpos.xyz = worldcoord.xyz; + pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; + + if (uGlowTopColor.a > 0.0 || uGlowBottomColor.a > 0.0) + { + float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z; + float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z; + glowdist.x = topatpoint - worldcoord.y; + glowdist.y = worldcoord.y - bottomatpoint; + glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } + + if (uObjectColor2.a != 0.0) + { + float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; + float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z; + gradientdist.x = topatpoint - worldcoord.y; + gradientdist.y = worldcoord.y - bottomatpoint; + gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } + + if (uSplitBottomPlane.z != 0.0) + { + ClipDistance3 = ((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; + ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); + } + + #ifdef HAS_UNIFORM_VERTEX_DATA + if ((useVertexData & 2) == 0) + vWorldNormal = NormalModelMatrix * vec4(uVertexNormal.xyz, 1.0); + else + vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0); + #else + vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0); + #endif + vEyeNormal = NormalViewMatrix * vWorldNormal; + #endif + + #ifdef SPHEREMAP + vec3 u = normalize(eyeCoordPos.xyz); + vec4 n = normalize(NormalViewMatrix * vec4(parmTexCoord.x, 0.0, parmTexCoord.y, 0.0)); + vec3 r = reflect(u, n.xyz); + float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); + vec2 sst = vec2(r.x/m + 0.5, r.y/m + 0.5); + vTexCoord.xy = sst; + #else + vTexCoord = TextureMatrix * vec4(parmTexCoord, 0.0, 1.0); + #endif + + + if (uClipHeightDirection != 0.0) // clip planes used for reflective flats + { + ClipDistance0 = (worldcoord.y - uClipHeight) * uClipHeightDirection; + } + else if (uClipLine.x > -1000000.0) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane. + { + ClipDistance0 = -( (worldcoord.z - uClipLine.y) * uClipLine.z + (uClipLine.x - worldcoord.x) * uClipLine.w ) + 1.0/32768.0; // allow a tiny bit of imprecisions for colinear linedefs. + } + else + { + ClipDistance0 = 1.0; + } + + // clip planes used for translucency splitting + ClipDistance1 = worldcoord.y - uClipSplit.x; + ClipDistance2 = uClipSplit.y - worldcoord.y; + + if (uSplitTopPlane == vec4(0.0)) + { + ClipDistance3 = 1.0; + ClipDistance4 = 1.0; + } + + ClipDistanceA = vec4(ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3); + ClipDistanceB = vec4(ClipDistance4, 0.0, 0.0, 0.0); + + + //gl_PointSize = 1.0; + + gl_Position = ProjectionMatrix * eyeCoordPos; +} diff --git a/wadsrc/static/shaders_gles/glsl/material_nolight.fp b/wadsrc/static/shaders_gles/glsl/material_nolight.fp new file mode 100644 index 000000000..b71404423 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/material_nolight.fp @@ -0,0 +1,5 @@ + +vec3 ProcessMaterialLight(Material material, vec3 color) +{ + return material.Base.rgb * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4); +} diff --git a/wadsrc/static/shaders_gles/glsl/material_normal.fp b/wadsrc/static/shaders_gles/glsl/material_normal.fp new file mode 100644 index 000000000..61d8abbee --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/material_normal.fp @@ -0,0 +1,130 @@ + +vec3 lightContribution(int i, vec3 normal) +{ + vec4 lightpos = lights[i]; + vec4 lightcolor = lights[i+1]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + + //if (lightpos.w < lightdistance) + // return vec3(0.0); // Early out lights touching surface but not this fragment + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + float dotprod = dot(normal, lightdir); + + //if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues. + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + + // NOTE, all spot light stuff gone + return lightcolor.rgb * attenuation; + +/* + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag + { + attenuation *= clamp(dotprod, 0.0, 1.0); + } + + + + if (attenuation > 0.0) // Skip shadow map test if possible + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + return lightcolor.rgb * attenuation; + } + else + { + return vec3(0.0); + } +*/ +} + + +vec3 ProcessMaterialLight(Material material, vec3 color) +{ + vec4 dynlight = uDynLightColor; + vec3 normal = material.Normal; + +#if (DEF_DYNAMIC_LIGHTS_MOD == 1) + // modulated lights + + // Some very old GLES2 hardward does not allow non-constants in a for-loop expression because it can not unroll it. + // However they do allow 'break' and use stupid hack + #if (USE_GLSL_V100 == 1) + + for(int i = 0; i < 8; i++) // Max 8 lights + { + if(i == ((uLightRange.y - uLightRange.x) / 4)) + break; + + dynlight.rgb += lightContribution(i * 4, normal); + } + + #else + + for(int i=uLightRange.x; i= 0) + { + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + if (lightRange.z > lightRange.x) + { + // + // modulated lights + // + for(int i=lightRange.x; i 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + + vec3 radiance = lightcolor.rgb * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); + + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo += (kD * albedo / PI + specular) * radiance; + } + } + // + // subtractive lights + // + for(int i=lightRange.y; i 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + + vec3 radiance = lightcolor.rgb * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); + + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo -= (kD * albedo / PI + specular) * radiance; + } + } + } + } + + // Pretend we sampled the sector light level from an irradiance map + + vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); + + vec3 kS = F; + vec3 kD = 1.0 - kS; + + vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb + vec3 diffuse = irradiance * albedo; + + //kD *= 1.0 - metallic; + //const float MAX_REFLECTION_LOD = 4.0; + //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; + //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; + //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); + + //vec3 ambient = (kD * diffuse + specular) * ao; + vec3 ambient = (kD * diffuse) * ao; + + vec3 color = max(ambient + Lo, vec3(0.0)); + + // Tonemap (reinhard) and apply sRGB gamma + //color = color / (color + vec3(1.0)); + return pow(color, vec3(1.0 / 2.2)); +} diff --git a/wadsrc/static/shaders_gles/glsl/material_specular.fp b/wadsrc/static/shaders_gles/glsl/material_specular.fp new file mode 100644 index 000000000..f6c142308 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/material_specular.fp @@ -0,0 +1,95 @@ + +vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) +{ + vec4 lightpos = lights[i]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec2(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + + if (lightcolorA < 0.0) // Sign bit is the attenuated light flag + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + + if (attenuation > 0.0) // Skip shadow map test if possible + attenuation *= shadowAttenuation(lightpos, lightcolorA); + + if (attenuation <= 0.0) + return vec2(0.0); + + float glossiness = uSpecularMaterial.x; + float specularLevel = uSpecularMaterial.y; + + vec3 halfdir = normalize(viewdir + lightdir); + float specAngle = clamp(dot(halfdir, normal), 0.0, 1.0); + float phExp = glossiness * 4.0; + return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); +} + +vec3 ProcessMaterialLight(Material material, vec3 color) +{ + vec4 dynlight = uDynLightColor; + vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); + + vec3 normal = material.Normal; + vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); + + if (uLightIndex >= 0) + { + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i= 0) + { + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + if (lightRange.w > lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + #if (FXAA_DISCARD == 1) + return FxaaTexTop(tex, posM); + #else + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); + #endif +} + +void main() +{ + FragColor = FxaaPixelShader(TexCoord, InputTexture, ReciprocalResolution, 0.75f, 0.166f, 0.0833f); +} + +#endif // FXAA_LUMA_PASS diff --git a/wadsrc/static/shaders_gles/pp/lensdistortion.fp b/wadsrc/static/shaders_gles/pp/lensdistortion.fp new file mode 100644 index 000000000..1b0d47b4f --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/lensdistortion.fp @@ -0,0 +1,54 @@ +/* + Original Lens Distortion Algorithm from SSontech + http://www.ssontech.com/content/lensalg.htm + + If (u,v) are the coordinates of a feature in the undistorted perfect + image plane, then (u', v') are the coordinates of the feature on the + distorted image plate, ie the scanned or captured image from the + camera. The distortion occurs radially away from the image center, + with correction for the image aspect ratio (image_aspect = physical + image width/height), as follows: + + r2 = image_aspect*image_aspect*u*u + v*v + f = 1 + r2*(k + kcube*sqrt(r2)) + u' = f*u + v' = f*v + + The constant k is the distortion coefficient that appears on the lens + panel and through Sizzle. It is generally a small positive or negative + number under 1%. The constant kcube is the cubic distortion value found + on the image preprocessor's lens panel: it can be used to undistort or + redistort images, but it does not affect or get computed by the solver. + When no cubic distortion is needed, neither is the square root, saving + time. + + Chromatic Aberration example, + using red distord channel with green and blue undistord channel: + + k = vec3(-0.15, 0.0, 0.0); + kcube = vec3(0.15, 0.0, 0.0); +*/ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D InputTexture; + +void main() +{ + vec2 position = (TexCoord - vec2(0.5)); + + vec2 p = vec2(position.x * Aspect, position.y); + float r2 = dot(p, p); + vec3 f = vec3(1.0) + r2 * (k.rgb + kcube.rgb * sqrt(r2)); + + vec3 x = f * position.x * Scale + 0.5; + vec3 y = f * position.y * Scale + 0.5; + + vec3 c; + c.r = texture(InputTexture, vec2(x.r, y.r)).r; + c.g = texture(InputTexture, vec2(x.g, y.g)).g; + c.b = texture(InputTexture, vec2(x.b, y.b)).b; + + FragColor = vec4(c, 1.0); +} diff --git a/wadsrc/static/shaders_gles/pp/lineardepth.fp b/wadsrc/static/shaders_gles/pp/lineardepth.fp new file mode 100644 index 000000000..7966e310a --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/lineardepth.fp @@ -0,0 +1,38 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +#if defined(MULTISAMPLE) +layout(binding=0) uniform sampler2DMS DepthTexture; +layout(binding=1) uniform sampler2DMS ColorTexture; +#else +layout(binding=0) uniform sampler2D DepthTexture; +layout(binding=1) uniform sampler2D ColorTexture; +#endif + +float normalizeDepth(float depth) +{ + float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); + return 1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB); +} + +void main() +{ + vec2 uv = Offset + TexCoord * Scale; + +#if defined(MULTISAMPLE) + ivec2 texSize = textureSize(DepthTexture); +#else + ivec2 texSize = textureSize(DepthTexture, 0); +#endif + + ivec2 ipos = ivec2(max(uv * vec2(texSize), vec2(0.0))); + +#if defined(MULTISAMPLE) + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, SampleIndex).a != 0.0 ? texelFetch(DepthTexture, ipos, SampleIndex).x : 1.0); +#else + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); +#endif + + FragColor = vec4(depth, 0.0, 0.0, 1.0); +} diff --git a/wadsrc/static/shaders_gles/pp/present.fp b/wadsrc/static/shaders_gles/pp/present.fp new file mode 100644 index 000000000..a27b78f33 --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/present.fp @@ -0,0 +1,32 @@ + +varying vec2 TexCoord; + +uniform sampler2D InputTexture; +uniform sampler2D DitherTexture; + +vec4 ApplyGamma(vec4 c) +{ + vec3 valgray; + + valgray = mix(vec3(dot(c.rgb, vec3(0.3,0.56,0.14))), c.rgb, Saturation); + + vec3 val = valgray * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +//vec4 Dither(vec4 c) +//{ +// if (ColorScale == 0.0) +// return c; +// vec2 texSize = vec2(textureSize(DitherTexture, 0)); +// float threshold = texture2D(DitherTexture, gl_FragCoord.xy / texSize).r; +// return vec4(floor(c.rgb * ColorScale + threshold) / ColorScale, c.a); +//} + + +void main() +{ + gl_FragColor = ApplyGamma(texture2D(InputTexture, UVOffset + TexCoord * UVScale)); +} diff --git a/wadsrc/static/shaders_gles/pp/present_checker3d.fp b/wadsrc/static/shaders_gles/pp/present_checker3d.fp new file mode 100644 index 000000000..36d77e250 --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/present_checker3d.fp @@ -0,0 +1,33 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D LeftEyeTexture; +layout(binding=1) uniform sampler2D RightEyeTexture; + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + int thisVerticalPixel = int(gl_FragCoord.y); // Bottom row is typically the right eye, when WindowHeight is even + int thisHorizontalPixel = int(gl_FragCoord.x); // column + bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row + + thisHorizontalPixel // and each column + + WindowPositionParity // because the window might not be aligned to the screen + ) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, UVOffset + TexCoord * UVScale); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, UVOffset + TexCoord * UVScale); + } + FragColor = ApplyGamma(inputColor); +} diff --git a/wadsrc/static/shaders_gles/pp/present_column3d.fp b/wadsrc/static/shaders_gles/pp/present_column3d.fp new file mode 100644 index 000000000..cf8758e3a --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/present_column3d.fp @@ -0,0 +1,31 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D LeftEyeTexture; +layout(binding=1) uniform sampler2D RightEyeTexture; + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + int thisHorizontalPixel = int(gl_FragCoord.x); // zero-based column index from left + bool isLeftEye = (thisHorizontalPixel // because we want to alternate eye view on each column + + WindowPositionParity // because the window might not be aligned to the screen + ) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, UVOffset + TexCoord * UVScale); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, UVOffset + TexCoord * UVScale); + } + FragColor = ApplyGamma(inputColor); +} diff --git a/wadsrc/static/shaders_gles/pp/present_row3d.fp b/wadsrc/static/shaders_gles/pp/present_row3d.fp new file mode 100644 index 000000000..a88be0ed0 --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/present_row3d.fp @@ -0,0 +1,31 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D LeftEyeTexture; +layout(binding=1) uniform sampler2D RightEyeTexture; + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + int thisVerticalPixel = int(gl_FragCoord.y); // Bottom row is typically the right eye, when WindowHeight is even + bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row + + WindowPositionParity // because the window might not be aligned to the screen + ) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, UVOffset + TexCoord * UVScale); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, UVOffset + TexCoord * UVScale); + } + FragColor = ApplyGamma(inputColor); +} diff --git a/wadsrc/static/shaders_gles/pp/screenquad.vp b/wadsrc/static/shaders_gles/pp/screenquad.vp new file mode 100644 index 000000000..87378f6e9 --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/screenquad.vp @@ -0,0 +1,11 @@ + +attribute vec4 PositionInProjection; +attribute vec2 UV; + +varying vec2 TexCoord; + +void main() +{ + gl_Position = PositionInProjection; + TexCoord = UV; +} diff --git a/wadsrc/static/shaders_gles/pp/shadowmap.fp b/wadsrc/static/shaders_gles/pp/shadowmap.fp new file mode 100644 index 000000000..ec141f0fc --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/shadowmap.fp @@ -0,0 +1,190 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +// A node in an AABB binary tree with lines stored in the leaf nodes +struct GPUNode +{ + vec2 aabb_min; // Min xy values for the axis-aligned box containing the node and its subtree + vec2 aabb_max; // Max xy values + int left; // Left subnode index + int right; // Right subnode index + int line_index; // Line index if it is a leaf node, otherwise -1 + int padding; // Unused - maintains 16 byte alignment +}; + +// 2D line segment, referenced by leaf nodes +struct GPULine +{ + vec2 pos; // Line start position + vec2 delta; // Line end position - line start position +}; + +layout(std430, binding = 4) buffer LightNodes +{ + GPUNode nodes[]; +}; + +layout(std430, binding = 5) buffer LightLines +{ + GPULine lines[]; +}; + +layout(std430, binding = 6) buffer LightList +{ + vec4 lights[]; +}; + +// Overlap test between line segment and axis-aligned bounding box. Returns true if they overlap. +bool overlapRayAABB(vec2 ray_start2d, vec2 ray_end2d, vec2 aabb_min2d, vec2 aabb_max2d) +{ + // To do: simplify test to use a 2D test + vec3 ray_start = vec3(ray_start2d, 0.0); + vec3 ray_end = vec3(ray_end2d, 0.0); + vec3 aabb_min = vec3(aabb_min2d, -1.0); + vec3 aabb_max = vec3(aabb_max2d, 1.0); + + vec3 c = (ray_start + ray_end) * 0.5f; + vec3 w = ray_end - c; + vec3 h = (aabb_max - aabb_min) * 0.5f; // aabb.extents(); + + c -= (aabb_max + aabb_min) * 0.5f; // aabb.center(); + + vec3 v = abs(w); + + if (abs(c.x) > v.x + h.x || abs(c.y) > v.y + h.y || abs(c.z) > v.z + h.z) + return false; // disjoint; + + if (abs(c.y * w.z - c.z * w.y) > h.y * v.z + h.z * v.y || + abs(c.x * w.z - c.z * w.x) > h.x * v.z + h.z * v.x || + abs(c.x * w.y - c.y * w.x) > h.x * v.y + h.y * v.x) + return false; // disjoint; + + return true; // overlap; +} + +// Intersection test between two line segments. +// Returns the intersection point as a value between 0-1 on the ray line segment. 1.0 if there was no hit. +float intersectRayLine(vec2 ray_start, vec2 ray_end, int line_index, vec2 raydelta, float rayd, float raydist2) +{ + const float epsilon = 0.0000001; + GPULine line = lines[line_index]; + + vec2 raynormal = vec2(raydelta.y, -raydelta.x); + + float den = dot(raynormal, line.delta); + if (abs(den) > epsilon) + { + float t_line = (rayd - dot(raynormal, line.pos)) / den; + if (t_line >= 0.0 && t_line <= 1.0) + { + vec2 linehitdelta = line.pos + line.delta * t_line - ray_start; + float t = dot(raydelta, linehitdelta) / raydist2; + return t > 0.0 ? t : 1.0; + } + } + + return 1.0; +} + +// Returns true if an AABB tree node is a leaf node. Leaf nodes contains a line. +bool isLeaf(int node_index) +{ + return nodes[node_index].line_index != -1; +} + +// Perform ray intersection test between the ray line segment and all the lines in the AABB binary tree. +// Returns the intersection point as a value between 0-1 on the ray line segment. 1.0 if there was no hit. +float rayTest(vec2 ray_start, vec2 ray_end) +{ + vec2 raydelta = ray_end - ray_start; + float raydist2 = dot(raydelta, raydelta); + vec2 raynormal = vec2(raydelta.y, -raydelta.x); + float rayd = dot(raynormal, ray_start); + if (raydist2 < 1.0) + return 1.0; + + float t = 1.0; + + // Walk the AABB binary tree searching for nodes touching the ray line segment's AABB box. + // When it reaches a leaf node, use a line segment intersection test to see if we got a hit. + + int stack[32]; + int stack_pos = 1; + stack[0] = NodesCount - 1; + while (stack_pos > 0) + { + int node_index = stack[stack_pos - 1]; + + if (!overlapRayAABB(ray_start, ray_end, nodes[node_index].aabb_min, nodes[node_index].aabb_max)) + { + stack_pos--; + } + else if (isLeaf(node_index)) + { + t = min(intersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), t); + stack_pos--; + } + else if (stack_pos == 32) + { + stack_pos--; // stack overflow + } + else + { + stack[stack_pos - 1] = nodes[node_index].left; + stack[stack_pos] = nodes[node_index].right; + stack_pos++; + } + } + + return t; +} + +void main() +{ + // Find the light that belongs to this texel in the shadowmap texture we output to: + + int lightIndex = int(gl_FragCoord.y); + + vec4 light = lights[lightIndex]; + float radius = light.w; + vec2 lightpos = light.xy; + + if (radius > 0.0) + { + // We found an active light. Calculate the ray direction for the texel. + // + // The texels are laid out so that there are four projections: + // + // * top-left to top-right + // * top-right to bottom-right + // * bottom-right to bottom-left + // * bottom-left to top-left + // + vec2 raydir; + float u = gl_FragCoord.x / ShadowmapQuality * 4.0; + switch (int(u)) + { + case 0: raydir = vec2(u * 2.0 - 1.0, 1.0); break; + case 1: raydir = vec2(1.0, 1.0 - (u - 1.0) * 2.0); break; + case 2: raydir = vec2(1.0 - (u - 2.0) * 2.0, -1.0); break; + case 3: raydir = vec2(-1.0, (u - 3.0) * 2.0 - 1.0); break; + } + + // Find the position for the ray starting at the light position and travelling until light contribution is zero: + vec2 pixelpos = lightpos + raydir * radius; + + // Check if we hit any line between the light and the end position: + float t = rayTest(lightpos, pixelpos); + + // Calculate the square distance for the hit, if any: + vec2 delta = (pixelpos - lightpos) * t; + float dist2 = dot(delta, delta); + + FragColor = vec4(dist2, 0.0, 0.0, 1.0); + } + else + { + FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } +} diff --git a/wadsrc/static/shaders_gles/pp/ssao.fp b/wadsrc/static/shaders_gles/pp/ssao.fp new file mode 100644 index 000000000..b3ab1178c --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/ssao.fp @@ -0,0 +1,123 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D DepthTexture; + +#if defined(MULTISAMPLE) +layout(binding=1) uniform sampler2DMS NormalTexture; +#else +layout(binding=1) uniform sampler2D NormalTexture; +#endif + +#if defined(USE_RANDOM_TEXTURE) +layout(binding=2) uniform sampler2D RandomTexture; +#endif + +#define PI 3.14159265358979323846 + +// Calculate eye space position for the specified texture coordinate +vec3 FetchViewPos(vec2 uv) +{ + float z = texture(DepthTexture, uv).x; + return vec3((UVToViewA * uv + UVToViewB) * z, z); +} + +#if defined(MULTISAMPLE) +vec3 SampleNormal(vec2 uv) +{ + ivec2 texSize = textureSize(NormalTexture); + ivec2 ipos = ivec2(uv * vec2(texSize)); + return texelFetch(NormalTexture, ipos, SampleIndex).xyz * 2.0 - 1.0; +} +#else +vec3 SampleNormal(vec2 uv) +{ + ivec2 texSize = textureSize(NormalTexture, 0); + ivec2 ipos = ivec2(uv * vec2(texSize)); + return texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0; +} +#endif + +// Look up the eye space normal for the specified texture coordinate +vec3 FetchNormal(vec2 uv) +{ + vec3 normal = SampleNormal(Offset + uv * Scale); + if (length(normal) > 0.1) + { + normal = normalize(normal); + normal.z = -normal.z; + return normal; + } + else + { + return vec3(0.0); + } +} + +// Compute normalized 2D direction +vec2 RotateDirection(vec2 dir, vec2 cossin) +{ + return vec2(dir.x * cossin.x - dir.y * cossin.y, dir.x * cossin.y + dir.y * cossin.x); +} + +vec4 GetJitter() +{ +#if !defined(USE_RANDOM_TEXTURE) + return vec4(1,0,1,1); + //vec3 rand = noise3(TexCoord.x + TexCoord.y); + //float angle = 2.0 * PI * rand.x / NUM_DIRECTIONS; + //return vec4(cos(angle), sin(angle), rand.y, rand.z); +#else + return texture(RandomTexture, gl_FragCoord.xy / RANDOM_TEXTURE_WIDTH); +#endif +} + +// Calculates the ambient occlusion of a sample +float ComputeSampleAO(vec3 kernelPos, vec3 normal, vec3 samplePos) +{ + vec3 v = samplePos - kernelPos; + float distanceSquare = dot(v, v); + float nDotV = dot(normal, v) * inversesqrt(distanceSquare); + return clamp(nDotV - NDotVBias, 0.0, 1.0) * clamp(distanceSquare * NegInvR2 + 1.0, 0.0, 1.0); +} + +// Calculates the total ambient occlusion for the entire fragment +float ComputeAO(vec3 viewPosition, vec3 viewNormal) +{ + vec4 rand = GetJitter(); + + float radiusPixels = RadiusToScreen / viewPosition.z; + float stepSizePixels = radiusPixels / (NUM_STEPS + 1.0); + + const float directionAngleStep = 2.0 * PI / NUM_DIRECTIONS; + float ao = 0.0; + + for (float directionIndex = 0.0; directionIndex < NUM_DIRECTIONS; ++directionIndex) + { + float angle = directionAngleStep * directionIndex; + + vec2 direction = RotateDirection(vec2(cos(angle), sin(angle)), rand.xy); + float rayPixels = (rand.z * stepSizePixels + 1.0); + + for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex) + { + vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord; + vec3 samplePos = FetchViewPos(sampleUV); + ao += ComputeSampleAO(viewPosition, viewNormal, samplePos); + rayPixels += stepSizePixels; + } + } + + ao *= AOMultiplier / (NUM_DIRECTIONS * NUM_STEPS); + return clamp(1.0 - ao * 2.0, 0.0, 1.0); +} + +void main() +{ + vec3 viewPosition = FetchViewPos(TexCoord); + vec3 viewNormal = FetchNormal(TexCoord); + float occlusion = viewNormal != vec3(0.0) ? ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength) : 1.0; + + FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); +} diff --git a/wadsrc/static/shaders_gles/pp/ssaocombine.fp b/wadsrc/static/shaders_gles/pp/ssaocombine.fp new file mode 100644 index 000000000..0d592549f --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/ssaocombine.fp @@ -0,0 +1,41 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D AODepthTexture; + +#if defined(MULTISAMPLE) +layout(binding=1) uniform sampler2DMS SceneFogTexture; +#else +layout(binding=1) uniform sampler2D SceneFogTexture; +#endif + +void main() +{ + vec2 uv = Offset + TexCoord * Scale; + +#if defined(MULTISAMPLE) + ivec2 texSize = textureSize(SceneFogTexture); +#else + ivec2 texSize = textureSize(SceneFogTexture, 0); +#endif + ivec2 ipos = ivec2(uv * vec2(texSize)); + +#if defined(MULTISAMPLE) + vec3 fogColor = texelFetch(SceneFogTexture, ipos, 0).rgb; +#else + vec3 fogColor = texelFetch(SceneFogTexture, ipos, 0).rgb; +#endif + + vec4 ssao = texture(AODepthTexture, TexCoord); + float attenutation = ssao.x; + + if (DebugMode == 0) + FragColor = vec4(fogColor, 1.0 - attenutation); + else if (DebugMode < 3) + FragColor = vec4(attenutation, attenutation, attenutation, 1.0); + else if (DebugMode == 3) + FragColor = vec4(ssao.yyy / 1000.0, 1.0); + else + FragColor = vec4(ssao.xyz, 1.0); +} diff --git a/wadsrc/static/shaders_gles/pp/tonemap.fp b/wadsrc/static/shaders_gles/pp/tonemap.fp new file mode 100644 index 000000000..f18e9fc9e --- /dev/null +++ b/wadsrc/static/shaders_gles/pp/tonemap.fp @@ -0,0 +1,89 @@ + +layout(location=0) in vec2 TexCoord; +layout(location=0) out vec4 FragColor; + +layout(binding=0) uniform sampler2D InputTexture; + +vec3 Linear(vec3 c) +{ + //c = max(c, vec3(0.0)); + //return pow(c, 2.2); + return c * c; // cheaper, but assuming gamma of 2.0 instead of 2.2 +} + +vec3 sRGB(vec3 c) +{ + c = max(c, vec3(0.0)); + //return pow(c, vec3(1.0 / 2.2)); + return sqrt(c); // cheaper, but assuming gamma of 2.0 instead of 2.2 +} + +#if defined(LINEAR) + +vec3 Tonemap(vec3 color) +{ + return sRGB(color); +} + +#elif defined(REINHARD) + +vec3 Tonemap(vec3 color) +{ + color = color / (1.0 + color); + return sRGB(color); +} + +#elif defined(HEJLDAWSON) + +vec3 Tonemap(vec3 color) +{ + vec3 x = max(vec3(0.0), color - 0.004); + return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); // no sRGB needed +} + +#elif defined(UNCHARTED2) + +vec3 Uncharted2Tonemap(vec3 x) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec3 Tonemap(vec3 color) +{ + float W = 11.2; + vec3 curr = Uncharted2Tonemap(color); + vec3 whiteScale = vec3(1) / Uncharted2Tonemap(vec3(W)); + return sRGB(curr * whiteScale); +} + +#elif defined(PALETTE) + +layout(binding=1) uniform sampler2D PaletteLUT; + +vec3 Tonemap(vec3 color) +{ + ivec3 c = ivec3(clamp(color.rgb, vec3(0.0), vec3(1.0)) * 63.0 + 0.5); + int index = (c.r * 64 + c.g) * 64 + c.b; + int tx = index % 512; + int ty = index / 512; + return texelFetch(PaletteLUT, ivec2(tx, ty), 0).rgb; +} + +#else +#error Tonemap mode define is missing +#endif + +void main() +{ + vec3 color = texture(InputTexture, TexCoord).rgb; +#ifndef PALETTE + color = Linear(color); // needed because gzdoom's scene texture is not linear at the moment +#endif + FragColor = vec4(Tonemap(color), 1.0); +}