@gjsify/webgl 0.3.12 → 0.3.14

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.
Files changed (55) hide show
  1. package/lib/esm/conformance/attribs.spec.js +312 -293
  2. package/lib/esm/conformance/buffers.spec.js +217 -200
  3. package/lib/esm/conformance/context.spec.js +295 -295
  4. package/lib/esm/conformance/programs.spec.js +458 -445
  5. package/lib/esm/conformance/rendering-basic.spec.js +134 -128
  6. package/lib/esm/conformance/rendering.spec.js +502 -400
  7. package/lib/esm/conformance/setup.js +42 -31
  8. package/lib/esm/conformance/state.spec.js +360 -343
  9. package/lib/esm/conformance/textures.spec.js +330 -338
  10. package/lib/esm/conformance/uniforms.spec.js +465 -309
  11. package/lib/esm/conformance-test.js +24 -22
  12. package/lib/esm/extensions/ext-blend-minmax.js +16 -16
  13. package/lib/esm/extensions/ext-color-buffer-float.js +10 -11
  14. package/lib/esm/extensions/ext-color-buffer-half-float.js +10 -11
  15. package/lib/esm/extensions/ext-texture-filter-anisotropic.js +16 -16
  16. package/lib/esm/extensions/oes-element-index-unit.js +11 -12
  17. package/lib/esm/extensions/oes-standard-derivatives.js +15 -15
  18. package/lib/esm/extensions/oes-texture-float-linear.js +11 -12
  19. package/lib/esm/extensions/oes-texture-float.js +11 -12
  20. package/lib/esm/extensions/oes-texture-half-float.js +17 -17
  21. package/lib/esm/extensions/stackgl-destroy-context.js +10 -10
  22. package/lib/esm/extensions/stackgl-resize-drawing-buffer.js +10 -10
  23. package/lib/esm/html-canvas-element.js +64 -64
  24. package/lib/esm/index.js +29 -26
  25. package/lib/esm/linkable.js +49 -49
  26. package/lib/esm/test-utils.js +158 -107
  27. package/lib/esm/test.js +8 -4
  28. package/lib/esm/types/index.js +5 -5
  29. package/lib/esm/utils.js +164 -187
  30. package/lib/esm/webgl-active-info.js +10 -9
  31. package/lib/esm/webgl-bridge.js +162 -147
  32. package/lib/esm/webgl-buffer.js +17 -15
  33. package/lib/esm/webgl-context-attributes.js +23 -22
  34. package/lib/esm/webgl-context-base.js +3039 -3351
  35. package/lib/esm/webgl-drawing-buffer-wrapper.js +10 -9
  36. package/lib/esm/webgl-framebuffer.js +108 -106
  37. package/lib/esm/webgl-program.js +25 -23
  38. package/lib/esm/webgl-query.js +15 -13
  39. package/lib/esm/webgl-renderbuffer.js +23 -21
  40. package/lib/esm/webgl-rendering-context.js +173 -187
  41. package/lib/esm/webgl-sampler.js +15 -13
  42. package/lib/esm/webgl-shader-precision-format.js +10 -9
  43. package/lib/esm/webgl-shader.js +23 -21
  44. package/lib/esm/webgl-sync.js +15 -13
  45. package/lib/esm/webgl-texture-unit.js +12 -11
  46. package/lib/esm/webgl-texture.js +21 -19
  47. package/lib/esm/webgl-transform-feedback.js +15 -13
  48. package/lib/esm/webgl-uniform-location.js +14 -13
  49. package/lib/esm/webgl-vertex-array-object.js +20 -18
  50. package/lib/esm/webgl-vertex-attribute.js +149 -145
  51. package/lib/esm/webgl1.spec.js +1039 -650
  52. package/lib/esm/webgl2-rendering-context.js +1210 -1273
  53. package/lib/esm/webgl2.spec.js +1284 -1252
  54. package/package.json +9 -9
  55. package/lib/esm/@types/glsl-tokenizer/index.d.js +0 -0
