export default class ShaderEffect { /** * @param {WebGLRenderer|WebGPURenderer|CanvasRenderer} renderer - the current renderer instance * @param {string|{glsl?: string, wgsl?: string}} body - the effect body: * a GLSL string (containing a `vec4 apply(vec4 color, vec2 uv)` function — * unchanged from previous versions), or an object carrying one body per * shading language (`glsl` and/or `wgsl`, the WGSL body defining * `fn apply(color : vec4f, uv : vec2f) -> vec4f`). The renderer picks the * body matching its {@link Renderer#shaderLanguage}; when no matching body * exists the effect warns once and stays disabled (`enabled === false`), * exactly like the Canvas renderer. * @param {string} [precision=auto detected] - float precision ('lowp', 'mediump' or 'highp'), GLSL only */ constructor(renderer: WebGLRenderer | WebGPURenderer | CanvasRenderer, body: string | { glsl?: string; wgsl?: string; }, precision?: string); /** * whether this effect is active (false in Canvas mode, false after * {@link destroy}, and false while the WebGL context is suspended * between an `ONCONTEXT_LOST` and the matching `ONCONTEXT_RESTORED` * event). * @type {boolean} */ enabled: boolean; /** * `true` once {@link destroy} has been called. Distinct from * `enabled` — which also toggles transiently across a context * lost / restored cycle — to give callers a stable signal for * "this effect has been explicitly released." * @type {boolean} * @readonly */ readonly destroyed: boolean; /** * When `true`, a renderable will NOT auto-destroy this effect when it is * removed from its `postEffects` (via the `shader` setter, * {@link Renderable#removePostEffect}, {@link Renderable#clearPostEffects}) * or when the renderable itself is destroyed. Set this on an effect shared * across several renderables so one of them going away doesn't free the GL * program still used by the others — you then own its lifecycle and call * {@link destroy} yourself. * @type {boolean} * @default false */ shared: boolean; /** * Set the uniform to the given value * @param {string} name - the uniform name * @param {number|boolean|number[]|Float32Array|object} value - the value to assign to that * uniform. Scalars (`float`, `int`, `bool`) take a number or a boolean; * vectors and matrices take an array, a `Float32Array`, or any object * exposing `toArray()` — which is every {@link Vector2d}, * {@link Vector3d}, {@link Color} and {@link Matrix3d}. * @example * // a scalar the body declares as `uniform float uStrength;` * fx.setUniform("uStrength", 0.5); * // a vec3 — an array, or anything with toArray() * fx.setUniform("uTint", [1.0, 0.82, 0.55]); * fx.setUniform("uOrigin", new me.Vector2d(0.5, 0.5)); */ setUniform(name: string, value: number | boolean | number[] | Float32Array | object): void; /** * Set the shader's `uTime` uniform (elapsed time, in seconds). A convenience * over `setUniform("uTime", ...)`; call it once per frame from your update * loop to animate a shader that declares `uniform float uTime` (e.g. scrolling * a static noise texture's UVs, pulsing, waving). Drive it with whatever clock * you like — real time, a paused/scaled/scrubbed one. * * No-op if the shader does not declare a `uTime` uniform (nothing to update), * or in Canvas mode. The engine does NOT call this for you — animation is * opt-in, exactly like re-baking a {@link NoiseTexture2d} with `update(dt)`. * @param {number} seconds - elapsed time in seconds * @returns {ShaderEffect} this effect for chaining * @example * // a shader that scrolls a static seamless noise texture over time * const flow = new me.ShaderEffect(renderer, ` * uniform float uTime; * vec4 apply(vec4 color, vec2 uv) { * return texture2D(uSampler, uv + vec2(uTime * 0.05, 0.0)); * }`); * mySprite.addPostEffect(flow); * // then in your Stage's update(dt): * flow.setTime(me.timer.getTime() / 1000); */ setTime(seconds: number): ShaderEffect; /** * Bind an **extra** texture to a named `sampler2D` uniform in this shader, so * a custom effect can read a *second* texture — a noise map, mask, gradient, * flow/lookup table — besides the sprite/target it post-processes (`uSampler`). * The engine uploads, caches, and re-binds it to a reserved texture unit each * time the effect draws, and points the sampler uniform at it — no raw WebGL * texture-unit juggling. * * Declare the sampler in your fragment (`uniform sampler2D ;`) and pass * that name here. Any engine texture works — a {@link Texture2d} asset * (`NoiseTexture2d`, `TextureAtlas`, …) can be passed directly, or a raw * drawable source. No-op in Canvas mode. * @param {string} name - the `sampler2D` uniform name declared in the fragment * @param {Texture2d|HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} image - the texture: an engine texture asset, or a raw drawable source * @param {"repeat"|"repeat-x"|"repeat-y"|"no-repeat"} [repeat="no-repeat"] - wrap mode; use `"repeat"` for a tiled/scrolled texture * @returns {ShaderEffect} this effect for chaining * @example * // "water": distort the sprite by a static noise texture scrolled over time * const noise = new me.NoiseTexture2d({ width: 256, height: 256, seamless: true }); * const water = new me.ShaderEffect(renderer, ` * uniform sampler2D uNoise; * uniform float uTime; * vec4 apply(vec4 color, vec2 uv) { * vec2 flow = texture2D(uNoise, uv + uTime * 0.03).rg - 0.5; * return texture2D(uSampler, uv + flow * 0.02); * }`); * water.setTexture("uNoise", noise, "repeat"); * waterSprite.addPostEffect(water); * // each frame, in your Stage's update(dt): * water.setTime(me.timer.getTime() / 1000); */ setTexture(name: string, image: Texture2d | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap, repeat?: "repeat" | "repeat-x" | "repeat-y" | "no-repeat"): ShaderEffect; /** * Create an independent copy of this effect, compiled as its own GL * program. Use it when several renderables need the same effect with * *different* uniform values — a single instance has a single set of * uniforms, shared by everything it is assigned to. * * The clone copies the **recipe**: the fragment source, float precision, * every uniform value set so far, and any extra textures bound via * {@link setTexture} (the clone uploads and owns its own GL copies). * It does NOT copy **ownership or lifecycle** state — in particular the * clone's {@link shared} flag is **always reset to `false`**, even when * cloning a shared shader (such as one returned by `loader.getShader()`): * the clone is caller-owned and will be auto-destroyed by the renderable * it is assigned to, exactly like a hand-constructed effect. Set * `shared = true` on the clone yourself if you intend to reuse it across * several renderables. * @returns {ShaderEffect} a new, caller-owned effect (`shared === false`) * @example * // the loader's shader is ONE shared program — one uniform state for all * sprite.addPostEffect(loader.getShader("flash")); * // the boss needs its own intensity — clone a private, caller-owned copy * const bossFlash = loader.getShader("flash").clone(); * boss.addPostEffect(bossFlash); * bossFlash.setUniform("uIntensity", 0.9); */ clone(): ShaderEffect; /** * destroy this shader effect. Idempotent — calling destroy twice * is safe. Unsubscribes from the renderer's context-lost / restored * events so a destroyed effect is not auto-reactivated. */ destroy(): void; } import GLShader from "../webgl/glshader.js"; import WGSLEffectRealization from "./wgsl_realization.js"; import Texture2d from "../texture/texture2d.ts"; //# sourceMappingURL=shadereffect.d.ts.map