/** * Shared TSL building blocks and atlas helpers for the MSDF text renderers. * * The single-block {@link MSDFText} and the batched {@link BatchedMSDFText} decode the exact * same atlas the exact same way — median-of-RGB signed distance, antialiased over one screen * pixel — and normalize the atlas sampler state identically. That fragment math and the atlas * setup live here once so both materials stay pixel-identical. * * @module MSDFTextNodes */ import * as THREE from 'three/webgpu'; import type { TSLFloatInput, TSLFloatNode, TSLTextureNode, TSLVec2Node, TSLVec4Node } from '../types/tsl.js'; /** The shared 1×1 transparent placeholder atlas (created lazily). */ export declare function getMSDFFallbackAtlas(): THREE.DataTexture; /** * Normalizes an atlas texture's sampling state for MSDF decoding: MSDF atlases must sample * linearly, without mips, and as raw data (KTX2Loader's raw path arrives NearestFilter). * Passing null returns the shared fallback atlas. * * @param {THREE.Texture|null} map * @returns {THREE.Texture} The normalized atlas (or the fallback when `map` is null). */ export declare function normalizeMSDFAtlas(map: TTexture): TTexture; export declare function normalizeMSDFAtlas(map: null): THREE.Texture; export declare function normalizeMSDFAtlas(map: THREE.Texture | null): THREE.Texture; /** * Maps the base unit-quad uv into a glyph's atlas rect. Quad uv y=1 is the glyph top, which * is `uvRect.y` for flipY = false atlases (`v0` at the glyph's TOP edge), so the v channel is * mixed top→bottom. * * @tsl * @param {Node} uvRect - vec4 atlas rect (u0, v0, u1, v1); v0 at the glyph's TOP edge. * @returns {Node} vec2 atlas uv for the current fragment. */ export declare function msdfGlyphUv(uvRect: TSLVec4Node): TSLVec2Node; /** * Median-of-RGB MSDF coverage: decodes the signed distance and antialiases it over exactly * one screen pixel via Chlumsky's screen-px-range term, so glyphs stay crisp at any scale and * any DPR with no per-size tuning. * * @tsl * @param {Object} params * @param {Node} params.atlas - The atlas TextureNode (`texture( map )`). * @param {Node} params.glyphUv - vec2 atlas uv (see {@link msdfGlyphUv}). * @param {Node} params.distanceRange - Atlas distance range in px (from the font JSON). * @param {Node} [params.weightBias] - Threshold bias approximating font weights the atlas was * not generated at: positive fattens strokes, negative thins them. * @returns {Node} float coverage in [0, 1]. */ export interface MSDFAlphaParameters { atlas: TSLTextureNode; glyphUv: TSLVec2Node; distanceRange: TSLFloatInput; weightBias?: TSLFloatInput; } /** * Pixel-snapped screen-space clip position for glyph quads laid out in CSS pixels (y-up), * shared by the single-block and batched screen-space vertex paths. * * The quad arrives split into its per-instance origin and the current corner's offset so the * origin can be snapped to the drawing buffer's physical pixel grid: each glyph translates * as a whole — never distorts — and every stem lands on the same subpixel phase, which keeps * small text uniformly crisp at any DPR (pretext-style alignment). CSS px map to device px * through the actual buffer/viewport ratio (`screenSize / viewport`), so snapping stays * correct when the app renders at a capped or fractional pixel ratio. * * Whole-pixel snapping steps by design; smoothly animated text should keep the direct * (unsnapped) CSS→NDC path instead. * * @tsl * @param {Object} params * @param {Node} params.originPx - vec2 per-instance glyph pen origin (baseline-left) in CSS px * (y-up layout units). Snap the pen, not the sprite corner: the corner sits a fractional, * per-glyph number of pixels from the baseline, so snapping it lands each baseline on a * different sub-pixel phase (a 50% grey baseline row at DPR 1). * @param {Node} params.cornerPx - vec2 corner offset from that origin in CSS px (y-up layout units). * @param {Node} params.offset - vec2 screen offset uniform in CSS px (top-left origin, y-down). * @param {Node} params.viewport - vec2 canvas CSS pixel size uniform. * @param {Node} params.depth - float NDC depth. * @returns {Node} vec4 clip-space position. */ export interface MSDFSnappedScreenClipParameters { originPx: TSLVec2Node; cornerPx: TSLVec2Node; offset: TSLVec2Node; viewport: TSLVec2Node; depth: TSLFloatNode; } export declare function msdfSnappedScreenClip({ originPx, cornerPx, offset, viewport, depth }: MSDFSnappedScreenClipParameters): TSLVec4Node; export declare function msdfAlpha({ atlas, glyphUv, distanceRange, weightBias }: MSDFAlphaParameters): TSLFloatNode;