@thi.ng/webgl 6.6.11 → 6.6.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/texture.js CHANGED
@@ -1,248 +1,295 @@
1
1
  import { withoutKeysObj } from "@thi.ng/associative/without-keys";
2
2
  import { isArray } from "@thi.ng/checks/is-array";
3
- import { TEX_FORMATS, TextureFilter, TextureFormat, TextureRepeat, TextureTarget, TextureType, } from "./api/texture.js";
3
+ import {
4
+ TEX_FORMATS,
5
+ TextureFilter,
6
+ TextureFormat,
7
+ TextureRepeat,
8
+ TextureTarget,
9
+ TextureType
10
+ } from "./api/texture.js";
4
11
  import { isGL2Context } from "./checks.js";
5
12
  import { error } from "./error.js";
6
13
  const $bind = (op) => (textures) => {
7
- if (!textures)
8
- return;
9
- for (let i = textures.length, tex; i-- > 0;) {
10
- (tex = textures[i]) && tex[op](i);
11
- }
14
+ if (!textures)
15
+ return;
16
+ for (let i = textures.length, tex; i-- > 0; ) {
17
+ (tex = textures[i]) && tex[op](i);
18
+ }
12
19
  };
13
- export const bindTextures = $bind("bind");
14
- export const unbindTextures = $bind("unbind");
15
- export class Texture {
16
- gl;
17
- tex;
18
- target;
19
- format;
20
- filter;
21
- wrap;
22
- type;
23
- size;
24
- constructor(gl, opts = {}) {
25
- this.gl = gl;
26
- this.tex = gl.createTexture() || error("error creating WebGL texture");
27
- this.configure({
28
- filter: TextureFilter.NEAREST,
29
- wrap: TextureRepeat.CLAMP,
30
- ...opts,
31
- });
32
- }
33
- configure(opts = {}, unbind = true) {
34
- const gl = this.gl;
35
- const target = opts.target || this.target || TextureTarget.TEXTURE_2D;
36
- const format = opts.format || this.format || TextureFormat.RGBA;
37
- const decl = TEX_FORMATS[format];
38
- const type = opts.type || this.type || decl.types[0];
39
- !this.target && (this.target = target);
40
- this.format = format;
41
- this.type = type;
42
- gl.bindTexture(this.target, this.tex);
43
- opts.flip !== undefined &&
44
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, opts.flip ? 1 : 0);
45
- opts.premultiply !== undefined &&
46
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, opts.premultiply ? 1 : 0);
47
- this.configureImage(target, opts);
48
- opts.mipmap && gl.generateMipmap(target);
49
- this.configureFilter(target, opts);
50
- this.configureWrap(target, opts);
51
- this.configureLOD(target, opts);
52
- this.configureLevels(target, opts);
53
- unbind && gl.bindTexture(this.target, null);
54
- return true;
55
- }
56
- configureImage(target, opts) {
57
- if (opts.image === undefined)
58
- return;
59
- target === TextureTarget.TEXTURE_3D
60
- ? this.configureImage3d(target, opts)
61
- : this.configureImage2d(target, opts);
62
- }
63
- configureImage2d(target, opts) {
64
- const level = opts.level || 0;
65
- const pos = opts.pos || [0, 0, 0];
66
- const { image, width, height } = opts;
67
- const decl = TEX_FORMATS[this.format];
68
- const baseFormat = decl.format;
69
- const { gl, type, format } = this;
70
- if (width && height) {
71
- if (opts.sub) {
72
- gl.texSubImage2D(target, level, pos[0], pos[1], width, height, baseFormat, type, image);
73
- }
74
- else {
75
- if (level === 0) {
76
- this.size = [width, height];
77
- }
78
- gl.texImage2D(target, level, format, width, height, 0, baseFormat, type, image);
79
- }
20
+ const bindTextures = $bind("bind");
21
+ const unbindTextures = $bind("unbind");
22
+ class Texture {
23
+ gl;
24
+ tex;
25
+ target;
26
+ format;
27
+ filter;
28
+ wrap;
29
+ type;
30
+ size;
31
+ constructor(gl, opts = {}) {
32
+ this.gl = gl;
33
+ this.tex = gl.createTexture() || error("error creating WebGL texture");
34
+ this.configure({
35
+ filter: TextureFilter.NEAREST,
36
+ wrap: TextureRepeat.CLAMP,
37
+ ...opts
38
+ });
39
+ }
40
+ configure(opts = {}, unbind = true) {
41
+ const gl = this.gl;
42
+ const target = opts.target || this.target || TextureTarget.TEXTURE_2D;
43
+ const format = opts.format || this.format || TextureFormat.RGBA;
44
+ const decl = TEX_FORMATS[format];
45
+ const type = opts.type || this.type || decl.types[0];
46
+ !this.target && (this.target = target);
47
+ this.format = format;
48
+ this.type = type;
49
+ gl.bindTexture(this.target, this.tex);
50
+ opts.flip !== void 0 && gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, opts.flip ? 1 : 0);
51
+ opts.premultiply !== void 0 && gl.pixelStorei(
52
+ gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,
53
+ opts.premultiply ? 1 : 0
54
+ );
55
+ this.configureImage(target, opts);
56
+ opts.mipmap && gl.generateMipmap(target);
57
+ this.configureFilter(target, opts);
58
+ this.configureWrap(target, opts);
59
+ this.configureLOD(target, opts);
60
+ this.configureLevels(target, opts);
61
+ unbind && gl.bindTexture(this.target, null);
62
+ return true;
63
+ }
64
+ configureImage(target, opts) {
65
+ if (opts.image === void 0)
66
+ return;
67
+ target === TextureTarget.TEXTURE_3D ? this.configureImage3d(target, opts) : this.configureImage2d(target, opts);
68
+ }
69
+ configureImage2d(target, opts) {
70
+ const level = opts.level || 0;
71
+ const pos = opts.pos || [0, 0, 0];
72
+ const { image, width, height } = opts;
73
+ const decl = TEX_FORMATS[this.format];
74
+ const baseFormat = decl.format;
75
+ const { gl, type, format } = this;
76
+ if (width && height) {
77
+ if (opts.sub) {
78
+ gl.texSubImage2D(
79
+ target,
80
+ level,
81
+ pos[0],
82
+ pos[1],
83
+ width,
84
+ height,
85
+ baseFormat,
86
+ type,
87
+ image
88
+ );
89
+ } else {
90
+ if (level === 0) {
91
+ this.size = [width, height];
80
92
  }
81
- else {
82
- if (opts.sub) {
83
- gl.texSubImage2D(target, level, pos[0], pos[1], baseFormat, type, image);
84
- }
85
- else {
86
- if (image != null && level === 0) {
87
- this.size = [image.width, image.height];
88
- }
89
- gl.texImage2D(target, level, format, baseFormat, type, image);
90
- }
93
+ gl.texImage2D(
94
+ target,
95
+ level,
96
+ format,
97
+ width,
98
+ height,
99
+ 0,
100
+ baseFormat,
101
+ type,
102
+ image
103
+ );
104
+ }
105
+ } else {
106
+ if (opts.sub) {
107
+ gl.texSubImage2D(
108
+ target,
109
+ level,
110
+ pos[0],
111
+ pos[1],
112
+ baseFormat,
113
+ type,
114
+ image
115
+ );
116
+ } else {
117
+ if (image != null && level === 0) {
118
+ this.size = [image.width, image.height];
91
119
  }
120
+ gl.texImage2D(
121
+ target,
122
+ level,
123
+ format,
124
+ baseFormat,
125
+ type,
126
+ image
127
+ );
128
+ }
92
129
  }
93
- configureImage3d(target, opts) {
94
- const { image, width, height, depth } = opts;
95
- if (!(width && height && depth))
96
- return;
97
- const level = opts.level || 0;
98
- const pos = opts.pos || [0, 0, 0];
99
- const decl = TEX_FORMATS[this.format];
100
- const baseFormat = decl.format;
101
- const { gl, type, format } = this;
102
- if (opts.sub) {
103
- gl.texSubImage3D(target, level, pos[0], pos[1], pos[2], width, height, depth, baseFormat, type, image);
104
- }
105
- else {
106
- if (level === 0) {
107
- this.size = [width, height, depth];
108
- }
109
- gl.texImage3D(target, level, format, width, height, depth, 0, baseFormat, type, image);
110
- }
130
+ }
131
+ configureImage3d(target, opts) {
132
+ const { image, width, height, depth } = opts;
133
+ if (!(width && height && depth))
134
+ return;
135
+ const level = opts.level || 0;
136
+ const pos = opts.pos || [0, 0, 0];
137
+ const decl = TEX_FORMATS[this.format];
138
+ const baseFormat = decl.format;
139
+ const { gl, type, format } = this;
140
+ if (opts.sub) {
141
+ gl.texSubImage3D(
142
+ target,
143
+ level,
144
+ pos[0],
145
+ pos[1],
146
+ pos[2],
147
+ width,
148
+ height,
149
+ depth,
150
+ baseFormat,
151
+ type,
152
+ image
153
+ );
154
+ } else {
155
+ if (level === 0) {
156
+ this.size = [width, height, depth];
157
+ }
158
+ gl.texImage3D(
159
+ target,
160
+ level,
161
+ format,
162
+ width,
163
+ height,
164
+ depth,
165
+ 0,
166
+ baseFormat,
167
+ type,
168
+ image
169
+ );
111
170
  }
112
- configureFilter(target, opts) {
113
- const gl = this.gl;
114
- const flt = opts.filter || this.filter || TextureFilter.NEAREST;
115
- let t1, t2;
116
- if (isArray(flt)) {
117
- t1 = flt[0];
118
- t2 = flt[1] || t1;
119
- this.filter = [t1, t2];
120
- }
121
- else {
122
- this.filter = [flt, flt, flt];
123
- t1 = t2 = flt;
124
- }
125
- gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, t1);
126
- gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, t2);
171
+ }
172
+ configureFilter(target, opts) {
173
+ const gl = this.gl;
174
+ const flt = opts.filter || this.filter || TextureFilter.NEAREST;
175
+ let t1, t2;
176
+ if (isArray(flt)) {
177
+ t1 = flt[0];
178
+ t2 = flt[1] || t1;
179
+ this.filter = [t1, t2];
180
+ } else {
181
+ this.filter = [flt, flt, flt];
182
+ t1 = t2 = flt;
127
183
  }
128
- configureWrap(target, opts) {
129
- const gl = this.gl;
130
- const wrap = opts.wrap || this.wrap || TextureRepeat.CLAMP;
131
- let t1, t2, t3;
132
- if (isArray(wrap)) {
133
- t1 = wrap[0];
134
- t2 = wrap[1] || t1;
135
- t3 = wrap[2] || t1;
136
- this.wrap = [t1, t2, t3];
137
- }
138
- else {
139
- t1 = t2 = t3 = wrap;
140
- this.wrap = [wrap, wrap, wrap];
141
- }
142
- gl.texParameteri(target, gl.TEXTURE_WRAP_S, t1);
143
- gl.texParameteri(target, gl.TEXTURE_WRAP_T, t2);
144
- isGL2Context(gl) &&
145
- target === gl.TEXTURE_3D &&
146
- gl.texParameteri(target, gl.TEXTURE_WRAP_R, t3);
147
- }
148
- configureLOD(target, opts) {
149
- const gl = this.gl;
150
- if (opts.lod) {
151
- const [t1, t2] = opts.lod;
152
- t1 &&
153
- gl.texParameterf(target, gl.TEXTURE_MIN_LOD, t1);
154
- t2 &&
155
- gl.texParameterf(target, gl.TEXTURE_MAX_LOD, t2);
156
- }
157
- }
158
- configureLevels(target, opts) {
159
- const gl = this.gl;
160
- if (opts.minMaxLevel) {
161
- const [t1, t2] = opts.minMaxLevel;
162
- gl.texParameteri(target, gl.TEXTURE_BASE_LEVEL, t1);
163
- gl.texParameteri(target, gl.TEXTURE_MAX_LEVEL, t2);
164
- }
184
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, t1);
185
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, t2);
186
+ }
187
+ configureWrap(target, opts) {
188
+ const gl = this.gl;
189
+ const wrap = opts.wrap || this.wrap || TextureRepeat.CLAMP;
190
+ let t1, t2, t3;
191
+ if (isArray(wrap)) {
192
+ t1 = wrap[0];
193
+ t2 = wrap[1] || t1;
194
+ t3 = wrap[2] || t1;
195
+ this.wrap = [t1, t2, t3];
196
+ } else {
197
+ t1 = t2 = t3 = wrap;
198
+ this.wrap = [wrap, wrap, wrap];
165
199
  }
166
- bind(id = 0) {
167
- const gl = this.gl;
168
- gl.activeTexture(gl.TEXTURE0 + id);
169
- gl.bindTexture(this.target, this.tex);
170
- return true;
200
+ gl.texParameteri(target, gl.TEXTURE_WRAP_S, t1);
201
+ gl.texParameteri(target, gl.TEXTURE_WRAP_T, t2);
202
+ isGL2Context(gl) && target === gl.TEXTURE_3D && gl.texParameteri(
203
+ target,
204
+ gl.TEXTURE_WRAP_R,
205
+ t3
206
+ );
207
+ }
208
+ configureLOD(target, opts) {
209
+ const gl = this.gl;
210
+ if (opts.lod) {
211
+ const [t1, t2] = opts.lod;
212
+ t1 && gl.texParameterf(
213
+ target,
214
+ gl.TEXTURE_MIN_LOD,
215
+ t1
216
+ );
217
+ t2 && gl.texParameterf(
218
+ target,
219
+ gl.TEXTURE_MAX_LOD,
220
+ t2
221
+ );
171
222
  }
172
- unbind(id = 0) {
173
- const gl = this.gl;
174
- gl.activeTexture(gl.TEXTURE0 + id);
175
- gl.bindTexture(this.target, null);
176
- return true;
223
+ }
224
+ configureLevels(target, opts) {
225
+ const gl = this.gl;
226
+ if (opts.minMaxLevel) {
227
+ const [t1, t2] = opts.minMaxLevel;
228
+ gl.texParameteri(
229
+ target,
230
+ gl.TEXTURE_BASE_LEVEL,
231
+ t1
232
+ );
233
+ gl.texParameteri(
234
+ target,
235
+ gl.TEXTURE_MAX_LEVEL,
236
+ t2
237
+ );
177
238
  }
178
- release() {
179
- if (this.tex) {
180
- this.gl.deleteTexture(this.tex);
181
- delete this.tex;
182
- delete this.gl;
183
- return true;
184
- }
185
- return false;
239
+ }
240
+ bind(id = 0) {
241
+ const gl = this.gl;
242
+ gl.activeTexture(gl.TEXTURE0 + id);
243
+ gl.bindTexture(this.target, this.tex);
244
+ return true;
245
+ }
246
+ unbind(id = 0) {
247
+ const gl = this.gl;
248
+ gl.activeTexture(gl.TEXTURE0 + id);
249
+ gl.bindTexture(this.target, null);
250
+ return true;
251
+ }
252
+ release() {
253
+ if (this.tex) {
254
+ this.gl.deleteTexture(this.tex);
255
+ delete this.tex;
256
+ delete this.gl;
257
+ return true;
186
258
  }
259
+ return false;
260
+ }
187
261
  }
188
- export const defTexture = (gl, opts) => new Texture(gl, opts);
189
- /**
190
- * Creates cube map texture from given 6 `face` texture sources. The
191
- * given options are shared by each each side/face of the cube map. The
192
- * following options are applied to the cube map directly:
193
- *
194
- * - `filter`
195
- * - `mipmap`
196
- *
197
- * The following options are ignored entirely:
198
- *
199
- * - `target`
200
- * - `image`
201
- *
202
- * @param gl -
203
- * @param faces - in order: +x,-x,+y,-y,+z,-z
204
- * @param opts -
205
- */
206
- export const defTextureCubeMap = (gl, faces, opts = {}) => {
207
- const tex = new Texture(gl, { target: gl.TEXTURE_CUBE_MAP });
208
- const faceOpts = withoutKeysObj(opts, [
209
- "target",
210
- "image",
211
- "filter",
212
- "mipmap",
213
- ]);
214
- for (let i = 0; i < 6; i++) {
215
- faceOpts.target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + i;
216
- faceOpts.image = faces[i];
217
- tex.configure(faceOpts);
218
- }
219
- tex.configure({ filter: opts.filter, mipmap: opts.mipmap });
220
- return tex;
262
+ const defTexture = (gl, opts) => new Texture(gl, opts);
263
+ const defTextureCubeMap = (gl, faces, opts = {}) => {
264
+ const tex = new Texture(gl, { target: gl.TEXTURE_CUBE_MAP });
265
+ const faceOpts = withoutKeysObj(opts, [
266
+ "target",
267
+ "image",
268
+ "filter",
269
+ "mipmap"
270
+ ]);
271
+ for (let i = 0; i < 6; i++) {
272
+ faceOpts.target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + i;
273
+ faceOpts.image = faces[i];
274
+ tex.configure(faceOpts);
275
+ }
276
+ tex.configure({ filter: opts.filter, mipmap: opts.mipmap });
277
+ return tex;
221
278
  };
222
- /**
223
- * Creates & configure a new float texture.
224
- *
225
- * **Important:** Since each texel will hold 4x 32-bit float values, the
226
- * `data` buffer needs to have a length of at least `4 * width *
227
- * height`.
228
- *
229
- * Under WebGL 1.0, we assume the caller has previously enabled the
230
- * `OES_texture_float` extension.
231
- *
232
- * @param gl - GL context
233
- * @param data - texture data
234
- * @param width - width
235
- * @param height - height
236
- * @param format -
237
- * @param type -
238
- */
239
- export const defTextureFloat = (gl, data, width, height, format, type) => new Texture(gl, {
240
- filter: gl.NEAREST,
241
- wrap: gl.CLAMP_TO_EDGE,
242
- format: format ||
243
- (isGL2Context(gl) ? TextureFormat.RGBA32F : TextureFormat.RGBA),
244
- type: type || gl.FLOAT,
245
- image: data,
246
- width,
247
- height,
279
+ const defTextureFloat = (gl, data, width, height, format, type) => new Texture(gl, {
280
+ filter: gl.NEAREST,
281
+ wrap: gl.CLAMP_TO_EDGE,
282
+ format: format || (isGL2Context(gl) ? TextureFormat.RGBA32F : TextureFormat.RGBA),
283
+ type: type || gl.FLOAT,
284
+ image: data,
285
+ width,
286
+ height
248
287
  });
288
+ export {
289
+ Texture,
290
+ bindTextures,
291
+ defTexture,
292
+ defTextureCubeMap,
293
+ defTextureFloat,
294
+ unbindTextures
295
+ };
@@ -1,29 +1,32 @@
1
1
  import { canvasPixels } from "@thi.ng/pixel/canvas";
2
2
  import { ARGB8888 } from "@thi.ng/pixel/format/argb8888";
3
- export const checkerboard = (opts) => {
4
- opts = {
5
- size: 16,
6
- col1: 0xffffffff,
7
- col2: 0xff000000,
8
- cornerCols: [0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00],
9
- ...opts,
10
- };
11
- const size = opts.size;
12
- const col1 = ARGB8888.toABGR(opts.col1);
13
- const col2 = ARGB8888.toABGR(opts.col2);
14
- const { canvas, ctx, img, data } = canvasPixels(size);
15
- for (let y = 0, i = 0; y < size; y++) {
16
- for (let x = 0; x < size; x++, i++) {
17
- data[i] = (y & 1) ^ (x & 1) ? col1 : col2;
18
- }
3
+ const checkerboard = (opts) => {
4
+ opts = {
5
+ size: 16,
6
+ col1: 4294967295,
7
+ col2: 4278190080,
8
+ cornerCols: [4294901760, 4278255360, 4278190335, 4294967040],
9
+ ...opts
10
+ };
11
+ const size = opts.size;
12
+ const col1 = ARGB8888.toABGR(opts.col1);
13
+ const col2 = ARGB8888.toABGR(opts.col2);
14
+ const { canvas, ctx, img, data } = canvasPixels(size);
15
+ for (let y = 0, i = 0; y < size; y++) {
16
+ for (let x = 0; x < size; x++, i++) {
17
+ data[i] = y & 1 ^ x & 1 ? col1 : col2;
19
18
  }
20
- if (opts.corners) {
21
- const corners = opts.cornerCols.map(ARGB8888.toABGR);
22
- data[0] = corners[0];
23
- data[size - 1] = corners[1];
24
- data[data.length - size] = corners[2];
25
- data[data.length - 1] = corners[3];
26
- }
27
- ctx.putImageData(img, 0, 0);
28
- return canvas;
19
+ }
20
+ if (opts.corners) {
21
+ const corners = opts.cornerCols.map(ARGB8888.toABGR);
22
+ data[0] = corners[0];
23
+ data[size - 1] = corners[1];
24
+ data[data.length - size] = corners[2];
25
+ data[data.length - 1] = corners[3];
26
+ }
27
+ ctx.putImageData(img, 0, 0);
28
+ return canvas;
29
+ };
30
+ export {
31
+ checkerboard
29
32
  };
@@ -1,21 +1,22 @@
1
1
  import { canvasPixels } from "@thi.ng/pixel/canvas";
2
2
  import { ARGB8888 } from "@thi.ng/pixel/format/argb8888";
3
- export const stripes = (opts) => {
4
- opts = {
5
- size: 16,
6
- col1: 0xffffffff,
7
- col2: 0xff000000,
8
- ...opts,
9
- };
10
- const size = opts.size;
11
- const col1 = ARGB8888.toABGR(opts.col1);
12
- const col2 = ARGB8888.toABGR(opts.col2);
13
- const { canvas, ctx, img, data } = opts.horizontal
14
- ? canvasPixels(1, size)
15
- : canvasPixels(size, 1);
16
- for (let x = size; x-- > 0;) {
17
- data[x] = x & 1 ? col1 : col2;
18
- }
19
- ctx.putImageData(img, 0, 0);
20
- return canvas;
3
+ const stripes = (opts) => {
4
+ opts = {
5
+ size: 16,
6
+ col1: 4294967295,
7
+ col2: 4278190080,
8
+ ...opts
9
+ };
10
+ const size = opts.size;
11
+ const col1 = ARGB8888.toABGR(opts.col1);
12
+ const col2 = ARGB8888.toABGR(opts.col2);
13
+ const { canvas, ctx, img, data } = opts.horizontal ? canvasPixels(1, size) : canvasPixels(size, 1);
14
+ for (let x = size; x-- > 0; ) {
15
+ data[x] = x & 1 ? col1 : col2;
16
+ }
17
+ ctx.putImageData(img, 0, 0);
18
+ return canvas;
19
+ };
20
+ export {
21
+ stripes
21
22
  };