@flighthq/render-gl 0.1.0 → 0.2.1-next.410.a23f189
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/dist/glCompressedTexture.d.ts +8 -0
- package/dist/glCompressedTexture.d.ts.map +1 -0
- package/dist/glCompressedTexture.js +270 -0
- package/dist/glCompressedTexture.js.map +1 -0
- package/dist/glDraw.d.ts +7 -2
- package/dist/glDraw.d.ts.map +1 -1
- package/dist/glDraw.js +260 -35
- package/dist/glDraw.js.map +1 -1
- package/dist/glFullscreenPass.d.ts.map +1 -1
- package/dist/glFullscreenPass.js +32 -0
- package/dist/glFullscreenPass.js.map +1 -1
- package/dist/glLinearToSrgbPass.d.ts +4 -0
- package/dist/glLinearToSrgbPass.d.ts.map +1 -0
- package/dist/glLinearToSrgbPass.js +42 -0
- package/dist/glLinearToSrgbPass.js.map +1 -0
- package/dist/glPresentRenderTarget.d.ts +3 -0
- package/dist/glPresentRenderTarget.d.ts.map +1 -0
- package/dist/glPresentRenderTarget.js +35 -0
- package/dist/glPresentRenderTarget.js.map +1 -0
- package/dist/glRenderPass.d.ts +5 -0
- package/dist/glRenderPass.d.ts.map +1 -0
- package/dist/glRenderPass.js +130 -0
- package/dist/glRenderPass.js.map +1 -0
- package/dist/glRenderState.d.ts +1 -1
- package/dist/glRenderState.d.ts.map +1 -1
- package/dist/glRenderState.js +5 -2
- package/dist/glRenderState.js.map +1 -1
- package/dist/glRenderTarget.d.ts +2 -15
- package/dist/glRenderTarget.d.ts.map +1 -1
- package/dist/glRenderTarget.js +48 -57
- package/dist/glRenderTarget.js.map +1 -1
- package/dist/glRenderTargetPool.d.ts.map +1 -1
- package/dist/glRenderTargetPool.js +11 -0
- package/dist/glRenderTargetPool.js.map +1 -1
- package/dist/glSkinPaletteTexture.d.ts +5 -0
- package/dist/glSkinPaletteTexture.d.ts.map +1 -0
- package/dist/glSkinPaletteTexture.js +42 -0
- package/dist/glSkinPaletteTexture.js.map +1 -0
- package/dist/glTestHelper.d.ts.map +1 -1
- package/dist/glTestHelper.js +1 -0
- package/dist/glTestHelper.js.map +1 -1
- package/dist/glTextureUpload.d.ts +5 -0
- package/dist/glTextureUpload.d.ts.map +1 -0
- package/dist/glTextureUpload.js +27 -0
- package/dist/glTextureUpload.js.map +1 -0
- package/dist/glTextureVideoUpload.d.ts +3 -0
- package/dist/glTextureVideoUpload.d.ts.map +1 -0
- package/dist/glTextureVideoUpload.js +24 -0
- package/dist/glTextureVideoUpload.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +10 -5
- package/src/glBackground.test.ts +3 -1
- package/src/glCompressedTexture.test.ts +276 -0
- package/src/glDraw.test.ts +449 -4
- package/src/glFullscreenPass.test.ts +22 -1
- package/src/glLinearToSrgbPass.test.ts +75 -0
- package/src/glPresentRenderTarget.test.ts +62 -0
- package/src/glReadback.test.ts +1 -0
- package/src/glRenderPass.test.ts +170 -0
- package/src/glRenderTarget.test.ts +63 -98
- package/src/glRenderTargetPool.test.ts +27 -0
- package/src/glSkinPaletteTexture.test.ts +129 -0
- package/src/glTextureUpload.test.ts +49 -0
- package/src/glTextureVideoUpload.test.ts +53 -0
package/dist/glTestHelper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glTestHelper.js","sourceRoot":"","sources":["../src/glTestHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAG7D,MAAM,UAAU,aAAa,CAAC,OAAsE;IAMlG,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC;IACnB,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAC9B,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,IAAI;QAC/C,mBAAmB,EAAE,OAAO,EAAE,mBAAmB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KAClE,CAAkB,CAAC;IAEpB,4CAA4C;IAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QACnB,MAAM;QACN,EAAE;QACF,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;IAEH,iGAAiG;IACjG,yDAAyD;IACzD,MAAM,OAAO,GAAG,0BAA0B,EAAE,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;QACrB,gBAAgB,EAAE,IAAI;QACtB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE,CAAC;QACnB,cAAc,EAAE,IAAI;QACpB,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,IAAI;QACpB,oBAAoB,EAAE,IAAI;QAC1B,YAAY,EAAE,IAAI,OAAO,EAAmC;QAC5D,SAAS;QACT,mBAAmB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;QACxF,gBAAgB,EAAE,EAAiB;QACnC,eAAe,EAAE,EAAiB;QAClC,cAAc,EAAE,IAAI,YAAY,CAAC,EAAE,CAAC;QACpC,WAAW,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC;QAChC,YAAY,EAAE,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,oBAAoB,EAAE,IAAI;QAC1B,gBAAgB,EAAE,CAAC;QACnB,yBAAyB,EAAE,IAAI;QAC/B,uBAAuB,EAAE,IAAI,YAAY,CAAC,EAAE,GAAG,GAAG,CAAC;QACnD,kBAAkB,EAAE,IAAI;KACe,CAAC,CAAC;IAC3C,KAAK,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC;IAElC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC1C,CAAC;AAED,6EAA6E;AAC7E,uEAAuE;AACvE,mFAAmF;AACnF,MAAM,UAAU,MAAM;IACpB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAA2B,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,OAAO,EAAE,EAAkB;QAC3B,WAAW,EAAE,CAAC;QACd,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,EAA0B;QACrC,QAAQ,EAAE,EAA0B;QACpC,kBAAkB,EAAE,EAA0B;QAC9C,cAAc,EAAE,EAA0B;QAC1C,oBAAoB,EAAE,EAA0B;QAChD,UAAU,EAAE,EAA0B;KACvC,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"glTestHelper.js","sourceRoot":"","sources":["../src/glTestHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAG7D,MAAM,UAAU,aAAa,CAAC,OAAsE;IAMlG,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC;IACnB,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAC9B,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,IAAI;QAC/C,mBAAmB,EAAE,OAAO,EAAE,mBAAmB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KAClE,CAAkB,CAAC;IAEpB,4CAA4C;IAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QACnB,MAAM;QACN,EAAE;QACF,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;IAEH,iGAAiG;IACjG,yDAAyD;IACzD,MAAM,OAAO,GAAG,0BAA0B,EAAE,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;QACrB,gBAAgB,EAAE,IAAI;QACtB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE,CAAC;QACnB,cAAc,EAAE,IAAI;QACpB,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,IAAI;QACpB,oBAAoB,EAAE,IAAI;QAC1B,YAAY,EAAE,IAAI,OAAO,EAAmC;QAC5D,yBAAyB,EAAE,IAAI,OAAO,EAAE;QACxC,SAAS;QACT,mBAAmB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;QACxF,gBAAgB,EAAE,EAAiB;QACnC,eAAe,EAAE,EAAiB;QAClC,cAAc,EAAE,IAAI,YAAY,CAAC,EAAE,CAAC;QACpC,WAAW,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC;QAChC,YAAY,EAAE,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,oBAAoB,EAAE,IAAI;QAC1B,gBAAgB,EAAE,CAAC;QACnB,yBAAyB,EAAE,IAAI;QAC/B,uBAAuB,EAAE,IAAI,YAAY,CAAC,EAAE,GAAG,GAAG,CAAC;QACnD,kBAAkB,EAAE,IAAI;KACe,CAAC,CAAC;IAC3C,KAAK,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC;IAElC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC1C,CAAC;AAED,6EAA6E;AAC7E,uEAAuE;AACvE,mFAAmF;AACnF,MAAM,UAAU,MAAM;IACpB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAA2B,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,OAAO,EAAE,EAAkB;QAC3B,WAAW,EAAE,CAAC;QACd,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,EAA0B;QACrC,QAAQ,EAAE,EAA0B;QACpC,kBAAkB,EAAE,EAA0B;QAC9C,cAAc,EAAE,EAA0B;QAC1C,oBAAoB,EAAE,EAA0B;QAChD,UAAU,EAAE,EAA0B;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ImageResource } from '@flighthq/types';
|
|
2
|
+
export declare function uploadGlTextureData(gl: WebGL2RenderingContext, target: number, width: number, height: number, data: Readonly<Uint8ClampedArray<ArrayBuffer>>): void;
|
|
3
|
+
export declare function uploadGlTextureElement(gl: WebGL2RenderingContext, target: number, source: TexImageSource): void;
|
|
4
|
+
export declare function uploadGlTextureImageResource(gl: WebGL2RenderingContext, target: number, image: Readonly<ImageResource>): void;
|
|
5
|
+
//# sourceMappingURL=glTextureUpload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glTextureUpload.d.ts","sourceRoot":"","sources":["../src/glTextureUpload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWrD,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,sBAAsB,EAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,GAC7C,IAAI,CAYN;AAID,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,sBAAsB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAE/G;AAMD,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,sBAAsB,EAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAC7B,IAAI,CAGN"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Raw texel-upload primitives. Each writes level 0 of the texture currently bound at `target` — the GL
|
|
2
|
+
// enum for a 2D texture (gl.TEXTURE_2D) or a cube face (gl.TEXTURE_CUBE_MAP_POSITIVE_X + face). They set
|
|
3
|
+
// no sampler or pixel-store state: premultiply, wrap, and filter are the caller's policy applied around
|
|
4
|
+
// the call, so one primitive serves both the premultiplied 2D sprite path and the raw-radiance cube path.
|
|
5
|
+
// The caller owns creating and binding the texture and choosing the target.
|
|
6
|
+
// Uploads raw CPU pixels (rgba8, straight from a Surface's `data`) through the ArrayBufferView overload.
|
|
7
|
+
// The portable bedrock upload — no web types in the signature — so a native GL/Vulkan backend reimplements
|
|
8
|
+
// it 1:1. `width`/`height` are the pixel dimensions the data fills.
|
|
9
|
+
export function uploadGlTextureData(gl, target, width, height, data) {
|
|
10
|
+
gl.texImage2D(target, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
11
|
+
}
|
|
12
|
+
// Uploads a decoded DOM element (image, canvas, ImageBitmap, VideoFrame) through the TexImageSource
|
|
13
|
+
// overload — the web fast-path, a zero-CPU-copy GPU DMA. Absent on non-web hosts, which carry only `data`.
|
|
14
|
+
export function uploadGlTextureElement(gl, target, source) {
|
|
15
|
+
gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
|
|
16
|
+
}
|
|
17
|
+
// Dispatches an ImageResource to whichever representation it carries: the element fast-path when a decoded
|
|
18
|
+
// `source` is present, else the portable `data` path (a generated Surface). The seam that makes data-backed
|
|
19
|
+
// resources first-class — the same texture uploads whether it was loaded (element) or generated in memory
|
|
20
|
+
// (data). Assumes the resource has pixels in at least one form.
|
|
21
|
+
export function uploadGlTextureImageResource(gl, target, image) {
|
|
22
|
+
if (image.source !== null)
|
|
23
|
+
uploadGlTextureElement(gl, target, image.source);
|
|
24
|
+
else
|
|
25
|
+
uploadGlTextureData(gl, target, image.width, image.height, image.data);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=glTextureUpload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glTextureUpload.js","sourceRoot":"","sources":["../src/glTextureUpload.ts"],"names":[],"mappings":"AAEA,uGAAuG;AACvG,yGAAyG;AACzG,wGAAwG;AACxG,0GAA0G;AAC1G,4EAA4E;AAE5E,yGAAyG;AACzG,2GAA2G;AAC3G,oEAAoE;AACpE,MAAM,UAAU,mBAAmB,CACjC,EAA0B,EAC1B,MAAc,EACd,KAAa,EACb,MAAc,EACd,IAA8C;IAE9C,EAAE,CAAC,UAAU,CACX,MAAM,EACN,CAAC,EACD,EAAE,CAAC,IAAI,EACP,KAAK,EACL,MAAM,EACN,CAAC,EACD,EAAE,CAAC,IAAI,EACP,EAAE,CAAC,aAAa,EAChB,IAAsC,CACvC,CAAC;AACJ,CAAC;AAED,oGAAoG;AACpG,2GAA2G;AAC3G,MAAM,UAAU,sBAAsB,CAAC,EAA0B,EAAE,MAAc,EAAE,MAAsB;IACvG,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AACvE,CAAC;AAED,2GAA2G;AAC3G,4GAA4G;AAC5G,0GAA0G;AAC1G,gEAAgE;AAChE,MAAM,UAAU,4BAA4B,CAC1C,EAA0B,EAC1B,MAAc,EACd,KAA8B;IAE9B,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI;QAAE,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAwB,CAAC,CAAC;;QACzF,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAK,CAAC,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glTextureVideoUpload.d.ts","sourceRoot":"","sources":["../src/glTextureVideoUpload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAcpD,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,sBAAsB,EAC1B,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,EACpC,eAAe,EAAE,MAAM,GACtB,MAAM,CAUR"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { uploadGlTextureElement } from './glTextureUpload';
|
|
2
|
+
// The per-frame video-to-GPU upload path. A VideoTexture's backing HTMLVideoElement decodes new pixels
|
|
3
|
+
// continuously, so a driver re-uploads the currently-bound GL texture whenever the element's frame
|
|
4
|
+
// advances — but not on frames where nothing changed (a paused or stalled stream), which would waste a
|
|
5
|
+
// full-frame DMA. `uploadedFrameId` is the id the caller last uploaded; this compares it to the
|
|
6
|
+
// VideoTexture's `frameId` and re-uploads through the element fast-path only on a change, returning the
|
|
7
|
+
// id now on the GPU so the caller stores it for the next frame.
|
|
8
|
+
//
|
|
9
|
+
// The caller owns creating, binding, and setting sampler/pixel-store state on the texture; this writes
|
|
10
|
+
// level 0 at gl.TEXTURE_2D. Returns `uploadedFrameId` unchanged (no GL call) when the frame has not
|
|
11
|
+
// advanced or the element has no decoded frame yet, so it is safe to call every frame unconditionally.
|
|
12
|
+
export function uploadGlTextureVideoFrame(gl, videoTexture, uploadedFrameId) {
|
|
13
|
+
if (videoTexture.frameId === uploadedFrameId)
|
|
14
|
+
return uploadedFrameId;
|
|
15
|
+
const element = videoTexture.source.element;
|
|
16
|
+
// A first-frame guard: HAVE_CURRENT_DATA (2) with non-zero dimensions. texImage2D on an element with
|
|
17
|
+
// no decoded frame throws in some browsers, so skip until a frame exists and report no upload.
|
|
18
|
+
if (element === null || element.readyState < 2 || element.videoWidth <= 0 || element.videoHeight <= 0) {
|
|
19
|
+
return uploadedFrameId;
|
|
20
|
+
}
|
|
21
|
+
uploadGlTextureElement(gl, gl.TEXTURE_2D, element);
|
|
22
|
+
return videoTexture.frameId;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=glTextureVideoUpload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glTextureVideoUpload.js","sourceRoot":"","sources":["../src/glTextureVideoUpload.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,uGAAuG;AACvG,mGAAmG;AACnG,uGAAuG;AACvG,gGAAgG;AAChG,wGAAwG;AACxG,gEAAgE;AAChE,EAAE;AACF,uGAAuG;AACvG,oGAAoG;AACpG,uGAAuG;AACvG,MAAM,UAAU,yBAAyB,CACvC,EAA0B,EAC1B,YAAoC,EACpC,eAAuB;IAEvB,IAAI,YAAY,CAAC,OAAO,KAAK,eAAe;QAAE,OAAO,eAAe,CAAC;IACrE,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC;IAC5C,qGAAqG;IACrG,+FAA+F;IAC/F,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,IAAI,CAAC,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC;QACtG,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,sBAAsB,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,EAAE,OAAoC,CAAC,CAAC;IAChF,OAAO,YAAY,CAAC,OAAO,CAAC;AAC9B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
export * from './glBackground';
|
|
2
|
+
export * from './glCompressedTexture';
|
|
2
3
|
export * from './glDraw';
|
|
3
4
|
export * from './glElement';
|
|
4
5
|
export * from './glFullscreenPass';
|
|
6
|
+
export * from './glLinearToSrgbPass';
|
|
5
7
|
export * from './glMaterialRegistry';
|
|
8
|
+
export * from './glPresentRenderTarget';
|
|
6
9
|
export * from './glProgram';
|
|
7
10
|
export * from './glReadback';
|
|
11
|
+
export * from './glRenderPass';
|
|
8
12
|
export * from './glRenderState';
|
|
9
13
|
export * from './glRenderTarget';
|
|
10
14
|
export * from './glRenderTargetPool';
|
|
11
15
|
export * from './glShader';
|
|
12
16
|
export * from './glShaderBinding';
|
|
17
|
+
export * from './glSkinPaletteTexture';
|
|
18
|
+
export * from './glTextureUpload';
|
|
19
|
+
export * from './glTextureVideoUpload';
|
|
13
20
|
export type { GlRenderTarget } from '@flighthq/types';
|
|
14
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
export * from './glBackground';
|
|
2
|
+
export * from './glCompressedTexture';
|
|
2
3
|
export * from './glDraw';
|
|
3
4
|
export * from './glElement';
|
|
4
5
|
export * from './glFullscreenPass';
|
|
6
|
+
export * from './glLinearToSrgbPass';
|
|
5
7
|
export * from './glMaterialRegistry';
|
|
8
|
+
export * from './glPresentRenderTarget';
|
|
6
9
|
export * from './glProgram';
|
|
7
10
|
export * from './glReadback';
|
|
11
|
+
export * from './glRenderPass';
|
|
8
12
|
export * from './glRenderState';
|
|
9
13
|
export * from './glRenderTarget';
|
|
10
14
|
export * from './glRenderTargetPool';
|
|
11
15
|
export * from './glShader';
|
|
12
16
|
export * from './glShaderBinding';
|
|
17
|
+
export * from './glSkinPaletteTexture';
|
|
18
|
+
export * from './glTextureUpload';
|
|
19
|
+
export * from './glTextureVideoUpload';
|
|
13
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/render-gl",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.2.1-next.410.a23f189",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/flighthq/flight.git",
|
|
7
|
+
"directory": "packages/render-gl"
|
|
8
|
+
},
|
|
4
9
|
"type": "module",
|
|
5
10
|
"main": "dist/index.js",
|
|
6
11
|
"types": "dist/index.d.ts",
|
|
@@ -27,10 +32,10 @@
|
|
|
27
32
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
28
33
|
},
|
|
29
34
|
"dependencies": {
|
|
30
|
-
"@flighthq/displayobject": "0.1.
|
|
31
|
-
"@flighthq/geometry": "0.1.
|
|
32
|
-
"@flighthq/render": "0.1.
|
|
33
|
-
"@flighthq/types": "0.1.
|
|
35
|
+
"@flighthq/displayobject": "0.2.1-next.410.a23f189",
|
|
36
|
+
"@flighthq/geometry": "0.2.1-next.410.a23f189",
|
|
37
|
+
"@flighthq/render": "0.2.1-next.410.a23f189",
|
|
38
|
+
"@flighthq/types": "0.2.1-next.410.a23f189"
|
|
34
39
|
},
|
|
35
40
|
"devDependencies": {
|
|
36
41
|
"typescript": "^5.3.0"
|
package/src/glBackground.test.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { BlendMode } from '@flighthq/types';
|
|
2
|
+
|
|
1
3
|
import { renderGlBackground } from './glBackground';
|
|
2
4
|
import { getGlRenderStateRuntime } from './glRenderState';
|
|
3
5
|
import { createGlState } from './glTestHelper';
|
|
@@ -30,7 +32,7 @@ describe('renderGlBackground', () => {
|
|
|
30
32
|
it('resets currentBlendMode to null', () => {
|
|
31
33
|
const { state } = createGlState();
|
|
32
34
|
const runtime = getGlRenderStateRuntime(state);
|
|
33
|
-
runtime.currentBlendMode =
|
|
35
|
+
runtime.currentBlendMode = BlendMode.Add;
|
|
34
36
|
renderGlBackground(state);
|
|
35
37
|
expect(runtime.currentBlendMode).toBeNull();
|
|
36
38
|
});
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import type { GlCompressedTextureSupport, ImageResource, TextureContainer } from '@flighthq/types';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
detectGlCompressedTextureSupport,
|
|
5
|
+
getGlCompressedTextureFormat,
|
|
6
|
+
hasGlCompressedTextureFormat,
|
|
7
|
+
registerGlCompressedTextureDecoder,
|
|
8
|
+
registerGlCompressedTextureUpload,
|
|
9
|
+
uploadGlCompressedTextureContainer,
|
|
10
|
+
} from './glCompressedTexture';
|
|
11
|
+
import { getGlRenderStateRuntime } from './glRenderState';
|
|
12
|
+
import { createGlState } from './glTestHelper';
|
|
13
|
+
|
|
14
|
+
// The subset of extension enum constants the tests exercise (BC3 via s3tc, ASTC 4x4).
|
|
15
|
+
const S3TC_EXT = { COMPRESSED_RGBA_S3TC_DXT5_EXT: 0x83f3 };
|
|
16
|
+
const ASTC_EXT = { COMPRESSED_RGBA_ASTC_4x4_KHR: 0x93b0 };
|
|
17
|
+
|
|
18
|
+
// A WebGL2 mock whose getExtension returns only the named extension objects; every other extension
|
|
19
|
+
// resolves to null so a format outside the supported set maps to -1.
|
|
20
|
+
function makeGl(available: Readonly<Record<string, Record<string, number>>>): WebGL2RenderingContext {
|
|
21
|
+
return {
|
|
22
|
+
RGBA: 0x1908,
|
|
23
|
+
UNSIGNED_BYTE: 0x1401,
|
|
24
|
+
TEXTURE_2D: 0x0de1,
|
|
25
|
+
TEXTURE_2D_ARRAY: 0x8c1a,
|
|
26
|
+
TEXTURE_CUBE_MAP_POSITIVE_X: 0x8515,
|
|
27
|
+
getExtension: vi.fn((name: string) => available[name] ?? null),
|
|
28
|
+
compressedTexImage2D: vi.fn(),
|
|
29
|
+
compressedTexSubImage3D: vi.fn(),
|
|
30
|
+
texStorage3D: vi.fn(),
|
|
31
|
+
texImage2D: vi.fn(),
|
|
32
|
+
} as unknown as WebGL2RenderingContext;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function makeContainer(): TextureContainer {
|
|
36
|
+
return {
|
|
37
|
+
format: 'bc3',
|
|
38
|
+
width: 4,
|
|
39
|
+
height: 4,
|
|
40
|
+
depth: 1,
|
|
41
|
+
mipLevels: 1,
|
|
42
|
+
layers: 1,
|
|
43
|
+
faces: 1,
|
|
44
|
+
supercompression: 'None',
|
|
45
|
+
levels: [{ byteOffset: 0, byteLength: 16, width: 4, height: 4 }],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// A compressed-only ImageResource wrapping makeContainer, for exercising the installed upload seam.
|
|
50
|
+
function uploadableCompressedImage(): ImageResource {
|
|
51
|
+
return {
|
|
52
|
+
source: null,
|
|
53
|
+
data: null,
|
|
54
|
+
compressed: { container: makeContainer(), payload: new Uint8Array(16) },
|
|
55
|
+
width: 4,
|
|
56
|
+
height: 4,
|
|
57
|
+
version: 1,
|
|
58
|
+
alphaType: 'straight',
|
|
59
|
+
} as unknown as ImageResource;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('detectGlCompressedTextureSupport', () => {
|
|
63
|
+
it('reports a family true only when its extension resolves', () => {
|
|
64
|
+
const gl = makeGl({ WEBGL_compressed_texture_astc: ASTC_EXT });
|
|
65
|
+
const support = detectGlCompressedTextureSupport(gl);
|
|
66
|
+
expect(support.astc).toBe(true);
|
|
67
|
+
expect(support.s3tc).toBe(false);
|
|
68
|
+
expect(support.bptc).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('requires both s3tc and s3tc_srgb for the s3tc flag', () => {
|
|
72
|
+
const onlyBase = detectGlCompressedTextureSupport(makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT }));
|
|
73
|
+
expect(onlyBase.s3tc).toBe(false);
|
|
74
|
+
const both = detectGlCompressedTextureSupport(
|
|
75
|
+
makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT, WEBGL_compressed_texture_s3tc_srgb: {} }),
|
|
76
|
+
);
|
|
77
|
+
expect(both.s3tc).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('getGlCompressedTextureFormat', () => {
|
|
82
|
+
it('resolves the GL enum from the live extension object', () => {
|
|
83
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
84
|
+
expect(getGlCompressedTextureFormat(gl, 'bc3')).toBe(0x83f3);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('returns -1 when the extension is absent', () => {
|
|
88
|
+
const gl = makeGl({});
|
|
89
|
+
expect(getGlCompressedTextureFormat(gl, 'bc3')).toBe(-1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('returns -1 for uncompressed and Basis-intermediate formats', () => {
|
|
93
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
94
|
+
expect(getGlCompressedTextureFormat(gl, 'rgba8unorm')).toBe(-1);
|
|
95
|
+
expect(getGlCompressedTextureFormat(gl, 'etc1s')).toBe(-1);
|
|
96
|
+
expect(getGlCompressedTextureFormat(gl, 'uastc')).toBe(-1);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('hasGlCompressedTextureFormat', () => {
|
|
101
|
+
const support: GlCompressedTextureSupport = {
|
|
102
|
+
astc: true,
|
|
103
|
+
bptc: false,
|
|
104
|
+
etc: false,
|
|
105
|
+
pvrtc: false,
|
|
106
|
+
rgtc: false,
|
|
107
|
+
s3tc: true,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
it('maps a format to its family flag, including the srgb twin', () => {
|
|
111
|
+
expect(hasGlCompressedTextureFormat(support, 'bc3')).toBe(true);
|
|
112
|
+
expect(hasGlCompressedTextureFormat(support, 'bc3Srgb')).toBe(true);
|
|
113
|
+
expect(hasGlCompressedTextureFormat(support, 'astc8x8')).toBe(true);
|
|
114
|
+
expect(hasGlCompressedTextureFormat(support, 'bc7')).toBe(false);
|
|
115
|
+
expect(hasGlCompressedTextureFormat(support, 'etc2Rgb')).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('is false for a non-compressed format', () => {
|
|
119
|
+
expect(hasGlCompressedTextureFormat(support, 'rgba8unorm')).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('registerGlCompressedTextureDecoder', () => {
|
|
124
|
+
it('installs the decoder on the render-state runtime and clears it with null', () => {
|
|
125
|
+
const { state } = createGlState();
|
|
126
|
+
const decode = vi.fn(() => new Uint8ClampedArray(4));
|
|
127
|
+
registerGlCompressedTextureDecoder(state, decode);
|
|
128
|
+
expect(getGlRenderStateRuntime(state).compressedTextureDecoder).toBe(decode);
|
|
129
|
+
registerGlCompressedTextureDecoder(state, null);
|
|
130
|
+
expect(getGlRenderStateRuntime(state).compressedTextureDecoder).toBeNull();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('registerGlCompressedTextureUpload', () => {
|
|
135
|
+
it('installs the compressed upload seam on the render-state runtime and clears it with null', () => {
|
|
136
|
+
const { state } = createGlState();
|
|
137
|
+
registerGlCompressedTextureUpload(state);
|
|
138
|
+
expect(getGlRenderStateRuntime(state).compressedTextureUpload).toBeTypeOf('function');
|
|
139
|
+
registerGlCompressedTextureUpload(state, null);
|
|
140
|
+
expect(getGlRenderStateRuntime(state).compressedTextureUpload).toBeNull();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('uploads a compressed-only ImageResource once installed, threading the registered decoder', () => {
|
|
144
|
+
const { state, gl } = createGlState();
|
|
145
|
+
const rgba = new Uint8ClampedArray(4 * 4 * 4);
|
|
146
|
+
const decode = vi.fn(() => rgba);
|
|
147
|
+
registerGlCompressedTextureUpload(state);
|
|
148
|
+
registerGlCompressedTextureDecoder(state, decode);
|
|
149
|
+
const uploader = getGlRenderStateRuntime(state).compressedTextureUpload!;
|
|
150
|
+
const ok = uploader(gl, uploadableCompressedImage(), decode);
|
|
151
|
+
expect(ok).toBe(true);
|
|
152
|
+
expect(decode).toHaveBeenCalledWith('bc3', 4, 4, expect.any(Uint8Array));
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('reports false for a resource with no compressed payload', () => {
|
|
156
|
+
const { state, gl } = createGlState();
|
|
157
|
+
registerGlCompressedTextureUpload(state);
|
|
158
|
+
const uploader = getGlRenderStateRuntime(state).compressedTextureUpload!;
|
|
159
|
+
const plain = { source: null, data: null, compressed: null } as unknown as ImageResource;
|
|
160
|
+
expect(uploader(gl, plain, null)).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe('uploadGlCompressedTextureContainer', () => {
|
|
165
|
+
it('drives compressedTexImage2D per level on the native path', () => {
|
|
166
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
167
|
+
const payload = new Uint8Array(16);
|
|
168
|
+
const ok = uploadGlCompressedTextureContainer(gl, makeContainer(), payload);
|
|
169
|
+
expect(ok).toBe(true);
|
|
170
|
+
expect(gl.compressedTexImage2D).toHaveBeenCalledTimes(1);
|
|
171
|
+
expect(gl.compressedTexImage2D).toHaveBeenCalledWith(gl.TEXTURE_2D, 0, 0x83f3, 4, 4, 0, expect.any(Uint8Array));
|
|
172
|
+
expect(gl.texImage2D).not.toHaveBeenCalled();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('decodes to RGBA and uploads via texImage2D when native support is missing', () => {
|
|
176
|
+
const gl = makeGl({});
|
|
177
|
+
const payload = new Uint8Array(16);
|
|
178
|
+
const rgba = new Uint8ClampedArray(4 * 4 * 4);
|
|
179
|
+
const decode = vi.fn(() => rgba);
|
|
180
|
+
const ok = uploadGlCompressedTextureContainer(gl, makeContainer(), payload, decode);
|
|
181
|
+
expect(ok).toBe(true);
|
|
182
|
+
expect(decode).toHaveBeenCalledWith('bc3', 4, 4, expect.any(Uint8Array));
|
|
183
|
+
expect(gl.texImage2D).toHaveBeenCalledWith(gl.TEXTURE_2D, 0, gl.RGBA, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, rgba);
|
|
184
|
+
expect(gl.compressedTexImage2D).not.toHaveBeenCalled();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('returns false when neither native support nor a decoder is available', () => {
|
|
188
|
+
const gl = makeGl({});
|
|
189
|
+
expect(uploadGlCompressedTextureContainer(gl, makeContainer(), new Uint8Array(16))).toBe(false);
|
|
190
|
+
expect(gl.compressedTexImage2D).not.toHaveBeenCalled();
|
|
191
|
+
expect(gl.texImage2D).not.toHaveBeenCalled();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('returns false when the decoder cannot handle the format', () => {
|
|
195
|
+
const gl = makeGl({});
|
|
196
|
+
const decode = vi.fn(() => null);
|
|
197
|
+
expect(uploadGlCompressedTextureContainer(gl, makeContainer(), new Uint8Array(16), decode)).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('slices each level from the payload at its byte range', () => {
|
|
201
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
202
|
+
const container: TextureContainer = {
|
|
203
|
+
...makeContainer(),
|
|
204
|
+
mipLevels: 2,
|
|
205
|
+
levels: [
|
|
206
|
+
{ byteOffset: 0, byteLength: 16, width: 4, height: 4 },
|
|
207
|
+
{ byteOffset: 16, byteLength: 8, width: 2, height: 2 },
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
const payload = new Uint8Array(24);
|
|
211
|
+
uploadGlCompressedTextureContainer(gl, container, payload);
|
|
212
|
+
expect(gl.compressedTexImage2D).toHaveBeenCalledTimes(2);
|
|
213
|
+
const secondCall = (gl.compressedTexImage2D as ReturnType<typeof vi.fn>).mock.calls[1];
|
|
214
|
+
const view = secondCall[6] as Uint8Array;
|
|
215
|
+
expect(view.byteOffset).toBe(16);
|
|
216
|
+
expect(view.byteLength).toBe(8);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('returns false without uploading when the container is still supercompressed', () => {
|
|
220
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
221
|
+
const container: TextureContainer = { ...makeContainer(), supercompression: 'Zstd' };
|
|
222
|
+
expect(uploadGlCompressedTextureContainer(gl, container, new Uint8Array(16))).toBe(false);
|
|
223
|
+
expect(gl.compressedTexImage2D).not.toHaveBeenCalled();
|
|
224
|
+
expect(gl.texImage2D).not.toHaveBeenCalled();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('targets each cube face from the flat mip+face index', () => {
|
|
228
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
229
|
+
// A single-mip cubemap: six faces, flat index === face since mipLevels === 1.
|
|
230
|
+
const levels = Array.from({ length: 6 }, (_unused, face) => ({
|
|
231
|
+
byteOffset: face * 16,
|
|
232
|
+
byteLength: 16,
|
|
233
|
+
width: 4,
|
|
234
|
+
height: 4,
|
|
235
|
+
}));
|
|
236
|
+
const container: TextureContainer = { ...makeContainer(), faces: 6, levels };
|
|
237
|
+
uploadGlCompressedTextureContainer(gl, container, new Uint8Array(6 * 16));
|
|
238
|
+
expect(gl.compressedTexImage2D).toHaveBeenCalledTimes(6);
|
|
239
|
+
const calls = (gl.compressedTexImage2D as ReturnType<typeof vi.fn>).mock.calls;
|
|
240
|
+
for (let face = 0; face < 6; face += 1) {
|
|
241
|
+
expect(calls[face][0]).toBe(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face);
|
|
242
|
+
expect(calls[face][1]).toBe(0);
|
|
243
|
+
}
|
|
244
|
+
expect(gl.texStorage3D).not.toHaveBeenCalled();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('allocates immutable storage once and sub-uploads each layer of an array into TEXTURE_2D_ARRAY', () => {
|
|
248
|
+
const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
|
|
249
|
+
// A single-mip, two-layer array (layer-major): flat index 0 = layer 0, index 1 = layer 1.
|
|
250
|
+
const container: TextureContainer = {
|
|
251
|
+
...makeContainer(),
|
|
252
|
+
layers: 2,
|
|
253
|
+
levels: [
|
|
254
|
+
{ byteOffset: 0, byteLength: 16, width: 4, height: 4 },
|
|
255
|
+
{ byteOffset: 16, byteLength: 16, width: 4, height: 4 },
|
|
256
|
+
],
|
|
257
|
+
};
|
|
258
|
+
uploadGlCompressedTextureContainer(gl, container, new Uint8Array(32));
|
|
259
|
+
expect(gl.texStorage3D).toHaveBeenCalledTimes(1);
|
|
260
|
+
expect(gl.texStorage3D).toHaveBeenCalledWith(gl.TEXTURE_2D_ARRAY, 1, 0x83f3, 4, 4, 2);
|
|
261
|
+
expect(gl.compressedTexSubImage3D).toHaveBeenCalledTimes(2);
|
|
262
|
+
const subCalls = (gl.compressedTexSubImage3D as ReturnType<typeof vi.fn>).mock.calls;
|
|
263
|
+
expect(subCalls[0][4]).toBe(0);
|
|
264
|
+
expect(subCalls[1][4]).toBe(1);
|
|
265
|
+
expect(gl.compressedTexImage2D).not.toHaveBeenCalled();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('returns false for a cubemap the device cannot upload natively (no face-by-face decode)', () => {
|
|
269
|
+
const gl = makeGl({});
|
|
270
|
+
const container: TextureContainer = { ...makeContainer(), faces: 6 };
|
|
271
|
+
const decode = vi.fn(() => new Uint8ClampedArray(4 * 4 * 4));
|
|
272
|
+
expect(uploadGlCompressedTextureContainer(gl, container, new Uint8Array(6 * 16), decode)).toBe(false);
|
|
273
|
+
expect(decode).not.toHaveBeenCalled();
|
|
274
|
+
expect(gl.texImage2D).not.toHaveBeenCalled();
|
|
275
|
+
});
|
|
276
|
+
});
|