Skip to main content

TEXT

Constant TEXT 

Source
pub const TEXT: &str = "// Screen-space text and sprite overlay: single source for every backend.\n//\n// One alpha-blended quad per glyph, sprite or background box, drawn in the\n// composite pass so it sits on top of the tonemapped image. Vertex positions\n// arrive in logical pixels with the origin at the top left; the vertex stage\n// maps them straight to NDC.\n//\n// The fragment stage carries three cases, selected per vertex rather than per\n// pipeline: a negative u marks a solid background box, a positive `mode` marks\n// a textured sprite quad whose `mode` is the alpha multiplier, and everything\n// else samples the glyph atlas as a signed distance field.\n//\n// METAL_BINDINGS selects the Metal host\'s constant shape, which is a host\n// difference rather than a target one: Vulkan pushes the window size while the\n// Metal encoder writes it to vertex buffer(0).\n\n// Window size in logical points, 16 B. Mirrors `TextUniforms` in\n// gfx/render_types.rs.\nstruct TextUniforms\n{\n    float win_width;\n    float win_height;\n    float _pad0;\n    float _pad1;\n};\n\n#ifdef METAL_BINDINGS\nConstantBuffer<TextUniforms> uni : register(b0);\n#else\n[[vk::push_constant]] ConstantBuffer<TextUniforms> uni;\n#endif\n\n// The glyph atlas, or a sprite\'s own RGBA image on the textured path. A\n// combined sampler lowers to a texture(0) + sampler(0) pair on Metal, which is\n// what that host binds.\n[[vk::binding(0, 0)]] Sampler2D<float4> atlas;\n\n// Matches `TextVertex` (32 B: pos at 0, uv at 8, colour at 16, mode at 28),\n// which the host input layouts declare and `text_vertex_layout_matches_shaders`\n// pins.\n//\n// `mode` takes a semantic of its own rather than TEXCOORD1: slangc appends its\n// own index to whatever the semantic spells, so a trailing digit is multiplied\n// by ten on the way out (TEXCOORD1 lands as TEXCOORD index 10). That is\n// harmless between two stages that agree, which is why the varyings below keep\n// their TEXCOORDn names, but a vertex input has to match the index a host input\n// layout declares.\nstruct TextVertexIn\n{\n    [[vk::location(0)]] float2 pos : POSITION;\n    [[vk::location(1)]] float2 uv : TEXCOORD0;\n    [[vk::location(2)]] float3 color : COLOR;\n    [[vk::location(3)]] float mode : MODE;\n};\n\n// The varyings lead deliberately: D3D packs a stage signature in declaration\n// order and links the two stages by matching semantic *and* register, and this\n// fragment reads no position at all.\nstruct TextVertexOut\n{\n    [[vk::location(0)]] float2 uv : TEXCOORD0;\n    [[vk::location(1)]] float3 color : TEXCOORD1;\n    [[vk::location(2)]] float mode : TEXCOORD2;\n    float4 position : SV_Position;\n};\n\n// Vulkan is the exception rather than the rule, exactly as in `fullscreen.slang`:\n// the composite pass rasterises through a standard positive-height viewport\n// there, so pixel (0,0) already maps to NDC (-1,-1) and the remap is linear.\n// Metal and DirectX put NDC +1 at the top of the screen, so they flip.\nfloat text_ndc_y(float pixel_y, float win_height)\n{\n    __target_switch\n    {\n    case spirv:\n        return (pixel_y / win_height) * 2.0 - 1.0;\n    default:\n        return 1.0 - (pixel_y / win_height) * 2.0;\n    }\n}\n\n[shader(\"vertex\")]\nTextVertexOut text_vertex_main(TextVertexIn v)\n{\n    TextVertexOut o;\n    o.position = float4(\n        (v.pos.x / uni.win_width) * 2.0 - 1.0,\n        text_ndc_y(v.pos.y, uni.win_height),\n        0.0,\n        1.0);\n    o.uv = v.uv;\n    o.color = v.color;\n    o.mode = v.mode;\n    return o;\n}\n\n[shader(\"fragment\")]\nfloat4 text_fragment_main(TextVertexOut i) : SV_Target\n{\n    // A negative u marks a solid background-box vertex (a TextLabel.background\n    // quad emitted by gfx::text::build_text_calls): emit the colour directly,\n    // alpha carried through in v, no atlas sample.\n    if (i.uv.x < 0.0)\n    {\n        return float4(i.color, i.uv.y);\n    }\n    // A positive mode marks a textured quad (a Sprite with a texture): the\n    // bound atlas is the sprite\'s own RGBA image, tinted by the vertex colour\n    // with the mode value as the quad\'s alpha multiplier.\n    if (i.mode > 0.0)\n    {\n        float4 tex = atlas.Sample(i.uv);\n        return float4(tex.rgb * i.color, tex.a * i.mode);\n    }\n    // The atlas stores a signed distance field: 0.5 = edge, > 0.5 = inside.\n    // fwidth gives the screen-space derivative of d, so the smoothstep spans\n    // exactly one screen pixel and the glyph stays crisp at any text scale or\n    // display density. Sampling d directly as alpha ramps the whole distance\n    // field and reads as blurry.\n    float d = atlas.Sample(i.uv).r;\n    float aa = fwidth(d);\n    float a = smoothstep(0.5 - aa, 0.5 + aa, d);\n    return float4(i.color, a);\n}\n";
Expand description

text.slang.