import * as THREE from 'three/webgpu'; import type { MSDFFont } from './MSDFFont.cjs'; import { type MSDFTextAlign } from './MSDFTextLayout.cjs'; import type { MSDFTextAnchorX, MSDFTextAnchorY, MSDFTextLineInput } from './MSDFText.cjs'; /** Construction options for {@link BatchedMSDFText}. */ export interface BatchedMSDFTextOptions { /** Parsed atlas metrics shared by every batch member. */ font?: MSDFFont | null | undefined; /** Shared MSDF atlas texture. The caller retains ownership and disposes it. */ map?: THREE.Texture | null | undefined; /** Whether member transforms use CSS-pixel viewport coordinates. */ screenSpace?: boolean | undefined; /** screenSpace only: snap glyph origins to physical pixels (default true). Disable for smoothly animated text. */ pixelSnap?: boolean | undefined; /** Fixed maximum number of independently controlled text members. */ maxTextCount?: number | undefined; /** Fixed maximum number of drawable glyphs across all members. */ maxGlyphCount?: number | undefined; /** Initial opacity multiplier shared by the batch. */ opacity?: number | undefined; /** Optional advanced material override whose disposal ownership transfers to the batch. */ material?: THREE.Material | null | undefined; } /** Position shorthand accepted when adding a batch member. */ export interface BatchedMSDFTextPosition { /** X coordinate in batch-local space. */ x: number; /** Y coordinate in batch-local space. */ y: number; /** Z coordinate in batch-local space. */ z: number; } /** Content, layout, transform, and appearance for one new batch member. */ export interface BatchedMSDFTextAddOptions { /** Text content for self-layout mode. */ text?: unknown; /** Pre-broken lines that override self-layout while non-null. */ lines?: readonly MSDFTextLineInput[] | null | undefined; /** Complete member transform in batch-local space. */ matrix?: THREE.Matrix4 | null | undefined; /** Translation shorthand used when no matrix is supplied. */ position?: BatchedMSDFTextPosition | null | undefined; /** Initial member color. */ color?: THREE.ColorRepresentation | undefined; /** Initial member opacity. */ opacity?: number | undefined; /** World units per em, or CSS pixels per em in screen-space mode. */ fontSize?: number | undefined; /** Additional spacing between adjacent glyphs. */ letterSpacing?: number | undefined; /** Line-box height, or zero to use the font's default. */ lineHeight?: number | undefined; /** Maximum line width used by self-layout. */ maxWidth?: number | undefined; /** Horizontal alignment within the maximum width. */ align?: MSDFTextAlign | undefined; /** Horizontal origin for the laid-out member. */ anchorX?: MSDFTextAnchorX | undefined; /** Vertical origin for the laid-out member. */ anchorY?: MSDFTextAnchorY | undefined; } /** Layout fields that can be changed without replacing member content. */ export interface BatchedMSDFTextLayoutPatch { /** World units per em, or CSS pixels per em in screen-space mode. */ fontSize?: number | undefined; /** Additional spacing between adjacent glyphs. */ letterSpacing?: number | undefined; /** Line-box height, or zero to use the font's default. */ lineHeight?: number | undefined; /** Maximum line width used by self-layout. */ maxWidth?: number | undefined; /** Horizontal alignment within the maximum width. */ align?: MSDFTextAlign | undefined; /** Horizontal origin for the laid-out member. */ anchorX?: MSDFTextAnchorX | undefined; /** Vertical origin for the laid-out member. */ anchorY?: MSDFTextAnchorY | undefined; } /** Read-only packing statistics from the most recent update. */ export interface BatchedMSDFTextLayoutInfo { /** Number of drawable glyph instances packed into the batch. */ glyphCount: number; /** Number of live text members. */ memberCount: number; } /** * Many independent MSDF text blocks in a single draw call and a single atlas bind. * * This is the batched sibling of {@link MSDFText}: layout is still synchronous and CPU-cheap * (advances + kerning from the font JSON — no runtime SDF generation), but every glyph carries * a `member` index so per-member transforms and colors — held in two small storage buffers — * are applied entirely on the GPU. Add/move/recolor/retype members freely; only content or * layout changes trigger a repack, while `setMatrixAt`/`setColorAt` just touch a storage buffer. * * Members share one font and one atlas (that is the point — one bind, one draw). Capacity is * fixed at construction, like {@link https://threejs.org/docs/#api/en/objects/BatchedMesh BatchedMesh}: * `maxTextCount` members and `maxGlyphCount` glyphs total. * * @class BatchedMSDFText * @augments THREE.Mesh * @short Batched MSDF text: one draw call for many blocks, per-member GPU transform + color. * @category Text * @tags WebGPU, WebGL * * @example * const font = parseMSDFFont( await ( await fetch( 'font.msdf.json' ) ).json() ); * const map = await ktx2Loader.loadAsync( 'font.msdf.ktx2' ); * const batch = new BatchedMSDFText( { font, map, maxTextCount: 100, maxGlyphCount: 4000 } ); * scene.add( batch ); * * const m = new THREE.Matrix4().setPosition( 0, 1, 0 ); * const id = batch.addText( { text: 'Hello\nMSDF', matrix: m, color: 0xff8800, fontSize: 0.5, align: 'center' } ); * batch.setMatrixAt( id, new THREE.Matrix4().setPosition( 2, 1, 0 ) ); */ export declare class BatchedMSDFText extends THREE.Mesh { /** Runtime type guard for batched MSDF text meshes. */ readonly isBatchedMSDFText: boolean; /** Whether member transforms use CSS-pixel viewport coordinates. */ readonly isScreenSpace: boolean; private _font; private readonly _maxTextCount; private readonly _maxGlyphCount; private readonly _matrixBuffer; private readonly _colorBuffer; private readonly _members; private _memberCount; private _needsRepack; private _overflowWarned; private readonly _tmpColor; private readonly _identity; private _glyphCapacity; private _layoutInfo; private get _textMaterial(); /** * Creates a fixed-capacity text batch and takes ownership of its generated geometry and * material. The supplied font metrics and atlas texture remain caller-owned; disposal * ownership of a supplied custom material transfers to the batch. * * @param {Object} [options] * @param {import('./MSDFFont.js').MSDFFont|null} [options.font=null] - Parsed atlas metrics (shared by all members). * @param {THREE.Texture|null} [options.map=null] - The matching MSDF atlas texture. * @param {boolean} [options.screenSpace=false] - Project member matrices from CSS pixels instead of the camera. * @param {boolean} [options.pixelSnap=true] - screenSpace only: snap glyph origins to * physical pixels for uniformly crisp stems at any DPR. Disable for smoothly animated text. * @param {number} [options.maxTextCount=64] - Max member count (fixed storage capacity). * @param {number} [options.maxGlyphCount=4096] - Max total glyphs across all members. * @param {number} [options.opacity=1] - Global opacity, multiplied on top of per-member opacity. * @param {THREE.Material|null} [options.material=null] - Override material (advanced). */ constructor(options?: BatchedMSDFTextOptions); /** Fixed maximum number of live text members. */ get maxTextCount(): number; /** Fixed maximum number of drawable glyphs across all members. */ get maxGlyphCount(): number; /** Number of live text members. */ get memberCount(): number; /** Parsed atlas metrics shared by every member. The caller retains ownership. */ get font(): MSDFFont | null; set font(value: MSDFFont | null); /** Binds the atlas texture (normalizing its sampler state for MSDF). */ setMap(map: THREE.Texture | null): void; /** Opacity multiplier shared by every member in the batch. */ get opacity(): number; set opacity(value: number); /** Signed fake-weight bias shared by the batch; positive values make strokes bolder. */ get weightBias(): number; set weightBias(value: number); /** * Adds a text block as a batched member. * * @param {Object} [options] * @param {string} [options.text=''] - Block content (`\n` supported). * @param {Array<{text: string, x: number, y: number, width?: number}>|null} [options.lines=null] * Pre-broken lines with explicit offsets, for mirroring layout decisions made elsewhere. * @param {THREE.Matrix4|null} [options.matrix=null] - Member transform in the batch's local space. * @param {THREE.Vector3|{x:number,y:number,z:number}|null} [options.position=null] - Convenience when no full matrix is needed. * @param {THREE.Color|number|string} [options.color=0xffffff] * @param {number} [options.opacity=1] * @param {number} [options.fontSize=1] - Units per em. * @param {number} [options.letterSpacing=0] * @param {number} [options.lineHeight=0] - Line box height in units; 0 → font default. * @param {number} [options.maxWidth=Infinity] - Wrap width. * @param {('left'|'center'|'right')} [options.align='left'] * @param {('left'|'center'|'right'|number)} [options.anchorX='left'] * @param {('baseline'|'top'|'middle'|'bottom')} [options.anchorY='baseline'] * @returns {number} The member id (slot), or -1 if `maxTextCount` is exceeded. */ addText(options?: BatchedMSDFTextAddOptions): number; /** * Removes a member and frees its slot. * @param {number} slot */ removeText(slot: number): this; /** * Reports whether a live member occupies a slot. * @param {number} slot Member slot returned by {@link BatchedMSDFText#addText}. * @returns {boolean} Whether a live member occupies the slot. */ hasText(slot: number): boolean; /** * Reads a member's current self-layout content without exposing its mutable record. * @param {number} slot Member slot returned by {@link BatchedMSDFText#addText}. * @returns {string} The current content, or an empty string for a free slot. */ getStringAt(slot: number): string; /** * Replaces a member's content, triggering a repack. * @param {number} slot * @param {string} text */ setTextAt(slot: number, value: unknown): this; /** * Sets pre-broken line content for a member, triggering a repack. * @param {number} slot * @param {Array<{text: string, x: number, y: number, width?: number}>|null} lines */ setLinesAt(slot: number, lines: readonly MSDFTextLineInput[] | null): this; /** * Patches a member's layout-affecting properties (fontSize, align, anchors, wrapping…), * triggering a repack. * @param {number} slot * @param {Object} options - Any of the layout fields accepted by {@link BatchedMSDFText#addText}. */ setLayoutAt(slot: number, options?: BatchedMSDFTextLayoutPatch): this; /** * Sets a member's transform (batch-local space). Cheap — writes a storage buffer, no repack. * @param {number} slot * @param {THREE.Matrix4} matrix */ setMatrixAt(slot: number, matrix: THREE.Matrix4): this; /** * Copies a member's transform into a caller-provided target, or a new matrix when omitted. * * @param {number} slot * @param {THREE.Matrix4} [target] * @returns {THREE.Matrix4} The member's transform. */ getMatrixAt(slot: number, target?: THREE.Matrix4): THREE.Matrix4; /** * Sets a member's color. Cheap — writes a storage buffer, no repack. * @param {number} slot * @param {THREE.Color|number|string} color */ setColorAt(slot: number, color: THREE.ColorRepresentation): this; /** * Copies a member's color into a caller-provided target, or a new color when omitted. * * @param {number} slot * @param {THREE.Color} [target] * @returns {THREE.Color} The member's color. */ getColorAt(slot: number, target?: THREE.Color): THREE.Color; /** * Sets a member's opacity. Cheap — writes a storage buffer, no repack. * @param {number} slot * @param {number} opacity */ setOpacityAt(slot: number, opacity: number): this; /** * Reads a member's opacity multiplier. * @param {number} slot Member slot returned by {@link BatchedMSDFText#addText}. * @returns {number} The member's opacity. */ getOpacityAt(slot: number): number; /** screenSpace: batch origin in the viewport (CSS px, y-down top-left origin). */ setScreenOffset(x: number, y: number): void; /** screenSpace: the canvas CSS pixel size. */ setViewport(width: number, height: number): void; private _allocateGeometry; /** * Re-lays out any dirty members and rewrites the packed glyph buffers. Runs automatically * before rendering when something changed; call directly to force a synchronous rebuild. */ update(): void; /** Coalesces pending member layouts immediately before Three.js renders the mesh. */ onBeforeRender(): void; /** Read-only glyph and member counts from the most recent synchronous repack. */ get layoutInfo(): Readonly; /** * Frees the owned GPU geometry and material. The caller-owned atlas texture is not disposed. * A caller-supplied custom material is also disposed because it becomes the batch material. */ dispose(): void; }