@babylonjs/lite-gl 0.1.0 → 1.0.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.
Files changed (61) hide show
  1. package/README.md +10 -35
  2. package/apply-states.d.ts +1 -0
  3. package/apply-states.js +30 -0
  4. package/apply-states.js.map +1 -0
  5. package/blend.d.ts +123 -0
  6. package/blend.js +194 -0
  7. package/blend.js.map +1 -0
  8. package/context.d.ts +130 -0
  9. package/context.js +354 -0
  10. package/context.js.map +1 -0
  11. package/depth-stencil.d.ts +155 -231
  12. package/depth-stencil.js +399 -262
  13. package/depth-stencil.js.map +1 -1
  14. package/dynamic-texture.d.ts +59 -149
  15. package/dynamic-texture.js +123 -69
  16. package/dynamic-texture.js.map +1 -1
  17. package/effect-renderer.d.ts +65 -0
  18. package/effect-renderer.js +132 -0
  19. package/effect-renderer.js.map +1 -0
  20. package/effect.d.ts +142 -0
  21. package/effect.js +465 -0
  22. package/effect.js.map +1 -0
  23. package/html-texture.d.ts +44 -143
  24. package/html-texture.js +87 -81
  25. package/html-texture.js.map +1 -1
  26. package/index.d.ts +23 -1482
  27. package/index.js +42 -263
  28. package/index.js.map +1 -1
  29. package/mesh.d.ts +210 -307
  30. package/mesh.js +436 -311
  31. package/mesh.js.map +1 -1
  32. package/package.json +5 -29
  33. package/render-loop.d.ts +8 -0
  34. package/render-loop.js +62 -0
  35. package/render-loop.js.map +1 -0
  36. package/render-target.d.ts +190 -290
  37. package/render-target.js +459 -328
  38. package/render-target.js.map +1 -1
  39. package/scissor.d.ts +30 -72
  40. package/scissor.js +47 -33
  41. package/scissor.js.map +1 -1
  42. package/shader.d.ts +22 -0
  43. package/shader.js +65 -0
  44. package/shader.js.map +1 -0
  45. package/sprites.d.ts +182 -263
  46. package/sprites.js +426 -10
  47. package/sprites.js.map +1 -1
  48. package/state.d.ts +126 -0
  49. package/state.js +153 -0
  50. package/state.js.map +1 -0
  51. package/texture.d.ts +142 -0
  52. package/texture.js +433 -0
  53. package/texture.js.map +1 -0
  54. package/effect-BxxwfB_O.js +0 -737
  55. package/effect-BxxwfB_O.js.map +0 -1
  56. package/sprites--1oyVtJ3.js +0 -437
  57. package/sprites--1oyVtJ3.js.map +0 -1
  58. package/state--j_ncWIi.js +0 -155
  59. package/state--j_ncWIi.js.map +0 -1
  60. package/texture-DaMd1gGm.js +0 -329
  61. package/texture-DaMd1gGm.js.map +0 -1
