@viji-dev/core 0.2.10 → 0.2.12
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/dist/artist-dts.js +1 -1
- package/dist/artist-global.d.ts +1 -1
- package/dist/assets/{viji.worker-kGDstU5X.js → viji.worker-DHpeQQ14.js} +1276 -4
- package/dist/assets/viji.worker-DHpeQQ14.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/assets/renderers/P5WorkerAdapter-B4koBeZd.js +0 -343
- package/dist/assets/renderers/P5WorkerAdapter-B4koBeZd.js.map +0 -1
- package/dist/assets/renderers/ShaderWorkerAdapter-Cn60jh9g.js +0 -939
- package/dist/assets/renderers/ShaderWorkerAdapter-Cn60jh9g.js.map +0 -1
- package/dist/assets/viji.worker-kGDstU5X.js.map +0 -1
|
@@ -1,939 +0,0 @@
|
|
|
1
|
-
class ShaderParameterParser {
|
|
2
|
-
/**
|
|
3
|
-
* Parse all parameter declarations from shader code
|
|
4
|
-
*/
|
|
5
|
-
static parseParameters(shaderCode) {
|
|
6
|
-
const parameters = [];
|
|
7
|
-
const lines = shaderCode.split("\n");
|
|
8
|
-
for (const line of lines) {
|
|
9
|
-
const trimmed = line.trim();
|
|
10
|
-
const match = trimmed.match(/\/\/\s*@viji-(\w+):(\w+)\s+(.+)/);
|
|
11
|
-
if (match) {
|
|
12
|
-
const [, type, uniformName, configStr] = match;
|
|
13
|
-
try {
|
|
14
|
-
const config = this.parseKeyValuePairs(configStr);
|
|
15
|
-
const param = {
|
|
16
|
-
type,
|
|
17
|
-
uniformName,
|
|
18
|
-
label: config.label || uniformName,
|
|
19
|
-
default: config.default,
|
|
20
|
-
config
|
|
21
|
-
};
|
|
22
|
-
this.validateParameter(param);
|
|
23
|
-
parameters.push(param);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
console.warn(`Failed to parse shader parameter: ${line}`, error);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return parameters;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Parse key:value pairs from configuration string
|
|
33
|
-
*/
|
|
34
|
-
static parseKeyValuePairs(configStr) {
|
|
35
|
-
const config = {};
|
|
36
|
-
const keyValueRegex = /(\w+):((?:"[^"]*"|\[[^\]]*\]|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|[^\s]+))/g;
|
|
37
|
-
let match;
|
|
38
|
-
while ((match = keyValueRegex.exec(configStr)) !== null) {
|
|
39
|
-
const [, key, value] = match;
|
|
40
|
-
config[key] = this.parseValue(value);
|
|
41
|
-
}
|
|
42
|
-
return config;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Parse individual value from string
|
|
46
|
-
*/
|
|
47
|
-
static parseValue(value) {
|
|
48
|
-
if (value.startsWith('"') && value.endsWith('"')) {
|
|
49
|
-
return value.slice(1, -1);
|
|
50
|
-
}
|
|
51
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
52
|
-
try {
|
|
53
|
-
return JSON.parse(value);
|
|
54
|
-
} catch {
|
|
55
|
-
const items = value.slice(1, -1).split(",").map((s) => s.trim());
|
|
56
|
-
return items.map((item) => {
|
|
57
|
-
if (item.startsWith('"') && item.endsWith('"')) {
|
|
58
|
-
return item.slice(1, -1);
|
|
59
|
-
}
|
|
60
|
-
const num2 = parseFloat(item);
|
|
61
|
-
return isNaN(num2) ? item : num2;
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (value.startsWith("#")) {
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
if (value === "true") return true;
|
|
69
|
-
if (value === "false") return false;
|
|
70
|
-
const num = parseFloat(value);
|
|
71
|
-
if (!isNaN(num)) return num;
|
|
72
|
-
return value;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Validate parameter definition
|
|
76
|
-
*/
|
|
77
|
-
static validateParameter(param) {
|
|
78
|
-
if (!param.type) {
|
|
79
|
-
throw new Error("Parameter type is required");
|
|
80
|
-
}
|
|
81
|
-
if (!param.uniformName) {
|
|
82
|
-
throw new Error("Parameter uniformName is required");
|
|
83
|
-
}
|
|
84
|
-
if (!param.config.label) {
|
|
85
|
-
throw new Error(`Parameter ${param.uniformName} missing required 'label' key`);
|
|
86
|
-
}
|
|
87
|
-
switch (param.type) {
|
|
88
|
-
case "slider":
|
|
89
|
-
case "number":
|
|
90
|
-
if (param.config.default === void 0) {
|
|
91
|
-
throw new Error(`Parameter ${param.uniformName} of type ${param.type} missing required 'default' key`);
|
|
92
|
-
}
|
|
93
|
-
break;
|
|
94
|
-
case "color":
|
|
95
|
-
if (param.config.default === void 0) {
|
|
96
|
-
throw new Error(`Parameter ${param.uniformName} of type 'color' missing required 'default' key`);
|
|
97
|
-
}
|
|
98
|
-
if (!param.config.default.startsWith("#")) {
|
|
99
|
-
throw new Error(`Parameter ${param.uniformName} of type 'color' default must be hex color (e.g., #ff0000)`);
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
case "toggle":
|
|
103
|
-
if (param.config.default === void 0) {
|
|
104
|
-
throw new Error(`Parameter ${param.uniformName} of type 'toggle' missing required 'default' key`);
|
|
105
|
-
}
|
|
106
|
-
if (typeof param.config.default !== "boolean") {
|
|
107
|
-
throw new Error(`Parameter ${param.uniformName} of type 'toggle' default must be boolean (true or false)`);
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
110
|
-
case "select":
|
|
111
|
-
if (param.config.default === void 0) {
|
|
112
|
-
throw new Error(`Parameter ${param.uniformName} of type 'select' missing required 'default' key`);
|
|
113
|
-
}
|
|
114
|
-
if (!param.config.options || !Array.isArray(param.config.options)) {
|
|
115
|
-
throw new Error(`Parameter ${param.uniformName} of type 'select' missing required 'options' key (array)`);
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
case "image":
|
|
119
|
-
break;
|
|
120
|
-
default:
|
|
121
|
-
console.warn(`Unknown parameter type: ${param.type}`);
|
|
122
|
-
}
|
|
123
|
-
if (param.uniformName.startsWith("u_")) {
|
|
124
|
-
console.warn(`Parameter name "${param.uniformName}" uses reserved prefix "u_". Consider renaming to avoid conflicts with built-in uniforms.`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Generate uniform declaration for a parameter
|
|
129
|
-
*/
|
|
130
|
-
static generateUniformDeclaration(param) {
|
|
131
|
-
switch (param.type) {
|
|
132
|
-
case "slider":
|
|
133
|
-
case "number":
|
|
134
|
-
return `uniform float ${param.uniformName};`;
|
|
135
|
-
case "color":
|
|
136
|
-
return `uniform vec3 ${param.uniformName};`;
|
|
137
|
-
case "toggle":
|
|
138
|
-
return `uniform bool ${param.uniformName};`;
|
|
139
|
-
case "select":
|
|
140
|
-
return `uniform int ${param.uniformName};`;
|
|
141
|
-
case "image":
|
|
142
|
-
return `uniform sampler2D ${param.uniformName};`;
|
|
143
|
-
default:
|
|
144
|
-
return `// Unknown parameter type: ${param.type}`;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
class ShaderWorkerAdapter {
|
|
149
|
-
constructor(offscreenCanvas, _vijiAPI, shaderCode) {
|
|
150
|
-
this.shaderCode = shaderCode;
|
|
151
|
-
this.glslVersion = this.detectGLSLVersion(shaderCode);
|
|
152
|
-
this.backbufferEnabled = shaderCode.includes("backbuffer");
|
|
153
|
-
if (this.glslVersion === "glsl300") {
|
|
154
|
-
const gl = offscreenCanvas.getContext("webgl2");
|
|
155
|
-
if (!gl) {
|
|
156
|
-
throw new Error("WebGL 2 not supported. Use GLSL ES 1.00 syntax instead.");
|
|
157
|
-
}
|
|
158
|
-
this.gl = gl;
|
|
159
|
-
} else {
|
|
160
|
-
const gl = offscreenCanvas.getContext("webgl");
|
|
161
|
-
if (!gl) {
|
|
162
|
-
throw new Error("WebGL not supported");
|
|
163
|
-
}
|
|
164
|
-
this.gl = gl;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
gl;
|
|
168
|
-
program = null;
|
|
169
|
-
uniformLocations = /* @__PURE__ */ new Map();
|
|
170
|
-
textureUnits = /* @__PURE__ */ new Map();
|
|
171
|
-
nextTextureUnit = 0;
|
|
172
|
-
textures = /* @__PURE__ */ new Map();
|
|
173
|
-
// Fullscreen quad
|
|
174
|
-
quadBuffer = null;
|
|
175
|
-
// Parameter definitions
|
|
176
|
-
parameters = [];
|
|
177
|
-
// GLSL version detection
|
|
178
|
-
glslVersion = "glsl100";
|
|
179
|
-
// Audio FFT texture
|
|
180
|
-
audioFFTTexture = null;
|
|
181
|
-
videoTexture = null;
|
|
182
|
-
segmentationTexture = null;
|
|
183
|
-
// Backbuffer support (ping-pong framebuffers)
|
|
184
|
-
backbufferFramebuffer = null;
|
|
185
|
-
backbufferTexture = null;
|
|
186
|
-
currentFramebuffer = null;
|
|
187
|
-
currentTexture = null;
|
|
188
|
-
backbufferEnabled = false;
|
|
189
|
-
/**
|
|
190
|
-
* Initialize the shader adapter
|
|
191
|
-
*/
|
|
192
|
-
async init() {
|
|
193
|
-
try {
|
|
194
|
-
this.parameters = ShaderParameterParser.parseParameters(this.shaderCode);
|
|
195
|
-
this.createFullscreenQuad();
|
|
196
|
-
const processedCode = this.injectUniforms(this.shaderCode);
|
|
197
|
-
this.compileAndLinkShader(processedCode);
|
|
198
|
-
this.cacheUniformLocations();
|
|
199
|
-
this.reserveTextureUnits();
|
|
200
|
-
if (this.backbufferEnabled) {
|
|
201
|
-
this.createBackbufferFramebuffers();
|
|
202
|
-
}
|
|
203
|
-
} catch (error) {
|
|
204
|
-
console.error("Failed to initialize ShaderWorkerAdapter:", error);
|
|
205
|
-
throw error;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Detect GLSL version from shader code
|
|
210
|
-
*/
|
|
211
|
-
detectGLSLVersion(code) {
|
|
212
|
-
return code.includes("#version 300") ? "glsl300" : "glsl100";
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Create fullscreen quad geometry
|
|
216
|
-
*/
|
|
217
|
-
createFullscreenQuad() {
|
|
218
|
-
const vertices = new Float32Array([
|
|
219
|
-
-1,
|
|
220
|
-
-1,
|
|
221
|
-
// Bottom-left
|
|
222
|
-
1,
|
|
223
|
-
-1,
|
|
224
|
-
// Bottom-right
|
|
225
|
-
-1,
|
|
226
|
-
1,
|
|
227
|
-
// Top-left
|
|
228
|
-
1,
|
|
229
|
-
1
|
|
230
|
-
// Top-right
|
|
231
|
-
]);
|
|
232
|
-
this.quadBuffer = this.gl.createBuffer();
|
|
233
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadBuffer);
|
|
234
|
-
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Inject built-in and parameter uniforms into shader code
|
|
238
|
-
*/
|
|
239
|
-
injectUniforms(artistCode) {
|
|
240
|
-
let versionLine = "";
|
|
241
|
-
let codeWithoutVersion = artistCode;
|
|
242
|
-
const lines = artistCode.split("\n");
|
|
243
|
-
for (let i = 0; i < lines.length; i++) {
|
|
244
|
-
const trimmed = lines[i].trim();
|
|
245
|
-
if (trimmed.startsWith("#version")) {
|
|
246
|
-
versionLine = trimmed;
|
|
247
|
-
lines[i] = "";
|
|
248
|
-
codeWithoutVersion = lines.join("\n");
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
const injectionPoint = this.findInjectionPoint(codeWithoutVersion);
|
|
253
|
-
const builtInUniforms = this.getBuiltInUniforms();
|
|
254
|
-
const parameterUniforms = this.parameters.map((p) => ShaderParameterParser.generateUniformDeclaration(p)).join("\n");
|
|
255
|
-
const usesFwidth = artistCode.includes("fwidth");
|
|
256
|
-
if (usesFwidth && this.glslVersion === "glsl100") {
|
|
257
|
-
const ext = this.gl.getExtension("OES_standard_derivatives");
|
|
258
|
-
if (!ext) {
|
|
259
|
-
console.warn("Shader uses fwidth() but OES_standard_derivatives extension is not supported. Shader may not compile.");
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
const parts = [];
|
|
263
|
-
if (usesFwidth && this.glslVersion === "glsl100") {
|
|
264
|
-
parts.push("#extension GL_OES_standard_derivatives : enable");
|
|
265
|
-
}
|
|
266
|
-
if (this.glslVersion === "glsl100") {
|
|
267
|
-
parts.push("");
|
|
268
|
-
parts.push("#ifdef GL_ES");
|
|
269
|
-
parts.push("precision mediump float;");
|
|
270
|
-
parts.push("#endif");
|
|
271
|
-
} else {
|
|
272
|
-
parts.push("");
|
|
273
|
-
parts.push("precision mediump float;");
|
|
274
|
-
}
|
|
275
|
-
parts.push("");
|
|
276
|
-
parts.push("// ===== VIJI AUTO-INJECTED UNIFORMS =====");
|
|
277
|
-
parts.push("// Built-in uniforms (auto-provided)");
|
|
278
|
-
parts.push(builtInUniforms);
|
|
279
|
-
parts.push("");
|
|
280
|
-
parts.push("// Parameter uniforms (from @viji-* declarations)");
|
|
281
|
-
parts.push(parameterUniforms);
|
|
282
|
-
parts.push("");
|
|
283
|
-
parts.push("// ===== ARTIST CODE =====");
|
|
284
|
-
const uniformBlock = parts.join("\n");
|
|
285
|
-
const codeWithUniforms = codeWithoutVersion.slice(0, injectionPoint) + "\n" + uniformBlock + "\n" + codeWithoutVersion.slice(injectionPoint);
|
|
286
|
-
const finalCode = versionLine ? versionLine + "\n" + codeWithUniforms : codeWithUniforms;
|
|
287
|
-
console.log("=== INJECTED SHADER CODE (first 50 lines) ===");
|
|
288
|
-
console.log(finalCode.split("\n").slice(0, 50).join("\n"));
|
|
289
|
-
console.log("=== END INJECTED CODE ===");
|
|
290
|
-
return finalCode;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Find where to inject extensions and uniforms
|
|
294
|
-
* Extensions must come after #version but before any code
|
|
295
|
-
*
|
|
296
|
-
* Strategy:
|
|
297
|
-
* 1. If #version exists, inject right after it
|
|
298
|
-
* 2. Otherwise, skip ALL comments (single and multi-line) and inject before first code
|
|
299
|
-
*/
|
|
300
|
-
findInjectionPoint(code) {
|
|
301
|
-
const lines = code.split("\n");
|
|
302
|
-
for (let i = 0; i < lines.length; i++) {
|
|
303
|
-
const line = lines[i].trim();
|
|
304
|
-
if (line.startsWith("#version")) {
|
|
305
|
-
return this.getLineEndPosition(code, i);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
let inMultiLineComment = false;
|
|
309
|
-
let firstCodeLine = 0;
|
|
310
|
-
for (let i = 0; i < lines.length; i++) {
|
|
311
|
-
const line = lines[i].trim();
|
|
312
|
-
if (line.includes("/*")) {
|
|
313
|
-
inMultiLineComment = true;
|
|
314
|
-
}
|
|
315
|
-
if (line.includes("*/")) {
|
|
316
|
-
inMultiLineComment = false;
|
|
317
|
-
firstCodeLine = i + 1;
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
if (inMultiLineComment) {
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if (line === "" || line.startsWith("//")) {
|
|
324
|
-
firstCodeLine = i + 1;
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
if (firstCodeLine > 0 && firstCodeLine < lines.length) {
|
|
330
|
-
return this.getLineEndPosition(code, firstCodeLine - 1);
|
|
331
|
-
}
|
|
332
|
-
return 0;
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* Get byte position of end of line N
|
|
336
|
-
*/
|
|
337
|
-
getLineEndPosition(code, lineNumber) {
|
|
338
|
-
const lines = code.split("\n");
|
|
339
|
-
let position = 0;
|
|
340
|
-
for (let i = 0; i <= lineNumber && i < lines.length; i++) {
|
|
341
|
-
position += lines[i].length + 1;
|
|
342
|
-
}
|
|
343
|
-
return position;
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Get built-in uniform declarations
|
|
347
|
-
*/
|
|
348
|
-
getBuiltInUniforms() {
|
|
349
|
-
return `// Core - Canvas & Timing
|
|
350
|
-
uniform vec2 u_resolution;
|
|
351
|
-
uniform float u_time;
|
|
352
|
-
uniform float u_deltaTime;
|
|
353
|
-
uniform int u_frame;
|
|
354
|
-
uniform float u_pixelRatio;
|
|
355
|
-
uniform float u_fps;
|
|
356
|
-
|
|
357
|
-
// Mouse API
|
|
358
|
-
uniform vec2 u_mouse;
|
|
359
|
-
uniform bool u_mouseInCanvas;
|
|
360
|
-
uniform bool u_mousePressed;
|
|
361
|
-
uniform bool u_mouseLeft;
|
|
362
|
-
uniform bool u_mouseRight;
|
|
363
|
-
uniform bool u_mouseMiddle;
|
|
364
|
-
uniform vec2 u_mouseVelocity;
|
|
365
|
-
|
|
366
|
-
// Keyboard API - Common keys
|
|
367
|
-
uniform bool u_keySpace;
|
|
368
|
-
uniform bool u_keyShift;
|
|
369
|
-
uniform bool u_keyCtrl;
|
|
370
|
-
uniform bool u_keyAlt;
|
|
371
|
-
uniform bool u_keyW;
|
|
372
|
-
uniform bool u_keyA;
|
|
373
|
-
uniform bool u_keyS;
|
|
374
|
-
uniform bool u_keyD;
|
|
375
|
-
uniform bool u_keyUp;
|
|
376
|
-
uniform bool u_keyDown;
|
|
377
|
-
uniform bool u_keyLeft;
|
|
378
|
-
uniform bool u_keyRight;
|
|
379
|
-
|
|
380
|
-
// Touch API
|
|
381
|
-
uniform int u_touchCount;
|
|
382
|
-
uniform vec2 u_touch0;
|
|
383
|
-
uniform vec2 u_touch1;
|
|
384
|
-
uniform vec2 u_touch2;
|
|
385
|
-
uniform vec2 u_touch3;
|
|
386
|
-
uniform vec2 u_touch4;
|
|
387
|
-
|
|
388
|
-
// Audio
|
|
389
|
-
uniform float u_audioVolume;
|
|
390
|
-
uniform float u_audioPeak;
|
|
391
|
-
uniform float u_audioBass;
|
|
392
|
-
uniform float u_audioMid;
|
|
393
|
-
uniform float u_audioTreble;
|
|
394
|
-
uniform float u_audioSubBass;
|
|
395
|
-
uniform float u_audioLowMid;
|
|
396
|
-
uniform float u_audioHighMid;
|
|
397
|
-
uniform float u_audioPresence;
|
|
398
|
-
uniform float u_audioBrilliance;
|
|
399
|
-
uniform sampler2D u_audioFFT;
|
|
400
|
-
|
|
401
|
-
// Video
|
|
402
|
-
uniform sampler2D u_video;
|
|
403
|
-
uniform vec2 u_videoResolution;
|
|
404
|
-
uniform float u_videoFrameRate;
|
|
405
|
-
|
|
406
|
-
// CV - Face Detection
|
|
407
|
-
uniform int u_faceCount;
|
|
408
|
-
uniform vec4 u_face0Bounds;
|
|
409
|
-
uniform vec3 u_face0HeadPose;
|
|
410
|
-
uniform float u_face0Confidence;
|
|
411
|
-
uniform float u_face0Happy;
|
|
412
|
-
uniform float u_face0Sad;
|
|
413
|
-
uniform float u_face0Angry;
|
|
414
|
-
uniform float u_face0Surprised;
|
|
415
|
-
|
|
416
|
-
// CV - Hand Tracking
|
|
417
|
-
uniform int u_handCount;
|
|
418
|
-
uniform vec3 u_leftHandPalm;
|
|
419
|
-
uniform vec3 u_rightHandPalm;
|
|
420
|
-
uniform float u_leftHandFist;
|
|
421
|
-
uniform float u_leftHandOpen;
|
|
422
|
-
uniform float u_rightHandFist;
|
|
423
|
-
uniform float u_rightHandOpen;
|
|
424
|
-
|
|
425
|
-
// CV - Pose Detection
|
|
426
|
-
uniform bool u_poseDetected;
|
|
427
|
-
uniform vec2 u_nosePosition;
|
|
428
|
-
uniform vec2 u_leftWristPosition;
|
|
429
|
-
uniform vec2 u_rightWristPosition;
|
|
430
|
-
uniform vec2 u_leftAnklePosition;
|
|
431
|
-
uniform vec2 u_rightAnklePosition;
|
|
432
|
-
|
|
433
|
-
// CV - Segmentation
|
|
434
|
-
uniform sampler2D u_segmentationMask;
|
|
435
|
-
uniform vec2 u_segmentationRes;
|
|
436
|
-
|
|
437
|
-
// Backbuffer (previous frame feedback)
|
|
438
|
-
${this.backbufferEnabled ? "uniform sampler2D backbuffer;" : "// backbuffer not enabled"}
|
|
439
|
-
`;
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Compile and link shader program
|
|
443
|
-
*/
|
|
444
|
-
compileAndLinkShader(fragmentShaderCode) {
|
|
445
|
-
const gl = this.gl;
|
|
446
|
-
const vertexShaderCode = this.glslVersion === "glsl300" ? `#version 300 es
|
|
447
|
-
precision mediump float;
|
|
448
|
-
in vec2 a_position;
|
|
449
|
-
void main() {
|
|
450
|
-
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
451
|
-
}` : `attribute vec2 a_position;
|
|
452
|
-
void main() {
|
|
453
|
-
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
454
|
-
}`;
|
|
455
|
-
const vertexShader = this.compileShader(gl.VERTEX_SHADER, vertexShaderCode);
|
|
456
|
-
const fragmentShader = this.compileShader(gl.FRAGMENT_SHADER, fragmentShaderCode);
|
|
457
|
-
const program = gl.createProgram();
|
|
458
|
-
if (!program) {
|
|
459
|
-
throw new Error("Failed to create WebGL program");
|
|
460
|
-
}
|
|
461
|
-
gl.attachShader(program, vertexShader);
|
|
462
|
-
gl.attachShader(program, fragmentShader);
|
|
463
|
-
gl.linkProgram(program);
|
|
464
|
-
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
465
|
-
const error = gl.getProgramInfoLog(program);
|
|
466
|
-
throw new Error(`Shader program link failed: ${error}`);
|
|
467
|
-
}
|
|
468
|
-
this.program = program;
|
|
469
|
-
gl.useProgram(program);
|
|
470
|
-
gl.deleteShader(vertexShader);
|
|
471
|
-
gl.deleteShader(fragmentShader);
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Compile a shader
|
|
475
|
-
*/
|
|
476
|
-
compileShader(type, source) {
|
|
477
|
-
const gl = this.gl;
|
|
478
|
-
const shader = gl.createShader(type);
|
|
479
|
-
if (!shader) {
|
|
480
|
-
throw new Error("Failed to create shader");
|
|
481
|
-
}
|
|
482
|
-
gl.shaderSource(shader, source);
|
|
483
|
-
gl.compileShader(shader);
|
|
484
|
-
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
485
|
-
const error = gl.getShaderInfoLog(shader);
|
|
486
|
-
const shaderType = type === gl.VERTEX_SHADER ? "vertex" : "fragment";
|
|
487
|
-
throw new Error(`${shaderType} shader compilation failed:
|
|
488
|
-
${error}`);
|
|
489
|
-
}
|
|
490
|
-
return shader;
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Cache uniform locations for fast access
|
|
494
|
-
*/
|
|
495
|
-
cacheUniformLocations() {
|
|
496
|
-
if (!this.program) return;
|
|
497
|
-
const gl = this.gl;
|
|
498
|
-
const numUniforms = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
|
|
499
|
-
for (let i = 0; i < numUniforms; i++) {
|
|
500
|
-
const info = gl.getActiveUniform(this.program, i);
|
|
501
|
-
if (info) {
|
|
502
|
-
const location = gl.getUniformLocation(this.program, info.name);
|
|
503
|
-
this.uniformLocations.set(info.name, location);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Reserve texture units for special textures
|
|
509
|
-
*/
|
|
510
|
-
reserveTextureUnits() {
|
|
511
|
-
this.textureUnits.set("u_audioFFT", this.nextTextureUnit++);
|
|
512
|
-
this.textureUnits.set("u_video", this.nextTextureUnit++);
|
|
513
|
-
this.textureUnits.set("u_segmentationMask", this.nextTextureUnit++);
|
|
514
|
-
if (this.backbufferEnabled) {
|
|
515
|
-
this.textureUnits.set("backbuffer", this.nextTextureUnit++);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Create ping-pong framebuffers for backbuffer support
|
|
520
|
-
*/
|
|
521
|
-
createBackbufferFramebuffers() {
|
|
522
|
-
const gl = this.gl;
|
|
523
|
-
const width = gl.canvas.width;
|
|
524
|
-
const height = gl.canvas.height;
|
|
525
|
-
const createFBOTexture = () => {
|
|
526
|
-
const texture = gl.createTexture();
|
|
527
|
-
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
528
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
529
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
530
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
531
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
532
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
533
|
-
const framebuffer = gl.createFramebuffer();
|
|
534
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
535
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
536
|
-
return { framebuffer, texture };
|
|
537
|
-
};
|
|
538
|
-
const fbo1 = createFBOTexture();
|
|
539
|
-
const fbo2 = createFBOTexture();
|
|
540
|
-
this.backbufferFramebuffer = fbo1.framebuffer;
|
|
541
|
-
this.backbufferTexture = fbo1.texture;
|
|
542
|
-
this.currentFramebuffer = fbo2.framebuffer;
|
|
543
|
-
this.currentTexture = fbo2.texture;
|
|
544
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
545
|
-
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Main render method
|
|
549
|
-
*/
|
|
550
|
-
render(viji, parameterObjects) {
|
|
551
|
-
const gl = this.gl;
|
|
552
|
-
if (!this.program || !this.quadBuffer) {
|
|
553
|
-
console.warn("Shader not initialized");
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
gl.useProgram(this.program);
|
|
557
|
-
this.updateBuiltInUniforms(viji);
|
|
558
|
-
this.updateParameterUniforms(parameterObjects);
|
|
559
|
-
if (this.backbufferEnabled && this.backbufferTexture) {
|
|
560
|
-
const backbufferUnit = this.textureUnits.get("backbuffer");
|
|
561
|
-
if (backbufferUnit !== void 0) {
|
|
562
|
-
gl.activeTexture(gl.TEXTURE0 + backbufferUnit);
|
|
563
|
-
gl.bindTexture(gl.TEXTURE_2D, this.backbufferTexture);
|
|
564
|
-
this.setUniform("backbuffer", "sampler2D", backbufferUnit);
|
|
565
|
-
}
|
|
566
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, this.currentFramebuffer);
|
|
567
|
-
}
|
|
568
|
-
const positionLocation = gl.getAttribLocation(this.program, "a_position");
|
|
569
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);
|
|
570
|
-
gl.enableVertexAttribArray(positionLocation);
|
|
571
|
-
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
572
|
-
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
573
|
-
if (this.backbufferEnabled) {
|
|
574
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
575
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
576
|
-
gl.bindTexture(gl.TEXTURE_2D, this.currentTexture);
|
|
577
|
-
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
578
|
-
const tempFB = this.backbufferFramebuffer;
|
|
579
|
-
const tempTex = this.backbufferTexture;
|
|
580
|
-
this.backbufferFramebuffer = this.currentFramebuffer;
|
|
581
|
-
this.backbufferTexture = this.currentTexture;
|
|
582
|
-
this.currentFramebuffer = tempFB;
|
|
583
|
-
this.currentTexture = tempTex;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Update built-in uniforms from viji object
|
|
588
|
-
*/
|
|
589
|
-
updateBuiltInUniforms(viji) {
|
|
590
|
-
this.setUniform("u_resolution", "vec2", [viji.width, viji.height]);
|
|
591
|
-
this.setUniform("u_time", "float", viji.time);
|
|
592
|
-
this.setUniform("u_deltaTime", "float", viji.deltaTime);
|
|
593
|
-
this.setUniform("u_frame", "int", viji.frameCount);
|
|
594
|
-
this.setUniform("u_pixelRatio", "float", viji.pixelRatio);
|
|
595
|
-
this.setUniform("u_fps", "float", viji.fps);
|
|
596
|
-
this.setUniform("u_mouse", "vec2", [viji.mouse.x, viji.height - viji.mouse.y]);
|
|
597
|
-
this.setUniform("u_mouseInCanvas", "bool", viji.mouse.isInCanvas);
|
|
598
|
-
this.setUniform("u_mousePressed", "bool", viji.mouse.isPressed);
|
|
599
|
-
this.setUniform("u_mouseLeft", "bool", viji.mouse.leftButton);
|
|
600
|
-
this.setUniform("u_mouseRight", "bool", viji.mouse.rightButton);
|
|
601
|
-
this.setUniform("u_mouseMiddle", "bool", viji.mouse.middleButton);
|
|
602
|
-
this.setUniform("u_mouseVelocity", "vec2", [viji.mouse.velocity.x, -viji.mouse.velocity.y]);
|
|
603
|
-
this.setUniform("u_keySpace", "bool", viji.keyboard.isPressed(" ") || viji.keyboard.isPressed("space"));
|
|
604
|
-
this.setUniform("u_keyShift", "bool", viji.keyboard.shift);
|
|
605
|
-
this.setUniform("u_keyCtrl", "bool", viji.keyboard.ctrl);
|
|
606
|
-
this.setUniform("u_keyAlt", "bool", viji.keyboard.alt);
|
|
607
|
-
this.setUniform("u_keyW", "bool", viji.keyboard.isPressed("w") || viji.keyboard.isPressed("W"));
|
|
608
|
-
this.setUniform("u_keyA", "bool", viji.keyboard.isPressed("a") || viji.keyboard.isPressed("A"));
|
|
609
|
-
this.setUniform("u_keyS", "bool", viji.keyboard.isPressed("s") || viji.keyboard.isPressed("S"));
|
|
610
|
-
this.setUniform("u_keyD", "bool", viji.keyboard.isPressed("d") || viji.keyboard.isPressed("D"));
|
|
611
|
-
this.setUniform("u_keyUp", "bool", viji.keyboard.isPressed("ArrowUp"));
|
|
612
|
-
this.setUniform("u_keyDown", "bool", viji.keyboard.isPressed("ArrowDown"));
|
|
613
|
-
this.setUniform("u_keyLeft", "bool", viji.keyboard.isPressed("ArrowLeft"));
|
|
614
|
-
this.setUniform("u_keyRight", "bool", viji.keyboard.isPressed("ArrowRight"));
|
|
615
|
-
this.setUniform("u_touchCount", "int", viji.touches.count);
|
|
616
|
-
for (let i = 0; i < 5; i++) {
|
|
617
|
-
const touch = viji.touches.points[i];
|
|
618
|
-
if (touch) {
|
|
619
|
-
this.setUniform(`u_touch${i}`, "vec2", [touch.x, viji.height - touch.y]);
|
|
620
|
-
} else {
|
|
621
|
-
this.setUniform(`u_touch${i}`, "vec2", [0, 0]);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
const audio = viji.audio;
|
|
625
|
-
this.setUniform("u_audioVolume", "float", audio.volume?.rms || 0);
|
|
626
|
-
this.setUniform("u_audioPeak", "float", audio.volume?.peak || 0);
|
|
627
|
-
this.setUniform("u_audioBass", "float", audio.bands?.bass || 0);
|
|
628
|
-
this.setUniform("u_audioMid", "float", audio.bands?.mid || 0);
|
|
629
|
-
this.setUniform("u_audioTreble", "float", audio.bands?.treble || 0);
|
|
630
|
-
this.setUniform("u_audioSubBass", "float", audio.bands?.subBass || 0);
|
|
631
|
-
this.setUniform("u_audioLowMid", "float", audio.bands?.lowMid || 0);
|
|
632
|
-
this.setUniform("u_audioHighMid", "float", audio.bands?.highMid || 0);
|
|
633
|
-
this.setUniform("u_audioPresence", "float", audio.bands?.presence || 0);
|
|
634
|
-
this.setUniform("u_audioBrilliance", "float", audio.bands?.brilliance || 0);
|
|
635
|
-
if (audio.isConnected) {
|
|
636
|
-
this.updateAudioFFTTexture(audio.getFrequencyData());
|
|
637
|
-
}
|
|
638
|
-
const video = viji.video;
|
|
639
|
-
if (video.isConnected && video.currentFrame) {
|
|
640
|
-
this.updateVideoTexture(video.currentFrame);
|
|
641
|
-
this.setUniform("u_videoResolution", "vec2", [video.frameWidth, video.frameHeight]);
|
|
642
|
-
this.setUniform("u_videoFrameRate", "float", video.frameRate);
|
|
643
|
-
} else {
|
|
644
|
-
this.setUniform("u_videoResolution", "vec2", [0, 0]);
|
|
645
|
-
this.setUniform("u_videoFrameRate", "float", 0);
|
|
646
|
-
}
|
|
647
|
-
const faces = video.faces || [];
|
|
648
|
-
this.setUniform("u_faceCount", "int", faces.length);
|
|
649
|
-
if (faces.length > 0) {
|
|
650
|
-
const face = faces[0];
|
|
651
|
-
this.setUniform("u_face0Bounds", "vec4", [face.bounds.x, face.bounds.y, face.bounds.width, face.bounds.height]);
|
|
652
|
-
this.setUniform("u_face0HeadPose", "vec3", [face.headPose.pitch, face.headPose.yaw, face.headPose.roll]);
|
|
653
|
-
this.setUniform("u_face0Confidence", "float", face.confidence);
|
|
654
|
-
this.setUniform("u_face0Happy", "float", face.expressions.happy);
|
|
655
|
-
this.setUniform("u_face0Sad", "float", face.expressions.sad);
|
|
656
|
-
this.setUniform("u_face0Angry", "float", face.expressions.angry);
|
|
657
|
-
this.setUniform("u_face0Surprised", "float", face.expressions.surprised);
|
|
658
|
-
} else {
|
|
659
|
-
this.setUniform("u_face0Bounds", "vec4", [0, 0, 0, 0]);
|
|
660
|
-
this.setUniform("u_face0HeadPose", "vec3", [0, 0, 0]);
|
|
661
|
-
this.setUniform("u_face0Confidence", "float", 0);
|
|
662
|
-
this.setUniform("u_face0Happy", "float", 0);
|
|
663
|
-
this.setUniform("u_face0Sad", "float", 0);
|
|
664
|
-
this.setUniform("u_face0Angry", "float", 0);
|
|
665
|
-
this.setUniform("u_face0Surprised", "float", 0);
|
|
666
|
-
}
|
|
667
|
-
const hands = video.hands || [];
|
|
668
|
-
this.setUniform("u_handCount", "int", hands.length);
|
|
669
|
-
const leftHand = hands.find((h) => h.handedness === "left");
|
|
670
|
-
const rightHand = hands.find((h) => h.handedness === "right");
|
|
671
|
-
if (leftHand) {
|
|
672
|
-
this.setUniform("u_leftHandPalm", "vec3", [leftHand.palm.x, leftHand.palm.y, leftHand.palm.z]);
|
|
673
|
-
this.setUniform("u_leftHandFist", "float", leftHand.gestures?.fist || 0);
|
|
674
|
-
this.setUniform("u_leftHandOpen", "float", leftHand.gestures?.openPalm || 0);
|
|
675
|
-
} else {
|
|
676
|
-
this.setUniform("u_leftHandPalm", "vec3", [0, 0, 0]);
|
|
677
|
-
this.setUniform("u_leftHandFist", "float", 0);
|
|
678
|
-
this.setUniform("u_leftHandOpen", "float", 0);
|
|
679
|
-
}
|
|
680
|
-
if (rightHand) {
|
|
681
|
-
this.setUniform("u_rightHandPalm", "vec3", [rightHand.palm.x, rightHand.palm.y, rightHand.palm.z]);
|
|
682
|
-
this.setUniform("u_rightHandFist", "float", rightHand.gestures?.fist || 0);
|
|
683
|
-
this.setUniform("u_rightHandOpen", "float", rightHand.gestures?.openPalm || 0);
|
|
684
|
-
} else {
|
|
685
|
-
this.setUniform("u_rightHandPalm", "vec3", [0, 0, 0]);
|
|
686
|
-
this.setUniform("u_rightHandFist", "float", 0);
|
|
687
|
-
this.setUniform("u_rightHandOpen", "float", 0);
|
|
688
|
-
}
|
|
689
|
-
const pose = video.pose;
|
|
690
|
-
this.setUniform("u_poseDetected", "bool", pose !== null);
|
|
691
|
-
if (pose) {
|
|
692
|
-
const nose = pose.landmarks[0];
|
|
693
|
-
const leftWrist = pose.landmarks[15];
|
|
694
|
-
const rightWrist = pose.landmarks[16];
|
|
695
|
-
const leftAnkle = pose.landmarks[27];
|
|
696
|
-
const rightAnkle = pose.landmarks[28];
|
|
697
|
-
this.setUniform("u_nosePosition", "vec2", [nose?.x || 0, nose?.y || 0]);
|
|
698
|
-
this.setUniform("u_leftWristPosition", "vec2", [leftWrist?.x || 0, leftWrist?.y || 0]);
|
|
699
|
-
this.setUniform("u_rightWristPosition", "vec2", [rightWrist?.x || 0, rightWrist?.y || 0]);
|
|
700
|
-
this.setUniform("u_leftAnklePosition", "vec2", [leftAnkle?.x || 0, leftAnkle?.y || 0]);
|
|
701
|
-
this.setUniform("u_rightAnklePosition", "vec2", [rightAnkle?.x || 0, rightAnkle?.y || 0]);
|
|
702
|
-
} else {
|
|
703
|
-
this.setUniform("u_nosePosition", "vec2", [0, 0]);
|
|
704
|
-
this.setUniform("u_leftWristPosition", "vec2", [0, 0]);
|
|
705
|
-
this.setUniform("u_rightWristPosition", "vec2", [0, 0]);
|
|
706
|
-
this.setUniform("u_leftAnklePosition", "vec2", [0, 0]);
|
|
707
|
-
this.setUniform("u_rightAnklePosition", "vec2", [0, 0]);
|
|
708
|
-
}
|
|
709
|
-
const segmentation = video.segmentation;
|
|
710
|
-
if (segmentation) {
|
|
711
|
-
this.updateSegmentationTexture(segmentation.mask, segmentation.width, segmentation.height);
|
|
712
|
-
this.setUniform("u_segmentationRes", "vec2", [segmentation.width, segmentation.height]);
|
|
713
|
-
} else {
|
|
714
|
-
this.setUniform("u_segmentationRes", "vec2", [0, 0]);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
/**
|
|
718
|
-
* Update parameter uniforms from parameter objects
|
|
719
|
-
*/
|
|
720
|
-
updateParameterUniforms(parameterObjects) {
|
|
721
|
-
for (const param of this.parameters) {
|
|
722
|
-
const paramObj = parameterObjects.get(param.uniformName);
|
|
723
|
-
if (!paramObj) continue;
|
|
724
|
-
const value = paramObj.value;
|
|
725
|
-
switch (param.type) {
|
|
726
|
-
case "slider":
|
|
727
|
-
case "number":
|
|
728
|
-
this.setUniform(param.uniformName, "float", value);
|
|
729
|
-
break;
|
|
730
|
-
case "color":
|
|
731
|
-
const rgb = this.hexToRgb(value);
|
|
732
|
-
this.setUniform(param.uniformName, "vec3", rgb);
|
|
733
|
-
break;
|
|
734
|
-
case "toggle":
|
|
735
|
-
this.setUniform(param.uniformName, "bool", value);
|
|
736
|
-
break;
|
|
737
|
-
case "select":
|
|
738
|
-
const index = param.config.options?.indexOf(value) || 0;
|
|
739
|
-
this.setUniform(param.uniformName, "int", index);
|
|
740
|
-
break;
|
|
741
|
-
case "image":
|
|
742
|
-
if (value) {
|
|
743
|
-
this.updateImageTexture(param.uniformName, value);
|
|
744
|
-
}
|
|
745
|
-
break;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Set uniform value
|
|
751
|
-
*/
|
|
752
|
-
setUniform(name, type, value) {
|
|
753
|
-
const location = this.uniformLocations.get(name);
|
|
754
|
-
if (location === null || location === void 0) {
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
const gl = this.gl;
|
|
758
|
-
switch (type) {
|
|
759
|
-
case "float":
|
|
760
|
-
gl.uniform1f(location, value);
|
|
761
|
-
break;
|
|
762
|
-
case "int":
|
|
763
|
-
gl.uniform1i(location, value);
|
|
764
|
-
break;
|
|
765
|
-
case "bool":
|
|
766
|
-
gl.uniform1i(location, value ? 1 : 0);
|
|
767
|
-
break;
|
|
768
|
-
case "vec2":
|
|
769
|
-
gl.uniform2f(location, value[0], value[1]);
|
|
770
|
-
break;
|
|
771
|
-
case "vec3":
|
|
772
|
-
gl.uniform3f(location, value[0], value[1], value[2]);
|
|
773
|
-
break;
|
|
774
|
-
case "vec4":
|
|
775
|
-
gl.uniform4f(location, value[0], value[1], value[2], value[3]);
|
|
776
|
-
break;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
/**
|
|
780
|
-
* Convert hex color to RGB [0-1]
|
|
781
|
-
*/
|
|
782
|
-
hexToRgb(hex) {
|
|
783
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
784
|
-
if (result) {
|
|
785
|
-
return [
|
|
786
|
-
parseInt(result[1], 16) / 255,
|
|
787
|
-
parseInt(result[2], 16) / 255,
|
|
788
|
-
parseInt(result[3], 16) / 255
|
|
789
|
-
];
|
|
790
|
-
}
|
|
791
|
-
return [0, 0, 0];
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Update audio FFT texture
|
|
795
|
-
*/
|
|
796
|
-
updateAudioFFTTexture(frequencyData) {
|
|
797
|
-
const gl = this.gl;
|
|
798
|
-
const unit = this.textureUnits.get("u_audioFFT");
|
|
799
|
-
if (!this.audioFFTTexture) {
|
|
800
|
-
this.audioFFTTexture = gl.createTexture();
|
|
801
|
-
}
|
|
802
|
-
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
803
|
-
gl.bindTexture(gl.TEXTURE_2D, this.audioFFTTexture);
|
|
804
|
-
gl.texImage2D(
|
|
805
|
-
gl.TEXTURE_2D,
|
|
806
|
-
0,
|
|
807
|
-
gl.LUMINANCE,
|
|
808
|
-
frequencyData.length,
|
|
809
|
-
1,
|
|
810
|
-
0,
|
|
811
|
-
gl.LUMINANCE,
|
|
812
|
-
gl.UNSIGNED_BYTE,
|
|
813
|
-
frequencyData
|
|
814
|
-
);
|
|
815
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
816
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
817
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
818
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
819
|
-
const location = this.uniformLocations.get("u_audioFFT");
|
|
820
|
-
if (location) {
|
|
821
|
-
gl.uniform1i(location, unit);
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* Update video texture
|
|
826
|
-
*/
|
|
827
|
-
updateVideoTexture(videoFrame) {
|
|
828
|
-
const gl = this.gl;
|
|
829
|
-
const unit = this.textureUnits.get("u_video");
|
|
830
|
-
if (!this.videoTexture) {
|
|
831
|
-
this.videoTexture = gl.createTexture();
|
|
832
|
-
}
|
|
833
|
-
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
834
|
-
gl.bindTexture(gl.TEXTURE_2D, this.videoTexture);
|
|
835
|
-
gl.texImage2D(
|
|
836
|
-
gl.TEXTURE_2D,
|
|
837
|
-
0,
|
|
838
|
-
gl.RGBA,
|
|
839
|
-
gl.RGBA,
|
|
840
|
-
gl.UNSIGNED_BYTE,
|
|
841
|
-
videoFrame
|
|
842
|
-
);
|
|
843
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
844
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
845
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
846
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
847
|
-
const location = this.uniformLocations.get("u_video");
|
|
848
|
-
if (location) {
|
|
849
|
-
gl.uniform1i(location, unit);
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
/**
|
|
853
|
-
* Update segmentation mask texture
|
|
854
|
-
*/
|
|
855
|
-
updateSegmentationTexture(mask, width, height) {
|
|
856
|
-
const gl = this.gl;
|
|
857
|
-
const unit = this.textureUnits.get("u_segmentationMask");
|
|
858
|
-
if (!this.segmentationTexture) {
|
|
859
|
-
this.segmentationTexture = gl.createTexture();
|
|
860
|
-
}
|
|
861
|
-
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
862
|
-
gl.bindTexture(gl.TEXTURE_2D, this.segmentationTexture);
|
|
863
|
-
gl.texImage2D(
|
|
864
|
-
gl.TEXTURE_2D,
|
|
865
|
-
0,
|
|
866
|
-
gl.LUMINANCE,
|
|
867
|
-
width,
|
|
868
|
-
height,
|
|
869
|
-
0,
|
|
870
|
-
gl.LUMINANCE,
|
|
871
|
-
gl.UNSIGNED_BYTE,
|
|
872
|
-
mask
|
|
873
|
-
);
|
|
874
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
875
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
876
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
877
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
878
|
-
const location = this.uniformLocations.get("u_segmentationMask");
|
|
879
|
-
if (location) {
|
|
880
|
-
gl.uniform1i(location, unit);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
/**
|
|
884
|
-
* Update image parameter texture
|
|
885
|
-
*/
|
|
886
|
-
updateImageTexture(name, imageBitmap) {
|
|
887
|
-
const gl = this.gl;
|
|
888
|
-
if (!this.textureUnits.has(name)) {
|
|
889
|
-
this.textureUnits.set(name, this.nextTextureUnit++);
|
|
890
|
-
}
|
|
891
|
-
const unit = this.textureUnits.get(name);
|
|
892
|
-
if (!this.textures.has(name)) {
|
|
893
|
-
const texture2 = gl.createTexture();
|
|
894
|
-
if (texture2) {
|
|
895
|
-
this.textures.set(name, texture2);
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
const texture = this.textures.get(name);
|
|
899
|
-
if (!texture) return;
|
|
900
|
-
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
901
|
-
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
902
|
-
gl.texImage2D(
|
|
903
|
-
gl.TEXTURE_2D,
|
|
904
|
-
0,
|
|
905
|
-
gl.RGBA,
|
|
906
|
-
gl.RGBA,
|
|
907
|
-
gl.UNSIGNED_BYTE,
|
|
908
|
-
imageBitmap
|
|
909
|
-
);
|
|
910
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
911
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
912
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
913
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
914
|
-
const location = this.uniformLocations.get(name);
|
|
915
|
-
if (location) {
|
|
916
|
-
gl.uniform1i(location, unit);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* Handle canvas resize
|
|
921
|
-
*/
|
|
922
|
-
resize(width, height) {
|
|
923
|
-
const gl = this.gl;
|
|
924
|
-
gl.viewport(0, 0, width, height);
|
|
925
|
-
if (this.backbufferEnabled) {
|
|
926
|
-
this.createBackbufferFramebuffers();
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Get parameter definitions for host
|
|
931
|
-
*/
|
|
932
|
-
getParameterDefinitions() {
|
|
933
|
-
return this.parameters;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
export {
|
|
937
|
-
ShaderWorkerAdapter
|
|
938
|
-
};
|
|
939
|
-
//# sourceMappingURL=ShaderWorkerAdapter-Cn60jh9g.js.map
|