webgl2 1.2.1 → 1.2.3

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.
@@ -1,2483 +1,2555 @@
1
- // Thin forwarding WasmWebGL2RenderingContext and helpers
2
- // This module contains the class and small helpers that operate on the
3
- // WebAssembly instance. It is intentionally minimal: JS forwards calls to
4
- // WASM and reads last-error strings when needed.
5
-
6
- /** @typedef {number} u32 */
7
-
8
- // Errno constants (must match src/webgl2_context.rs)
9
- export const ERR_OK = 0;
10
- export const ERR_INVALID_HANDLE = 1;
11
- export const ERR_OOM = 2;
12
- export const ERR_INVALID_ARGS = 3;
13
- export const ERR_NOT_IMPLEMENTED = 4;
14
- export const ERR_GL = 5;
15
- export const ERR_INTERNAL = 6;
16
-
17
- import { WasmWebGLTexture } from './webgl2_texture.js';
18
- import { WasmWebGLShader, WasmWebGLProgram, WasmWebGLBuffer, WasmWebGLRenderbuffer } from './webgl2_resources.js';
19
-
20
- /**
21
- * @implements {WebGL2RenderingContext}
22
- */
23
- export class WasmWebGL2RenderingContext {
24
- // Constants
25
- FRAGMENT_SHADER = 0x8B30;
26
- VERTEX_SHADER = 0x8B31;
27
- TRIANGLES = 0x0004;
28
- TRIANGLE_STRIP = 0x0005;
29
- COLOR_BUFFER_BIT = 0x00004000;
30
- DEPTH_BUFFER_BIT = 0x00000100;
31
- DEPTH_TEST = 0x0B71;
32
- STENCIL_TEST = 0x0B90;
33
- SCISSOR_TEST = 0x0C11;
34
- STENCIL_BUFFER_BIT = 0x00000400;
35
- COMPILE_STATUS = 0x8B81;
36
- LINK_STATUS = 0x8B82;
37
- DELETE_STATUS = 0x8B80;
38
- VALIDATE_STATUS = 0x8B83;
39
- ARRAY_BUFFER = 0x8892;
40
- ELEMENT_ARRAY_BUFFER = 0x8893;
41
- COPY_READ_BUFFER = 0x8F36;
42
- COPY_WRITE_BUFFER = 0x8F37;
43
- PIXEL_PACK_BUFFER = 0x88EB;
44
- PIXEL_UNPACK_BUFFER = 0x88EC;
45
- UNIFORM_BUFFER = 0x8A11;
46
- TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
47
- STATIC_DRAW = 0x88E4;
48
- BYTE = 0x1400;
49
- UNSIGNED_BYTE = 0x1401;
50
- SHORT = 0x1402;
51
- UNSIGNED_SHORT = 0x1403;
52
- INT = 0x1404;
53
- UNSIGNED_INT = 0x1405;
54
- FLOAT = 0x1406;
55
- FLOAT_VEC2 = 0x8B50;
56
- FLOAT_VEC3 = 0x8B51;
57
- FLOAT_VEC4 = 0x8B52;
58
- INT_VEC2 = 0x8B53;
59
- INT_VEC3 = 0x8B54;
60
- INT_VEC4 = 0x8B55;
61
- BOOL = 0x8B56;
62
- BOOL_VEC2 = 0x8B57;
63
- BOOL_VEC3 = 0x8B58;
64
- BOOL_VEC4 = 0x8B59;
65
- FLOAT_MAT2 = 0x8B5A;
66
- FLOAT_MAT3 = 0x8B5B;
67
- FLOAT_MAT4 = 0x8B5C;
68
- SAMPLER_2D = 0x8B5E;
69
- SAMPLER_3D = 0x8B5F;
70
- SAMPLER_CUBE = 0x8B60;
71
- ACTIVE_UNIFORMS = 0x8B86;
72
- ACTIVE_ATTRIBUTES = 0x8B89;
73
- VIEWPORT = 0x0BA2;
74
- COLOR_CLEAR_VALUE = 0x0C22;
75
- COLOR_WRITEMASK = 0x0C23;
76
- DEPTH_WRITEMASK = 0x0B72;
77
- STENCIL_WRITEMASK = 0x0B98;
78
- STENCIL_BACK_WRITEMASK = 0x8CA5;
79
-
80
- DEPTH_FUNC = 0x0B74;
81
- STENCIL_FUNC = 0x0B92;
82
- STENCIL_VALUE_MASK = 0x0B93;
83
- STENCIL_REF = 0x0B97;
84
- STENCIL_BACK_FUNC = 0x8800;
85
- STENCIL_BACK_VALUE_MASK = 0x8CA4;
86
- STENCIL_BACK_REF = 0x8CA3;
87
- STENCIL_FAIL = 0x0B94;
88
- STENCIL_PASS_DEPTH_FAIL = 0x0B95;
89
- STENCIL_PASS_DEPTH_PASS = 0x0B96;
90
- STENCIL_BACK_FAIL = 0x8801;
91
- STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802;
92
- STENCIL_BACK_PASS_DEPTH_PASS = 0x8803;
93
-
94
- BUFFER_SIZE = 0x8764;
95
- MAX_VERTEX_ATTRIBS = 0x8869;
96
- NO_ERROR = 0;
97
- INVALID_ENUM = 0x0500;
98
- INVALID_VALUE = 0x0501;
99
- INVALID_OPERATION = 0x0502;
100
- OUT_OF_MEMORY = 0x0505;
101
-
102
- ZERO = 0;
103
- ONE = 1;
104
-
105
- CURRENT_VERTEX_ATTRIB = 0x8626;
106
- VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622;
107
- VERTEX_ATTRIB_ARRAY_SIZE = 0x8623;
108
- VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624;
109
- VERTEX_ATTRIB_ARRAY_TYPE = 0x8625;
110
- VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A;
111
- VERTEX_ATTRIB_ARRAY_POINTER = 0x8645;
112
- VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
113
- VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE;
114
- VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD;
115
-
116
- RENDERBUFFER = 0x8D41;
117
- FRAMEBUFFER = 0x8D40;
118
- READ_FRAMEBUFFER = 0x8CA8;
119
- DRAW_FRAMEBUFFER = 0x8CA9;
120
- DEPTH_COMPONENT16 = 0x81A5;
121
- DEPTH_STENCIL = 0x84F9;
122
- RGBA4 = 0x8056;
123
- RGB565 = 0x8D62;
124
- RGB5_A1 = 0x8057;
125
- RGBA8 = 0x8058;
126
- STENCIL_INDEX8 = 0x8D48;
127
- COLOR_ATTACHMENT0 = 0x8CE0;
128
- DEPTH_ATTACHMENT = 0x8D00;
129
- STENCIL_ATTACHMENT = 0x8D20;
130
- DEPTH_STENCIL_ATTACHMENT = 0x821A;
131
-
132
- LESS = 0x0201;
133
- EQUAL = 0x0202;
134
- LEQUAL = 0x0203;
135
- GREATER = 0x0204;
136
- NOTEQUAL = 0x0205;
137
- GEQUAL = 0x0206;
138
- ALWAYS = 0x0207;
139
- NEVER = 0x0200;
140
-
141
- KEEP = 0x1E00;
142
- REPLACE = 0x1E01;
143
- INCR = 0x1E02;
144
- DECR = 0x1E03;
145
- INVERT = 0x150A;
146
- INCR_WRAP = 0x8507;
147
- DECR_WRAP = 0x8508;
148
-
149
- FRONT = 0x0404;
150
- BACK = 0x0405;
151
- FRONT_AND_BACK = 0x0408;
152
-
153
- TEXTURE_2D = 0x0DE1;
154
- TEXTURE_3D = 0x806F;
155
- TEXTURE_2D_ARRAY = 0x8C1A;
156
- TEXTURE_WRAP_S = 0x2802;
157
- TEXTURE_WRAP_T = 0x2803;
158
- TEXTURE_WRAP_R = 0x8072;
159
- TEXTURE_MAG_FILTER = 0x2800;
160
- TEXTURE_MIN_FILTER = 0x2801;
161
- RGBA = 0x1908;
162
- RED = 0x1903;
163
- RG = 0x8227;
164
- UNSIGNED_BYTE = 0x1401;
165
- FLOAT = 0x1406;
166
- NEAREST = 0x2600;
167
- LINEAR = 0x2601;
168
- NEAREST_MIPMAP_NEAREST = 0x2700;
169
- LINEAR_MIPMAP_NEAREST = 0x2701;
170
- NEAREST_MIPMAP_LINEAR = 0x2702;
171
- LINEAR_MIPMAP_LINEAR = 0x2703;
172
- REPEAT = 0x2901;
173
- CLAMP_TO_EDGE = 0x812F;
174
- MIRRORED_REPEAT = 0x8370;
175
-
176
- /**
177
- * @param {WebAssembly.Instance} instance
178
- * @param {u32} ctxHandle
179
- * @param {number} width
180
- * @param {number} height
181
- * @param {boolean} [debugShaders]
182
- */
183
- constructor({ instance, ctxHandle, width, height, debugShaders = false, sharedTable = null, tableAllocator = null }) {
184
- this._instance = instance;
185
- this._ctxHandle = ctxHandle;
186
- this._destroyed = false;
187
- /** @type {import('./webgl2_resources.js').WasmWebGLProgram | null} */
188
- this._currentProgram = null;
189
- // Explicit booleans for clarity
190
- this._debugShaders = !!debugShaders;
191
- this._drawingBufferWidth = width;
192
- this._drawingBufferHeight = height;
193
- this._sharedTable = sharedTable;
194
- this._tableAllocator = tableAllocator;
195
-
196
- WasmWebGL2RenderingContext._contexts.set(this._ctxHandle, this);
197
- }
198
-
199
- get drawingBufferWidth() {
200
- return this._drawingBufferWidth;
201
- }
202
-
203
- get drawingBufferHeight() {
204
- return this._drawingBufferHeight;
205
- }
206
-
207
- resize(width, height) {
208
- this._assertNotDestroyed();
209
- const ex = this._instance.exports;
210
- if (!ex || typeof ex.wasm_ctx_resize !== 'function') {
211
- throw new Error('wasm_ctx_resize not found');
212
- }
213
- const code = ex.wasm_ctx_resize(this._ctxHandle, width, height);
214
- _checkErr(code, this._instance);
215
- this._drawingBufferWidth = width;
216
- this._drawingBufferHeight = height;
217
- }
218
-
219
- // Set the viewport for rendering
220
- viewport(x, y, width, height) {
221
- this._assertNotDestroyed();
222
- const ex = this._instance.exports;
223
- if (!ex || typeof ex.wasm_ctx_viewport !== 'function') {
224
- throw new Error('wasm_ctx_viewport not found');
225
- }
226
- const code = ex.wasm_ctx_viewport(this._ctxHandle, x | 0, y | 0, width >>> 0, height >>> 0);
227
- _checkErr(code, this._instance);
228
- }
229
-
230
- /** @type {Map<number, WasmWebGL2RenderingContext>} */
231
- static _contexts = new Map();
232
-
233
- _executeShader(type, tableIdx, attrPtr, uniformPtr, varyingPtr, privatePtr, texturePtr) {
234
- if (!this._currentProgram) {
235
- return;
236
- }
237
-
238
- if (tableIdx > 0 && this._sharedTable) {
239
- const func = this._sharedTable.get(tableIdx);
240
- if (func) {
241
- func(this._ctxHandle, type, tableIdx, attrPtr, uniformPtr, varyingPtr, privatePtr, texturePtr);
242
- return;
243
- }
244
- }
245
-
246
- const shaderInstance = type === this.VERTEX_SHADER ? this._currentProgram._vsInstance : this._currentProgram._fsInstance;
247
- if (shaderInstance && shaderInstance.exports.main) {
248
- // @ts-ignore
249
- shaderInstance.exports.main(this._ctxHandle, type, tableIdx, attrPtr, uniformPtr, varyingPtr, privatePtr, texturePtr);
250
- }
251
- }
252
-
253
- destroy() {
254
- if (this._destroyed) return;
255
- WasmWebGL2RenderingContext._contexts.delete(this._ctxHandle);
256
- const ex = this._instance.exports;
257
- if (ex && typeof ex.wasm_destroy_context === 'function') {
258
- const code = ex.wasm_destroy_context(this._ctxHandle);
259
- _checkErr(code, this._instance);
260
- }
261
- this._destroyed = true;
262
- }
263
-
264
- _assertNotDestroyed() {
265
- if (this._destroyed) throw new Error('context has been destroyed');
266
- }
267
-
268
- createTexture() {
269
- this._assertNotDestroyed();
270
- const ex = this._instance.exports;
271
- if (!ex || typeof ex.wasm_ctx_create_texture !== 'function') {
272
- throw new Error('wasm_ctx_create_texture not found');
273
- }
274
- const handle = ex.wasm_ctx_create_texture(this._ctxHandle);
275
- if (handle === 0) {
276
- const msg = readErrorMessage(this._instance);
277
- throw new Error(`Failed to create texture: ${msg}`);
278
- }
279
- // Return a thin wrapper object representing the texture.
280
- return new WasmWebGLTexture(this, handle);
281
- }
282
-
283
- deleteTexture(tex) {
284
- this._assertNotDestroyed();
285
- const ex = this._instance.exports;
286
- if (!ex || typeof ex.wasm_ctx_delete_texture !== 'function') {
287
- throw new Error('wasm_ctx_delete_texture not found');
288
- }
289
- const handle = tex && typeof tex === 'object' && typeof tex._handle === 'number' ? tex._handle : (tex >>> 0);
290
- const code = ex.wasm_ctx_delete_texture(this._ctxHandle, handle);
291
- _checkErr(code, this._instance);
292
- // If a wrapper object was passed, mark it as deleted.
293
- if (tex && typeof tex === 'object') {
294
- try { tex._handle = 0; tex._deleted = true; } catch (e) { /* ignore */ }
295
- }
296
- }
297
-
298
- bindTexture(target, tex) {
299
- this._assertNotDestroyed();
300
- const ex = this._instance.exports;
301
- if (!ex || typeof ex.wasm_ctx_bind_texture !== 'function') {
302
- throw new Error('wasm_ctx_bind_texture not found');
303
- }
304
- const handle = tex && typeof tex === 'object' && typeof tex._handle === 'number' ? tex._handle : (tex >>> 0);
305
- const code = ex.wasm_ctx_bind_texture(this._ctxHandle, target >>> 0, handle);
306
- _checkErr(code, this._instance);
307
- // Record bound texture in JS so we can map units to texture data for texel fetch
308
- this._boundTexture = handle;
309
- this._textureUnits = this._textureUnits || [];
310
- const unit = this._activeTextureUnit || 0;
311
- this._textureUnits[unit] = handle;
312
- }
313
-
314
- texImage2D(target, level, internalFormat, width, height, border, format, type_, pixels) {
315
- this._assertNotDestroyed();
316
- const ex = this._instance.exports;
317
- if (!ex || typeof ex.wasm_ctx_tex_image_2d !== 'function') {
318
- throw new Error('wasm_ctx_tex_image_2d not found');
319
- }
320
-
321
- let data = pixels;
322
- if (!data) {
323
- data = new Uint8Array(width * height * 4);
324
- } else if (ArrayBuffer.isView(data)) {
325
- data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
326
- } else if (data instanceof ArrayBuffer) {
327
- data = new Uint8Array(data);
328
- }
329
-
330
- const len = data.length;
331
- const ptr = ex.wasm_alloc(len);
332
- if (ptr === 0) throw new Error('Failed to allocate memory for pixel data');
333
-
334
- try {
335
- const mem = new Uint8Array(ex.memory.buffer);
336
- mem.set(data, ptr);
337
-
338
- const code = ex.wasm_ctx_tex_image_2d(
339
- this._ctxHandle,
340
- target >>> 0,
341
- level >>> 0,
342
- internalFormat >>> 0,
343
- width >>> 0,
344
- height >>> 0,
345
- border >>> 0,
346
- format >>> 0,
347
- type_ >>> 0,
348
- ptr >>> 0,
349
- len >>> 0
350
- );
351
- _checkErr(code, this._instance);
352
-
353
- // Mirror texture data in JS for fast texel fetches by shader imports
354
- this._textureData = this._textureData || new Map();
355
- const handle = this._boundTexture || 0;
356
- const copy = new Uint8Array(mem.slice(ptr, ptr + len));
357
- this._textureData.set(handle, { width: width >>> 0, height: height >>> 0, data: copy });
358
- } finally {
359
- ex.wasm_free(ptr);
360
- }
361
- }
362
-
363
- texImage3D(target, level, internalFormat, width, height, depth, border, format, type_, pixels) {
364
- this._assertNotDestroyed();
365
- const ex = this._instance.exports;
366
- if (!ex || typeof ex.wasm_ctx_tex_image_3d !== 'function') {
367
- throw new Error('wasm_ctx_tex_image_3d not found');
368
- }
369
-
370
- let data = pixels;
371
- if (!data) {
372
- data = new Uint8Array(width * height * depth * 4);
373
- } else if (ArrayBuffer.isView(data)) {
374
- data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
375
- } else if (data instanceof ArrayBuffer) {
376
- data = new Uint8Array(data);
377
- }
378
-
379
- const len = data.length;
380
- const ptr = ex.wasm_alloc(len);
381
- if (ptr === 0) throw new Error('Failed to allocate memory for pixel data');
382
-
383
- try {
384
- const mem = new Uint8Array(ex.memory.buffer);
385
- mem.set(data, ptr);
386
-
387
- const code = ex.wasm_ctx_tex_image_3d(
388
- this._ctxHandle,
389
- target >>> 0,
390
- level >>> 0,
391
- internalFormat >>> 0,
392
- width >>> 0,
393
- height >>> 0,
394
- depth >>> 0,
395
- border >>> 0,
396
- format >>> 0,
397
- type_ >>> 0,
398
- ptr >>> 0,
399
- len >>> 0
400
- );
401
- _checkErr(code, this._instance);
402
-
403
- // Mirror texture data in JS for fast texel fetches by shader imports
404
- this._textureData = this._textureData || new Map();
405
- const handle = this._boundTexture || 0;
406
- const copy = new Uint8Array(mem.slice(ptr, ptr + len));
407
- this._textureData.set(handle, { width: width >>> 0, height: height >>> 0, depth: depth >>> 0, data: copy });
408
- } finally {
409
- ex.wasm_free(ptr);
410
- }
411
- }
412
-
413
- copyTexImage2D(target, level, internalFormat, x, y, width, height, border) {
414
- this._assertNotDestroyed();
415
- const ex = this._instance.exports;
416
- if (!ex || typeof ex.wasm_ctx_copy_tex_image_2d !== 'function') {
417
- throw new Error('wasm_ctx_copy_tex_image_2d not found');
418
- }
419
- const code = ex.wasm_ctx_copy_tex_image_2d(
420
- this._ctxHandle,
421
- target >>> 0,
422
- level >>> 0,
423
- internalFormat >>> 0,
424
- x | 0,
425
- y | 0,
426
- width >>> 0,
427
- height >>> 0,
428
- border >>> 0
429
- );
430
- _checkErr(code, this._instance);
431
- }
432
-
433
- createFramebuffer() {
434
- this._assertNotDestroyed();
435
- const ex = this._instance.exports;
436
- if (!ex || typeof ex.wasm_ctx_create_framebuffer !== 'function') {
437
- throw new Error('wasm_ctx_create_framebuffer not found');
438
- }
439
- const handle = ex.wasm_ctx_create_framebuffer(this._ctxHandle);
440
- if (handle === 0) {
441
- const msg = readErrorMessage(this._instance);
442
- throw new Error(`Failed to create framebuffer: ${msg}`);
443
- }
444
- return handle;
445
- }
446
-
447
- deleteFramebuffer(fb) {
448
- this._assertNotDestroyed();
449
- const ex = this._instance.exports;
450
- if (!ex || typeof ex.wasm_ctx_delete_framebuffer !== 'function') {
451
- throw new Error('wasm_ctx_delete_framebuffer not found');
452
- }
453
- const code = ex.wasm_ctx_delete_framebuffer(this._ctxHandle, fb);
454
- _checkErr(code, this._instance);
455
- }
456
-
457
- bindFramebuffer(target, fb) {
458
- this._assertNotDestroyed();
459
- const ex = this._instance.exports;
460
- if (!ex || typeof ex.wasm_ctx_bind_framebuffer !== 'function') {
461
- throw new Error('wasm_ctx_bind_framebuffer not found');
462
- }
463
- const code = ex.wasm_ctx_bind_framebuffer(this._ctxHandle, target >>> 0, fb >>> 0);
464
- _checkErr(code, this._instance);
465
- }
466
-
467
- framebufferTexture2D(target, attachment, textarget, texture, level) {
468
- this._assertNotDestroyed();
469
- const ex = this._instance.exports;
470
- if (!ex || typeof ex.wasm_ctx_framebuffer_texture2d !== 'function') {
471
- throw new Error('wasm_ctx_framebuffer_texture2d not found');
472
- }
473
- const texHandle = texture && typeof texture === 'object' && typeof texture._handle === 'number' ? texture._handle : (texture >>> 0);
474
- const code = ex.wasm_ctx_framebuffer_texture2d(
475
- this._ctxHandle,
476
- target >>> 0,
477
- attachment >>> 0,
478
- textarget >>> 0,
479
- texHandle,
480
- level >>> 0
481
- );
482
- _checkErr(code, this._instance);
483
- }
484
-
485
- createRenderbuffer() {
486
- this._assertNotDestroyed();
487
- const ex = this._instance.exports;
488
- if (!ex || typeof ex.wasm_ctx_create_renderbuffer !== 'function') {
489
- throw new Error('wasm_ctx_create_renderbuffer not found');
490
- }
491
- const handle = ex.wasm_ctx_create_renderbuffer(this._ctxHandle);
492
- if (handle === 0) {
493
- const msg = readErrorMessage(this._instance);
494
- throw new Error(`Failed to create renderbuffer: ${msg}`);
495
- }
496
- return new WasmWebGLRenderbuffer(this, handle);
497
- }
498
-
499
- bindRenderbuffer(target, renderbuffer) {
500
- this._assertNotDestroyed();
501
- const ex = this._instance.exports;
502
- if (!ex || typeof ex.wasm_ctx_bind_renderbuffer !== 'function') {
503
- throw new Error('wasm_ctx_bind_renderbuffer not found');
504
- }
505
- const rbHandle = renderbuffer && typeof renderbuffer === 'object' && typeof renderbuffer._handle === 'number' ? renderbuffer._handle : (renderbuffer >>> 0);
506
- const code = ex.wasm_ctx_bind_renderbuffer(this._ctxHandle, target >>> 0, rbHandle);
507
- _checkErr(code, this._instance);
508
- }
509
-
510
- deleteRenderbuffer(renderbuffer) {
511
- this._assertNotDestroyed();
512
- const ex = this._instance.exports;
513
- if (!ex || typeof ex.wasm_ctx_delete_renderbuffer !== 'function') {
514
- throw new Error('wasm_ctx_delete_renderbuffer not found');
515
- }
516
- const rbHandle = renderbuffer && typeof renderbuffer === 'object' && typeof renderbuffer._handle === 'number' ? renderbuffer._handle : (renderbuffer >>> 0);
517
- const code = ex.wasm_ctx_delete_renderbuffer(this._ctxHandle, rbHandle);
518
- _checkErr(code, this._instance);
519
- }
520
-
521
- isRenderbuffer(rb) {
522
- this._assertNotDestroyed();
523
- if (!rb || typeof rb !== 'object' || !(rb instanceof WasmWebGLRenderbuffer)) return false;
524
- if (rb._ctx !== this) return false;
525
- const ex = this._instance.exports;
526
- return ex.wasm_ctx_is_renderbuffer(this._ctxHandle, rb._handle) !== 0;
527
- }
528
-
529
- renderbufferStorage(target, internalFormat, width, height) {
530
- this._assertNotDestroyed();
531
- const ex = this._instance.exports;
532
- if (!ex || typeof ex.wasm_ctx_renderbuffer_storage !== 'function') {
533
- throw new Error('wasm_ctx_renderbuffer_storage not found');
534
- }
535
- const code = ex.wasm_ctx_renderbuffer_storage(this._ctxHandle, target >>> 0, internalFormat >>> 0, width | 0, height | 0);
536
- _checkErr(code, this._instance);
537
- }
538
-
539
- framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) {
540
- this._assertNotDestroyed();
541
- const ex = this._instance.exports;
542
- if (!ex || typeof ex.wasm_ctx_framebuffer_renderbuffer !== 'function') {
543
- throw new Error('wasm_ctx_framebuffer_renderbuffer not found');
544
- }
545
- const rbHandle = renderbuffer && typeof renderbuffer === 'object' && typeof renderbuffer._handle === 'number' ? renderbuffer._handle : (renderbuffer >>> 0);
546
- const code = ex.wasm_ctx_framebuffer_renderbuffer(
547
- this._ctxHandle,
548
- target >>> 0,
549
- attachment >>> 0,
550
- renderbuffertarget >>> 0,
551
- rbHandle
552
- );
553
- _checkErr(code, this._instance);
554
- }
555
-
556
- readPixels(x, y, width, height, format, type_, out) {
557
- this._assertNotDestroyed();
558
- const ex = this._instance.exports;
559
- if (!ex || typeof ex.wasm_ctx_read_pixels !== 'function') {
560
- throw new Error('wasm_ctx_read_pixels not found');
561
- }
562
-
563
- let bpp = 4;
564
- if (type_ === 0x1406) { // GL_FLOAT
565
- if (format === 0x1908) bpp = 16; // GL_RGBA
566
- else if (format === 0x8227) bpp = 8; // GL_RG
567
- else if (format === 0x1903) bpp = 4; // GL_RED
568
- } else if (type_ === 0x1401) { // GL_UNSIGNED_BYTE
569
- if (format === 0x1908) bpp = 4;
570
- }
571
-
572
- const len = width * height * bpp;
573
- if (!out || out.byteLength < len) {
574
- throw new Error(`output buffer too small (need ${len} bytes, have ${out ? out.byteLength : 0})`);
575
- }
576
-
577
- const ptr = ex.wasm_alloc(len);
578
- if (ptr === 0) throw new Error('Failed to allocate memory for readPixels output');
579
-
580
- try {
581
- const code = ex.wasm_ctx_read_pixels(
582
- this._ctxHandle,
583
- x | 0,
584
- y | 0,
585
- width >>> 0,
586
- height >>> 0,
587
- format >>> 0,
588
- type_ >>> 0,
589
- ptr >>> 0,
590
- len >>> 0
591
- );
592
- _checkErr(code, this._instance);
593
-
594
- const mem = new Uint8Array(ex.memory.buffer);
595
- const src = mem.subarray(ptr, ptr + len);
596
- const out_bytes = new Uint8Array(out.buffer, out.byteOffset, len);
597
- out_bytes.set(src);
598
- } finally {
599
- ex.wasm_free(ptr);
600
- }
601
- }
602
-
603
- // --- Stubs for unimplemented WebGL2 methods (forwarding API surface) ---
604
- // These are intentionally not implemented in the prototype. They allow
605
- // callers to detect missing functionality early with a uniform error.
606
-
607
- createShader(type) {
608
- this._assertNotDestroyed();
609
- const ex = this._instance.exports;
610
- if (!ex || typeof ex.wasm_ctx_create_shader !== 'function') {
611
- throw new Error('wasm_ctx_create_shader not found');
612
- }
613
- const handle = ex.wasm_ctx_create_shader(this._ctxHandle, type >>> 0);
614
- if (handle === 0) {
615
- const msg = readErrorMessage(this._instance);
616
- throw new Error(`Failed to create shader: ${msg}`);
617
- }
618
- return new WasmWebGLShader(this, handle);
619
- }
620
-
621
- shaderSource(shader, source) {
622
- this._assertNotDestroyed();
623
- const ex = this._instance.exports;
624
- if (!ex || typeof ex.wasm_ctx_shader_source !== 'function') {
625
- throw new Error('wasm_ctx_shader_source not found');
626
- }
627
-
628
- const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
629
- const sourceStr = String(source);
630
- const bytes = new TextEncoder().encode(sourceStr);
631
- const len = bytes.length;
632
- const ptr = ex.wasm_alloc(len);
633
- if (ptr === 0) throw new Error('Failed to allocate memory for shaderSource');
634
-
635
- try {
636
- const mem = new Uint8Array(ex.memory.buffer);
637
- mem.set(bytes, ptr);
638
- const code = ex.wasm_ctx_shader_source(this._ctxHandle, shaderHandle, ptr, len);
639
- _checkErr(code, this._instance);
640
- } finally {
641
- ex.wasm_free(ptr);
642
- }
643
- }
644
-
645
- compileShader(shader) {
646
- this._assertNotDestroyed();
647
- const ex = this._instance.exports;
648
- if (!ex || typeof ex.wasm_ctx_compile_shader !== 'function') {
649
- throw new Error('wasm_ctx_compile_shader not found');
650
- }
651
- const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
652
- const code = ex.wasm_ctx_compile_shader(this._ctxHandle, shaderHandle);
653
- _checkErr(code, this._instance);
654
- }
655
-
656
- deleteShader(shader) {
657
- this._assertNotDestroyed();
658
- const ex = this._instance.exports;
659
- if (!ex || typeof ex.wasm_ctx_delete_shader !== 'function') {
660
- throw new Error('wasm_ctx_delete_shader not found');
661
- }
662
- const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
663
- const code = ex.wasm_ctx_delete_shader(this._ctxHandle, shaderHandle);
664
- _checkErr(code, this._instance);
665
- if (shader && typeof shader === 'object') {
666
- try { shader._handle = 0; shader._deleted = true; } catch (e) { /* ignore */ }
667
- }
668
- }
669
-
670
- createProgram() {
671
- this._assertNotDestroyed();
672
- const ex = this._instance.exports;
673
- if (!ex || typeof ex.wasm_ctx_create_program !== 'function') {
674
- throw new Error('wasm_ctx_create_program not found');
675
- }
676
- const handle = ex.wasm_ctx_create_program(this._ctxHandle);
677
- if (handle === 0) {
678
- const msg = readErrorMessage(this._instance);
679
- throw new Error(`Failed to create program: ${msg}`);
680
- }
681
- return new WasmWebGLProgram(this, handle);
682
- }
683
-
684
- attachShader(program, shader) {
685
- this._assertNotDestroyed();
686
- const ex = this._instance.exports;
687
- if (!ex || typeof ex.wasm_ctx_attach_shader !== 'function') {
688
- throw new Error('wasm_ctx_attach_shader not found');
689
- }
690
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
691
- const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
692
- const code = ex.wasm_ctx_attach_shader(this._ctxHandle, programHandle, shaderHandle);
693
- _checkErr(code, this._instance);
694
- }
695
-
696
- detachShader(program, shader) { this._assertNotDestroyed(); throw new Error('not implemented'); }
697
-
698
- getActiveUniform(program, index) {
699
- this._assertNotDestroyed();
700
- const ex = this._instance.exports;
701
- if (!ex || typeof ex.wasm_ctx_get_active_uniform !== 'function') {
702
- throw new Error('wasm_ctx_get_active_uniform not found');
703
- }
704
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
705
-
706
- // Allocate buffers: size(4) + type(4) + name(256)
707
- const sizePtr = ex.wasm_alloc(4);
708
- const typePtr = ex.wasm_alloc(4);
709
- const nameMaxLen = 256;
710
- const namePtr = ex.wasm_alloc(nameMaxLen);
711
-
712
- try {
713
- const nameLen = ex.wasm_ctx_get_active_uniform(
714
- this._ctxHandle,
715
- programHandle,
716
- index >>> 0,
717
- sizePtr,
718
- typePtr,
719
- namePtr,
720
- nameMaxLen
721
- );
722
-
723
- if (nameLen === 0) {
724
- return null;
725
- }
726
-
727
- const mem32SizeIdx = sizePtr >>> 2;
728
- const mem32TypeIdx = typePtr >>> 2;
729
-
730
- const size = new Int32Array(ex.memory.buffer)[mem32SizeIdx];
731
- const type_ = new Uint32Array(ex.memory.buffer)[mem32TypeIdx];
732
-
733
- const nameBytes = new Uint8Array(ex.memory.buffer, namePtr, nameLen);
734
- const name = new TextDecoder().decode(nameBytes);
735
-
736
- return { name, size, type: type_ };
737
-
738
- } finally {
739
- ex.wasm_free(sizePtr);
740
- ex.wasm_free(typePtr);
741
- ex.wasm_free(namePtr);
742
- }
743
- }
744
-
745
- getActiveAttrib(program, index) {
746
- this._assertNotDestroyed();
747
- const ex = this._instance.exports;
748
- if (!ex || typeof ex.wasm_ctx_get_active_attrib !== 'function') {
749
- throw new Error('wasm_ctx_get_active_attrib not found');
750
- }
751
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
752
-
753
- // Allocate buffers: size(4) + type(4) + name(256)
754
- const sizePtr = ex.wasm_alloc(4);
755
- const typePtr = ex.wasm_alloc(4);
756
- const nameMaxLen = 256;
757
- const namePtr = ex.wasm_alloc(nameMaxLen);
758
-
759
- try {
760
- const nameLen = ex.wasm_ctx_get_active_attrib(
761
- this._ctxHandle,
762
- programHandle,
763
- index >>> 0,
764
- sizePtr,
765
- typePtr,
766
- namePtr,
767
- nameMaxLen
768
- );
769
-
770
- if (nameLen === 0) {
771
- return null;
772
- }
773
-
774
- const mem32SizeIdx = sizePtr >>> 2;
775
- const mem32TypeIdx = typePtr >>> 2;
776
-
777
- const size = new Int32Array(ex.memory.buffer)[mem32SizeIdx];
778
- const type_ = new Uint32Array(ex.memory.buffer)[mem32TypeIdx];
779
-
780
- const nameBytes = new Uint8Array(ex.memory.buffer, namePtr, nameLen);
781
- const name = new TextDecoder().decode(nameBytes);
782
-
783
- return { name, size, type: type_ };
784
-
785
- } finally {
786
- ex.wasm_free(sizePtr);
787
- ex.wasm_free(typePtr);
788
- ex.wasm_free(namePtr);
789
- }
790
- }
791
-
792
- linkProgram(program) {
793
- this._assertNotDestroyed();
794
- const ex = this._instance.exports;
795
- if (!ex || typeof ex.wasm_ctx_link_program !== 'function') {
796
- throw new Error('wasm_ctx_link_program not found');
797
- }
798
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
799
- const code = ex.wasm_ctx_link_program(this._ctxHandle, programHandle);
800
- _checkErr(code, this._instance);
801
-
802
- // After linking, we need to instantiate the WASM modules on the host.
803
- if (program && typeof program === 'object') {
804
- const linkStatus = this.getProgramParameter(program, this.LINK_STATUS);
805
- if (linkStatus) {
806
- this._instantiateProgramShaders(program);
807
- }
808
- }
809
- }
810
-
811
- _instantiateProgramShaders(program) {
812
- const vsWasm = this.getProgramWasm(program, this.VERTEX_SHADER);
813
- const fsWasm = this.getProgramWasm(program, this.FRAGMENT_SHADER);
814
-
815
- if (!vsWasm || !fsWasm) {
816
- return;
817
- }
818
-
819
- // Allocate table slots for both shaders
820
- const vsIdx = this._tableAllocator ? this._tableAllocator.allocate() : null;
821
- const fsIdx = this._tableAllocator ? this._tableAllocator.allocate() : null;
822
-
823
- const createDebugEnv = (type, instanceRef) => {
824
- if (!this._debugShaders) return {};
825
-
826
- const stubCode = this.getProgramDebugStub(program, type);
827
- if (!stubCode) return {};
828
-
829
- // // Add sourceURL for debugging
830
- // const debugName = `shader_stub_program_${program._handle}_${type === this.VERTEX_SHADER ? 'vs' : 'fs'}.js`;
831
- // const codeWithUrl = stubCode + `\n//# sourceURL=${debugName}`;
832
-
833
- let stubFuncs;
834
- try {
835
- // Eval the stub array
836
- stubFuncs = (0, eval)(stubCode);
837
- } catch (e) {
838
- console.error("Failed to eval debug stub:", e);
839
- return {};
840
- }
841
-
842
- return {
843
- debug_step: (line, funcIdx, resultPtr) => {
844
- if (line === 999999) {
845
- return;
846
- }
847
- const func = stubFuncs[line - 1];
848
- if (func) {
849
- const ctx = {
850
- go: () => {
851
- // Trampoline logic would go here
852
- // For now we rely on WASM calling the function after debug_step returns
853
- }
854
- };
855
- try {
856
- func.call(ctx);
857
- } catch (e) {
858
- console.error("Error in debug stub:", e);
859
- }
860
- }
861
- }
862
- };
863
- };
864
-
865
- let vsModule;
866
- vsModule = new WebAssembly.Module(vsWasm);
867
- const vsInstanceRef = { current: null };
868
- const vsDebugEnv = createDebugEnv(this.VERTEX_SHADER, vsInstanceRef);
869
-
870
- const env = {
871
- memory: this._instance.exports.memory,
872
- __indirect_function_table: this._sharedTable,
873
- ...vsDebugEnv
874
- };
875
-
876
- // Add math builtins from renderer (skipping host)
877
- const mathFuncs = [
878
- 'gl_sin', 'gl_cos', 'gl_tan', 'gl_asin', 'gl_acos', 'gl_atan', 'gl_atan2',
879
- 'gl_exp', 'gl_exp2', 'gl_log', 'gl_log2', 'gl_pow',
880
- 'gl_sinh', 'gl_cosh', 'gl_tanh', 'gl_asinh', 'gl_acosh', 'gl_atanh'
881
- ];
882
- for (const name of mathFuncs) {
883
- if (this._instance.exports[name]) {
884
- env[name] = this._instance.exports[name];
885
- }
886
- }
887
-
888
- program._vsInstance = new WebAssembly.Instance(vsModule, {
889
- env
890
- });
891
- vsInstanceRef.current = program._vsInstance;
892
-
893
- // Register in table
894
- if (this._sharedTable && vsIdx !== null && program._vsInstance.exports.main) {
895
- this._sharedTable.set(vsIdx, program._vsInstance.exports.main);
896
- program._vsTableIndex = vsIdx;
897
- }
898
-
899
- let fsModule;
900
- fsModule = new WebAssembly.Module(fsWasm);
901
- const fsInstanceRef = { current: null };
902
- const fsDebugEnv = createDebugEnv(this.FRAGMENT_SHADER, fsInstanceRef);
903
-
904
- const fsEnv = {
905
- memory: this._instance.exports.memory,
906
- __indirect_function_table: this._sharedTable,
907
- ...fsDebugEnv
908
- };
909
-
910
- for (const name of mathFuncs) {
911
- if (this._instance.exports[name]) {
912
- fsEnv[name] = this._instance.exports[name];
913
- }
914
- }
915
-
916
- program._fsInstance = new WebAssembly.Instance(fsModule, {
917
- env: fsEnv
918
- });
919
- fsInstanceRef.current = program._fsInstance;
920
-
921
- // Register in table
922
- if (this._sharedTable && fsIdx !== null && program._fsInstance.exports.main) {
923
- this._sharedTable.set(fsIdx, program._fsInstance.exports.main);
924
- program._fsTableIndex = fsIdx;
925
- }
926
-
927
- // Notify Rust of table indices (requires Phase 4)
928
- if (vsIdx !== null && fsIdx !== null) {
929
- const ex = this._instance.exports;
930
- if (ex.wasm_ctx_register_shader_indices) {
931
- ex.wasm_ctx_register_shader_indices(
932
- this._ctxHandle,
933
- program._handle,
934
- vsIdx,
935
- fsIdx
936
- );
937
- }
938
- }
939
- }
940
-
941
- getProgramDebugStub(program, shaderType) {
942
- this._assertNotDestroyed();
943
- const ex = this._instance.exports;
944
- if (!ex || typeof ex.wasm_ctx_get_program_debug_stub !== 'function') {
945
- return null;
946
- }
947
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
948
- const len = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, 0, 0);
949
- if (len === 0) return null;
950
-
951
- const ptr = ex.wasm_alloc(len);
952
- if (ptr === 0) return null;
953
-
954
- try {
955
- const actualLen = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, ptr, len);
956
- const mem = new Uint8Array(ex.memory.buffer);
957
- const bytes = mem.subarray(ptr, ptr + actualLen);
958
- return new TextDecoder().decode(bytes);
959
- } finally {
960
- ex.wasm_free(ptr);
961
- }
962
- }
963
-
964
- getProgramDebugStub(program, shaderType) {
965
- this._assertNotDestroyed();
966
- const ex = this._instance.exports;
967
- if (!ex || typeof ex.wasm_ctx_get_program_debug_stub !== 'function') {
968
- return null;
969
- }
970
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
971
- const len = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, 0, 0);
972
- if (len === 0) return null;
973
-
974
- const ptr = ex.wasm_alloc(len);
975
- if (ptr === 0) return null;
976
-
977
- try {
978
- const actualLen = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, ptr, len);
979
- const mem = new Uint8Array(ex.memory.buffer);
980
- const bytes = mem.subarray(ptr, ptr + actualLen);
981
- return new TextDecoder().decode(bytes);
982
- } finally {
983
- ex.wasm_free(ptr);
984
- }
985
- }
986
-
987
- deleteProgram(program) {
988
- this._assertNotDestroyed();
989
- const ex = this._instance.exports;
990
- if (!ex || typeof ex.wasm_ctx_delete_program !== 'function') {
991
- throw new Error('wasm_ctx_delete_program not found');
992
- }
993
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
994
-
995
- // Free table indices
996
- if (program && typeof program === 'object') {
997
- if (program._vsTableIndex !== undefined && this._tableAllocator) {
998
- this._tableAllocator.free(program._vsTableIndex);
999
- }
1000
- if (program._fsTableIndex !== undefined && this._tableAllocator) {
1001
- this._tableAllocator.free(program._fsTableIndex);
1002
- }
1003
- }
1004
-
1005
- const code = ex.wasm_ctx_delete_program(this._ctxHandle, programHandle);
1006
- _checkErr(code, this._instance);
1007
- if (program && typeof program === 'object') {
1008
- try { program._handle = 0; program._deleted = true; } catch (e) { /* ignore */ }
1009
- }
1010
- }
1011
-
1012
- useProgram(program) {
1013
- this._assertNotDestroyed();
1014
- const ex = this._instance.exports;
1015
- if (!ex || typeof ex.wasm_ctx_use_program !== 'function') {
1016
- throw new Error('wasm_ctx_use_program not found');
1017
- }
1018
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1019
- const code = ex.wasm_ctx_use_program(this._ctxHandle, programHandle);
1020
- _checkErr(code, this._instance);
1021
- this._currentProgram = program;
1022
- }
1023
-
1024
- getShaderParameter(shader, pname) {
1025
- this._assertNotDestroyed();
1026
- const ex = this._instance.exports;
1027
- if (!ex || typeof ex.wasm_ctx_get_shader_parameter !== 'function') {
1028
- throw new Error('wasm_ctx_get_shader_parameter not found');
1029
- }
1030
- const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
1031
- const val = ex.wasm_ctx_get_shader_parameter(this._ctxHandle, shaderHandle, pname >>> 0);
1032
-
1033
- // WebGL returns boolean for status parameters
1034
- if (pname === 0x8B81 /* COMPILE_STATUS */ || pname === 0x8B80 /* DELETE_STATUS */) {
1035
- return !!val;
1036
- }
1037
- return val;
1038
- }
1039
-
1040
- getProgramParameter(program, pname) {
1041
- this._assertNotDestroyed();
1042
- const ex = this._instance.exports;
1043
- if (!ex || typeof ex.wasm_ctx_get_program_parameter !== 'function') {
1044
- throw new Error('wasm_ctx_get_program_parameter not found');
1045
- }
1046
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1047
- const val = ex.wasm_ctx_get_program_parameter(this._ctxHandle, programHandle, pname >>> 0);
1048
-
1049
- // WebGL returns boolean for status parameters
1050
- if (pname === 0x8B82 /* LINK_STATUS */ || pname === 0x8B80 /* DELETE_STATUS */ || pname === 0x8B83 /* VALIDATE_STATUS */) {
1051
- return !!val;
1052
- }
1053
- return val;
1054
- }
1055
-
1056
- getShaderInfoLog(shader) {
1057
- this._assertNotDestroyed();
1058
- const ex = this._instance.exports;
1059
- if (!ex || typeof ex.wasm_ctx_get_shader_info_log !== 'function') {
1060
- throw new Error('wasm_ctx_get_shader_info_log not found');
1061
- }
1062
- const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
1063
-
1064
- const maxLen = 1024;
1065
- const ptr = ex.wasm_alloc(maxLen);
1066
- if (ptr === 0) throw new Error('Failed to allocate memory for getShaderInfoLog');
1067
-
1068
- try {
1069
- const len = ex.wasm_ctx_get_shader_info_log(this._ctxHandle, shaderHandle, ptr, maxLen);
1070
- const mem = new Uint8Array(ex.memory.buffer);
1071
- const bytes = mem.subarray(ptr, ptr + len);
1072
- return new TextDecoder().decode(bytes);
1073
- } finally {
1074
- ex.wasm_free(ptr);
1075
- }
1076
- }
1077
-
1078
- getProgramInfoLog(program) {
1079
- this._assertNotDestroyed();
1080
- const ex = this._instance.exports;
1081
- if (!ex || typeof ex.wasm_ctx_get_program_info_log !== 'function') {
1082
- throw new Error('wasm_ctx_get_program_info_log not found');
1083
- }
1084
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1085
-
1086
- const maxLen = 1024;
1087
- const ptr = ex.wasm_alloc(maxLen);
1088
- if (ptr === 0) throw new Error('Failed to allocate memory for getProgramInfoLog');
1089
-
1090
- try {
1091
- const len = ex.wasm_ctx_get_program_info_log(this._ctxHandle, programHandle, ptr, maxLen);
1092
- const mem = new Uint8Array(ex.memory.buffer);
1093
- const bytes = mem.subarray(ptr, ptr + len);
1094
- return new TextDecoder().decode(bytes);
1095
- } finally {
1096
- ex.wasm_free(ptr);
1097
- }
1098
- }
1099
-
1100
- getProgramWasm(program, shaderType) {
1101
- this._assertNotDestroyed();
1102
- const ex = this._instance.exports;
1103
- if (!ex || typeof ex.wasm_ctx_get_program_wasm_len !== 'function') {
1104
- throw new Error('wasm_ctx_get_program_wasm_len not found');
1105
- }
1106
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1107
- const len = ex.wasm_ctx_get_program_wasm_len(this._ctxHandle, programHandle, shaderType);
1108
- if (len === 0) return null;
1109
-
1110
- const ptr = ex.wasm_alloc(len);
1111
- if (ptr === 0) throw new Error('Failed to allocate memory for getProgramWasm');
1112
-
1113
- try {
1114
- const actualLen = ex.wasm_ctx_get_program_wasm(this._ctxHandle, programHandle, shaderType, ptr, len);
1115
- const mem = new Uint8Array(ex.memory.buffer);
1116
- return new Uint8Array(mem.buffer, ptr, actualLen).slice();
1117
- } finally {
1118
- ex.wasm_free(ptr);
1119
- }
1120
- }
1121
-
1122
- getAttribLocation(program, name) {
1123
- this._assertNotDestroyed();
1124
- const ex = this._instance.exports;
1125
- if (!ex || typeof ex.wasm_ctx_get_attrib_location !== 'function') {
1126
- throw new Error('wasm_ctx_get_attrib_location not found');
1127
- }
1128
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1129
- const nameStr = String(name);
1130
- const bytes = new TextEncoder().encode(nameStr);
1131
- const len = bytes.length;
1132
- const ptr = ex.wasm_alloc(len);
1133
- if (ptr === 0) throw new Error('Failed to allocate memory for getAttribLocation');
1134
-
1135
- try {
1136
- const mem = new Uint8Array(ex.memory.buffer);
1137
- mem.set(bytes, ptr);
1138
- return ex.wasm_ctx_get_attrib_location(this._ctxHandle, programHandle, ptr, len);
1139
- } finally {
1140
- ex.wasm_free(ptr);
1141
- }
1142
- }
1143
-
1144
- bindAttribLocation(program, index, name) {
1145
- this._assertNotDestroyed();
1146
- const ex = this._instance.exports;
1147
- if (!ex || typeof ex.wasm_ctx_bind_attrib_location !== 'function') {
1148
- throw new Error('wasm_ctx_bind_attrib_location not found');
1149
- }
1150
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1151
- const nameStr = String(name);
1152
- const bytes = new TextEncoder().encode(nameStr);
1153
- const len = bytes.length;
1154
- const ptr = ex.wasm_alloc(len);
1155
- if (ptr === 0) throw new Error('Failed to allocate memory for bindAttribLocation');
1156
-
1157
- try {
1158
- const mem = new Uint8Array(ex.memory.buffer);
1159
- mem.set(bytes, ptr);
1160
- const code = ex.wasm_ctx_bind_attrib_location(this._ctxHandle, programHandle, index >>> 0, ptr, len);
1161
- _checkErr(code, this._instance);
1162
- } finally {
1163
- ex.wasm_free(ptr);
1164
- }
1165
- }
1166
-
1167
- enableVertexAttribArray(index) {
1168
- this._assertNotDestroyed();
1169
- const ex = this._instance.exports;
1170
- if (!ex || typeof ex.wasm_ctx_enable_vertex_attrib_array !== 'function') {
1171
- throw new Error('wasm_ctx_enable_vertex_attrib_array not found');
1172
- }
1173
- const code = ex.wasm_ctx_enable_vertex_attrib_array(this._ctxHandle, index >>> 0);
1174
- _checkErr(code, this._instance);
1175
- }
1176
-
1177
- disableVertexAttribArray(index) {
1178
- this._assertNotDestroyed();
1179
- const ex = this._instance.exports;
1180
- if (!ex || typeof ex.wasm_ctx_disable_vertex_attrib_array !== 'function') {
1181
- throw new Error('wasm_ctx_disable_vertex_attrib_array not found');
1182
- }
1183
- const code = ex.wasm_ctx_disable_vertex_attrib_array(this._ctxHandle, index >>> 0);
1184
- _checkErr(code, this._instance);
1185
- }
1186
-
1187
- vertexAttribPointer(index, size, type, normalized, stride, offset) {
1188
- this._assertNotDestroyed();
1189
- const ex = this._instance.exports;
1190
- if (!ex || typeof ex.wasm_ctx_vertex_attrib_pointer !== 'function') {
1191
- throw new Error('wasm_ctx_vertex_attrib_pointer not found');
1192
- }
1193
- const code = ex.wasm_ctx_vertex_attrib_pointer(
1194
- this._ctxHandle,
1195
- index >>> 0,
1196
- size >>> 0,
1197
- type >>> 0,
1198
- normalized ? 1 : 0,
1199
- stride >>> 0,
1200
- offset >>> 0
1201
- );
1202
- if (code === 5) return; // ERR_GL
1203
- _checkErr(code, this._instance);
1204
- }
1205
-
1206
- vertexAttribIPointer(index, size, type, stride, offset) {
1207
- this._assertNotDestroyed();
1208
- const ex = this._instance.exports;
1209
- if (!ex || typeof ex.wasm_ctx_vertex_attrib_ipointer !== 'function') {
1210
- throw new Error('wasm_ctx_vertex_attrib_ipointer not found');
1211
- }
1212
- const code = ex.wasm_ctx_vertex_attrib_ipointer(
1213
- this._ctxHandle,
1214
- index >>> 0,
1215
- size >>> 0,
1216
- type >>> 0,
1217
- stride >>> 0,
1218
- offset >>> 0
1219
- );
1220
- if (code === 5) return; // ERR_GL
1221
- _checkErr(code, this._instance);
1222
- }
1223
-
1224
- vertexAttrib1f(index, v0) {
1225
- this._assertNotDestroyed();
1226
- const ex = this._instance.exports;
1227
- if (!ex || typeof ex.wasm_ctx_vertex_attrib1f !== 'function') {
1228
- throw new Error('wasm_ctx_vertex_attrib1f not found');
1229
- }
1230
- const code = ex.wasm_ctx_vertex_attrib1f(this._ctxHandle, index >>> 0, +v0);
1231
- if (code === 5) return; // ERR_GL
1232
- _checkErr(code, this._instance);
1233
- }
1234
- vertexAttrib2f(index, v0, v1) {
1235
- this._assertNotDestroyed();
1236
- const ex = this._instance.exports;
1237
- if (!ex || typeof ex.wasm_ctx_vertex_attrib2f !== 'function') {
1238
- throw new Error('wasm_ctx_vertex_attrib2f not found');
1239
- }
1240
- const code = ex.wasm_ctx_vertex_attrib2f(this._ctxHandle, index >>> 0, +v0, +v1);
1241
- if (code === 5) return; // ERR_GL
1242
- _checkErr(code, this._instance);
1243
- }
1244
- vertexAttrib3f(index, v0, v1, v2) {
1245
- this._assertNotDestroyed();
1246
- const ex = this._instance.exports;
1247
- if (!ex || typeof ex.wasm_ctx_vertex_attrib3f !== 'function') {
1248
- throw new Error('wasm_ctx_vertex_attrib3f not found');
1249
- }
1250
- const code = ex.wasm_ctx_vertex_attrib3f(this._ctxHandle, index >>> 0, +v0, +v1, +v2);
1251
- if (code === 5) return; // ERR_GL
1252
- _checkErr(code, this._instance);
1253
- }
1254
- vertexAttrib4f(index, v0, v1, v2, v3) {
1255
- this._assertNotDestroyed();
1256
- const ex = this._instance.exports;
1257
- if (!ex || typeof ex.wasm_ctx_vertex_attrib4f !== 'function') {
1258
- throw new Error('wasm_ctx_vertex_attrib4f not found');
1259
- }
1260
- const code = ex.wasm_ctx_vertex_attrib4f(this._ctxHandle, index >>> 0, +v0, +v1, +v2, +v3);
1261
- if (code === 5) return; // ERR_GL
1262
- _checkErr(code, this._instance);
1263
- }
1264
-
1265
- vertexAttrib1fv(index, v) {
1266
- if (v && v.length >= 1) {
1267
- this.vertexAttrib1f(index, v[0]);
1268
- } else {
1269
- this._setError(0x0501);
1270
- }
1271
- }
1272
- vertexAttrib2fv(index, v) {
1273
- if (v && v.length >= 2) {
1274
- this.vertexAttrib2f(index, v[0], v[1]);
1275
- } else {
1276
- this._setError(0x0501);
1277
- }
1278
- }
1279
- vertexAttrib3fv(index, v) {
1280
- if (v && v.length >= 3) {
1281
- this.vertexAttrib3f(index, v[0], v[1], v[2]);
1282
- } else {
1283
- this._setError(0x0501);
1284
- }
1285
- }
1286
- vertexAttrib4fv(index, v) {
1287
- if (v && v.length >= 4) {
1288
- this.vertexAttrib4f(index, v[0], v[1], v[2], v[3]);
1289
- } else {
1290
- this._setError(0x0501);
1291
- }
1292
- }
1293
-
1294
- vertexAttribI4i(index, v0, v1, v2, v3) {
1295
- this._assertNotDestroyed();
1296
- const ex = this._instance.exports;
1297
- if (!ex || typeof ex.wasm_ctx_vertex_attrib_i4i !== 'function') {
1298
- throw new Error('wasm_ctx_vertex_attrib_i4i not found');
1299
- }
1300
- const code = ex.wasm_ctx_vertex_attrib_i4i(this._ctxHandle, index >>> 0, v0 | 0, v1 | 0, v2 | 0, v3 | 0);
1301
- if (code === 5) return; // ERR_GL
1302
- _checkErr(code, this._instance);
1303
- }
1304
-
1305
- vertexAttribI4ui(index, v0, v1, v2, v3) {
1306
- this._assertNotDestroyed();
1307
- const ex = this._instance.exports;
1308
- if (!ex || typeof ex.wasm_ctx_vertex_attrib_i4ui !== 'function') {
1309
- throw new Error('wasm_ctx_vertex_attrib_i4ui not found');
1310
- }
1311
- const code = ex.wasm_ctx_vertex_attrib_i4ui(this._ctxHandle, index >>> 0, v0 >>> 0, v1 >>> 0, v2 >>> 0, v3 >>> 0);
1312
- if (code === 5) return; // ERR_GL
1313
- _checkErr(code, this._instance);
1314
- }
1315
-
1316
- vertexAttribI4iv(index, v) {
1317
- if (v && v.length >= 4) {
1318
- this.vertexAttribI4i(index, v[0], v[1], v[2], v[3]);
1319
- } else {
1320
- this._setError(0x0501);
1321
- }
1322
- }
1323
-
1324
- vertexAttribI4uiv(index, v) {
1325
- if (v && v.length >= 4) {
1326
- this.vertexAttribI4ui(index, v[0], v[1], v[2], v[3]);
1327
- } else {
1328
- this._setError(0x0501);
1329
- }
1330
- }
1331
-
1332
- vertexAttribDivisor(index, divisor) {
1333
- this._assertNotDestroyed();
1334
- const ex = this._instance.exports;
1335
- if (!ex || typeof ex.wasm_ctx_vertex_attrib_divisor !== 'function') {
1336
- throw new Error('wasm_ctx_vertex_attrib_divisor not found');
1337
- }
1338
- const code = ex.wasm_ctx_vertex_attrib_divisor(this._ctxHandle, index >>> 0, divisor >>> 0);
1339
- _checkErr(code, this._instance);
1340
- }
1341
-
1342
- createBuffer() {
1343
- this._assertNotDestroyed();
1344
- const ex = this._instance.exports;
1345
- if (!ex || typeof ex.wasm_ctx_create_buffer !== 'function') {
1346
- throw new Error('wasm_ctx_create_buffer not found');
1347
- }
1348
- const handle = ex.wasm_ctx_create_buffer(this._ctxHandle);
1349
- if (handle === 0) {
1350
- const msg = readErrorMessage(this._instance);
1351
- throw new Error(`Failed to create buffer: ${msg}`);
1352
- }
1353
- return new WasmWebGLBuffer(this, handle);
1354
- }
1355
-
1356
- bindBuffer(target, buffer) {
1357
- this._assertNotDestroyed();
1358
- const ex = this._instance.exports;
1359
- if (!ex || typeof ex.wasm_ctx_bind_buffer !== 'function') {
1360
- throw new Error('wasm_ctx_bind_buffer not found');
1361
- }
1362
- const handle = buffer && typeof buffer === 'object' && typeof buffer._handle === 'number' ? buffer._handle : (buffer >>> 0);
1363
- const code = ex.wasm_ctx_bind_buffer(this._ctxHandle, target >>> 0, handle);
1364
- _checkErr(code, this._instance);
1365
- }
1366
-
1367
- deleteBuffer(buffer) {
1368
- this._assertNotDestroyed();
1369
- const ex = this._instance.exports;
1370
- if (!ex || typeof ex.wasm_ctx_delete_buffer !== 'function') {
1371
- throw new Error('wasm_ctx_delete_buffer not found');
1372
- }
1373
- const handle = buffer && typeof buffer === 'object' && typeof buffer._handle === 'number' ? buffer._handle : (buffer >>> 0);
1374
- const code = ex.wasm_ctx_delete_buffer(this._ctxHandle, handle);
1375
- _checkErr(code, this._instance); if (buffer && typeof buffer === 'object') {
1376
- try { buffer._handle = 0; buffer._deleted = true; } catch (e) { /* ignore */ }
1377
- }
1378
- }
1379
-
1380
- bufferData(target, data, usage) {
1381
- this._assertNotDestroyed();
1382
- const ex = this._instance.exports;
1383
- if (!ex || typeof ex.wasm_ctx_buffer_data !== 'function') {
1384
- throw new Error('wasm_ctx_buffer_data not found');
1385
- }
1386
-
1387
- let bytes;
1388
- if (data instanceof ArrayBuffer) {
1389
- bytes = new Uint8Array(data);
1390
- } else if (ArrayBuffer.isView(data)) {
1391
- bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1392
- } else if (typeof data === 'number') {
1393
- bytes = new Uint8Array(data);
1394
- } else {
1395
- throw new Error('Invalid data type for bufferData');
1396
- }
1397
-
1398
- const len = bytes.length;
1399
- if (len === 0) {
1400
- const code = ex.wasm_ctx_buffer_data(this._ctxHandle, target >>> 0, 0, 0, usage >>> 0);
1401
- _checkErr(code, this._instance);
1402
- return;
1403
- }
1404
-
1405
- const ptr = ex.wasm_alloc(len);
1406
- if (ptr === 0) throw new Error('Failed to allocate memory for bufferData');
1407
-
1408
- try {
1409
- const mem = new Uint8Array(ex.memory.buffer);
1410
- mem.set(bytes, ptr);
1411
- const code = ex.wasm_ctx_buffer_data(this._ctxHandle, target >>> 0, ptr, len, usage >>> 0);
1412
- _checkErr(code, this._instance);
1413
- } finally {
1414
- ex.wasm_free(ptr);
1415
- }
1416
- }
1417
-
1418
- bufferSubData(target, offset, data) {
1419
- this._assertNotDestroyed();
1420
- const ex = this._instance.exports;
1421
- if (!ex || typeof ex.wasm_ctx_buffer_sub_data !== 'function') {
1422
- throw new Error('wasm_ctx_buffer_sub_data not found');
1423
- }
1424
-
1425
- let bytes;
1426
- if (data instanceof Uint8Array) bytes = data;
1427
- else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1428
- else if (data instanceof ArrayBuffer) bytes = new Uint8Array(data);
1429
- else bytes = new Uint8Array(data); // Fallback for arrays
1430
-
1431
- const len = bytes.length;
1432
- const ptr = ex.wasm_alloc(len);
1433
- if (ptr === 0) throw new Error('Failed to allocate memory for bufferSubData');
1434
-
1435
- try {
1436
- const mem = new Uint8Array(ex.memory.buffer);
1437
- mem.set(bytes, ptr);
1438
- const code = ex.wasm_ctx_buffer_sub_data(this._ctxHandle, target >>> 0, offset >>> 0, ptr, len);
1439
- _checkErr(code, this._instance);
1440
- } finally {
1441
- ex.wasm_free(ptr);
1442
- }
1443
- }
1444
- copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) {
1445
- this._assertNotDestroyed();
1446
- const ex = this._instance.exports;
1447
- if (!ex || typeof ex.wasm_ctx_copy_buffer_sub_data !== 'function') {
1448
- throw new Error('wasm_ctx_copy_buffer_sub_data not found');
1449
- }
1450
- const code = ex.wasm_ctx_copy_buffer_sub_data(
1451
- this._ctxHandle,
1452
- readTarget >>> 0,
1453
- writeTarget >>> 0,
1454
- readOffset >>> 0,
1455
- writeOffset >>> 0,
1456
- size >>> 0
1457
- );
1458
- _checkErr(code, this._instance);
1459
- }
1460
- getBufferParameter(target, pname) {
1461
- this._assertNotDestroyed();
1462
- const ex = this._instance.exports;
1463
- if (!ex || typeof ex.wasm_ctx_get_buffer_parameter !== 'function') {
1464
- throw new Error('wasm_ctx_get_buffer_parameter not found');
1465
- }
1466
- const val = ex.wasm_ctx_get_buffer_parameter(this._ctxHandle, target >>> 0, pname >>> 0);
1467
- if (val < 0) {
1468
- const msg = readErrorMessage(this._instance);
1469
- throw new Error(`getBufferParameter failed: ${msg}`);
1470
- }
1471
- return val;
1472
- }
1473
- isBuffer(buffer) {
1474
- this._assertNotDestroyed();
1475
- if (!buffer || typeof buffer !== 'object' || !(buffer instanceof WasmWebGLBuffer)) return false;
1476
- if (buffer._ctx !== this) return false;
1477
- const ex = this._instance.exports;
1478
- return ex.wasm_ctx_is_buffer(this._ctxHandle, buffer._handle) !== 0;
1479
- }
1480
-
1481
- drawArrays(mode, first, count) {
1482
- this._assertNotDestroyed();
1483
- const ex = this._instance.exports;
1484
- if (!ex || typeof ex.wasm_ctx_draw_arrays !== 'function') {
1485
- throw new Error('wasm_ctx_draw_arrays not found');
1486
- }
1487
- const code = ex.wasm_ctx_draw_arrays(this._ctxHandle, mode >>> 0, first >>> 0, count >>> 0);
1488
- _checkErr(code, this._instance);
1489
- }
1490
-
1491
- drawElements(mode, count, type, offset) {
1492
- this._assertNotDestroyed();
1493
- const ex = this._instance.exports;
1494
- if (!ex || typeof ex.wasm_ctx_draw_elements !== 'function') {
1495
- throw new Error('wasm_ctx_draw_elements not found');
1496
- }
1497
- const code = ex.wasm_ctx_draw_elements(this._ctxHandle, mode >>> 0, count >>> 0, type >>> 0, offset >>> 0);
1498
- _checkErr(code, this._instance);
1499
- }
1500
- drawArraysInstanced(mode, first, count, instanceCount) {
1501
- this._assertNotDestroyed();
1502
- const ex = this._instance.exports;
1503
- if (!ex || typeof ex.wasm_ctx_draw_arrays_instanced !== 'function') {
1504
- throw new Error('wasm_ctx_draw_arrays_instanced not found');
1505
- }
1506
- const code = ex.wasm_ctx_draw_arrays_instanced(this._ctxHandle, mode >>> 0, first | 0, count | 0, instanceCount | 0);
1507
- _checkErr(code, this._instance);
1508
- }
1509
- drawElementsInstanced(mode, count, type, offset, instanceCount) {
1510
- this._assertNotDestroyed();
1511
- const ex = this._instance.exports;
1512
- if (!ex || typeof ex.wasm_ctx_draw_elements_instanced !== 'function') {
1513
- throw new Error('wasm_ctx_draw_elements_instanced not found');
1514
- }
1515
- const code = ex.wasm_ctx_draw_elements_instanced(this._ctxHandle, mode >>> 0, count | 0, type >>> 0, offset >>> 0, instanceCount | 0);
1516
- _checkErr(code, this._instance);
1517
- }
1518
- drawRangeElements(mode, start, end, count, type, offset) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1519
- drawBuffers(buffers) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1520
-
1521
- createVertexArray() {
1522
- this._assertNotDestroyed();
1523
- const ex = this._instance.exports;
1524
- if (!ex || typeof ex.wasm_ctx_create_vertex_array !== 'function') {
1525
- throw new Error('wasm_ctx_create_vertex_array not found');
1526
- }
1527
- const handle = ex.wasm_ctx_create_vertex_array(this._ctxHandle);
1528
- if (handle === 0) return null;
1529
- return { _handle: handle, _type: 'WebGLVertexArrayObject' };
1530
- }
1531
-
1532
- bindVertexArray(vao) {
1533
- this._assertNotDestroyed();
1534
- const ex = this._instance.exports;
1535
- if (!ex || typeof ex.wasm_ctx_bind_vertex_array !== 'function') {
1536
- throw new Error('wasm_ctx_bind_vertex_array not found');
1537
- }
1538
- const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao ? (vao >>> 0) : 0);
1539
- const code = ex.wasm_ctx_bind_vertex_array(this._ctxHandle, handle);
1540
- _checkErr(code, this._instance);
1541
- }
1542
-
1543
- deleteVertexArray(vao) {
1544
- this._assertNotDestroyed();
1545
- const ex = this._instance.exports;
1546
- if (!ex || typeof ex.wasm_ctx_delete_vertex_array !== 'function') {
1547
- throw new Error('wasm_ctx_delete_vertex_array not found');
1548
- }
1549
- const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
1550
- const code = ex.wasm_ctx_delete_vertex_array(this._ctxHandle, handle);
1551
- _checkErr(code, this._instance);
1552
- if (vao && typeof vao === 'object') {
1553
- try { vao._handle = 0; vao._deleted = true; } catch (e) { /* ignore */ }
1554
- }
1555
- }
1556
-
1557
- isVertexArray(vao) {
1558
- this._assertNotDestroyed();
1559
- const ex = this._instance.exports;
1560
- if (!ex || typeof ex.wasm_ctx_is_vertex_array !== 'function') {
1561
- throw new Error('wasm_ctx_is_vertex_array not found');
1562
- }
1563
- const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
1564
- const res = ex.wasm_ctx_is_vertex_array(this._ctxHandle, handle);
1565
- return res !== 0;
1566
- }
1567
-
1568
- createTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1569
- bindTransformFeedback(target, tf) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1570
- beginTransformFeedback(primitiveMode) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1571
- pauseTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1572
- resumeTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1573
- endTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1574
- transformFeedbackVaryings(program, varyings, bufferMode) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1575
- getTransformFeedbackVarying(program, index) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1576
-
1577
- createQuery() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1578
- deleteQuery(q) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1579
- beginQuery(target, id) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1580
- endQuery(target) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1581
- getQueryParameter(query, pname) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1582
-
1583
- fenceSync(condition, flags) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1584
- clientWaitSync(sync, flags, timeout) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1585
- waitSync(sync, flags, timeout) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1586
- deleteSync(sync) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1587
- getSyncParameter(sync, pname) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1588
-
1589
- createSampler() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1590
- deleteSampler(s) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1591
- bindSampler(unit, sampler) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1592
- samplerParameteri(sampler, pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1593
- samplerParameterf(sampler, pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1594
-
1595
- activeTexture(texture) {
1596
- this._assertNotDestroyed();
1597
- const ex = this._instance.exports;
1598
- if (!ex || typeof ex.wasm_ctx_active_texture !== 'function') {
1599
- throw new Error('wasm_ctx_active_texture not found');
1600
- }
1601
- const code = ex.wasm_ctx_active_texture(this._ctxHandle, texture >>> 0);
1602
- _checkErr(code, this._instance);
1603
- // Track active texture unit in JS wrapper (GL_TEXTURE0 = 0x84C0)
1604
- this._activeTextureUnit = (texture >>> 0) - 0x84C0;
1605
- this._textureUnits = this._textureUnits || [];
1606
- }
1607
- texParameteri(target, pname, param) {
1608
- this._assertNotDestroyed();
1609
- const ex = this._instance.exports;
1610
- if (!ex || typeof ex.wasm_ctx_tex_parameter_i !== 'function') {
1611
- throw new Error('wasm_ctx_tex_parameter_i not found');
1612
- }
1613
- const code = ex.wasm_ctx_tex_parameter_i(this._ctxHandle, target >>> 0, pname >>> 0, param | 0);
1614
- _checkErr(code, this._instance);
1615
- }
1616
- generateMipmap(target) {
1617
- this._assertNotDestroyed();
1618
- const ex = this._instance.exports;
1619
- if (!ex || typeof ex.wasm_ctx_generate_mipmap !== 'function') {
1620
- throw new Error('wasm_ctx_generate_mipmap not found');
1621
- }
1622
- const code = ex.wasm_ctx_generate_mipmap(this._ctxHandle, target >>> 0);
1623
- _checkErr(code, this._instance);
1624
- }
1625
-
1626
- copyTexImage2D(target, level, internalformat, x, y, width, height, border) {
1627
- this._assertNotDestroyed();
1628
- const ex = this._instance.exports;
1629
- if (!ex || typeof ex.wasm_ctx_copy_tex_image_2d !== 'function') {
1630
- throw new Error('wasm_ctx_copy_tex_image_2d not found');
1631
- }
1632
- const code = ex.wasm_ctx_copy_tex_image_2d(
1633
- this._ctxHandle,
1634
- target >>> 0,
1635
- level | 0,
1636
- internalformat >>> 0,
1637
- x | 0,
1638
- y | 0,
1639
- width | 0,
1640
- height | 0,
1641
- border | 0
1642
- );
1643
- _checkErr(code, this._instance);
1644
- }
1645
- copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1646
- texSubImage2D(target, level, xoffset, yoffset, width, height, format, type_, pixels) {
1647
- this._assertNotDestroyed();
1648
- const ex = this._instance.exports;
1649
- if (!ex || typeof ex.wasm_ctx_tex_sub_image_2d !== 'function') {
1650
- throw new Error('wasm_ctx_tex_sub_image_2d not found');
1651
- }
1652
-
1653
- let data = pixels;
1654
- if (!data) return; // No-op if no data provided
1655
- if (!(data instanceof Uint8Array)) {
1656
- if (ArrayBuffer.isView(data)) {
1657
- data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1658
- } else {
1659
- data = new Uint8Array(data);
1660
- }
1661
- }
1662
-
1663
- const len = data.length;
1664
- const ptr = ex.wasm_alloc(len);
1665
- if (ptr === 0) throw new Error('Failed to allocate memory for sub-pixel data');
1666
-
1667
- try {
1668
- const mem = new Uint8Array(ex.memory.buffer);
1669
- mem.set(data, ptr);
1670
-
1671
- const code = ex.wasm_ctx_tex_sub_image_2d(
1672
- this._ctxHandle,
1673
- target >>> 0,
1674
- level >>> 0,
1675
- xoffset | 0,
1676
- yoffset | 0,
1677
- width >>> 0,
1678
- height >>> 0,
1679
- format >>> 0,
1680
- type_ >>> 0,
1681
- ptr >>> 0,
1682
- len >>> 0
1683
- );
1684
- _checkErr(code, this._instance);
1685
- } finally {
1686
- ex.wasm_free(ptr);
1687
- }
1688
- }
1689
-
1690
- checkFramebufferStatus(target) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1691
- blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) {
1692
- this._assertNotDestroyed();
1693
- const ex = this._instance.exports;
1694
- if (!ex || typeof ex.wasm_ctx_blit_framebuffer !== 'function') {
1695
- throw new Error('wasm_ctx_blit_framebuffer not found');
1696
- }
1697
- const code = ex.wasm_ctx_blit_framebuffer(
1698
- this._ctxHandle,
1699
- srcX0 | 0, srcY0 | 0, srcX1 | 0, srcY1 | 0,
1700
- dstX0 | 0, dstY0 | 0, dstX1 | 0, dstY1 | 0,
1701
- mask >>> 0, filter >>> 0
1702
- );
1703
- _checkErr(code, this._instance);
1704
- }
1705
- readBuffer(src) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1706
-
1707
- pixelStorei(pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1708
- getExtension(name) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1709
- getSupportedExtensions() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1710
-
1711
- getUniformLocation(program, name) {
1712
- this._assertNotDestroyed();
1713
- const ex = this._instance.exports;
1714
- if (!ex || typeof ex.wasm_ctx_get_uniform_location !== 'function') {
1715
- throw new Error('wasm_ctx_get_uniform_location not found');
1716
- }
1717
- const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1718
- const nameStr = String(name);
1719
- const bytes = new TextEncoder().encode(nameStr);
1720
- const len = bytes.length;
1721
- const ptr = ex.wasm_alloc(len);
1722
- if (ptr === 0) throw new Error('Failed to allocate memory for getUniformLocation');
1723
-
1724
- try {
1725
- const mem = new Uint8Array(ex.memory.buffer);
1726
- mem.set(bytes, ptr);
1727
- const loc = ex.wasm_ctx_get_uniform_location(this._ctxHandle, programHandle, ptr, len);
1728
- return loc === -1 ? null : loc;
1729
- } finally {
1730
- ex.wasm_free(ptr);
1731
- }
1732
- }
1733
-
1734
- uniform1f(loc, x) {
1735
- this._assertNotDestroyed();
1736
- const ex = this._instance.exports;
1737
- if (!ex || typeof ex.wasm_ctx_uniform1f !== 'function') {
1738
- throw new Error('wasm_ctx_uniform1f not found');
1739
- }
1740
- const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1741
- const code = ex.wasm_ctx_uniform1f(this._ctxHandle, locHandle, +x);
1742
- _checkErr(code, this._instance);
1743
- }
1744
-
1745
- uniform2f(loc, x, y) {
1746
- this._assertNotDestroyed();
1747
- const ex = this._instance.exports;
1748
- if (!ex || typeof ex.wasm_ctx_uniform2f !== 'function') {
1749
- throw new Error('wasm_ctx_uniform2f not found');
1750
- }
1751
- const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1752
- const code = ex.wasm_ctx_uniform2f(this._ctxHandle, locHandle, +x, +y);
1753
- _checkErr(code, this._instance);
1754
- }
1755
-
1756
- uniform3f(loc, x, y, z) {
1757
- this._assertNotDestroyed();
1758
- const ex = this._instance.exports;
1759
- if (!ex || typeof ex.wasm_ctx_uniform3f !== 'function') {
1760
- throw new Error('wasm_ctx_uniform3f not found');
1761
- }
1762
- const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1763
- const code = ex.wasm_ctx_uniform3f(this._ctxHandle, locHandle, +x, +y, +z);
1764
- _checkErr(code, this._instance);
1765
- }
1766
-
1767
- uniform4f(loc, x, y, z, w) {
1768
- this._assertNotDestroyed();
1769
- const ex = this._instance.exports;
1770
- if (!ex || typeof ex.wasm_ctx_uniform4f !== 'function') {
1771
- throw new Error('wasm_ctx_uniform4f not found');
1772
- }
1773
- const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1774
- const code = ex.wasm_ctx_uniform4f(this._ctxHandle, locHandle, +x, +y, +z, +w);
1775
- _checkErr(code, this._instance);
1776
- }
1777
-
1778
- uniform1i(loc, x) {
1779
- this._assertNotDestroyed();
1780
- const ex = this._instance.exports;
1781
- if (!ex || typeof ex.wasm_ctx_uniform1i !== 'function') {
1782
- throw new Error('wasm_ctx_uniform1i not found');
1783
- }
1784
- const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1785
- const code = ex.wasm_ctx_uniform1i(this._ctxHandle, locHandle, x | 0);
1786
- _checkErr(code, this._instance);
1787
- }
1788
-
1789
- uniformMatrix4fv(loc, transpose, value) {
1790
- this._assertNotDestroyed();
1791
- const ex = this._instance.exports;
1792
- if (!ex || typeof ex.wasm_ctx_uniform_matrix_4fv !== 'function') {
1793
- throw new Error('wasm_ctx_uniform_matrix_4fv not found');
1794
- }
1795
- const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1796
-
1797
- let bytes;
1798
- if (value instanceof Float32Array) {
1799
- bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1800
- } else {
1801
- bytes = new Uint8Array(new Float32Array(value).buffer);
1802
- }
1803
-
1804
- const len = bytes.length;
1805
- const ptr = ex.wasm_alloc(len);
1806
- if (ptr === 0) throw new Error('Failed to allocate memory for uniformMatrix4fv');
1807
-
1808
- try {
1809
- const mem = new Uint8Array(ex.memory.buffer);
1810
- mem.set(bytes, ptr);
1811
- const count = len / 4;
1812
- const code = ex.wasm_ctx_uniform_matrix_4fv(this._ctxHandle, locHandle, transpose ? 1 : 0, ptr, count);
1813
- _checkErr(code, this._instance);
1814
- } finally {
1815
- ex.wasm_free(ptr);
1816
- }
1817
- }
1818
-
1819
- getVertexAttrib(index, pname) {
1820
- this._assertNotDestroyed();
1821
- const ex = this._instance.exports;
1822
- if (!ex || typeof ex.wasm_ctx_get_vertex_attrib !== 'function') {
1823
- throw new Error('wasm_ctx_get_vertex_attrib not found');
1824
- }
1825
-
1826
- // Allocate memory for result.
1827
- // Most params return 1 int (4 bytes).
1828
- // CURRENT_VERTEX_ATTRIB returns 4 values (16 bytes) + type (4 bytes) = 20 bytes.
1829
- const len = 20;
1830
- const ptr = ex.wasm_alloc(len);
1831
- if (ptr === 0) throw new Error('Failed to allocate memory for getVertexAttrib');
1832
-
1833
- try {
1834
- const code = ex.wasm_ctx_get_vertex_attrib(this._ctxHandle, index >>> 0, pname >>> 0, ptr, len);
1835
- if (code === 5) { // ERR_GL
1836
- return undefined;
1837
- }
1838
- _checkErr(code, this._instance);
1839
-
1840
- const mem = new Int32Array(ex.memory.buffer, ptr, 5);
1841
- const memU = new Uint32Array(ex.memory.buffer, ptr, 5);
1842
- const memF = new Float32Array(ex.memory.buffer, ptr, 5);
1843
-
1844
- if (pname === 0x8626 /* CURRENT_VERTEX_ATTRIB */) {
1845
- // Check type at index 4
1846
- const type = memU[4];
1847
- if (type === 0x1404 /* INT */) {
1848
- return new Int32Array([mem[0], mem[1], mem[2], mem[3]]);
1849
- } else if (type === 0x1405 /* UNSIGNED_INT */) {
1850
- return new Uint32Array([memU[0], memU[1], memU[2], memU[3]]);
1851
- } else {
1852
- // Default to float
1853
- return new Float32Array([memF[0], memF[1], memF[2], memF[3]]);
1854
- }
1855
- }
1856
-
1857
- // Other params
1858
- if (pname === 0x8622 /* ENABLED */ ||
1859
- pname === 0x886A /* NORMALIZED */ ||
1860
- pname === 0x88FD /* INTEGER */) {
1861
- return mem[0] !== 0;
1862
- }
1863
-
1864
- if (pname === 0x889F /* BUFFER_BINDING */) {
1865
- const handle = memU[0];
1866
- if (handle === 0) return null;
1867
- return new WasmWebGLBuffer(this, handle);
1868
- }
1869
-
1870
- return mem[0];
1871
- } finally {
1872
- ex.wasm_free(ptr, len);
1873
- }
1874
- }
1875
-
1876
-
1877
- getParameter(pname) {
1878
- this._assertNotDestroyed();
1879
- const ex = this._instance.exports;
1880
- if (!ex || typeof ex.wasm_ctx_get_parameter_v !== 'function') {
1881
- throw new Error('wasm_ctx_get_parameter_v not found');
1882
- }
1883
-
1884
- if (pname === 0x0BA2 /* VIEWPORT */) {
1885
- const ptr = ex.wasm_alloc(16);
1886
- try {
1887
- const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 16);
1888
- _checkErr(code, this._instance);
1889
- const mem = new Int32Array(ex.memory.buffer, ptr, 4);
1890
- return new Int32Array(mem);
1891
- } finally {
1892
- ex.wasm_free(ptr, 16);
1893
- }
1894
- }
1895
-
1896
- if (pname === 0x0C22 /* COLOR_CLEAR_VALUE */) {
1897
- const ptr = ex.wasm_alloc(16);
1898
- try {
1899
- const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 16);
1900
- _checkErr(code, this._instance);
1901
- const mem = new Float32Array(ex.memory.buffer, ptr, 4);
1902
- return new Float32Array(mem);
1903
- } finally {
1904
- ex.wasm_free(ptr, 16);
1905
- }
1906
- }
1907
-
1908
- if (pname === 0x0C23 /* COLOR_WRITEMASK */) {
1909
- const ptr = ex.wasm_alloc(4);
1910
- try {
1911
- const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1912
- _checkErr(code, this._instance);
1913
- const mem = new Uint8Array(ex.memory.buffer, ptr, 4);
1914
- return [mem[0] !== 0, mem[1] !== 0, mem[2] !== 0, mem[3] !== 0];
1915
- } finally {
1916
- ex.wasm_free(ptr, 4);
1917
- }
1918
- }
1919
-
1920
- if (pname === 0x0B72 /* DEPTH_WRITEMASK */) {
1921
- const ptr = ex.wasm_alloc(4);
1922
- try {
1923
- const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1924
- _checkErr(code, this._instance);
1925
- const mem = new Uint8Array(ex.memory.buffer, ptr, 1);
1926
- return mem[0] !== 0;
1927
- } finally {
1928
- ex.wasm_free(ptr, 4);
1929
- }
1930
- }
1931
-
1932
- if (pname === 0x0B98 /* STENCIL_WRITEMASK */ || pname === 0x8CA5 /* STENCIL_BACK_WRITEMASK */) {
1933
- const ptr = ex.wasm_alloc(4);
1934
- try {
1935
- const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1936
- _checkErr(code, this._instance);
1937
- const mem = new Int32Array(ex.memory.buffer, ptr, 1);
1938
- return mem[0];
1939
- } finally {
1940
- ex.wasm_free(ptr, 4);
1941
- }
1942
- }
1943
-
1944
- const singleIntParams = [
1945
- 0x0B74, // DEPTH_FUNC
1946
- 0x0B92, // STENCIL_FUNC
1947
- 0x0B93, // STENCIL_VALUE_MASK
1948
- 0x0B97, // STENCIL_REF
1949
- 0x8800, // STENCIL_BACK_FUNC
1950
- 0x8CA4, // STENCIL_BACK_VALUE_MASK
1951
- 0x8CA3, // STENCIL_BACK_REF
1952
- 0x0B94, // STENCIL_FAIL
1953
- 0x0B95, // STENCIL_PASS_DEPTH_FAIL
1954
- 0x0B96, // STENCIL_PASS_DEPTH_PASS
1955
- 0x8801, // STENCIL_BACK_FAIL
1956
- 0x8802, // STENCIL_BACK_PASS_DEPTH_FAIL
1957
- 0x8803, // STENCIL_BACK_PASS_DEPTH_PASS
1958
- ];
1959
-
1960
- if (singleIntParams.includes(pname)) {
1961
- const ptr = ex.wasm_alloc(4);
1962
- try {
1963
- const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1964
- _checkErr(code, this._instance);
1965
- const mem = new Int32Array(ex.memory.buffer, ptr, 1);
1966
- return mem[0];
1967
- } finally {
1968
- ex.wasm_free(ptr, 4);
1969
- }
1970
- }
1971
-
1972
- if (pname === 0x8869 /* MAX_VERTEX_ATTRIBS */) {
1973
- return 16;
1974
- }
1975
-
1976
- throw new Error(`getParameter for ${pname} not implemented`);
1977
- }
1978
- getError() {
1979
- this._assertNotDestroyed();
1980
- const ex = this._instance.exports;
1981
- if (!ex || typeof ex.wasm_ctx_get_error !== 'function') {
1982
- throw new Error('wasm_ctx_get_error not found');
1983
- }
1984
- return ex.wasm_ctx_get_error(this._ctxHandle);
1985
- }
1986
-
1987
- _setError(error) {
1988
- const ex = this._instance.exports;
1989
- if (ex && typeof ex.wasm_ctx_set_gl_error === 'function') {
1990
- ex.wasm_ctx_set_gl_error(this._ctxHandle, error);
1991
- }
1992
- }
1993
-
1994
- finish() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1995
- flush() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1996
-
1997
- isTexture(tex) {
1998
- this._assertNotDestroyed();
1999
- if (!tex || typeof tex !== 'object' || !(tex instanceof WasmWebGLTexture)) return false;
2000
- if (tex._ctx !== this) return false;
2001
- const ex = this._instance.exports;
2002
- return ex.wasm_ctx_is_texture(this._ctxHandle, tex._handle) !== 0;
2003
- }
2004
- isFramebuffer(fb) {
2005
- this._assertNotDestroyed();
2006
- // Framebuffer is currently implemented as a number handle
2007
- if (typeof fb !== 'number') return false;
2008
- const ex = this._instance.exports;
2009
- return ex.wasm_ctx_is_framebuffer(this._ctxHandle, fb) !== 0;
2010
- }
2011
- isProgram(p) {
2012
- this._assertNotDestroyed();
2013
- if (!p || typeof p !== 'object' || !(p instanceof WasmWebGLProgram)) return false;
2014
- if (p._ctx !== this) return false;
2015
- const ex = this._instance.exports;
2016
- return ex.wasm_ctx_is_program(this._ctxHandle, p._handle) !== 0;
2017
- }
2018
- isShader(s) {
2019
- this._assertNotDestroyed();
2020
- if (!s || typeof s !== 'object' || !(s instanceof WasmWebGLShader)) return false;
2021
- if (s._ctx !== this) return false;
2022
- const ex = this._instance.exports;
2023
- return ex.wasm_ctx_is_shader(this._ctxHandle, s._handle) !== 0;
2024
- }
2025
- enable(cap) {
2026
- this._assertNotDestroyed();
2027
- const ex = this._instance.exports;
2028
- if (!ex || typeof ex.wasm_ctx_enable !== 'function') {
2029
- throw new Error('wasm_ctx_enable not found');
2030
- }
2031
- const code = ex.wasm_ctx_enable(this._ctxHandle, cap >>> 0);
2032
- _checkErr(code, this._instance);
2033
- }
2034
- disable(cap) {
2035
- this._assertNotDestroyed();
2036
- const ex = this._instance.exports;
2037
- if (!ex || typeof ex.wasm_ctx_disable !== 'function') {
2038
- throw new Error('wasm_ctx_disable not found');
2039
- }
2040
- const code = ex.wasm_ctx_disable(this._ctxHandle, cap >>> 0);
2041
- _checkErr(code, this._instance);
2042
- }
2043
-
2044
- blendFunc(sfactor, dfactor) {
2045
- this._assertNotDestroyed();
2046
- const ex = this._instance.exports;
2047
- if (!ex || typeof ex.wasm_ctx_blend_func !== 'function') {
2048
- throw new Error('wasm_ctx_blend_func not found');
2049
- }
2050
- const code = ex.wasm_ctx_blend_func(this._ctxHandle, sfactor >>> 0, dfactor >>> 0);
2051
- _checkErr(code, this._instance);
2052
- }
2053
-
2054
- blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) {
2055
- this._assertNotDestroyed();
2056
- const ex = this._instance.exports;
2057
- if (!ex || typeof ex.wasm_ctx_blend_func_separate !== 'function') {
2058
- throw new Error('wasm_ctx_blend_func_separate not found');
2059
- }
2060
- const code = ex.wasm_ctx_blend_func_separate(
2061
- this._ctxHandle,
2062
- srcRGB >>> 0,
2063
- dstRGB >>> 0,
2064
- srcAlpha >>> 0,
2065
- dstAlpha >>> 0
2066
- );
2067
- _checkErr(code, this._instance);
2068
- }
2069
-
2070
- blendEquation(mode) {
2071
- this._assertNotDestroyed();
2072
- const ex = this._instance.exports;
2073
- if (!ex || typeof ex.wasm_ctx_blend_equation !== 'function') {
2074
- throw new Error('wasm_ctx_blend_equation not found');
2075
- }
2076
- const code = ex.wasm_ctx_blend_equation(this._ctxHandle, mode >>> 0);
2077
- _checkErr(code, this._instance);
2078
- }
2079
-
2080
- blendEquationSeparate(modeRGB, modeAlpha) {
2081
- this._assertNotDestroyed();
2082
- const ex = this._instance.exports;
2083
- if (!ex || typeof ex.wasm_ctx_blend_equation_separate !== 'function') {
2084
- throw new Error('wasm_ctx_blend_equation_separate not found');
2085
- }
2086
- const code = ex.wasm_ctx_blend_equation_separate(
2087
- this._ctxHandle,
2088
- modeRGB >>> 0,
2089
- modeAlpha >>> 0
2090
- );
2091
- _checkErr(code, this._instance);
2092
- }
2093
-
2094
- blendColor(red, green, blue, alpha) {
2095
- this._assertNotDestroyed();
2096
- const ex = this._instance.exports;
2097
- if (!ex || typeof ex.wasm_ctx_blend_color !== 'function') {
2098
- throw new Error('wasm_ctx_blend_color not found');
2099
- }
2100
- const code = ex.wasm_ctx_blend_color(
2101
- this._ctxHandle,
2102
- +red,
2103
- +green,
2104
- +blue,
2105
- +alpha
2106
- );
2107
- _checkErr(code, this._instance);
2108
- }
2109
-
2110
- isEnabled(cap) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2111
-
2112
- viewport(x, y, width, height) {
2113
- this._assertNotDestroyed();
2114
- const ex = this._instance.exports;
2115
- if (!ex || typeof ex.wasm_ctx_viewport !== 'function') {
2116
- throw new Error('wasm_ctx_viewport not found');
2117
- }
2118
- const code = ex.wasm_ctx_viewport(this._ctxHandle, x >>> 0, y >>> 0, width >>> 0, height >>> 0);
2119
- _checkErr(code, this._instance);
2120
- }
2121
- scissor(x, y, width, height) {
2122
- this._assertNotDestroyed();
2123
- const ex = this._instance.exports;
2124
- if (!ex || typeof ex.wasm_ctx_scissor !== 'function') {
2125
- throw new Error('wasm_ctx_scissor not found');
2126
- }
2127
- const code = ex.wasm_ctx_scissor(this._ctxHandle, x | 0, y | 0, width >>> 0, height >>> 0);
2128
- _checkErr(code, this._instance);
2129
- }
2130
- clear(mask) {
2131
- this._assertNotDestroyed();
2132
- const ex = this._instance.exports;
2133
- if (!ex || typeof ex.wasm_ctx_clear !== 'function') {
2134
- throw new Error('wasm_ctx_clear not found');
2135
- }
2136
- const code = ex.wasm_ctx_clear(this._ctxHandle, mask >>> 0);
2137
- _checkErr(code, this._instance);
2138
- }
2139
- clearColor(r, g, b, a) {
2140
- this._assertNotDestroyed();
2141
- const ex = this._instance.exports;
2142
- if (!ex || typeof ex.wasm_ctx_clear_color !== 'function') {
2143
- throw new Error('wasm_ctx_clear_color not found');
2144
- }
2145
- const code = ex.wasm_ctx_clear_color(this._ctxHandle, +r, +g, +b, +a);
2146
- _checkErr(code, this._instance);
2147
- }
2148
- clearDepth(depth) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2149
- depthFunc(func) {
2150
- this._assertNotDestroyed();
2151
- const ex = this._instance.exports;
2152
- if (!ex || typeof ex.wasm_ctx_depth_func !== 'function') {
2153
- throw new Error('wasm_ctx_depth_func not found');
2154
- }
2155
- const code = ex.wasm_ctx_depth_func(this._ctxHandle, func >>> 0);
2156
- _checkErr(code, this._instance);
2157
- }
2158
- depthMask(flag) {
2159
- this._assertNotDestroyed();
2160
- const ex = this._instance.exports;
2161
- if (!ex || typeof ex.wasm_ctx_depth_mask !== 'function') {
2162
- throw new Error('wasm_ctx_depth_mask not found');
2163
- }
2164
- const code = ex.wasm_ctx_depth_mask(this._ctxHandle, flag ? 1 : 0);
2165
- _checkErr(code, this._instance);
2166
- }
2167
- colorMask(r, g, b, a) {
2168
- this._assertNotDestroyed();
2169
- const ex = this._instance.exports;
2170
- if (!ex || typeof ex.wasm_ctx_color_mask !== 'function') {
2171
- throw new Error('wasm_ctx_color_mask not found');
2172
- }
2173
- const code = ex.wasm_ctx_color_mask(this._ctxHandle, r ? 1 : 0, g ? 1 : 0, b ? 1 : 0, a ? 1 : 0);
2174
- _checkErr(code, this._instance);
2175
- }
2176
- polygonOffset(factor, units) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2177
- sampleCoverage(value, invert) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2178
- stencilFunc(func, ref, mask) {
2179
- this._assertNotDestroyed();
2180
- const ex = this._instance.exports;
2181
- if (!ex || typeof ex.wasm_ctx_stencil_func !== 'function') {
2182
- throw new Error('wasm_ctx_stencil_func not found');
2183
- }
2184
- const code = ex.wasm_ctx_stencil_func(this._ctxHandle, func >>> 0, ref | 0, mask >>> 0);
2185
- _checkErr(code, this._instance);
2186
- }
2187
- stencilFuncSeparate(face, func, ref, mask) {
2188
- this._assertNotDestroyed();
2189
- const ex = this._instance.exports;
2190
- if (!ex || typeof ex.wasm_ctx_stencil_func_separate !== 'function') {
2191
- throw new Error('wasm_ctx_stencil_func_separate not found');
2192
- }
2193
- const code = ex.wasm_ctx_stencil_func_separate(this._ctxHandle, face >>> 0, func >>> 0, ref | 0, mask >>> 0);
2194
- _checkErr(code, this._instance);
2195
- }
2196
- stencilOp(fail, zfail, zpass) {
2197
- this._assertNotDestroyed();
2198
- const ex = this._instance.exports;
2199
- if (!ex || typeof ex.wasm_ctx_stencil_op !== 'function') {
2200
- throw new Error('wasm_ctx_stencil_op not found');
2201
- }
2202
- const code = ex.wasm_ctx_stencil_op(this._ctxHandle, fail >>> 0, zfail >>> 0, zpass >>> 0);
2203
- _checkErr(code, this._instance);
2204
- }
2205
- stencilOpSeparate(face, fail, zfail, zpass) {
2206
- this._assertNotDestroyed();
2207
- const ex = this._instance.exports;
2208
- if (!ex || typeof ex.wasm_ctx_stencil_op_separate !== 'function') {
2209
- throw new Error('wasm_ctx_stencil_op_separate not found');
2210
- }
2211
- const code = ex.wasm_ctx_stencil_op_separate(this._ctxHandle, face >>> 0, fail >>> 0, zfail >>> 0, zpass >>> 0);
2212
- _checkErr(code, this._instance);
2213
- }
2214
- stencilMask(mask) {
2215
- this._assertNotDestroyed();
2216
- const ex = this._instance.exports;
2217
- if (!ex || typeof ex.wasm_ctx_stencil_mask !== 'function') {
2218
- throw new Error('wasm_ctx_stencil_mask not found');
2219
- }
2220
- const code = ex.wasm_ctx_stencil_mask(this._ctxHandle, mask >>> 0);
2221
- _checkErr(code, this._instance);
2222
- }
2223
- stencilMaskSeparate(face, mask) {
2224
- this._assertNotDestroyed();
2225
- const ex = this._instance.exports;
2226
- if (!ex || typeof ex.wasm_ctx_stencil_mask_separate !== 'function') {
2227
- throw new Error('wasm_ctx_stencil_mask_separate not found');
2228
- }
2229
- const code = ex.wasm_ctx_stencil_mask_separate(this._ctxHandle, face >>> 0, mask >>> 0);
2230
- _checkErr(code, this._instance);
2231
- }
2232
- }
2233
-
2234
- /**
2235
- * Thin wrapper for a WebGLTexture handle returned from WASM.
2236
- * Holds a reference to the originating WasmWebGL2RenderingContext and the numeric handle.
2237
- */
2238
- // WebGLTexture wrapper moved to `src/webgl2_texture.js`.
2239
-
2240
- /**
2241
- * Read an error message from WASM memory and return it as string.
2242
- * Exported so callers outside this module can report errors.
2243
- * @param {WebAssembly.Instance} instance
2244
- * @returns {string}
2245
- */
2246
- export function readErrorMessage(instance) {
2247
- const ex = instance.exports;
2248
- if (!ex || typeof ex.wasm_last_error_ptr !== 'function' || typeof ex.wasm_last_error_len !== 'function') {
2249
- return '(no error message available)';
2250
- }
2251
- const ptr = ex.wasm_last_error_ptr();
2252
- const len = ex.wasm_last_error_len();
2253
- if (ptr === 0 || len === 0) {
2254
- return '';
2255
- }
2256
- const mem = new Uint8Array(ex.memory.buffer);
2257
- const bytes = mem.subarray(ptr, ptr + len);
2258
- return new TextDecoder('utf-8').decode(bytes);
2259
- }
2260
-
2261
- function _checkErr(code, instance) {
2262
- if (code === ERR_OK) return;
2263
- const msg = readErrorMessage(instance);
2264
- throw new Error(`WASM error ${code}: ${msg}`);
2265
- }
2266
-
2267
- // ============================================================================
2268
- // WAT Testing Support (docs/1.9-wat-testing.md)
2269
- // ============================================================================
2270
-
2271
- /**
2272
- * Get the compiled WASM bytes for a shader in a program.
2273
- *
2274
- * @param {number} ctxHandle - Context handle
2275
- * @param {number} programHandle - Program handle
2276
- * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2277
- * @returns {Uint8Array | null} WASM bytes or null if not available
2278
- */
2279
- export function getShaderModule(ctxHandle, programHandle, shaderType) {
2280
- const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2281
- if (!ctx) {
2282
- throw new Error('Invalid context handle');
2283
- }
2284
-
2285
- const ex = ctx._instance.exports;
2286
- if (!ex || typeof ex.wasm_ctx_get_program_wasm_ref !== 'function') {
2287
- throw new Error('wasm_ctx_get_program_wasm_ref not found');
2288
- }
2289
-
2290
- // Call the WASM function - it returns a packed u64 (BigInt or Number)
2291
- const result = ex.wasm_ctx_get_program_wasm_ref(ctxHandle, programHandle, shaderType);
2292
-
2293
- // Unpack: low 32 bits = ptr, high 32 bits = len
2294
- let ptr, len;
2295
- if (typeof result === 'bigint') {
2296
- ptr = Number(result & 0xFFFFFFFFn);
2297
- len = Number((result >> 32n) & 0xFFFFFFFFn);
2298
- } else {
2299
- // Fallback for number (may lose precision for very large values)
2300
- ptr = result >>> 0; // Low 32 bits
2301
- len = Math.floor(result / 0x100000000); // High 32 bits
2302
- }
2303
-
2304
- // Check for failure (0, 0)
2305
- if (ptr === 0 || len === 0) {
2306
- return null;
2307
- }
2308
-
2309
- // Copy bytes from WASM memory into a new Uint8Array
2310
- const mem = new Uint8Array(ex.memory.buffer);
2311
- const bytes = new Uint8Array(len);
2312
- bytes.set(mem.subarray(ptr, ptr + len));
2313
-
2314
- return bytes;
2315
- }
2316
-
2317
- /**
2318
- * Get the WAT (WebAssembly Text) representation for a shader in a program.
2319
- *
2320
- * @param {number} ctxHandle - Context handle
2321
- * @param {number} programHandle - Program handle
2322
- * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2323
- * @returns {string | null} WAT text or null if not available
2324
- */
2325
- export function getShaderWat(ctxHandle, programHandle, shaderType) {
2326
- const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2327
- if (!ctx) {
2328
- throw new Error('Invalid context handle');
2329
- }
2330
-
2331
- const ex = ctx._instance.exports;
2332
- if (!ex || typeof ex.wasm_ctx_get_program_wat_ref !== 'function') {
2333
- throw new Error('wasm_ctx_get_program_wat_ref not found');
2334
- }
2335
-
2336
- // Call the WASM function - it returns a packed u64 (BigInt or Number)
2337
- const result = ex.wasm_ctx_get_program_wat_ref(ctxHandle, programHandle, shaderType);
2338
-
2339
- // Unpack: low 32 bits = ptr, high 32 bits = len
2340
- let ptr, len;
2341
- if (typeof result === 'bigint') {
2342
- ptr = Number(result & 0xFFFFFFFFn);
2343
- len = Number((result >> 32n) & 0xFFFFFFFFn);
2344
- } else {
2345
- // Fallback for number (may lose precision for very large values)
2346
- ptr = result >>> 0; // Low 32 bits
2347
- len = Math.floor(result / 0x100000000); // High 32 bits
2348
- }
2349
-
2350
- // Check for failure (0, 0)
2351
- if (ptr === 0 || len === 0) {
2352
- return null;
2353
- }
2354
-
2355
- // Copy bytes from WASM memory and decode as UTF-8
2356
- const mem = new Uint8Array(ex.memory.buffer);
2357
- const bytes = mem.subarray(ptr, ptr + len);
2358
- const decoder = new TextDecoder('utf-8');
2359
- const watText = decoder.decode(bytes);
2360
-
2361
- return watText;
2362
- }
2363
-
2364
- /**
2365
- * Decompile WASM bytes to GLSL source code.
2366
- *
2367
- * This uses the WASM-to-GLSL decompiler to convert compiled shader WASM
2368
- * back into readable GLSL-like code.
2369
- *
2370
- * @param {number} ctxHandle - Context handle
2371
- * @param {number} programHandle - Program handle
2372
- * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2373
- * @returns {string | null} GLSL source code or null if not available
2374
- */
2375
- export function getShaderGlsl(ctxHandle, programHandle, shaderType) {
2376
- const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2377
- if (!ctx) {
2378
- throw new Error('Invalid context handle');
2379
- }
2380
-
2381
- // First get the WASM bytes for the shader
2382
- const wasmBytes = getShaderModule(ctxHandle, programHandle, shaderType);
2383
- if (!wasmBytes) {
2384
- return null;
2385
- }
2386
-
2387
- const ex = ctx._instance.exports;
2388
- if (!ex || typeof ex.wasm_decompile_to_glsl !== 'function') {
2389
- throw new Error('wasm_decompile_to_glsl not found');
2390
- }
2391
-
2392
- // Allocate memory in WASM for the input bytes
2393
- const wasmBytesLen = wasmBytes.length;
2394
- const wasmBytesPtr = ex.wasm_alloc(wasmBytesLen);
2395
- if (wasmBytesPtr === 0) {
2396
- throw new Error('Failed to allocate memory for WASM bytes');
2397
- }
2398
-
2399
- try {
2400
- // Copy WASM bytes to linear memory
2401
- const mem = new Uint8Array(ex.memory.buffer);
2402
- mem.set(wasmBytes, wasmBytesPtr);
2403
-
2404
- // Call the decompiler
2405
- const resultLen = ex.wasm_decompile_to_glsl(wasmBytesPtr, wasmBytesLen);
2406
-
2407
- if (resultLen === 0) {
2408
- return null;
2409
- }
2410
-
2411
- // Get the decompiled GLSL
2412
- const glslPtr = ex.wasm_get_decompiled_glsl_ptr();
2413
- const glslLen = ex.wasm_get_decompiled_glsl_len();
2414
-
2415
- if (glslPtr === 0 || glslLen === 0) {
2416
- return null;
2417
- }
2418
-
2419
- // Read the GLSL string
2420
- const glslBytes = new Uint8Array(ex.memory.buffer).subarray(glslPtr, glslPtr + glslLen);
2421
- const decoder = new TextDecoder('utf-8');
2422
- return decoder.decode(glslBytes);
2423
- } finally {
2424
- // Free the allocated memory
2425
- ex.wasm_free(wasmBytesPtr);
2426
- }
2427
- }
2428
-
2429
- /**
2430
- * Decompile raw WASM bytes to GLSL source code.
2431
- *
2432
- * This is a lower-level API that takes raw WASM bytes directly.
2433
- *
2434
- * @param {WasmWebGL2RenderingContext} gl - WebGL2 context
2435
- * @param {Uint8Array} wasmBytes - Raw WASM bytecode to decompile
2436
- * @returns {string | null} GLSL source code or null on error
2437
- */
2438
- export function decompileWasmToGlsl(gl, wasmBytes) {
2439
- if (!gl || !gl._instance) {
2440
- throw new Error('Invalid WebGL2 context');
2441
- }
2442
-
2443
- const ex = gl._instance.exports;
2444
- if (!ex || typeof ex.wasm_decompile_to_glsl !== 'function') {
2445
- throw new Error('wasm_decompile_to_glsl not found');
2446
- }
2447
-
2448
- // Allocate memory in WASM for the input bytes
2449
- const wasmBytesLen = wasmBytes.length;
2450
- const wasmBytesPtr = ex.wasm_alloc(wasmBytesLen);
2451
- if (wasmBytesPtr === 0) {
2452
- throw new Error('Failed to allocate memory for WASM bytes');
2453
- }
2454
-
2455
- try {
2456
- // Copy WASM bytes to linear memory
2457
- const mem = new Uint8Array(ex.memory.buffer);
2458
- mem.set(wasmBytes, wasmBytesPtr);
2459
-
2460
- // Call the decompiler
2461
- const resultLen = ex.wasm_decompile_to_glsl(wasmBytesPtr, wasmBytesLen);
2462
-
2463
- if (resultLen === 0) {
2464
- return null;
2465
- }
2466
-
2467
- // Get the decompiled GLSL
2468
- const glslPtr = ex.wasm_get_decompiled_glsl_ptr();
2469
- const glslLen = ex.wasm_get_decompiled_glsl_len();
2470
-
2471
- if (glslPtr === 0 || glslLen === 0) {
2472
- return null;
2473
- }
2474
-
2475
- // Read the GLSL string
2476
- const glslBytes = new Uint8Array(ex.memory.buffer).subarray(glslPtr, glslPtr + glslLen);
2477
- const decoder = new TextDecoder('utf-8');
2478
- return decoder.decode(glslBytes);
2479
- } finally {
2480
- // Free the allocated memory
2481
- ex.wasm_free(wasmBytesPtr);
2482
- }
2483
- }
1
+ // Thin forwarding WasmWebGL2RenderingContext and helpers
2
+ // This module contains the class and small helpers that operate on the
3
+ // WebAssembly instance. It is intentionally minimal: JS forwards calls to
4
+ // WASM and reads last-error strings when needed.
5
+
6
+ /** @typedef {number} u32 */
7
+
8
+ // Errno constants (must match src/webgl2_context.rs)
9
+ export const ERR_OK = 0;
10
+ export const ERR_INVALID_HANDLE = 1;
11
+ export const ERR_OOM = 2;
12
+ export const ERR_INVALID_ARGS = 3;
13
+ export const ERR_NOT_IMPLEMENTED = 4;
14
+ export const ERR_GL = 5;
15
+ export const ERR_INTERNAL = 6;
16
+
17
+ import { WasmWebGLTexture } from './webgl2_texture.js';
18
+ import {
19
+ WasmWebGLShader,
20
+ WasmWebGLProgram,
21
+ WasmWebGLBuffer,
22
+ WasmWebGLRenderbuffer,
23
+ WasmWebGLFramebuffer,
24
+ WasmWebGLVertexArrayObject,
25
+ WasmWebGLQuery,
26
+ WasmWebGLSampler,
27
+ WasmWebGLSync,
28
+ WasmWebGLTransformFeedback,
29
+ WasmWebGLUniformLocation
30
+ } from './webgl2_resources.js';
31
+
32
+ /**
33
+ * @implements {WebGL2RenderingContext}
34
+ */
35
+ export class WasmWebGL2RenderingContext {
36
+ // Constants
37
+ FRAGMENT_SHADER = 0x8B30;
38
+ VERTEX_SHADER = 0x8B31;
39
+ TRIANGLES = 0x0004;
40
+ TRIANGLE_STRIP = 0x0005;
41
+ COLOR_BUFFER_BIT = 0x00004000;
42
+ DEPTH_BUFFER_BIT = 0x00000100;
43
+ DEPTH_TEST = 0x0B71;
44
+ STENCIL_TEST = 0x0B90;
45
+ SCISSOR_TEST = 0x0C11;
46
+ STENCIL_BUFFER_BIT = 0x00000400;
47
+ COMPILE_STATUS = 0x8B81;
48
+ LINK_STATUS = 0x8B82;
49
+ DELETE_STATUS = 0x8B80;
50
+ VALIDATE_STATUS = 0x8B83;
51
+ ARRAY_BUFFER = 0x8892;
52
+ ELEMENT_ARRAY_BUFFER = 0x8893;
53
+ COPY_READ_BUFFER = 0x8F36;
54
+ COPY_WRITE_BUFFER = 0x8F37;
55
+ PIXEL_PACK_BUFFER = 0x88EB;
56
+ PIXEL_UNPACK_BUFFER = 0x88EC;
57
+ UNIFORM_BUFFER = 0x8A11;
58
+ TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
59
+ STATIC_DRAW = 0x88E4;
60
+ BYTE = 0x1400;
61
+ UNSIGNED_BYTE = 0x1401;
62
+ SHORT = 0x1402;
63
+ UNSIGNED_SHORT = 0x1403;
64
+ INT = 0x1404;
65
+ UNSIGNED_INT = 0x1405;
66
+ FLOAT = 0x1406;
67
+ FLOAT_VEC2 = 0x8B50;
68
+ FLOAT_VEC3 = 0x8B51;
69
+ FLOAT_VEC4 = 0x8B52;
70
+ INT_VEC2 = 0x8B53;
71
+ INT_VEC3 = 0x8B54;
72
+ INT_VEC4 = 0x8B55;
73
+ BOOL = 0x8B56;
74
+ BOOL_VEC2 = 0x8B57;
75
+ BOOL_VEC3 = 0x8B58;
76
+ BOOL_VEC4 = 0x8B59;
77
+ FLOAT_MAT2 = 0x8B5A;
78
+ FLOAT_MAT3 = 0x8B5B;
79
+ FLOAT_MAT4 = 0x8B5C;
80
+ SAMPLER_2D = 0x8B5E;
81
+ SAMPLER_3D = 0x8B5F;
82
+ SAMPLER_CUBE = 0x8B60;
83
+ ACTIVE_UNIFORMS = 0x8B86;
84
+ ACTIVE_ATTRIBUTES = 0x8B89;
85
+ VIEWPORT = 0x0BA2;
86
+ COLOR_CLEAR_VALUE = 0x0C22;
87
+ COLOR_WRITEMASK = 0x0C23;
88
+ DEPTH_WRITEMASK = 0x0B72;
89
+ STENCIL_WRITEMASK = 0x0B98;
90
+ STENCIL_BACK_WRITEMASK = 0x8CA5;
91
+
92
+ DEPTH_FUNC = 0x0B74;
93
+ STENCIL_FUNC = 0x0B92;
94
+ STENCIL_VALUE_MASK = 0x0B93;
95
+ STENCIL_REF = 0x0B97;
96
+ STENCIL_BACK_FUNC = 0x8800;
97
+ STENCIL_BACK_VALUE_MASK = 0x8CA4;
98
+ STENCIL_BACK_REF = 0x8CA3;
99
+ STENCIL_FAIL = 0x0B94;
100
+ STENCIL_PASS_DEPTH_FAIL = 0x0B95;
101
+ STENCIL_PASS_DEPTH_PASS = 0x0B96;
102
+ STENCIL_BACK_FAIL = 0x8801;
103
+ STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802;
104
+ STENCIL_BACK_PASS_DEPTH_PASS = 0x8803;
105
+
106
+ BUFFER_SIZE = 0x8764;
107
+ MAX_VERTEX_ATTRIBS = 0x8869;
108
+ NO_ERROR = 0;
109
+ INVALID_ENUM = 0x0500;
110
+ INVALID_VALUE = 0x0501;
111
+ INVALID_OPERATION = 0x0502;
112
+ OUT_OF_MEMORY = 0x0505;
113
+
114
+ ZERO = 0;
115
+ ONE = 1;
116
+
117
+ CURRENT_VERTEX_ATTRIB = 0x8626;
118
+ VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622;
119
+ VERTEX_ATTRIB_ARRAY_SIZE = 0x8623;
120
+ VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624;
121
+ VERTEX_ATTRIB_ARRAY_TYPE = 0x8625;
122
+ VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A;
123
+ VERTEX_ATTRIB_ARRAY_POINTER = 0x8645;
124
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
125
+ VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE;
126
+ VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD;
127
+
128
+ RENDERBUFFER = 0x8D41;
129
+ FRAMEBUFFER = 0x8D40;
130
+ READ_FRAMEBUFFER = 0x8CA8;
131
+ DRAW_FRAMEBUFFER = 0x8CA9;
132
+ FRAMEBUFFER_COMPLETE = 0x8CD5;
133
+ FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
134
+ FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
135
+ FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
136
+ FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
137
+ FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56;
138
+ RENDERBUFFER_SAMPLES = 0x8CAB;
139
+ FRAMEBUFFER_UNDEFINED = 0x8219;
140
+ DEPTH_COMPONENT16 = 0x81A5;
141
+ DEPTH_STENCIL = 0x84F9;
142
+ RGBA4 = 0x8056;
143
+ RGB565 = 0x8D62;
144
+ RGB5_A1 = 0x8057;
145
+ RGBA8 = 0x8058;
146
+ RGBA32F = 0x8814;
147
+ RGB32F = 0x8815;
148
+ RGBA16F = 0x881A;
149
+ RGB16F = 0x881B;
150
+ R8UI = 0x8232;
151
+ RG8UI = 0x8238;
152
+ RGB8UI = 0x8D7D;
153
+ RGBA8UI = 0x8D7C;
154
+ R16UI = 0x8234;
155
+ RG16UI = 0x823A;
156
+ RGB16UI = 0x8D77;
157
+ RGBA16UI = 0x8D76;
158
+ R32UI = 0x8236;
159
+ RG32UI = 0x823C;
160
+ RGB32UI = 0x8D71;
161
+ RGBA32UI = 0x8D70;
162
+ R8I = 0x8231;
163
+ RG8I = 0x8237;
164
+ RGB8I = 0x8D8F;
165
+ RGBA8I = 0x8D8E;
166
+ R16I = 0x8233;
167
+ RG16I = 0x8239;
168
+ RGB16I = 0x8D89;
169
+ RGBA16I = 0x8D88;
170
+ R32I = 0x8235;
171
+ RG32I = 0x823B;
172
+ RGB32I = 0x8D83;
173
+ RGBA32I = 0x8D82;
174
+ RED_INTEGER = 0x8D94;
175
+ RG_INTEGER = 0x8D95;
176
+ RGB_INTEGER = 0x8D96;
177
+ RGBA_INTEGER = 0x8D99;
178
+ R32F = 0x822E;
179
+ RG32F = 0x8230;
180
+ R16F = 0x822D;
181
+ RG16F = 0x822F;
182
+ STENCIL_INDEX8 = 0x8D48;
183
+ COLOR_ATTACHMENT0 = 0x8CE0;
184
+ COLOR_ATTACHMENT1 = 0x8CE1;
185
+ COLOR_ATTACHMENT2 = 0x8CE2;
186
+ COLOR_ATTACHMENT3 = 0x8CE3;
187
+ COLOR_ATTACHMENT4 = 0x8CE4;
188
+ COLOR_ATTACHMENT5 = 0x8CE5;
189
+ COLOR_ATTACHMENT6 = 0x8CE6;
190
+ COLOR_ATTACHMENT7 = 0x8CE7;
191
+ DEPTH_ATTACHMENT = 0x8D00;
192
+ STENCIL_ATTACHMENT = 0x8D20;
193
+ DEPTH_STENCIL_ATTACHMENT = 0x821A;
194
+
195
+ LESS = 0x0201;
196
+ EQUAL = 0x0202;
197
+ LEQUAL = 0x0203;
198
+ GREATER = 0x0204;
199
+ NOTEQUAL = 0x0205;
200
+ GEQUAL = 0x0206;
201
+ ALWAYS = 0x0207;
202
+ NEVER = 0x0200;
203
+
204
+ KEEP = 0x1E00;
205
+ REPLACE = 0x1E01;
206
+ INCR = 0x1E02;
207
+ DECR = 0x1E03;
208
+ INVERT = 0x150A;
209
+ INCR_WRAP = 0x8507;
210
+ DECR_WRAP = 0x8508;
211
+
212
+ FRONT = 0x0404;
213
+ BACK = 0x0405;
214
+ FRONT_AND_BACK = 0x0408;
215
+
216
+ TEXTURE_2D = 0x0DE1;
217
+ TEXTURE_3D = 0x806F;
218
+ TEXTURE_2D_ARRAY = 0x8C1A;
219
+ TEXTURE_WRAP_S = 0x2802;
220
+ TEXTURE_WRAP_T = 0x2803;
221
+ TEXTURE_WRAP_R = 0x8072;
222
+ TEXTURE_MAG_FILTER = 0x2800;
223
+ TEXTURE_MIN_FILTER = 0x2801;
224
+ RGBA = 0x1908;
225
+ RED = 0x1903;
226
+ RG = 0x8227;
227
+ UNSIGNED_BYTE = 0x1401;
228
+ FLOAT = 0x1406;
229
+ NEAREST = 0x2600;
230
+ LINEAR = 0x2601;
231
+ NEAREST_MIPMAP_NEAREST = 0x2700;
232
+ LINEAR_MIPMAP_NEAREST = 0x2701;
233
+ NEAREST_MIPMAP_LINEAR = 0x2702;
234
+ LINEAR_MIPMAP_LINEAR = 0x2703;
235
+ REPEAT = 0x2901;
236
+ CLAMP_TO_EDGE = 0x812F;
237
+ MIRRORED_REPEAT = 0x8370;
238
+
239
+ /**
240
+ * @param {{
241
+ * instance: WebAssembly.Instance,
242
+ * ctxHandle: number,
243
+ * width: number,
244
+ * height: number,
245
+ * debugShaders: boolean,
246
+ * sharedTable: any,
247
+ * tableAllocator: any
248
+ * }} options
249
+ */
250
+ constructor({ instance, ctxHandle, width, height, debugShaders = false, sharedTable = null, tableAllocator = null, turboGlobals = null }) {
251
+ this._instance = instance;
252
+ this._ctxHandle = ctxHandle;
253
+ this._destroyed = false;
254
+ /** @type {import('./webgl2_resources.js').WasmWebGLProgram | null} */
255
+ this._currentProgram = null;
256
+ // Explicit booleans for clarity
257
+ this._debugShaders = !!debugShaders;
258
+ this._drawingBufferWidth = width;
259
+ this._drawingBufferHeight = height;
260
+ this._sharedTable = sharedTable;
261
+ this._tableAllocator = tableAllocator;
262
+
263
+ // TODO: potentially retrieve those one demand from the main WASM module when shader WASM modules are initialised
264
+ this._turboGlobals = turboGlobals;
265
+
266
+ WasmWebGL2RenderingContext._contexts.set(this._ctxHandle, this);
267
+ }
268
+
269
+ get drawingBufferWidth() {
270
+ return this._drawingBufferWidth;
271
+ }
272
+
273
+ get drawingBufferHeight() {
274
+ return this._drawingBufferHeight;
275
+ }
276
+
277
+ resize(width, height) {
278
+ this._assertNotDestroyed();
279
+ const ex = this._instance.exports;
280
+ if (!ex || typeof ex.wasm_ctx_resize !== 'function') {
281
+ throw new Error('wasm_ctx_resize not found');
282
+ }
283
+ const code = ex.wasm_ctx_resize(this._ctxHandle, width, height);
284
+ _checkErr(code, this._instance);
285
+ this._drawingBufferWidth = width;
286
+ this._drawingBufferHeight = height;
287
+ }
288
+
289
+ // Set the viewport for rendering
290
+ viewport(x, y, width, height) {
291
+ this._assertNotDestroyed();
292
+ const ex = this._instance.exports;
293
+ if (!ex || typeof ex.wasm_ctx_viewport !== 'function') {
294
+ throw new Error('wasm_ctx_viewport not found');
295
+ }
296
+ const code = ex.wasm_ctx_viewport(this._ctxHandle, x | 0, y | 0, width >>> 0, height >>> 0);
297
+ _checkErr(code, this._instance);
298
+ }
299
+
300
+ /** @type {Map<number, WasmWebGL2RenderingContext>} */
301
+ static _contexts = new Map();
302
+
303
+ destroy() {
304
+ if (this._destroyed) return;
305
+ WasmWebGL2RenderingContext._contexts.delete(this._ctxHandle);
306
+ const ex = this._instance.exports;
307
+ if (ex && typeof ex.wasm_destroy_context === 'function') {
308
+ const code = ex.wasm_destroy_context(this._ctxHandle);
309
+ _checkErr(code, this._instance);
310
+ }
311
+ this._destroyed = true;
312
+ }
313
+
314
+ _assertNotDestroyed() {
315
+ if (this._destroyed) throw new Error('context has been destroyed');
316
+ }
317
+
318
+ createTexture() {
319
+ this._assertNotDestroyed();
320
+ const ex = this._instance.exports;
321
+ if (!ex || typeof ex.wasm_ctx_create_texture !== 'function') {
322
+ throw new Error('wasm_ctx_create_texture not found');
323
+ }
324
+ const handle = ex.wasm_ctx_create_texture(this._ctxHandle);
325
+ if (handle === 0) {
326
+ const msg = readErrorMessage(this._instance);
327
+ throw new Error(`Failed to create texture: ${msg}`);
328
+ }
329
+ // Return a thin wrapper object representing the texture.
330
+ return new WasmWebGLTexture(this, handle);
331
+ }
332
+
333
+ deleteTexture(tex) {
334
+ this._assertNotDestroyed();
335
+ const ex = this._instance.exports;
336
+ if (!ex || typeof ex.wasm_ctx_delete_texture !== 'function') {
337
+ throw new Error('wasm_ctx_delete_texture not found');
338
+ }
339
+ const handle = tex && typeof tex === 'object' && typeof tex._handle === 'number' ? tex._handle : (tex >>> 0);
340
+ const code = ex.wasm_ctx_delete_texture(this._ctxHandle, handle);
341
+ _checkErr(code, this._instance);
342
+ // If a wrapper object was passed, mark it as deleted.
343
+ if (tex && typeof tex === 'object') {
344
+ try { tex._handle = 0; tex._deleted = true; } catch (e) { /* ignore */ }
345
+ }
346
+ }
347
+
348
+ bindTexture(target, tex) {
349
+ this._assertNotDestroyed();
350
+ const ex = this._instance.exports;
351
+ if (!ex || typeof ex.wasm_ctx_bind_texture !== 'function') {
352
+ throw new Error('wasm_ctx_bind_texture not found');
353
+ }
354
+ const handle = tex && typeof tex === 'object' && typeof tex._handle === 'number' ? tex._handle : (tex >>> 0);
355
+ const code = ex.wasm_ctx_bind_texture(this._ctxHandle, target >>> 0, handle);
356
+ _checkErr(code, this._instance);
357
+ // Record bound texture in JS so we can map units to texture data for texel fetch
358
+ this._boundTexture = handle;
359
+ this._textureUnits = this._textureUnits || [];
360
+ const unit = this._activeTextureUnit || 0;
361
+ this._textureUnits[unit] = handle;
362
+ }
363
+
364
+ texImage2D(target, level, internalFormat, width, height, border, format, type_, pixels) {
365
+ this._assertNotDestroyed();
366
+ const ex = this._instance.exports;
367
+ if (!ex || typeof ex.wasm_ctx_tex_image_2d !== 'function') {
368
+ throw new Error('wasm_ctx_tex_image_2d not found');
369
+ }
370
+
371
+ let data = pixels;
372
+ if (!data) {
373
+ data = new Uint8Array(width * height * 4);
374
+ } else if (ArrayBuffer.isView(data)) {
375
+ data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
376
+ } else if (data instanceof ArrayBuffer) {
377
+ data = new Uint8Array(data);
378
+ }
379
+
380
+ const len = data.length;
381
+ const ptr = ex.wasm_alloc(len);
382
+ if (ptr === 0) throw new Error('Failed to allocate memory for pixel data');
383
+
384
+ try {
385
+ const mem = new Uint8Array(ex.memory.buffer);
386
+ mem.set(data, ptr);
387
+
388
+ const code = ex.wasm_ctx_tex_image_2d(
389
+ this._ctxHandle,
390
+ target >>> 0,
391
+ level >>> 0,
392
+ internalFormat >>> 0,
393
+ width >>> 0,
394
+ height >>> 0,
395
+ border >>> 0,
396
+ format >>> 0,
397
+ type_ >>> 0,
398
+ ptr >>> 0,
399
+ len >>> 0
400
+ );
401
+ _checkErr(code, this._instance);
402
+ } finally {
403
+ ex.wasm_free(ptr);
404
+ }
405
+ }
406
+
407
+ texImage3D(target, level, internalFormat, width, height, depth, border, format, type_, pixels) {
408
+ this._assertNotDestroyed();
409
+ const ex = this._instance.exports;
410
+ if (!ex || typeof ex.wasm_ctx_tex_image_3d !== 'function') {
411
+ throw new Error('wasm_ctx_tex_image_3d not found');
412
+ }
413
+
414
+ let data = pixels;
415
+ if (!data) {
416
+ data = new Uint8Array(width * height * depth * 4);
417
+ } else if (ArrayBuffer.isView(data)) {
418
+ data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
419
+ } else if (data instanceof ArrayBuffer) {
420
+ data = new Uint8Array(data);
421
+ }
422
+
423
+ const len = data.length;
424
+ const ptr = ex.wasm_alloc(len);
425
+ if (ptr === 0) throw new Error('Failed to allocate memory for pixel data');
426
+
427
+ try {
428
+ const mem = new Uint8Array(ex.memory.buffer);
429
+ mem.set(data, ptr);
430
+
431
+ const code = ex.wasm_ctx_tex_image_3d(
432
+ this._ctxHandle,
433
+ target >>> 0,
434
+ level >>> 0,
435
+ internalFormat >>> 0,
436
+ width >>> 0,
437
+ height >>> 0,
438
+ depth >>> 0,
439
+ border >>> 0,
440
+ format >>> 0,
441
+ type_ >>> 0,
442
+ ptr >>> 0,
443
+ len >>> 0
444
+ );
445
+ _checkErr(code, this._instance);
446
+ } finally {
447
+ ex.wasm_free(ptr);
448
+ }
449
+ }
450
+
451
+ copyTexImage2D(target, level, internalFormat, x, y, width, height, border) {
452
+ this._assertNotDestroyed();
453
+ const ex = this._instance.exports;
454
+ if (!ex || typeof ex.wasm_ctx_copy_tex_image_2d !== 'function') {
455
+ throw new Error('wasm_ctx_copy_tex_image_2d not found');
456
+ }
457
+ const code = ex.wasm_ctx_copy_tex_image_2d(
458
+ this._ctxHandle,
459
+ target >>> 0,
460
+ level >>> 0,
461
+ internalFormat >>> 0,
462
+ x | 0,
463
+ y | 0,
464
+ width >>> 0,
465
+ height >>> 0,
466
+ border >>> 0
467
+ );
468
+ _checkErr(code, this._instance);
469
+ }
470
+
471
+ createFramebuffer() {
472
+ this._assertNotDestroyed();
473
+ const ex = this._instance.exports;
474
+ if (!ex || typeof ex.wasm_ctx_create_framebuffer !== 'function') {
475
+ throw new Error('wasm_ctx_create_framebuffer not found');
476
+ }
477
+ const handle = ex.wasm_ctx_create_framebuffer(this._ctxHandle);
478
+ if (handle === 0) {
479
+ const msg = readErrorMessage(this._instance);
480
+ throw new Error(`Failed to create framebuffer: ${msg}`);
481
+ }
482
+ return new WasmWebGLFramebuffer(this, handle);
483
+ }
484
+
485
+ deleteFramebuffer(fb) {
486
+ this._assertNotDestroyed();
487
+ const ex = this._instance.exports;
488
+ if (!ex || typeof ex.wasm_ctx_delete_framebuffer !== 'function') {
489
+ throw new Error('wasm_ctx_delete_framebuffer not found');
490
+ }
491
+ const handle = fb && typeof fb === 'object' && typeof fb._handle === 'number' ? fb._handle : (fb >>> 0);
492
+ const code = ex.wasm_ctx_delete_framebuffer(this._ctxHandle, handle);
493
+ _checkErr(code, this._instance);
494
+ if (fb && typeof fb === 'object') {
495
+ try { fb._handle = 0; fb._deleted = true; } catch (e) { /* ignore */ }
496
+ }
497
+ }
498
+
499
+ bindFramebuffer(target, fb) {
500
+ this._assertNotDestroyed();
501
+ const ex = this._instance.exports;
502
+ if (!ex || typeof ex.wasm_ctx_bind_framebuffer !== 'function') {
503
+ throw new Error('wasm_ctx_bind_framebuffer not found');
504
+ }
505
+ const handle = fb && typeof fb === 'object' && typeof fb._handle === 'number' ? fb._handle : (fb >>> 0);
506
+ const code = ex.wasm_ctx_bind_framebuffer(this._ctxHandle, target >>> 0, handle);
507
+ _checkErr(code, this._instance);
508
+ }
509
+
510
+ framebufferTexture2D(target, attachment, textarget, texture, level) {
511
+ this._assertNotDestroyed();
512
+ const ex = this._instance.exports;
513
+ if (!ex || typeof ex.wasm_ctx_framebuffer_texture2d !== 'function') {
514
+ throw new Error('wasm_ctx_framebuffer_texture2d not found');
515
+ }
516
+ const texHandle = texture && typeof texture === 'object' && typeof texture._handle === 'number' ? texture._handle : (texture >>> 0);
517
+ const code = ex.wasm_ctx_framebuffer_texture2d(
518
+ this._ctxHandle,
519
+ target >>> 0,
520
+ attachment >>> 0,
521
+ textarget >>> 0,
522
+ texHandle,
523
+ level >>> 0
524
+ );
525
+ _checkErr(code, this._instance);
526
+ }
527
+
528
+ createRenderbuffer() {
529
+ this._assertNotDestroyed();
530
+ const ex = this._instance.exports;
531
+ if (!ex || typeof ex.wasm_ctx_create_renderbuffer !== 'function') {
532
+ throw new Error('wasm_ctx_create_renderbuffer not found');
533
+ }
534
+ const handle = ex.wasm_ctx_create_renderbuffer(this._ctxHandle);
535
+ if (handle === 0) {
536
+ const msg = readErrorMessage(this._instance);
537
+ throw new Error(`Failed to create renderbuffer: ${msg}`);
538
+ }
539
+ return new WasmWebGLRenderbuffer(this, handle);
540
+ }
541
+
542
+ bindRenderbuffer(target, renderbuffer) {
543
+ this._assertNotDestroyed();
544
+ const ex = this._instance.exports;
545
+ if (!ex || typeof ex.wasm_ctx_bind_renderbuffer !== 'function') {
546
+ throw new Error('wasm_ctx_bind_renderbuffer not found');
547
+ }
548
+ const rbHandle = renderbuffer && typeof renderbuffer === 'object' && typeof renderbuffer._handle === 'number' ? renderbuffer._handle : (renderbuffer >>> 0);
549
+ const code = ex.wasm_ctx_bind_renderbuffer(this._ctxHandle, target >>> 0, rbHandle);
550
+ _checkErr(code, this._instance);
551
+ }
552
+
553
+ deleteRenderbuffer(renderbuffer) {
554
+ this._assertNotDestroyed();
555
+ const ex = this._instance.exports;
556
+ if (!ex || typeof ex.wasm_ctx_delete_renderbuffer !== 'function') {
557
+ throw new Error('wasm_ctx_delete_renderbuffer not found');
558
+ }
559
+ const rbHandle = renderbuffer && typeof renderbuffer === 'object' && typeof renderbuffer._handle === 'number' ? renderbuffer._handle : (renderbuffer >>> 0);
560
+ const code = ex.wasm_ctx_delete_renderbuffer(this._ctxHandle, rbHandle);
561
+ _checkErr(code, this._instance);
562
+ }
563
+
564
+ isRenderbuffer(rb) {
565
+ this._assertNotDestroyed();
566
+ if (!rb || typeof rb !== 'object' || !(rb instanceof WasmWebGLRenderbuffer)) return false;
567
+ if (rb._ctx !== this) return false;
568
+ const ex = this._instance.exports;
569
+ return ex.wasm_ctx_is_renderbuffer(this._ctxHandle, rb._handle) !== 0;
570
+ }
571
+
572
+ renderbufferStorage(target, internalFormat, width, height) {
573
+ this._assertNotDestroyed();
574
+ const ex = this._instance.exports;
575
+ if (!ex || typeof ex.wasm_ctx_renderbuffer_storage !== 'function') {
576
+ throw new Error('wasm_ctx_renderbuffer_storage not found');
577
+ }
578
+ const code = ex.wasm_ctx_renderbuffer_storage(this._ctxHandle, target >>> 0, internalFormat >>> 0, width | 0, height | 0);
579
+ _checkErr(code, this._instance);
580
+ }
581
+
582
+ framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) {
583
+ this._assertNotDestroyed();
584
+ const ex = this._instance.exports;
585
+ if (!ex || typeof ex.wasm_ctx_framebuffer_renderbuffer !== 'function') {
586
+ throw new Error('wasm_ctx_framebuffer_renderbuffer not found');
587
+ }
588
+ const rbHandle = renderbuffer && typeof renderbuffer === 'object' && typeof renderbuffer._handle === 'number' ? renderbuffer._handle : (renderbuffer >>> 0);
589
+ const code = ex.wasm_ctx_framebuffer_renderbuffer(
590
+ this._ctxHandle,
591
+ target >>> 0,
592
+ attachment >>> 0,
593
+ renderbuffertarget >>> 0,
594
+ rbHandle
595
+ );
596
+ _checkErr(code, this._instance);
597
+ }
598
+
599
+ readPixels(x, y, width, height, format, type_, out) {
600
+ this._assertNotDestroyed();
601
+ const ex = this._instance.exports;
602
+ if (!ex || typeof ex.wasm_ctx_read_pixels !== 'function') {
603
+ throw new Error('wasm_ctx_read_pixels not found');
604
+ }
605
+
606
+ let bpp = 4;
607
+ if (type_ === 0x1406) { // GL_FLOAT
608
+ if (format === 0x1908) bpp = 16; // GL_RGBA
609
+ else if (format === 0x8227) bpp = 8; // GL_RG
610
+ else if (format === 0x1903) bpp = 4; // GL_RED
611
+ } else if (type_ === 0x1401) { // GL_UNSIGNED_BYTE
612
+ if (format === 0x1908) bpp = 4;
613
+ }
614
+
615
+ const len = width * height * bpp;
616
+ if (!out || out.byteLength < len) {
617
+ throw new Error(`output buffer too small (need ${len} bytes, have ${out ? out.byteLength : 0})`);
618
+ }
619
+
620
+ const ptr = ex.wasm_alloc(len);
621
+ if (ptr === 0) throw new Error('Failed to allocate memory for readPixels output');
622
+
623
+ try {
624
+ const code = ex.wasm_ctx_read_pixels(
625
+ this._ctxHandle,
626
+ x | 0,
627
+ y | 0,
628
+ width >>> 0,
629
+ height >>> 0,
630
+ format >>> 0,
631
+ type_ >>> 0,
632
+ ptr >>> 0,
633
+ len >>> 0
634
+ );
635
+ _checkErr(code, this._instance);
636
+
637
+ const mem = new Uint8Array(ex.memory.buffer);
638
+ const src = mem.subarray(ptr, ptr + len);
639
+ const out_bytes = new Uint8Array(out.buffer, out.byteOffset, len);
640
+ out_bytes.set(src);
641
+ } finally {
642
+ ex.wasm_free(ptr);
643
+ }
644
+ }
645
+
646
+ // --- Stubs for unimplemented WebGL2 methods (forwarding API surface) ---
647
+ // These are intentionally not implemented in the prototype. They allow
648
+ // callers to detect missing functionality early with a uniform error.
649
+
650
+ createShader(type) {
651
+ this._assertNotDestroyed();
652
+ const ex = this._instance.exports;
653
+ if (!ex || typeof ex.wasm_ctx_create_shader !== 'function') {
654
+ throw new Error('wasm_ctx_create_shader not found');
655
+ }
656
+ const handle = ex.wasm_ctx_create_shader(this._ctxHandle, type >>> 0);
657
+ if (handle === 0) {
658
+ const msg = readErrorMessage(this._instance);
659
+ throw new Error(`Failed to create shader: ${msg}`);
660
+ }
661
+ return new WasmWebGLShader(this, handle);
662
+ }
663
+
664
+ shaderSource(shader, source) {
665
+ this._assertNotDestroyed();
666
+ const ex = this._instance.exports;
667
+ if (!ex || typeof ex.wasm_ctx_shader_source !== 'function') {
668
+ throw new Error('wasm_ctx_shader_source not found');
669
+ }
670
+
671
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
672
+ const sourceStr = String(source);
673
+ const bytes = new TextEncoder().encode(sourceStr);
674
+ const len = bytes.length;
675
+ const ptr = ex.wasm_alloc(len);
676
+ if (ptr === 0) throw new Error('Failed to allocate memory for shaderSource');
677
+
678
+ try {
679
+ const mem = new Uint8Array(ex.memory.buffer);
680
+ mem.set(bytes, ptr);
681
+ const code = ex.wasm_ctx_shader_source(this._ctxHandle, shaderHandle, ptr, len);
682
+ _checkErr(code, this._instance);
683
+ } finally {
684
+ ex.wasm_free(ptr);
685
+ }
686
+ }
687
+
688
+ compileShader(shader) {
689
+ this._assertNotDestroyed();
690
+ const ex = this._instance.exports;
691
+ if (!ex || typeof ex.wasm_ctx_compile_shader !== 'function') {
692
+ throw new Error('wasm_ctx_compile_shader not found');
693
+ }
694
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
695
+ const code = ex.wasm_ctx_compile_shader(this._ctxHandle, shaderHandle);
696
+ _checkErr(code, this._instance);
697
+ }
698
+
699
+ deleteShader(shader) {
700
+ this._assertNotDestroyed();
701
+ const ex = this._instance.exports;
702
+ if (!ex || typeof ex.wasm_ctx_delete_shader !== 'function') {
703
+ throw new Error('wasm_ctx_delete_shader not found');
704
+ }
705
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
706
+ const code = ex.wasm_ctx_delete_shader(this._ctxHandle, shaderHandle);
707
+ _checkErr(code, this._instance);
708
+ if (shader && typeof shader === 'object') {
709
+ try { shader._handle = 0; shader._deleted = true; } catch (e) { /* ignore */ }
710
+ }
711
+ }
712
+
713
+ createProgram() {
714
+ this._assertNotDestroyed();
715
+ const ex = this._instance.exports;
716
+ if (!ex || typeof ex.wasm_ctx_create_program !== 'function') {
717
+ throw new Error('wasm_ctx_create_program not found');
718
+ }
719
+ const handle = ex.wasm_ctx_create_program(this._ctxHandle);
720
+ if (handle === 0) {
721
+ const msg = readErrorMessage(this._instance);
722
+ throw new Error(`Failed to create program: ${msg}`);
723
+ }
724
+ return new WasmWebGLProgram(this, handle);
725
+ }
726
+
727
+ attachShader(program, shader) {
728
+ this._assertNotDestroyed();
729
+ const ex = this._instance.exports;
730
+ if (!ex || typeof ex.wasm_ctx_attach_shader !== 'function') {
731
+ throw new Error('wasm_ctx_attach_shader not found');
732
+ }
733
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
734
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
735
+ const code = ex.wasm_ctx_attach_shader(this._ctxHandle, programHandle, shaderHandle);
736
+ _checkErr(code, this._instance);
737
+ }
738
+
739
+ detachShader(program, shader) { this._assertNotDestroyed(); throw new Error('not implemented'); }
740
+
741
+ getActiveUniform(program, index) {
742
+ this._assertNotDestroyed();
743
+ const ex = this._instance.exports;
744
+ if (!ex || typeof ex.wasm_ctx_get_active_uniform !== 'function') {
745
+ throw new Error('wasm_ctx_get_active_uniform not found');
746
+ }
747
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
748
+
749
+ // Allocate buffers: size(4) + type(4) + name(256)
750
+ const sizePtr = ex.wasm_alloc(4);
751
+ const typePtr = ex.wasm_alloc(4);
752
+ const nameMaxLen = 256;
753
+ const namePtr = ex.wasm_alloc(nameMaxLen);
754
+
755
+ try {
756
+ const nameLen = ex.wasm_ctx_get_active_uniform(
757
+ this._ctxHandle,
758
+ programHandle,
759
+ index >>> 0,
760
+ sizePtr,
761
+ typePtr,
762
+ namePtr,
763
+ nameMaxLen
764
+ );
765
+
766
+ if (nameLen === 0) {
767
+ return null;
768
+ }
769
+
770
+ const mem32SizeIdx = sizePtr >>> 2;
771
+ const mem32TypeIdx = typePtr >>> 2;
772
+
773
+ const size = new Int32Array(ex.memory.buffer)[mem32SizeIdx];
774
+ const type_ = new Uint32Array(ex.memory.buffer)[mem32TypeIdx];
775
+
776
+ const nameBytes = new Uint8Array(ex.memory.buffer, namePtr, nameLen);
777
+ const name = new TextDecoder().decode(nameBytes);
778
+
779
+ return { name, size, type: type_ };
780
+
781
+ } finally {
782
+ ex.wasm_free(sizePtr);
783
+ ex.wasm_free(typePtr);
784
+ ex.wasm_free(namePtr);
785
+ }
786
+ }
787
+
788
+ getActiveAttrib(program, index) {
789
+ this._assertNotDestroyed();
790
+ const ex = this._instance.exports;
791
+ if (!ex || typeof ex.wasm_ctx_get_active_attrib !== 'function') {
792
+ throw new Error('wasm_ctx_get_active_attrib not found');
793
+ }
794
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
795
+
796
+ // Allocate buffers: size(4) + type(4) + name(256)
797
+ const sizePtr = ex.wasm_alloc(4);
798
+ const typePtr = ex.wasm_alloc(4);
799
+ const nameMaxLen = 256;
800
+ const namePtr = ex.wasm_alloc(nameMaxLen);
801
+
802
+ try {
803
+ const nameLen = ex.wasm_ctx_get_active_attrib(
804
+ this._ctxHandle,
805
+ programHandle,
806
+ index >>> 0,
807
+ sizePtr,
808
+ typePtr,
809
+ namePtr,
810
+ nameMaxLen
811
+ );
812
+
813
+ if (nameLen === 0) {
814
+ return null;
815
+ }
816
+
817
+ const mem32SizeIdx = sizePtr >>> 2;
818
+ const mem32TypeIdx = typePtr >>> 2;
819
+
820
+ const size = new Int32Array(ex.memory.buffer)[mem32SizeIdx];
821
+ const type_ = new Uint32Array(ex.memory.buffer)[mem32TypeIdx];
822
+
823
+ const nameBytes = new Uint8Array(ex.memory.buffer, namePtr, nameLen);
824
+ const name = new TextDecoder().decode(nameBytes);
825
+
826
+ return { name, size, type: type_ };
827
+
828
+ } finally {
829
+ ex.wasm_free(sizePtr);
830
+ ex.wasm_free(typePtr);
831
+ ex.wasm_free(namePtr);
832
+ }
833
+ }
834
+
835
+ linkProgram(program) {
836
+ this._assertNotDestroyed();
837
+ const ex = this._instance.exports;
838
+ if (!ex || typeof ex.wasm_ctx_link_program !== 'function') {
839
+ throw new Error('wasm_ctx_link_program not found');
840
+ }
841
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
842
+ const code = ex.wasm_ctx_link_program(this._ctxHandle, programHandle);
843
+ _checkErr(code, this._instance);
844
+
845
+ // After linking, we need to instantiate the WASM modules on the host.
846
+ if (program && typeof program === 'object') {
847
+ const linkStatus = this.getProgramParameter(program, this.LINK_STATUS);
848
+ if (linkStatus) {
849
+ this._instantiateProgramShaders(program);
850
+ }
851
+ }
852
+ }
853
+
854
+ _instantiateProgramShaders(program) {
855
+ const vsWasm = this.getProgramWasm(program, this.VERTEX_SHADER);
856
+ const fsWasm = this.getProgramWasm(program, this.FRAGMENT_SHADER);
857
+
858
+ if (!vsWasm || !fsWasm) {
859
+ return;
860
+ }
861
+
862
+ // Allocate table slots for both shaders
863
+ const vsIdx = this._tableAllocator ? this._tableAllocator.allocate() : null;
864
+ const fsIdx = this._tableAllocator ? this._tableAllocator.allocate() : null;
865
+
866
+ const createDebugEnv = (type, instanceRef) => {
867
+ if (!this._debugShaders) return {};
868
+
869
+ const stubCode = this.getProgramDebugStub(program, type);
870
+ if (!stubCode) return {};
871
+
872
+ // // Add sourceURL for debugging
873
+ // const debugName = `shader_stub_program_${program._handle}_${type === this.VERTEX_SHADER ? 'vs' : 'fs'}.js`;
874
+ // const codeWithUrl = stubCode + `\n//# sourceURL=${debugName}`;
875
+
876
+ let stubFuncs;
877
+ try {
878
+ // Eval the stub array
879
+ stubFuncs = (0, eval)(stubCode);
880
+ } catch (e) {
881
+ console.error("Failed to eval debug stub:", e);
882
+ return {};
883
+ }
884
+
885
+ return {
886
+ debug_step: (line, funcIdx, resultPtr) => {
887
+ if (line === 999999) {
888
+ return;
889
+ }
890
+ const func = stubFuncs[line - 1];
891
+ if (func) {
892
+ const ctx = {
893
+ go: () => {
894
+ // Trampoline logic would go here
895
+ // For now we rely on WASM calling the function after debug_step returns
896
+ }
897
+ };
898
+ try {
899
+ func.call(ctx);
900
+ } catch (e) {
901
+ console.error("Error in debug stub:", e);
902
+ }
903
+ }
904
+ }
905
+ };
906
+ };
907
+
908
+ let vsModule;
909
+ vsModule = new WebAssembly.Module(vsWasm);
910
+ const vsInstanceRef = { current: null };
911
+ const vsDebugEnv = createDebugEnv(this.VERTEX_SHADER, vsInstanceRef);
912
+
913
+ const env = {
914
+ memory: this._instance.exports.memory,
915
+ __indirect_function_table: this._sharedTable,
916
+ ACTIVE_ATTR_PTR: this._turboGlobals.ACTIVE_ATTR_PTR,
917
+ ACTIVE_UNIFORM_PTR: this._turboGlobals.ACTIVE_UNIFORM_PTR,
918
+ ACTIVE_VARYING_PTR: this._turboGlobals.ACTIVE_VARYING_PTR,
919
+ ACTIVE_PRIVATE_PTR: this._turboGlobals.ACTIVE_PRIVATE_PTR,
920
+ ACTIVE_TEXTURE_PTR: this._turboGlobals.ACTIVE_TEXTURE_PTR,
921
+ ACTIVE_FRAME_SP: this._turboGlobals.ACTIVE_FRAME_SP,
922
+ ...vsDebugEnv
923
+ };
924
+
925
+ // Add math builtins from renderer (skipping host)
926
+ const mathFuncs = [
927
+ 'gl_sin', 'gl_cos', 'gl_tan', 'gl_asin', 'gl_acos', 'gl_atan', 'gl_atan2',
928
+ 'gl_exp', 'gl_exp2', 'gl_log', 'gl_log2', 'gl_pow',
929
+ 'gl_sinh', 'gl_cosh', 'gl_tanh', 'gl_asinh', 'gl_acosh', 'gl_atanh'
930
+ ];
931
+ for (const name of mathFuncs) {
932
+ if (this._instance.exports[name]) {
933
+ env[name] = this._instance.exports[name];
934
+ }
935
+ }
936
+
937
+ program._vsInstance = new WebAssembly.Instance(vsModule, {
938
+ env
939
+ });
940
+ vsInstanceRef.current = program._vsInstance;
941
+
942
+ // Register in table
943
+ if (this._sharedTable && vsIdx !== null && program._vsInstance.exports.main) {
944
+ this._sharedTable.set(vsIdx, program._vsInstance.exports.main);
945
+ program._vsTableIndex = vsIdx;
946
+ }
947
+
948
+ let fsModule;
949
+ fsModule = new WebAssembly.Module(fsWasm);
950
+ const fsInstanceRef = { current: null };
951
+ const fsDebugEnv = createDebugEnv(this.FRAGMENT_SHADER, fsInstanceRef);
952
+
953
+ const fsEnv = {
954
+ memory: this._instance.exports.memory,
955
+ __indirect_function_table: this._sharedTable,
956
+ ACTIVE_ATTR_PTR: this._turboGlobals.ACTIVE_ATTR_PTR,
957
+ ACTIVE_UNIFORM_PTR: this._turboGlobals.ACTIVE_UNIFORM_PTR,
958
+ ACTIVE_VARYING_PTR: this._turboGlobals.ACTIVE_VARYING_PTR,
959
+ ACTIVE_PRIVATE_PTR: this._turboGlobals.ACTIVE_PRIVATE_PTR,
960
+ ACTIVE_TEXTURE_PTR: this._turboGlobals.ACTIVE_TEXTURE_PTR,
961
+ ACTIVE_FRAME_SP: this._turboGlobals.ACTIVE_FRAME_SP,
962
+ ...fsDebugEnv
963
+ };
964
+
965
+ for (const name of mathFuncs) {
966
+ if (this._instance.exports[name]) {
967
+ fsEnv[name] = this._instance.exports[name];
968
+ }
969
+ }
970
+
971
+ program._fsInstance = new WebAssembly.Instance(fsModule, {
972
+ env: fsEnv
973
+ });
974
+ fsInstanceRef.current = program._fsInstance;
975
+
976
+ // Register in table
977
+ if (this._sharedTable && fsIdx !== null && program._fsInstance.exports.main) {
978
+ this._sharedTable.set(fsIdx, program._fsInstance.exports.main);
979
+ program._fsTableIndex = fsIdx;
980
+ }
981
+
982
+ // Notify Rust of table indices (requires Phase 4)
983
+ if (vsIdx !== null && fsIdx !== null) {
984
+ const ex = this._instance.exports;
985
+ if (ex.wasm_ctx_register_shader_indices) {
986
+ ex.wasm_ctx_register_shader_indices(
987
+ this._ctxHandle,
988
+ program._handle,
989
+ vsIdx,
990
+ fsIdx
991
+ );
992
+ }
993
+ }
994
+ }
995
+
996
+ getProgramDebugStub(program, shaderType) {
997
+ this._assertNotDestroyed();
998
+ const ex = this._instance.exports;
999
+ if (!ex || typeof ex.wasm_ctx_get_program_debug_stub !== 'function') {
1000
+ return null;
1001
+ }
1002
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1003
+ const len = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, 0, 0);
1004
+ if (len === 0) return null;
1005
+
1006
+ const ptr = ex.wasm_alloc(len);
1007
+ if (ptr === 0) return null;
1008
+
1009
+ try {
1010
+ const actualLen = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, ptr, len);
1011
+ const mem = new Uint8Array(ex.memory.buffer);
1012
+ const bytes = mem.subarray(ptr, ptr + actualLen);
1013
+ return new TextDecoder().decode(bytes);
1014
+ } finally {
1015
+ ex.wasm_free(ptr);
1016
+ }
1017
+ }
1018
+
1019
+ deleteProgram(program) {
1020
+ this._assertNotDestroyed();
1021
+ const ex = this._instance.exports;
1022
+ if (!ex || typeof ex.wasm_ctx_delete_program !== 'function') {
1023
+ throw new Error('wasm_ctx_delete_program not found');
1024
+ }
1025
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1026
+
1027
+ // Table indices are now freed by Rust when the Program's refcount reaches zero.
1028
+ // This allows bound programs to remain valid even if deleted by the user,
1029
+ // as required by the WebGL specification.
1030
+
1031
+ const code = ex.wasm_ctx_delete_program(this._ctxHandle, programHandle);
1032
+ _checkErr(code, this._instance);
1033
+ if (program && typeof program === 'object') {
1034
+ try { program._handle = 0; program._deleted = true; } catch (e) { /* ignore */ }
1035
+ }
1036
+ }
1037
+
1038
+ useProgram(program) {
1039
+ this._assertNotDestroyed();
1040
+ const ex = this._instance.exports;
1041
+ if (!ex || typeof ex.wasm_ctx_use_program !== 'function') {
1042
+ throw new Error('wasm_ctx_use_program not found');
1043
+ }
1044
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1045
+ const code = ex.wasm_ctx_use_program(this._ctxHandle, programHandle);
1046
+ _checkErr(code, this._instance);
1047
+ this._currentProgram = program;
1048
+ }
1049
+
1050
+ getShaderParameter(shader, pname) {
1051
+ this._assertNotDestroyed();
1052
+ const ex = this._instance.exports;
1053
+ if (!ex || typeof ex.wasm_ctx_get_shader_parameter !== 'function') {
1054
+ throw new Error('wasm_ctx_get_shader_parameter not found');
1055
+ }
1056
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
1057
+ const val = ex.wasm_ctx_get_shader_parameter(this._ctxHandle, shaderHandle, pname >>> 0);
1058
+
1059
+ // WebGL returns boolean for status parameters
1060
+ if (pname === 0x8B81 /* COMPILE_STATUS */ || pname === 0x8B80 /* DELETE_STATUS */) {
1061
+ return !!val;
1062
+ }
1063
+ return val;
1064
+ }
1065
+
1066
+ getProgramParameter(program, pname) {
1067
+ this._assertNotDestroyed();
1068
+ const ex = this._instance.exports;
1069
+ if (!ex || typeof ex.wasm_ctx_get_program_parameter !== 'function') {
1070
+ throw new Error('wasm_ctx_get_program_parameter not found');
1071
+ }
1072
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1073
+ const val = ex.wasm_ctx_get_program_parameter(this._ctxHandle, programHandle, pname >>> 0);
1074
+
1075
+ // WebGL returns boolean for status parameters
1076
+ if (pname === 0x8B82 /* LINK_STATUS */ || pname === 0x8B80 /* DELETE_STATUS */ || pname === 0x8B83 /* VALIDATE_STATUS */) {
1077
+ return !!val;
1078
+ }
1079
+ return val;
1080
+ }
1081
+
1082
+ getShaderInfoLog(shader) {
1083
+ this._assertNotDestroyed();
1084
+ const ex = this._instance.exports;
1085
+ if (!ex || typeof ex.wasm_ctx_get_shader_info_log !== 'function') {
1086
+ throw new Error('wasm_ctx_get_shader_info_log not found');
1087
+ }
1088
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
1089
+
1090
+ const maxLen = 1024;
1091
+ const ptr = ex.wasm_alloc(maxLen);
1092
+ if (ptr === 0) throw new Error('Failed to allocate memory for getShaderInfoLog');
1093
+
1094
+ try {
1095
+ const len = ex.wasm_ctx_get_shader_info_log(this._ctxHandle, shaderHandle, ptr, maxLen);
1096
+ const mem = new Uint8Array(ex.memory.buffer);
1097
+ const bytes = mem.subarray(ptr, ptr + len);
1098
+ return new TextDecoder().decode(bytes);
1099
+ } finally {
1100
+ ex.wasm_free(ptr);
1101
+ }
1102
+ }
1103
+
1104
+ getProgramInfoLog(program) {
1105
+ this._assertNotDestroyed();
1106
+ const ex = this._instance.exports;
1107
+ if (!ex || typeof ex.wasm_ctx_get_program_info_log !== 'function') {
1108
+ throw new Error('wasm_ctx_get_program_info_log not found');
1109
+ }
1110
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1111
+
1112
+ const maxLen = 1024;
1113
+ const ptr = ex.wasm_alloc(maxLen);
1114
+ if (ptr === 0) throw new Error('Failed to allocate memory for getProgramInfoLog');
1115
+
1116
+ try {
1117
+ const len = ex.wasm_ctx_get_program_info_log(this._ctxHandle, programHandle, ptr, maxLen);
1118
+ const mem = new Uint8Array(ex.memory.buffer);
1119
+ const bytes = mem.subarray(ptr, ptr + len);
1120
+ return new TextDecoder().decode(bytes);
1121
+ } finally {
1122
+ ex.wasm_free(ptr);
1123
+ }
1124
+ }
1125
+
1126
+ getProgramWasm(program, shaderType) {
1127
+ this._assertNotDestroyed();
1128
+ const ex = this._instance.exports;
1129
+ if (!ex || typeof ex.wasm_ctx_get_program_wasm_len !== 'function') {
1130
+ throw new Error('wasm_ctx_get_program_wasm_len not found');
1131
+ }
1132
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1133
+ const len = ex.wasm_ctx_get_program_wasm_len(this._ctxHandle, programHandle, shaderType);
1134
+ if (len === 0) return null;
1135
+
1136
+ const ptr = ex.wasm_alloc(len);
1137
+ if (ptr === 0) throw new Error('Failed to allocate memory for getProgramWasm');
1138
+
1139
+ try {
1140
+ const actualLen = ex.wasm_ctx_get_program_wasm(this._ctxHandle, programHandle, shaderType, ptr, len);
1141
+ const mem = new Uint8Array(ex.memory.buffer);
1142
+ return new Uint8Array(mem.buffer, ptr, actualLen).slice();
1143
+ } finally {
1144
+ ex.wasm_free(ptr);
1145
+ }
1146
+ }
1147
+
1148
+ getAttribLocation(program, name) {
1149
+ this._assertNotDestroyed();
1150
+ const ex = this._instance.exports;
1151
+ if (!ex || typeof ex.wasm_ctx_get_attrib_location !== 'function') {
1152
+ throw new Error('wasm_ctx_get_attrib_location not found');
1153
+ }
1154
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1155
+ const nameStr = String(name);
1156
+ const bytes = new TextEncoder().encode(nameStr);
1157
+ const len = bytes.length;
1158
+ const ptr = ex.wasm_alloc(len);
1159
+ if (ptr === 0) throw new Error('Failed to allocate memory for getAttribLocation');
1160
+
1161
+ try {
1162
+ const mem = new Uint8Array(ex.memory.buffer);
1163
+ mem.set(bytes, ptr);
1164
+ return ex.wasm_ctx_get_attrib_location(this._ctxHandle, programHandle, ptr, len);
1165
+ } finally {
1166
+ ex.wasm_free(ptr);
1167
+ }
1168
+ }
1169
+
1170
+ bindAttribLocation(program, index, name) {
1171
+ this._assertNotDestroyed();
1172
+ const ex = this._instance.exports;
1173
+ if (!ex || typeof ex.wasm_ctx_bind_attrib_location !== 'function') {
1174
+ throw new Error('wasm_ctx_bind_attrib_location not found');
1175
+ }
1176
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1177
+ const nameStr = String(name);
1178
+ const bytes = new TextEncoder().encode(nameStr);
1179
+ const len = bytes.length;
1180
+ const ptr = ex.wasm_alloc(len);
1181
+ if (ptr === 0) throw new Error('Failed to allocate memory for bindAttribLocation');
1182
+
1183
+ try {
1184
+ const mem = new Uint8Array(ex.memory.buffer);
1185
+ mem.set(bytes, ptr);
1186
+ const code = ex.wasm_ctx_bind_attrib_location(this._ctxHandle, programHandle, index >>> 0, ptr, len);
1187
+ _checkErr(code, this._instance);
1188
+ } finally {
1189
+ ex.wasm_free(ptr);
1190
+ }
1191
+ }
1192
+
1193
+ enableVertexAttribArray(index) {
1194
+ this._assertNotDestroyed();
1195
+ const ex = this._instance.exports;
1196
+ if (!ex || typeof ex.wasm_ctx_enable_vertex_attrib_array !== 'function') {
1197
+ throw new Error('wasm_ctx_enable_vertex_attrib_array not found');
1198
+ }
1199
+ const code = ex.wasm_ctx_enable_vertex_attrib_array(this._ctxHandle, index >>> 0);
1200
+ _checkErr(code, this._instance);
1201
+ }
1202
+
1203
+ disableVertexAttribArray(index) {
1204
+ this._assertNotDestroyed();
1205
+ const ex = this._instance.exports;
1206
+ if (!ex || typeof ex.wasm_ctx_disable_vertex_attrib_array !== 'function') {
1207
+ throw new Error('wasm_ctx_disable_vertex_attrib_array not found');
1208
+ }
1209
+ const code = ex.wasm_ctx_disable_vertex_attrib_array(this._ctxHandle, index >>> 0);
1210
+ _checkErr(code, this._instance);
1211
+ }
1212
+
1213
+ vertexAttribPointer(index, size, type, normalized, stride, offset) {
1214
+ this._assertNotDestroyed();
1215
+ const ex = this._instance.exports;
1216
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_pointer !== 'function') {
1217
+ throw new Error('wasm_ctx_vertex_attrib_pointer not found');
1218
+ }
1219
+ const code = ex.wasm_ctx_vertex_attrib_pointer(
1220
+ this._ctxHandle,
1221
+ index >>> 0,
1222
+ size >>> 0,
1223
+ type >>> 0,
1224
+ normalized ? 1 : 0,
1225
+ stride >>> 0,
1226
+ offset >>> 0
1227
+ );
1228
+ if (code === 5) return; // ERR_GL
1229
+ _checkErr(code, this._instance);
1230
+ }
1231
+
1232
+ vertexAttribIPointer(index, size, type, stride, offset) {
1233
+ this._assertNotDestroyed();
1234
+ const ex = this._instance.exports;
1235
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_ipointer !== 'function') {
1236
+ throw new Error('wasm_ctx_vertex_attrib_ipointer not found');
1237
+ }
1238
+ const code = ex.wasm_ctx_vertex_attrib_ipointer(
1239
+ this._ctxHandle,
1240
+ index >>> 0,
1241
+ size >>> 0,
1242
+ type >>> 0,
1243
+ stride >>> 0,
1244
+ offset >>> 0
1245
+ );
1246
+ if (code === 5) return; // ERR_GL
1247
+ _checkErr(code, this._instance);
1248
+ }
1249
+
1250
+ vertexAttrib1f(index, v0) {
1251
+ this._assertNotDestroyed();
1252
+ const ex = this._instance.exports;
1253
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib1f !== 'function') {
1254
+ throw new Error('wasm_ctx_vertex_attrib1f not found');
1255
+ }
1256
+ const code = ex.wasm_ctx_vertex_attrib1f(this._ctxHandle, index >>> 0, +v0);
1257
+ if (code === 5) return; // ERR_GL
1258
+ _checkErr(code, this._instance);
1259
+ }
1260
+ vertexAttrib2f(index, v0, v1) {
1261
+ this._assertNotDestroyed();
1262
+ const ex = this._instance.exports;
1263
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib2f !== 'function') {
1264
+ throw new Error('wasm_ctx_vertex_attrib2f not found');
1265
+ }
1266
+ const code = ex.wasm_ctx_vertex_attrib2f(this._ctxHandle, index >>> 0, +v0, +v1);
1267
+ if (code === 5) return; // ERR_GL
1268
+ _checkErr(code, this._instance);
1269
+ }
1270
+ vertexAttrib3f(index, v0, v1, v2) {
1271
+ this._assertNotDestroyed();
1272
+ const ex = this._instance.exports;
1273
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib3f !== 'function') {
1274
+ throw new Error('wasm_ctx_vertex_attrib3f not found');
1275
+ }
1276
+ const code = ex.wasm_ctx_vertex_attrib3f(this._ctxHandle, index >>> 0, +v0, +v1, +v2);
1277
+ if (code === 5) return; // ERR_GL
1278
+ _checkErr(code, this._instance);
1279
+ }
1280
+ vertexAttrib4f(index, v0, v1, v2, v3) {
1281
+ this._assertNotDestroyed();
1282
+ const ex = this._instance.exports;
1283
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib4f !== 'function') {
1284
+ throw new Error('wasm_ctx_vertex_attrib4f not found');
1285
+ }
1286
+ const code = ex.wasm_ctx_vertex_attrib4f(this._ctxHandle, index >>> 0, +v0, +v1, +v2, +v3);
1287
+ if (code === 5) return; // ERR_GL
1288
+ _checkErr(code, this._instance);
1289
+ }
1290
+
1291
+ vertexAttrib1fv(index, v) {
1292
+ if (v && v.length >= 1) {
1293
+ this.vertexAttrib1f(index, v[0]);
1294
+ } else {
1295
+ this._setError(0x0501);
1296
+ }
1297
+ }
1298
+ vertexAttrib2fv(index, v) {
1299
+ if (v && v.length >= 2) {
1300
+ this.vertexAttrib2f(index, v[0], v[1]);
1301
+ } else {
1302
+ this._setError(0x0501);
1303
+ }
1304
+ }
1305
+ vertexAttrib3fv(index, v) {
1306
+ if (v && v.length >= 3) {
1307
+ this.vertexAttrib3f(index, v[0], v[1], v[2]);
1308
+ } else {
1309
+ this._setError(0x0501);
1310
+ }
1311
+ }
1312
+ vertexAttrib4fv(index, v) {
1313
+ if (v && v.length >= 4) {
1314
+ this.vertexAttrib4f(index, v[0], v[1], v[2], v[3]);
1315
+ } else {
1316
+ this._setError(0x0501);
1317
+ }
1318
+ }
1319
+
1320
+ vertexAttribI4i(index, v0, v1, v2, v3) {
1321
+ this._assertNotDestroyed();
1322
+ const ex = this._instance.exports;
1323
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_i4i !== 'function') {
1324
+ throw new Error('wasm_ctx_vertex_attrib_i4i not found');
1325
+ }
1326
+ const code = ex.wasm_ctx_vertex_attrib_i4i(this._ctxHandle, index >>> 0, v0 | 0, v1 | 0, v2 | 0, v3 | 0);
1327
+ if (code === 5) return; // ERR_GL
1328
+ _checkErr(code, this._instance);
1329
+ }
1330
+
1331
+ vertexAttribI4ui(index, v0, v1, v2, v3) {
1332
+ this._assertNotDestroyed();
1333
+ const ex = this._instance.exports;
1334
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_i4ui !== 'function') {
1335
+ throw new Error('wasm_ctx_vertex_attrib_i4ui not found');
1336
+ }
1337
+ const code = ex.wasm_ctx_vertex_attrib_i4ui(this._ctxHandle, index >>> 0, v0 >>> 0, v1 >>> 0, v2 >>> 0, v3 >>> 0);
1338
+ if (code === 5) return; // ERR_GL
1339
+ _checkErr(code, this._instance);
1340
+ }
1341
+
1342
+ vertexAttribI4iv(index, v) {
1343
+ if (v && v.length >= 4) {
1344
+ this.vertexAttribI4i(index, v[0], v[1], v[2], v[3]);
1345
+ } else {
1346
+ this._setError(0x0501);
1347
+ }
1348
+ }
1349
+
1350
+ vertexAttribI4uiv(index, v) {
1351
+ if (v && v.length >= 4) {
1352
+ this.vertexAttribI4ui(index, v[0], v[1], v[2], v[3]);
1353
+ } else {
1354
+ this._setError(0x0501);
1355
+ }
1356
+ }
1357
+
1358
+ vertexAttribDivisor(index, divisor) {
1359
+ this._assertNotDestroyed();
1360
+ const ex = this._instance.exports;
1361
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_divisor !== 'function') {
1362
+ throw new Error('wasm_ctx_vertex_attrib_divisor not found');
1363
+ }
1364
+ const code = ex.wasm_ctx_vertex_attrib_divisor(this._ctxHandle, index >>> 0, divisor >>> 0);
1365
+ _checkErr(code, this._instance);
1366
+ }
1367
+
1368
+ createBuffer() {
1369
+ this._assertNotDestroyed();
1370
+ const ex = this._instance.exports;
1371
+ if (!ex || typeof ex.wasm_ctx_create_buffer !== 'function') {
1372
+ throw new Error('wasm_ctx_create_buffer not found');
1373
+ }
1374
+ const handle = ex.wasm_ctx_create_buffer(this._ctxHandle);
1375
+ if (handle === 0) {
1376
+ const msg = readErrorMessage(this._instance);
1377
+ throw new Error(`Failed to create buffer: ${msg}`);
1378
+ }
1379
+ return new WasmWebGLBuffer(this, handle);
1380
+ }
1381
+
1382
+ bindBuffer(target, buffer) {
1383
+ this._assertNotDestroyed();
1384
+ const ex = this._instance.exports;
1385
+ if (!ex || typeof ex.wasm_ctx_bind_buffer !== 'function') {
1386
+ throw new Error('wasm_ctx_bind_buffer not found');
1387
+ }
1388
+ const handle = buffer && typeof buffer === 'object' && typeof buffer._handle === 'number' ? buffer._handle : (buffer >>> 0);
1389
+ const code = ex.wasm_ctx_bind_buffer(this._ctxHandle, target >>> 0, handle);
1390
+ _checkErr(code, this._instance);
1391
+ }
1392
+
1393
+ deleteBuffer(buffer) {
1394
+ this._assertNotDestroyed();
1395
+ const ex = this._instance.exports;
1396
+ if (!ex || typeof ex.wasm_ctx_delete_buffer !== 'function') {
1397
+ throw new Error('wasm_ctx_delete_buffer not found');
1398
+ }
1399
+ const handle = buffer && typeof buffer === 'object' && typeof buffer._handle === 'number' ? buffer._handle : (buffer >>> 0);
1400
+ const code = ex.wasm_ctx_delete_buffer(this._ctxHandle, handle);
1401
+ _checkErr(code, this._instance); if (buffer && typeof buffer === 'object') {
1402
+ try { buffer._handle = 0; buffer._deleted = true; } catch (e) { /* ignore */ }
1403
+ }
1404
+ }
1405
+
1406
+ bufferData(target, data, usage) {
1407
+ this._assertNotDestroyed();
1408
+ const ex = this._instance.exports;
1409
+ if (!ex || typeof ex.wasm_ctx_buffer_data !== 'function') {
1410
+ throw new Error('wasm_ctx_buffer_data not found');
1411
+ }
1412
+
1413
+ let bytes;
1414
+ if (data instanceof ArrayBuffer) {
1415
+ bytes = new Uint8Array(data);
1416
+ } else if (ArrayBuffer.isView(data)) {
1417
+ bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1418
+ } else if (typeof data === 'number') {
1419
+ bytes = new Uint8Array(data);
1420
+ } else {
1421
+ throw new Error('Invalid data type for bufferData');
1422
+ }
1423
+
1424
+ const len = bytes.length;
1425
+ if (len === 0) {
1426
+ const code = ex.wasm_ctx_buffer_data(this._ctxHandle, target >>> 0, 0, 0, usage >>> 0);
1427
+ _checkErr(code, this._instance);
1428
+ return;
1429
+ }
1430
+
1431
+ const ptr = ex.wasm_alloc(len);
1432
+ if (ptr === 0) throw new Error('Failed to allocate memory for bufferData');
1433
+
1434
+ try {
1435
+ const mem = new Uint8Array(ex.memory.buffer);
1436
+ mem.set(bytes, ptr);
1437
+ const code = ex.wasm_ctx_buffer_data(this._ctxHandle, target >>> 0, ptr, len, usage >>> 0);
1438
+ _checkErr(code, this._instance);
1439
+ } finally {
1440
+ ex.wasm_free(ptr);
1441
+ }
1442
+ }
1443
+
1444
+ bufferSubData(target, offset, data) {
1445
+ this._assertNotDestroyed();
1446
+ const ex = this._instance.exports;
1447
+ if (!ex || typeof ex.wasm_ctx_buffer_sub_data !== 'function') {
1448
+ throw new Error('wasm_ctx_buffer_sub_data not found');
1449
+ }
1450
+
1451
+ let bytes;
1452
+ if (data instanceof Uint8Array) bytes = data;
1453
+ else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1454
+ else if (data instanceof ArrayBuffer) bytes = new Uint8Array(data);
1455
+ else bytes = new Uint8Array(data); // Fallback for arrays
1456
+
1457
+ const len = bytes.length;
1458
+ const ptr = ex.wasm_alloc(len);
1459
+ if (ptr === 0) throw new Error('Failed to allocate memory for bufferSubData');
1460
+
1461
+ try {
1462
+ const mem = new Uint8Array(ex.memory.buffer);
1463
+ mem.set(bytes, ptr);
1464
+ const code = ex.wasm_ctx_buffer_sub_data(this._ctxHandle, target >>> 0, offset >>> 0, ptr, len);
1465
+ _checkErr(code, this._instance);
1466
+ } finally {
1467
+ ex.wasm_free(ptr);
1468
+ }
1469
+ }
1470
+ copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) {
1471
+ this._assertNotDestroyed();
1472
+ const ex = this._instance.exports;
1473
+ if (!ex || typeof ex.wasm_ctx_copy_buffer_sub_data !== 'function') {
1474
+ throw new Error('wasm_ctx_copy_buffer_sub_data not found');
1475
+ }
1476
+ const code = ex.wasm_ctx_copy_buffer_sub_data(
1477
+ this._ctxHandle,
1478
+ readTarget >>> 0,
1479
+ writeTarget >>> 0,
1480
+ readOffset >>> 0,
1481
+ writeOffset >>> 0,
1482
+ size >>> 0
1483
+ );
1484
+ _checkErr(code, this._instance);
1485
+ }
1486
+ getBufferParameter(target, pname) {
1487
+ this._assertNotDestroyed();
1488
+ const ex = this._instance.exports;
1489
+ if (!ex || typeof ex.wasm_ctx_get_buffer_parameter !== 'function') {
1490
+ throw new Error('wasm_ctx_get_buffer_parameter not found');
1491
+ }
1492
+ const val = ex.wasm_ctx_get_buffer_parameter(this._ctxHandle, target >>> 0, pname >>> 0);
1493
+ if (val < 0) {
1494
+ const msg = readErrorMessage(this._instance);
1495
+ throw new Error(`getBufferParameter failed: ${msg}`);
1496
+ }
1497
+ return val;
1498
+ }
1499
+ isBuffer(buffer) {
1500
+ this._assertNotDestroyed();
1501
+ if (!buffer || typeof buffer !== 'object' || !(buffer instanceof WasmWebGLBuffer)) return false;
1502
+ if (buffer._ctx !== this) return false;
1503
+ const ex = this._instance.exports;
1504
+ return ex.wasm_ctx_is_buffer(this._ctxHandle, buffer._handle) !== 0;
1505
+ }
1506
+
1507
+ drawArrays(mode, first, count) {
1508
+ this._assertNotDestroyed();
1509
+ const ex = this._instance.exports;
1510
+ if (!ex || typeof ex.wasm_ctx_draw_arrays !== 'function') {
1511
+ throw new Error('wasm_ctx_draw_arrays not found');
1512
+ }
1513
+ const code = ex.wasm_ctx_draw_arrays(this._ctxHandle, mode >>> 0, first >>> 0, count >>> 0);
1514
+ _checkErr(code, this._instance);
1515
+ }
1516
+
1517
+ drawElements(mode, count, type, offset) {
1518
+ this._assertNotDestroyed();
1519
+ const ex = this._instance.exports;
1520
+ if (!ex || typeof ex.wasm_ctx_draw_elements !== 'function') {
1521
+ throw new Error('wasm_ctx_draw_elements not found');
1522
+ }
1523
+ const code = ex.wasm_ctx_draw_elements(this._ctxHandle, mode >>> 0, count >>> 0, type >>> 0, offset >>> 0);
1524
+ _checkErr(code, this._instance);
1525
+ }
1526
+ drawArraysInstanced(mode, first, count, instanceCount) {
1527
+ this._assertNotDestroyed();
1528
+ const ex = this._instance.exports;
1529
+ if (!ex || typeof ex.wasm_ctx_draw_arrays_instanced !== 'function') {
1530
+ throw new Error('wasm_ctx_draw_arrays_instanced not found');
1531
+ }
1532
+ const code = ex.wasm_ctx_draw_arrays_instanced(this._ctxHandle, mode >>> 0, first | 0, count | 0, instanceCount | 0);
1533
+ _checkErr(code, this._instance);
1534
+ }
1535
+ drawElementsInstanced(mode, count, type, offset, instanceCount) {
1536
+ this._assertNotDestroyed();
1537
+ const ex = this._instance.exports;
1538
+ if (!ex || typeof ex.wasm_ctx_draw_elements_instanced !== 'function') {
1539
+ throw new Error('wasm_ctx_draw_elements_instanced not found');
1540
+ }
1541
+ const code = ex.wasm_ctx_draw_elements_instanced(this._ctxHandle, mode >>> 0, count | 0, type >>> 0, offset >>> 0, instanceCount | 0);
1542
+ _checkErr(code, this._instance);
1543
+ }
1544
+ drawRangeElements(mode, start, end, count, type, offset) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1545
+ drawBuffers(buffers) {
1546
+ this._assertNotDestroyed();
1547
+ const ex = this._instance.exports;
1548
+ if (!ex || typeof ex.wasm_ctx_draw_buffers !== 'function') {
1549
+ throw new Error('wasm_ctx_draw_buffers not found');
1550
+ }
1551
+
1552
+ const count = buffers.length;
1553
+ const bufs = new Uint32Array(count);
1554
+ for (let i = 0; i < count; i++) {
1555
+ bufs[i] = buffers[i];
1556
+ }
1557
+
1558
+ const ptr = ex.wasm_alloc(count * 4);
1559
+ const view = new Uint32Array(ex.memory.buffer, ptr, count);
1560
+ view.set(bufs);
1561
+
1562
+ const code = ex.wasm_ctx_draw_buffers(this._ctxHandle, ptr, count);
1563
+ ex.wasm_free(ptr, count * 4);
1564
+ _checkErr(code, this._instance);
1565
+ }
1566
+
1567
+ readBuffer(mode) {
1568
+ this._assertNotDestroyed();
1569
+ const ex = this._instance.exports;
1570
+ if (!ex || typeof ex.wasm_ctx_read_buffer !== 'function') {
1571
+ throw new Error('wasm_ctx_read_buffer not found');
1572
+ }
1573
+
1574
+ const code = ex.wasm_ctx_read_buffer(this._ctxHandle, mode);
1575
+ _checkErr(code, this._instance);
1576
+ }
1577
+
1578
+ createVertexArray() {
1579
+ this._assertNotDestroyed();
1580
+ const ex = this._instance.exports;
1581
+ if (!ex || typeof ex.wasm_ctx_create_vertex_array !== 'function') {
1582
+ throw new Error('wasm_ctx_create_vertex_array not found');
1583
+ }
1584
+ const handle = ex.wasm_ctx_create_vertex_array(this._ctxHandle);
1585
+ if (handle === 0) return null;
1586
+ return new WasmWebGLVertexArrayObject(this, handle);
1587
+ }
1588
+
1589
+ bindVertexArray(vao) {
1590
+ this._assertNotDestroyed();
1591
+ const ex = this._instance.exports;
1592
+ if (!ex || typeof ex.wasm_ctx_bind_vertex_array !== 'function') {
1593
+ throw new Error('wasm_ctx_bind_vertex_array not found');
1594
+ }
1595
+ const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao ? (vao >>> 0) : 0);
1596
+ const code = ex.wasm_ctx_bind_vertex_array(this._ctxHandle, handle);
1597
+ _checkErr(code, this._instance);
1598
+ }
1599
+
1600
+ deleteVertexArray(vao) {
1601
+ this._assertNotDestroyed();
1602
+ const ex = this._instance.exports;
1603
+ if (!ex || typeof ex.wasm_ctx_delete_vertex_array !== 'function') {
1604
+ throw new Error('wasm_ctx_delete_vertex_array not found');
1605
+ }
1606
+ const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
1607
+ const code = ex.wasm_ctx_delete_vertex_array(this._ctxHandle, handle);
1608
+ _checkErr(code, this._instance);
1609
+ if (vao && typeof vao === 'object') {
1610
+ try { vao._handle = 0; vao._deleted = true; } catch (e) { /* ignore */ }
1611
+ }
1612
+ }
1613
+
1614
+ isVertexArray(vao) {
1615
+ this._assertNotDestroyed();
1616
+ const ex = this._instance.exports;
1617
+ if (!ex || typeof ex.wasm_ctx_is_vertex_array !== 'function') {
1618
+ throw new Error('wasm_ctx_is_vertex_array not found');
1619
+ }
1620
+ const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
1621
+ const res = ex.wasm_ctx_is_vertex_array(this._ctxHandle, handle);
1622
+ return res !== 0;
1623
+ }
1624
+
1625
+ createTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1626
+ bindTransformFeedback(target, tf) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1627
+ beginTransformFeedback(primitiveMode) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1628
+ pauseTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1629
+ resumeTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1630
+ endTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1631
+ transformFeedbackVaryings(program, varyings, bufferMode) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1632
+ getTransformFeedbackVarying(program, index) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1633
+
1634
+ createQuery() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1635
+ deleteQuery(q) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1636
+ beginQuery(target, id) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1637
+ endQuery(target) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1638
+ getQueryParameter(query, pname) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1639
+
1640
+ fenceSync(condition, flags) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1641
+ clientWaitSync(sync, flags, timeout) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1642
+ waitSync(sync, flags, timeout) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1643
+ deleteSync(sync) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1644
+ getSyncParameter(sync, pname) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1645
+
1646
+ createSampler() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1647
+ deleteSampler(s) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1648
+ bindSampler(unit, sampler) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1649
+ samplerParameteri(sampler, pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1650
+ samplerParameterf(sampler, pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1651
+
1652
+ activeTexture(texture) {
1653
+ this._assertNotDestroyed();
1654
+ const ex = this._instance.exports;
1655
+ if (!ex || typeof ex.wasm_ctx_active_texture !== 'function') {
1656
+ throw new Error('wasm_ctx_active_texture not found');
1657
+ }
1658
+ const code = ex.wasm_ctx_active_texture(this._ctxHandle, texture >>> 0);
1659
+ _checkErr(code, this._instance);
1660
+ // Track active texture unit in JS wrapper (GL_TEXTURE0 = 0x84C0)
1661
+ this._activeTextureUnit = (texture >>> 0) - 0x84C0;
1662
+ this._textureUnits = this._textureUnits || [];
1663
+ }
1664
+ texParameteri(target, pname, param) {
1665
+ this._assertNotDestroyed();
1666
+ const ex = this._instance.exports;
1667
+ if (!ex || typeof ex.wasm_ctx_tex_parameter_i !== 'function') {
1668
+ throw new Error('wasm_ctx_tex_parameter_i not found');
1669
+ }
1670
+ const code = ex.wasm_ctx_tex_parameter_i(this._ctxHandle, target >>> 0, pname >>> 0, param | 0);
1671
+ _checkErr(code, this._instance);
1672
+ }
1673
+ generateMipmap(target) {
1674
+ this._assertNotDestroyed();
1675
+ const ex = this._instance.exports;
1676
+ if (!ex || typeof ex.wasm_ctx_generate_mipmap !== 'function') {
1677
+ throw new Error('wasm_ctx_generate_mipmap not found');
1678
+ }
1679
+ const code = ex.wasm_ctx_generate_mipmap(this._ctxHandle, target >>> 0);
1680
+ _checkErr(code, this._instance);
1681
+ }
1682
+
1683
+ copyTexImage2D(target, level, internalformat, x, y, width, height, border) {
1684
+ this._assertNotDestroyed();
1685
+ const ex = this._instance.exports;
1686
+ if (!ex || typeof ex.wasm_ctx_copy_tex_image_2d !== 'function') {
1687
+ throw new Error('wasm_ctx_copy_tex_image_2d not found');
1688
+ }
1689
+ const code = ex.wasm_ctx_copy_tex_image_2d(
1690
+ this._ctxHandle,
1691
+ target >>> 0,
1692
+ level | 0,
1693
+ internalformat >>> 0,
1694
+ x | 0,
1695
+ y | 0,
1696
+ width | 0,
1697
+ height | 0,
1698
+ border | 0
1699
+ );
1700
+ _checkErr(code, this._instance);
1701
+ }
1702
+ copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1703
+ texSubImage2D(target, level, xoffset, yoffset, width, height, format, type_, pixels) {
1704
+ this._assertNotDestroyed();
1705
+ const ex = this._instance.exports;
1706
+ if (!ex || typeof ex.wasm_ctx_tex_sub_image_2d !== 'function') {
1707
+ throw new Error('wasm_ctx_tex_sub_image_2d not found');
1708
+ }
1709
+
1710
+ let data = pixels;
1711
+ if (!data) return; // No-op if no data provided
1712
+ if (!(data instanceof Uint8Array)) {
1713
+ if (ArrayBuffer.isView(data)) {
1714
+ data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1715
+ } else {
1716
+ data = new Uint8Array(data);
1717
+ }
1718
+ }
1719
+
1720
+ const len = data.length;
1721
+ const ptr = ex.wasm_alloc(len);
1722
+ if (ptr === 0) throw new Error('Failed to allocate memory for sub-pixel data');
1723
+
1724
+ try {
1725
+ const mem = new Uint8Array(ex.memory.buffer);
1726
+ mem.set(data, ptr);
1727
+
1728
+ const code = ex.wasm_ctx_tex_sub_image_2d(
1729
+ this._ctxHandle,
1730
+ target >>> 0,
1731
+ level >>> 0,
1732
+ xoffset | 0,
1733
+ yoffset | 0,
1734
+ width >>> 0,
1735
+ height >>> 0,
1736
+ format >>> 0,
1737
+ type_ >>> 0,
1738
+ ptr >>> 0,
1739
+ len >>> 0
1740
+ );
1741
+ _checkErr(code, this._instance);
1742
+ } finally {
1743
+ ex.wasm_free(ptr);
1744
+ }
1745
+ }
1746
+
1747
+ checkFramebufferStatus(target) {
1748
+ this._assertNotDestroyed();
1749
+ const ex = this._instance.exports;
1750
+ if (!ex || typeof ex.wasm_ctx_check_framebuffer_status !== 'function') {
1751
+ throw new Error('wasm_ctx_check_framebuffer_status not found');
1752
+ }
1753
+ return ex.wasm_ctx_check_framebuffer_status(this._ctxHandle, target);
1754
+ }
1755
+ blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) {
1756
+ this._assertNotDestroyed();
1757
+ const ex = this._instance.exports;
1758
+ if (!ex || typeof ex.wasm_ctx_blit_framebuffer !== 'function') {
1759
+ throw new Error('wasm_ctx_blit_framebuffer not found');
1760
+ }
1761
+ const code = ex.wasm_ctx_blit_framebuffer(
1762
+ this._ctxHandle,
1763
+ srcX0 | 0, srcY0 | 0, srcX1 | 0, srcY1 | 0,
1764
+ dstX0 | 0, dstY0 | 0, dstX1 | 0, dstY1 | 0,
1765
+ mask >>> 0, filter >>> 0
1766
+ );
1767
+ _checkErr(code, this._instance);
1768
+ }
1769
+
1770
+ pixelStorei(pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1771
+ getExtension(name) {
1772
+ this._assertNotDestroyed();
1773
+ if (name === 'EXT_color_buffer_float') {
1774
+ return {};
1775
+ }
1776
+ return null;
1777
+ }
1778
+ getSupportedExtensions() {
1779
+ this._assertNotDestroyed();
1780
+ return ['EXT_color_buffer_float'];
1781
+ }
1782
+
1783
+ getUniformLocation(program, name) {
1784
+ this._assertNotDestroyed();
1785
+ const ex = this._instance.exports;
1786
+ if (!ex || typeof ex.wasm_ctx_get_uniform_location !== 'function') {
1787
+ throw new Error('wasm_ctx_get_uniform_location not found');
1788
+ }
1789
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1790
+ const nameStr = String(name);
1791
+ const bytes = new TextEncoder().encode(nameStr);
1792
+ const len = bytes.length;
1793
+ const ptr = ex.wasm_alloc(len);
1794
+ if (ptr === 0) throw new Error('Failed to allocate memory for getUniformLocation');
1795
+
1796
+ try {
1797
+ const mem = new Uint8Array(ex.memory.buffer);
1798
+ mem.set(bytes, ptr);
1799
+ const loc = ex.wasm_ctx_get_uniform_location(this._ctxHandle, programHandle, ptr, len);
1800
+ return loc === -1 ? null : new WasmWebGLUniformLocation(this, loc);
1801
+ } finally {
1802
+ ex.wasm_free(ptr);
1803
+ }
1804
+ }
1805
+
1806
+ uniform1f(loc, x) {
1807
+ this._assertNotDestroyed();
1808
+ const ex = this._instance.exports;
1809
+ if (!ex || typeof ex.wasm_ctx_uniform1f !== 'function') {
1810
+ throw new Error('wasm_ctx_uniform1f not found');
1811
+ }
1812
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1813
+ const code = ex.wasm_ctx_uniform1f(this._ctxHandle, locHandle, +x);
1814
+ _checkErr(code, this._instance);
1815
+ }
1816
+
1817
+ uniform2f(loc, x, y) {
1818
+ this._assertNotDestroyed();
1819
+ const ex = this._instance.exports;
1820
+ if (!ex || typeof ex.wasm_ctx_uniform2f !== 'function') {
1821
+ throw new Error('wasm_ctx_uniform2f not found');
1822
+ }
1823
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1824
+ const code = ex.wasm_ctx_uniform2f(this._ctxHandle, locHandle, +x, +y);
1825
+ _checkErr(code, this._instance);
1826
+ }
1827
+
1828
+ uniform3f(loc, x, y, z) {
1829
+ this._assertNotDestroyed();
1830
+ const ex = this._instance.exports;
1831
+ if (!ex || typeof ex.wasm_ctx_uniform3f !== 'function') {
1832
+ throw new Error('wasm_ctx_uniform3f not found');
1833
+ }
1834
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1835
+ const code = ex.wasm_ctx_uniform3f(this._ctxHandle, locHandle, +x, +y, +z);
1836
+ _checkErr(code, this._instance);
1837
+ }
1838
+
1839
+ uniform4f(loc, x, y, z, w) {
1840
+ this._assertNotDestroyed();
1841
+ const ex = this._instance.exports;
1842
+ if (!ex || typeof ex.wasm_ctx_uniform4f !== 'function') {
1843
+ throw new Error('wasm_ctx_uniform4f not found');
1844
+ }
1845
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1846
+ const code = ex.wasm_ctx_uniform4f(this._ctxHandle, locHandle, +x, +y, +z, +w);
1847
+ _checkErr(code, this._instance);
1848
+ }
1849
+
1850
+ uniform1i(loc, x) {
1851
+ this._assertNotDestroyed();
1852
+ const ex = this._instance.exports;
1853
+ if (!ex || typeof ex.wasm_ctx_uniform1i !== 'function') {
1854
+ throw new Error('wasm_ctx_uniform1i not found');
1855
+ }
1856
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1857
+ const code = ex.wasm_ctx_uniform1i(this._ctxHandle, locHandle, x | 0);
1858
+ _checkErr(code, this._instance);
1859
+ }
1860
+
1861
+ uniformMatrix4fv(loc, transpose, value) {
1862
+ this._assertNotDestroyed();
1863
+ const ex = this._instance.exports;
1864
+ if (!ex || typeof ex.wasm_ctx_uniform_matrix_4fv !== 'function') {
1865
+ throw new Error('wasm_ctx_uniform_matrix_4fv not found');
1866
+ }
1867
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1868
+
1869
+ let bytes;
1870
+ if (value instanceof Float32Array) {
1871
+ bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1872
+ } else {
1873
+ bytes = new Uint8Array(new Float32Array(value).buffer);
1874
+ }
1875
+
1876
+ const len = bytes.length;
1877
+ const ptr = ex.wasm_alloc(len);
1878
+ if (ptr === 0) throw new Error('Failed to allocate memory for uniformMatrix4fv');
1879
+
1880
+ try {
1881
+ const mem = new Uint8Array(ex.memory.buffer);
1882
+ mem.set(bytes, ptr);
1883
+ const count = len / 4;
1884
+ const code = ex.wasm_ctx_uniform_matrix_4fv(this._ctxHandle, locHandle, transpose ? 1 : 0, ptr, count);
1885
+ _checkErr(code, this._instance);
1886
+ } finally {
1887
+ ex.wasm_free(ptr);
1888
+ }
1889
+ }
1890
+
1891
+ getVertexAttrib(index, pname) {
1892
+ this._assertNotDestroyed();
1893
+ const ex = this._instance.exports;
1894
+ if (!ex || typeof ex.wasm_ctx_get_vertex_attrib !== 'function') {
1895
+ throw new Error('wasm_ctx_get_vertex_attrib not found');
1896
+ }
1897
+
1898
+ // Allocate memory for result.
1899
+ // Most params return 1 int (4 bytes).
1900
+ // CURRENT_VERTEX_ATTRIB returns 4 values (16 bytes) + type (4 bytes) = 20 bytes.
1901
+ const len = 20;
1902
+ const ptr = ex.wasm_alloc(len);
1903
+ if (ptr === 0) throw new Error('Failed to allocate memory for getVertexAttrib');
1904
+
1905
+ try {
1906
+ const code = ex.wasm_ctx_get_vertex_attrib(this._ctxHandle, index >>> 0, pname >>> 0, ptr, len);
1907
+ if (code === 5) { // ERR_GL
1908
+ return undefined;
1909
+ }
1910
+ _checkErr(code, this._instance);
1911
+
1912
+ const mem = new Int32Array(ex.memory.buffer, ptr, 5);
1913
+ const memU = new Uint32Array(ex.memory.buffer, ptr, 5);
1914
+ const memF = new Float32Array(ex.memory.buffer, ptr, 5);
1915
+
1916
+ if (pname === 0x8626 /* CURRENT_VERTEX_ATTRIB */) {
1917
+ // Check type at index 4
1918
+ const type = memU[4];
1919
+ if (type === 0x1404 /* INT */) {
1920
+ return new Int32Array([mem[0], mem[1], mem[2], mem[3]]);
1921
+ } else if (type === 0x1405 /* UNSIGNED_INT */) {
1922
+ return new Uint32Array([memU[0], memU[1], memU[2], memU[3]]);
1923
+ } else {
1924
+ // Default to float
1925
+ return new Float32Array([memF[0], memF[1], memF[2], memF[3]]);
1926
+ }
1927
+ }
1928
+
1929
+ // Other params
1930
+ if (pname === 0x8622 /* ENABLED */ ||
1931
+ pname === 0x886A /* NORMALIZED */ ||
1932
+ pname === 0x88FD /* INTEGER */) {
1933
+ return mem[0] !== 0;
1934
+ }
1935
+
1936
+ if (pname === 0x889F /* BUFFER_BINDING */) {
1937
+ const handle = memU[0];
1938
+ if (handle === 0) return null;
1939
+ return new WasmWebGLBuffer(this, handle);
1940
+ }
1941
+
1942
+ return mem[0];
1943
+ } finally {
1944
+ ex.wasm_free(ptr, len);
1945
+ }
1946
+ }
1947
+
1948
+
1949
+ getParameter(pname) {
1950
+ this._assertNotDestroyed();
1951
+ const ex = this._instance.exports;
1952
+ if (!ex || typeof ex.wasm_ctx_get_parameter_v !== 'function') {
1953
+ throw new Error('wasm_ctx_get_parameter_v not found');
1954
+ }
1955
+
1956
+ if (pname === 0x0BA2 /* VIEWPORT */) {
1957
+ const ptr = ex.wasm_alloc(16);
1958
+ try {
1959
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 16);
1960
+ _checkErr(code, this._instance);
1961
+ const mem = new Int32Array(ex.memory.buffer, ptr, 4);
1962
+ return new Int32Array(mem);
1963
+ } finally {
1964
+ ex.wasm_free(ptr, 16);
1965
+ }
1966
+ }
1967
+
1968
+ if (pname === 0x0C22 /* COLOR_CLEAR_VALUE */) {
1969
+ const ptr = ex.wasm_alloc(16);
1970
+ try {
1971
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 16);
1972
+ _checkErr(code, this._instance);
1973
+ const mem = new Float32Array(ex.memory.buffer, ptr, 4);
1974
+ return new Float32Array(mem);
1975
+ } finally {
1976
+ ex.wasm_free(ptr, 16);
1977
+ }
1978
+ }
1979
+
1980
+ if (pname === 0x0C23 /* COLOR_WRITEMASK */) {
1981
+ const ptr = ex.wasm_alloc(4);
1982
+ try {
1983
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1984
+ _checkErr(code, this._instance);
1985
+ const mem = new Uint8Array(ex.memory.buffer, ptr, 4);
1986
+ return [mem[0] !== 0, mem[1] !== 0, mem[2] !== 0, mem[3] !== 0];
1987
+ } finally {
1988
+ ex.wasm_free(ptr, 4);
1989
+ }
1990
+ }
1991
+
1992
+ if (pname === 0x0B72 /* DEPTH_WRITEMASK */) {
1993
+ const ptr = ex.wasm_alloc(4);
1994
+ try {
1995
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1996
+ _checkErr(code, this._instance);
1997
+ const mem = new Uint8Array(ex.memory.buffer, ptr, 1);
1998
+ return mem[0] !== 0;
1999
+ } finally {
2000
+ ex.wasm_free(ptr, 4);
2001
+ }
2002
+ }
2003
+
2004
+ if (pname === 0x0B98 /* STENCIL_WRITEMASK */ || pname === 0x8CA5 /* STENCIL_BACK_WRITEMASK */) {
2005
+ const ptr = ex.wasm_alloc(4);
2006
+ try {
2007
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
2008
+ _checkErr(code, this._instance);
2009
+ const mem = new Int32Array(ex.memory.buffer, ptr, 1);
2010
+ return mem[0];
2011
+ } finally {
2012
+ ex.wasm_free(ptr, 4);
2013
+ }
2014
+ }
2015
+
2016
+ const singleIntParams = [
2017
+ 0x0B74, // DEPTH_FUNC
2018
+ 0x0B92, // STENCIL_FUNC
2019
+ 0x0B93, // STENCIL_VALUE_MASK
2020
+ 0x0B97, // STENCIL_REF
2021
+ 0x8800, // STENCIL_BACK_FUNC
2022
+ 0x8CA4, // STENCIL_BACK_VALUE_MASK
2023
+ 0x8CA3, // STENCIL_BACK_REF
2024
+ 0x0B94, // STENCIL_FAIL
2025
+ 0x0B95, // STENCIL_PASS_DEPTH_FAIL
2026
+ 0x0B96, // STENCIL_PASS_DEPTH_PASS
2027
+ 0x8801, // STENCIL_BACK_FAIL
2028
+ 0x8802, // STENCIL_BACK_PASS_DEPTH_FAIL
2029
+ 0x8803, // STENCIL_BACK_PASS_DEPTH_PASS
2030
+ ];
2031
+
2032
+ if (singleIntParams.includes(pname)) {
2033
+ const ptr = ex.wasm_alloc(4);
2034
+ try {
2035
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
2036
+ _checkErr(code, this._instance);
2037
+ const mem = new Int32Array(ex.memory.buffer, ptr, 1);
2038
+ return mem[0];
2039
+ } finally {
2040
+ ex.wasm_free(ptr, 4);
2041
+ }
2042
+ }
2043
+
2044
+ if (pname === 0x8869 /* MAX_VERTEX_ATTRIBS */) {
2045
+ return 16;
2046
+ }
2047
+
2048
+ throw new Error(`getParameter for ${pname} not implemented`);
2049
+ }
2050
+ getError() {
2051
+ this._assertNotDestroyed();
2052
+ const ex = this._instance.exports;
2053
+ if (!ex || typeof ex.wasm_ctx_get_error !== 'function') {
2054
+ throw new Error('wasm_ctx_get_error not found');
2055
+ }
2056
+ return ex.wasm_ctx_get_error(this._ctxHandle);
2057
+ }
2058
+
2059
+ _setError(error) {
2060
+ const ex = this._instance.exports;
2061
+ if (ex && typeof ex.wasm_ctx_set_gl_error === 'function') {
2062
+ ex.wasm_ctx_set_gl_error(this._ctxHandle, error);
2063
+ }
2064
+ }
2065
+
2066
+ finish() { this._assertNotDestroyed(); throw new Error('not implemented'); }
2067
+ flush() { this._assertNotDestroyed(); throw new Error('not implemented'); }
2068
+
2069
+ isTexture(tex) {
2070
+ this._assertNotDestroyed();
2071
+ if (!tex || typeof tex !== 'object' || !(tex instanceof WasmWebGLTexture)) return false;
2072
+ if (tex._ctx !== this) return false;
2073
+ const ex = this._instance.exports;
2074
+ return ex.wasm_ctx_is_texture(this._ctxHandle, tex._handle) !== 0;
2075
+ }
2076
+ isFramebuffer(fb) {
2077
+ this._assertNotDestroyed();
2078
+ if (!fb || typeof fb !== 'object' || !(fb instanceof WasmWebGLFramebuffer)) return false;
2079
+ if (fb._ctx !== this) return false;
2080
+ const ex = this._instance.exports;
2081
+ return ex.wasm_ctx_is_framebuffer(this._ctxHandle, fb._handle) !== 0;
2082
+ }
2083
+ isProgram(p) {
2084
+ this._assertNotDestroyed();
2085
+ if (!p || typeof p !== 'object' || !(p instanceof WasmWebGLProgram)) return false;
2086
+ if (p._ctx !== this) return false;
2087
+ const ex = this._instance.exports;
2088
+ return ex.wasm_ctx_is_program(this._ctxHandle, p._handle) !== 0;
2089
+ }
2090
+ isShader(s) {
2091
+ this._assertNotDestroyed();
2092
+ if (!s || typeof s !== 'object' || !(s instanceof WasmWebGLShader)) return false;
2093
+ if (s._ctx !== this) return false;
2094
+ const ex = this._instance.exports;
2095
+ return ex.wasm_ctx_is_shader(this._ctxHandle, s._handle) !== 0;
2096
+ }
2097
+ enable(cap) {
2098
+ this._assertNotDestroyed();
2099
+ const ex = this._instance.exports;
2100
+ if (!ex || typeof ex.wasm_ctx_enable !== 'function') {
2101
+ throw new Error('wasm_ctx_enable not found');
2102
+ }
2103
+ const code = ex.wasm_ctx_enable(this._ctxHandle, cap >>> 0);
2104
+ _checkErr(code, this._instance);
2105
+ }
2106
+ disable(cap) {
2107
+ this._assertNotDestroyed();
2108
+ const ex = this._instance.exports;
2109
+ if (!ex || typeof ex.wasm_ctx_disable !== 'function') {
2110
+ throw new Error('wasm_ctx_disable not found');
2111
+ }
2112
+ const code = ex.wasm_ctx_disable(this._ctxHandle, cap >>> 0);
2113
+ _checkErr(code, this._instance);
2114
+ }
2115
+
2116
+ blendFunc(sfactor, dfactor) {
2117
+ this._assertNotDestroyed();
2118
+ const ex = this._instance.exports;
2119
+ if (!ex || typeof ex.wasm_ctx_blend_func !== 'function') {
2120
+ throw new Error('wasm_ctx_blend_func not found');
2121
+ }
2122
+ const code = ex.wasm_ctx_blend_func(this._ctxHandle, sfactor >>> 0, dfactor >>> 0);
2123
+ _checkErr(code, this._instance);
2124
+ }
2125
+
2126
+ blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) {
2127
+ this._assertNotDestroyed();
2128
+ const ex = this._instance.exports;
2129
+ if (!ex || typeof ex.wasm_ctx_blend_func_separate !== 'function') {
2130
+ throw new Error('wasm_ctx_blend_func_separate not found');
2131
+ }
2132
+ const code = ex.wasm_ctx_blend_func_separate(
2133
+ this._ctxHandle,
2134
+ srcRGB >>> 0,
2135
+ dstRGB >>> 0,
2136
+ srcAlpha >>> 0,
2137
+ dstAlpha >>> 0
2138
+ );
2139
+ _checkErr(code, this._instance);
2140
+ }
2141
+
2142
+ blendEquation(mode) {
2143
+ this._assertNotDestroyed();
2144
+ const ex = this._instance.exports;
2145
+ if (!ex || typeof ex.wasm_ctx_blend_equation !== 'function') {
2146
+ throw new Error('wasm_ctx_blend_equation not found');
2147
+ }
2148
+ const code = ex.wasm_ctx_blend_equation(this._ctxHandle, mode >>> 0);
2149
+ _checkErr(code, this._instance);
2150
+ }
2151
+
2152
+ blendEquationSeparate(modeRGB, modeAlpha) {
2153
+ this._assertNotDestroyed();
2154
+ const ex = this._instance.exports;
2155
+ if (!ex || typeof ex.wasm_ctx_blend_equation_separate !== 'function') {
2156
+ throw new Error('wasm_ctx_blend_equation_separate not found');
2157
+ }
2158
+ const code = ex.wasm_ctx_blend_equation_separate(
2159
+ this._ctxHandle,
2160
+ modeRGB >>> 0,
2161
+ modeAlpha >>> 0
2162
+ );
2163
+ _checkErr(code, this._instance);
2164
+ }
2165
+
2166
+ blendColor(red, green, blue, alpha) {
2167
+ this._assertNotDestroyed();
2168
+ const ex = this._instance.exports;
2169
+ if (!ex || typeof ex.wasm_ctx_blend_color !== 'function') {
2170
+ throw new Error('wasm_ctx_blend_color not found');
2171
+ }
2172
+ const code = ex.wasm_ctx_blend_color(
2173
+ this._ctxHandle,
2174
+ +red,
2175
+ +green,
2176
+ +blue,
2177
+ +alpha
2178
+ );
2179
+ _checkErr(code, this._instance);
2180
+ }
2181
+
2182
+ isEnabled(cap) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2183
+
2184
+ viewport(x, y, width, height) {
2185
+ this._assertNotDestroyed();
2186
+ const ex = this._instance.exports;
2187
+ if (!ex || typeof ex.wasm_ctx_viewport !== 'function') {
2188
+ throw new Error('wasm_ctx_viewport not found');
2189
+ }
2190
+ const code = ex.wasm_ctx_viewport(this._ctxHandle, x >>> 0, y >>> 0, width >>> 0, height >>> 0);
2191
+ _checkErr(code, this._instance);
2192
+ }
2193
+ scissor(x, y, width, height) {
2194
+ this._assertNotDestroyed();
2195
+ const ex = this._instance.exports;
2196
+ if (!ex || typeof ex.wasm_ctx_scissor !== 'function') {
2197
+ throw new Error('wasm_ctx_scissor not found');
2198
+ }
2199
+ const code = ex.wasm_ctx_scissor(this._ctxHandle, x | 0, y | 0, width >>> 0, height >>> 0);
2200
+ _checkErr(code, this._instance);
2201
+ }
2202
+ clear(mask) {
2203
+ this._assertNotDestroyed();
2204
+ const ex = this._instance.exports;
2205
+ if (!ex || typeof ex.wasm_ctx_clear !== 'function') {
2206
+ throw new Error('wasm_ctx_clear not found');
2207
+ }
2208
+ const code = ex.wasm_ctx_clear(this._ctxHandle, mask >>> 0);
2209
+ _checkErr(code, this._instance);
2210
+ }
2211
+ clearColor(r, g, b, a) {
2212
+ this._assertNotDestroyed();
2213
+ const ex = this._instance.exports;
2214
+ if (!ex || typeof ex.wasm_ctx_clear_color !== 'function') {
2215
+ throw new Error('wasm_ctx_clear_color not found');
2216
+ }
2217
+ const code = ex.wasm_ctx_clear_color(this._ctxHandle, +r, +g, +b, +a);
2218
+ _checkErr(code, this._instance);
2219
+ }
2220
+ clearDepth(depth) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2221
+ depthFunc(func) {
2222
+ this._assertNotDestroyed();
2223
+ const ex = this._instance.exports;
2224
+ if (!ex || typeof ex.wasm_ctx_depth_func !== 'function') {
2225
+ throw new Error('wasm_ctx_depth_func not found');
2226
+ }
2227
+ const code = ex.wasm_ctx_depth_func(this._ctxHandle, func >>> 0);
2228
+ _checkErr(code, this._instance);
2229
+ }
2230
+ depthMask(flag) {
2231
+ this._assertNotDestroyed();
2232
+ const ex = this._instance.exports;
2233
+ if (!ex || typeof ex.wasm_ctx_depth_mask !== 'function') {
2234
+ throw new Error('wasm_ctx_depth_mask not found');
2235
+ }
2236
+ const code = ex.wasm_ctx_depth_mask(this._ctxHandle, flag ? 1 : 0);
2237
+ _checkErr(code, this._instance);
2238
+ }
2239
+ colorMask(r, g, b, a) {
2240
+ this._assertNotDestroyed();
2241
+ const ex = this._instance.exports;
2242
+ if (!ex || typeof ex.wasm_ctx_color_mask !== 'function') {
2243
+ throw new Error('wasm_ctx_color_mask not found');
2244
+ }
2245
+ const code = ex.wasm_ctx_color_mask(this._ctxHandle, r ? 1 : 0, g ? 1 : 0, b ? 1 : 0, a ? 1 : 0);
2246
+ _checkErr(code, this._instance);
2247
+ }
2248
+ polygonOffset(factor, units) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2249
+ sampleCoverage(value, invert) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2250
+ stencilFunc(func, ref, mask) {
2251
+ this._assertNotDestroyed();
2252
+ const ex = this._instance.exports;
2253
+ if (!ex || typeof ex.wasm_ctx_stencil_func !== 'function') {
2254
+ throw new Error('wasm_ctx_stencil_func not found');
2255
+ }
2256
+ const code = ex.wasm_ctx_stencil_func(this._ctxHandle, func >>> 0, ref | 0, mask >>> 0);
2257
+ _checkErr(code, this._instance);
2258
+ }
2259
+ stencilFuncSeparate(face, func, ref, mask) {
2260
+ this._assertNotDestroyed();
2261
+ const ex = this._instance.exports;
2262
+ if (!ex || typeof ex.wasm_ctx_stencil_func_separate !== 'function') {
2263
+ throw new Error('wasm_ctx_stencil_func_separate not found');
2264
+ }
2265
+ const code = ex.wasm_ctx_stencil_func_separate(this._ctxHandle, face >>> 0, func >>> 0, ref | 0, mask >>> 0);
2266
+ _checkErr(code, this._instance);
2267
+ }
2268
+ stencilOp(fail, zfail, zpass) {
2269
+ this._assertNotDestroyed();
2270
+ const ex = this._instance.exports;
2271
+ if (!ex || typeof ex.wasm_ctx_stencil_op !== 'function') {
2272
+ throw new Error('wasm_ctx_stencil_op not found');
2273
+ }
2274
+ const code = ex.wasm_ctx_stencil_op(this._ctxHandle, fail >>> 0, zfail >>> 0, zpass >>> 0);
2275
+ _checkErr(code, this._instance);
2276
+ }
2277
+ stencilOpSeparate(face, fail, zfail, zpass) {
2278
+ this._assertNotDestroyed();
2279
+ const ex = this._instance.exports;
2280
+ if (!ex || typeof ex.wasm_ctx_stencil_op_separate !== 'function') {
2281
+ throw new Error('wasm_ctx_stencil_op_separate not found');
2282
+ }
2283
+ const code = ex.wasm_ctx_stencil_op_separate(this._ctxHandle, face >>> 0, fail >>> 0, zfail >>> 0, zpass >>> 0);
2284
+ _checkErr(code, this._instance);
2285
+ }
2286
+ stencilMask(mask) {
2287
+ this._assertNotDestroyed();
2288
+ const ex = this._instance.exports;
2289
+ if (!ex || typeof ex.wasm_ctx_stencil_mask !== 'function') {
2290
+ throw new Error('wasm_ctx_stencil_mask not found');
2291
+ }
2292
+ const code = ex.wasm_ctx_stencil_mask(this._ctxHandle, mask >>> 0);
2293
+ _checkErr(code, this._instance);
2294
+ }
2295
+ stencilMaskSeparate(face, mask) {
2296
+ this._assertNotDestroyed();
2297
+ const ex = this._instance.exports;
2298
+ if (!ex || typeof ex.wasm_ctx_stencil_mask_separate !== 'function') {
2299
+ throw new Error('wasm_ctx_stencil_mask_separate not found');
2300
+ }
2301
+ const code = ex.wasm_ctx_stencil_mask_separate(this._ctxHandle, face >>> 0, mask >>> 0);
2302
+ _checkErr(code, this._instance);
2303
+ }
2304
+ }
2305
+
2306
+ /**
2307
+ * Thin wrapper for a WebGLTexture handle returned from WASM.
2308
+ * Holds a reference to the originating WasmWebGL2RenderingContext and the numeric handle.
2309
+ */
2310
+ // WebGLTexture wrapper moved to `src/webgl2_texture.js`.
2311
+
2312
+ /**
2313
+ * Read an error message from WASM memory and return it as string.
2314
+ * Exported so callers outside this module can report errors.
2315
+ * @param {WebAssembly.Instance} instance
2316
+ * @returns {string}
2317
+ */
2318
+ export function readErrorMessage(instance) {
2319
+ const ex = instance.exports;
2320
+ if (!ex || typeof ex.wasm_last_error_ptr !== 'function' || typeof ex.wasm_last_error_len !== 'function') {
2321
+ return '(no error message available)';
2322
+ }
2323
+ const ptr = ex.wasm_last_error_ptr();
2324
+ const len = ex.wasm_last_error_len();
2325
+ if (ptr === 0 || len === 0) {
2326
+ return '';
2327
+ }
2328
+ const mem = new Uint8Array(ex.memory.buffer);
2329
+ const bytes = mem.subarray(ptr, ptr + len);
2330
+ return new TextDecoder('utf-8').decode(bytes);
2331
+ }
2332
+
2333
+ function _checkErr(code, instance) {
2334
+ if (code === ERR_OK) return;
2335
+ const msg = readErrorMessage(instance);
2336
+ throw new Error(`WASM error ${code}: ${msg}`);
2337
+ }
2338
+
2339
+ // ============================================================================
2340
+ // WAT Testing Support (docs/1.9-wat-testing.md)
2341
+ // ============================================================================
2342
+
2343
+ /**
2344
+ * Get the compiled WASM bytes for a shader in a program.
2345
+ *
2346
+ * @param {number} ctxHandle - Context handle
2347
+ * @param {number} programHandle - Program handle
2348
+ * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2349
+ * @returns {Uint8Array | null} WASM bytes or null if not available
2350
+ */
2351
+ export function getShaderModule(ctxHandle, programHandle, shaderType) {
2352
+ const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2353
+ if (!ctx) {
2354
+ throw new Error('Invalid context handle');
2355
+ }
2356
+
2357
+ const ex = ctx._instance.exports;
2358
+ if (!ex || typeof ex.wasm_ctx_get_program_wasm_ref !== 'function') {
2359
+ throw new Error('wasm_ctx_get_program_wasm_ref not found');
2360
+ }
2361
+
2362
+ // Call the WASM function - it returns a packed u64 (BigInt or Number)
2363
+ const result = ex.wasm_ctx_get_program_wasm_ref(ctxHandle, programHandle, shaderType);
2364
+
2365
+ // Unpack: low 32 bits = ptr, high 32 bits = len
2366
+ let ptr, len;
2367
+ if (typeof result === 'bigint') {
2368
+ ptr = Number(result & 0xFFFFFFFFn);
2369
+ len = Number((result >> 32n) & 0xFFFFFFFFn);
2370
+ } else {
2371
+ // Fallback for number (may lose precision for very large values)
2372
+ ptr = result >>> 0; // Low 32 bits
2373
+ len = Math.floor(result / 0x100000000); // High 32 bits
2374
+ }
2375
+
2376
+ // Check for failure (0, 0)
2377
+ if (ptr === 0 || len === 0) {
2378
+ return null;
2379
+ }
2380
+
2381
+ // Copy bytes from WASM memory into a new Uint8Array
2382
+ const mem = new Uint8Array(ex.memory.buffer);
2383
+ const bytes = new Uint8Array(len);
2384
+ bytes.set(mem.subarray(ptr, ptr + len));
2385
+
2386
+ return bytes;
2387
+ }
2388
+
2389
+ /**
2390
+ * Get the WAT (WebAssembly Text) representation for a shader in a program.
2391
+ *
2392
+ * @param {number} ctxHandle - Context handle
2393
+ * @param {number} programHandle - Program handle
2394
+ * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2395
+ * @returns {string | null} WAT text or null if not available
2396
+ */
2397
+ export function getShaderWat(ctxHandle, programHandle, shaderType) {
2398
+ const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2399
+ if (!ctx) {
2400
+ throw new Error('Invalid context handle');
2401
+ }
2402
+
2403
+ const ex = ctx._instance.exports;
2404
+ if (!ex || typeof ex.wasm_ctx_get_program_wat_ref !== 'function') {
2405
+ throw new Error('wasm_ctx_get_program_wat_ref not found');
2406
+ }
2407
+
2408
+ // Call the WASM function - it returns a packed u64 (BigInt or Number)
2409
+ const result = ex.wasm_ctx_get_program_wat_ref(ctxHandle, programHandle, shaderType);
2410
+
2411
+ // Unpack: low 32 bits = ptr, high 32 bits = len
2412
+ let ptr, len;
2413
+ if (typeof result === 'bigint') {
2414
+ ptr = Number(result & 0xFFFFFFFFn);
2415
+ len = Number((result >> 32n) & 0xFFFFFFFFn);
2416
+ } else {
2417
+ // Fallback for number (may lose precision for very large values)
2418
+ ptr = result >>> 0; // Low 32 bits
2419
+ len = Math.floor(result / 0x100000000); // High 32 bits
2420
+ }
2421
+
2422
+ // Check for failure (0, 0)
2423
+ if (ptr === 0 || len === 0) {
2424
+ return null;
2425
+ }
2426
+
2427
+ // Copy bytes from WASM memory and decode as UTF-8
2428
+ const mem = new Uint8Array(ex.memory.buffer);
2429
+ const bytes = mem.subarray(ptr, ptr + len);
2430
+ const decoder = new TextDecoder('utf-8');
2431
+ const watText = decoder.decode(bytes);
2432
+
2433
+ return watText;
2434
+ }
2435
+
2436
+ /**
2437
+ * Decompile WASM bytes to GLSL source code.
2438
+ *
2439
+ * This uses the WASM-to-GLSL decompiler to convert compiled shader WASM
2440
+ * back into readable GLSL-like code.
2441
+ *
2442
+ * @param {number} ctxHandle - Context handle
2443
+ * @param {number} programHandle - Program handle
2444
+ * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2445
+ * @returns {string | null} GLSL source code or null if not available
2446
+ */
2447
+ export function getShaderGlsl(ctxHandle, programHandle, shaderType) {
2448
+ const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2449
+ if (!ctx) {
2450
+ throw new Error('Invalid context handle');
2451
+ }
2452
+
2453
+ // First get the WASM bytes for the shader
2454
+ const wasmBytes = getShaderModule(ctxHandle, programHandle, shaderType);
2455
+ if (!wasmBytes) {
2456
+ return null;
2457
+ }
2458
+
2459
+ const ex = ctx._instance.exports;
2460
+ if (!ex || typeof ex.wasm_decompile_to_glsl !== 'function') {
2461
+ throw new Error('wasm_decompile_to_glsl not found');
2462
+ }
2463
+
2464
+ // Allocate memory in WASM for the input bytes
2465
+ const wasmBytesLen = wasmBytes.length;
2466
+ const wasmBytesPtr = ex.wasm_alloc(wasmBytesLen);
2467
+ if (wasmBytesPtr === 0) {
2468
+ throw new Error('Failed to allocate memory for WASM bytes');
2469
+ }
2470
+
2471
+ try {
2472
+ // Copy WASM bytes to linear memory
2473
+ const mem = new Uint8Array(ex.memory.buffer);
2474
+ mem.set(wasmBytes, wasmBytesPtr);
2475
+
2476
+ // Call the decompiler
2477
+ const resultLen = ex.wasm_decompile_to_glsl(wasmBytesPtr, wasmBytesLen);
2478
+
2479
+ if (resultLen === 0) {
2480
+ return null;
2481
+ }
2482
+
2483
+ // Get the decompiled GLSL
2484
+ const glslPtr = ex.wasm_get_decompiled_glsl_ptr();
2485
+ const glslLen = ex.wasm_get_decompiled_glsl_len();
2486
+
2487
+ if (glslPtr === 0 || glslLen === 0) {
2488
+ return null;
2489
+ }
2490
+
2491
+ // Read the GLSL string
2492
+ const glslBytes = new Uint8Array(ex.memory.buffer).subarray(glslPtr, glslPtr + glslLen);
2493
+ const decoder = new TextDecoder('utf-8');
2494
+ return decoder.decode(glslBytes);
2495
+ } finally {
2496
+ // Free the allocated memory
2497
+ ex.wasm_free(wasmBytesPtr);
2498
+ }
2499
+ }
2500
+
2501
+ /**
2502
+ * Decompile raw WASM bytes to GLSL source code.
2503
+ *
2504
+ * This is a lower-level API that takes raw WASM bytes directly.
2505
+ *
2506
+ * @param {WasmWebGL2RenderingContext} gl - WebGL2 context
2507
+ * @param {Uint8Array} wasmBytes - Raw WASM bytecode to decompile
2508
+ * @returns {string | null} GLSL source code or null on error
2509
+ */
2510
+ export function decompileWasmToGlsl(gl, wasmBytes) {
2511
+ if (!gl || !gl._instance) {
2512
+ throw new Error('Invalid WebGL2 context');
2513
+ }
2514
+
2515
+ const ex = gl._instance.exports;
2516
+ if (!ex || typeof ex.wasm_decompile_to_glsl !== 'function') {
2517
+ throw new Error('wasm_decompile_to_glsl not found');
2518
+ }
2519
+
2520
+ // Allocate memory in WASM for the input bytes
2521
+ const wasmBytesLen = wasmBytes.length;
2522
+ const wasmBytesPtr = ex.wasm_alloc(wasmBytesLen);
2523
+ if (wasmBytesPtr === 0) {
2524
+ throw new Error('Failed to allocate memory for WASM bytes');
2525
+ }
2526
+
2527
+ try {
2528
+ // Copy WASM bytes to linear memory
2529
+ const mem = new Uint8Array(ex.memory.buffer);
2530
+ mem.set(wasmBytes, wasmBytesPtr);
2531
+
2532
+ // Call the decompiler
2533
+ const resultLen = ex.wasm_decompile_to_glsl(wasmBytesPtr, wasmBytesLen);
2534
+
2535
+ if (resultLen === 0) {
2536
+ return null;
2537
+ }
2538
+
2539
+ // Get the decompiled GLSL
2540
+ const glslPtr = ex.wasm_get_decompiled_glsl_ptr();
2541
+ const glslLen = ex.wasm_get_decompiled_glsl_len();
2542
+
2543
+ if (glslPtr === 0 || glslLen === 0) {
2544
+ return null;
2545
+ }
2546
+
2547
+ // Read the GLSL string
2548
+ const glslBytes = new Uint8Array(ex.memory.buffer).subarray(glslPtr, glslPtr + glslLen);
2549
+ const decoder = new TextDecoder('utf-8');
2550
+ return decoder.decode(glslBytes);
2551
+ } finally {
2552
+ // Free the allocated memory
2553
+ ex.wasm_free(wasmBytesPtr);
2554
+ }
2555
+ }