package/texture.js ADDED
@@ -0,0 +1,433 @@
1
+ /**
2
+ * Apply the three `UNPACK_*` pixel-store flags through the GL-state cache,
3
+ * eliding redundant `pixelStorei` calls. Centralising this guarantees EVERY
4
+ * upload path sets all three explicitly, so a premultiplying / flipping upload
5
+ * never leaks its flag into a later upload that forgot to set it.
6
+ * @internal
7
+ */
8
+ export function setUnpackState(engine, flipY, premultiplyAlpha, alignment = 4) {
9
+ const gl = engine.gl;
10
+ const s = engine._state;
11
+ const fy = flipY ? 1 : 0;
12
+ if (s.unpackFlipY !== fy) {
13
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, fy);
14
+ s.unpackFlipY = fy;
15
+ }
16
+ const pm = premultiplyAlpha ? 1 : 0;
17
+ if (s.unpackPremultiplyAlpha !== pm) {
18
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, pm);
19
+ s.unpackPremultiplyAlpha = pm;
20
+ }
21
+ if (s.unpackAlignment !== alignment) {
22
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);
23
+ s.unpackAlignment = alignment;
24
+ }
25
+ }
26
+ /** Uint8 / float raw texture upload. The pixel data can be replaced later via
27
+ * {@link updateRawTexture}; the sampling and wrap can be changed via
28
+ * {@link updateTextureSamplingMode} / {@link updateTextureWrapMode}. */
29
+ export function createRawTexture(engine, data, width, height, format, type, options) {
30
+ const gl = engine.gl;
31
+ const handle = gl.createTexture();
32
+ if (handle === null) {
33
+ throw new Error("lite-gl: gl.createTexture returned null");
34
+ }
35
+ const opts = options ?? {};
36
+ const minFilter = opts.minFilter ?? gl.LINEAR;
37
+ const magFilter = opts.magFilter ?? gl.LINEAR;
38
+ const wrapS = opts.wrapS ?? gl.CLAMP_TO_EDGE;
39
+ const wrapT = opts.wrapT ?? gl.CLAMP_TO_EDGE;
40
+ const invertY = opts.invertY ?? false;
41
+ const premultiply = opts.premultiplyAlpha ?? false;
42
+ // LDR byte formats are resolved INLINE here; the float-format table in
43
+ // `pickSizedInternalFormat` is deliberately NOT referenced from this path so
44
+ // it tree-shakes out of byte-only bundles. `createFloatTexture` injects its
45
+ // sized float format via `opts.internalFormat`.
46
+ const internalFormat = opts.internalFormat ?? resolveLdrInternalFormat(gl, format, type);
47
+ // Mutable upload state — `updateRawTexture` mutates these and re-runs
48
+ // `upload`, so the context-restore replay (which calls the same `upload`)
49
+ // always reproduces the latest contents.
50
+ let curData = data;
51
+ let curWidth = width;
52
+ let curHeight = height;
53
+ let curAlign = opts.unpackAlignment ?? 4;
54
+ const upload = (target) => {
55
+ const g = target.gl;
56
+ setUnpackState(target, invertY, premultiply, curAlign);
57
+ bindTextureForUpload(target, tex.handle);
58
+ g.texImage2D(g.TEXTURE_2D, 0, internalFormat, curWidth, curHeight, 0, format, type, curData);
59
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MIN_FILTER, minFilter);
60
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MAG_FILTER, magFilter);
61
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_S, wrapS);
62
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_T, wrapT);
63
+ };
64
+ const tex = {
65
+ handle,
66
+ target: gl.TEXTURE_2D,
67
+ width,
68
+ height,
69
+ isReady: true,
70
+ _disposed: false,
71
+ _refCount: 1,
72
+ _upload: upload,
73
+ _wasReady: true,
74
+ };
75
+ tex._updateRaw = (target, newData, newWidth, newHeight, unpackAlignment) => {
76
+ curData = newData;
77
+ curWidth = newWidth;
78
+ curHeight = newHeight;
79
+ curAlign = unpackAlignment;
80
+ tex.width = newWidth;
81
+ tex.height = newHeight;
82
+ upload(target);
83
+ };
84
+ upload(engine);
85
+ engine._textures.push(tex);
86
+ return tex;
87
+ }
88
+ /**
89
+ * Create a float / half-float raw texture — the HDR counterpart of
90
+ * {@link createRawTexture}. This is the ONLY texture factory that carries the
91
+ * `RGBA16F` / `RGBA32F` sized-format knowledge (via {@link pickSizedInternalFormat}),
92
+ * so byte-only consumers calling {@link createRawTexture} ship none of it.
93
+ * Defaults to `gl.HALF_FLOAT`; pass `options.type = gl.FLOAT` for full 32-bit.
94
+ * The caller is responsible for the matching engine cap (e.g.
95
+ * `caps.textureFloatLinearFiltering`) when sampling these with `LINEAR`.
96
+ *
97
+ * @param engine - The engine.
98
+ * @param data - Initial pixels (`Float32Array` for FLOAT, `Uint16Array` for
99
+ * HALF_FLOAT), or `null` for an uninitialised allocation.
100
+ * @param width - Texture width in texels (≥ 1).
101
+ * @param height - Texture height in texels (≥ 1).
102
+ * @param options - See {@link GLFloatTextureOptions}.
103
+ * @returns The new {@link GLTexture}.
104
+ */
105
+ export function createFloatTexture(engine, data, width, height, options) {
106
+ const gl = engine.gl;
107
+ const o = options ?? {};
108
+ const format = o.format ?? gl.RGBA;
109
+ const type = o.type ?? gl.HALF_FLOAT;
110
+ // Precompute the sized float internalFormat HERE and pass it through, so
111
+ // `createRawTexture`'s inline LDR resolver is bypassed and the float table
112
+ // stays out of byte-only bundles.
113
+ const internalFormat = pickSizedInternalFormat(gl, format, type);
114
+ return createRawTexture(engine, data, width, height, format, type, { ...o, internalFormat });
115
+ }
116
+ /** Generate the mip chain for a texture from its level-0 contents — mipmaps as
117
+ * an explicit opt-in function rather than baked into the create path. Binds for
118
+ * upload (unit 0). No-op on a lost/disposed context or a handle-less texture. */
119
+ export function generateTextureMipMaps(engine, tex) {
120
+ if (engine._isLost || engine._disposed || tex._disposed || tex.handle === null) {
121
+ return;
122
+ }
123
+ bindTextureForUpload(engine, tex.handle);
124
+ engine.gl.generateMipmap(engine.gl.TEXTURE_2D);
125
+ }
126
+ /**
127
+ * Re-upload the pixel data (and optionally resize) of a texture created by
128
+ * {@link createRawTexture} — the lite-gl equivalent of Babylon's
129
+ * `updateRawTexture` / `_uploadDataToTextureDirectly`. Goes through the same
130
+ * upload closure used by context-restore, so the new contents survive a context
131
+ * loss. No-op on a lost/disposed/non-raw texture.
132
+ *
133
+ * @param engine - The engine.
134
+ * @param tex - The raw texture to update.
135
+ * @param data - New pixel data (must match the original `format`/`type`).
136
+ * @param options - Optional new `width`/`height` (default: unchanged) and
137
+ * `unpackAlignment` (default 4).
138
+ */
139
+ export function updateRawTexture(engine, tex, data, options) {
140
+ if (engine._isLost || engine._disposed || tex._disposed || tex._updateRaw === undefined) {
141
+ return;
142
+ }
143
+ const o = options ?? {};
144
+ tex._updateRaw(engine, data, o.width ?? tex.width, o.height ?? tex.height, o.unpackAlignment ?? 4);
145
+ }
146
+ /** Update a texture's min/mag sampling filters — the lite-gl equivalent of
147
+ * Babylon's `updateTextureSamplingMode`. Binds for upload (unit 0) so the
148
+ * `texParameteri` lands on this texture. No-op on a lost/disposed context. */
149
+ export function updateTextureSamplingMode(engine, tex, minFilter, magFilter) {
150
+ if (engine._isLost || engine._disposed || tex._disposed) {
151
+ return;
152
+ }
153
+ const gl = engine.gl;
154
+ bindTextureForUpload(engine, tex.handle);
155
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
156
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
157
+ }
158
+ /** Update a texture's S/T wrap modes (`gl.CLAMP_TO_EDGE` / `gl.REPEAT` /
159
+ * `gl.MIRRORED_REPEAT`) — the lite-gl equivalent of Babylon's
160
+ * `updateTextureWrappingMode`. No-op on a lost/disposed context. */
161
+ export function updateTextureWrapMode(engine, tex, wrapS, wrapT) {
162
+ if (engine._isLost || engine._disposed || tex._disposed) {
163
+ return;
164
+ }
165
+ const gl = engine.gl;
166
+ bindTextureForUpload(engine, tex.handle);
167
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
168
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
169
+ }
170
+ /**
171
+ * Wrap an existing raw `WebGLTexture` (e.g. one created by a host renderer or a
172
+ * previous engine) as a {@link GLTexture} — the lite-gl equivalent of
173
+ * ShapeBuilder's `createTextureGraphicsResourceFromExternalWebGLTexture`.
174
+ *
175
+ * The wrapper does NOT own the underlying handle's upload — it is NOT registered
176
+ * for context-restore replay (the external owner is responsible for that) and is
177
+ * marked ready immediately. `disposeTexture` will still `gl.deleteTexture` it, so
178
+ * only wrap a handle whose deletion you intend lite-gl to manage.
179
+ *
180
+ * @param engine - The engine.
181
+ * @param handle - The external `WebGLTexture`.
182
+ * @param width - Texture width in texels.
183
+ * @param height - Texture height in texels.
184
+ * @param options - Optional sampling/wrap to apply once (min/mag/wrapS/wrapT).
185
+ * @returns A {@link GLTexture} wrapping the handle.
186
+ */
187
+ export function createTextureFromHandle(engine, handle, width, height, options) {
188
+ const tex = {
189
+ handle,
190
+ target: engine.gl.TEXTURE_2D,
191
+ width,
192
+ height,
193
+ isReady: true,
194
+ _disposed: false,
195
+ _refCount: 1,
196
+ // External handle — restore replay is the external owner's job.
197
+ _upload: () => { },
198
+ _wasReady: true,
199
+ };
200
+ if (options !== undefined) {
201
+ const gl = engine.gl;
202
+ bindTextureForUpload(engine, handle);
203
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, options.minFilter ?? gl.LINEAR);
204
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, options.magFilter ?? gl.LINEAR);
205
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, options.wrapS ?? gl.CLAMP_TO_EDGE);
206
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, options.wrapT ?? gl.CLAMP_TO_EDGE);
207
+ }
208
+ return tex;
209
+ }
210
+ /** Asynchronous image upload.The returned texture is immediately usable (1×1
211
+ * transparent placeholder); `isReady` flips true once the image has been
212
+ * decoded and uploaded. The decoded `ImageBitmap` is retained on the texture
213
+ * for offline-safe `webglcontextrestored` replay. */
214
+ export function loadTexture2D(engine, url, options, onLoad, onError) {
215
+ const gl = engine.gl;
216
+ const handle = gl.createTexture();
217
+ if (handle === null) {
218
+ throw new Error("lite-gl: gl.createTexture returned null");
219
+ }
220
+ const opts = options ?? {};
221
+ const minFilter = opts.minFilter ?? gl.LINEAR;
222
+ const magFilter = opts.magFilter ?? gl.LINEAR;
223
+ const wrapS = opts.wrapS ?? gl.CLAMP_TO_EDGE;
224
+ const wrapT = opts.wrapT ?? gl.CLAMP_TO_EDGE;
225
+ const invertY = opts.invertY ?? false;
226
+ let bitmap = null;
227
+ const placeholderPixels = new Uint8Array([0, 0, 0, 0]);
228
+ const upload = (target) => {
229
+ const g = target.gl;
230
+ // invertY is applied at decode time via createImageBitmap({ imageOrientation })
231
+ // because UNPACK_FLIP_Y_WEBGL is IGNORED for ImageBitmap sources (and the 1×1
232
+ // placeholder is flip-invariant), so keep flip + premultiply off here.
233
+ setUnpackState(target, false, false);
234
+ bindTextureForUpload(target, tex.handle);
235
+ if (bitmap !== null) {
236
+ g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, bitmap);
237
+ tex.width = bitmap.width;
238
+ tex.height = bitmap.height;
239
+ }
240
+ else {
241
+ g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, 1, 1, 0, g.RGBA, g.UNSIGNED_BYTE, placeholderPixels);
242
+ }
243
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MIN_FILTER, minFilter);
244
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MAG_FILTER, magFilter);
245
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_S, wrapS);
246
+ g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_T, wrapT);
247
+ };
248
+ const tex = {
249
+ handle,
250
+ target: gl.TEXTURE_2D,
251
+ width: 1,
252
+ height: 1,
253
+ isReady: false,
254
+ _disposed: false,
255
+ _refCount: 1,
256
+ _upload: upload,
257
+ _wasReady: false,
258
+ };
259
+ // Placeholder upload — makes the texture sampleable before the real image arrives.
260
+ upload(engine);
261
+ engine._textures.push(tex);
262
+ // Fetch + decode the real image. Re-uploads via the same closure once the
263
+ // bitmap is in hand (so context-restore replay sees the real image too).
264
+ fetch(url)
265
+ .then((r) => {
266
+ if (!r.ok) {
267
+ throw new Error(`lite-gl: fetch ${url} -> HTTP ${r.status}`);
268
+ }
269
+ return r.blob();
270
+ })
271
+ .then((blob) => createImageBitmap(blob, { premultiplyAlpha: "none", imageOrientation: invertY ? "flipY" : "none" }))
272
+ .then((bm) => {
273
+ if (tex._disposed) {
274
+ bm.close();
275
+ return;
276
+ }
277
+ bitmap = bm;
278
+ // If the context is lost mid-flight, defer the upload — the restore
279
+ // handler will call _upload again, which will then see `bitmap !== null`
280
+ // and replay the real image.
281
+ if (!engine._isLost) {
282
+ upload(engine);
283
+ tex.isReady = true;
284
+ }
285
+ tex._wasReady = true;
286
+ if (onLoad !== undefined) {
287
+ onLoad(tex);
288
+ }
289
+ })
290
+ .catch((err) => {
291
+ const e = err instanceof Error ? err : new Error(String(err));
292
+ if (onError !== undefined) {
293
+ onError(e);
294
+ }
295
+ else {
296
+ console.error("lite-gl: loadTexture2D failed", e);
297
+ }
298
+ });
299
+ return tex;
300
+ }
301
+ /** Cached bind. Skips `gl.activeTexture` and/or `gl.bindTexture` when nothing
302
+ * changes. No-op when `tex._disposed` or `engine._isLost`. */
303
+ export function bindTexture(engine, unit, tex) {
304
+ if (engine._isLost || engine._disposed) {
305
+ return;
306
+ }
307
+ if (tex !== null && tex._disposed) {
308
+ return;
309
+ }
310
+ bindTextureRaw(engine, unit, tex === null ? null : tex.handle);
311
+ }
312
+ /** @internal — for callers that already hold a raw `WebGLTexture`. Not part of
313
+ * the public API: `bindTexture` (public) and the texture `_upload` closures bind
314
+ * through the cache, so consumers never call this directly. */
315
+ export function bindTextureRaw(engine, unit, handle) {
316
+ const s = engine._state;
317
+ const gl = engine.gl;
318
+ if (s.boundTextures[unit] === handle) {
319
+ return;
320
+ }
321
+ if (s.activeTextureUnit !== unit) {
322
+ gl.activeTexture(gl.TEXTURE0 + unit);
323
+ s.activeTextureUnit = unit;
324
+ }
325
+ gl.bindTexture(gl.TEXTURE_2D, handle);
326
+ s.boundTextures[unit] = handle;
327
+ }
328
+ /** @internal Bind `handle` on texture unit 0 **for an upload** (`texImage2D`).
329
+ * Unlike {@link bindTextureRaw} — which elides the entire bind when the handle is
330
+ * already bound on the unit (correct for *sampling*, where the active unit is
331
+ * irrelevant) — an upload writes into the texture on the ACTIVE unit. A prior
332
+ * multi-sampler draw may have left a non-zero unit active while this handle is
333
+ * still bound on unit 0, so we must force unit 0 active even on a bind cache-hit,
334
+ * keeping the `_state` cache coherent. */
335
+ export function bindTextureForUpload(engine, handle) {
336
+ const s = engine._state;
337
+ const gl = engine.gl;
338
+ if (s.activeTextureUnit !== 0) {
339
+ gl.activeTexture(gl.TEXTURE0);
340
+ s.activeTextureUnit = 0;
341
+ }
342
+ if (s.boundTextures[0] !== handle) {
343
+ gl.bindTexture(gl.TEXTURE_2D, handle);
344
+ s.boundTextures[0] = handle;
345
+ }
346
+ }
347
+ /** Disposes the texture. Walks `_state.boundTextures` and clears every slot
348
+ * that still references the handle — otherwise a later `bindTexture(unit, B)`
349
+ * to the same unit would be wrongly elided when slot still showed handle A. */
350
+ export function disposeTexture(engine, tex) {
351
+ if (tex._disposed) {
352
+ return;
353
+ }
354
+ if (tex._refCount > 1) {
355
+ tex._refCount--;
356
+ return;
357
+ }
358
+ tex._disposed = true;
359
+ const i = engine._textures.indexOf(tex);
360
+ if (i !== -1) {
361
+ engine._textures.splice(i, 1);
362
+ }
363
+ if (!engine._isLost && !engine._disposed) {
364
+ engine.gl.deleteTexture(tex.handle);
365
+ }
366
+ const bound = engine._state.boundTextures;
367
+ for (let u = 0; u < bound.length; u++) {
368
+ if (bound[u] === tex.handle) {
369
+ bound[u] = null;
370
+ }
371
+ }
372
+ }
373
+ /** Internal — resolve the sized internalFormat for the LDR (byte) `texImage2D`
374
+ * paths ONLY: RGBA→RGBA8, RGB→RGB8, RG→RG8, RED→R8, LUMINANCE passthrough.
375
+ * Deliberately knows nothing about FLOAT / HALF_FLOAT so the float-format table
376
+ * in {@link pickSizedInternalFormat} tree-shakes out of byte-only bundles.
377
+ * @internal */
378
+ function resolveLdrInternalFormat(gl, format, type) {
379
+ if (type === gl.UNSIGNED_BYTE) {
380
+ if (format === gl.RGBA) {
381
+ return gl.RGBA8;
382
+ }
383
+ if (format === gl.RGB) {
384
+ return gl.RGB8;
385
+ }
386
+ if (format === gl.RG) {
387
+ return gl.RG8;
388
+ }
389
+ if (format === gl.RED) {
390
+ return gl.R8;
391
+ }
392
+ if (format === gl.LUMINANCE) {
393
+ return gl.LUMINANCE;
394
+ }
395
+ }
396
+ return format;
397
+ }
398
+ /** Internal — pick a sized internalFormat for `texImage2D`. WebGL2 prefers
399
+ * sized formats for non-color-renderable / non-readback paths; for the
400
+ * NeonBrush use cases (sample-only) the unsized format works too, but sized
401
+ * is more portable. Shared with the render-target module.
402
+ * @internal */
403
+ export function pickSizedInternalFormat(gl, format, type) {
404
+ if (type === gl.UNSIGNED_BYTE) {
405
+ if (format === gl.RGBA) {
406
+ return gl.RGBA8;
407
+ }
408
+ if (format === gl.RGB) {
409
+ return gl.RGB8;
410
+ }
411
+ if (format === gl.LUMINANCE) {
412
+ return gl.LUMINANCE;
413
+ }
414
+ }
415
+ if (type === gl.FLOAT) {
416
+ if (format === gl.RGBA) {
417
+ return gl.RGBA32F;
418
+ }
419
+ if (format === gl.RGB) {
420
+ return gl.RGB32F;
421
+ }
422
+ }
423
+ if (type === gl.HALF_FLOAT) {
424
+ if (format === gl.RGBA) {
425
+ return gl.RGBA16F;
426
+ }
427
+ if (format === gl.RGB) {
428
+ return gl.RGB16F;
429
+ }
430
+ }
431
+ return format;
432
+ }
433
+ //# sourceMappingURL=texture.js.map
package/texture.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"texture.js","sourceRoot":"","sources":["../src/texture.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GLEngineContext } from \"./context.js\";\n\n/** Texture sampling / wrap options. All have GL-spec defaults. Mipmaps are NOT\n * a create option — generate the chain explicitly via {@link generateTextureMipMaps}. */\nexport interface GLTextureOptions {\n /** Default: false (matches Babylon's default raw-texture behaviour). */\n invertY?: boolean;\n /** Default: gl.LINEAR. */\n minFilter?: GLenum;\n /** Default: gl.LINEAR. */\n magFilter?: GLenum;\n /** Default: gl.CLAMP_TO_EDGE. May be `gl.REPEAT` / `gl.MIRRORED_REPEAT`\n * (NPOT-safe in WebGL2). */\n wrapS?: GLenum;\n /** Default: gl.CLAMP_TO_EDGE. May be `gl.REPEAT` / `gl.MIRRORED_REPEAT`. */\n wrapT?: GLenum;\n /** `gl.pixelStorei(UNPACK_ALIGNMENT)` for the upload (1/2/4/8). Default 4.\n * Use 1 for tightly-packed non-RGBA rows. */\n unpackAlignment?: number;\n /** Premultiply alpha at upload (`UNPACK_PREMULTIPLY_ALPHA_WEBGL`). Default\n * false. */\n premultiplyAlpha?: boolean;\n /** Explicit sized internalFormat for `texImage2D`. When provided it is used\n * verbatim and the inline LDR resolver is bypassed — this is how\n * {@link createFloatTexture} injects its `RGBA16F` / `RGBA32F` choice\n * without the byte path ever referencing the float-format table (keeping it\n * tree-shakeable out of RGBA8-only bundles). Default: derived from\n * `format`/`type` via the LDR resolver. */\n internalFormat?: GLenum;\n}\n\n/**\n * Pure-state texture handle. The `handle` field is MUTABLE so the same logical\n * texture survives a `webglcontextrestored` event — every consumer keeps the\n * same `GLTexture` reference; only the internal `WebGLTexture` is swapped.\n *\n * `loadTexture2D` also uses the same handle for the 1×1 placeholder upload AND\n * the final image upload — so a `bindTexture(engine, unit, tex)` made before the\n * image has decoded remains valid once the image arrives.\n */\nexport interface GLTexture {\n /** The live `WebGLTexture`. MUTABLE — swapped for a fresh handle on\n * `webglcontextrestored` while consumers keep the same `GLTexture` reference. */\n handle: WebGLTexture;\n /** GL texture target (always `gl.TEXTURE_2D` for this package). */\n readonly target: GLenum;\n /** Texture width in texels. Updated once an async upload resolves. */\n width: number;\n /** Texture height in texels. Updated once an async upload resolves. */\n height: number;\n /** True when the texture is safe to sample with final content (placeholders\n * read as not-ready until their image/upload completes). */\n isReady: boolean;\n /** @internal */\n _disposed: boolean;\n /** @internal */\n _refCount: number;\n /**\n * Replay closure for context-restore (§4.7 of 00-lite-gl.md). Captures the\n * original upload arguments and re-issues the `gl.texImage2D` /\n * `texParameteri` sequence into the freshly-allocated `handle`. After\n * the upload completes the texture is ready iff `_isReadyAfterUpload`.\n * @internal\n */\n _upload: (engine: GLEngineContext) => void;\n /**\n * Snapshot of `isReady` captured on `webglcontextlost` so the restore\n * handler knows whether to flip it back on after `_upload`. Textures\n * that were still mid-load (e.g. `loadTexture2D` whose bitmap hadn't\n * arrived) stay not-ready; the async path will set `isReady=true` once\n * the bitmap finishes decoding into the new handle.\n * @internal\n */\n _wasReady: boolean;\n /**\n * Live re-upload hook installed by `createRawTexture` — lets\n * `updateRawTexture` replace the pixel data (and optionally the size)\n * through the same closure that the context-restore replay uses, keeping\n * restore correct. Absent on image / HTML-element / external textures.\n * @internal\n */\n _updateRaw?: (engine: GLEngineContext, data: ArrayBufferView | null, width: number, height: number, unpackAlignment: number) => void;\n /**\n * Dynamic-texture source captured by `updateDynamicTexture`\n * (`@babylonjs/lite-gl`) and replayed into the fresh handle\n * on `webglcontextrestored`. Null/absent on non-dynamic textures.\n * @internal\n */\n _dynSource?: TexImageSource | null;\n /** UNPACK_FLIP_Y applied when replaying {@link GLTexture._dynSource}. @internal */\n _dynInvertY?: boolean;\n /** UNPACK_PREMULTIPLY_ALPHA applied when replaying {@link GLTexture._dynSource}. @internal */\n _dynPremultiplyAlpha?: boolean;\n /**\n * The `handle` the dynamic texture's `texParameteri` filter/wrap state was\n * last applied to. `texParameteri` is per-texture GL state that survives pixel\n * re-uploads, so the dynamic-texture `_upload` re-applies it ONLY when this no\n * longer matches `handle` — i.e. at creation and after `webglcontextrestored`\n * installs a fresh handle — not on every per-frame `updateDynamicTexture`.\n * @internal\n */\n _dynParamsHandle?: WebGLTexture | null;\n}\n\n/**\n * Apply the three `UNPACK_*` pixel-store flags through the GL-state cache,\n * eliding redundant `pixelStorei` calls. Centralising this guarantees EVERY\n * upload path sets all three explicitly, so a premultiplying / flipping upload\n * never leaks its flag into a later upload that forgot to set it.\n * @internal\n */\nexport function setUnpackState(engine: GLEngineContext, flipY: boolean, premultiplyAlpha: boolean, alignment = 4): void {\n const gl = engine.gl;\n const s = engine._state;\n const fy = flipY ? 1 : 0;\n if (s.unpackFlipY !== fy) {\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, fy);\n s.unpackFlipY = fy;\n }\n const pm = premultiplyAlpha ? 1 : 0;\n if (s.unpackPremultiplyAlpha !== pm) {\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, pm);\n s.unpackPremultiplyAlpha = pm;\n }\n if (s.unpackAlignment !== alignment) {\n gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);\n s.unpackAlignment = alignment;\n }\n}\n\n/** Uint8 / float raw texture upload. The pixel data can be replaced later via\n * {@link updateRawTexture}; the sampling and wrap can be changed via\n * {@link updateTextureSamplingMode} / {@link updateTextureWrapMode}. */\nexport function createRawTexture(\n engine: GLEngineContext,\n data: ArrayBufferView | null,\n width: number,\n height: number,\n format: GLenum,\n type: GLenum,\n options?: GLTextureOptions\n): GLTexture {\n const gl = engine.gl;\n const handle = gl.createTexture();\n if (handle === null) {\n throw new Error(\"lite-gl: gl.createTexture returned null\");\n }\n const opts = options ?? {};\n const minFilter = opts.minFilter ?? gl.LINEAR;\n const magFilter = opts.magFilter ?? gl.LINEAR;\n const wrapS = opts.wrapS ?? gl.CLAMP_TO_EDGE;\n const wrapT = opts.wrapT ?? gl.CLAMP_TO_EDGE;\n const invertY = opts.invertY ?? false;\n const premultiply = opts.premultiplyAlpha ?? false;\n // LDR byte formats are resolved INLINE here; the float-format table in\n // `pickSizedInternalFormat` is deliberately NOT referenced from this path so\n // it tree-shakes out of byte-only bundles. `createFloatTexture` injects its\n // sized float format via `opts.internalFormat`.\n const internalFormat = opts.internalFormat ?? resolveLdrInternalFormat(gl, format, type);\n\n // Mutable upload state — `updateRawTexture` mutates these and re-runs\n // `upload`, so the context-restore replay (which calls the same `upload`)\n // always reproduces the latest contents.\n let curData = data;\n let curWidth = width;\n let curHeight = height;\n let curAlign = opts.unpackAlignment ?? 4;\n\n const upload = (target: GLEngineContext): void => {\n const g = target.gl;\n setUnpackState(target, invertY, premultiply, curAlign);\n bindTextureForUpload(target, tex.handle);\n g.texImage2D(g.TEXTURE_2D, 0, internalFormat, curWidth, curHeight, 0, format, type, curData);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MIN_FILTER, minFilter);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MAG_FILTER, magFilter);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_S, wrapS);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_T, wrapT);\n };\n\n const tex: GLTexture = {\n handle,\n target: gl.TEXTURE_2D,\n width,\n height,\n isReady: true,\n _disposed: false,\n _refCount: 1,\n _upload: upload,\n _wasReady: true,\n };\n tex._updateRaw = (target: GLEngineContext, newData: ArrayBufferView | null, newWidth: number, newHeight: number, unpackAlignment: number): void => {\n curData = newData;\n curWidth = newWidth;\n curHeight = newHeight;\n curAlign = unpackAlignment;\n tex.width = newWidth;\n tex.height = newHeight;\n upload(target);\n };\n upload(engine);\n engine._textures.push(tex);\n return tex;\n}\n\n/** Options for {@link createFloatTexture} — the shared {@link GLTextureOptions}\n * plus the float-specific `type` / `format`. */\nexport interface GLFloatTextureOptions extends GLTextureOptions {\n /** Float texel type — `gl.HALF_FLOAT` (default) or `gl.FLOAT`. */\n type?: GLenum;\n /** Color format. Default `gl.RGBA`. */\n format?: GLenum;\n}\n\n/**\n * Create a float / half-float raw texture — the HDR counterpart of\n * {@link createRawTexture}. This is the ONLY texture factory that carries the\n * `RGBA16F` / `RGBA32F` sized-format knowledge (via {@link pickSizedInternalFormat}),\n * so byte-only consumers calling {@link createRawTexture} ship none of it.\n * Defaults to `gl.HALF_FLOAT`; pass `options.type = gl.FLOAT` for full 32-bit.\n * The caller is responsible for the matching engine cap (e.g.\n * `caps.textureFloatLinearFiltering`) when sampling these with `LINEAR`.\n *\n * @param engine - The engine.\n * @param data - Initial pixels (`Float32Array` for FLOAT, `Uint16Array` for\n * HALF_FLOAT), or `null` for an uninitialised allocation.\n * @param width - Texture width in texels (≥ 1).\n * @param height - Texture height in texels (≥ 1).\n * @param options - See {@link GLFloatTextureOptions}.\n * @returns The new {@link GLTexture}.\n */\nexport function createFloatTexture(engine: GLEngineContext, data: ArrayBufferView | null, width: number, height: number, options?: GLFloatTextureOptions): GLTexture {\n const gl = engine.gl;\n const o = options ?? {};\n const format = o.format ?? gl.RGBA;\n const type = o.type ?? gl.HALF_FLOAT;\n // Precompute the sized float internalFormat HERE and pass it through, so\n // `createRawTexture`'s inline LDR resolver is bypassed and the float table\n // stays out of byte-only bundles.\n const internalFormat = pickSizedInternalFormat(gl, format, type);\n return createRawTexture(engine, data, width, height, format, type, { ...o, internalFormat });\n}\n\n/** Generate the mip chain for a texture from its level-0 contents — mipmaps as\n * an explicit opt-in function rather than baked into the create path. Binds for\n * upload (unit 0). No-op on a lost/disposed context or a handle-less texture. */\nexport function generateTextureMipMaps(engine: GLEngineContext, tex: GLTexture): void {\n if (engine._isLost || engine._disposed || tex._disposed || tex.handle === null) {\n return;\n }\n bindTextureForUpload(engine, tex.handle);\n engine.gl.generateMipmap(engine.gl.TEXTURE_2D);\n}\n\n/**\n * Re-upload the pixel data (and optionally resize) of a texture created by\n * {@link createRawTexture} — the lite-gl equivalent of Babylon's\n * `updateRawTexture` / `_uploadDataToTextureDirectly`. Goes through the same\n * upload closure used by context-restore, so the new contents survive a context\n * loss. No-op on a lost/disposed/non-raw texture.\n *\n * @param engine - The engine.\n * @param tex - The raw texture to update.\n * @param data - New pixel data (must match the original `format`/`type`).\n * @param options - Optional new `width`/`height` (default: unchanged) and\n * `unpackAlignment` (default 4).\n */\nexport function updateRawTexture(\n engine: GLEngineContext,\n tex: GLTexture,\n data: ArrayBufferView | null,\n options?: { width?: number; height?: number; unpackAlignment?: number }\n): void {\n if (engine._isLost || engine._disposed || tex._disposed || tex._updateRaw === undefined) {\n return;\n }\n const o = options ?? {};\n tex._updateRaw(engine, data, o.width ?? tex.width, o.height ?? tex.height, o.unpackAlignment ?? 4);\n}\n\n/** Update a texture's min/mag sampling filters — the lite-gl equivalent of\n * Babylon's `updateTextureSamplingMode`. Binds for upload (unit 0) so the\n * `texParameteri` lands on this texture. No-op on a lost/disposed context. */\nexport function updateTextureSamplingMode(engine: GLEngineContext, tex: GLTexture, minFilter: GLenum, magFilter: GLenum): void {\n if (engine._isLost || engine._disposed || tex._disposed) {\n return;\n }\n const gl = engine.gl;\n bindTextureForUpload(engine, tex.handle);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);\n}\n\n/** Update a texture's S/T wrap modes (`gl.CLAMP_TO_EDGE` / `gl.REPEAT` /\n * `gl.MIRRORED_REPEAT`) — the lite-gl equivalent of Babylon's\n * `updateTextureWrappingMode`. No-op on a lost/disposed context. */\nexport function updateTextureWrapMode(engine: GLEngineContext, tex: GLTexture, wrapS: GLenum, wrapT: GLenum): void {\n if (engine._isLost || engine._disposed || tex._disposed) {\n return;\n }\n const gl = engine.gl;\n bindTextureForUpload(engine, tex.handle);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);\n}\n\n/**\n * Wrap an existing raw `WebGLTexture` (e.g. one created by a host renderer or a\n * previous engine) as a {@link GLTexture} — the lite-gl equivalent of\n * ShapeBuilder's `createTextureGraphicsResourceFromExternalWebGLTexture`.\n *\n * The wrapper does NOT own the underlying handle's upload — it is NOT registered\n * for context-restore replay (the external owner is responsible for that) and is\n * marked ready immediately. `disposeTexture` will still `gl.deleteTexture` it, so\n * only wrap a handle whose deletion you intend lite-gl to manage.\n *\n * @param engine - The engine.\n * @param handle - The external `WebGLTexture`.\n * @param width - Texture width in texels.\n * @param height - Texture height in texels.\n * @param options - Optional sampling/wrap to apply once (min/mag/wrapS/wrapT).\n * @returns A {@link GLTexture} wrapping the handle.\n */\nexport function createTextureFromHandle(engine: GLEngineContext, handle: WebGLTexture, width: number, height: number, options?: GLTextureOptions): GLTexture {\n const tex: GLTexture = {\n handle,\n target: engine.gl.TEXTURE_2D,\n width,\n height,\n isReady: true,\n _disposed: false,\n _refCount: 1,\n // External handle — restore replay is the external owner's job.\n _upload: () => {},\n _wasReady: true,\n };\n if (options !== undefined) {\n const gl = engine.gl;\n bindTextureForUpload(engine, handle);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, options.minFilter ?? gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, options.magFilter ?? gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, options.wrapS ?? gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, options.wrapT ?? gl.CLAMP_TO_EDGE);\n }\n return tex;\n}\n\n/** Asynchronous image upload.The returned texture is immediately usable (1×1\n * transparent placeholder); `isReady` flips true once the image has been\n * decoded and uploaded. The decoded `ImageBitmap` is retained on the texture\n * for offline-safe `webglcontextrestored` replay. */\nexport function loadTexture2D(engine: GLEngineContext, url: string, options?: GLTextureOptions, onLoad?: (tex: GLTexture) => void, onError?: (err: Error) => void): GLTexture {\n const gl = engine.gl;\n const handle = gl.createTexture();\n if (handle === null) {\n throw new Error(\"lite-gl: gl.createTexture returned null\");\n }\n const opts = options ?? {};\n const minFilter = opts.minFilter ?? gl.LINEAR;\n const magFilter = opts.magFilter ?? gl.LINEAR;\n const wrapS = opts.wrapS ?? gl.CLAMP_TO_EDGE;\n const wrapT = opts.wrapT ?? gl.CLAMP_TO_EDGE;\n const invertY = opts.invertY ?? false;\n\n let bitmap: ImageBitmap | null = null;\n const placeholderPixels = new Uint8Array([0, 0, 0, 0]);\n\n const upload = (target: GLEngineContext): void => {\n const g = target.gl;\n // invertY is applied at decode time via createImageBitmap({ imageOrientation })\n // because UNPACK_FLIP_Y_WEBGL is IGNORED for ImageBitmap sources (and the 1×1\n // placeholder is flip-invariant), so keep flip + premultiply off here.\n setUnpackState(target, false, false);\n bindTextureForUpload(target, tex.handle);\n if (bitmap !== null) {\n g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, bitmap);\n tex.width = bitmap.width;\n tex.height = bitmap.height;\n } else {\n g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, 1, 1, 0, g.RGBA, g.UNSIGNED_BYTE, placeholderPixels);\n }\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MIN_FILTER, minFilter);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MAG_FILTER, magFilter);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_S, wrapS);\n g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_T, wrapT);\n };\n\n const tex: GLTexture = {\n handle,\n target: gl.TEXTURE_2D,\n width: 1,\n height: 1,\n isReady: false,\n _disposed: false,\n _refCount: 1,\n _upload: upload,\n _wasReady: false,\n };\n // Placeholder upload — makes the texture sampleable before the real image arrives.\n upload(engine);\n engine._textures.push(tex);\n\n // Fetch + decode the real image. Re-uploads via the same closure once the\n // bitmap is in hand (so context-restore replay sees the real image too).\n fetch(url)\n .then((r) => {\n if (!r.ok) {\n throw new Error(`lite-gl: fetch ${url} -> HTTP ${r.status}`);\n }\n return r.blob();\n })\n .then((blob) => createImageBitmap(blob, { premultiplyAlpha: \"none\", imageOrientation: invertY ? \"flipY\" : \"none\" }))\n .then((bm) => {\n if (tex._disposed) {\n bm.close();\n return;\n }\n bitmap = bm;\n // If the context is lost mid-flight, defer the upload — the restore\n // handler will call _upload again, which will then see `bitmap !== null`\n // and replay the real image.\n if (!engine._isLost) {\n upload(engine);\n tex.isReady = true;\n }\n tex._wasReady = true;\n if (onLoad !== undefined) {\n onLoad(tex);\n }\n })\n .catch((err: unknown) => {\n const e = err instanceof Error ? err : new Error(String(err));\n if (onError !== undefined) {\n onError(e);\n } else {\n console.error(\"lite-gl: loadTexture2D failed\", e);\n }\n });\n\n return tex;\n}\n\n/** Cached bind. Skips `gl.activeTexture` and/or `gl.bindTexture` when nothing\n * changes. No-op when `tex._disposed` or `engine._isLost`. */\nexport function bindTexture(engine: GLEngineContext, unit: number, tex: GLTexture | null): void {\n if (engine._isLost || engine._disposed) {\n return;\n }\n if (tex !== null && tex._disposed) {\n return;\n }\n bindTextureRaw(engine, unit, tex === null ? null : tex.handle);\n}\n\n/** @internal — for callers that already hold a raw `WebGLTexture`. Not part of\n * the public API: `bindTexture` (public) and the texture `_upload` closures bind\n * through the cache, so consumers never call this directly. */\nexport function bindTextureRaw(engine: GLEngineContext, unit: number, handle: WebGLTexture | null): void {\n const s = engine._state;\n const gl = engine.gl;\n if (s.boundTextures[unit] === handle) {\n return;\n }\n if (s.activeTextureUnit !== unit) {\n gl.activeTexture(gl.TEXTURE0 + unit);\n s.activeTextureUnit = unit;\n }\n gl.bindTexture(gl.TEXTURE_2D, handle);\n s.boundTextures[unit] = handle;\n}\n\n/** @internal Bind `handle` on texture unit 0 **for an upload** (`texImage2D`).\n * Unlike {@link bindTextureRaw} — which elides the entire bind when the handle is\n * already bound on the unit (correct for *sampling*, where the active unit is\n * irrelevant) — an upload writes into the texture on the ACTIVE unit. A prior\n * multi-sampler draw may have left a non-zero unit active while this handle is\n * still bound on unit 0, so we must force unit 0 active even on a bind cache-hit,\n * keeping the `_state` cache coherent. */\nexport function bindTextureForUpload(engine: GLEngineContext, handle: WebGLTexture): void {\n const s = engine._state;\n const gl = engine.gl;\n if (s.activeTextureUnit !== 0) {\n gl.activeTexture(gl.TEXTURE0);\n s.activeTextureUnit = 0;\n }\n if (s.boundTextures[0] !== handle) {\n gl.bindTexture(gl.TEXTURE_2D, handle);\n s.boundTextures[0] = handle;\n }\n}\n\n/** Disposes the texture. Walks `_state.boundTextures` and clears every slot\n * that still references the handle — otherwise a later `bindTexture(unit, B)`\n * to the same unit would be wrongly elided when slot still showed handle A. */\nexport function disposeTexture(engine: GLEngineContext, tex: GLTexture): void {\n if (tex._disposed) {\n return;\n }\n if (tex._refCount > 1) {\n tex._refCount--;\n return;\n }\n tex._disposed = true;\n const i = engine._textures.indexOf(tex);\n if (i !== -1) {\n engine._textures.splice(i, 1);\n }\n if (!engine._isLost && !engine._disposed) {\n engine.gl.deleteTexture(tex.handle);\n }\n const bound = engine._state.boundTextures;\n for (let u = 0; u < bound.length; u++) {\n if (bound[u] === tex.handle) {\n bound[u] = null;\n }\n }\n}\n\n/** Internal — resolve the sized internalFormat for the LDR (byte) `texImage2D`\n * paths ONLY: RGBA→RGBA8, RGB→RGB8, RG→RG8, RED→R8, LUMINANCE passthrough.\n * Deliberately knows nothing about FLOAT / HALF_FLOAT so the float-format table\n * in {@link pickSizedInternalFormat} tree-shakes out of byte-only bundles.\n * @internal */\nfunction resolveLdrInternalFormat(gl: WebGL2RenderingContext, format: GLenum, type: GLenum): GLenum {\n if (type === gl.UNSIGNED_BYTE) {\n if (format === gl.RGBA) {\n return gl.RGBA8;\n }\n if (format === gl.RGB) {\n return gl.RGB8;\n }\n if (format === gl.RG) {\n return gl.RG8;\n }\n if (format === gl.RED) {\n return gl.R8;\n }\n if (format === gl.LUMINANCE) {\n return gl.LUMINANCE;\n }\n }\n return format;\n}\n\n/** Internal — pick a sized internalFormat for `texImage2D`. WebGL2 prefers\n * sized formats for non-color-renderable / non-readback paths; for the\n * NeonBrush use cases (sample-only) the unsized format works too, but sized\n * is more portable. Shared with the render-target module.\n * @internal */\nexport function pickSizedInternalFormat(gl: WebGL2RenderingContext, format: GLenum, type: GLenum): GLenum {\n if (type === gl.UNSIGNED_BYTE) {\n if (format === gl.RGBA) {\n return gl.RGBA8;\n }\n if (format === gl.RGB) {\n return gl.RGB8;\n }\n if (format === gl.LUMINANCE) {\n return gl.LUMINANCE;\n }\n }\n if (type === gl.FLOAT) {\n if (format === gl.RGBA) {\n return gl.RGBA32F;\n }\n if (format === gl.RGB) {\n return gl.RGB32F;\n }\n }\n if (type === gl.HALF_FLOAT) {\n if (format === gl.RGBA) {\n return gl.RGBA16F;\n }\n if (format === gl.RGB) {\n return gl.RGB16F;\n }\n }\n return format;\n}\n"]}