import type { WebGLContextManager } from "../../../webgl/context-manager"; import type { CartesianChart } from "../cartesian"; import type { Glyph } from "../glyph"; /** * Density-field glyph. Each cartesian row is rasterized as an additive * radial splat into an RGBA float FBO; a fullscreen pass resolves the * accumulated density (and optional color-weighted average) through the * chart's gradient LUT and composites the result inside the plot rect. * * The user-facing `gradient_color_mode` plugin field selects between: * * - `density` — alpha and hue from density alone. * - `mean` — density-weighted average of color-t (default). * - `extreme` — sign-aware MAX of per-point color deviation. Requires * a second accumulation target; uses `OES_draw_buffers_indexed` * MRT in one pass when available, otherwise falls back to two * sequential splat passes. * - `signed` — net positive vs. negative accumulation via the * `G - 0.5·R` identity. Requires a float-capable framebuffer; on * `UNSIGNED_BYTE` fallback the glyph silently degrades to `mean` * with a one-line console warning. */ export declare class DensityGlyph implements Glyph { readonly name: "density"; private _cache; ensureProgram(chart: CartesianChart, glManager: WebGLContextManager): void; draw(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array): void; drawSeries(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array, seriesIdx: number): void; buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise; tooltipOptions(): { crosshair: boolean; highlightRadius: number; }; destroy(chart: CartesianChart): void; /** * Resize the heat (and, when allocated, extreme + MRT) targets to * the current canvas bitmap size. The canvas backing store changes * on DPR or layout updates, so we compare cached dimensions and * re-allocate when stale. */ private ensureHeatTarget; /** * Re-allocate the storage for one accumulation texture using the * cached format triple. Called both at first draw and on every * canvas-size change. */ private allocAccumTexture; /** * Lazily allocate the extreme-mode accumulation texture + its * framebuffers. Sized to match the heat target. Also probes * `OES_draw_buffers_indexed` once per cache; if available, builds * the MRT framebuffer with both textures attached. */ private ensureExtremeTarget; /** * Compile (and cache) the single-target extreme splat program — the * fallback two-pass path's second pass. Reuses the splat vertex * shader so `v_color_t` semantics match the heat pass. */ private ensureExtremeSplatProgram; /** * Compile (and cache) the MRT splat program. Only safe to call * after `cache.indexedBlend` resolves truthy — the program's * `#extension GL_EXT_draw_buffers : require` would fail to * compile on contexts without multi-render-target support. */ private ensureMrtSplatProgram; /** * Resolve the active mode for this frame. Folds in the silent * downgrades to `mean` with a one-shot console warning: * * - `signed` requires a float-capable framebuffer * (`EXT_color_buffer_float` on WebGL2 in practice). * - `extreme` requires `gl.MAX` blend and a second color * attachment, both of which are WebGL2-only here. On WebGL1 * we could probe `EXT_blend_minmax` + `WEBGL_draw_buffers` * but degrading is simpler and the context manager prefers * WebGL2 already. */ private activeMode; private warnDowngradeOnce; /** * Shared splat → resolve pipeline. `dispatchSplats(cb)` iterates * the series ranges the caller wants drawn, invoking * `cb(slotOffset, count)` per range — `drawSeries` passes a single * range, `draw` iterates every series. Internally branches on the * active color mode: density/mean/signed share the single-target * heat-only pass, `extreme` runs either an MRT single-pass or two * sequential passes depending on extension support. */ private runSplatAndResolve; /** * Single-target accumulation into the heat FBO. ADD blend; writes * `(w, w·t, 0, 0)`. Used by every mode except `extreme` on the * MRT path (which does this work and the extreme pass in one go). */ private runHeatPass; /** * Second pass of the two-pass extreme path. MAX blend; writes * sign-split deviation magnitudes into the extreme FBO. Skipped * entirely on the MRT fast path. */ private runExtremePass; /** * MRT fast path: one splat draw writes density (ADD) and extreme * (MAX) in the same invocation by routing `gl_FragData[0]` / * `gl_FragData[1]` to attachments 0 and 1 with per-attachment * blend equations. */ private runMrtExtremePass; /** * Clear the currently bound framebuffer's color attachment(s) to * fully transparent, bypassing scissor so leftovers from a prior * facet's region don't bleed into this pass's full sample range. * Restores the scissor state on exit. */ private clearTarget; /** * Upload the per-frame splat-program uniforms (projection, splat * radius, intensity, color range). Shared by the heat-only pass, * the extreme single-target pass, and the MRT pass since each * program exposes the same uniform layout. */ private bindSplatProgram; /** * Bind the static unit-quad corner buffer (divisor 0) and per- * instance position + color attributes (divisor 1), then iterate * the caller's series ranges issuing one instanced draw each. */ private bindAndDispatchInstanced; /** * Reset the per-instance divisors so subsequent draws (in this or * another chart) don't inherit the instanced bindings. */ private unbindSplatInstancing; /** * Resolve pass on the canvas FBO. Standard alpha composite. Reads * the heat FBO (always) and, in `extreme` mode, the extreme FBO. * Uploads the mode int that the resolve frag branches on. */ private runResolvePass; }