@@ -1,6 +1,8 @@
1
- import { describe, it, expect, beforeEach, on } from "@gjsify/unit";
2
- import { makeProgram, drawTriangle, makeTestFBO, destroyTestFBO } from "../test-utils.js";
1
+ import { destroyTestFBO, drawTriangle, makeProgram, makeTestFBO } from "../test-utils.js";
3
2
  import { createGLSetup } from "./setup.js";
3
+ import { beforeEach, describe, expect, it, on } from "@gjsify/unit";
4
+
5
+ //#region src/ts/conformance/textures.spec.ts
4
6
  const VS_TEX = `
5
7
  precision mediump float;
6
8
  attribute vec2 position;
@@ -15,340 +17,330 @@ const FS_TEX = `
15
17
  varying vec2 vTexCoord;
16
18
  void main() { gl_FragColor = texture2D(uTex, vTexCoord); }`;
17
19
  var textures_spec_default = async () => {
18
- await on("Display", async () => {
19
- const setup = createGLSetup();
20
- if (!setup) {
21
- console.warn("WebGL context not available \u2014 skipping conformance/textures tests");
22
- return;
23
- }
24
- const { gl, glArea } = setup;
25
- glArea.make_current();
26
- await describe("textures/texImage2D-rgba", async () => {
27
- beforeEach(async () => {
28
- glArea.make_current();
29
- });
30
- await it("upload 2\xD72 RGBA Uint8Array and sample it back", async () => {
31
- const W = 2, H = 2;
32
- const fbo = makeTestFBO(gl, W, H);
33
- const data = new Uint8Array([
34
- 255,
35
- 0,
36
- 0,
37
- 255,
38
- // red
39
- 0,
40
- 255,
41
- 0,
42
- 255,
43
- // green
44
- 0,
45
- 0,
46
- 255,
47
- 255,
48
- // blue
49
- 255,
50
- 255,
51
- 0,
52
- 255
53
- // yellow
54
- ]);
55
- const tex = gl.createTexture();
56
- gl.bindTexture(gl.TEXTURE_2D, tex);
57
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
58
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
59
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
60
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
61
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
62
- const prog = makeProgram(gl, VS_TEX, FS_TEX);
63
- gl.useProgram(prog);
64
- gl.uniform1i(gl.getUniformLocation(prog, "uTex"), 0);
65
- drawTriangle(gl);
66
- expect(gl.getError()).toBe(gl.NO_ERROR);
67
- gl.deleteTexture(tex);
68
- destroyTestFBO(gl, fbo);
69
- });
70
- await it("createTexture returns non-null; deleteTexture cleans up", async () => {
71
- const tex = gl.createTexture();
72
- expect(tex).toBeDefined();
73
- gl.bindTexture(gl.TEXTURE_2D, tex);
74
- gl.texImage2D(
75
- gl.TEXTURE_2D,
76
- 0,
77
- gl.RGBA,
78
- 1,
79
- 1,
80
- 0,
81
- gl.RGBA,
82
- gl.UNSIGNED_BYTE,
83
- new Uint8Array([128, 128, 128, 255])
84
- );
85
- expect(gl.getError()).toBe(gl.NO_ERROR);
86
- gl.bindTexture(gl.TEXTURE_2D, null);
87
- gl.deleteTexture(tex);
88
- expect(gl.getError()).toBe(gl.NO_ERROR);
89
- });
90
- });
91
- await describe("textures/alpha-texture", async () => {
92
- beforeEach(async () => {
93
- glArea.make_current();
94
- });
95
- await it("ALPHA format texImage2D: RGB channels zero, alpha matches upload data", async () => {
96
- const W = 4, H = 4;
97
- const fbo = makeTestFBO(gl, W, H);
98
- const data = new Uint8Array(W * H);
99
- for (let i = 0; i < H; i++) {
100
- for (let j = 0; j < W; j++) {
101
- data[i * W + j] = (i + j) % 255;
102
- }
103
- }
104
- const tex = gl.createTexture();
105
- gl.bindTexture(gl.TEXTURE_2D, tex);
106
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
107
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
108
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
109
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
110
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, W, H, 0, gl.ALPHA, gl.UNSIGNED_BYTE, data);
111
- expect(gl.getError()).toBe(gl.NO_ERROR);
112
- gl.clearColor(0, 0, 0, 0);
113
- gl.clear(gl.COLOR_BUFFER_BIT);
114
- const prog = makeProgram(gl, VS_TEX, FS_TEX);
115
- gl.useProgram(prog);
116
- gl.uniform1i(gl.getUniformLocation(prog, "uTex"), 0);
117
- drawTriangle(gl);
118
- expect(gl.getError()).toBe(gl.NO_ERROR);
119
- const pixels = new Uint8Array(W * H * 4);
120
- gl.readPixels(0, 0, W, H, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
121
- let ok = true;
122
- for (let k = 0; k < W * H; k++) {
123
- const i = k * 4;
124
- if (pixels[i] !== 0 || pixels[i + 1] !== 0 || pixels[i + 2] !== 0) {
125
- ok = false;
126
- break;
127
- }
128
- if (Math.abs(pixels[i + 3] - data[k]) > 3) {
129
- ok = false;
130
- break;
131
- }
132
- }
133
- expect(ok).toBe(true);
134
- gl.deleteTexture(tex);
135
- destroyTestFBO(gl, fbo);
136
- });
137
- });
138
- await describe("textures/texSubImage2D", async () => {
139
- beforeEach(async () => {
140
- glArea.make_current();
141
- });
142
- await it("texSubImage2D overwrites a sub-region of an RGBA texture", async () => {
143
- const W = 4, H = 4;
144
- const fbo = makeTestFBO(gl, W, H);
145
- const redData = new Uint8Array(W * H * 4).fill(0);
146
- for (let i = 0; i < W * H; i++) {
147
- redData[i * 4] = 255;
148
- redData[i * 4 + 3] = 255;
149
- }
150
- const tex = gl.createTexture();
151
- gl.bindTexture(gl.TEXTURE_2D, tex);
152
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
153
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
154
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
155
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
156
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, redData);
157
- const greenPatch = new Uint8Array([
158
- 0,
159
- 255,
160
- 0,
161
- 255,
162
- 0,
163
- 255,
164
- 0,
165
- 255,
166
- 0,
167
- 255,
168
- 0,
169
- 255,
170
- 0,
171
- 255,
172
- 0,
173
- 255
174
- ]);
175
- gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, greenPatch);
176
- expect(gl.getError()).toBe(gl.NO_ERROR);
177
- gl.deleteTexture(tex);
178
- destroyTestFBO(gl, fbo);
179
- });
180
- });
181
- await describe("textures/parameters", async () => {
182
- beforeEach(async () => {
183
- glArea.make_current();
184
- });
185
- await it("getTexParameter returns set WRAP and FILTER values", async () => {
186
- const tex = gl.createTexture();
187
- gl.bindTexture(gl.TEXTURE_2D, tex);
188
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
189
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
190
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
191
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
192
- expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)).toBe(gl.CLAMP_TO_EDGE);
193
- expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T)).toBe(gl.REPEAT);
194
- expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)).toBe(gl.LINEAR);
195
- expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER)).toBe(gl.NEAREST);
196
- expect(gl.getError()).toBe(gl.NO_ERROR);
197
- gl.bindTexture(gl.TEXTURE_2D, null);
198
- gl.deleteTexture(tex);
199
- });
200
- await it("MIRRORED_REPEAT wrap mode is accepted", async () => {
201
- const tex = gl.createTexture();
202
- gl.bindTexture(gl.TEXTURE_2D, tex);
203
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
204
- expect(gl.getError()).toBe(gl.NO_ERROR);
205
- expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)).toBe(gl.MIRRORED_REPEAT);
206
- gl.bindTexture(gl.TEXTURE_2D, null);
207
- gl.deleteTexture(tex);
208
- });
209
- await it("LINEAR_MIPMAP_LINEAR min filter is accepted", async () => {
210
- const tex = gl.createTexture();
211
- gl.bindTexture(gl.TEXTURE_2D, tex);
212
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
213
- expect(gl.getError()).toBe(gl.NO_ERROR);
214
- expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)).toBe(gl.LINEAR_MIPMAP_LINEAR);
215
- gl.bindTexture(gl.TEXTURE_2D, null);
216
- gl.deleteTexture(tex);
217
- });
218
- });
219
- await describe("textures/active-texture", async () => {
220
- beforeEach(async () => {
221
- glArea.make_current();
222
- });
223
- await it("activeTexture switches binding slot; each unit holds independent binding", async () => {
224
- const tex0 = gl.createTexture();
225
- const tex1 = gl.createTexture();
226
- gl.activeTexture(gl.TEXTURE0);
227
- gl.bindTexture(gl.TEXTURE_2D, tex0);
228
- gl.activeTexture(gl.TEXTURE1);
229
- gl.bindTexture(gl.TEXTURE_2D, tex1);
230
- gl.activeTexture(gl.TEXTURE0);
231
- expect(gl.getParameter(gl.TEXTURE_BINDING_2D)).toBe(tex0);
232
- gl.activeTexture(gl.TEXTURE1);
233
- expect(gl.getParameter(gl.TEXTURE_BINDING_2D)).toBe(tex1);
234
- expect(gl.getError()).toBe(gl.NO_ERROR);
235
- gl.activeTexture(gl.TEXTURE0);
236
- gl.bindTexture(gl.TEXTURE_2D, null);
237
- gl.activeTexture(gl.TEXTURE1);
238
- gl.bindTexture(gl.TEXTURE_2D, null);
239
- gl.deleteTexture(tex0);
240
- gl.deleteTexture(tex1);
241
- });
242
- await it("getParameter ACTIVE_TEXTURE reflects activeTexture call", async () => {
243
- gl.activeTexture(gl.TEXTURE3);
244
- expect(gl.getParameter(gl.ACTIVE_TEXTURE)).toBe(gl.TEXTURE3);
245
- gl.activeTexture(gl.TEXTURE0);
246
- expect(gl.getParameter(gl.ACTIVE_TEXTURE)).toBe(gl.TEXTURE0);
247
- expect(gl.getError()).toBe(gl.NO_ERROR);
248
- });
249
- });
250
- await describe("textures/cubemap", async () => {
251
- beforeEach(async () => {
252
- glArea.make_current();
253
- });
254
- await it("attach all 6 cubemap faces to FBO \u2014 no GL error", async () => {
255
- const tex = gl.createTexture();
256
- const fb = gl.createFramebuffer();
257
- const whitePixel = new Uint8Array([255, 255, 255, 255]);
258
- gl.activeTexture(gl.TEXTURE1);
259
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
260
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
261
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
262
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
263
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
264
- gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
265
- for (let i = 0; i < 6; i++) {
266
- gl.texImage2D(
267
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
268
- 0,
269
- gl.RGBA,
270
- 1,
271
- 1,
272
- 0,
273
- gl.RGBA,
274
- gl.UNSIGNED_BYTE,
275
- whitePixel
276
- );
277
- gl.framebufferTexture2D(
278
- gl.FRAMEBUFFER,
279
- gl.COLOR_ATTACHMENT0,
280
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
281
- tex,
282
- 0
283
- );
284
- }
285
- expect(gl.getError()).toBe(gl.NO_ERROR);
286
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
287
- gl.activeTexture(gl.TEXTURE1);
288
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
289
- gl.activeTexture(gl.TEXTURE0);
290
- gl.deleteTexture(tex);
291
- gl.deleteFramebuffer(fb);
292
- });
293
- await it("createTexture with TEXTURE_CUBE_MAP binding \u2014 no error", async () => {
294
- const tex = gl.createTexture();
295
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
296
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
297
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
298
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
299
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
300
- expect(gl.getError()).toBe(gl.NO_ERROR);
301
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
302
- gl.deleteTexture(tex);
303
- });
304
- });
305
- await describe("textures/luminance", async () => {
306
- beforeEach(async () => {
307
- glArea.make_current();
308
- });
309
- await it("LUMINANCE format texImage2D \u2014 no error", async () => {
310
- const tex = gl.createTexture();
311
- gl.bindTexture(gl.TEXTURE_2D, tex);
312
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
313
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
314
- const data = new Uint8Array([128, 64, 192, 32]);
315
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 4, 1, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data);
316
- expect(gl.getError()).toBe(gl.NO_ERROR);
317
- gl.bindTexture(gl.TEXTURE_2D, null);
318
- gl.deleteTexture(tex);
319
- });
320
- await it("LUMINANCE_ALPHA format texImage2D \u2014 no error", async () => {
321
- const tex = gl.createTexture();
322
- gl.bindTexture(gl.TEXTURE_2D, tex);
323
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
324
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
325
- const data = new Uint8Array([128, 255, 64, 128]);
326
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE_ALPHA, 2, 1, 0, gl.LUMINANCE_ALPHA, gl.UNSIGNED_BYTE, data);
327
- expect(gl.getError()).toBe(gl.NO_ERROR);
328
- gl.bindTexture(gl.TEXTURE_2D, null);
329
- gl.deleteTexture(tex);
330
- });
331
- });
332
- await describe("textures/generateMipmap", async () => {
333
- beforeEach(async () => {
334
- glArea.make_current();
335
- });
336
- await it("generateMipmap on power-of-two RGBA texture \u2014 no error", async () => {
337
- const tex = gl.createTexture();
338
- gl.bindTexture(gl.TEXTURE_2D, tex);
339
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
340
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
341
- const W = 4, H = 4;
342
- const data = new Uint8Array(W * H * 4).fill(255);
343
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
344
- gl.generateMipmap(gl.TEXTURE_2D);
345
- expect(gl.getError()).toBe(gl.NO_ERROR);
346
- gl.bindTexture(gl.TEXTURE_2D, null);
347
- gl.deleteTexture(tex);
348
- });
349
- });
350
- });
351
- };
352
- export {
353
- textures_spec_default as default
20
+ await on("Display", async () => {
21
+ const setup = createGLSetup();
22
+ if (!setup) {
23
+ console.warn("WebGL context not available skipping conformance/textures tests");
24
+ return;
25
+ }
26
+ const { gl, glArea } = setup;
27
+ glArea.make_current();
28
+ await describe("textures/texImage2D-rgba", async () => {
29
+ beforeEach(async () => {
30
+ glArea.make_current();
31
+ });
32
+ await it("upload 2×2 RGBA Uint8Array and sample it back", async () => {
33
+ const W = 2, H = 2;
34
+ const fbo = makeTestFBO(gl, W, H);
35
+ const data = new Uint8Array([
36
+ 255,
37
+ 0,
38
+ 0,
39
+ 255,
40
+ 0,
41
+ 255,
42
+ 0,
43
+ 255,
44
+ 0,
45
+ 0,
46
+ 255,
47
+ 255,
48
+ 255,
49
+ 255,
50
+ 0,
51
+ 255
52
+ ]);
53
+ const tex = gl.createTexture();
54
+ gl.bindTexture(gl.TEXTURE_2D, tex);
55
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
56
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
57
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
58
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
59
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
60
+ const prog = makeProgram(gl, VS_TEX, FS_TEX);
61
+ gl.useProgram(prog);
62
+ gl.uniform1i(gl.getUniformLocation(prog, "uTex"), 0);
63
+ drawTriangle(gl);
64
+ expect(gl.getError()).toBe(gl.NO_ERROR);
65
+ gl.deleteTexture(tex);
66
+ destroyTestFBO(gl, fbo);
67
+ });
68
+ await it("createTexture returns non-null; deleteTexture cleans up", async () => {
69
+ const tex = gl.createTexture();
70
+ expect(tex).toBeDefined();
71
+ gl.bindTexture(gl.TEXTURE_2D, tex);
72
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
73
+ 128,
74
+ 128,
75
+ 128,
76
+ 255
77
+ ]));
78
+ expect(gl.getError()).toBe(gl.NO_ERROR);
79
+ gl.bindTexture(gl.TEXTURE_2D, null);
80
+ gl.deleteTexture(tex);
81
+ expect(gl.getError()).toBe(gl.NO_ERROR);
82
+ });
83
+ });
84
+ await describe("textures/alpha-texture", async () => {
85
+ beforeEach(async () => {
86
+ glArea.make_current();
87
+ });
88
+ await it("ALPHA format texImage2D: RGB channels zero, alpha matches upload data", async () => {
89
+ const W = 4, H = 4;
90
+ const fbo = makeTestFBO(gl, W, H);
91
+ const data = new Uint8Array(W * H);
92
+ for (let i = 0; i < H; i++) {
93
+ for (let j = 0; j < W; j++) {
94
+ data[i * W + j] = (i + j) % 255;
95
+ }
96
+ }
97
+ const tex = gl.createTexture();
98
+ gl.bindTexture(gl.TEXTURE_2D, tex);
99
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
100
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
101
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
102
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
103
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, W, H, 0, gl.ALPHA, gl.UNSIGNED_BYTE, data);
104
+ expect(gl.getError()).toBe(gl.NO_ERROR);
105
+ gl.clearColor(0, 0, 0, 0);
106
+ gl.clear(gl.COLOR_BUFFER_BIT);
107
+ const prog = makeProgram(gl, VS_TEX, FS_TEX);
108
+ gl.useProgram(prog);
109
+ gl.uniform1i(gl.getUniformLocation(prog, "uTex"), 0);
110
+ drawTriangle(gl);
111
+ expect(gl.getError()).toBe(gl.NO_ERROR);
112
+ const pixels = new Uint8Array(W * H * 4);
113
+ gl.readPixels(0, 0, W, H, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
114
+ let ok = true;
115
+ for (let k = 0; k < W * H; k++) {
116
+ const i = k * 4;
117
+ if (pixels[i] !== 0 || pixels[i + 1] !== 0 || pixels[i + 2] !== 0) {
118
+ ok = false;
119
+ break;
120
+ }
121
+ if (Math.abs(pixels[i + 3] - data[k]) > 3) {
122
+ ok = false;
123
+ break;
124
+ }
125
+ }
126
+ expect(ok).toBe(true);
127
+ gl.deleteTexture(tex);
128
+ destroyTestFBO(gl, fbo);
129
+ });
130
+ });
131
+ await describe("textures/texSubImage2D", async () => {
132
+ beforeEach(async () => {
133
+ glArea.make_current();
134
+ });
135
+ await it("texSubImage2D overwrites a sub-region of an RGBA texture", async () => {
136
+ const W = 4, H = 4;
137
+ const fbo = makeTestFBO(gl, W, H);
138
+ const redData = new Uint8Array(W * H * 4).fill(0);
139
+ for (let i = 0; i < W * H; i++) {
140
+ redData[i * 4] = 255;
141
+ redData[i * 4 + 3] = 255;
142
+ }
143
+ const tex = gl.createTexture();
144
+ gl.bindTexture(gl.TEXTURE_2D, tex);
145
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
146
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
147
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
148
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
149
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, redData);
150
+ const greenPatch = new Uint8Array([
151
+ 0,
152
+ 255,
153
+ 0,
154
+ 255,
155
+ 0,
156
+ 255,
157
+ 0,
158
+ 255,
159
+ 0,
160
+ 255,
161
+ 0,
162
+ 255,
163
+ 0,
164
+ 255,
165
+ 0,
166
+ 255
167
+ ]);
168
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, greenPatch);
169
+ expect(gl.getError()).toBe(gl.NO_ERROR);
170
+ gl.deleteTexture(tex);
171
+ destroyTestFBO(gl, fbo);
172
+ });
173
+ });
174
+ await describe("textures/parameters", async () => {
175
+ beforeEach(async () => {
176
+ glArea.make_current();
177
+ });
178
+ await it("getTexParameter returns set WRAP and FILTER values", async () => {
179
+ const tex = gl.createTexture();
180
+ gl.bindTexture(gl.TEXTURE_2D, tex);
181
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
182
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
183
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
184
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
185
+ expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)).toBe(gl.CLAMP_TO_EDGE);
186
+ expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T)).toBe(gl.REPEAT);
187
+ expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)).toBe(gl.LINEAR);
188
+ expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER)).toBe(gl.NEAREST);
189
+ expect(gl.getError()).toBe(gl.NO_ERROR);
190
+ gl.bindTexture(gl.TEXTURE_2D, null);
191
+ gl.deleteTexture(tex);
192
+ });
193
+ await it("MIRRORED_REPEAT wrap mode is accepted", async () => {
194
+ const tex = gl.createTexture();
195
+ gl.bindTexture(gl.TEXTURE_2D, tex);
196
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
197
+ expect(gl.getError()).toBe(gl.NO_ERROR);
198
+ expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)).toBe(gl.MIRRORED_REPEAT);
199
+ gl.bindTexture(gl.TEXTURE_2D, null);
200
+ gl.deleteTexture(tex);
201
+ });
202
+ await it("LINEAR_MIPMAP_LINEAR min filter is accepted", async () => {
203
+ const tex = gl.createTexture();
204
+ gl.bindTexture(gl.TEXTURE_2D, tex);
205
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
206
+ expect(gl.getError()).toBe(gl.NO_ERROR);
207
+ expect(gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)).toBe(gl.LINEAR_MIPMAP_LINEAR);
208
+ gl.bindTexture(gl.TEXTURE_2D, null);
209
+ gl.deleteTexture(tex);
210
+ });
211
+ });
212
+ await describe("textures/active-texture", async () => {
213
+ beforeEach(async () => {
214
+ glArea.make_current();
215
+ });
216
+ await it("activeTexture switches binding slot; each unit holds independent binding", async () => {
217
+ const tex0 = gl.createTexture();
218
+ const tex1 = gl.createTexture();
219
+ gl.activeTexture(gl.TEXTURE0);
220
+ gl.bindTexture(gl.TEXTURE_2D, tex0);
221
+ gl.activeTexture(gl.TEXTURE1);
222
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
223
+ gl.activeTexture(gl.TEXTURE0);
224
+ expect(gl.getParameter(gl.TEXTURE_BINDING_2D)).toBe(tex0);
225
+ gl.activeTexture(gl.TEXTURE1);
226
+ expect(gl.getParameter(gl.TEXTURE_BINDING_2D)).toBe(tex1);
227
+ expect(gl.getError()).toBe(gl.NO_ERROR);
228
+ gl.activeTexture(gl.TEXTURE0);
229
+ gl.bindTexture(gl.TEXTURE_2D, null);
230
+ gl.activeTexture(gl.TEXTURE1);
231
+ gl.bindTexture(gl.TEXTURE_2D, null);
232
+ gl.deleteTexture(tex0);
233
+ gl.deleteTexture(tex1);
234
+ });
235
+ await it("getParameter ACTIVE_TEXTURE reflects activeTexture call", async () => {
236
+ gl.activeTexture(gl.TEXTURE3);
237
+ expect(gl.getParameter(gl.ACTIVE_TEXTURE)).toBe(gl.TEXTURE3);
238
+ gl.activeTexture(gl.TEXTURE0);
239
+ expect(gl.getParameter(gl.ACTIVE_TEXTURE)).toBe(gl.TEXTURE0);
240
+ expect(gl.getError()).toBe(gl.NO_ERROR);
241
+ });
242
+ });
243
+ await describe("textures/cubemap", async () => {
244
+ beforeEach(async () => {
245
+ glArea.make_current();
246
+ });
247
+ await it("attach all 6 cubemap faces to FBO — no GL error", async () => {
248
+ const tex = gl.createTexture();
249
+ const fb = gl.createFramebuffer();
250
+ const whitePixel = new Uint8Array([
251
+ 255,
252
+ 255,
253
+ 255,
254
+ 255
255
+ ]);
256
+ gl.activeTexture(gl.TEXTURE1);
257
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
258
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
259
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
260
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
261
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
262
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
263
+ for (let i = 0; i < 6; i++) {
264
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, whitePixel);
265
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, tex, 0);
266
+ }
267
+ expect(gl.getError()).toBe(gl.NO_ERROR);
268
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
269
+ gl.activeTexture(gl.TEXTURE1);
270
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
271
+ gl.activeTexture(gl.TEXTURE0);
272
+ gl.deleteTexture(tex);
273
+ gl.deleteFramebuffer(fb);
274
+ });
275
+ await it("createTexture with TEXTURE_CUBE_MAP binding — no error", async () => {
276
+ const tex = gl.createTexture();
277
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
278
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
279
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
280
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
281
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
282
+ expect(gl.getError()).toBe(gl.NO_ERROR);
283
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
284
+ gl.deleteTexture(tex);
285
+ });
286
+ });
287
+ await describe("textures/luminance", async () => {
288
+ beforeEach(async () => {
289
+ glArea.make_current();
290
+ });
291
+ await it("LUMINANCE format texImage2D — no error", async () => {
292
+ const tex = gl.createTexture();
293
+ gl.bindTexture(gl.TEXTURE_2D, tex);
294
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
295
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
296
+ const data = new Uint8Array([
297
+ 128,
298
+ 64,
299
+ 192,
300
+ 32
301
+ ]);
302
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 4, 1, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data);
303
+ expect(gl.getError()).toBe(gl.NO_ERROR);
304
+ gl.bindTexture(gl.TEXTURE_2D, null);
305
+ gl.deleteTexture(tex);
306
+ });
307
+ await it("LUMINANCE_ALPHA format texImage2D — no error", async () => {
308
+ const tex = gl.createTexture();
309
+ gl.bindTexture(gl.TEXTURE_2D, tex);
310
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
311
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
312
+ const data = new Uint8Array([
313
+ 128,
314
+ 255,
315
+ 64,
316
+ 128
317
+ ]);
318
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE_ALPHA, 2, 1, 0, gl.LUMINANCE_ALPHA, gl.UNSIGNED_BYTE, data);
319
+ expect(gl.getError()).toBe(gl.NO_ERROR);
320
+ gl.bindTexture(gl.TEXTURE_2D, null);
321
+ gl.deleteTexture(tex);
322
+ });
323
+ });
324
+ await describe("textures/generateMipmap", async () => {
325
+ beforeEach(async () => {
326
+ glArea.make_current();
327
+ });
328
+ await it("generateMipmap on power-of-two RGBA texture no error", async () => {
329
+ const tex = gl.createTexture();
330
+ gl.bindTexture(gl.TEXTURE_2D, tex);
331
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
332
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
333
+ const W = 4, H = 4;
334
+ const data = new Uint8Array(W * H * 4).fill(255);
335
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
336
+ gl.generateMipmap(gl.TEXTURE_2D);
337
+ expect(gl.getError()).toBe(gl.NO_ERROR);
338
+ gl.bindTexture(gl.TEXTURE_2D, null);
339
+ gl.deleteTexture(tex);
340
+ });
341
+ });
342
+ });
354
343
  };
344
+
345
+ //#endregion
346
+ export { textures_spec_default as default };