2022-03-11 22:17:04 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//
|
|
|
|
// EmulationStation Desktop Edition
|
|
|
|
// core.glsl
|
|
|
|
//
|
2023-08-20 17:41:07 +00:00
|
|
|
// Core shader functionality.
|
2022-03-11 22:17:04 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
// Vertex section of code:
|
2022-03-14 23:14:06 +00:00
|
|
|
#if defined(VERTEX)
|
2022-03-11 22:17:04 +00:00
|
|
|
|
|
|
|
uniform mat4 MVPMatrix;
|
2022-03-14 23:14:06 +00:00
|
|
|
in vec2 positionVertex;
|
|
|
|
in vec2 texCoordVertex;
|
|
|
|
in vec4 colorVertex;
|
|
|
|
|
2022-08-30 17:42:37 +00:00
|
|
|
out vec2 position;
|
2022-03-14 23:14:06 +00:00
|
|
|
out vec2 texCoord;
|
2022-08-30 17:42:37 +00:00
|
|
|
out vec4 color;
|
2022-03-11 22:17:04 +00:00
|
|
|
|
|
|
|
void main(void)
|
|
|
|
{
|
2022-03-14 23:14:06 +00:00
|
|
|
gl_Position = MVPMatrix * vec4(positionVertex.xy, 0.0, 1.0);
|
2022-08-30 17:42:37 +00:00
|
|
|
position = positionVertex;
|
2022-03-14 23:14:06 +00:00
|
|
|
texCoord = texCoordVertex;
|
2022-10-27 22:08:41 +00:00
|
|
|
color.abgr = colorVertex.rgba;
|
2022-03-11 22:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fragment section of code:
|
2022-03-14 23:14:06 +00:00
|
|
|
#elif defined(FRAGMENT)
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2022-03-13 22:52:32 +00:00
|
|
|
#ifdef GL_ES
|
2022-03-14 23:14:06 +00:00
|
|
|
precision mediump float;
|
2022-03-13 22:52:32 +00:00
|
|
|
#endif
|
|
|
|
|
2022-08-30 17:42:37 +00:00
|
|
|
in vec2 position;
|
2022-03-14 23:14:06 +00:00
|
|
|
in vec2 texCoord;
|
2022-08-30 17:42:37 +00:00
|
|
|
in vec4 color;
|
|
|
|
|
2023-08-31 15:11:32 +00:00
|
|
|
uniform vec2 texSize;
|
2022-08-30 17:42:37 +00:00
|
|
|
uniform vec4 clipRegion;
|
2022-12-14 19:17:41 +00:00
|
|
|
uniform float brightness;
|
2022-03-14 23:14:06 +00:00
|
|
|
uniform float saturation;
|
2022-12-12 19:21:22 +00:00
|
|
|
uniform float opacity;
|
2022-03-14 23:14:06 +00:00
|
|
|
uniform float dimming;
|
2023-08-20 17:41:07 +00:00
|
|
|
uniform float cornerRadius;
|
2022-04-18 19:37:58 +00:00
|
|
|
uniform float reflectionsFalloff;
|
2022-03-14 23:25:02 +00:00
|
|
|
uniform uint shaderFlags;
|
2022-03-14 23:14:06 +00:00
|
|
|
|
2023-09-07 19:02:38 +00:00
|
|
|
uniform sampler2D textureSampler0;
|
|
|
|
uniform sampler2D textureSampler1;
|
2022-03-14 23:14:06 +00:00
|
|
|
out vec4 FragColor;
|
2022-03-14 21:30:24 +00:00
|
|
|
|
|
|
|
// shaderFlags:
|
2022-10-27 22:08:41 +00:00
|
|
|
// 0x00000001 - Premultiplied alpha (BGRA)
|
2022-03-14 21:30:24 +00:00
|
|
|
// 0x00000002 - Font texture
|
|
|
|
// 0x00000004 - Post processing
|
2022-08-30 17:42:37 +00:00
|
|
|
// 0x00000008 - Clipping
|
2023-02-06 22:38:35 +00:00
|
|
|
// 0x00000010 - Screen rotated 90 or 270 degrees
|
2023-08-20 17:41:07 +00:00
|
|
|
// 0x00000020 - Rounded corners
|
|
|
|
// 0x00000040 - Rounded corners with no anti-aliasing
|
2022-03-11 22:17:04 +00:00
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
2022-08-30 17:42:37 +00:00
|
|
|
// Discard any pixels outside the clipping region.
|
2022-10-27 22:08:41 +00:00
|
|
|
if (0x0u != (shaderFlags & 0x8u)) {
|
2022-08-30 17:42:37 +00:00
|
|
|
if (position.x < clipRegion.x)
|
|
|
|
discard;
|
|
|
|
else if (position.y < clipRegion.y)
|
|
|
|
discard;
|
|
|
|
else if (position.x > clipRegion.z)
|
|
|
|
discard;
|
|
|
|
else if (position.y > clipRegion.w)
|
|
|
|
discard;
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:02:38 +00:00
|
|
|
vec4 sampledColor = texture(textureSampler0, texCoord);
|
2022-03-13 22:52:32 +00:00
|
|
|
|
2023-08-20 17:41:07 +00:00
|
|
|
// Rounded corners.
|
|
|
|
if (0x0u != (shaderFlags & 0x20u) || 0x0u != (shaderFlags & 0x40u)) {
|
2023-09-07 19:02:38 +00:00
|
|
|
float cornerRadiusClamped = cornerRadius;
|
2023-08-20 17:41:07 +00:00
|
|
|
// Don't go beyond half the width and height.
|
2023-09-07 19:02:38 +00:00
|
|
|
if (cornerRadiusClamped > texSize.x / 2.0)
|
|
|
|
cornerRadiusClamped = texSize.x / 2.0;
|
|
|
|
if (cornerRadiusClamped > texSize.y / 2.0)
|
|
|
|
cornerRadiusClamped = texSize.y / 2.0;
|
|
|
|
|
|
|
|
vec2 center = position - texSize / 2.0;
|
|
|
|
vec2 q = abs(center) - (vec2(texSize.x / 2.0, texSize.y / 2.0) - cornerRadiusClamped);
|
|
|
|
float pixelDistance = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - cornerRadiusClamped;
|
2023-08-20 17:41:07 +00:00
|
|
|
|
|
|
|
if (pixelDistance > 0.0) {
|
|
|
|
discard;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
float pixelValue;
|
|
|
|
if (0x0u != (shaderFlags & 0x20u))
|
|
|
|
pixelValue = 1.0 - smoothstep(-0.75, 0.5, pixelDistance);
|
|
|
|
else
|
|
|
|
pixelValue = 1.0;
|
|
|
|
|
|
|
|
sampledColor.a *= pixelValue;
|
|
|
|
sampledColor.rgb *= pixelValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-14 19:17:41 +00:00
|
|
|
// Brightness.
|
2022-12-14 22:09:17 +00:00
|
|
|
if (brightness != 0.0) {
|
2022-12-15 18:13:37 +00:00
|
|
|
sampledColor.rgb /= sampledColor.a;
|
2022-12-14 22:09:17 +00:00
|
|
|
sampledColor.rgb += 0.3 * brightness;
|
|
|
|
sampledColor.rgb *= sampledColor.a;
|
|
|
|
}
|
2022-12-14 19:17:41 +00:00
|
|
|
|
2023-03-03 21:37:39 +00:00
|
|
|
// Saturation, except for font textures.
|
|
|
|
if (saturation != 1.0 && 0x0u == (shaderFlags & 0x2u)) {
|
2022-12-12 19:21:22 +00:00
|
|
|
vec3 grayscale;
|
|
|
|
// Premultiplied textures are all in BGRA format.
|
|
|
|
if (0x0u != (shaderFlags & 0x01u))
|
2022-12-13 21:45:05 +00:00
|
|
|
grayscale = vec3(dot(sampledColor.bgr, vec3(0.114, 0.587, 0.299)));
|
2022-12-12 19:21:22 +00:00
|
|
|
else
|
2022-12-13 21:45:05 +00:00
|
|
|
grayscale = vec3(dot(sampledColor.rgb, vec3(0.299, 0.587, 0.114)));
|
2022-12-12 19:21:22 +00:00
|
|
|
vec3 blendedColor = mix(grayscale, sampledColor.rgb, saturation);
|
|
|
|
sampledColor = vec4(blendedColor, sampledColor.a);
|
|
|
|
}
|
|
|
|
|
2022-03-13 22:52:32 +00:00
|
|
|
// For fonts the alpha information is stored in the red channel.
|
2022-10-27 22:08:41 +00:00
|
|
|
if (0x0u != (shaderFlags & 0x2u))
|
2022-03-14 23:14:06 +00:00
|
|
|
sampledColor = vec4(1.0, 1.0, 1.0, sampledColor.r);
|
2022-03-13 22:52:32 +00:00
|
|
|
|
2022-10-28 19:41:55 +00:00
|
|
|
// We need different color calculations depending on whether the texture contains
|
|
|
|
// premultiplied alpha or straight alpha values.
|
2022-10-27 22:08:41 +00:00
|
|
|
if (0x0u != (shaderFlags & 0x01u)) {
|
|
|
|
sampledColor.rgb *= color.rgb;
|
|
|
|
sampledColor *= color.a;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sampledColor *= color;
|
|
|
|
}
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2023-03-03 21:37:39 +00:00
|
|
|
// Saturation for font textures.
|
|
|
|
if (saturation != 1.0 && 0x0u != (shaderFlags & 0x2u)) {
|
|
|
|
vec3 grayscale = vec3(dot(sampledColor.rgb, vec3(0.299, 0.587, 0.114)));
|
|
|
|
vec3 blendedColor = mix(grayscale, sampledColor.rgb, saturation);
|
|
|
|
sampledColor = vec4(blendedColor, sampledColor.a);
|
|
|
|
}
|
|
|
|
|
2022-10-27 22:08:41 +00:00
|
|
|
// When post-processing we drop the alpha channel to avoid strange issues with some
|
|
|
|
// graphics drivers.
|
|
|
|
if (0x0u != (shaderFlags & 0x4u))
|
2022-03-14 23:14:06 +00:00
|
|
|
sampledColor.a = 1.0;
|
2022-03-12 16:57:59 +00:00
|
|
|
|
2022-03-11 22:17:04 +00:00
|
|
|
// Opacity.
|
2022-10-27 22:08:41 +00:00
|
|
|
if (opacity != 1.0) {
|
|
|
|
if (0x0u == (shaderFlags & 0x01u))
|
|
|
|
sampledColor.a *= opacity;
|
|
|
|
else
|
|
|
|
sampledColor *= opacity;
|
|
|
|
}
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2022-10-28 19:41:55 +00:00
|
|
|
// Dimming.
|
2022-03-14 23:14:06 +00:00
|
|
|
if (dimming != 1.0) {
|
|
|
|
vec4 dimColor = vec4(dimming, dimming, dimming, 1.0);
|
2022-03-13 22:52:32 +00:00
|
|
|
sampledColor *= dimColor;
|
2022-03-12 13:22:27 +00:00
|
|
|
}
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2022-04-18 19:37:58 +00:00
|
|
|
// Reflections falloff.
|
|
|
|
if (reflectionsFalloff > 0.0)
|
2022-10-27 22:08:41 +00:00
|
|
|
sampledColor.argb *= mix(0.0, 1.0, reflectionsFalloff - position.y) / reflectionsFalloff;
|
2022-04-18 19:37:58 +00:00
|
|
|
|
2022-03-13 22:52:32 +00:00
|
|
|
FragColor = sampledColor;
|
2022-03-11 22:17:04 +00:00
|
|
|
}
|
|
|
|
#endif
|