keid-render-basic-0.1.12.0: src/Render/Font/Msdf/Code.hs
module Render.Font.Msdf.Code
( vert
, frag
) where
import RIO
import Render.Code (Code, glsl)
import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)
vert :: Code
vert = fromString
[glsl|
#version 450
${set0binding0}
layout(location = 0) in vec4 iVert;
layout(location = 1) in vec4 iFrag;
layout(location = 2) in ivec2 iTextureIds;
layout(location = 3) in vec2 iSdfDist;
layout(location = 4) in vec4 iColor;
layout(location = 5) in vec4 iOutlineColor;
layout(location = 6) in vec2 iSdf;
layout(location = 0) out vec2 fTexCoord;
layout(location = 1) flat out vec4 fColor;
layout(location = 2) flat out vec4 fOutlineColor;
layout(location = 3) flat out vec4 fSdf;
layout(location = 4) flat out ivec2 fTextureIds;
vec2 positions[6] = vec2[](
vec2(-0.5, 0.5),
vec2(0.5, 0.5),
vec2(-0.5, -0.5),
vec2(0.5, -0.5),
vec2(-0.5, -0.5),
vec2(0.5, 0.5)
);
vec2 texCoords[6] = vec2[](
vec2(0.0, 1),
vec2(1.0, 1),
vec2(0.0, 0),
vec2(1.0, 0),
vec2(0.0, 0),
vec2(1.0, 1)
);
void main() {
vec2 pos = positions[gl_VertexIndex];
gl_Position
= scene.projection
* scene.view
// TODO: * iModel
* vec4(iVert.xy + pos * iVert.zw, 0, 1.0);
vec2 uv = texCoords[gl_VertexIndex];
fTexCoord = iFrag.xy + uv * iFrag.zw;
fColor = iColor;
fOutlineColor = iOutlineColor;
fTextureIds = iTextureIds;
fSdf = vec4(iSdfDist, iSdf);
}
|]
frag :: Code
frag = fromString
[glsl|
#version 450
#extension GL_EXT_nonuniform_qualifier : enable
${set0binding1}
${set0binding2}
layout(location = 0) in vec2 fTexCoord;
layout(location = 1) flat in vec4 fColor;
layout(location = 2) flat in vec4 fOutlineColor;
layout(location = 3) flat in vec4 fSdf;
layout(location = 4) flat in ivec2 fTextureIds;
layout(location = 0) out vec4 outColor;
#define HARDMASK 0
#define SOFTMASK 1
#define SDF 2
#define PSDF 3
#define MSDF 4
#define MTSDF 5
layout(constant_id = 0) const uint type = MTSDF;
layout(constant_id = 1) const bool srgb = false;
float median3(float a, float b, float c) {
return max(min(a, b), min(max(a, b), c));
}
void main() {
float hard; // text
float soft; // effects
switch (type) {
// single-channel
case HARDMASK: // actually, bit-packed
case SOFTMASK: // r8, antialiased greyscale
case SDF: // r8, actually distance
case PSDF: // r8, dunno
hard = texture(
sampler2D(
textures[nonuniformEXT(fTextureIds[1])],
samplers[nonuniformEXT(fTextureIds[0])]
),
fTexCoord
).r;
if (srgb) hard = pow(hard, 1/2.2);
// No outlines for non-SDF types, just apply tint
outColor = fColor * vec4(hard);
return;
// 3-channel
case MSDF:
vec3 msdf = texture(
sampler2D(
textures[nonuniformEXT(fTextureIds[1])],
samplers[nonuniformEXT(fTextureIds[0])]
),
fTexCoord
).rgb;
hard = median3(msdf.r, msdf.g, msdf.b);
if (srgb) hard = pow(hard, 1/2.2);
soft = hard; // no dedicated channel
break;
// 4-channel
case MTSDF:
vec4 mtsdf = texture(
sampler2D(
textures[nonuniformEXT(fTextureIds[1])],
samplers[nonuniformEXT(fTextureIds[0])]
),
fTexCoord
).rgba;
hard = median3(mtsdf.r, mtsdf.g, mtsdf.b);
if (srgb) hard = pow(hard, 1/2.2);
soft = mtsdf.a; // dedicated channel for soft effects
break;
}
float sdfLower = fSdf[0];
float sdfRange = fSdf[1];
float sdfSmoothing = fSdf[2]; // fallback
float sdfOutline = fSdf[3];
float hardPx = sdfLower + (hard * sdfRange);
float hardWidth = max(fwidth(hard) * sdfRange, sdfSmoothing);
float hardCoverage = smoothstep(-0.5, 0.5, hardPx / hardWidth);
float softPx = sdfLower + (soft * sdfRange);
float softWidth = max(fwidth(soft) * sdfRange, sdfSmoothing);
float softCoverage = clamp(smoothstep(-sdfOutline / softWidth, 0, softPx / softWidth), 0, 1);
outColor = mix(fOutlineColor, fColor, hardCoverage) * softCoverage;
}
|]