webgl2 1.2.1 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2483 +1,2559 @@
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 = 0x8228;
176
+ RGB_INTEGER = 0x8D98;
177
+ RGBA_INTEGER = 0x8D9E;
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_ === 0x1405 || type_ === 0x1404) { // GL_UNSIGNED_INT or GL_INT
612
+ if (format === 0x8D9E) bpp = 16; // GL_RGBA_INTEGER
613
+ else if (format === 0x8228) bpp = 8; // GL_RG_INTEGER
614
+ else if (format === 0x8D94) bpp = 4; // GL_RED_INTEGER
615
+ } else if (type_ === 0x1401) { // GL_UNSIGNED_BYTE
616
+ if (format === 0x1908) bpp = 4;
617
+ }
618
+
619
+ const len = width * height * bpp;
620
+ if (!out || out.byteLength < len) {
621
+ throw new Error(`output buffer too small (need ${len} bytes, have ${out ? out.byteLength : 0})`);
622
+ }
623
+
624
+ const ptr = ex.wasm_alloc(len);
625
+ if (ptr === 0) throw new Error('Failed to allocate memory for readPixels output');
626
+
627
+ try {
628
+ const code = ex.wasm_ctx_read_pixels(
629
+ this._ctxHandle,
630
+ x | 0,
631
+ y | 0,
632
+ width >>> 0,
633
+ height >>> 0,
634
+ format >>> 0,
635
+ type_ >>> 0,
636
+ ptr >>> 0,
637
+ len >>> 0
638
+ );
639
+ _checkErr(code, this._instance);
640
+
641
+ const mem = new Uint8Array(ex.memory.buffer);
642
+ const src = mem.subarray(ptr, ptr + len);
643
+ const out_bytes = new Uint8Array(out.buffer, out.byteOffset, len);
644
+ out_bytes.set(src);
645
+ } finally {
646
+ ex.wasm_free(ptr);
647
+ }
648
+ }
649
+
650
+ // --- Stubs for unimplemented WebGL2 methods (forwarding API surface) ---
651
+ // These are intentionally not implemented in the prototype. They allow
652
+ // callers to detect missing functionality early with a uniform error.
653
+
654
+ createShader(type) {
655
+ this._assertNotDestroyed();
656
+ const ex = this._instance.exports;
657
+ if (!ex || typeof ex.wasm_ctx_create_shader !== 'function') {
658
+ throw new Error('wasm_ctx_create_shader not found');
659
+ }
660
+ const handle = ex.wasm_ctx_create_shader(this._ctxHandle, type >>> 0);
661
+ if (handle === 0) {
662
+ const msg = readErrorMessage(this._instance);
663
+ throw new Error(`Failed to create shader: ${msg}`);
664
+ }
665
+ return new WasmWebGLShader(this, handle);
666
+ }
667
+
668
+ shaderSource(shader, source) {
669
+ this._assertNotDestroyed();
670
+ const ex = this._instance.exports;
671
+ if (!ex || typeof ex.wasm_ctx_shader_source !== 'function') {
672
+ throw new Error('wasm_ctx_shader_source not found');
673
+ }
674
+
675
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
676
+ const sourceStr = String(source);
677
+ const bytes = new TextEncoder().encode(sourceStr);
678
+ const len = bytes.length;
679
+ const ptr = ex.wasm_alloc(len);
680
+ if (ptr === 0) throw new Error('Failed to allocate memory for shaderSource');
681
+
682
+ try {
683
+ const mem = new Uint8Array(ex.memory.buffer);
684
+ mem.set(bytes, ptr);
685
+ const code = ex.wasm_ctx_shader_source(this._ctxHandle, shaderHandle, ptr, len);
686
+ _checkErr(code, this._instance);
687
+ } finally {
688
+ ex.wasm_free(ptr);
689
+ }
690
+ }
691
+
692
+ compileShader(shader) {
693
+ this._assertNotDestroyed();
694
+ const ex = this._instance.exports;
695
+ if (!ex || typeof ex.wasm_ctx_compile_shader !== 'function') {
696
+ throw new Error('wasm_ctx_compile_shader not found');
697
+ }
698
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
699
+ const code = ex.wasm_ctx_compile_shader(this._ctxHandle, shaderHandle);
700
+ _checkErr(code, this._instance);
701
+ }
702
+
703
+ deleteShader(shader) {
704
+ this._assertNotDestroyed();
705
+ const ex = this._instance.exports;
706
+ if (!ex || typeof ex.wasm_ctx_delete_shader !== 'function') {
707
+ throw new Error('wasm_ctx_delete_shader not found');
708
+ }
709
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
710
+ const code = ex.wasm_ctx_delete_shader(this._ctxHandle, shaderHandle);
711
+ _checkErr(code, this._instance);
712
+ if (shader && typeof shader === 'object') {
713
+ try { shader._handle = 0; shader._deleted = true; } catch (e) { /* ignore */ }
714
+ }
715
+ }
716
+
717
+ createProgram() {
718
+ this._assertNotDestroyed();
719
+ const ex = this._instance.exports;
720
+ if (!ex || typeof ex.wasm_ctx_create_program !== 'function') {
721
+ throw new Error('wasm_ctx_create_program not found');
722
+ }
723
+ const handle = ex.wasm_ctx_create_program(this._ctxHandle);
724
+ if (handle === 0) {
725
+ const msg = readErrorMessage(this._instance);
726
+ throw new Error(`Failed to create program: ${msg}`);
727
+ }
728
+ return new WasmWebGLProgram(this, handle);
729
+ }
730
+
731
+ attachShader(program, shader) {
732
+ this._assertNotDestroyed();
733
+ const ex = this._instance.exports;
734
+ if (!ex || typeof ex.wasm_ctx_attach_shader !== 'function') {
735
+ throw new Error('wasm_ctx_attach_shader not found');
736
+ }
737
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
738
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
739
+ const code = ex.wasm_ctx_attach_shader(this._ctxHandle, programHandle, shaderHandle);
740
+ _checkErr(code, this._instance);
741
+ }
742
+
743
+ detachShader(program, shader) { this._assertNotDestroyed(); throw new Error('not implemented'); }
744
+
745
+ getActiveUniform(program, index) {
746
+ this._assertNotDestroyed();
747
+ const ex = this._instance.exports;
748
+ if (!ex || typeof ex.wasm_ctx_get_active_uniform !== 'function') {
749
+ throw new Error('wasm_ctx_get_active_uniform 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_uniform(
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
+ getActiveAttrib(program, index) {
793
+ this._assertNotDestroyed();
794
+ const ex = this._instance.exports;
795
+ if (!ex || typeof ex.wasm_ctx_get_active_attrib !== 'function') {
796
+ throw new Error('wasm_ctx_get_active_attrib not found');
797
+ }
798
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
799
+
800
+ // Allocate buffers: size(4) + type(4) + name(256)
801
+ const sizePtr = ex.wasm_alloc(4);
802
+ const typePtr = ex.wasm_alloc(4);
803
+ const nameMaxLen = 256;
804
+ const namePtr = ex.wasm_alloc(nameMaxLen);
805
+
806
+ try {
807
+ const nameLen = ex.wasm_ctx_get_active_attrib(
808
+ this._ctxHandle,
809
+ programHandle,
810
+ index >>> 0,
811
+ sizePtr,
812
+ typePtr,
813
+ namePtr,
814
+ nameMaxLen
815
+ );
816
+
817
+ if (nameLen === 0) {
818
+ return null;
819
+ }
820
+
821
+ const mem32SizeIdx = sizePtr >>> 2;
822
+ const mem32TypeIdx = typePtr >>> 2;
823
+
824
+ const size = new Int32Array(ex.memory.buffer)[mem32SizeIdx];
825
+ const type_ = new Uint32Array(ex.memory.buffer)[mem32TypeIdx];
826
+
827
+ const nameBytes = new Uint8Array(ex.memory.buffer, namePtr, nameLen);
828
+ const name = new TextDecoder().decode(nameBytes);
829
+
830
+ return { name, size, type: type_ };
831
+
832
+ } finally {
833
+ ex.wasm_free(sizePtr);
834
+ ex.wasm_free(typePtr);
835
+ ex.wasm_free(namePtr);
836
+ }
837
+ }
838
+
839
+ linkProgram(program) {
840
+ this._assertNotDestroyed();
841
+ const ex = this._instance.exports;
842
+ if (!ex || typeof ex.wasm_ctx_link_program !== 'function') {
843
+ throw new Error('wasm_ctx_link_program not found');
844
+ }
845
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
846
+ const code = ex.wasm_ctx_link_program(this._ctxHandle, programHandle);
847
+ _checkErr(code, this._instance);
848
+
849
+ // After linking, we need to instantiate the WASM modules on the host.
850
+ if (program && typeof program === 'object') {
851
+ const linkStatus = this.getProgramParameter(program, this.LINK_STATUS);
852
+ if (linkStatus) {
853
+ this._instantiateProgramShaders(program);
854
+ }
855
+ }
856
+ }
857
+
858
+ _instantiateProgramShaders(program) {
859
+ const vsWasm = this.getProgramWasm(program, this.VERTEX_SHADER);
860
+ const fsWasm = this.getProgramWasm(program, this.FRAGMENT_SHADER);
861
+
862
+ if (!vsWasm || !fsWasm) {
863
+ return;
864
+ }
865
+
866
+ // Allocate table slots for both shaders
867
+ const vsIdx = this._tableAllocator ? this._tableAllocator.allocate() : null;
868
+ const fsIdx = this._tableAllocator ? this._tableAllocator.allocate() : null;
869
+
870
+ const createDebugEnv = (type, instanceRef) => {
871
+ if (!this._debugShaders) return {};
872
+
873
+ const stubCode = this.getProgramDebugStub(program, type);
874
+ if (!stubCode) return {};
875
+
876
+ // // Add sourceURL for debugging
877
+ // const debugName = `shader_stub_program_${program._handle}_${type === this.VERTEX_SHADER ? 'vs' : 'fs'}.js`;
878
+ // const codeWithUrl = stubCode + `\n//# sourceURL=${debugName}`;
879
+
880
+ let stubFuncs;
881
+ try {
882
+ // Eval the stub array
883
+ stubFuncs = (0, eval)(stubCode);
884
+ } catch (e) {
885
+ console.error("Failed to eval debug stub:", e);
886
+ return {};
887
+ }
888
+
889
+ return {
890
+ debug_step: (line, funcIdx, resultPtr) => {
891
+ if (line === 999999) {
892
+ return;
893
+ }
894
+ const func = stubFuncs[line - 1];
895
+ if (func) {
896
+ const ctx = {
897
+ go: () => {
898
+ // Trampoline logic would go here
899
+ // For now we rely on WASM calling the function after debug_step returns
900
+ }
901
+ };
902
+ try {
903
+ func.call(ctx);
904
+ } catch (e) {
905
+ console.error("Error in debug stub:", e);
906
+ }
907
+ }
908
+ }
909
+ };
910
+ };
911
+
912
+ let vsModule;
913
+ vsModule = new WebAssembly.Module(vsWasm);
914
+ const vsInstanceRef = { current: null };
915
+ const vsDebugEnv = createDebugEnv(this.VERTEX_SHADER, vsInstanceRef);
916
+
917
+ const env = {
918
+ memory: this._instance.exports.memory,
919
+ __indirect_function_table: this._sharedTable,
920
+ ACTIVE_ATTR_PTR: this._turboGlobals.ACTIVE_ATTR_PTR,
921
+ ACTIVE_UNIFORM_PTR: this._turboGlobals.ACTIVE_UNIFORM_PTR,
922
+ ACTIVE_VARYING_PTR: this._turboGlobals.ACTIVE_VARYING_PTR,
923
+ ACTIVE_PRIVATE_PTR: this._turboGlobals.ACTIVE_PRIVATE_PTR,
924
+ ACTIVE_TEXTURE_PTR: this._turboGlobals.ACTIVE_TEXTURE_PTR,
925
+ ACTIVE_FRAME_SP: this._turboGlobals.ACTIVE_FRAME_SP,
926
+ ...vsDebugEnv
927
+ };
928
+
929
+ // Add math builtins from renderer (skipping host)
930
+ const mathFuncs = [
931
+ 'gl_sin', 'gl_cos', 'gl_tan', 'gl_asin', 'gl_acos', 'gl_atan', 'gl_atan2',
932
+ 'gl_exp', 'gl_exp2', 'gl_log', 'gl_log2', 'gl_pow',
933
+ 'gl_sinh', 'gl_cosh', 'gl_tanh', 'gl_asinh', 'gl_acosh', 'gl_atanh'
934
+ ];
935
+ for (const name of mathFuncs) {
936
+ if (this._instance.exports[name]) {
937
+ env[name] = this._instance.exports[name];
938
+ }
939
+ }
940
+
941
+ program._vsInstance = new WebAssembly.Instance(vsModule, {
942
+ env
943
+ });
944
+ vsInstanceRef.current = program._vsInstance;
945
+
946
+ // Register in table
947
+ if (this._sharedTable && vsIdx !== null && program._vsInstance.exports.main) {
948
+ this._sharedTable.set(vsIdx, program._vsInstance.exports.main);
949
+ program._vsTableIndex = vsIdx;
950
+ }
951
+
952
+ let fsModule;
953
+ fsModule = new WebAssembly.Module(fsWasm);
954
+ const fsInstanceRef = { current: null };
955
+ const fsDebugEnv = createDebugEnv(this.FRAGMENT_SHADER, fsInstanceRef);
956
+
957
+ const fsEnv = {
958
+ memory: this._instance.exports.memory,
959
+ __indirect_function_table: this._sharedTable,
960
+ ACTIVE_ATTR_PTR: this._turboGlobals.ACTIVE_ATTR_PTR,
961
+ ACTIVE_UNIFORM_PTR: this._turboGlobals.ACTIVE_UNIFORM_PTR,
962
+ ACTIVE_VARYING_PTR: this._turboGlobals.ACTIVE_VARYING_PTR,
963
+ ACTIVE_PRIVATE_PTR: this._turboGlobals.ACTIVE_PRIVATE_PTR,
964
+ ACTIVE_TEXTURE_PTR: this._turboGlobals.ACTIVE_TEXTURE_PTR,
965
+ ACTIVE_FRAME_SP: this._turboGlobals.ACTIVE_FRAME_SP,
966
+ ...fsDebugEnv
967
+ };
968
+
969
+ for (const name of mathFuncs) {
970
+ if (this._instance.exports[name]) {
971
+ fsEnv[name] = this._instance.exports[name];
972
+ }
973
+ }
974
+
975
+ program._fsInstance = new WebAssembly.Instance(fsModule, {
976
+ env: fsEnv
977
+ });
978
+ fsInstanceRef.current = program._fsInstance;
979
+
980
+ // Register in table
981
+ if (this._sharedTable && fsIdx !== null && program._fsInstance.exports.main) {
982
+ this._sharedTable.set(fsIdx, program._fsInstance.exports.main);
983
+ program._fsTableIndex = fsIdx;
984
+ }
985
+
986
+ // Notify Rust of table indices (requires Phase 4)
987
+ if (vsIdx !== null && fsIdx !== null) {
988
+ const ex = this._instance.exports;
989
+ if (ex.wasm_ctx_register_shader_indices) {
990
+ ex.wasm_ctx_register_shader_indices(
991
+ this._ctxHandle,
992
+ program._handle,
993
+ vsIdx,
994
+ fsIdx
995
+ );
996
+ }
997
+ }
998
+ }
999
+
1000
+ getProgramDebugStub(program, shaderType) {
1001
+ this._assertNotDestroyed();
1002
+ const ex = this._instance.exports;
1003
+ if (!ex || typeof ex.wasm_ctx_get_program_debug_stub !== 'function') {
1004
+ return null;
1005
+ }
1006
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1007
+ const len = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, 0, 0);
1008
+ if (len === 0) return null;
1009
+
1010
+ const ptr = ex.wasm_alloc(len);
1011
+ if (ptr === 0) return null;
1012
+
1013
+ try {
1014
+ const actualLen = ex.wasm_ctx_get_program_debug_stub(this._ctxHandle, programHandle, shaderType, ptr, len);
1015
+ const mem = new Uint8Array(ex.memory.buffer);
1016
+ const bytes = mem.subarray(ptr, ptr + actualLen);
1017
+ return new TextDecoder().decode(bytes);
1018
+ } finally {
1019
+ ex.wasm_free(ptr);
1020
+ }
1021
+ }
1022
+
1023
+ deleteProgram(program) {
1024
+ this._assertNotDestroyed();
1025
+ const ex = this._instance.exports;
1026
+ if (!ex || typeof ex.wasm_ctx_delete_program !== 'function') {
1027
+ throw new Error('wasm_ctx_delete_program not found');
1028
+ }
1029
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1030
+
1031
+ // Table indices are now freed by Rust when the Program's refcount reaches zero.
1032
+ // This allows bound programs to remain valid even if deleted by the user,
1033
+ // as required by the WebGL specification.
1034
+
1035
+ const code = ex.wasm_ctx_delete_program(this._ctxHandle, programHandle);
1036
+ _checkErr(code, this._instance);
1037
+ if (program && typeof program === 'object') {
1038
+ try { program._handle = 0; program._deleted = true; } catch (e) { /* ignore */ }
1039
+ }
1040
+ }
1041
+
1042
+ useProgram(program) {
1043
+ this._assertNotDestroyed();
1044
+ const ex = this._instance.exports;
1045
+ if (!ex || typeof ex.wasm_ctx_use_program !== 'function') {
1046
+ throw new Error('wasm_ctx_use_program not found');
1047
+ }
1048
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1049
+ const code = ex.wasm_ctx_use_program(this._ctxHandle, programHandle);
1050
+ _checkErr(code, this._instance);
1051
+ this._currentProgram = program;
1052
+ }
1053
+
1054
+ getShaderParameter(shader, pname) {
1055
+ this._assertNotDestroyed();
1056
+ const ex = this._instance.exports;
1057
+ if (!ex || typeof ex.wasm_ctx_get_shader_parameter !== 'function') {
1058
+ throw new Error('wasm_ctx_get_shader_parameter not found');
1059
+ }
1060
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
1061
+ const val = ex.wasm_ctx_get_shader_parameter(this._ctxHandle, shaderHandle, pname >>> 0);
1062
+
1063
+ // WebGL returns boolean for status parameters
1064
+ if (pname === 0x8B81 /* COMPILE_STATUS */ || pname === 0x8B80 /* DELETE_STATUS */) {
1065
+ return !!val;
1066
+ }
1067
+ return val;
1068
+ }
1069
+
1070
+ getProgramParameter(program, pname) {
1071
+ this._assertNotDestroyed();
1072
+ const ex = this._instance.exports;
1073
+ if (!ex || typeof ex.wasm_ctx_get_program_parameter !== 'function') {
1074
+ throw new Error('wasm_ctx_get_program_parameter not found');
1075
+ }
1076
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1077
+ const val = ex.wasm_ctx_get_program_parameter(this._ctxHandle, programHandle, pname >>> 0);
1078
+
1079
+ // WebGL returns boolean for status parameters
1080
+ if (pname === 0x8B82 /* LINK_STATUS */ || pname === 0x8B80 /* DELETE_STATUS */ || pname === 0x8B83 /* VALIDATE_STATUS */) {
1081
+ return !!val;
1082
+ }
1083
+ return val;
1084
+ }
1085
+
1086
+ getShaderInfoLog(shader) {
1087
+ this._assertNotDestroyed();
1088
+ const ex = this._instance.exports;
1089
+ if (!ex || typeof ex.wasm_ctx_get_shader_info_log !== 'function') {
1090
+ throw new Error('wasm_ctx_get_shader_info_log not found');
1091
+ }
1092
+ const shaderHandle = shader && typeof shader === 'object' && typeof shader._handle === 'number' ? shader._handle : (shader >>> 0);
1093
+
1094
+ const maxLen = 1024;
1095
+ const ptr = ex.wasm_alloc(maxLen);
1096
+ if (ptr === 0) throw new Error('Failed to allocate memory for getShaderInfoLog');
1097
+
1098
+ try {
1099
+ const len = ex.wasm_ctx_get_shader_info_log(this._ctxHandle, shaderHandle, ptr, maxLen);
1100
+ const mem = new Uint8Array(ex.memory.buffer);
1101
+ const bytes = mem.subarray(ptr, ptr + len);
1102
+ return new TextDecoder().decode(bytes);
1103
+ } finally {
1104
+ ex.wasm_free(ptr);
1105
+ }
1106
+ }
1107
+
1108
+ getProgramInfoLog(program) {
1109
+ this._assertNotDestroyed();
1110
+ const ex = this._instance.exports;
1111
+ if (!ex || typeof ex.wasm_ctx_get_program_info_log !== 'function') {
1112
+ throw new Error('wasm_ctx_get_program_info_log not found');
1113
+ }
1114
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1115
+
1116
+ const maxLen = 1024;
1117
+ const ptr = ex.wasm_alloc(maxLen);
1118
+ if (ptr === 0) throw new Error('Failed to allocate memory for getProgramInfoLog');
1119
+
1120
+ try {
1121
+ const len = ex.wasm_ctx_get_program_info_log(this._ctxHandle, programHandle, ptr, maxLen);
1122
+ const mem = new Uint8Array(ex.memory.buffer);
1123
+ const bytes = mem.subarray(ptr, ptr + len);
1124
+ return new TextDecoder().decode(bytes);
1125
+ } finally {
1126
+ ex.wasm_free(ptr);
1127
+ }
1128
+ }
1129
+
1130
+ getProgramWasm(program, shaderType) {
1131
+ this._assertNotDestroyed();
1132
+ const ex = this._instance.exports;
1133
+ if (!ex || typeof ex.wasm_ctx_get_program_wasm_len !== 'function') {
1134
+ throw new Error('wasm_ctx_get_program_wasm_len not found');
1135
+ }
1136
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1137
+ const len = ex.wasm_ctx_get_program_wasm_len(this._ctxHandle, programHandle, shaderType);
1138
+ if (len === 0) return null;
1139
+
1140
+ const ptr = ex.wasm_alloc(len);
1141
+ if (ptr === 0) throw new Error('Failed to allocate memory for getProgramWasm');
1142
+
1143
+ try {
1144
+ const actualLen = ex.wasm_ctx_get_program_wasm(this._ctxHandle, programHandle, shaderType, ptr, len);
1145
+ const mem = new Uint8Array(ex.memory.buffer);
1146
+ return new Uint8Array(mem.buffer, ptr, actualLen).slice();
1147
+ } finally {
1148
+ ex.wasm_free(ptr);
1149
+ }
1150
+ }
1151
+
1152
+ getAttribLocation(program, name) {
1153
+ this._assertNotDestroyed();
1154
+ const ex = this._instance.exports;
1155
+ if (!ex || typeof ex.wasm_ctx_get_attrib_location !== 'function') {
1156
+ throw new Error('wasm_ctx_get_attrib_location not found');
1157
+ }
1158
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1159
+ const nameStr = String(name);
1160
+ const bytes = new TextEncoder().encode(nameStr);
1161
+ const len = bytes.length;
1162
+ const ptr = ex.wasm_alloc(len);
1163
+ if (ptr === 0) throw new Error('Failed to allocate memory for getAttribLocation');
1164
+
1165
+ try {
1166
+ const mem = new Uint8Array(ex.memory.buffer);
1167
+ mem.set(bytes, ptr);
1168
+ return ex.wasm_ctx_get_attrib_location(this._ctxHandle, programHandle, ptr, len);
1169
+ } finally {
1170
+ ex.wasm_free(ptr);
1171
+ }
1172
+ }
1173
+
1174
+ bindAttribLocation(program, index, name) {
1175
+ this._assertNotDestroyed();
1176
+ const ex = this._instance.exports;
1177
+ if (!ex || typeof ex.wasm_ctx_bind_attrib_location !== 'function') {
1178
+ throw new Error('wasm_ctx_bind_attrib_location not found');
1179
+ }
1180
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1181
+ const nameStr = String(name);
1182
+ const bytes = new TextEncoder().encode(nameStr);
1183
+ const len = bytes.length;
1184
+ const ptr = ex.wasm_alloc(len);
1185
+ if (ptr === 0) throw new Error('Failed to allocate memory for bindAttribLocation');
1186
+
1187
+ try {
1188
+ const mem = new Uint8Array(ex.memory.buffer);
1189
+ mem.set(bytes, ptr);
1190
+ const code = ex.wasm_ctx_bind_attrib_location(this._ctxHandle, programHandle, index >>> 0, ptr, len);
1191
+ _checkErr(code, this._instance);
1192
+ } finally {
1193
+ ex.wasm_free(ptr);
1194
+ }
1195
+ }
1196
+
1197
+ enableVertexAttribArray(index) {
1198
+ this._assertNotDestroyed();
1199
+ const ex = this._instance.exports;
1200
+ if (!ex || typeof ex.wasm_ctx_enable_vertex_attrib_array !== 'function') {
1201
+ throw new Error('wasm_ctx_enable_vertex_attrib_array not found');
1202
+ }
1203
+ const code = ex.wasm_ctx_enable_vertex_attrib_array(this._ctxHandle, index >>> 0);
1204
+ _checkErr(code, this._instance);
1205
+ }
1206
+
1207
+ disableVertexAttribArray(index) {
1208
+ this._assertNotDestroyed();
1209
+ const ex = this._instance.exports;
1210
+ if (!ex || typeof ex.wasm_ctx_disable_vertex_attrib_array !== 'function') {
1211
+ throw new Error('wasm_ctx_disable_vertex_attrib_array not found');
1212
+ }
1213
+ const code = ex.wasm_ctx_disable_vertex_attrib_array(this._ctxHandle, index >>> 0);
1214
+ _checkErr(code, this._instance);
1215
+ }
1216
+
1217
+ vertexAttribPointer(index, size, type, normalized, stride, offset) {
1218
+ this._assertNotDestroyed();
1219
+ const ex = this._instance.exports;
1220
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_pointer !== 'function') {
1221
+ throw new Error('wasm_ctx_vertex_attrib_pointer not found');
1222
+ }
1223
+ const code = ex.wasm_ctx_vertex_attrib_pointer(
1224
+ this._ctxHandle,
1225
+ index >>> 0,
1226
+ size >>> 0,
1227
+ type >>> 0,
1228
+ normalized ? 1 : 0,
1229
+ stride >>> 0,
1230
+ offset >>> 0
1231
+ );
1232
+ if (code === 5) return; // ERR_GL
1233
+ _checkErr(code, this._instance);
1234
+ }
1235
+
1236
+ vertexAttribIPointer(index, size, type, stride, offset) {
1237
+ this._assertNotDestroyed();
1238
+ const ex = this._instance.exports;
1239
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_ipointer !== 'function') {
1240
+ throw new Error('wasm_ctx_vertex_attrib_ipointer not found');
1241
+ }
1242
+ const code = ex.wasm_ctx_vertex_attrib_ipointer(
1243
+ this._ctxHandle,
1244
+ index >>> 0,
1245
+ size >>> 0,
1246
+ type >>> 0,
1247
+ stride >>> 0,
1248
+ offset >>> 0
1249
+ );
1250
+ if (code === 5) return; // ERR_GL
1251
+ _checkErr(code, this._instance);
1252
+ }
1253
+
1254
+ vertexAttrib1f(index, v0) {
1255
+ this._assertNotDestroyed();
1256
+ const ex = this._instance.exports;
1257
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib1f !== 'function') {
1258
+ throw new Error('wasm_ctx_vertex_attrib1f not found');
1259
+ }
1260
+ const code = ex.wasm_ctx_vertex_attrib1f(this._ctxHandle, index >>> 0, +v0);
1261
+ if (code === 5) return; // ERR_GL
1262
+ _checkErr(code, this._instance);
1263
+ }
1264
+ vertexAttrib2f(index, v0, v1) {
1265
+ this._assertNotDestroyed();
1266
+ const ex = this._instance.exports;
1267
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib2f !== 'function') {
1268
+ throw new Error('wasm_ctx_vertex_attrib2f not found');
1269
+ }
1270
+ const code = ex.wasm_ctx_vertex_attrib2f(this._ctxHandle, index >>> 0, +v0, +v1);
1271
+ if (code === 5) return; // ERR_GL
1272
+ _checkErr(code, this._instance);
1273
+ }
1274
+ vertexAttrib3f(index, v0, v1, v2) {
1275
+ this._assertNotDestroyed();
1276
+ const ex = this._instance.exports;
1277
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib3f !== 'function') {
1278
+ throw new Error('wasm_ctx_vertex_attrib3f not found');
1279
+ }
1280
+ const code = ex.wasm_ctx_vertex_attrib3f(this._ctxHandle, index >>> 0, +v0, +v1, +v2);
1281
+ if (code === 5) return; // ERR_GL
1282
+ _checkErr(code, this._instance);
1283
+ }
1284
+ vertexAttrib4f(index, v0, v1, v2, v3) {
1285
+ this._assertNotDestroyed();
1286
+ const ex = this._instance.exports;
1287
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib4f !== 'function') {
1288
+ throw new Error('wasm_ctx_vertex_attrib4f not found');
1289
+ }
1290
+ const code = ex.wasm_ctx_vertex_attrib4f(this._ctxHandle, index >>> 0, +v0, +v1, +v2, +v3);
1291
+ if (code === 5) return; // ERR_GL
1292
+ _checkErr(code, this._instance);
1293
+ }
1294
+
1295
+ vertexAttrib1fv(index, v) {
1296
+ if (v && v.length >= 1) {
1297
+ this.vertexAttrib1f(index, v[0]);
1298
+ } else {
1299
+ this._setError(0x0501);
1300
+ }
1301
+ }
1302
+ vertexAttrib2fv(index, v) {
1303
+ if (v && v.length >= 2) {
1304
+ this.vertexAttrib2f(index, v[0], v[1]);
1305
+ } else {
1306
+ this._setError(0x0501);
1307
+ }
1308
+ }
1309
+ vertexAttrib3fv(index, v) {
1310
+ if (v && v.length >= 3) {
1311
+ this.vertexAttrib3f(index, v[0], v[1], v[2]);
1312
+ } else {
1313
+ this._setError(0x0501);
1314
+ }
1315
+ }
1316
+ vertexAttrib4fv(index, v) {
1317
+ if (v && v.length >= 4) {
1318
+ this.vertexAttrib4f(index, v[0], v[1], v[2], v[3]);
1319
+ } else {
1320
+ this._setError(0x0501);
1321
+ }
1322
+ }
1323
+
1324
+ vertexAttribI4i(index, v0, v1, v2, v3) {
1325
+ this._assertNotDestroyed();
1326
+ const ex = this._instance.exports;
1327
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_i4i !== 'function') {
1328
+ throw new Error('wasm_ctx_vertex_attrib_i4i not found');
1329
+ }
1330
+ const code = ex.wasm_ctx_vertex_attrib_i4i(this._ctxHandle, index >>> 0, v0 | 0, v1 | 0, v2 | 0, v3 | 0);
1331
+ if (code === 5) return; // ERR_GL
1332
+ _checkErr(code, this._instance);
1333
+ }
1334
+
1335
+ vertexAttribI4ui(index, v0, v1, v2, v3) {
1336
+ this._assertNotDestroyed();
1337
+ const ex = this._instance.exports;
1338
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_i4ui !== 'function') {
1339
+ throw new Error('wasm_ctx_vertex_attrib_i4ui not found');
1340
+ }
1341
+ const code = ex.wasm_ctx_vertex_attrib_i4ui(this._ctxHandle, index >>> 0, v0 >>> 0, v1 >>> 0, v2 >>> 0, v3 >>> 0);
1342
+ if (code === 5) return; // ERR_GL
1343
+ _checkErr(code, this._instance);
1344
+ }
1345
+
1346
+ vertexAttribI4iv(index, v) {
1347
+ if (v && v.length >= 4) {
1348
+ this.vertexAttribI4i(index, v[0], v[1], v[2], v[3]);
1349
+ } else {
1350
+ this._setError(0x0501);
1351
+ }
1352
+ }
1353
+
1354
+ vertexAttribI4uiv(index, v) {
1355
+ if (v && v.length >= 4) {
1356
+ this.vertexAttribI4ui(index, v[0], v[1], v[2], v[3]);
1357
+ } else {
1358
+ this._setError(0x0501);
1359
+ }
1360
+ }
1361
+
1362
+ vertexAttribDivisor(index, divisor) {
1363
+ this._assertNotDestroyed();
1364
+ const ex = this._instance.exports;
1365
+ if (!ex || typeof ex.wasm_ctx_vertex_attrib_divisor !== 'function') {
1366
+ throw new Error('wasm_ctx_vertex_attrib_divisor not found');
1367
+ }
1368
+ const code = ex.wasm_ctx_vertex_attrib_divisor(this._ctxHandle, index >>> 0, divisor >>> 0);
1369
+ _checkErr(code, this._instance);
1370
+ }
1371
+
1372
+ createBuffer() {
1373
+ this._assertNotDestroyed();
1374
+ const ex = this._instance.exports;
1375
+ if (!ex || typeof ex.wasm_ctx_create_buffer !== 'function') {
1376
+ throw new Error('wasm_ctx_create_buffer not found');
1377
+ }
1378
+ const handle = ex.wasm_ctx_create_buffer(this._ctxHandle);
1379
+ if (handle === 0) {
1380
+ const msg = readErrorMessage(this._instance);
1381
+ throw new Error(`Failed to create buffer: ${msg}`);
1382
+ }
1383
+ return new WasmWebGLBuffer(this, handle);
1384
+ }
1385
+
1386
+ bindBuffer(target, buffer) {
1387
+ this._assertNotDestroyed();
1388
+ const ex = this._instance.exports;
1389
+ if (!ex || typeof ex.wasm_ctx_bind_buffer !== 'function') {
1390
+ throw new Error('wasm_ctx_bind_buffer not found');
1391
+ }
1392
+ const handle = buffer && typeof buffer === 'object' && typeof buffer._handle === 'number' ? buffer._handle : (buffer >>> 0);
1393
+ const code = ex.wasm_ctx_bind_buffer(this._ctxHandle, target >>> 0, handle);
1394
+ _checkErr(code, this._instance);
1395
+ }
1396
+
1397
+ deleteBuffer(buffer) {
1398
+ this._assertNotDestroyed();
1399
+ const ex = this._instance.exports;
1400
+ if (!ex || typeof ex.wasm_ctx_delete_buffer !== 'function') {
1401
+ throw new Error('wasm_ctx_delete_buffer not found');
1402
+ }
1403
+ const handle = buffer && typeof buffer === 'object' && typeof buffer._handle === 'number' ? buffer._handle : (buffer >>> 0);
1404
+ const code = ex.wasm_ctx_delete_buffer(this._ctxHandle, handle);
1405
+ _checkErr(code, this._instance); if (buffer && typeof buffer === 'object') {
1406
+ try { buffer._handle = 0; buffer._deleted = true; } catch (e) { /* ignore */ }
1407
+ }
1408
+ }
1409
+
1410
+ bufferData(target, data, usage) {
1411
+ this._assertNotDestroyed();
1412
+ const ex = this._instance.exports;
1413
+ if (!ex || typeof ex.wasm_ctx_buffer_data !== 'function') {
1414
+ throw new Error('wasm_ctx_buffer_data not found');
1415
+ }
1416
+
1417
+ let bytes;
1418
+ if (data instanceof ArrayBuffer) {
1419
+ bytes = new Uint8Array(data);
1420
+ } else if (ArrayBuffer.isView(data)) {
1421
+ bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1422
+ } else if (typeof data === 'number') {
1423
+ bytes = new Uint8Array(data);
1424
+ } else {
1425
+ throw new Error('Invalid data type for bufferData');
1426
+ }
1427
+
1428
+ const len = bytes.length;
1429
+ if (len === 0) {
1430
+ const code = ex.wasm_ctx_buffer_data(this._ctxHandle, target >>> 0, 0, 0, usage >>> 0);
1431
+ _checkErr(code, this._instance);
1432
+ return;
1433
+ }
1434
+
1435
+ const ptr = ex.wasm_alloc(len);
1436
+ if (ptr === 0) throw new Error('Failed to allocate memory for bufferData');
1437
+
1438
+ try {
1439
+ const mem = new Uint8Array(ex.memory.buffer);
1440
+ mem.set(bytes, ptr);
1441
+ const code = ex.wasm_ctx_buffer_data(this._ctxHandle, target >>> 0, ptr, len, usage >>> 0);
1442
+ _checkErr(code, this._instance);
1443
+ } finally {
1444
+ ex.wasm_free(ptr);
1445
+ }
1446
+ }
1447
+
1448
+ bufferSubData(target, offset, data) {
1449
+ this._assertNotDestroyed();
1450
+ const ex = this._instance.exports;
1451
+ if (!ex || typeof ex.wasm_ctx_buffer_sub_data !== 'function') {
1452
+ throw new Error('wasm_ctx_buffer_sub_data not found');
1453
+ }
1454
+
1455
+ let bytes;
1456
+ if (data instanceof Uint8Array) bytes = data;
1457
+ else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1458
+ else if (data instanceof ArrayBuffer) bytes = new Uint8Array(data);
1459
+ else bytes = new Uint8Array(data); // Fallback for arrays
1460
+
1461
+ const len = bytes.length;
1462
+ const ptr = ex.wasm_alloc(len);
1463
+ if (ptr === 0) throw new Error('Failed to allocate memory for bufferSubData');
1464
+
1465
+ try {
1466
+ const mem = new Uint8Array(ex.memory.buffer);
1467
+ mem.set(bytes, ptr);
1468
+ const code = ex.wasm_ctx_buffer_sub_data(this._ctxHandle, target >>> 0, offset >>> 0, ptr, len);
1469
+ _checkErr(code, this._instance);
1470
+ } finally {
1471
+ ex.wasm_free(ptr);
1472
+ }
1473
+ }
1474
+ copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) {
1475
+ this._assertNotDestroyed();
1476
+ const ex = this._instance.exports;
1477
+ if (!ex || typeof ex.wasm_ctx_copy_buffer_sub_data !== 'function') {
1478
+ throw new Error('wasm_ctx_copy_buffer_sub_data not found');
1479
+ }
1480
+ const code = ex.wasm_ctx_copy_buffer_sub_data(
1481
+ this._ctxHandle,
1482
+ readTarget >>> 0,
1483
+ writeTarget >>> 0,
1484
+ readOffset >>> 0,
1485
+ writeOffset >>> 0,
1486
+ size >>> 0
1487
+ );
1488
+ _checkErr(code, this._instance);
1489
+ }
1490
+ getBufferParameter(target, pname) {
1491
+ this._assertNotDestroyed();
1492
+ const ex = this._instance.exports;
1493
+ if (!ex || typeof ex.wasm_ctx_get_buffer_parameter !== 'function') {
1494
+ throw new Error('wasm_ctx_get_buffer_parameter not found');
1495
+ }
1496
+ const val = ex.wasm_ctx_get_buffer_parameter(this._ctxHandle, target >>> 0, pname >>> 0);
1497
+ if (val < 0) {
1498
+ const msg = readErrorMessage(this._instance);
1499
+ throw new Error(`getBufferParameter failed: ${msg}`);
1500
+ }
1501
+ return val;
1502
+ }
1503
+ isBuffer(buffer) {
1504
+ this._assertNotDestroyed();
1505
+ if (!buffer || typeof buffer !== 'object' || !(buffer instanceof WasmWebGLBuffer)) return false;
1506
+ if (buffer._ctx !== this) return false;
1507
+ const ex = this._instance.exports;
1508
+ return ex.wasm_ctx_is_buffer(this._ctxHandle, buffer._handle) !== 0;
1509
+ }
1510
+
1511
+ drawArrays(mode, first, count) {
1512
+ this._assertNotDestroyed();
1513
+ const ex = this._instance.exports;
1514
+ if (!ex || typeof ex.wasm_ctx_draw_arrays !== 'function') {
1515
+ throw new Error('wasm_ctx_draw_arrays not found');
1516
+ }
1517
+ const code = ex.wasm_ctx_draw_arrays(this._ctxHandle, mode >>> 0, first >>> 0, count >>> 0);
1518
+ _checkErr(code, this._instance);
1519
+ }
1520
+
1521
+ drawElements(mode, count, type, offset) {
1522
+ this._assertNotDestroyed();
1523
+ const ex = this._instance.exports;
1524
+ if (!ex || typeof ex.wasm_ctx_draw_elements !== 'function') {
1525
+ throw new Error('wasm_ctx_draw_elements not found');
1526
+ }
1527
+ const code = ex.wasm_ctx_draw_elements(this._ctxHandle, mode >>> 0, count >>> 0, type >>> 0, offset >>> 0);
1528
+ _checkErr(code, this._instance);
1529
+ }
1530
+ drawArraysInstanced(mode, first, count, instanceCount) {
1531
+ this._assertNotDestroyed();
1532
+ const ex = this._instance.exports;
1533
+ if (!ex || typeof ex.wasm_ctx_draw_arrays_instanced !== 'function') {
1534
+ throw new Error('wasm_ctx_draw_arrays_instanced not found');
1535
+ }
1536
+ const code = ex.wasm_ctx_draw_arrays_instanced(this._ctxHandle, mode >>> 0, first | 0, count | 0, instanceCount | 0);
1537
+ _checkErr(code, this._instance);
1538
+ }
1539
+ drawElementsInstanced(mode, count, type, offset, instanceCount) {
1540
+ this._assertNotDestroyed();
1541
+ const ex = this._instance.exports;
1542
+ if (!ex || typeof ex.wasm_ctx_draw_elements_instanced !== 'function') {
1543
+ throw new Error('wasm_ctx_draw_elements_instanced not found');
1544
+ }
1545
+ const code = ex.wasm_ctx_draw_elements_instanced(this._ctxHandle, mode >>> 0, count | 0, type >>> 0, offset >>> 0, instanceCount | 0);
1546
+ _checkErr(code, this._instance);
1547
+ }
1548
+ drawRangeElements(mode, start, end, count, type, offset) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1549
+ drawBuffers(buffers) {
1550
+ this._assertNotDestroyed();
1551
+ const ex = this._instance.exports;
1552
+ if (!ex || typeof ex.wasm_ctx_draw_buffers !== 'function') {
1553
+ throw new Error('wasm_ctx_draw_buffers not found');
1554
+ }
1555
+
1556
+ const count = buffers.length;
1557
+ const bufs = new Uint32Array(count);
1558
+ for (let i = 0; i < count; i++) {
1559
+ bufs[i] = buffers[i];
1560
+ }
1561
+
1562
+ const ptr = ex.wasm_alloc(count * 4);
1563
+ const view = new Uint32Array(ex.memory.buffer, ptr, count);
1564
+ view.set(bufs);
1565
+
1566
+ const code = ex.wasm_ctx_draw_buffers(this._ctxHandle, ptr, count);
1567
+ ex.wasm_free(ptr, count * 4);
1568
+ _checkErr(code, this._instance);
1569
+ }
1570
+
1571
+ readBuffer(mode) {
1572
+ this._assertNotDestroyed();
1573
+ const ex = this._instance.exports;
1574
+ if (!ex || typeof ex.wasm_ctx_read_buffer !== 'function') {
1575
+ throw new Error('wasm_ctx_read_buffer not found');
1576
+ }
1577
+
1578
+ const code = ex.wasm_ctx_read_buffer(this._ctxHandle, mode);
1579
+ _checkErr(code, this._instance);
1580
+ }
1581
+
1582
+ createVertexArray() {
1583
+ this._assertNotDestroyed();
1584
+ const ex = this._instance.exports;
1585
+ if (!ex || typeof ex.wasm_ctx_create_vertex_array !== 'function') {
1586
+ throw new Error('wasm_ctx_create_vertex_array not found');
1587
+ }
1588
+ const handle = ex.wasm_ctx_create_vertex_array(this._ctxHandle);
1589
+ if (handle === 0) return null;
1590
+ return new WasmWebGLVertexArrayObject(this, handle);
1591
+ }
1592
+
1593
+ bindVertexArray(vao) {
1594
+ this._assertNotDestroyed();
1595
+ const ex = this._instance.exports;
1596
+ if (!ex || typeof ex.wasm_ctx_bind_vertex_array !== 'function') {
1597
+ throw new Error('wasm_ctx_bind_vertex_array not found');
1598
+ }
1599
+ const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao ? (vao >>> 0) : 0);
1600
+ const code = ex.wasm_ctx_bind_vertex_array(this._ctxHandle, handle);
1601
+ _checkErr(code, this._instance);
1602
+ }
1603
+
1604
+ deleteVertexArray(vao) {
1605
+ this._assertNotDestroyed();
1606
+ const ex = this._instance.exports;
1607
+ if (!ex || typeof ex.wasm_ctx_delete_vertex_array !== 'function') {
1608
+ throw new Error('wasm_ctx_delete_vertex_array not found');
1609
+ }
1610
+ const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
1611
+ const code = ex.wasm_ctx_delete_vertex_array(this._ctxHandle, handle);
1612
+ _checkErr(code, this._instance);
1613
+ if (vao && typeof vao === 'object') {
1614
+ try { vao._handle = 0; vao._deleted = true; } catch (e) { /* ignore */ }
1615
+ }
1616
+ }
1617
+
1618
+ isVertexArray(vao) {
1619
+ this._assertNotDestroyed();
1620
+ const ex = this._instance.exports;
1621
+ if (!ex || typeof ex.wasm_ctx_is_vertex_array !== 'function') {
1622
+ throw new Error('wasm_ctx_is_vertex_array not found');
1623
+ }
1624
+ const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
1625
+ const res = ex.wasm_ctx_is_vertex_array(this._ctxHandle, handle);
1626
+ return res !== 0;
1627
+ }
1628
+
1629
+ createTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1630
+ bindTransformFeedback(target, tf) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1631
+ beginTransformFeedback(primitiveMode) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1632
+ pauseTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1633
+ resumeTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1634
+ endTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1635
+ transformFeedbackVaryings(program, varyings, bufferMode) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1636
+ getTransformFeedbackVarying(program, index) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1637
+
1638
+ createQuery() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1639
+ deleteQuery(q) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1640
+ beginQuery(target, id) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1641
+ endQuery(target) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1642
+ getQueryParameter(query, pname) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1643
+
1644
+ fenceSync(condition, flags) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1645
+ clientWaitSync(sync, flags, timeout) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1646
+ waitSync(sync, flags, timeout) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1647
+ deleteSync(sync) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1648
+ getSyncParameter(sync, pname) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1649
+
1650
+ createSampler() { this._assertNotDestroyed(); throw new Error('not implemented'); }
1651
+ deleteSampler(s) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1652
+ bindSampler(unit, sampler) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1653
+ samplerParameteri(sampler, pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1654
+ samplerParameterf(sampler, pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1655
+
1656
+ activeTexture(texture) {
1657
+ this._assertNotDestroyed();
1658
+ const ex = this._instance.exports;
1659
+ if (!ex || typeof ex.wasm_ctx_active_texture !== 'function') {
1660
+ throw new Error('wasm_ctx_active_texture not found');
1661
+ }
1662
+ const code = ex.wasm_ctx_active_texture(this._ctxHandle, texture >>> 0);
1663
+ _checkErr(code, this._instance);
1664
+ // Track active texture unit in JS wrapper (GL_TEXTURE0 = 0x84C0)
1665
+ this._activeTextureUnit = (texture >>> 0) - 0x84C0;
1666
+ this._textureUnits = this._textureUnits || [];
1667
+ }
1668
+ texParameteri(target, pname, param) {
1669
+ this._assertNotDestroyed();
1670
+ const ex = this._instance.exports;
1671
+ if (!ex || typeof ex.wasm_ctx_tex_parameter_i !== 'function') {
1672
+ throw new Error('wasm_ctx_tex_parameter_i not found');
1673
+ }
1674
+ const code = ex.wasm_ctx_tex_parameter_i(this._ctxHandle, target >>> 0, pname >>> 0, param | 0);
1675
+ _checkErr(code, this._instance);
1676
+ }
1677
+ generateMipmap(target) {
1678
+ this._assertNotDestroyed();
1679
+ const ex = this._instance.exports;
1680
+ if (!ex || typeof ex.wasm_ctx_generate_mipmap !== 'function') {
1681
+ throw new Error('wasm_ctx_generate_mipmap not found');
1682
+ }
1683
+ const code = ex.wasm_ctx_generate_mipmap(this._ctxHandle, target >>> 0);
1684
+ _checkErr(code, this._instance);
1685
+ }
1686
+
1687
+ copyTexImage2D(target, level, internalformat, x, y, width, height, border) {
1688
+ this._assertNotDestroyed();
1689
+ const ex = this._instance.exports;
1690
+ if (!ex || typeof ex.wasm_ctx_copy_tex_image_2d !== 'function') {
1691
+ throw new Error('wasm_ctx_copy_tex_image_2d not found');
1692
+ }
1693
+ const code = ex.wasm_ctx_copy_tex_image_2d(
1694
+ this._ctxHandle,
1695
+ target >>> 0,
1696
+ level | 0,
1697
+ internalformat >>> 0,
1698
+ x | 0,
1699
+ y | 0,
1700
+ width | 0,
1701
+ height | 0,
1702
+ border | 0
1703
+ );
1704
+ _checkErr(code, this._instance);
1705
+ }
1706
+ copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1707
+ texSubImage2D(target, level, xoffset, yoffset, width, height, format, type_, pixels) {
1708
+ this._assertNotDestroyed();
1709
+ const ex = this._instance.exports;
1710
+ if (!ex || typeof ex.wasm_ctx_tex_sub_image_2d !== 'function') {
1711
+ throw new Error('wasm_ctx_tex_sub_image_2d not found');
1712
+ }
1713
+
1714
+ let data = pixels;
1715
+ if (!data) return; // No-op if no data provided
1716
+ if (!(data instanceof Uint8Array)) {
1717
+ if (ArrayBuffer.isView(data)) {
1718
+ data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1719
+ } else {
1720
+ data = new Uint8Array(data);
1721
+ }
1722
+ }
1723
+
1724
+ const len = data.length;
1725
+ const ptr = ex.wasm_alloc(len);
1726
+ if (ptr === 0) throw new Error('Failed to allocate memory for sub-pixel data');
1727
+
1728
+ try {
1729
+ const mem = new Uint8Array(ex.memory.buffer);
1730
+ mem.set(data, ptr);
1731
+
1732
+ const code = ex.wasm_ctx_tex_sub_image_2d(
1733
+ this._ctxHandle,
1734
+ target >>> 0,
1735
+ level >>> 0,
1736
+ xoffset | 0,
1737
+ yoffset | 0,
1738
+ width >>> 0,
1739
+ height >>> 0,
1740
+ format >>> 0,
1741
+ type_ >>> 0,
1742
+ ptr >>> 0,
1743
+ len >>> 0
1744
+ );
1745
+ _checkErr(code, this._instance);
1746
+ } finally {
1747
+ ex.wasm_free(ptr);
1748
+ }
1749
+ }
1750
+
1751
+ checkFramebufferStatus(target) {
1752
+ this._assertNotDestroyed();
1753
+ const ex = this._instance.exports;
1754
+ if (!ex || typeof ex.wasm_ctx_check_framebuffer_status !== 'function') {
1755
+ throw new Error('wasm_ctx_check_framebuffer_status not found');
1756
+ }
1757
+ return ex.wasm_ctx_check_framebuffer_status(this._ctxHandle, target);
1758
+ }
1759
+ blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) {
1760
+ this._assertNotDestroyed();
1761
+ const ex = this._instance.exports;
1762
+ if (!ex || typeof ex.wasm_ctx_blit_framebuffer !== 'function') {
1763
+ throw new Error('wasm_ctx_blit_framebuffer not found');
1764
+ }
1765
+ const code = ex.wasm_ctx_blit_framebuffer(
1766
+ this._ctxHandle,
1767
+ srcX0 | 0, srcY0 | 0, srcX1 | 0, srcY1 | 0,
1768
+ dstX0 | 0, dstY0 | 0, dstX1 | 0, dstY1 | 0,
1769
+ mask >>> 0, filter >>> 0
1770
+ );
1771
+ _checkErr(code, this._instance);
1772
+ }
1773
+
1774
+ pixelStorei(pname, param) { this._assertNotDestroyed(); throw new Error('not implemented'); }
1775
+ getExtension(name) {
1776
+ this._assertNotDestroyed();
1777
+ if (name === 'EXT_color_buffer_float') {
1778
+ return {};
1779
+ }
1780
+ return null;
1781
+ }
1782
+ getSupportedExtensions() {
1783
+ this._assertNotDestroyed();
1784
+ return ['EXT_color_buffer_float'];
1785
+ }
1786
+
1787
+ getUniformLocation(program, name) {
1788
+ this._assertNotDestroyed();
1789
+ const ex = this._instance.exports;
1790
+ if (!ex || typeof ex.wasm_ctx_get_uniform_location !== 'function') {
1791
+ throw new Error('wasm_ctx_get_uniform_location not found');
1792
+ }
1793
+ const programHandle = program && typeof program === 'object' && typeof program._handle === 'number' ? program._handle : (program >>> 0);
1794
+ const nameStr = String(name);
1795
+ const bytes = new TextEncoder().encode(nameStr);
1796
+ const len = bytes.length;
1797
+ const ptr = ex.wasm_alloc(len);
1798
+ if (ptr === 0) throw new Error('Failed to allocate memory for getUniformLocation');
1799
+
1800
+ try {
1801
+ const mem = new Uint8Array(ex.memory.buffer);
1802
+ mem.set(bytes, ptr);
1803
+ const loc = ex.wasm_ctx_get_uniform_location(this._ctxHandle, programHandle, ptr, len);
1804
+ return loc === -1 ? null : new WasmWebGLUniformLocation(this, loc);
1805
+ } finally {
1806
+ ex.wasm_free(ptr);
1807
+ }
1808
+ }
1809
+
1810
+ uniform1f(loc, x) {
1811
+ this._assertNotDestroyed();
1812
+ const ex = this._instance.exports;
1813
+ if (!ex || typeof ex.wasm_ctx_uniform1f !== 'function') {
1814
+ throw new Error('wasm_ctx_uniform1f not found');
1815
+ }
1816
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1817
+ const code = ex.wasm_ctx_uniform1f(this._ctxHandle, locHandle, +x);
1818
+ _checkErr(code, this._instance);
1819
+ }
1820
+
1821
+ uniform2f(loc, x, y) {
1822
+ this._assertNotDestroyed();
1823
+ const ex = this._instance.exports;
1824
+ if (!ex || typeof ex.wasm_ctx_uniform2f !== 'function') {
1825
+ throw new Error('wasm_ctx_uniform2f not found');
1826
+ }
1827
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1828
+ const code = ex.wasm_ctx_uniform2f(this._ctxHandle, locHandle, +x, +y);
1829
+ _checkErr(code, this._instance);
1830
+ }
1831
+
1832
+ uniform3f(loc, x, y, z) {
1833
+ this._assertNotDestroyed();
1834
+ const ex = this._instance.exports;
1835
+ if (!ex || typeof ex.wasm_ctx_uniform3f !== 'function') {
1836
+ throw new Error('wasm_ctx_uniform3f not found');
1837
+ }
1838
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1839
+ const code = ex.wasm_ctx_uniform3f(this._ctxHandle, locHandle, +x, +y, +z);
1840
+ _checkErr(code, this._instance);
1841
+ }
1842
+
1843
+ uniform4f(loc, x, y, z, w) {
1844
+ this._assertNotDestroyed();
1845
+ const ex = this._instance.exports;
1846
+ if (!ex || typeof ex.wasm_ctx_uniform4f !== 'function') {
1847
+ throw new Error('wasm_ctx_uniform4f not found');
1848
+ }
1849
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1850
+ const code = ex.wasm_ctx_uniform4f(this._ctxHandle, locHandle, +x, +y, +z, +w);
1851
+ _checkErr(code, this._instance);
1852
+ }
1853
+
1854
+ uniform1i(loc, x) {
1855
+ this._assertNotDestroyed();
1856
+ const ex = this._instance.exports;
1857
+ if (!ex || typeof ex.wasm_ctx_uniform1i !== 'function') {
1858
+ throw new Error('wasm_ctx_uniform1i not found');
1859
+ }
1860
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1861
+ const code = ex.wasm_ctx_uniform1i(this._ctxHandle, locHandle, x | 0);
1862
+ _checkErr(code, this._instance);
1863
+ }
1864
+
1865
+ uniformMatrix4fv(loc, transpose, value) {
1866
+ this._assertNotDestroyed();
1867
+ const ex = this._instance.exports;
1868
+ if (!ex || typeof ex.wasm_ctx_uniform_matrix_4fv !== 'function') {
1869
+ throw new Error('wasm_ctx_uniform_matrix_4fv not found');
1870
+ }
1871
+ const locHandle = loc === null ? -1 : (typeof loc === 'number' ? loc : (loc._handle >>> 0));
1872
+
1873
+ let bytes;
1874
+ if (value instanceof Float32Array) {
1875
+ bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1876
+ } else {
1877
+ bytes = new Uint8Array(new Float32Array(value).buffer);
1878
+ }
1879
+
1880
+ const len = bytes.length;
1881
+ const ptr = ex.wasm_alloc(len);
1882
+ if (ptr === 0) throw new Error('Failed to allocate memory for uniformMatrix4fv');
1883
+
1884
+ try {
1885
+ const mem = new Uint8Array(ex.memory.buffer);
1886
+ mem.set(bytes, ptr);
1887
+ const count = len / 4;
1888
+ const code = ex.wasm_ctx_uniform_matrix_4fv(this._ctxHandle, locHandle, transpose ? 1 : 0, ptr, count);
1889
+ _checkErr(code, this._instance);
1890
+ } finally {
1891
+ ex.wasm_free(ptr);
1892
+ }
1893
+ }
1894
+
1895
+ getVertexAttrib(index, pname) {
1896
+ this._assertNotDestroyed();
1897
+ const ex = this._instance.exports;
1898
+ if (!ex || typeof ex.wasm_ctx_get_vertex_attrib !== 'function') {
1899
+ throw new Error('wasm_ctx_get_vertex_attrib not found');
1900
+ }
1901
+
1902
+ // Allocate memory for result.
1903
+ // Most params return 1 int (4 bytes).
1904
+ // CURRENT_VERTEX_ATTRIB returns 4 values (16 bytes) + type (4 bytes) = 20 bytes.
1905
+ const len = 20;
1906
+ const ptr = ex.wasm_alloc(len);
1907
+ if (ptr === 0) throw new Error('Failed to allocate memory for getVertexAttrib');
1908
+
1909
+ try {
1910
+ const code = ex.wasm_ctx_get_vertex_attrib(this._ctxHandle, index >>> 0, pname >>> 0, ptr, len);
1911
+ if (code === 5) { // ERR_GL
1912
+ return undefined;
1913
+ }
1914
+ _checkErr(code, this._instance);
1915
+
1916
+ const mem = new Int32Array(ex.memory.buffer, ptr, 5);
1917
+ const memU = new Uint32Array(ex.memory.buffer, ptr, 5);
1918
+ const memF = new Float32Array(ex.memory.buffer, ptr, 5);
1919
+
1920
+ if (pname === 0x8626 /* CURRENT_VERTEX_ATTRIB */) {
1921
+ // Check type at index 4
1922
+ const type = memU[4];
1923
+ if (type === 0x1404 /* INT */) {
1924
+ return new Int32Array([mem[0], mem[1], mem[2], mem[3]]);
1925
+ } else if (type === 0x1405 /* UNSIGNED_INT */) {
1926
+ return new Uint32Array([memU[0], memU[1], memU[2], memU[3]]);
1927
+ } else {
1928
+ // Default to float
1929
+ return new Float32Array([memF[0], memF[1], memF[2], memF[3]]);
1930
+ }
1931
+ }
1932
+
1933
+ // Other params
1934
+ if (pname === 0x8622 /* ENABLED */ ||
1935
+ pname === 0x886A /* NORMALIZED */ ||
1936
+ pname === 0x88FD /* INTEGER */) {
1937
+ return mem[0] !== 0;
1938
+ }
1939
+
1940
+ if (pname === 0x889F /* BUFFER_BINDING */) {
1941
+ const handle = memU[0];
1942
+ if (handle === 0) return null;
1943
+ return new WasmWebGLBuffer(this, handle);
1944
+ }
1945
+
1946
+ return mem[0];
1947
+ } finally {
1948
+ ex.wasm_free(ptr, len);
1949
+ }
1950
+ }
1951
+
1952
+
1953
+ getParameter(pname) {
1954
+ this._assertNotDestroyed();
1955
+ const ex = this._instance.exports;
1956
+ if (!ex || typeof ex.wasm_ctx_get_parameter_v !== 'function') {
1957
+ throw new Error('wasm_ctx_get_parameter_v not found');
1958
+ }
1959
+
1960
+ if (pname === 0x0BA2 /* VIEWPORT */) {
1961
+ const ptr = ex.wasm_alloc(16);
1962
+ try {
1963
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 16);
1964
+ _checkErr(code, this._instance);
1965
+ const mem = new Int32Array(ex.memory.buffer, ptr, 4);
1966
+ return new Int32Array(mem);
1967
+ } finally {
1968
+ ex.wasm_free(ptr, 16);
1969
+ }
1970
+ }
1971
+
1972
+ if (pname === 0x0C22 /* COLOR_CLEAR_VALUE */) {
1973
+ const ptr = ex.wasm_alloc(16);
1974
+ try {
1975
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 16);
1976
+ _checkErr(code, this._instance);
1977
+ const mem = new Float32Array(ex.memory.buffer, ptr, 4);
1978
+ return new Float32Array(mem);
1979
+ } finally {
1980
+ ex.wasm_free(ptr, 16);
1981
+ }
1982
+ }
1983
+
1984
+ if (pname === 0x0C23 /* COLOR_WRITEMASK */) {
1985
+ const ptr = ex.wasm_alloc(4);
1986
+ try {
1987
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
1988
+ _checkErr(code, this._instance);
1989
+ const mem = new Uint8Array(ex.memory.buffer, ptr, 4);
1990
+ return [mem[0] !== 0, mem[1] !== 0, mem[2] !== 0, mem[3] !== 0];
1991
+ } finally {
1992
+ ex.wasm_free(ptr, 4);
1993
+ }
1994
+ }
1995
+
1996
+ if (pname === 0x0B72 /* DEPTH_WRITEMASK */) {
1997
+ const ptr = ex.wasm_alloc(4);
1998
+ try {
1999
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
2000
+ _checkErr(code, this._instance);
2001
+ const mem = new Uint8Array(ex.memory.buffer, ptr, 1);
2002
+ return mem[0] !== 0;
2003
+ } finally {
2004
+ ex.wasm_free(ptr, 4);
2005
+ }
2006
+ }
2007
+
2008
+ if (pname === 0x0B98 /* STENCIL_WRITEMASK */ || pname === 0x8CA5 /* STENCIL_BACK_WRITEMASK */) {
2009
+ const ptr = ex.wasm_alloc(4);
2010
+ try {
2011
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
2012
+ _checkErr(code, this._instance);
2013
+ const mem = new Int32Array(ex.memory.buffer, ptr, 1);
2014
+ return mem[0];
2015
+ } finally {
2016
+ ex.wasm_free(ptr, 4);
2017
+ }
2018
+ }
2019
+
2020
+ const singleIntParams = [
2021
+ 0x0B74, // DEPTH_FUNC
2022
+ 0x0B92, // STENCIL_FUNC
2023
+ 0x0B93, // STENCIL_VALUE_MASK
2024
+ 0x0B97, // STENCIL_REF
2025
+ 0x8800, // STENCIL_BACK_FUNC
2026
+ 0x8CA4, // STENCIL_BACK_VALUE_MASK
2027
+ 0x8CA3, // STENCIL_BACK_REF
2028
+ 0x0B94, // STENCIL_FAIL
2029
+ 0x0B95, // STENCIL_PASS_DEPTH_FAIL
2030
+ 0x0B96, // STENCIL_PASS_DEPTH_PASS
2031
+ 0x8801, // STENCIL_BACK_FAIL
2032
+ 0x8802, // STENCIL_BACK_PASS_DEPTH_FAIL
2033
+ 0x8803, // STENCIL_BACK_PASS_DEPTH_PASS
2034
+ ];
2035
+
2036
+ if (singleIntParams.includes(pname)) {
2037
+ const ptr = ex.wasm_alloc(4);
2038
+ try {
2039
+ const code = ex.wasm_ctx_get_parameter_v(this._ctxHandle, pname, ptr, 4);
2040
+ _checkErr(code, this._instance);
2041
+ const mem = new Int32Array(ex.memory.buffer, ptr, 1);
2042
+ return mem[0];
2043
+ } finally {
2044
+ ex.wasm_free(ptr, 4);
2045
+ }
2046
+ }
2047
+
2048
+ if (pname === 0x8869 /* MAX_VERTEX_ATTRIBS */) {
2049
+ return 16;
2050
+ }
2051
+
2052
+ throw new Error(`getParameter for ${pname} not implemented`);
2053
+ }
2054
+ getError() {
2055
+ this._assertNotDestroyed();
2056
+ const ex = this._instance.exports;
2057
+ if (!ex || typeof ex.wasm_ctx_get_error !== 'function') {
2058
+ throw new Error('wasm_ctx_get_error not found');
2059
+ }
2060
+ return ex.wasm_ctx_get_error(this._ctxHandle);
2061
+ }
2062
+
2063
+ _setError(error) {
2064
+ const ex = this._instance.exports;
2065
+ if (ex && typeof ex.wasm_ctx_set_gl_error === 'function') {
2066
+ ex.wasm_ctx_set_gl_error(this._ctxHandle, error);
2067
+ }
2068
+ }
2069
+
2070
+ finish() { this._assertNotDestroyed(); throw new Error('not implemented'); }
2071
+ flush() { this._assertNotDestroyed(); throw new Error('not implemented'); }
2072
+
2073
+ isTexture(tex) {
2074
+ this._assertNotDestroyed();
2075
+ if (!tex || typeof tex !== 'object' || !(tex instanceof WasmWebGLTexture)) return false;
2076
+ if (tex._ctx !== this) return false;
2077
+ const ex = this._instance.exports;
2078
+ return ex.wasm_ctx_is_texture(this._ctxHandle, tex._handle) !== 0;
2079
+ }
2080
+ isFramebuffer(fb) {
2081
+ this._assertNotDestroyed();
2082
+ if (!fb || typeof fb !== 'object' || !(fb instanceof WasmWebGLFramebuffer)) return false;
2083
+ if (fb._ctx !== this) return false;
2084
+ const ex = this._instance.exports;
2085
+ return ex.wasm_ctx_is_framebuffer(this._ctxHandle, fb._handle) !== 0;
2086
+ }
2087
+ isProgram(p) {
2088
+ this._assertNotDestroyed();
2089
+ if (!p || typeof p !== 'object' || !(p instanceof WasmWebGLProgram)) return false;
2090
+ if (p._ctx !== this) return false;
2091
+ const ex = this._instance.exports;
2092
+ return ex.wasm_ctx_is_program(this._ctxHandle, p._handle) !== 0;
2093
+ }
2094
+ isShader(s) {
2095
+ this._assertNotDestroyed();
2096
+ if (!s || typeof s !== 'object' || !(s instanceof WasmWebGLShader)) return false;
2097
+ if (s._ctx !== this) return false;
2098
+ const ex = this._instance.exports;
2099
+ return ex.wasm_ctx_is_shader(this._ctxHandle, s._handle) !== 0;
2100
+ }
2101
+ enable(cap) {
2102
+ this._assertNotDestroyed();
2103
+ const ex = this._instance.exports;
2104
+ if (!ex || typeof ex.wasm_ctx_enable !== 'function') {
2105
+ throw new Error('wasm_ctx_enable not found');
2106
+ }
2107
+ const code = ex.wasm_ctx_enable(this._ctxHandle, cap >>> 0);
2108
+ _checkErr(code, this._instance);
2109
+ }
2110
+ disable(cap) {
2111
+ this._assertNotDestroyed();
2112
+ const ex = this._instance.exports;
2113
+ if (!ex || typeof ex.wasm_ctx_disable !== 'function') {
2114
+ throw new Error('wasm_ctx_disable not found');
2115
+ }
2116
+ const code = ex.wasm_ctx_disable(this._ctxHandle, cap >>> 0);
2117
+ _checkErr(code, this._instance);
2118
+ }
2119
+
2120
+ blendFunc(sfactor, dfactor) {
2121
+ this._assertNotDestroyed();
2122
+ const ex = this._instance.exports;
2123
+ if (!ex || typeof ex.wasm_ctx_blend_func !== 'function') {
2124
+ throw new Error('wasm_ctx_blend_func not found');
2125
+ }
2126
+ const code = ex.wasm_ctx_blend_func(this._ctxHandle, sfactor >>> 0, dfactor >>> 0);
2127
+ _checkErr(code, this._instance);
2128
+ }
2129
+
2130
+ blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) {
2131
+ this._assertNotDestroyed();
2132
+ const ex = this._instance.exports;
2133
+ if (!ex || typeof ex.wasm_ctx_blend_func_separate !== 'function') {
2134
+ throw new Error('wasm_ctx_blend_func_separate not found');
2135
+ }
2136
+ const code = ex.wasm_ctx_blend_func_separate(
2137
+ this._ctxHandle,
2138
+ srcRGB >>> 0,
2139
+ dstRGB >>> 0,
2140
+ srcAlpha >>> 0,
2141
+ dstAlpha >>> 0
2142
+ );
2143
+ _checkErr(code, this._instance);
2144
+ }
2145
+
2146
+ blendEquation(mode) {
2147
+ this._assertNotDestroyed();
2148
+ const ex = this._instance.exports;
2149
+ if (!ex || typeof ex.wasm_ctx_blend_equation !== 'function') {
2150
+ throw new Error('wasm_ctx_blend_equation not found');
2151
+ }
2152
+ const code = ex.wasm_ctx_blend_equation(this._ctxHandle, mode >>> 0);
2153
+ _checkErr(code, this._instance);
2154
+ }
2155
+
2156
+ blendEquationSeparate(modeRGB, modeAlpha) {
2157
+ this._assertNotDestroyed();
2158
+ const ex = this._instance.exports;
2159
+ if (!ex || typeof ex.wasm_ctx_blend_equation_separate !== 'function') {
2160
+ throw new Error('wasm_ctx_blend_equation_separate not found');
2161
+ }
2162
+ const code = ex.wasm_ctx_blend_equation_separate(
2163
+ this._ctxHandle,
2164
+ modeRGB >>> 0,
2165
+ modeAlpha >>> 0
2166
+ );
2167
+ _checkErr(code, this._instance);
2168
+ }
2169
+
2170
+ blendColor(red, green, blue, alpha) {
2171
+ this._assertNotDestroyed();
2172
+ const ex = this._instance.exports;
2173
+ if (!ex || typeof ex.wasm_ctx_blend_color !== 'function') {
2174
+ throw new Error('wasm_ctx_blend_color not found');
2175
+ }
2176
+ const code = ex.wasm_ctx_blend_color(
2177
+ this._ctxHandle,
2178
+ +red,
2179
+ +green,
2180
+ +blue,
2181
+ +alpha
2182
+ );
2183
+ _checkErr(code, this._instance);
2184
+ }
2185
+
2186
+ isEnabled(cap) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2187
+
2188
+ viewport(x, y, width, height) {
2189
+ this._assertNotDestroyed();
2190
+ const ex = this._instance.exports;
2191
+ if (!ex || typeof ex.wasm_ctx_viewport !== 'function') {
2192
+ throw new Error('wasm_ctx_viewport not found');
2193
+ }
2194
+ const code = ex.wasm_ctx_viewport(this._ctxHandle, x >>> 0, y >>> 0, width >>> 0, height >>> 0);
2195
+ _checkErr(code, this._instance);
2196
+ }
2197
+ scissor(x, y, width, height) {
2198
+ this._assertNotDestroyed();
2199
+ const ex = this._instance.exports;
2200
+ if (!ex || typeof ex.wasm_ctx_scissor !== 'function') {
2201
+ throw new Error('wasm_ctx_scissor not found');
2202
+ }
2203
+ const code = ex.wasm_ctx_scissor(this._ctxHandle, x | 0, y | 0, width >>> 0, height >>> 0);
2204
+ _checkErr(code, this._instance);
2205
+ }
2206
+ clear(mask) {
2207
+ this._assertNotDestroyed();
2208
+ const ex = this._instance.exports;
2209
+ if (!ex || typeof ex.wasm_ctx_clear !== 'function') {
2210
+ throw new Error('wasm_ctx_clear not found');
2211
+ }
2212
+ const code = ex.wasm_ctx_clear(this._ctxHandle, mask >>> 0);
2213
+ _checkErr(code, this._instance);
2214
+ }
2215
+ clearColor(r, g, b, a) {
2216
+ this._assertNotDestroyed();
2217
+ const ex = this._instance.exports;
2218
+ if (!ex || typeof ex.wasm_ctx_clear_color !== 'function') {
2219
+ throw new Error('wasm_ctx_clear_color not found');
2220
+ }
2221
+ const code = ex.wasm_ctx_clear_color(this._ctxHandle, +r, +g, +b, +a);
2222
+ _checkErr(code, this._instance);
2223
+ }
2224
+ clearDepth(depth) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2225
+ depthFunc(func) {
2226
+ this._assertNotDestroyed();
2227
+ const ex = this._instance.exports;
2228
+ if (!ex || typeof ex.wasm_ctx_depth_func !== 'function') {
2229
+ throw new Error('wasm_ctx_depth_func not found');
2230
+ }
2231
+ const code = ex.wasm_ctx_depth_func(this._ctxHandle, func >>> 0);
2232
+ _checkErr(code, this._instance);
2233
+ }
2234
+ depthMask(flag) {
2235
+ this._assertNotDestroyed();
2236
+ const ex = this._instance.exports;
2237
+ if (!ex || typeof ex.wasm_ctx_depth_mask !== 'function') {
2238
+ throw new Error('wasm_ctx_depth_mask not found');
2239
+ }
2240
+ const code = ex.wasm_ctx_depth_mask(this._ctxHandle, flag ? 1 : 0);
2241
+ _checkErr(code, this._instance);
2242
+ }
2243
+ colorMask(r, g, b, a) {
2244
+ this._assertNotDestroyed();
2245
+ const ex = this._instance.exports;
2246
+ if (!ex || typeof ex.wasm_ctx_color_mask !== 'function') {
2247
+ throw new Error('wasm_ctx_color_mask not found');
2248
+ }
2249
+ const code = ex.wasm_ctx_color_mask(this._ctxHandle, r ? 1 : 0, g ? 1 : 0, b ? 1 : 0, a ? 1 : 0);
2250
+ _checkErr(code, this._instance);
2251
+ }
2252
+ polygonOffset(factor, units) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2253
+ sampleCoverage(value, invert) { this._assertNotDestroyed(); throw new Error('not implemented'); }
2254
+ stencilFunc(func, ref, mask) {
2255
+ this._assertNotDestroyed();
2256
+ const ex = this._instance.exports;
2257
+ if (!ex || typeof ex.wasm_ctx_stencil_func !== 'function') {
2258
+ throw new Error('wasm_ctx_stencil_func not found');
2259
+ }
2260
+ const code = ex.wasm_ctx_stencil_func(this._ctxHandle, func >>> 0, ref | 0, mask >>> 0);
2261
+ _checkErr(code, this._instance);
2262
+ }
2263
+ stencilFuncSeparate(face, func, ref, mask) {
2264
+ this._assertNotDestroyed();
2265
+ const ex = this._instance.exports;
2266
+ if (!ex || typeof ex.wasm_ctx_stencil_func_separate !== 'function') {
2267
+ throw new Error('wasm_ctx_stencil_func_separate not found');
2268
+ }
2269
+ const code = ex.wasm_ctx_stencil_func_separate(this._ctxHandle, face >>> 0, func >>> 0, ref | 0, mask >>> 0);
2270
+ _checkErr(code, this._instance);
2271
+ }
2272
+ stencilOp(fail, zfail, zpass) {
2273
+ this._assertNotDestroyed();
2274
+ const ex = this._instance.exports;
2275
+ if (!ex || typeof ex.wasm_ctx_stencil_op !== 'function') {
2276
+ throw new Error('wasm_ctx_stencil_op not found');
2277
+ }
2278
+ const code = ex.wasm_ctx_stencil_op(this._ctxHandle, fail >>> 0, zfail >>> 0, zpass >>> 0);
2279
+ _checkErr(code, this._instance);
2280
+ }
2281
+ stencilOpSeparate(face, fail, zfail, zpass) {
2282
+ this._assertNotDestroyed();
2283
+ const ex = this._instance.exports;
2284
+ if (!ex || typeof ex.wasm_ctx_stencil_op_separate !== 'function') {
2285
+ throw new Error('wasm_ctx_stencil_op_separate not found');
2286
+ }
2287
+ const code = ex.wasm_ctx_stencil_op_separate(this._ctxHandle, face >>> 0, fail >>> 0, zfail >>> 0, zpass >>> 0);
2288
+ _checkErr(code, this._instance);
2289
+ }
2290
+ stencilMask(mask) {
2291
+ this._assertNotDestroyed();
2292
+ const ex = this._instance.exports;
2293
+ if (!ex || typeof ex.wasm_ctx_stencil_mask !== 'function') {
2294
+ throw new Error('wasm_ctx_stencil_mask not found');
2295
+ }
2296
+ const code = ex.wasm_ctx_stencil_mask(this._ctxHandle, mask >>> 0);
2297
+ _checkErr(code, this._instance);
2298
+ }
2299
+ stencilMaskSeparate(face, mask) {
2300
+ this._assertNotDestroyed();
2301
+ const ex = this._instance.exports;
2302
+ if (!ex || typeof ex.wasm_ctx_stencil_mask_separate !== 'function') {
2303
+ throw new Error('wasm_ctx_stencil_mask_separate not found');
2304
+ }
2305
+ const code = ex.wasm_ctx_stencil_mask_separate(this._ctxHandle, face >>> 0, mask >>> 0);
2306
+ _checkErr(code, this._instance);
2307
+ }
2308
+ }
2309
+
2310
+ /**
2311
+ * Thin wrapper for a WebGLTexture handle returned from WASM.
2312
+ * Holds a reference to the originating WasmWebGL2RenderingContext and the numeric handle.
2313
+ */
2314
+ // WebGLTexture wrapper moved to `src/webgl2_texture.js`.
2315
+
2316
+ /**
2317
+ * Read an error message from WASM memory and return it as string.
2318
+ * Exported so callers outside this module can report errors.
2319
+ * @param {WebAssembly.Instance} instance
2320
+ * @returns {string}
2321
+ */
2322
+ export function readErrorMessage(instance) {
2323
+ const ex = instance.exports;
2324
+ if (!ex || typeof ex.wasm_last_error_ptr !== 'function' || typeof ex.wasm_last_error_len !== 'function') {
2325
+ return '(no error message available)';
2326
+ }
2327
+ const ptr = ex.wasm_last_error_ptr();
2328
+ const len = ex.wasm_last_error_len();
2329
+ if (ptr === 0 || len === 0) {
2330
+ return '';
2331
+ }
2332
+ const mem = new Uint8Array(ex.memory.buffer);
2333
+ const bytes = mem.subarray(ptr, ptr + len);
2334
+ return new TextDecoder('utf-8').decode(bytes);
2335
+ }
2336
+
2337
+ function _checkErr(code, instance) {
2338
+ if (code === ERR_OK) return;
2339
+ const msg = readErrorMessage(instance);
2340
+ throw new Error(`WASM error ${code}: ${msg}`);
2341
+ }
2342
+
2343
+ // ============================================================================
2344
+ // WAT Testing Support (docs/1.9-wat-testing.md)
2345
+ // ============================================================================
2346
+
2347
+ /**
2348
+ * Get the compiled WASM bytes for a shader in a program.
2349
+ *
2350
+ * @param {number} ctxHandle - Context handle
2351
+ * @param {number} programHandle - Program handle
2352
+ * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2353
+ * @returns {Uint8Array | null} WASM bytes or null if not available
2354
+ */
2355
+ export function getShaderModule(ctxHandle, programHandle, shaderType) {
2356
+ const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2357
+ if (!ctx) {
2358
+ throw new Error('Invalid context handle');
2359
+ }
2360
+
2361
+ const ex = ctx._instance.exports;
2362
+ if (!ex || typeof ex.wasm_ctx_get_program_wasm_ref !== 'function') {
2363
+ throw new Error('wasm_ctx_get_program_wasm_ref not found');
2364
+ }
2365
+
2366
+ // Call the WASM function - it returns a packed u64 (BigInt or Number)
2367
+ const result = ex.wasm_ctx_get_program_wasm_ref(ctxHandle, programHandle, shaderType);
2368
+
2369
+ // Unpack: low 32 bits = ptr, high 32 bits = len
2370
+ let ptr, len;
2371
+ if (typeof result === 'bigint') {
2372
+ ptr = Number(result & 0xFFFFFFFFn);
2373
+ len = Number((result >> 32n) & 0xFFFFFFFFn);
2374
+ } else {
2375
+ // Fallback for number (may lose precision for very large values)
2376
+ ptr = result >>> 0; // Low 32 bits
2377
+ len = Math.floor(result / 0x100000000); // High 32 bits
2378
+ }
2379
+
2380
+ // Check for failure (0, 0)
2381
+ if (ptr === 0 || len === 0) {
2382
+ return null;
2383
+ }
2384
+
2385
+ // Copy bytes from WASM memory into a new Uint8Array
2386
+ const mem = new Uint8Array(ex.memory.buffer);
2387
+ const bytes = new Uint8Array(len);
2388
+ bytes.set(mem.subarray(ptr, ptr + len));
2389
+
2390
+ return bytes;
2391
+ }
2392
+
2393
+ /**
2394
+ * Get the WAT (WebAssembly Text) representation for a shader in a program.
2395
+ *
2396
+ * @param {number} ctxHandle - Context handle
2397
+ * @param {number} programHandle - Program handle
2398
+ * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2399
+ * @returns {string | null} WAT text or null if not available
2400
+ */
2401
+ export function getShaderWat(ctxHandle, programHandle, shaderType) {
2402
+ const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2403
+ if (!ctx) {
2404
+ throw new Error('Invalid context handle');
2405
+ }
2406
+
2407
+ const ex = ctx._instance.exports;
2408
+ if (!ex || typeof ex.wasm_ctx_get_program_wat_ref !== 'function') {
2409
+ throw new Error('wasm_ctx_get_program_wat_ref not found');
2410
+ }
2411
+
2412
+ // Call the WASM function - it returns a packed u64 (BigInt or Number)
2413
+ const result = ex.wasm_ctx_get_program_wat_ref(ctxHandle, programHandle, shaderType);
2414
+
2415
+ // Unpack: low 32 bits = ptr, high 32 bits = len
2416
+ let ptr, len;
2417
+ if (typeof result === 'bigint') {
2418
+ ptr = Number(result & 0xFFFFFFFFn);
2419
+ len = Number((result >> 32n) & 0xFFFFFFFFn);
2420
+ } else {
2421
+ // Fallback for number (may lose precision for very large values)
2422
+ ptr = result >>> 0; // Low 32 bits
2423
+ len = Math.floor(result / 0x100000000); // High 32 bits
2424
+ }
2425
+
2426
+ // Check for failure (0, 0)
2427
+ if (ptr === 0 || len === 0) {
2428
+ return null;
2429
+ }
2430
+
2431
+ // Copy bytes from WASM memory and decode as UTF-8
2432
+ const mem = new Uint8Array(ex.memory.buffer);
2433
+ const bytes = mem.subarray(ptr, ptr + len);
2434
+ const decoder = new TextDecoder('utf-8');
2435
+ const watText = decoder.decode(bytes);
2436
+
2437
+ return watText;
2438
+ }
2439
+
2440
+ /**
2441
+ * Decompile WASM bytes to GLSL source code.
2442
+ *
2443
+ * This uses the WASM-to-GLSL decompiler to convert compiled shader WASM
2444
+ * back into readable GLSL-like code.
2445
+ *
2446
+ * @param {number} ctxHandle - Context handle
2447
+ * @param {number} programHandle - Program handle
2448
+ * @param {number} shaderType - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)
2449
+ * @returns {string | null} GLSL source code or null if not available
2450
+ */
2451
+ export function getShaderGlsl(ctxHandle, programHandle, shaderType) {
2452
+ const ctx = WasmWebGL2RenderingContext._contexts.get(ctxHandle);
2453
+ if (!ctx) {
2454
+ throw new Error('Invalid context handle');
2455
+ }
2456
+
2457
+ // First get the WASM bytes for the shader
2458
+ const wasmBytes = getShaderModule(ctxHandle, programHandle, shaderType);
2459
+ if (!wasmBytes) {
2460
+ return null;
2461
+ }
2462
+
2463
+ const ex = ctx._instance.exports;
2464
+ if (!ex || typeof ex.wasm_decompile_to_glsl !== 'function') {
2465
+ throw new Error('wasm_decompile_to_glsl not found');
2466
+ }
2467
+
2468
+ // Allocate memory in WASM for the input bytes
2469
+ const wasmBytesLen = wasmBytes.length;
2470
+ const wasmBytesPtr = ex.wasm_alloc(wasmBytesLen);
2471
+ if (wasmBytesPtr === 0) {
2472
+ throw new Error('Failed to allocate memory for WASM bytes');
2473
+ }
2474
+
2475
+ try {
2476
+ // Copy WASM bytes to linear memory
2477
+ const mem = new Uint8Array(ex.memory.buffer);
2478
+ mem.set(wasmBytes, wasmBytesPtr);
2479
+
2480
+ // Call the decompiler
2481
+ const resultLen = ex.wasm_decompile_to_glsl(wasmBytesPtr, wasmBytesLen);
2482
+
2483
+ if (resultLen === 0) {
2484
+ return null;
2485
+ }
2486
+
2487
+ // Get the decompiled GLSL
2488
+ const glslPtr = ex.wasm_get_decompiled_glsl_ptr();
2489
+ const glslLen = ex.wasm_get_decompiled_glsl_len();
2490
+
2491
+ if (glslPtr === 0 || glslLen === 0) {
2492
+ return null;
2493
+ }
2494
+
2495
+ // Read the GLSL string
2496
+ const glslBytes = new Uint8Array(ex.memory.buffer).subarray(glslPtr, glslPtr + glslLen);
2497
+ const decoder = new TextDecoder('utf-8');
2498
+ return decoder.decode(glslBytes);
2499
+ } finally {
2500
+ // Free the allocated memory
2501
+ ex.wasm_free(wasmBytesPtr);
2502
+ }
2503
+ }
2504
+
2505
+ /**
2506
+ * Decompile raw WASM bytes to GLSL source code.
2507
+ *
2508
+ * This is a lower-level API that takes raw WASM bytes directly.
2509
+ *
2510
+ * @param {WasmWebGL2RenderingContext} gl - WebGL2 context
2511
+ * @param {Uint8Array} wasmBytes - Raw WASM bytecode to decompile
2512
+ * @returns {string | null} GLSL source code or null on error
2513
+ */
2514
+ export function decompileWasmToGlsl(gl, wasmBytes) {
2515
+ if (!gl || !gl._instance) {
2516
+ throw new Error('Invalid WebGL2 context');
2517
+ }
2518
+
2519
+ const ex = gl._instance.exports;
2520
+ if (!ex || typeof ex.wasm_decompile_to_glsl !== 'function') {
2521
+ throw new Error('wasm_decompile_to_glsl not found');
2522
+ }
2523
+
2524
+ // Allocate memory in WASM for the input bytes
2525
+ const wasmBytesLen = wasmBytes.length;
2526
+ const wasmBytesPtr = ex.wasm_alloc(wasmBytesLen);
2527
+ if (wasmBytesPtr === 0) {
2528
+ throw new Error('Failed to allocate memory for WASM bytes');
2529
+ }
2530
+
2531
+ try {
2532
+ // Copy WASM bytes to linear memory
2533
+ const mem = new Uint8Array(ex.memory.buffer);
2534
+ mem.set(wasmBytes, wasmBytesPtr);
2535
+
2536
+ // Call the decompiler
2537
+ const resultLen = ex.wasm_decompile_to_glsl(wasmBytesPtr, wasmBytesLen);
2538
+
2539
+ if (resultLen === 0) {
2540
+ return null;
2541
+ }
2542
+
2543
+ // Get the decompiled GLSL
2544
+ const glslPtr = ex.wasm_get_decompiled_glsl_ptr();
2545
+ const glslLen = ex.wasm_get_decompiled_glsl_len();
2546
+
2547
+ if (glslPtr === 0 || glslLen === 0) {
2548
+ return null;
2549
+ }
2550
+
2551
+ // Read the GLSL string
2552
+ const glslBytes = new Uint8Array(ex.memory.buffer).subarray(glslPtr, glslPtr + glslLen);
2553
+ const decoder = new TextDecoder('utf-8');
2554
+ return decoder.decode(glslBytes);
2555
+ } finally {
2556
+ // Free the allocated memory
2557
+ ex.wasm_free(wasmBytesPtr);
2558
+ }
2559
+ }