@live-codes/odin-wasm 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/assets/odin.js ADDED
@@ -0,0 +1,2302 @@
1
+ "use strict";
2
+
3
+ (function() {
4
+
5
+ function getElement(name) {
6
+ if (name) {
7
+ return document.getElementById(name);
8
+ }
9
+ return undefined;
10
+ }
11
+
12
+ function stripNewline(str) {
13
+ return str.replace(/\n/, ' ')
14
+ }
15
+
16
+ class WasmMemoryInterface {
17
+ constructor() {
18
+ this.memory = null;
19
+ this.exports = null;
20
+ this.listenerMap = new Map();
21
+
22
+ this.isShared = false;
23
+
24
+ // Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32`
25
+ this.intSize = 4;
26
+ }
27
+
28
+ setIntSize(size) {
29
+ this.intSize = size;
30
+ }
31
+
32
+ setMemory(memory) {
33
+ this.memory = memory;
34
+ // Avoid instanceof because memory may come from another realm.
35
+ this.isShared = typeof SharedArrayBuffer !== "undefined" && memory != null &&
36
+ Object.prototype.toString.call(memory.buffer) === "[object SharedArrayBuffer]";
37
+ }
38
+
39
+ setExports(exports) {
40
+ this.exports = exports;
41
+ }
42
+
43
+ get mem() {
44
+ return new DataView(this.memory.buffer);
45
+ }
46
+
47
+
48
+ loadF32Array(addr, len) { return new Float32Array(this.memory.buffer, addr, len); }
49
+ loadF64Array(addr, len) { return new Float64Array(this.memory.buffer, addr, len); }
50
+ loadU32Array(addr, len) { return new Uint32Array(this.memory.buffer, addr, len); }
51
+ loadI32Array(addr, len) { return new Int32Array(this.memory.buffer, addr, len); }
52
+ loadU16Array(addr, len) { return new Uint16Array(this.memory.buffer, addr, len); }
53
+ loadI16Array(addr, len) { return new Int16Array(this.memory.buffer, addr, len); }
54
+ loadU8Array(addr, len) { return new Uint8Array(this.memory.buffer, addr, len); }
55
+ loadI8Array(addr, len) { return new Int8Array(this.memory.buffer, addr, len); }
56
+
57
+
58
+ loadU8(addr) { return this.mem.getUint8 (addr); }
59
+ loadI8(addr) { return this.mem.getInt8 (addr); }
60
+ loadU16(addr) { return this.mem.getUint16 (addr, true); }
61
+ loadI16(addr) { return this.mem.getInt16 (addr, true); }
62
+ loadU32(addr) { return this.mem.getUint32 (addr, true); }
63
+ loadI32(addr) { return this.mem.getInt32 (addr, true); }
64
+ loadU64(addr) {
65
+ const lo = this.mem.getUint32(addr + 0, true);
66
+ const hi = this.mem.getUint32(addr + 4, true);
67
+ return lo + hi*4294967296;
68
+ };
69
+ loadI64(addr) {
70
+ const lo = this.mem.getUint32(addr + 0, true);
71
+ const hi = this.mem.getInt32 (addr + 4, true);
72
+ return lo + hi*4294967296;
73
+ };
74
+ loadF32(addr) { return this.mem.getFloat32(addr, true); }
75
+ loadF64(addr) { return this.mem.getFloat64(addr, true); }
76
+ loadInt(addr) {
77
+ if (this.intSize == 8) {
78
+ return this.loadI64(addr);
79
+ } else if (this.intSize == 4) {
80
+ return this.loadI32(addr);
81
+ } else {
82
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
83
+ }
84
+ };
85
+ loadUint(addr) {
86
+ if (this.intSize == 8) {
87
+ return this.loadU64(addr);
88
+ } else if (this.intSize == 4) {
89
+ return this.loadU32(addr);
90
+ } else {
91
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
92
+ }
93
+ };
94
+ loadPtr(addr) { return this.loadU32(addr); }
95
+
96
+ loadB32(addr) {
97
+ return this.loadU32(addr) != 0;
98
+ }
99
+
100
+ loadBytes(ptr, len) {
101
+ return new Uint8Array(this.memory.buffer, ptr, Number(len));
102
+ }
103
+
104
+ loadBytesUnshared(ptr, len) {
105
+ const bytes = this.loadBytes(ptr, len);
106
+ if (this.isShared) {
107
+ return bytes.slice();
108
+ }
109
+ return bytes;
110
+ }
111
+
112
+ loadString(ptr, len) {
113
+ return new TextDecoder().decode(this.loadBytesUnshared(ptr, Number(len)));
114
+ }
115
+
116
+ loadCstring(ptr) {
117
+ if (ptr == 0) {
118
+ return null;
119
+ }
120
+ let len = 0;
121
+ for (; this.mem.getUint8(ptr+len) != 0; len += 1) {}
122
+ return this.loadString(ptr, len);
123
+ }
124
+
125
+ storeU8(addr, value) { this.mem.setUint8 (addr, value); }
126
+ storeI8(addr, value) { this.mem.setInt8 (addr, value); }
127
+ storeU16(addr, value) { this.mem.setUint16 (addr, value, true); }
128
+ storeI16(addr, value) { this.mem.setInt16 (addr, value, true); }
129
+ storeU32(addr, value) { this.mem.setUint32 (addr, value, true); }
130
+ storeI32(addr, value) { this.mem.setInt32 (addr, value, true); }
131
+ storeU64(addr, value) {
132
+ this.mem.setUint32(addr + 0, Number(value), true);
133
+
134
+ let div = 4294967296;
135
+ if (typeof value == 'bigint') {
136
+ div = BigInt(div);
137
+ }
138
+
139
+ this.mem.setUint32(addr + 4, Math.floor(Number(value / div)), true);
140
+ }
141
+ storeI64(addr, value) {
142
+ this.mem.setUint32(addr + 0, Number(value), true);
143
+
144
+ let div = 4294967296;
145
+ if (typeof value == 'bigint') {
146
+ div = BigInt(div);
147
+ }
148
+
149
+ this.mem.setInt32(addr + 4, Math.floor(Number(value / div)), true);
150
+ }
151
+ storeF32(addr, value) { this.mem.setFloat32(addr, value, true); }
152
+ storeF64(addr, value) { this.mem.setFloat64(addr, value, true); }
153
+ storeInt(addr, value) {
154
+ if (this.intSize == 8) {
155
+ this.storeI64(addr, value);
156
+ } else if (this.intSize == 4) {
157
+ this.storeI32(addr, value);
158
+ } else {
159
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
160
+ }
161
+ }
162
+ storeUint(addr, value) {
163
+ if (this.intSize == 8) {
164
+ this.storeU64(addr, value);
165
+ } else if (this.intSize == 4) {
166
+ this.storeU32(addr, value);
167
+ } else {
168
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
169
+ }
170
+ }
171
+
172
+ // Returned length might not be the same as `value.length` if non-ascii strings are given.
173
+ storeString(addr, value) {
174
+ const src = new TextEncoder().encode(value);
175
+ const dst = new Uint8Array(this.memory.buffer, addr, src.length);
176
+ dst.set(src);
177
+ return src.length;
178
+ }
179
+ };
180
+
181
+ class WebGLInterface {
182
+ constructor(wasmMemoryInterface) {
183
+ this.wasmMemoryInterface = wasmMemoryInterface;
184
+ this.ctxElement = null;
185
+ this.ctx = null;
186
+ this.ctxVersion = 1.0;
187
+ this.counter = 1;
188
+ this.lastError = 0;
189
+ this.buffers = [];
190
+ this.mappedBuffers = {};
191
+ this.programs = [];
192
+ this.framebuffers = [];
193
+ this.renderbuffers = [];
194
+ this.textures = [];
195
+ this.uniforms = [];
196
+ this.shaders = [];
197
+ this.vaos = [];
198
+ this.contexts = [];
199
+ this.currentContext = null;
200
+ this.offscreenCanvases = {};
201
+ this.timerQueriesEXT = [];
202
+ this.queries = [];
203
+ this.samplers = [];
204
+ this.transformFeedbacks = [];
205
+ this.syncs = [];
206
+ this.programInfos = {};
207
+ this.extensions = [];
208
+ }
209
+
210
+ get mem() {
211
+ return this.wasmMemoryInterface
212
+ }
213
+
214
+ setCurrentContext(element, contextSettings) {
215
+ if (!element) {
216
+ return false;
217
+ }
218
+ if (this.ctxElement == element) {
219
+ return true;
220
+ }
221
+
222
+ contextSettings = contextSettings ?? {};
223
+ this.ctx = element.getContext("webgl2", contextSettings) || element.getContext("webgl", contextSettings);
224
+ if (!this.ctx) {
225
+ return false;
226
+ }
227
+ this.ctxElement = element;
228
+ if (this.ctx.getParameter(0x1F02).indexOf("WebGL 2.0") !== -1) {
229
+ this.ctxVersion = 2.0;
230
+ } else {
231
+ this.ctxVersion = 1.0;
232
+ }
233
+
234
+ this.extensions = this.ctx.getSupportedExtensions();
235
+
236
+ return true;
237
+ }
238
+
239
+ assertWebGL2() {
240
+ if (this.ctxVersion < 2) {
241
+ throw new Error("WebGL2 procedure called in a canvas without a WebGL2 context");
242
+ }
243
+ }
244
+ getNewId(table) {
245
+ for (var ret = this.counter++, i = table.length; i < ret; i++) {
246
+ table[i] = null;
247
+ }
248
+ return ret;
249
+ }
250
+ recordError(errorCode) {
251
+ this.lastError || (this.lastError = errorCode);
252
+ }
253
+ populateUniformTable(program) {
254
+ let p = this.programs[program];
255
+ this.programInfos[program] = {
256
+ uniforms: {},
257
+ maxUniformLength: 0,
258
+ maxAttributeLength: -1,
259
+ maxUniformBlockNameLength: -1,
260
+ };
261
+ for (let ptable = this.programInfos[program], utable = ptable.uniforms, numUniforms = this.ctx.getProgramParameter(p, this.ctx.ACTIVE_UNIFORMS), i = 0; i < numUniforms; ++i) {
262
+ let u = this.ctx.getActiveUniform(p, i);
263
+ let name = u.name;
264
+ if (ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length + 1), name.indexOf("]", name.length - 1) !== -1) {
265
+ name = name.slice(0, name.lastIndexOf("["));
266
+ }
267
+ let loc = this.ctx.getUniformLocation(p, name);
268
+ if (loc !== null) {
269
+ let id = this.getNewId(this.uniforms);
270
+ utable[name] = [u.size, id], this.uniforms[id] = loc;
271
+ for (let j = 1; j < u.size; ++j) {
272
+ let n = name + "[" + j + "]";
273
+ let loc = this.ctx.getUniformLocation(p, n);
274
+ let id = this.getNewId(this.uniforms);
275
+ this.uniforms[id] = loc;
276
+ }
277
+ }
278
+ }
279
+ }
280
+ getSource(shader, strings_ptr, strings_length) {
281
+ const stringSize = this.mem.intSize*2;
282
+ let source = "";
283
+ for (let i = 0; i < strings_length; i++) {
284
+ let ptr = this.mem.loadPtr(strings_ptr + i*stringSize);
285
+ let len = this.mem.loadPtr(strings_ptr + i*stringSize + 4);
286
+ let str = this.mem.loadString(ptr, len);
287
+ source += str;
288
+ }
289
+ return source;
290
+ }
291
+
292
+ loadTypedArrayFromTexelType(type, size, data) {
293
+ switch (type) {
294
+ case this.ctx.SHORT: return this.mem.loadI16Array(data, size/2);
295
+ case this.ctx.UNSIGNED_SHORT_5_5_5_1:
296
+ case this.ctx.UNSIGNED_SHORT_5_6_5:
297
+ case this.ctx.UNSIGNED_SHORT_4_4_4_4:
298
+ case this.ctx.UNSIGNED_SHORT:
299
+ case this.ctx.HALF_FLOAT: return this.mem.loadU16Array(data, size/2);
300
+ case this.ctx.FLOAT: return this.mem.loadF32Array(data, size/4);
301
+ case this.ctx.INT: return this.mem.loadI32Array(data, size/4)
302
+ case this.ctx.UNSIGNED_INT_24_8:
303
+ case this.ctx.UNSIGNED_INT_5_9_9_9_REV:
304
+ case this.ctx.UNSIGNED_INT_10F_11F_11F_REV:
305
+ case this.ctx.UNSIGNED_INT_2_10_10_10_REV:
306
+ case this.ctx.UNSIGNED_INT: return this.mem.loadU32Array(data, size/4)
307
+ case this.ctx.BYTE: return this.mem.loadI8Array(data, size);
308
+ case this.ctx.UNSIGNED_BYTE: return this.mem.loadU8Array(data, size);
309
+ case this.ctx.FLOAT_32_UNSIGNED_INT_24_8_REV:
310
+ throw new Error("Source data of type FLOAT_32_UNSIGNED_INT_24_8_REV must be null");
311
+ }
312
+
313
+ throw new Error(`Unsupported texture data type: 0x${type.toString(16)}`);
314
+ }
315
+
316
+ getWebGL1Interface() {
317
+ return {
318
+ SetCurrentContextById: (name_ptr, name_len) => {
319
+ let name = this.mem.loadString(name_ptr, name_len);
320
+ let element = getElement(name);
321
+ return this.setCurrentContext(element, {alpha: true, antialias: true, depth: true, premultipliedAlpha: true});
322
+ },
323
+ CreateCurrentContextById: (name_ptr, name_len, attributes) => {
324
+ let name = this.mem.loadString(name_ptr, name_len);
325
+ let element = getElement(name);
326
+
327
+ let contextSettings = {
328
+ alpha: !(attributes & (1<<0)),
329
+ antialias: !(attributes & (1<<1)),
330
+ depth: !(attributes & (1<<2)),
331
+ failIfMajorPerformanceCaveat: !!(attributes & (1<<3)),
332
+ premultipliedAlpha: !(attributes & (1<<4)),
333
+ preserveDrawingBuffer: !!(attributes & (1<<5)),
334
+ stencil: !!(attributes & (1<<6)),
335
+ desynchronized: !!(attributes & (1<<7)),
336
+ };
337
+
338
+ return this.setCurrentContext(element, contextSettings);
339
+ },
340
+ GetCurrentContextAttributes: () => {
341
+ if (!this.ctx) {
342
+ return 0;
343
+ }
344
+ let attrs = this.ctx.getContextAttributes();
345
+ let res = 0;
346
+ if (!attrs.alpha) res |= 1<<0;
347
+ if (!attrs.antialias) res |= 1<<1;
348
+ if (!attrs.depth) res |= 1<<2;
349
+ if (attrs.failIfMajorPerformanceCaveat) res |= 1<<3;
350
+ if (!attrs.premultipliedAlpha) res |= 1<<4;
351
+ if (attrs.preserveDrawingBuffer) res |= 1<<5;
352
+ if (attrs.stencil) res |= 1<<6;
353
+ if (attrs.desynchronized) res |= 1<<7;
354
+ return res;
355
+ },
356
+
357
+ DrawingBufferWidth: () => this.ctx.drawingBufferWidth,
358
+ DrawingBufferHeight: () => this.ctx.drawingBufferHeight,
359
+
360
+ IsExtensionSupported: (name_ptr, name_len) => {
361
+ let name = this.mem.loadString(name_ptr, name_len);
362
+ let extensions = this.extensions;
363
+ return extensions.indexOf(name) !== -1
364
+ },
365
+
366
+ GetSupportedExtensionFromIndex: (index, buf_ptr, buf_len, length_ptr) => {
367
+ let extensions = this.extensions;
368
+ if (index < 0 || index >= extensions.length) {
369
+ return false;
370
+ }
371
+
372
+ let ext = extensions[index];
373
+ const n = Math.min(buf_len, ext.length);
374
+ ext = ext.substring(0, n);
375
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(ext));
376
+
377
+ this.mem.storeInt(length_ptr, n);
378
+
379
+ return true;
380
+ },
381
+
382
+ GetExtension: (name_ptr, name_len) => {
383
+ let name = this.mem.loadString(name_ptr, name_len);
384
+ this.ctx.getExtension(name);
385
+ },
386
+
387
+ GetError: () => {
388
+ let err = this.lastError;
389
+ this.recordError(0);
390
+ if (err) {
391
+ return err;
392
+ }
393
+ return this.ctx.getError();
394
+ },
395
+
396
+ GetWebGLVersion: (major_ptr, minor_ptr) => {
397
+ let version = this.ctx.getParameter(0x1F02);
398
+ if (version.indexOf("WebGL 2.0") !== -1) {
399
+ this.mem.storeI32(major_ptr, 2);
400
+ this.mem.storeI32(minor_ptr, 0);
401
+ return;
402
+ }
403
+
404
+ this.mem.storeI32(major_ptr, 1);
405
+ this.mem.storeI32(minor_ptr, 0);
406
+ },
407
+ GetESVersion: (major_ptr, minor_ptr) => {
408
+ let version = this.ctx.getParameter(0x1F02);
409
+ if (version.indexOf("OpenGL ES 3.0") !== -1) {
410
+ this.mem.storeI32(major_ptr, 3);
411
+ this.mem.storeI32(minor_ptr, 0);
412
+ return;
413
+ }
414
+
415
+ this.mem.storeI32(major_ptr, 2);
416
+ this.mem.storeI32(minor_ptr, 0);
417
+ },
418
+
419
+
420
+ ActiveTexture: (x) => {
421
+ this.ctx.activeTexture(x);
422
+ },
423
+ AttachShader: (program, shader) => {
424
+ this.ctx.attachShader(this.programs[program], this.shaders[shader]);
425
+ },
426
+ BindAttribLocation: (program, index, name_ptr, name_len) => {
427
+ let name = this.mem.loadString(name_ptr, name_len);
428
+ this.ctx.bindAttribLocation(this.programs[program], index, name)
429
+ },
430
+ BindBuffer: (target, buffer) => {
431
+ let bufferObj = buffer ? this.buffers[buffer] : null;
432
+ if (target == 35051) {
433
+ this.ctx.currentPixelPackBufferBinding = buffer;
434
+ } else {
435
+ if (target == 35052) {
436
+ this.ctx.currentPixelUnpackBufferBinding = buffer;
437
+ }
438
+ this.ctx.bindBuffer(target, bufferObj)
439
+ }
440
+ },
441
+ BindFramebuffer: (target, framebuffer) => {
442
+ this.ctx.bindFramebuffer(target, framebuffer ? this.framebuffers[framebuffer] : null)
443
+ },
444
+ BindTexture: (target, texture) => {
445
+ this.ctx.bindTexture(target, texture ? this.textures[texture] : null)
446
+ },
447
+ BindRenderbuffer: (target, renderbuffer) => {
448
+ this.ctx.bindRenderbuffer(target, renderbuffer ? this.renderbuffers[renderbuffer] : null)
449
+ },
450
+ BlendColor: (red, green, blue, alpha) => {
451
+ this.ctx.blendColor(red, green, blue, alpha);
452
+ },
453
+ BlendEquation: (mode) => {
454
+ this.ctx.blendEquation(mode);
455
+ },
456
+ BlendEquationSeparate: (modeRGB, modeAlpha) => {
457
+ this.ctx.blendEquationSeparate(modeRGB, modeAlpha);
458
+ },
459
+ BlendFunc: (sfactor, dfactor) => {
460
+ this.ctx.blendFunc(sfactor, dfactor);
461
+ },
462
+ BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => {
463
+ this.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
464
+ },
465
+
466
+
467
+ BufferData: (target, size, data, usage) => {
468
+ if (data) {
469
+ this.ctx.bufferData(target, this.mem.loadBytes(data, size), usage);
470
+ } else {
471
+ this.ctx.bufferData(target, size, usage);
472
+ }
473
+ },
474
+ BufferSubData: (target, offset, size, data) => {
475
+ if (data) {
476
+ this.ctx.bufferSubData(target, offset, this.mem.loadBytes(data, size));
477
+ } else {
478
+ this.ctx.bufferSubData(target, offset, null);
479
+ }
480
+ },
481
+
482
+
483
+ Clear: (x) => {
484
+ this.ctx.clear(x);
485
+ },
486
+ ClearColor: (r, g, b, a) => {
487
+ this.ctx.clearColor(r, g, b, a);
488
+ },
489
+ ClearDepth: (x) => {
490
+ this.ctx.clearDepth(x);
491
+ },
492
+ ClearStencil: (x) => {
493
+ this.ctx.clearStencil(x);
494
+ },
495
+ ColorMask: (r, g, b, a) => {
496
+ this.ctx.colorMask(!!r, !!g, !!b, !!a);
497
+ },
498
+ CompileShader: (shader) => {
499
+ this.ctx.compileShader(this.shaders[shader]);
500
+ },
501
+
502
+
503
+ CompressedTexImage2D: (target, level, internalformat, width, height, border, imageSize, data) => {
504
+ if (data) {
505
+ this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, this.mem.loadBytes(data, imageSize));
506
+ } else {
507
+ this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, null);
508
+ }
509
+ },
510
+ CompressedTexSubImage2D: (target, level, xoffset, yoffset, width, height, format, imageSize, data) => {
511
+ if (data) {
512
+ this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, this.mem.loadBytes(data, imageSize));
513
+ } else {
514
+ this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, null);
515
+ }
516
+ },
517
+
518
+ CopyTexImage2D: (target, level, internalformat, x, y, width, height, border) => {
519
+ this.ctx.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
520
+ },
521
+ CopyTexSubImage2D: (target, level, xoffset, yoffset, x, y, width, height) => {
522
+ this.ctx.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
523
+ },
524
+
525
+
526
+ CreateBuffer: () => {
527
+ let buffer = this.ctx.createBuffer();
528
+ if (!buffer) {
529
+ this.recordError(1282);
530
+ return 0;
531
+ }
532
+ let id = this.getNewId(this.buffers);
533
+ buffer.name = id
534
+ this.buffers[id] = buffer;
535
+ return id;
536
+ },
537
+ CreateFramebuffer: () => {
538
+ let buffer = this.ctx.createFramebuffer();
539
+ let id = this.getNewId(this.framebuffers);
540
+ buffer.name = id
541
+ this.framebuffers[id] = buffer;
542
+ return id;
543
+ },
544
+ CreateProgram: () => {
545
+ let program = this.ctx.createProgram();
546
+ let id = this.getNewId(this.programs);
547
+ program.name = id;
548
+ this.programs[id] = program;
549
+ return id;
550
+ },
551
+ CreateRenderbuffer: () => {
552
+ let buffer = this.ctx.createRenderbuffer();
553
+ let id = this.getNewId(this.renderbuffers);
554
+ buffer.name = id;
555
+ this.renderbuffers[id] = buffer;
556
+ return id;
557
+ },
558
+ CreateShader: (shaderType) => {
559
+ let shader = this.ctx.createShader(shaderType);
560
+ let id = this.getNewId(this.shaders);
561
+ shader.name = id;
562
+ this.shaders[id] = shader;
563
+ return id;
564
+ },
565
+ CreateTexture: () => {
566
+ let texture = this.ctx.createTexture();
567
+ if (!texture) {
568
+ this.recordError(1282)
569
+ return 0;
570
+ }
571
+ let id = this.getNewId(this.textures);
572
+ texture.name = id;
573
+ this.textures[id] = texture;
574
+ return id;
575
+ },
576
+
577
+
578
+ CullFace: (mode) => {
579
+ this.ctx.cullFace(mode);
580
+ },
581
+
582
+
583
+ DeleteBuffer: (id) => {
584
+ let obj = this.buffers[id];
585
+ if (obj && id != 0) {
586
+ this.ctx.deleteBuffer(obj);
587
+ this.buffers[id] = null;
588
+ }
589
+ },
590
+ DeleteFramebuffer: (id) => {
591
+ let obj = this.framebuffers[id];
592
+ if (obj && id != 0) {
593
+ this.ctx.deleteFramebuffer(obj);
594
+ this.framebuffers[id] = null;
595
+ }
596
+ },
597
+ DeleteProgram: (id) => {
598
+ let obj = this.programs[id];
599
+ if (obj && id != 0) {
600
+ this.ctx.deleteProgram(obj);
601
+ this.programs[id] = null;
602
+ }
603
+ },
604
+ DeleteRenderbuffer: (id) => {
605
+ let obj = this.renderbuffers[id];
606
+ if (obj && id != 0) {
607
+ this.ctx.deleteRenderbuffer(obj);
608
+ this.renderbuffers[id] = null;
609
+ }
610
+ },
611
+ DeleteShader: (id) => {
612
+ let obj = this.shaders[id];
613
+ if (obj && id != 0) {
614
+ this.ctx.deleteShader(obj);
615
+ this.shaders[id] = null;
616
+ }
617
+ },
618
+ DeleteTexture: (id) => {
619
+ let obj = this.textures[id];
620
+ if (obj && id != 0) {
621
+ this.ctx.deleteTexture(obj);
622
+ this.textures[id] = null;
623
+ }
624
+ },
625
+
626
+
627
+ DepthFunc: (func) => {
628
+ this.ctx.depthFunc(func);
629
+ },
630
+ DepthMask: (flag) => {
631
+ this.ctx.depthMask(!!flag);
632
+ },
633
+ DepthRange: (zNear, zFar) => {
634
+ this.ctx.depthRange(zNear, zFar);
635
+ },
636
+ DetachShader: (program, shader) => {
637
+ this.ctx.detachShader(this.programs[program], this.shaders[shader]);
638
+ },
639
+ Disable: (cap) => {
640
+ this.ctx.disable(cap);
641
+ },
642
+ DisableVertexAttribArray: (index) => {
643
+ this.ctx.disableVertexAttribArray(index);
644
+ },
645
+ DrawArrays: (mode, first, count) => {
646
+ this.ctx.drawArrays(mode, first, count);
647
+ },
648
+ DrawElements: (mode, count, type, indices) => {
649
+ this.ctx.drawElements(mode, count, type, indices);
650
+ },
651
+
652
+
653
+ Enable: (cap) => {
654
+ this.ctx.enable(cap);
655
+ },
656
+ EnableVertexAttribArray: (index) => {
657
+ this.ctx.enableVertexAttribArray(index);
658
+ },
659
+ Finish: () => {
660
+ this.ctx.finish();
661
+ },
662
+ Flush: () => {
663
+ this.ctx.flush();
664
+ },
665
+ FramebufferRenderbuffer: (target, attachment, renderbuffertarget, renderbuffer) => {
666
+ this.ctx.framebufferRenderbuffer(target, attachment, renderbuffertarget, this.renderbuffers[renderbuffer]);
667
+ },
668
+ FramebufferTexture2D: (target, attachment, textarget, texture, level) => {
669
+ this.ctx.framebufferTexture2D(target, attachment, textarget, this.textures[texture], level);
670
+ },
671
+ CheckFramebufferStatus: (target) => {
672
+ return this.ctx.checkFramebufferStatus(target)
673
+ },
674
+ FrontFace: (mode) => {
675
+ this.ctx.frontFace(mode);
676
+ },
677
+
678
+
679
+ GenerateMipmap: (target) => {
680
+ this.ctx.generateMipmap(target);
681
+ },
682
+
683
+ GetBufferParameter: (target, pname) => {
684
+ return this.ctx.getBufferParameter(target, pname);
685
+ },
686
+
687
+
688
+ GetActiveAttrib: (program, index, size_ptr, type_ptr, name_buf_ptr, name_buf_len, name_len_ptr) => {
689
+ const info = this.ctx.getActiveAttrib(this.programs[program], index);
690
+
691
+ if (size_ptr) {
692
+ this.mem.storeInt(size_ptr, info.size);
693
+ }
694
+
695
+ if (type_ptr) {
696
+ this.mem.storeI32(type_ptr, info.type);
697
+ }
698
+
699
+ if (name_buf_ptr && name_buf_len > 0) {
700
+ let n = Math.min(name_buf_len, info.name.length);
701
+ let name = info.name.substring(0, n);
702
+ this.mem.loadBytes(name_buf_ptr, name_buf_len).set(new TextEncoder().encode(name));
703
+ this.mem.storeInt(name_len_ptr, n);
704
+ } else if (name_len_ptr) {
705
+ this.mem.storeInt(name_len_ptr, info.name.length);
706
+ }
707
+ },
708
+
709
+ GetActiveUniform: (program, index, size_ptr, type_ptr, name_buf_ptr, name_buf_len, name_len_ptr) => {
710
+ let info = this.ctx.getActiveUniform(this.programs[program], index);
711
+
712
+ if (size_ptr) {
713
+ this.mem.storeInt(size_ptr, info.size);
714
+ }
715
+
716
+ if (type_ptr) {
717
+ this.mem.storeI32(type_ptr, info.type);
718
+ }
719
+
720
+ if (name_buf_ptr && name_buf_len > 0) {
721
+ let n = Math.min(name_buf_len, info.name.length);
722
+ let name = info.name.substring(0, n);
723
+ this.mem.loadBytes(name_buf_ptr, name_buf_len).set(new TextEncoder().encode(name));
724
+ this.mem.storeInt(name_len_ptr, n);
725
+ } else if (name_len_ptr) {
726
+ this.mem.storeInt(name_len_ptr, info.name.length);
727
+ }
728
+ },
729
+
730
+ GetAttribLocation: (program, name_ptr, name_len) => {
731
+ let name = this.mem.loadString(name_ptr, name_len);
732
+ return this.ctx.getAttribLocation(this.programs[program], name);
733
+ },
734
+
735
+
736
+ GetParameter: (pname) => {
737
+ return this.ctx.getParameter(pname);
738
+ },
739
+ GetParameter4i: (pname, v0, v1, v2, v3) => {
740
+ const i4 = this.ctx.getParameter(pname);
741
+ this.mem.storeI32(v0, i4[0]);
742
+ this.mem.storeI32(v1, i4[1]);
743
+ this.mem.storeI32(v2, i4[2]);
744
+ this.mem.storeI32(v3, i4[3]);
745
+ },
746
+ GetProgramParameter: (program, pname) => {
747
+ return this.ctx.getProgramParameter(this.programs[program], pname)
748
+ },
749
+ GetProgramInfoLog: (program, buf_ptr, buf_len, length_ptr) => {
750
+ let log = this.ctx.getProgramInfoLog(this.programs[program]);
751
+ if (log === null) {
752
+ log = "(unknown error)";
753
+ }
754
+ if (buf_len > 0 && buf_ptr) {
755
+ let n = Math.min(buf_len, log.length);
756
+ log = log.substring(0, n);
757
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(log))
758
+
759
+ this.mem.storeInt(length_ptr, n);
760
+ }
761
+ },
762
+ GetShaderInfoLog: (shader, buf_ptr, buf_len, length_ptr) => {
763
+ let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
764
+ if (log === null) {
765
+ log = "(unknown error)";
766
+ }
767
+ if (buf_len > 0 && buf_ptr) {
768
+ let n = Math.min(buf_len, log.length);
769
+ log = log.substring(0, n);
770
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(log))
771
+
772
+ this.mem.storeInt(length_ptr, n);
773
+ }
774
+ },
775
+ GetShaderiv: (shader, pname, p) => {
776
+ if (p) {
777
+ if (pname == 35716) {
778
+ let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
779
+ if (log === null) {
780
+ log = "(unknown error)";
781
+ }
782
+ this.mem.storeInt(p, log.length+1);
783
+ } else if (pname == 35720) {
784
+ let source = this.ctx.getShaderSource(this.shaders[shader]);
785
+ let sourceLength = (source === null || source.length == 0) ? 0 : source.length+1;
786
+ this.mem.storeInt(p, sourceLength);
787
+ } else {
788
+ let param = this.ctx.getShaderParameter(this.shaders[shader], pname);
789
+ this.mem.storeI32(p, param);
790
+ }
791
+ } else {
792
+ this.recordError(1281);
793
+ }
794
+ },
795
+
796
+
797
+ GetUniformLocation: (program, name_ptr, name_len) => {
798
+ let name = this.mem.loadString(name_ptr, name_len);
799
+ let arrayOffset = 0;
800
+ if (name.indexOf("]", name.length - 1) !== -1) {
801
+ let ls = name.lastIndexOf("["),
802
+ arrayIndex = name.slice(ls + 1, -1);
803
+ if (arrayIndex.length > 0 && (arrayOffset = parseInt(arrayIndex)) < 0) {
804
+ return -1;
805
+ }
806
+ name = name.slice(0, ls)
807
+ }
808
+ var ptable = this.programInfos[program];
809
+ if (!ptable) {
810
+ return -1;
811
+ }
812
+ var uniformInfo = ptable.uniforms[name];
813
+ return (uniformInfo && arrayOffset < uniformInfo[0]) ? uniformInfo[1] + arrayOffset : -1
814
+ },
815
+
816
+
817
+ GetVertexAttribOffset: (index, pname) => {
818
+ return this.ctx.getVertexAttribOffset(index, pname);
819
+ },
820
+
821
+
822
+ Hint: (target, mode) => {
823
+ this.ctx.hint(target, mode);
824
+ },
825
+
826
+
827
+ IsBuffer: (buffer) => this.ctx.isBuffer(this.buffers[buffer]),
828
+ IsEnabled: (cap) => this.ctx.isEnabled(cap),
829
+ IsFramebuffer: (framebuffer) => this.ctx.isFramebuffer(this.framebuffers[framebuffer]),
830
+ IsProgram: (program) => this.ctx.isProgram(this.programs[program]),
831
+ IsRenderbuffer: (renderbuffer) => this.ctx.isRenderbuffer(this.renderbuffers[renderbuffer]),
832
+ IsShader: (shader) => this.ctx.isShader(this.shaders[shader]),
833
+ IsTexture: (texture) => this.ctx.isTexture(this.textures[texture]),
834
+
835
+ LineWidth: (width) => {
836
+ this.ctx.lineWidth(width);
837
+ },
838
+ LinkProgram: (program) => {
839
+ this.ctx.linkProgram(this.programs[program]);
840
+ this.programInfos[program] = null;
841
+ this.populateUniformTable(program);
842
+ },
843
+ PixelStorei: (pname, param) => {
844
+ this.ctx.pixelStorei(pname, param);
845
+ },
846
+ PolygonOffset: (factor, units) => {
847
+ this.ctx.polygonOffset(factor, units);
848
+ },
849
+
850
+
851
+ ReadnPixels: (x, y, width, height, format, type, bufSize, data) => {
852
+ this.ctx.readPixels(x, y, width, height, format, type, this.mem.loadBytes(data, bufSize));
853
+ },
854
+ RenderbufferStorage: (target, internalformat, width, height) => {
855
+ this.ctx.renderbufferStorage(target, internalformat, width, height);
856
+ },
857
+ SampleCoverage: (value, invert) => {
858
+ this.ctx.sampleCoverage(value, !!invert);
859
+ },
860
+ Scissor: (x, y, width, height) => {
861
+ this.ctx.scissor(x, y, width, height);
862
+ },
863
+ ShaderSource: (shader, strings_ptr, strings_length) => {
864
+ let source = this.getSource(shader, strings_ptr, strings_length);
865
+ this.ctx.shaderSource(this.shaders[shader], source);
866
+ },
867
+
868
+ StencilFunc: (func, ref, mask) => {
869
+ this.ctx.stencilFunc(func, ref, mask);
870
+ },
871
+ StencilFuncSeparate: (face, func, ref, mask) => {
872
+ this.ctx.stencilFuncSeparate(face, func, ref, mask);
873
+ },
874
+ StencilMask: (mask) => {
875
+ this.ctx.stencilMask(mask);
876
+ },
877
+ StencilMaskSeparate: (face, mask) => {
878
+ this.ctx.stencilMaskSeparate(face, mask);
879
+ },
880
+ StencilOp: (fail, zfail, zpass) => {
881
+ this.ctx.stencilOp(fail, zfail, zpass);
882
+ },
883
+ StencilOpSeparate: (face, fail, zfail, zpass) => {
884
+ this.ctx.stencilOpSeparate(face, fail, zfail, zpass);
885
+ },
886
+
887
+
888
+ TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
889
+ if (data) {
890
+ const texelData = this.loadTypedArrayFromTexelType(type, size, data);
891
+ this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, texelData);
892
+ } else {
893
+ this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, null);
894
+ }
895
+ },
896
+ TexParameterf: (target, pname, param) => {
897
+ this.ctx.texParameterf(target, pname, param);
898
+ },
899
+ TexParameteri: (target, pname, param) => {
900
+ this.ctx.texParameteri(target, pname, param);
901
+ },
902
+ TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => {
903
+ const texelData = this.loadTypedArrayFromTexelType(type, size, data);
904
+ this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, texelData);
905
+ },
906
+
907
+
908
+ Uniform1f: (location, v0) => { this.ctx.uniform1f(this.uniforms[location], v0); },
909
+ Uniform2f: (location, v0, v1) => { this.ctx.uniform2f(this.uniforms[location], v0, v1); },
910
+ Uniform3f: (location, v0, v1, v2) => { this.ctx.uniform3f(this.uniforms[location], v0, v1, v2); },
911
+ Uniform4f: (location, v0, v1, v2, v3) => { this.ctx.uniform4f(this.uniforms[location], v0, v1, v2, v3); },
912
+
913
+ Uniform1i: (location, v0) => { this.ctx.uniform1i(this.uniforms[location], v0); },
914
+ Uniform2i: (location, v0, v1) => { this.ctx.uniform2i(this.uniforms[location], v0, v1); },
915
+ Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); },
916
+ Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
917
+
918
+ Uniform1fv: (location, count, addr) => {
919
+ let array = this.mem.loadF32Array(addr, 1*count);
920
+ this.ctx.uniform1fv(this.uniforms[location], array);
921
+ },
922
+ Uniform2fv: (location, count, addr) => {
923
+ let array = this.mem.loadF32Array(addr, 2*count);
924
+ this.ctx.uniform2fv(this.uniforms[location], array);
925
+ },
926
+ Uniform3fv: (location, count, addr) => {
927
+ let array = this.mem.loadF32Array(addr, 3*count);
928
+ this.ctx.uniform3fv(this.uniforms[location], array);
929
+ },
930
+ Uniform4fv: (location, count, addr) => {
931
+ let array = this.mem.loadF32Array(addr, 4*count);
932
+ this.ctx.uniform4fv(this.uniforms[location], array);
933
+ },
934
+
935
+ Uniform1iv: (location, count, addr) => {
936
+ let array = this.mem.loadI32Array(addr, 1*count);
937
+ this.ctx.uniform1iv(this.uniforms[location], array);
938
+ },
939
+ Uniform2iv: (location, count, addr) => {
940
+ let array = this.mem.loadI32Array(addr, 2*count);
941
+ this.ctx.uniform2iv(this.uniforms[location], array);
942
+ },
943
+ Uniform3iv: (location, count, addr) => {
944
+ let array = this.mem.loadI32Array(addr, 3*count);
945
+ this.ctx.uniform3iv(this.uniforms[location], array);
946
+ },
947
+ Uniform4iv: (location, count, addr) => {
948
+ let array = this.mem.loadI32Array(addr, 4*count);
949
+ this.ctx.uniform4iv(this.uniforms[location], array);
950
+ },
951
+
952
+ UniformMatrix2fv: (location, addr) => {
953
+ let array = this.mem.loadF32Array(addr, 2*2);
954
+ this.ctx.uniformMatrix2fv(this.uniforms[location], false, array);
955
+ },
956
+ UniformMatrix3fv: (location, addr) => {
957
+ let array = this.mem.loadF32Array(addr, 3*3);
958
+ this.ctx.uniformMatrix3fv(this.uniforms[location], false, array);
959
+ },
960
+ UniformMatrix4fv: (location, addr) => {
961
+ let array = this.mem.loadF32Array(addr, 4*4);
962
+ this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
963
+ },
964
+
965
+ UseProgram: (program) => {
966
+ if (program) this.ctx.useProgram(this.programs[program]);
967
+ },
968
+ ValidateProgram: (program) => {
969
+ if (program) this.ctx.validateProgram(this.programs[program]);
970
+ },
971
+
972
+
973
+ VertexAttrib1f: (index, x) => {
974
+ this.ctx.vertexAttrib1f(index, x);
975
+ },
976
+ VertexAttrib2f: (index, x, y) => {
977
+ this.ctx.vertexAttrib2f(index, x, y);
978
+ },
979
+ VertexAttrib3f: (index, x, y, z) => {
980
+ this.ctx.vertexAttrib3f(index, x, y, z);
981
+ },
982
+ VertexAttrib4f: (index, x, y, z, w) => {
983
+ this.ctx.vertexAttrib4f(index, x, y, z, w);
984
+ },
985
+ VertexAttribPointer: (index, size, type, normalized, stride, ptr) => {
986
+ this.ctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
987
+ },
988
+
989
+ Viewport: (x, y, w, h) => {
990
+ this.ctx.viewport(x, y, w, h);
991
+ },
992
+ };
993
+ }
994
+
995
+ getWebGL2Interface() {
996
+ return {
997
+ /* Buffer objects */
998
+ CopyBufferSubData: (readTarget, writeTarget, readOffset, writeOffset, size) => {
999
+ this.assertWebGL2();
1000
+ this.ctx.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
1001
+ },
1002
+ GetBufferSubData: (target, srcByteOffset, dst_buffer_ptr, dst_buffer_len, dstOffset, length) => {
1003
+ this.assertWebGL2();
1004
+ this.ctx.getBufferSubData(target, srcByteOffset, this.mem.loadBytes(dst_buffer_ptr, dst_buffer_len), dstOffset, length);
1005
+ },
1006
+
1007
+ /* Framebuffer objects */
1008
+ BlitFramebuffer: (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) => {
1009
+ this.assertWebGL2();
1010
+ this.ctx.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
1011
+ },
1012
+ FramebufferTextureLayer: (target, attachment, texture, level, layer) => {
1013
+ this.assertWebGL2();
1014
+ this.ctx.framebufferTextureLayer(target, attachment, this.textures[texture], level, layer);
1015
+ },
1016
+ InvalidateFramebuffer: (target, attachments_ptr, attachments_len) => {
1017
+ this.assertWebGL2();
1018
+ let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
1019
+ this.ctx.invalidateFramebuffer(target, attachments);
1020
+ },
1021
+ InvalidateSubFramebuffer: (target, attachments_ptr, attachments_len, x, y, width, height) => {
1022
+ this.assertWebGL2();
1023
+ let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
1024
+ this.ctx.invalidateSubFramebuffer(target, attachments, x, y, width, height);
1025
+ },
1026
+ ReadBuffer: (src) => {
1027
+ this.assertWebGL2();
1028
+ this.ctx.readBuffer(src);
1029
+ },
1030
+
1031
+ /* Renderbuffer objects */
1032
+ RenderbufferStorageMultisample: (target, samples, internalformat, width, height) => {
1033
+ this.assertWebGL2();
1034
+ this.ctx.renderbufferStorageMultisample(target, samples, internalformat, width, height);
1035
+ },
1036
+
1037
+ /* Texture objects */
1038
+ TexStorage2D: (target, levels, internalformat, width, height) => {
1039
+ this.assertWebGL2();
1040
+ this.ctx.texStorage2D(target, levels, internalformat, width, height);
1041
+ },
1042
+ TexStorage3D: (target, levels, internalformat, width, height, depth) => {
1043
+ this.assertWebGL2();
1044
+ this.ctx.texStorage3D(target, levels, internalformat, width, height, depth);
1045
+ },
1046
+ TexImage3D: (target, level, internalformat, width, height, depth, border, format, type, size, data) => {
1047
+ this.assertWebGL2();
1048
+ if (data) {
1049
+ const texelData = this.loadTypedArrayFromTexelType(type, size, data);
1050
+ this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, texelData);
1051
+ } else {
1052
+ this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null);
1053
+ }
1054
+ },
1055
+ TexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, size, data) => {
1056
+ this.assertWebGL2();
1057
+ const texelData = this.loadTypedArrayFromTexelType(type, size, data);
1058
+ this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texelData);
1059
+ },
1060
+ CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => {
1061
+ this.assertWebGL2();
1062
+ if (data) {
1063
+ this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, this.mem.loadBytes(data, imageSize));
1064
+ } else {
1065
+ this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, null);
1066
+ }
1067
+ },
1068
+ CompressedTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) => {
1069
+ this.assertWebGL2();
1070
+ if (data) {
1071
+ this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, this.mem.loadBytes(data, imageSize));
1072
+ } else {
1073
+ this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, null);
1074
+ }
1075
+ },
1076
+
1077
+ CopyTexSubImage3D: (target, level, xoffset, yoffset, zoffset, x, y, width, height) => {
1078
+ this.assertWebGL2();
1079
+ this.ctx.copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
1080
+ },
1081
+
1082
+ /* Programs and shaders */
1083
+ GetFragDataLocation: (program, name_ptr, name_len) => {
1084
+ this.assertWebGL2();
1085
+ return this.ctx.getFragDataLocation(this.programs[program], this.mem.loadString(name_ptr, name_len));
1086
+ },
1087
+
1088
+ /* Uniforms */
1089
+ Uniform1ui: (location, v0) => {
1090
+ this.assertWebGL2();
1091
+ this.ctx.uniform1ui(this.uniforms[location], v0);
1092
+ },
1093
+ Uniform2ui: (location, v0, v1) => {
1094
+ this.assertWebGL2();
1095
+ this.ctx.uniform2ui(this.uniforms[location], v0, v1);
1096
+ },
1097
+ Uniform3ui: (location, v0, v1, v2) => {
1098
+ this.assertWebGL2();
1099
+ this.ctx.uniform3ui(this.uniforms[location], v0, v1, v2);
1100
+ },
1101
+ Uniform4ui: (location, v0, v1, v2, v3) => {
1102
+ this.assertWebGL2();
1103
+ this.ctx.uniform4ui(this.uniforms[location], v0, v1, v2, v3);
1104
+ },
1105
+
1106
+ UniformMatrix3x2fv: (location, addr) => {
1107
+ this.assertWebGL2();
1108
+ let array = this.mem.loadF32Array(addr, 3*2);
1109
+ this.ctx.uniformMatrix3x2fv(this.uniforms[location], false, array);
1110
+ },
1111
+ UniformMatrix4x2fv: (location, addr) => {
1112
+ this.assertWebGL2();
1113
+ let array = this.mem.loadF32Array(addr, 4*2);
1114
+ this.ctx.uniformMatrix4x2fv(this.uniforms[location], false, array);
1115
+ },
1116
+ UniformMatrix2x3fv: (location, addr) => {
1117
+ this.assertWebGL2();
1118
+ let array = this.mem.loadF32Array(addr, 2*3);
1119
+ this.ctx.uniformMatrix2x3fv(this.uniforms[location], false, array);
1120
+ },
1121
+ UniformMatrix4x3fv: (location, addr) => {
1122
+ this.assertWebGL2();
1123
+ let array = this.mem.loadF32Array(addr, 4*3);
1124
+ this.ctx.uniformMatrix4x3fv(this.uniforms[location], false, array);
1125
+ },
1126
+ UniformMatrix2x4fv: (location, addr) => {
1127
+ this.assertWebGL2();
1128
+ let array = this.mem.loadF32Array(addr, 2*4);
1129
+ this.ctx.uniformMatrix2x4fv(this.uniforms[location], false, array);
1130
+ },
1131
+ UniformMatrix3x4fv: (location, addr) => {
1132
+ this.assertWebGL2();
1133
+ let array = this.mem.loadF32Array(addr, 3*4);
1134
+ this.ctx.uniformMatrix3x4fv(this.uniforms[location], false, array);
1135
+ },
1136
+
1137
+ /* Vertex attribs */
1138
+ VertexAttribI4i: (index, x, y, z, w) => {
1139
+ this.assertWebGL2();
1140
+ this.ctx.vertexAttribI4i(index, x, y, z, w);
1141
+ },
1142
+ VertexAttribI4ui: (index, x, y, z, w) => {
1143
+ this.assertWebGL2();
1144
+ this.ctx.vertexAttribI4ui(index, x, y, z, w);
1145
+ },
1146
+ VertexAttribIPointer: (index, size, type, stride, offset) => {
1147
+ this.assertWebGL2();
1148
+ this.ctx.vertexAttribIPointer(index, size, type, stride, offset);
1149
+ },
1150
+
1151
+ /* Writing to the drawing buffer */
1152
+ VertexAttribDivisor: (index, divisor) => {
1153
+ this.assertWebGL2();
1154
+ this.ctx.vertexAttribDivisor(index, divisor);
1155
+ },
1156
+ DrawArraysInstanced: (mode, first, count, instanceCount) => {
1157
+ this.assertWebGL2();
1158
+ this.ctx.drawArraysInstanced(mode, first, count, instanceCount);
1159
+ },
1160
+ DrawElementsInstanced: (mode, count, type, offset, instanceCount) => {
1161
+ this.assertWebGL2();
1162
+ this.ctx.drawElementsInstanced(mode, count, type, offset, instanceCount);
1163
+ },
1164
+ DrawRangeElements: (mode, start, end, count, type, offset) => {
1165
+ this.assertWebGL2();
1166
+ this.ctx.drawRangeElements(mode, start, end, count, type, offset);
1167
+ },
1168
+
1169
+ /* Multiple Render Targets */
1170
+ DrawBuffers: (buffers_ptr, buffers_len) => {
1171
+ this.assertWebGL2();
1172
+ let array = this.mem.loadU32Array(buffers_ptr, buffers_len);
1173
+ this.ctx.drawBuffers(array);
1174
+ },
1175
+ ClearBufferfv: (buffer, drawbuffer, values_ptr, values_len) => {
1176
+ this.assertWebGL2();
1177
+ let array = this.mem.loadF32Array(values_ptr, values_len);
1178
+ this.ctx.clearBufferfv(buffer, drawbuffer, array);
1179
+ },
1180
+ ClearBufferiv: (buffer, drawbuffer, values_ptr, values_len) => {
1181
+ this.assertWebGL2();
1182
+ let array = this.mem.loadI32Array(values_ptr, values_len);
1183
+ this.ctx.clearBufferiv(buffer, drawbuffer, array);
1184
+ },
1185
+ ClearBufferuiv: (buffer, drawbuffer, values_ptr, values_len) => {
1186
+ this.assertWebGL2();
1187
+ let array = this.mem.loadU32Array(values_ptr, values_len);
1188
+ this.ctx.clearBufferuiv(buffer, drawbuffer, array);
1189
+ },
1190
+ ClearBufferfi: (buffer, drawbuffer, depth, stencil) => {
1191
+ this.assertWebGL2();
1192
+ this.ctx.clearBufferfi(buffer, drawbuffer, depth, stencil);
1193
+ },
1194
+
1195
+ /* Query Objects */
1196
+ CreateQuery: () => {
1197
+ this.assertWebGL2();
1198
+ let query = this.ctx.createQuery();
1199
+ let id = this.getNewId(this.queries);
1200
+ query.name = id;
1201
+ this.queries[id] = query;
1202
+ return id;
1203
+ },
1204
+ DeleteQuery: (id) => {
1205
+ this.assertWebGL2();
1206
+ let obj = this.queries[id];
1207
+ if (obj && id != 0) {
1208
+ this.ctx.deleteQuery(obj);
1209
+ this.queries[id] = null;
1210
+ }
1211
+ },
1212
+ IsQuery: (query) => {
1213
+ this.assertWebGL2();
1214
+ return this.ctx.isQuery(this.queries[query]);
1215
+ },
1216
+ BeginQuery: (target, query) => {
1217
+ this.assertWebGL2();
1218
+ this.ctx.beginQuery(target, this.queries[query])
1219
+ },
1220
+ EndQuery: (target) => {
1221
+ this.assertWebGL2();
1222
+ this.ctx.endQuery(target);
1223
+ },
1224
+ GetQuery: (target, pname) => {
1225
+ this.assertWebGL2();
1226
+ let query = this.ctx.getQuery(target, pname);
1227
+ if (!query) {
1228
+ return 0;
1229
+ }
1230
+ if (this.queries.indexOf(query) !== -1) {
1231
+ return query.name;
1232
+ }
1233
+ let id = this.getNewId(this.queries);
1234
+ query.name = id;
1235
+ this.queries[id] = query;
1236
+ return id;
1237
+ },
1238
+
1239
+ /* Sampler Objects */
1240
+ CreateSampler: () => {
1241
+ this.assertWebGL2();
1242
+ let sampler = this.ctx.createSampler();
1243
+ let id = this.getNewId(this.samplers);
1244
+ sampler.name = id;
1245
+ this.samplers[id] = sampler;
1246
+ return id;
1247
+ },
1248
+ DeleteSampler: (id) => {
1249
+ this.assertWebGL2();
1250
+ let obj = this.samplers[id];
1251
+ if (obj && id != 0) {
1252
+ this.ctx.deleteSampler(obj);
1253
+ this.samplers[id] = null;
1254
+ }
1255
+ },
1256
+ IsSampler: (sampler) => {
1257
+ this.assertWebGL2();
1258
+ return this.ctx.isSampler(this.samplers[sampler]);
1259
+ },
1260
+ BindSampler: (unit, sampler) => {
1261
+ this.assertWebGL2();
1262
+ this.ctx.bindSampler(unit, this.samplers[sampler]);
1263
+ },
1264
+ SamplerParameteri: (sampler, pname, param) => {
1265
+ this.assertWebGL2();
1266
+ this.ctx.samplerParameteri(this.samplers[sampler], pname, param);
1267
+ },
1268
+ SamplerParameterf: (sampler, pname, param) => {
1269
+ this.assertWebGL2();
1270
+ this.ctx.samplerParameterf(this.samplers[sampler], pname, param);
1271
+ },
1272
+
1273
+ /* Sync objects */
1274
+ FenceSync: (condition, flags) => {
1275
+ this.assertWebGL2();
1276
+ let sync = this.ctx.fenceSync(condition, flags);
1277
+ let id = this.getNewId(this.syncs);
1278
+ sync.name = id;
1279
+ this.syncs[id] = sync;
1280
+ return id;
1281
+ },
1282
+ IsSync: (sync) => {
1283
+ this.assertWebGL2();
1284
+ return this.ctx.isSync(this.syncs[sync]);
1285
+ },
1286
+ DeleteSync: (id) => {
1287
+ this.assertWebGL2();
1288
+ let obj = this.syncs[id];
1289
+ if (obj && id != 0) {
1290
+ this.ctx.deleteSampler(obj);
1291
+ this.syncs[id] = null;
1292
+ }
1293
+ },
1294
+ ClientWaitSync: (sync, flags, timeout) => {
1295
+ this.assertWebGL2();
1296
+ return this.ctx.clientWaitSync(this.syncs[sync], flags, timeout);
1297
+ },
1298
+ WaitSync: (sync, flags, timeout) => {
1299
+ this.assertWebGL2();
1300
+ this.ctx.waitSync(this.syncs[sync], flags, timeout) ;
1301
+ },
1302
+
1303
+
1304
+ /* Transform Feedback */
1305
+ CreateTransformFeedback: () => {
1306
+ this.assertWebGL2();
1307
+ let transformFeedback = this.ctx.createTransformFeedback();
1308
+ let id = this.getNewId(this.transformFeedbacks);
1309
+ transformFeedback.name = id;
1310
+ this.transformFeedbacks[id] = transformFeedback;
1311
+ return id;
1312
+ },
1313
+ DeleteTransformFeedback: (id) => {
1314
+ this.assertWebGL2();
1315
+ let obj = this.transformFeedbacks[id];
1316
+ if (obj && id != 0) {
1317
+ this.ctx.deleteTransformFeedback(obj);
1318
+ this.transformFeedbacks[id] = null;
1319
+ }
1320
+ },
1321
+ IsTransformFeedback: (tf) => {
1322
+ this.assertWebGL2();
1323
+ return this.ctx.isTransformFeedback(this.transformFeedbacks[tf]);
1324
+ },
1325
+ BindTransformFeedback: (target, tf) => {
1326
+ this.assertWebGL2();
1327
+ this.ctx.bindTransformFeedback(target, this.transformFeedbacks[tf]);
1328
+ },
1329
+ BeginTransformFeedback: (primitiveMode) => {
1330
+ this.assertWebGL2();
1331
+ this.ctx.beginTransformFeedback(primitiveMode);
1332
+ },
1333
+ EndTransformFeedback: () => {
1334
+ this.assertWebGL2();
1335
+ this.ctx.endTransformFeedback();
1336
+ },
1337
+ TransformFeedbackVaryings: (program, varyings_ptr, varyings_len, bufferMode) => {
1338
+ this.assertWebGL2();
1339
+ const stringSize = this.mem.intSize*2;
1340
+ let varyings = [];
1341
+ for (let i = 0; i < varyings_len; i++) {
1342
+ let ptr = this.mem.loadPtr(varyings_ptr + i*stringSize + 0*4);
1343
+ let len = this.mem.loadPtr(varyings_ptr + i*stringSize + 1*4);
1344
+ varyings.push(this.mem.loadString(ptr, len));
1345
+ }
1346
+ this.ctx.transformFeedbackVaryings(this.programs[program], varyings, bufferMode);
1347
+ },
1348
+ PauseTransformFeedback: () => {
1349
+ this.assertWebGL2();
1350
+ this.ctx.pauseTransformFeedback();
1351
+ },
1352
+ ResumeTransformFeedback: () => {
1353
+ this.assertWebGL2();
1354
+ this.ctx.resumeTransformFeedback();
1355
+ },
1356
+
1357
+
1358
+ /* Uniform Buffer Objects and Transform Feedback Buffers */
1359
+ BindBufferBase: (target, index, buffer) => {
1360
+ this.assertWebGL2();
1361
+ this.ctx.bindBufferBase(target, index, this.buffers[buffer]);
1362
+ },
1363
+ BindBufferRange: (target, index, buffer, offset, size) => {
1364
+ this.assertWebGL2();
1365
+ this.ctx.bindBufferRange(target, index, this.buffers[buffer], offset, size);
1366
+ },
1367
+ GetUniformBlockIndex: (program, uniformBlockName_ptr, uniformBlockName_len) => {
1368
+ this.assertWebGL2();
1369
+ return this.ctx.getUniformBlockIndex(this.programs[program], this.mem.loadString(uniformBlockName_ptr, uniformBlockName_len));
1370
+ },
1371
+ GetActiveUniformBlockName: (program, uniformBlockIndex, name_buf_ptr, name_buf_len, name_length_ptr) => {
1372
+ this.assertWebGL2();
1373
+ let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex);
1374
+
1375
+ if (name_buf_ptr && name_buf_len > 0) {
1376
+ let n = Math.min(name_buf_len, name.length);
1377
+ name = name.substring(0, n);
1378
+ this.mem.loadBytes(name_buf_ptr, name_buf_len).set(new TextEncoder().encode(name));
1379
+ this.mem.storeInt(name_length_ptr, n);
1380
+ } else if (name_length_ptr) {
1381
+ this.mem.storeInt(name_length_ptr, name.length);
1382
+ }
1383
+ },
1384
+ GetActiveUniforms: (program, uniformIndices_ptr, uniformIndices_len, pname, res_ptr) => {
1385
+ this.assertWebGL2();
1386
+ let indices = this.mem.loadU32Array(uniformIndices_ptr, uniformIndices_len);
1387
+ this.ctx.getActiveUniforms(this.programs[program], indices, pname)
1388
+ this.mem.loadI32Array(res_ptr, indices.length).set(indices)
1389
+ },
1390
+ GetActiveUniformBlockParameter: (program, uniformBlockIndex, pname, params_ptr) => {
1391
+ this.assertWebGL2();
1392
+ let res = this.ctx.getActiveUniformBlockParameter(this.programs[program], uniformBlockIndex, pname);
1393
+
1394
+ if (res instanceof Uint32Array) { // for pname GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
1395
+ this.mem.loadU32Array(params_ptr, res.length).set(res)
1396
+ } else {
1397
+ this.mem.storeI32(params_ptr, res)
1398
+ }
1399
+ },
1400
+ UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => {
1401
+ this.assertWebGL2();
1402
+ this.ctx.uniformBlockBinding(this.programs[program], uniformBlockIndex, uniformBlockBinding);
1403
+ },
1404
+
1405
+ /* Vertex Array Objects */
1406
+ CreateVertexArray: () => {
1407
+ this.assertWebGL2();
1408
+ let vao = this.ctx.createVertexArray();
1409
+ let id = this.getNewId(this.vaos);
1410
+ vao.name = id;
1411
+ this.vaos[id] = vao;
1412
+ return id;
1413
+ },
1414
+ DeleteVertexArray: (id) => {
1415
+ this.assertWebGL2();
1416
+ let obj = this.vaos[id];
1417
+ if (obj && id != 0) {
1418
+ this.ctx.deleteVertexArray(obj);
1419
+ this.vaos[id] = null;
1420
+ }
1421
+ },
1422
+ IsVertexArray: (vertexArray) => {
1423
+ this.assertWebGL2();
1424
+ return this.ctx.isVertexArray(this.vaos[vertexArray]);
1425
+ },
1426
+ BindVertexArray: (vertexArray) => {
1427
+ this.assertWebGL2();
1428
+ this.ctx.bindVertexArray(this.vaos[vertexArray]);
1429
+ },
1430
+ };
1431
+ }
1432
+ };
1433
+
1434
+
1435
+ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
1436
+ const MAX_INFO_CONSOLE_LINES = 512;
1437
+ let infoConsoleLines = new Array();
1438
+ let currentLine = {};
1439
+ currentLine[false] = "";
1440
+ currentLine[true] = "";
1441
+ let prevIsError = false;
1442
+
1443
+ let event_temp = {};
1444
+
1445
+ const onEventReceived = (event_data, data, callback) => {
1446
+ event_temp.data = event_data;
1447
+
1448
+ const exports = wasmMemoryInterface.exports;
1449
+ const odin_ctx = exports.default_context_ptr();
1450
+
1451
+ exports.odin_dom_do_event_callback(data, callback, odin_ctx);
1452
+
1453
+ event_temp.data = null;
1454
+ };
1455
+
1456
+ const writeToConsole = (line, isError) => {
1457
+ if (!line) {
1458
+ return;
1459
+ }
1460
+
1461
+ const println = (text, forceIsError) => {
1462
+ let style = [
1463
+ "color: #eee",
1464
+ "background-color: #d20",
1465
+ "padding: 2px 4px",
1466
+ "border-radius: 2px",
1467
+ ].join(";");
1468
+ let doIsError = isError;
1469
+ if (forceIsError !== undefined) {
1470
+ doIsError = forceIsError;
1471
+ }
1472
+
1473
+ if (doIsError) {
1474
+ console.log("%c"+text, style);
1475
+ } else {
1476
+ console.log(text);
1477
+ }
1478
+
1479
+ };
1480
+
1481
+ // Print to console
1482
+ if (line == "\n") {
1483
+ println(currentLine[isError]);
1484
+ currentLine[isError] = "";
1485
+ } else if (!line.includes("\n")) {
1486
+ currentLine[isError] = currentLine[isError].concat(line);
1487
+ } else {
1488
+ let lines = line.trimEnd().split("\n");
1489
+ let printLast = lines.length > 1 && line.endsWith("\n");
1490
+ println(currentLine[isError].concat(lines[0]));
1491
+ currentLine[isError] = "";
1492
+ for (let i = 1; i < lines.length-1; i++) {
1493
+ println(lines[i]);
1494
+ }
1495
+ if (lines.length > 1) {
1496
+ let last = lines[lines.length-1];
1497
+ if (printLast) {
1498
+ println(last);
1499
+ } else {
1500
+ currentLine[isError] = last;
1501
+ }
1502
+ }
1503
+ }
1504
+
1505
+ if (prevIsError != isError) {
1506
+ if (prevIsError) {
1507
+ println(currentLine[prevIsError], prevIsError);
1508
+ currentLine[prevIsError] = "";
1509
+ }
1510
+ }
1511
+ prevIsError = isError;
1512
+
1513
+
1514
+ // HTML based console
1515
+ if (!consoleElement) {
1516
+ return;
1517
+ }
1518
+ const wrap = (x) => {
1519
+ if (isError) {
1520
+ return '<span style="color:#f21">'+x+'</span>';
1521
+ }
1522
+ return x;
1523
+ };
1524
+
1525
+ if (line == "\n") {
1526
+ infoConsoleLines.push(line);
1527
+ } else if (!line.includes("\n")) {
1528
+ let prevLine = "";
1529
+ if (infoConsoleLines.length > 0) {
1530
+ prevLine = infoConsoleLines.pop();
1531
+ }
1532
+ infoConsoleLines.push(prevLine.concat(wrap(line)));
1533
+ } else {
1534
+ let lines = line.split("\n");
1535
+ let lastHasNewline = lines.length > 1 && line.endsWith("\n");
1536
+
1537
+ let prevLine = "";
1538
+ if (infoConsoleLines.length > 0) {
1539
+ prevLine = infoConsoleLines.pop();
1540
+ }
1541
+ infoConsoleLines.push(prevLine.concat(wrap(lines[0]).concat("\n")));
1542
+
1543
+ for (let i = 1; i < lines.length-1; i++) {
1544
+ infoConsoleLines.push(wrap(lines[i]).concat("\n"));
1545
+ }
1546
+ let last = lines[lines.length-1];
1547
+ if (lastHasNewline) {
1548
+ infoConsoleLines.push(last.concat("\n"));
1549
+ } else {
1550
+ infoConsoleLines.push(last);
1551
+ }
1552
+ }
1553
+
1554
+ if (infoConsoleLines.length > MAX_INFO_CONSOLE_LINES) {
1555
+ infoConsoleLines.shift(MAX_INFO_CONSOLE_LINES);
1556
+ }
1557
+
1558
+ let data = "";
1559
+ for (let i = 0; i < infoConsoleLines.length; i++) {
1560
+ data = data.concat(infoConsoleLines[i]);
1561
+ }
1562
+
1563
+ let info = consoleElement;
1564
+ info.innerHTML = data;
1565
+ info.scrollTop = info.scrollHeight;
1566
+ };
1567
+
1568
+ const listener_key = (id, name, data, callback, useCapture) => {
1569
+ return `${id}-${name}-data:${data}-callback:${callback}-useCapture:${useCapture}`;
1570
+ };
1571
+
1572
+ let webglContext = new WebGLInterface(wasmMemoryInterface);
1573
+
1574
+ const env = {};
1575
+
1576
+ if (memory) {
1577
+ env.memory = memory;
1578
+ }
1579
+
1580
+ return {
1581
+ env,
1582
+ "odin_env": {
1583
+ write: (fd, ptr, len) => {
1584
+ const str = wasmMemoryInterface.loadString(ptr, len);
1585
+ if (fd == 1) {
1586
+ writeToConsole(str, false);
1587
+ return;
1588
+ } else if (fd == 2) {
1589
+ writeToConsole(str, true);
1590
+ return;
1591
+ } else {
1592
+ throw new Error("Invalid fd to 'write'" + stripNewline(str));
1593
+ }
1594
+ },
1595
+ trap: () => { throw new Error() },
1596
+ alert: (ptr, len) => { alert(wasmMemoryInterface.loadString(ptr, len)) },
1597
+ abort: () => { Module.abort() },
1598
+ evaluate: (str_ptr, str_len) => { eval.call(null, wasmMemoryInterface.loadString(str_ptr, str_len)); },
1599
+
1600
+ open: (url_ptr, url_len, name_ptr, name_len, specs_ptr, specs_len) => {
1601
+ const url = wasmMemoryInterface.loadString(url_ptr, url_len);
1602
+ const name = wasmMemoryInterface.loadString(name_ptr, name_len);
1603
+ const specs = wasmMemoryInterface.loadString(specs_ptr, specs_len);
1604
+ window.open(url, name, specs);
1605
+ },
1606
+
1607
+ // return a bigint to be converted to i64
1608
+ time_now: () => BigInt(Date.now()),
1609
+ tick_now: () => performance.now(),
1610
+ time_sleep: (duration_ms) => {
1611
+ if (duration_ms > 0) {
1612
+ // TODO(bill): Does this even make any sense?
1613
+ }
1614
+ },
1615
+
1616
+ sqrt: Math.sqrt,
1617
+ sin: Math.sin,
1618
+ cos: Math.cos,
1619
+ pow: Math.pow,
1620
+ fmuladd: (x, y, z) => x*y + z,
1621
+ ln: Math.log,
1622
+ exp: Math.exp,
1623
+ ldexp: (x, exp) => x * Math.pow(2, exp),
1624
+
1625
+ rand_bytes: (ptr, len) => {
1626
+ const view = new Uint8Array(wasmMemoryInterface.memory.buffer, ptr, len)
1627
+ if (wasmMemoryInterface.isShared) {
1628
+ const tmp = new Uint8Array(len)
1629
+ crypto.getRandomValues(tmp)
1630
+ view.set(tmp)
1631
+ return
1632
+ }
1633
+ crypto.getRandomValues(view)
1634
+ },
1635
+ },
1636
+ "odin_dom": {
1637
+ init_event_raw: (ep) => {
1638
+ const W = wasmMemoryInterface.intSize;
1639
+ let offset = ep;
1640
+ let off = (amount, alignment) => {
1641
+ if (alignment === undefined) {
1642
+ alignment = Math.min(amount, W);
1643
+ }
1644
+ if (offset % alignment != 0) {
1645
+ offset += alignment - (offset%alignment);
1646
+ }
1647
+ let x = offset;
1648
+ offset += amount;
1649
+ return x;
1650
+ };
1651
+
1652
+ let align = (alignment) => {
1653
+ const modulo = offset & (alignment-1);
1654
+ if (modulo != 0) {
1655
+ offset += alignment - modulo
1656
+ }
1657
+ };
1658
+
1659
+ let wmi = wasmMemoryInterface;
1660
+
1661
+ if (!event_temp.data) {
1662
+ return;
1663
+ }
1664
+
1665
+ let e = event_temp.data.event;
1666
+
1667
+ wmi.storeU32(off(4), event_temp.data.name_code);
1668
+ if (e.target == document) {
1669
+ wmi.storeU32(off(4), 1);
1670
+ } else if (e.target == window) {
1671
+ wmi.storeU32(off(4), 2);
1672
+ } else {
1673
+ wmi.storeU32(off(4), 0);
1674
+ }
1675
+ if (e.currentTarget == document) {
1676
+ wmi.storeU32(off(4), 1);
1677
+ } else if (e.currentTarget == window) {
1678
+ wmi.storeU32(off(4), 2);
1679
+ } else {
1680
+ wmi.storeU32(off(4), 0);
1681
+ }
1682
+
1683
+ align(W);
1684
+
1685
+ wmi.storeI32(off(W), event_temp.data.id_ptr);
1686
+ wmi.storeUint(off(W), event_temp.data.id_len);
1687
+
1688
+ align(8);
1689
+ wmi.storeF64(off(8), e.timeStamp*1e-3);
1690
+
1691
+ wmi.storeU8(off(1), e.eventPhase);
1692
+ let options = 0;
1693
+ if (!!e.bubbles) { options |= 1<<0; }
1694
+ if (!!e.cancelable) { options |= 1<<1; }
1695
+ if (!!e.composed) { options |= 1<<2; }
1696
+ wmi.storeU8(off(1), options);
1697
+ wmi.storeU8(off(1), !!e.isComposing);
1698
+ wmi.storeU8(off(1), !!e.isTrusted);
1699
+
1700
+ align(8);
1701
+ if (e instanceof WheelEvent) {
1702
+ wmi.storeF64(off(8), e.deltaX);
1703
+ wmi.storeF64(off(8), e.deltaY);
1704
+ wmi.storeF64(off(8), e.deltaZ);
1705
+ wmi.storeU32(off(4), e.deltaMode);
1706
+ } else if (e instanceof MouseEvent) {
1707
+ wmi.storeI64(off(8), e.screenX);
1708
+ wmi.storeI64(off(8), e.screenY);
1709
+ wmi.storeI64(off(8), e.clientX);
1710
+ wmi.storeI64(off(8), e.clientY);
1711
+ wmi.storeI64(off(8), e.offsetX);
1712
+ wmi.storeI64(off(8), e.offsetY);
1713
+ wmi.storeI64(off(8), e.pageX);
1714
+ wmi.storeI64(off(8), e.pageY);
1715
+ wmi.storeI64(off(8), e.movementX);
1716
+ wmi.storeI64(off(8), e.movementY);
1717
+
1718
+ wmi.storeU8(off(1), !!e.ctrlKey);
1719
+ wmi.storeU8(off(1), !!e.shiftKey);
1720
+ wmi.storeU8(off(1), !!e.altKey);
1721
+ wmi.storeU8(off(1), !!e.metaKey);
1722
+
1723
+ wmi.storeI16(off(2), e.button);
1724
+ wmi.storeU16(off(2), e.buttons);
1725
+
1726
+ if (e instanceof PointerEvent) {
1727
+ wmi.storeF64(off(8), e.altitudeAngle);
1728
+ wmi.storeF64(off(8), e.azimuthAngle);
1729
+ wmi.storeInt(off(W), e.persistentDeviceId);
1730
+ wmi.storeInt(off(W), e.pointerId);
1731
+ wmi.storeInt(off(W), e.width);
1732
+ wmi.storeInt(off(W), e.height);
1733
+ wmi.storeF64(off(8), e.pressure);
1734
+ wmi.storeF64(off(8), e.tangentialPressure);
1735
+ wmi.storeF64(off(8), e.tiltX);
1736
+ wmi.storeF64(off(8), e.tiltY);
1737
+ wmi.storeF64(off(8), e.twist);
1738
+ if (e.pointerType == "pen") {
1739
+ wmi.storeU8(off(1), 1);
1740
+ } else if (e.pointerType == "touch") {
1741
+ wmi.storeU8(off(1), 2);
1742
+ } else {
1743
+ wmi.storeU8(off(1), 0);
1744
+ }
1745
+ wmi.storeU8(off(1), !!e.isPrimary);
1746
+ }
1747
+
1748
+ } else if (e instanceof KeyboardEvent) {
1749
+ // Note: those strings are constructed
1750
+ // on the native side from buffers that
1751
+ // are filled later, so skip them
1752
+ const keyPtr = off(W*2, W);
1753
+ const codePtr = off(W*2, W);
1754
+
1755
+ wmi.storeU8(off(1), e.location);
1756
+
1757
+ wmi.storeU8(off(1), !!e.ctrlKey);
1758
+ wmi.storeU8(off(1), !!e.shiftKey);
1759
+ wmi.storeU8(off(1), !!e.altKey);
1760
+ wmi.storeU8(off(1), !!e.metaKey);
1761
+
1762
+ wmi.storeU8(off(1), !!e.repeat);
1763
+
1764
+ wmi.storeI32(off(4), e.charCode);
1765
+
1766
+ wmi.storeInt(off(W, W), e.key.length)
1767
+ wmi.storeInt(off(W, W), e.code.length)
1768
+ wmi.storeString(off(32, 1), e.key);
1769
+ wmi.storeString(off(32, 1), e.code);
1770
+ } else if (e.type === 'scroll') {
1771
+ wmi.storeF64(off(8, 8), window.scrollX);
1772
+ wmi.storeF64(off(8, 8), window.scrollY);
1773
+ } else if (e.type === 'visibilitychange') {
1774
+ wmi.storeU8(off(1), !document.hidden);
1775
+ } else if (e instanceof GamepadEvent) {
1776
+ const idPtr = off(W*2, W);
1777
+ const mappingPtr = off(W*2, W);
1778
+
1779
+ wmi.storeI32(off(W, W), e.gamepad.index);
1780
+ wmi.storeU8(off(1), !!e.gamepad.connected);
1781
+ wmi.storeF64(off(8, 8), e.gamepad.timestamp);
1782
+
1783
+ wmi.storeInt(off(W, W), e.gamepad.buttons.length);
1784
+ wmi.storeInt(off(W, W), e.gamepad.axes.length);
1785
+
1786
+ for (let i = 0; i < 64; i++) {
1787
+ if (i < e.gamepad.buttons.length) {
1788
+ let b = e.gamepad.buttons[i];
1789
+ wmi.storeF64(off(8, 8), b.value);
1790
+ wmi.storeU8(off(1), !!b.pressed);
1791
+ wmi.storeU8(off(1), !!b.touched);
1792
+ } else {
1793
+ off(16, 8);
1794
+ }
1795
+ }
1796
+ for (let i = 0; i < 16; i++) {
1797
+ if (i < e.gamepad.axes.length) {
1798
+ let a = e.gamepad.axes[i];
1799
+ wmi.storeF64(off(8, 8), a);
1800
+ } else {
1801
+ off(8, 8);
1802
+ }
1803
+ }
1804
+
1805
+ let idLength = e.gamepad.id.length;
1806
+ let id = e.gamepad.id;
1807
+ if (idLength > 96) {
1808
+ idLength = 96;
1809
+ id = id.slice(0, 93) + '...';
1810
+ }
1811
+
1812
+ let mappingLength = e.gamepad.mapping.length;
1813
+ let mapping = e.gamepad.mapping;
1814
+ if (mappingLength > 64) {
1815
+ mappingLength = 61;
1816
+ mapping = mapping.slice(0, 61) + '...';
1817
+ }
1818
+
1819
+ wmi.storeInt(off(W, W), idLength);
1820
+ wmi.storeInt(off(W, W), mappingLength);
1821
+ wmi.storeString(off(96, 1), id);
1822
+ wmi.storeString(off(64, 1), mapping);
1823
+ }
1824
+ },
1825
+
1826
+ add_event_listener: (id_ptr, id_len, name_ptr, name_len, name_code, data, callback, use_capture) => {
1827
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
1828
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1829
+ let element = getElement(id);
1830
+ if (element == undefined) {
1831
+ return false;
1832
+ }
1833
+ let key = listener_key(id, name, data, callback, !!use_capture);
1834
+ if (wasmMemoryInterface.listenerMap.has(key)) {
1835
+ return false;
1836
+ }
1837
+
1838
+ let listener = (e) => {
1839
+ let event_data = {};
1840
+ event_data.id_ptr = id_ptr;
1841
+ event_data.id_len = id_len;
1842
+ event_data.event = e;
1843
+ event_data.name_code = name_code;
1844
+
1845
+ onEventReceived(event_data, data, callback);
1846
+ };
1847
+ wasmMemoryInterface.listenerMap.set(key, listener);
1848
+ element.addEventListener(name, listener, !!use_capture);
1849
+ return true;
1850
+ },
1851
+
1852
+ add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
1853
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1854
+ let element = window;
1855
+ let key = listener_key('window', name, data, callback, !!use_capture);
1856
+ if (wasmMemoryInterface.listenerMap.has(key)) {
1857
+ return false;
1858
+ }
1859
+
1860
+ let listener = (e) => {
1861
+ let event_data = {};
1862
+ event_data.id_ptr = 0;
1863
+ event_data.id_len = 0;
1864
+ event_data.event = e;
1865
+ event_data.name_code = name_code;
1866
+
1867
+ onEventReceived(event_data, data, callback);
1868
+ };
1869
+ wasmMemoryInterface.listenerMap.set(key, listener);
1870
+ element.addEventListener(name, listener, !!use_capture);
1871
+ return true;
1872
+ },
1873
+
1874
+ add_document_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
1875
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1876
+ let element = document;
1877
+ let key = listener_key('document', name, data, callback, !!use_capture);
1878
+ if (wasmMemoryInterface.listenerMap.has(key)) {
1879
+ return false;
1880
+ }
1881
+
1882
+ let listener = (e) => {
1883
+ let event_data = {};
1884
+ event_data.id_ptr = 0;
1885
+ event_data.id_len = 0;
1886
+ event_data.event = e;
1887
+ event_data.name_code = name_code;
1888
+
1889
+ onEventReceived(event_data, data, callback);
1890
+ };
1891
+ wasmMemoryInterface.listenerMap.set(key, listener);
1892
+ element.addEventListener(name, listener, !!use_capture);
1893
+ return true;
1894
+ },
1895
+
1896
+ remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback, use_capture) => {
1897
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
1898
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1899
+ let element = getElement(id);
1900
+ if (element == undefined) {
1901
+ return false;
1902
+ }
1903
+
1904
+ let key = listener_key(id, name, data, callback, !!use_capture);
1905
+ let listener = wasmMemoryInterface.listenerMap.get(key);
1906
+ if (listener === undefined) {
1907
+ return false;
1908
+ }
1909
+ wasmMemoryInterface.listenerMap.delete(key);
1910
+
1911
+ element.removeEventListener(name, listener, !!use_capture);
1912
+ return true;
1913
+ },
1914
+ remove_window_event_listener: (name_ptr, name_len, data, callback, use_capture) => {
1915
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1916
+ let element = window;
1917
+
1918
+ let key = listener_key('window', name, data, callback, !!use_capture);
1919
+ let listener = wasmMemoryInterface.listenerMap.get(key);
1920
+ if (listener === undefined) {
1921
+ return false;
1922
+ }
1923
+ wasmMemoryInterface.listenerMap.delete(key);
1924
+
1925
+ element.removeEventListener(name, listener, !!use_capture);
1926
+ return true;
1927
+ },
1928
+ remove_document_event_listener: (name_ptr, name_len, data, callback, use_capture) => {
1929
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1930
+ let element = document;
1931
+
1932
+ let key = listener_key('document', name, data, callback, !!use_capture);
1933
+ let listener = wasmMemoryInterface.listenerMap.get(key);
1934
+ if (listener === undefined) {
1935
+ return false;
1936
+ }
1937
+ wasmMemoryInterface.listenerMap.delete(key);
1938
+
1939
+ element.removeEventListener(name, listener, !!use_capture);
1940
+ return true;
1941
+ },
1942
+
1943
+ event_stop_propagation: () => {
1944
+ if (event_temp.data && event_temp.data.event) {
1945
+ event_temp.data.event.stopPropagation();
1946
+ }
1947
+ },
1948
+ event_stop_immediate_propagation: () => {
1949
+ if (event_temp.data && event_temp.data.event) {
1950
+ event_temp.data.event.stopImmediatePropagation();
1951
+ }
1952
+ },
1953
+ event_prevent_default: () => {
1954
+ if (event_temp.data && event_temp.data.event) {
1955
+ event_temp.data.event.preventDefault();
1956
+ }
1957
+ },
1958
+
1959
+ dispatch_custom_event: (id_ptr, id_len, name_ptr, name_len, options_bits) => {
1960
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
1961
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
1962
+ let options = {
1963
+ bubbles: (options_bits & (1<<0)) !== 0,
1964
+ cancelable: (options_bits & (1<<1)) !== 0,
1965
+ composed: (options_bits & (1<<2)) !== 0,
1966
+ };
1967
+
1968
+ let element = getElement(id);
1969
+ if (element) {
1970
+ element.dispatchEvent(new Event(name, options));
1971
+ return true;
1972
+ }
1973
+ return false;
1974
+ },
1975
+
1976
+ // Writes a struct of type `Gamepad_State`, see `core/sys/wasm/js/events.odin`
1977
+ get_gamepad_state: (gamepad_id, ep) => {
1978
+ let index = gamepad_id;
1979
+ let gps = navigator.getGamepads();
1980
+ if (0 <= index && index < gps.length) {
1981
+ let gamepad = gps[index];
1982
+ if (!gamepad) {
1983
+ return false;
1984
+ }
1985
+
1986
+ const W = wasmMemoryInterface.intSize;
1987
+ let offset = ep;
1988
+ let off = (amount, alignment) => {
1989
+ if (alignment === undefined) {
1990
+ alignment = Math.min(amount, W);
1991
+ }
1992
+ if (offset % alignment != 0) {
1993
+ offset += alignment - (offset%alignment);
1994
+ }
1995
+ let x = offset;
1996
+ offset += amount;
1997
+ return x;
1998
+ };
1999
+
2000
+ let align = (alignment) => {
2001
+ const modulo = offset & (alignment-1);
2002
+ if (modulo != 0) {
2003
+ offset += alignment - modulo
2004
+ }
2005
+ };
2006
+
2007
+ let wmi = wasmMemoryInterface;
2008
+
2009
+ const idPtr = off(W*2, W);
2010
+ const mappingPtr = off(W*2, W);
2011
+
2012
+ wmi.storeI32(off(W), gamepad.index);
2013
+ wmi.storeU8(off(1), !!gamepad.connected);
2014
+ wmi.storeF64(off(8), gamepad.timestamp);
2015
+
2016
+ wmi.storeInt(off(W), gamepad.buttons.length);
2017
+ wmi.storeInt(off(W), gamepad.axes.length);
2018
+
2019
+ for (let i = 0; i < 64; i++) {
2020
+ if (i < gamepad.buttons.length) {
2021
+ let b = gamepad.buttons[i];
2022
+ wmi.storeF64(off(8, 8), b.value);
2023
+ wmi.storeU8(off(1), !!b.pressed);
2024
+ wmi.storeU8(off(1), !!b.touched);
2025
+ } else {
2026
+ off(16, 8);
2027
+ }
2028
+ }
2029
+ for (let i = 0; i < 16; i++) {
2030
+ if (i < gamepad.axes.length) {
2031
+ wmi.storeF64(off(8, 8), gamepad.axes[i]);
2032
+ } else {
2033
+ off(8, 8);
2034
+ }
2035
+ }
2036
+
2037
+ let idLength = gamepad.id.length;
2038
+ let id = gamepad.id;
2039
+ if (idLength > 96) {
2040
+ idLength = 96;
2041
+ id = id.slice(0, 93) + '...';
2042
+ }
2043
+
2044
+ let mappingLength = gamepad.mapping.length;
2045
+ let mapping = gamepad.mapping;
2046
+ if (mappingLength > 64) {
2047
+ mappingLength = 61;
2048
+ mapping = mapping.slice(0, 61) + '...';
2049
+ }
2050
+
2051
+ wmi.storeInt(off(W, W), idLength);
2052
+ wmi.storeInt(off(W, W), mappingLength);
2053
+ wmi.storeString(off(96, 1), id);
2054
+ wmi.storeString(off(64, 1), mapping);
2055
+
2056
+ return true;
2057
+ }
2058
+ return false;
2059
+ },
2060
+
2061
+ get_element_value_f64: (id_ptr, id_len) => {
2062
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2063
+ let element = getElement(id);
2064
+ return element ? element.value : 0;
2065
+ },
2066
+ get_element_value_string: (id_ptr, id_len, buf_ptr, buf_len) => {
2067
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2068
+ let element = getElement(id);
2069
+ if (element) {
2070
+ let str = element.value;
2071
+ if (buf_len > 0 && buf_ptr) {
2072
+ let n = Math.min(buf_len, str.length);
2073
+ str = str.substring(0, n);
2074
+ wasmMemoryInterface.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str))
2075
+ return n;
2076
+ }
2077
+ }
2078
+ return 0;
2079
+ },
2080
+ get_element_value_string_length: (id_ptr, id_len) => {
2081
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2082
+ let element = getElement(id);
2083
+ if (element) {
2084
+ return element.value.length;
2085
+ }
2086
+ return 0;
2087
+ },
2088
+ get_element_min_max: (ptr_array2_f64, id_ptr, id_len) => {
2089
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2090
+ let element = getElement(id);
2091
+ if (element) {
2092
+ let values = wasmMemoryInterface.loadF64Array(ptr_array2_f64, 2);
2093
+ values[0] = element.min;
2094
+ values[1] = element.max;
2095
+ }
2096
+ },
2097
+ set_element_value_f64: (id_ptr, id_len, value) => {
2098
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2099
+ let element = getElement(id);
2100
+ if (element) {
2101
+ element.value = value;
2102
+ }
2103
+ },
2104
+ set_element_value_string: (id_ptr, id_len, value_ptr, value_len) => {
2105
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2106
+ let value = wasmMemoryInterface.loadString(value_ptr, value_len);
2107
+ let element = getElement(id);
2108
+ if (element) {
2109
+ element.value = value;
2110
+ }
2111
+ },
2112
+
2113
+ set_element_style: (id_ptr, id_len, key_ptr, key_len, value_ptr, value_len) => {
2114
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2115
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
2116
+ let value = wasmMemoryInterface.loadString(value_ptr, value_len);
2117
+ let element = getElement(id);
2118
+ if (element) {
2119
+ element.style[key] = value;
2120
+ }
2121
+ },
2122
+
2123
+ set_document_title: (title_ptr, title_len) => {
2124
+ let title = wasmMemoryInterface.loadString(title_ptr, title_len);
2125
+ document.title = title;
2126
+ },
2127
+
2128
+ get_element_key_f64: (id_ptr, id_len, key_ptr, key_len) => {
2129
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2130
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
2131
+ let element = getElement(id);
2132
+ return element ? element[key] : 0;
2133
+ },
2134
+ get_element_key_string: (id_ptr, id_len, key_ptr, key_len, buf_ptr, buf_len) => {
2135
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2136
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
2137
+ let element = getElement(id);
2138
+ if (element) {
2139
+ let str = element[key];
2140
+ if (buf_len > 0 && buf_ptr) {
2141
+ let n = Math.min(buf_len, str.length);
2142
+ str = str.substring(0, n);
2143
+ wasmMemoryInterface.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str))
2144
+ return n;
2145
+ }
2146
+ }
2147
+ return 0;
2148
+ },
2149
+ get_element_key_string_length: (id_ptr, id_len, key_ptr, key_len) => {
2150
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2151
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
2152
+ let element = getElement(id);
2153
+ if (element && element[key]) {
2154
+ return element[key].length;
2155
+ }
2156
+ return 0;
2157
+ },
2158
+
2159
+ set_element_key_f64: (id_ptr, id_len, key_ptr, key_len, value) => {
2160
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2161
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
2162
+ let element = getElement(id);
2163
+ if (element) {
2164
+ element[key] = value;
2165
+ }
2166
+ },
2167
+ set_element_key_string: (id_ptr, id_len, key_ptr, key_len, value_ptr, value_len) => {
2168
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2169
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
2170
+ let value = wasmMemoryInterface.loadString(value_ptr, value_len);
2171
+ let element = getElement(id);
2172
+ if (element) {
2173
+ element[key] = value;
2174
+ }
2175
+ },
2176
+
2177
+
2178
+ get_bounding_client_rect: (rect_ptr, id_ptr, id_len) => {
2179
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
2180
+ let element = getElement(id);
2181
+ if (element) {
2182
+ let values = wasmMemoryInterface.loadF64Array(rect_ptr, 4);
2183
+ let rect = element.getBoundingClientRect();
2184
+ values[0] = rect.left;
2185
+ values[1] = rect.top;
2186
+ values[2] = rect.right - rect.left;
2187
+ values[3] = rect.bottom - rect.top;
2188
+ }
2189
+ },
2190
+ window_get_rect: (rect_ptr) => {
2191
+ let values = wasmMemoryInterface.loadF64Array(rect_ptr, 4);
2192
+ values[0] = window.screenX;
2193
+ values[1] = window.screenY;
2194
+ values[2] = window.screen.width;
2195
+ values[3] = window.screen.height;
2196
+ },
2197
+
2198
+ window_get_scroll: (pos_ptr) => {
2199
+ let values = wasmMemoryInterface.loadF64Array(pos_ptr, 2);
2200
+ values[0] = window.scrollX;
2201
+ values[1] = window.scrollY;
2202
+ },
2203
+ window_set_scroll: (x, y) => {
2204
+ window.scroll(x, y);
2205
+ },
2206
+
2207
+ device_pixel_ratio: () => {
2208
+ return window.devicePixelRatio;
2209
+ },
2210
+
2211
+ },
2212
+
2213
+ "webgl": webglContext.getWebGL1Interface(),
2214
+ "webgl2": webglContext.getWebGL2Interface(),
2215
+ };
2216
+ };
2217
+
2218
+ /**
2219
+ * @param {string} wasmPath - Path to the WASM module to run
2220
+ * @param {?HTMLPreElement} consoleElement - Optional console/pre element to append output to, in addition to the console
2221
+ * @param {any} extraForeignImports - Imports, in addition to the default runtime to provide the module
2222
+ * @param {?WasmMemoryInterface} wasmMemoryInterface - Optional memory to use instead of the defaults
2223
+ * @param {?int} intSize - Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32`
2224
+ */
2225
+ async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemoryInterface, intSize = 4) {
2226
+ if (!wasmMemoryInterface) {
2227
+ wasmMemoryInterface = new WasmMemoryInterface();
2228
+ }
2229
+ wasmMemoryInterface.setIntSize(intSize);
2230
+
2231
+ let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory);
2232
+ let exports = {};
2233
+
2234
+ if (extraForeignImports !== undefined) {
2235
+ imports = {
2236
+ ...imports,
2237
+ ...extraForeignImports,
2238
+ };
2239
+ }
2240
+
2241
+ const response = await fetch(wasmPath);
2242
+ const file = await response.arrayBuffer();
2243
+ const wasm = await WebAssembly.instantiate(file, imports);
2244
+ exports = wasm.instance.exports;
2245
+ wasmMemoryInterface.setExports(exports);
2246
+
2247
+ if (exports.memory) {
2248
+ if (wasmMemoryInterface.memory) {
2249
+ console.warn('WASM module exports memory, but `runWasm` was given an interface with existing memory too. Did you mean to use `-extra-linker-flags:"--import-memory"` to tell the compiler not to export memory?');
2250
+ }
2251
+ wasmMemoryInterface.setMemory(exports.memory);
2252
+ }
2253
+
2254
+ if (exports._start) {
2255
+ exports._start();
2256
+ }
2257
+
2258
+ // Define a `@export step :: proc(delta_time: f64) -> (keep_going: bool) {`
2259
+ // in your app and it will get called every frame.
2260
+ // return `false` to stop the execution of the module.
2261
+ if (exports.step) {
2262
+ const odin_ctx = exports.default_context_ptr();
2263
+
2264
+ let prevTimeStamp = undefined;
2265
+ function step(currTimeStamp) {
2266
+ if (prevTimeStamp == undefined) {
2267
+ prevTimeStamp = currTimeStamp;
2268
+ }
2269
+
2270
+ const dt = (currTimeStamp - prevTimeStamp)*0.001;
2271
+ prevTimeStamp = currTimeStamp;
2272
+
2273
+ if (!exports.step(dt, odin_ctx)) {
2274
+ if (exports._end) {
2275
+ exports._end();
2276
+ }
2277
+ return;
2278
+ }
2279
+
2280
+ window.requestAnimationFrame(step);
2281
+ }
2282
+
2283
+ window.requestAnimationFrame(step);
2284
+ } else {
2285
+ if (exports._end) {
2286
+ exports._end();
2287
+ }
2288
+ }
2289
+
2290
+ return;
2291
+ };
2292
+
2293
+ window.odin = {
2294
+ // Interface Types
2295
+ WasmMemoryInterface: WasmMemoryInterface,
2296
+ WebGLInterface: WebGLInterface,
2297
+
2298
+ // Functions
2299
+ setupDefaultImports: odinSetupDefaultImports,
2300
+ runWasm: runWasm,
2301
+ };
2302
+ })();