@codexo/exojs 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +124 -0
- package/dist/esm/audio/AudioAnalyser.d.ts +36 -0
- package/dist/esm/audio/AudioAnalyser.js +148 -0
- package/dist/esm/audio/AudioAnalyser.js.map +1 -1
- package/dist/esm/audio/BeatDetector.d.ts +62 -0
- package/dist/esm/audio/BeatDetector.js +77 -0
- package/dist/esm/audio/BeatDetector.js.map +1 -1
- package/dist/esm/audio/dsp/mel.js +70 -0
- package/dist/esm/audio/dsp/mel.js.map +1 -0
- package/dist/esm/debug/RenderPassInspectorLayer.d.ts +71 -0
- package/dist/esm/debug/RenderPassInspectorLayer.js +201 -0
- package/dist/esm/debug/RenderPassInspectorLayer.js.map +1 -0
- package/dist/esm/debug/index.d.ts +1 -0
- package/dist/esm/debug/index.js +1 -0
- package/dist/esm/debug/index.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/rendering/filters/WebGpuShaderFilter.js +5 -1
- package/dist/esm/rendering/filters/WebGpuShaderFilter.js.map +1 -1
- package/dist/esm/rendering/index.d.ts +2 -0
- package/dist/esm/rendering/mesh/Mesh.d.ts +4 -47
- package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
- package/dist/esm/rendering/mesh/MeshShader.d.ts +183 -0
- package/dist/esm/rendering/mesh/MeshShader.js +231 -0
- package/dist/esm/rendering/mesh/MeshShader.js.map +1 -0
- package/dist/esm/rendering/texture/DataTexture.d.ts +115 -0
- package/dist/esm/rendering/texture/DataTexture.js +173 -0
- package/dist/esm/rendering/texture/DataTexture.js.map +1 -0
- package/dist/esm/rendering/webgl2/WebGl2Backend.js +42 -1
- package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
- package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js +12 -1
- package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuBackend.d.ts +1 -0
- package/dist/esm/rendering/webgpu/WebGpuBackend.js +60 -7
- package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.js +2 -1
- package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.d.ts +13 -0
- package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js +636 -83
- package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js.map +1 -1
- package/dist/exo.esm.js +1452 -102
- package/dist/exo.esm.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { RenderTexture } from '@/rendering/texture/RenderTexture';
|
|
2
|
+
import type { Texture } from '@/rendering/texture/Texture';
|
|
3
|
+
/**
|
|
4
|
+
* Uniform value passed to a custom mesh shader. Scalars and small tuples
|
|
5
|
+
* auto-marshal to the appropriate `Float32Array`/`Int32Array` for the
|
|
6
|
+
* backend's uniform call. `Texture`/`RenderTexture` values are bound to
|
|
7
|
+
* texture slots starting at slot 1 — slot 0 is reserved for the mesh's
|
|
8
|
+
* own `texture`.
|
|
9
|
+
*/
|
|
10
|
+
export type MeshShaderUniformValue = number | readonly [number, number] | readonly [number, number, number] | readonly [number, number, number, number] | Float32Array | Int32Array | Texture | RenderTexture;
|
|
11
|
+
/**
|
|
12
|
+
* Construction options for {@link MeshShader}.
|
|
13
|
+
*
|
|
14
|
+
* At least one language must be supplied. Provide `glsl` for WebGL2,
|
|
15
|
+
* `wgsl` for WebGPU, or both for backend-portable meshes. The shader
|
|
16
|
+
* is compiled lazily on first use against the active backend; an
|
|
17
|
+
* unsupported backend at draw time throws with a clear error.
|
|
18
|
+
*/
|
|
19
|
+
export interface MeshShaderOptions {
|
|
20
|
+
/**
|
|
21
|
+
* GLSL ES 3.00 sources for the WebGL2 backend. Both `vertex` and
|
|
22
|
+
* `fragment` are required when `glsl` is supplied.
|
|
23
|
+
*/
|
|
24
|
+
readonly glsl?: {
|
|
25
|
+
readonly vertex: string;
|
|
26
|
+
readonly fragment: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* WGSL source for the WebGPU backend. Vertex and fragment entry
|
|
30
|
+
* points live in the same source file (WGSL convention).
|
|
31
|
+
*/
|
|
32
|
+
readonly wgsl?: string;
|
|
33
|
+
/** Initial uniform values; mutate per frame via {@link MeshShader.uniforms}. */
|
|
34
|
+
readonly uniforms?: Record<string, MeshShaderUniformValue>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Custom shader pair attached to a {@link Mesh}.
|
|
38
|
+
*
|
|
39
|
+
* One `MeshShader` instance can be shared across many meshes; renderers
|
|
40
|
+
* cache compiled programs/pipelines on the instance reference. Call
|
|
41
|
+
* {@link destroy} when the shader is no longer needed to release the
|
|
42
|
+
* cached GPU resources on every backend the shader was used on.
|
|
43
|
+
*
|
|
44
|
+
* # Vertex layout
|
|
45
|
+
*
|
|
46
|
+
* The vertex layout is fixed and shared with the default mesh shader,
|
|
47
|
+
* so custom vertex shaders MUST pin the standard attribute locations:
|
|
48
|
+
*
|
|
49
|
+
* ## GLSL (location-qualified)
|
|
50
|
+
*
|
|
51
|
+
* ```glsl
|
|
52
|
+
* layout(location = 0) in vec2 a_position;
|
|
53
|
+
* layout(location = 1) in vec2 a_texcoord;
|
|
54
|
+
* layout(location = 2) in vec4 a_color;
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* ## WGSL (location-qualified)
|
|
58
|
+
*
|
|
59
|
+
* ```wgsl
|
|
60
|
+
* struct VertexInput {
|
|
61
|
+
* @location(0) position: vec2<f32>,
|
|
62
|
+
* @location(1) texcoord: vec2<f32>,
|
|
63
|
+
* @location(2) color: vec4<f32>,
|
|
64
|
+
* };
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* # Auto-bound uniforms
|
|
68
|
+
*
|
|
69
|
+
* The renderer auto-binds these when the shader declares them. Declared
|
|
70
|
+
* but unused is fine; absent is fine too. Both backends carry the same
|
|
71
|
+
* logical uniforms, only the binding scheme differs.
|
|
72
|
+
*
|
|
73
|
+
* ## GLSL
|
|
74
|
+
*
|
|
75
|
+
* ```glsl
|
|
76
|
+
* uniform mat3 u_projection; // active view's projection
|
|
77
|
+
* uniform mat3 u_translation; // mesh's global transform
|
|
78
|
+
* uniform vec4 u_tint; // mesh.tint as RGBA in 0..1
|
|
79
|
+
* uniform sampler2D u_texture; // bound to texture slot 0
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* ## WGSL
|
|
83
|
+
*
|
|
84
|
+
* ```wgsl
|
|
85
|
+
* struct MeshUniforms {
|
|
86
|
+
* projection: mat3x3<f32>,
|
|
87
|
+
* translation: mat3x3<f32>,
|
|
88
|
+
* tint: vec4<f32>,
|
|
89
|
+
* };
|
|
90
|
+
*
|
|
91
|
+
* @group(0) @binding(0) var<uniform> u_mesh: MeshUniforms;
|
|
92
|
+
*
|
|
93
|
+
* @group(1) @binding(0) var u_texture: texture_2d<f32>;
|
|
94
|
+
* @group(1) @binding(1) var u_sampler: sampler;
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* # User uniforms
|
|
98
|
+
*
|
|
99
|
+
* Anything in {@link uniforms} is set after the auto-binds. `Texture`/
|
|
100
|
+
* `RenderTexture` values claim slots 1..N (slot 0 belongs to the mesh).
|
|
101
|
+
*
|
|
102
|
+
* ## WGSL user-uniform contract
|
|
103
|
+
*
|
|
104
|
+
* User uniforms live in `@group(2)`:
|
|
105
|
+
*
|
|
106
|
+
* - `@group(2) @binding(0) var<uniform> u_user: <UserUniformsStruct>;`
|
|
107
|
+
* for the packed scalar/vector/matrix uniforms.
|
|
108
|
+
* - `@group(2) @binding(N)` for each `Texture`/`RenderTexture` uniform,
|
|
109
|
+
* in declaration order, alongside its sampler at `@binding(N+1)`.
|
|
110
|
+
*/
|
|
111
|
+
export declare class MeshShader {
|
|
112
|
+
/**
|
|
113
|
+
* Mutable user uniform values. Mutate between frames to drive animated
|
|
114
|
+
* effects; the renderer reads from this map every draw.
|
|
115
|
+
*
|
|
116
|
+
* shader.uniforms.uTime = performance.now() / 1000;
|
|
117
|
+
* shader.uniforms.uColor = [1, 0.5, 0, 1];
|
|
118
|
+
*/
|
|
119
|
+
uniforms: Record<string, MeshShaderUniformValue>;
|
|
120
|
+
/** GLSL source pair for the WebGL2 backend, or `null` if not provided. */
|
|
121
|
+
readonly glsl: {
|
|
122
|
+
readonly vertex: string;
|
|
123
|
+
readonly fragment: string;
|
|
124
|
+
} | null;
|
|
125
|
+
/** WGSL source for the WebGPU backend, or `null` if not provided. */
|
|
126
|
+
readonly wgsl: string | null;
|
|
127
|
+
private readonly _disposeCallbacks;
|
|
128
|
+
constructor(options: MeshShaderOptions);
|
|
129
|
+
/**
|
|
130
|
+
* Convenience setter equivalent to `shader.uniforms[name] = value`.
|
|
131
|
+
* Provided for symmetry with engine APIs that prefer explicit methods
|
|
132
|
+
* over property mutation.
|
|
133
|
+
*/
|
|
134
|
+
setUniform(name: string, value: MeshShaderUniformValue): void;
|
|
135
|
+
/**
|
|
136
|
+
* Reflect declared uniforms from each language's source. Returns a per-
|
|
137
|
+
* language map of uniform-name → declared type, parsed from the shader
|
|
138
|
+
* sources via lightweight regex (not a full GLSL/WGSL grammar). Texture
|
|
139
|
+
* uniforms (`sampler2D`/`texture_2d`) are included; sampler bindings
|
|
140
|
+
* are not (they pair with textures by binding index).
|
|
141
|
+
*
|
|
142
|
+
* Reflection is best-effort and intended for CI drift-checks and editor
|
|
143
|
+
* tooling, not for runtime uniform binding decisions. The renderers do
|
|
144
|
+
* NOT consult this map; they bind uniforms by name from {@link uniforms}
|
|
145
|
+
* and let the underlying API resolve declared-but-unused entries.
|
|
146
|
+
*/
|
|
147
|
+
getDeclaredUniforms(): {
|
|
148
|
+
glsl: Record<string, string>;
|
|
149
|
+
wgsl: Record<string, string>;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Compare declared uniform names between the GLSL and WGSL sources.
|
|
153
|
+
* Returns lists of names declared in only one language. Use in CI to
|
|
154
|
+
* catch drift when both languages should expose the same logical
|
|
155
|
+
* uniforms. When only one language is provided, returns empty arrays.
|
|
156
|
+
*
|
|
157
|
+
* Auto-bound uniforms (`u_projection`, `u_translation`, `u_tint`,
|
|
158
|
+
* `u_texture`) are excluded from the comparison since the GLSL source
|
|
159
|
+
* declares them at the top-level uniform scope while the WGSL source
|
|
160
|
+
* receives them via the `@group(0)` mesh-uniforms struct and the
|
|
161
|
+
* `@group(1)` texture binding.
|
|
162
|
+
*/
|
|
163
|
+
detectUniformDrift(): {
|
|
164
|
+
onlyInGlsl: readonly string[];
|
|
165
|
+
onlyInWgsl: readonly string[];
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Release GPU resources cached against this `MeshShader` on every
|
|
169
|
+
* backend that has compiled it. Safe to call multiple times. After
|
|
170
|
+
* destroy, the shader can still be re-used — renderers will recompile
|
|
171
|
+
* on next draw — but typical usage is to drop the reference.
|
|
172
|
+
*/
|
|
173
|
+
destroy(): void;
|
|
174
|
+
/**
|
|
175
|
+
* Internal hook for renderers to register a per-shader-instance cleanup
|
|
176
|
+
* callback (release compiled program, pipeline, or bind groups). The
|
|
177
|
+
* callback fires on {@link destroy}; renderers MUST also tolerate the
|
|
178
|
+
* shader being garbage-collected without destroy ever being called.
|
|
179
|
+
*
|
|
180
|
+
* @internal
|
|
181
|
+
*/
|
|
182
|
+
_onDispose(callback: () => void): void;
|
|
183
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom shader pair attached to a {@link Mesh}.
|
|
3
|
+
*
|
|
4
|
+
* One `MeshShader` instance can be shared across many meshes; renderers
|
|
5
|
+
* cache compiled programs/pipelines on the instance reference. Call
|
|
6
|
+
* {@link destroy} when the shader is no longer needed to release the
|
|
7
|
+
* cached GPU resources on every backend the shader was used on.
|
|
8
|
+
*
|
|
9
|
+
* # Vertex layout
|
|
10
|
+
*
|
|
11
|
+
* The vertex layout is fixed and shared with the default mesh shader,
|
|
12
|
+
* so custom vertex shaders MUST pin the standard attribute locations:
|
|
13
|
+
*
|
|
14
|
+
* ## GLSL (location-qualified)
|
|
15
|
+
*
|
|
16
|
+
* ```glsl
|
|
17
|
+
* layout(location = 0) in vec2 a_position;
|
|
18
|
+
* layout(location = 1) in vec2 a_texcoord;
|
|
19
|
+
* layout(location = 2) in vec4 a_color;
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* ## WGSL (location-qualified)
|
|
23
|
+
*
|
|
24
|
+
* ```wgsl
|
|
25
|
+
* struct VertexInput {
|
|
26
|
+
* @location(0) position: vec2<f32>,
|
|
27
|
+
* @location(1) texcoord: vec2<f32>,
|
|
28
|
+
* @location(2) color: vec4<f32>,
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* # Auto-bound uniforms
|
|
33
|
+
*
|
|
34
|
+
* The renderer auto-binds these when the shader declares them. Declared
|
|
35
|
+
* but unused is fine; absent is fine too. Both backends carry the same
|
|
36
|
+
* logical uniforms, only the binding scheme differs.
|
|
37
|
+
*
|
|
38
|
+
* ## GLSL
|
|
39
|
+
*
|
|
40
|
+
* ```glsl
|
|
41
|
+
* uniform mat3 u_projection; // active view's projection
|
|
42
|
+
* uniform mat3 u_translation; // mesh's global transform
|
|
43
|
+
* uniform vec4 u_tint; // mesh.tint as RGBA in 0..1
|
|
44
|
+
* uniform sampler2D u_texture; // bound to texture slot 0
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* ## WGSL
|
|
48
|
+
*
|
|
49
|
+
* ```wgsl
|
|
50
|
+
* struct MeshUniforms {
|
|
51
|
+
* projection: mat3x3<f32>,
|
|
52
|
+
* translation: mat3x3<f32>,
|
|
53
|
+
* tint: vec4<f32>,
|
|
54
|
+
* };
|
|
55
|
+
*
|
|
56
|
+
* @group(0) @binding(0) var<uniform> u_mesh: MeshUniforms;
|
|
57
|
+
*
|
|
58
|
+
* @group(1) @binding(0) var u_texture: texture_2d<f32>;
|
|
59
|
+
* @group(1) @binding(1) var u_sampler: sampler;
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* # User uniforms
|
|
63
|
+
*
|
|
64
|
+
* Anything in {@link uniforms} is set after the auto-binds. `Texture`/
|
|
65
|
+
* `RenderTexture` values claim slots 1..N (slot 0 belongs to the mesh).
|
|
66
|
+
*
|
|
67
|
+
* ## WGSL user-uniform contract
|
|
68
|
+
*
|
|
69
|
+
* User uniforms live in `@group(2)`:
|
|
70
|
+
*
|
|
71
|
+
* - `@group(2) @binding(0) var<uniform> u_user: <UserUniformsStruct>;`
|
|
72
|
+
* for the packed scalar/vector/matrix uniforms.
|
|
73
|
+
* - `@group(2) @binding(N)` for each `Texture`/`RenderTexture` uniform,
|
|
74
|
+
* in declaration order, alongside its sampler at `@binding(N+1)`.
|
|
75
|
+
*/
|
|
76
|
+
class MeshShader {
|
|
77
|
+
/**
|
|
78
|
+
* Mutable user uniform values. Mutate between frames to drive animated
|
|
79
|
+
* effects; the renderer reads from this map every draw.
|
|
80
|
+
*
|
|
81
|
+
* shader.uniforms.uTime = performance.now() / 1000;
|
|
82
|
+
* shader.uniforms.uColor = [1, 0.5, 0, 1];
|
|
83
|
+
*/
|
|
84
|
+
uniforms;
|
|
85
|
+
/** GLSL source pair for the WebGL2 backend, or `null` if not provided. */
|
|
86
|
+
glsl;
|
|
87
|
+
/** WGSL source for the WebGPU backend, or `null` if not provided. */
|
|
88
|
+
wgsl;
|
|
89
|
+
_disposeCallbacks = new Set();
|
|
90
|
+
constructor(options) {
|
|
91
|
+
if (options.glsl === undefined && options.wgsl === undefined) {
|
|
92
|
+
throw new Error('MeshShader requires at least one of `glsl` or `wgsl`.');
|
|
93
|
+
}
|
|
94
|
+
if (options.glsl !== undefined) {
|
|
95
|
+
if (typeof options.glsl.vertex !== 'string' || options.glsl.vertex.length === 0) {
|
|
96
|
+
throw new Error('MeshShader.glsl.vertex must be a non-empty string.');
|
|
97
|
+
}
|
|
98
|
+
if (typeof options.glsl.fragment !== 'string' || options.glsl.fragment.length === 0) {
|
|
99
|
+
throw new Error('MeshShader.glsl.fragment must be a non-empty string.');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (options.wgsl !== undefined && (typeof options.wgsl !== 'string' || options.wgsl.length === 0)) {
|
|
103
|
+
throw new Error('MeshShader.wgsl must be a non-empty string.');
|
|
104
|
+
}
|
|
105
|
+
this.glsl = options.glsl ?? null;
|
|
106
|
+
this.wgsl = options.wgsl ?? null;
|
|
107
|
+
this.uniforms = { ...(options.uniforms ?? {}) };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Convenience setter equivalent to `shader.uniforms[name] = value`.
|
|
111
|
+
* Provided for symmetry with engine APIs that prefer explicit methods
|
|
112
|
+
* over property mutation.
|
|
113
|
+
*/
|
|
114
|
+
setUniform(name, value) {
|
|
115
|
+
this.uniforms[name] = value;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reflect declared uniforms from each language's source. Returns a per-
|
|
119
|
+
* language map of uniform-name → declared type, parsed from the shader
|
|
120
|
+
* sources via lightweight regex (not a full GLSL/WGSL grammar). Texture
|
|
121
|
+
* uniforms (`sampler2D`/`texture_2d`) are included; sampler bindings
|
|
122
|
+
* are not (they pair with textures by binding index).
|
|
123
|
+
*
|
|
124
|
+
* Reflection is best-effort and intended for CI drift-checks and editor
|
|
125
|
+
* tooling, not for runtime uniform binding decisions. The renderers do
|
|
126
|
+
* NOT consult this map; they bind uniforms by name from {@link uniforms}
|
|
127
|
+
* and let the underlying API resolve declared-but-unused entries.
|
|
128
|
+
*/
|
|
129
|
+
getDeclaredUniforms() {
|
|
130
|
+
return {
|
|
131
|
+
glsl: this.glsl !== null ? parseGlslUniforms(this.glsl.vertex, this.glsl.fragment) : {},
|
|
132
|
+
wgsl: this.wgsl !== null ? parseWgslUniforms(this.wgsl) : {},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Compare declared uniform names between the GLSL and WGSL sources.
|
|
137
|
+
* Returns lists of names declared in only one language. Use in CI to
|
|
138
|
+
* catch drift when both languages should expose the same logical
|
|
139
|
+
* uniforms. When only one language is provided, returns empty arrays.
|
|
140
|
+
*
|
|
141
|
+
* Auto-bound uniforms (`u_projection`, `u_translation`, `u_tint`,
|
|
142
|
+
* `u_texture`) are excluded from the comparison since the GLSL source
|
|
143
|
+
* declares them at the top-level uniform scope while the WGSL source
|
|
144
|
+
* receives them via the `@group(0)` mesh-uniforms struct and the
|
|
145
|
+
* `@group(1)` texture binding.
|
|
146
|
+
*/
|
|
147
|
+
detectUniformDrift() {
|
|
148
|
+
if (this.glsl === null || this.wgsl === null) {
|
|
149
|
+
return { onlyInGlsl: [], onlyInWgsl: [] };
|
|
150
|
+
}
|
|
151
|
+
const declared = this.getDeclaredUniforms();
|
|
152
|
+
const glslNames = new Set(Object.keys(declared.glsl).filter(n => !autoBoundUniformNames.has(n)));
|
|
153
|
+
const wgslNames = new Set(Object.keys(declared.wgsl).filter(n => !autoBoundUniformNames.has(n)));
|
|
154
|
+
const onlyInGlsl = [];
|
|
155
|
+
const onlyInWgsl = [];
|
|
156
|
+
for (const name of glslNames) {
|
|
157
|
+
if (!wgslNames.has(name))
|
|
158
|
+
onlyInGlsl.push(name);
|
|
159
|
+
}
|
|
160
|
+
for (const name of wgslNames) {
|
|
161
|
+
if (!glslNames.has(name))
|
|
162
|
+
onlyInWgsl.push(name);
|
|
163
|
+
}
|
|
164
|
+
return { onlyInGlsl, onlyInWgsl };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Release GPU resources cached against this `MeshShader` on every
|
|
168
|
+
* backend that has compiled it. Safe to call multiple times. After
|
|
169
|
+
* destroy, the shader can still be re-used — renderers will recompile
|
|
170
|
+
* on next draw — but typical usage is to drop the reference.
|
|
171
|
+
*/
|
|
172
|
+
destroy() {
|
|
173
|
+
for (const callback of this._disposeCallbacks) {
|
|
174
|
+
callback();
|
|
175
|
+
}
|
|
176
|
+
this._disposeCallbacks.clear();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Internal hook for renderers to register a per-shader-instance cleanup
|
|
180
|
+
* callback (release compiled program, pipeline, or bind groups). The
|
|
181
|
+
* callback fires on {@link destroy}; renderers MUST also tolerate the
|
|
182
|
+
* shader being garbage-collected without destroy ever being called.
|
|
183
|
+
*
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
186
|
+
_onDispose(callback) {
|
|
187
|
+
this._disposeCallbacks.add(callback);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const autoBoundUniformNames = new Set(['u_projection', 'u_translation', 'u_tint', 'u_texture', 'u_mesh']);
|
|
191
|
+
const glslUniformPattern = /\buniform\s+(?:mediump\s+|highp\s+|lowp\s+|)(\w+)\s+(\w+)[^;]*;/g;
|
|
192
|
+
const wgslUserUniformPattern = /@group\(\s*2\s*\)\s*@binding\(\s*\d+\s*\)\s*var(?:<[^>]+>|)\s+(\w+)\s*:\s*([^;]+);/g;
|
|
193
|
+
/**
|
|
194
|
+
* Strip line and block comments from a shader source so the uniform
|
|
195
|
+
* regexes don't match commented-out declarations. Conservative: works
|
|
196
|
+
* for both GLSL and WGSL syntax (both use `//` and `/* ... *\/`).
|
|
197
|
+
*/
|
|
198
|
+
function stripComments(source) {
|
|
199
|
+
return source.replaceAll(/\/\*[\s\S]*?\*\//g, '').replaceAll(/\/\/[^\n]*/g, '');
|
|
200
|
+
}
|
|
201
|
+
function parseGlslUniforms(vertex, fragment) {
|
|
202
|
+
const result = {};
|
|
203
|
+
for (const source of [vertex, fragment]) {
|
|
204
|
+
const stripped = stripComments(source);
|
|
205
|
+
glslUniformPattern.lastIndex = 0;
|
|
206
|
+
let match;
|
|
207
|
+
while ((match = glslUniformPattern.exec(stripped)) !== null) {
|
|
208
|
+
const [, type, name] = match;
|
|
209
|
+
result[name] = type;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
function parseWgslUniforms(source) {
|
|
215
|
+
const result = {};
|
|
216
|
+
const stripped = stripComments(source);
|
|
217
|
+
// User uniforms in @group(2). Each user-uniform binding is either:
|
|
218
|
+
// - var<uniform> u_user: SomeStruct;
|
|
219
|
+
// - var u_extraTex: texture_2d<f32>;
|
|
220
|
+
// We extract the name and the (trimmed) type expression.
|
|
221
|
+
wgslUserUniformPattern.lastIndex = 0;
|
|
222
|
+
let match;
|
|
223
|
+
while ((match = wgslUserUniformPattern.exec(stripped)) !== null) {
|
|
224
|
+
const [, name, type] = match;
|
|
225
|
+
result[name] = type.trim();
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export { MeshShader };
|
|
231
|
+
//# sourceMappingURL=MeshShader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MeshShader.js","sources":["../../../../../src/rendering/mesh/MeshShader.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { SamplerOptions } from '@/rendering/texture/Sampler';
|
|
2
|
+
import { Texture } from '@/rendering/texture/Texture';
|
|
3
|
+
/**
|
|
4
|
+
* Pixel format for {@link DataTexture}.
|
|
5
|
+
*
|
|
6
|
+
* - `r8` — single-channel 8-bit unsigned. Buffer is `Uint8Array`. 1 byte/pixel.
|
|
7
|
+
* - `r32f` — single-channel 32-bit float. Buffer is `Float32Array`. 4 bytes/pixel.
|
|
8
|
+
* - `rgba8` — 4-channel 8-bit unsigned. Buffer is `Uint8Array`. 4 bytes/pixel.
|
|
9
|
+
* - `rgba32f`— 4-channel 32-bit float. Buffer is `Float32Array`. 16 bytes/pixel.
|
|
10
|
+
*
|
|
11
|
+
* Float formats are core in WebGL2 and WebGPU; no extension probe required.
|
|
12
|
+
*/
|
|
13
|
+
export type DataTextureFormat = 'r8' | 'r32f' | 'rgba8' | 'rgba32f';
|
|
14
|
+
/** Buffer typed-array kind for a given format. */
|
|
15
|
+
export type DataTextureBuffer<F extends DataTextureFormat = DataTextureFormat> = F extends 'r8' | 'rgba8' ? Uint8Array : F extends 'r32f' | 'rgba32f' ? Float32Array : Uint8Array | Float32Array;
|
|
16
|
+
/**
|
|
17
|
+
* A region of the buffer marked for upload by the next backend sync.
|
|
18
|
+
* Bounds are pixel coordinates with origin at the top-left.
|
|
19
|
+
*/
|
|
20
|
+
export interface DataTextureDirtyRegion {
|
|
21
|
+
/** Whether the whole texture should be re-uploaded (covers initial alloc and full {@link DataTexture.commit}). */
|
|
22
|
+
readonly full: boolean;
|
|
23
|
+
readonly x: number;
|
|
24
|
+
readonly y: number;
|
|
25
|
+
readonly width: number;
|
|
26
|
+
readonly height: number;
|
|
27
|
+
}
|
|
28
|
+
/** Construction options for {@link DataTexture}. */
|
|
29
|
+
export interface DataTextureOptions {
|
|
30
|
+
readonly width: number;
|
|
31
|
+
readonly height: number;
|
|
32
|
+
readonly format: DataTextureFormat;
|
|
33
|
+
/**
|
|
34
|
+
* Optional external buffer. When omitted, an internal buffer is allocated
|
|
35
|
+
* sized exactly `width * height * channels`. When supplied:
|
|
36
|
+
* - A `Uint8Array` requires an 8-bit format (`r8`/`rgba8`).
|
|
37
|
+
* - A `Float32Array` requires a 32-bit float format (`r32f`/`rgba32f`).
|
|
38
|
+
* - An `ArrayBuffer` is accepted for any format and wrapped in the
|
|
39
|
+
* appropriate typed-array kind (zero-copy view, no allocation).
|
|
40
|
+
*
|
|
41
|
+
* In all cases the byte length must equal `width * height * channels * bytesPerChannel`,
|
|
42
|
+
* otherwise the constructor throws.
|
|
43
|
+
*/
|
|
44
|
+
readonly data?: Uint8Array | Float32Array | ArrayBuffer;
|
|
45
|
+
/** Sampler overrides; defaults to nearest filtering and clamp-to-edge wrapping. */
|
|
46
|
+
readonly samplerOptions?: Partial<SamplerOptions>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A 2D texture whose pixels live in a CPU-side typed array. Mutate the
|
|
50
|
+
* `buffer` directly and call {@link commit} to upload the whole array, or
|
|
51
|
+
* {@link commitRect} to upload a sub-region (cheaper for ring-buffer
|
|
52
|
+
* patterns like spectrograms).
|
|
53
|
+
*
|
|
54
|
+
* `DataTexture` extends {@link Texture}, so any API that accepts a
|
|
55
|
+
* `Texture` (filter uniforms, mesh textures, custom shader uniforms)
|
|
56
|
+
* accepts a `DataTexture` unchanged.
|
|
57
|
+
*
|
|
58
|
+
* # Default sampler
|
|
59
|
+
*
|
|
60
|
+
* `DataTexture` defaults to nearest filtering, clamp-to-edge wrap, no mip
|
|
61
|
+
* generation, and no premultiply. These match the typical "raw data
|
|
62
|
+
* lookup" use case where bilinear filtering would corrupt sampled values
|
|
63
|
+
* (e.g. spectrum bins sampled by index).
|
|
64
|
+
*
|
|
65
|
+
* # Bring-your-own buffer
|
|
66
|
+
*
|
|
67
|
+
* Pass `data` in options to share an external buffer. Useful for:
|
|
68
|
+
* - SharedArrayBuffer + Worker pipelines (audio DSP off the main thread)
|
|
69
|
+
* - Buffer pooling across many small textures
|
|
70
|
+
* - Interop with WebAssembly memory or other APIs that produce typed-array views
|
|
71
|
+
*
|
|
72
|
+
* The buffer reference is fixed for the lifetime of the texture (the
|
|
73
|
+
* `buffer` property is `readonly`); only its contents may be mutated.
|
|
74
|
+
*
|
|
75
|
+
* # Format / buffer correspondence
|
|
76
|
+
*
|
|
77
|
+
* The TypeScript type system narrows `buffer` based on `format`:
|
|
78
|
+
*
|
|
79
|
+
* const r8 = new DataTexture({ width: 256, height: 1, format: 'r8' });
|
|
80
|
+
* r8.buffer // Uint8Array
|
|
81
|
+
*
|
|
82
|
+
* const r32f = new DataTexture({ width: 256, height: 1, format: 'r32f' });
|
|
83
|
+
* r32f.buffer // Float32Array
|
|
84
|
+
*/
|
|
85
|
+
export declare class DataTexture<F extends DataTextureFormat = DataTextureFormat> extends Texture {
|
|
86
|
+
static defaultSamplerOptions: SamplerOptions;
|
|
87
|
+
readonly format: F;
|
|
88
|
+
readonly buffer: DataTextureBuffer<F>;
|
|
89
|
+
private _dirty;
|
|
90
|
+
constructor(options: DataTextureOptions & {
|
|
91
|
+
format: F;
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* Mark the entire buffer for re-upload on next backend sync. Call after
|
|
95
|
+
* mutating `buffer` contents to flush changes to the GPU.
|
|
96
|
+
*/
|
|
97
|
+
commit(): this;
|
|
98
|
+
/**
|
|
99
|
+
* Mark a sub-region of the buffer dirty for partial upload. More efficient
|
|
100
|
+
* than {@link commit} for ring-buffer patterns where only one row or column
|
|
101
|
+
* changes per frame. If a region was already pending, the union is uploaded.
|
|
102
|
+
*
|
|
103
|
+
* Coordinates are pixel-space with origin at the top-left. Bounds are clamped
|
|
104
|
+
* to the texture dimensions; out-of-range rectangles throw.
|
|
105
|
+
*/
|
|
106
|
+
commitRect(x: number, y: number, width: number, height: number): this;
|
|
107
|
+
/**
|
|
108
|
+
* Internal: backend reads the pending dirty region and clears it. Returns
|
|
109
|
+
* `null` when there is nothing pending. Backends call this once per sync
|
|
110
|
+
* pass to plan their texSubImage2D / writeTexture operations.
|
|
111
|
+
*
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
_consumeDirtyRegion(): DataTextureDirtyRegion | null;
|
|
115
|
+
}
|