@flighthq/render-gl 0.3.0 → 0.3.1-next.1050.9114695

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 (50) hide show
  1. package/dist/enableGlRenderStateGuards.d.ts.map +1 -1
  2. package/dist/enableGlRenderStateGuards.js +12 -3
  3. package/dist/enableGlRenderStateGuards.js.map +1 -1
  4. package/dist/explainGlTextureResolution.d.ts.map +1 -1
  5. package/dist/explainGlTextureResolution.js +4 -1
  6. package/dist/explainGlTextureResolution.js.map +1 -1
  7. package/dist/glCompressedTexture.d.ts.map +1 -1
  8. package/dist/glCompressedTexture.js +13 -2
  9. package/dist/glCompressedTexture.js.map +1 -1
  10. package/dist/glDraw.d.ts.map +1 -1
  11. package/dist/glDraw.js +21 -14
  12. package/dist/glDraw.js.map +1 -1
  13. package/dist/glFullscreenPass.d.ts.map +1 -1
  14. package/dist/glFullscreenPass.js +2 -1
  15. package/dist/glFullscreenPass.js.map +1 -1
  16. package/dist/glMaterialRegistry.d.ts.map +1 -1
  17. package/dist/glMaterialRegistry.js +13 -8
  18. package/dist/glMaterialRegistry.js.map +1 -1
  19. package/dist/glRenderState.d.ts +3 -1
  20. package/dist/glRenderState.d.ts.map +1 -1
  21. package/dist/glRenderState.js +55 -37
  22. package/dist/glRenderState.js.map +1 -1
  23. package/dist/glRenderStateBracket.d.ts.map +1 -1
  24. package/dist/glRenderStateBracket.js +54 -0
  25. package/dist/glRenderStateBracket.js.map +1 -1
  26. package/dist/glRenderTarget.js.map +1 -1
  27. package/dist/glShader.d.ts +2 -1
  28. package/dist/glShader.d.ts.map +1 -1
  29. package/dist/glShader.js +10 -0
  30. package/dist/glShader.js.map +1 -1
  31. package/dist/glShaderBinding.d.ts.map +1 -1
  32. package/dist/glShaderBinding.js +2 -1
  33. package/dist/glShaderBinding.js.map +1 -1
  34. package/dist/glSkinPaletteTexture.d.ts +1 -1
  35. package/dist/glSkinPaletteTexture.d.ts.map +1 -1
  36. package/dist/glSkinPaletteTexture.js +6 -2
  37. package/dist/glSkinPaletteTexture.js.map +1 -1
  38. package/dist/glTextureResolver.d.ts.map +1 -1
  39. package/dist/glTextureResolver.js +13 -11
  40. package/dist/glTextureResolver.js.map +1 -1
  41. package/package.json +11 -10
  42. package/src/enableGlRenderStateGuards.test.ts +10 -0
  43. package/src/glCompressedTexture.test.ts +29 -12
  44. package/src/glDraw.test.ts +25 -6
  45. package/src/glMaterialRegistry.test.ts +16 -0
  46. package/src/glRenderState.test.ts +338 -29
  47. package/src/glRenderStateBracket.test.ts +170 -0
  48. package/src/glShader.test.ts +55 -1
  49. package/src/glTestHelper.test.ts +51 -0
  50. package/src/glTextureResolver.test.ts +11 -6
@@ -1 +1 @@
1
- {"version":3,"file":"glTextureResolver.js","sourceRoot":"","sources":["../src/glTextureResolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"glTextureResolver.js","sourceRoot":"","sources":["../src/glTextureResolver.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/render-gl",
3
- "version": "0.3.0",
3
+ "version": "0.3.1-next.1050.9114695",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,15 +38,16 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/color": "0.3.0",
42
- "@flighthq/entity": "0.3.0",
43
- "@flighthq/log": "0.3.0",
44
- "@flighthq/scene2d": "0.3.0",
45
- "@flighthq/geometry": "0.3.0",
46
- "@flighthq/render": "0.3.0",
47
- "@flighthq/signals": "0.3.0",
48
- "@flighthq/texture": "0.3.0",
49
- "@flighthq/types": "0.3.0"
41
+ "@flighthq/color": "0.3.1-next.1050.9114695",
42
+ "@flighthq/entity": "0.3.1-next.1050.9114695",
43
+ "@flighthq/log": "0.3.1-next.1050.9114695",
44
+ "@flighthq/scene2d": "0.3.1-next.1050.9114695",
45
+ "@flighthq/geometry": "0.3.1-next.1050.9114695",
46
+ "@flighthq/render": "0.3.1-next.1050.9114695",
47
+ "@flighthq/registry": "0.3.1-next.1050.9114695",
48
+ "@flighthq/signals": "0.3.1-next.1050.9114695",
49
+ "@flighthq/texture": "0.3.1-next.1050.9114695",
50
+ "@flighthq/types": "0.3.1-next.1050.9114695"
50
51
  },
51
52
  "devDependencies": {
52
53
  "typescript": "^5.3.0"
@@ -1,5 +1,7 @@
1
1
  import { setLogSink } from '@flighthq/log/contract';
2
+ import { getRenderStateRuntime } from '@flighthq/render/contract';
2
3
  import type { LogEntry } from '@flighthq/types/contract';
4
+ import { RegistryEntryState } from '@flighthq/types/contract';
3
5
 
4
6
  import { areGlRenderStateGuardsEnabled, enableGlRenderStateGuards } from './enableGlRenderStateGuards';
5
7
  import { useGlProgram } from './glDraw';
@@ -25,8 +27,16 @@ describe('enableGlRenderStateGuards', () => {
25
27
  it('installs the state-local multiple-root guard idempotently', () => {
26
28
  const state = createState();
27
29
  enableGlRenderStateGuards(state);
30
+ const table = getRenderStateRuntime(state).registries.renderRootGuard;
31
+ expect(table).toMatchObject({
32
+ entry: { state: RegistryEntryState.Bound },
33
+ onMiss: 'Disabled',
34
+ registry: 'RenderRootGuard',
35
+ shape: 'slot',
36
+ });
28
37
  enableGlRenderStateGuards(state);
29
38
  expect(areGlRenderStateGuardsEnabled(state)).toBe(true);
39
+ expect(getRenderStateRuntime(state).registries.renderRootGuard).toBe(table);
30
40
  });
31
41
  });
32
42
 
@@ -1,5 +1,5 @@
1
1
  import type { CompressedImage, GlCompressedTextureSupport, TextureContainer } from '@flighthq/types/contract';
2
- import { CompressedImageTextureSourceKind } from '@flighthq/types/contract';
2
+ import { CompressedImageTextureSourceKind, RegistryEntryState } from '@flighthq/types/contract';
3
3
 
4
4
  import {
5
5
  detectGlCompressedTextureSupport,
@@ -119,23 +119,35 @@ describe('hasGlCompressedTextureFormat', () => {
119
119
  });
120
120
 
121
121
  describe('registerGlCompressedTextureDecoder', () => {
122
- it('installs the decoder on the render-state runtime and clears it with null', () => {
122
+ it('replaces the decoder policy slot and clears it with null', () => {
123
123
  const { state } = createGlState();
124
+ const runtime = getGlRenderStateRuntime(state);
125
+ const before = runtime.registries.compressedTextureDecoder;
124
126
  const decode = vi.fn(() => new Uint8ClampedArray(4));
125
127
  registerGlCompressedTextureDecoder(state, decode);
126
- expect(getGlRenderStateRuntime(state).compressedTextureDecoder).toBe(decode);
128
+ expect(runtime.registries.compressedTextureDecoder).not.toBe(before);
129
+ expect(runtime.registries.compressedTextureDecoder.entry).toEqual({
130
+ state: RegistryEntryState.Bound,
131
+ value: decode,
132
+ });
127
133
  registerGlCompressedTextureDecoder(state, null);
128
- expect(getGlRenderStateRuntime(state).compressedTextureDecoder).toBeNull();
134
+ expect(runtime.registries.compressedTextureDecoder.entry).toBeNull();
129
135
  });
130
136
  });
131
137
 
132
138
  describe('registerGlCompressedTextureUpload', () => {
133
- it('installs the compressed upload seam on the render-state runtime and clears it with null', () => {
139
+ it('replaces the compressed upload policy slot and clears it with null', () => {
134
140
  const { state } = createGlState();
141
+ const runtime = getGlRenderStateRuntime(state);
142
+ const before = runtime.registries.compressedTextureUpload;
135
143
  registerGlCompressedTextureUpload(state);
136
- expect(getGlRenderStateRuntime(state).compressedTextureUpload).toBeTypeOf('function');
144
+ expect(runtime.registries.compressedTextureUpload).not.toBe(before);
145
+ expect(runtime.registries.compressedTextureUpload.entry).toMatchObject({
146
+ state: RegistryEntryState.Bound,
147
+ value: expect.any(Function),
148
+ });
137
149
  registerGlCompressedTextureUpload(state, null);
138
- expect(getGlRenderStateRuntime(state).compressedTextureUpload).toBeNull();
150
+ expect(runtime.registries.compressedTextureUpload.entry).toBeNull();
139
151
  });
140
152
 
141
153
  it('uploads a CompressedImage once installed, threading the registered decoder', () => {
@@ -144,8 +156,11 @@ describe('registerGlCompressedTextureUpload', () => {
144
156
  const decode = vi.fn(() => rgba);
145
157
  registerGlCompressedTextureUpload(state);
146
158
  registerGlCompressedTextureDecoder(state, decode);
147
- const uploader = getGlRenderStateRuntime(state).compressedTextureUpload!;
148
- const ok = uploader(gl, uploadableCompressedImage(), decode);
159
+ const entry = getGlRenderStateRuntime(state).registries.compressedTextureUpload.entry;
160
+ expect(entry?.state).toBe(RegistryEntryState.Bound);
161
+ const uploader = entry?.state === RegistryEntryState.Bound ? entry.value : null;
162
+ expect(uploader).not.toBeNull();
163
+ const ok = uploader!(gl, uploadableCompressedImage(), decode);
149
164
  expect(ok).toBe(true);
150
165
  expect(decode).toHaveBeenCalledWith('bc3', 4, 4, expect.any(Uint8Array));
151
166
  });
@@ -153,10 +168,12 @@ describe('registerGlCompressedTextureUpload', () => {
153
168
  it('rejects non-2D containers because the installed image bridge is bound to TEXTURE_2D', () => {
154
169
  const { state } = createGlState();
155
170
  registerGlCompressedTextureUpload(state);
156
- const uploader = getGlRenderStateRuntime(state).compressedTextureUpload!;
171
+ const entry = getGlRenderStateRuntime(state).registries.compressedTextureUpload.entry;
172
+ const uploader = entry?.state === RegistryEntryState.Bound ? entry.value : null;
173
+ expect(uploader).not.toBeNull();
157
174
  const gl = makeGl({ WEBGL_compressed_texture_s3tc: S3TC_EXT });
158
- expect(uploader(gl, uploadableCompressedImage({ faces: 6 }), null)).toBe(false);
159
- expect(uploader(gl, uploadableCompressedImage({ layers: 2 }), null)).toBe(false);
175
+ expect(uploader!(gl, uploadableCompressedImage({ faces: 6 }), null)).toBe(false);
176
+ expect(uploader!(gl, uploadableCompressedImage({ layers: 2 }), null)).toBe(false);
160
177
  expect(gl.compressedTexImage2D).not.toHaveBeenCalled();
161
178
  expect(gl.texStorage3D).not.toHaveBeenCalled();
162
179
  });
@@ -1,3 +1,4 @@
1
+ import { getRegistryTableEntry } from '@flighthq/registry/contract';
1
2
  import { getTextureSource } from '@flighthq/texture/contract';
2
3
  import type { Bitmap, CompressedImage, Image, SamplerLike, Texture } from '@flighthq/types/contract';
3
4
  import {
@@ -27,7 +28,7 @@ import {
27
28
  updateGlTexture,
28
29
  useGlProgram,
29
30
  } from './glDraw';
30
- import { getGlRenderStateRuntime } from './glRenderState';
31
+ import { createGlOffscreenRenderState, getGlRenderStateRuntime } from './glRenderState';
31
32
  import { registerGlBitmapShader } from './glShaderRegistry';
32
33
  import { createGlState } from './glTestHelper';
33
34
 
@@ -833,6 +834,24 @@ describe('registerGlBlendMode', () => {
833
834
  const g = gl as unknown as { ONE: number; ZERO: number };
834
835
  expect(gl.blendFunc).toHaveBeenCalledWith(g.ZERO, g.ONE);
835
836
  });
837
+
838
+ it("replaces the table without changing an offscreen state's retained snapshot", () => {
839
+ const { state: screen } = createGlState();
840
+ const initial = { src: 'DST_COLOR', dst: 'ZERO' } as const;
841
+ const replacement = { src: 'ZERO', dst: 'ONE' } as const;
842
+ registerGlBlendMode(screen, 'acme.Foo', initial);
843
+ const snapshot = getGlRenderStateRuntime(screen).registries.blendRealizations;
844
+ const offscreen = createGlOffscreenRenderState(screen);
845
+
846
+ registerGlBlendMode(screen, 'acme.Foo', replacement);
847
+
848
+ expect(getGlRenderStateRuntime(screen).registries.blendRealizations).not.toBe(snapshot);
849
+ expect(getGlRenderStateRuntime(offscreen).registries.blendRealizations).toBe(snapshot);
850
+ expect(getRegistryTableEntry(snapshot, 'acme.Foo')).toBe(initial);
851
+ expect(getRegistryTableEntry(getGlRenderStateRuntime(screen).registries.blendRealizations, 'acme.Foo')).toBe(
852
+ replacement,
853
+ );
854
+ });
836
855
  });
837
856
 
838
857
  describe('setGlQuadMatrixFromOffset', () => {
@@ -841,7 +860,7 @@ describe('setGlQuadMatrixFromOffset', () => {
841
860
  // Identity transform + offset (dx=10, dy=20): effective tx = 0 + 1*10 + 0*20 = 10
842
861
  const runtime = getGlRenderStateRuntime(state);
843
862
  setGlQuadMatrixFromOffset(state, 1, 0, 0, 1, 0, 0, 10, 20);
844
- expect(gl.uniformMatrix3fv).toHaveBeenCalledWith(runtime.shaderLoc.locMatrix, false, runtime.matrixArray);
863
+ expect(gl.uniformMatrix3fv).toHaveBeenCalledWith(runtime.shaderLoc!.locMatrix, false, runtime.matrixArray);
845
864
  // tx * 2/200 - 1 = 10 * 0.01 - 1 = -0.9
846
865
  expect(runtime.matrixArray[6]).toBeCloseTo(-0.9);
847
866
  // -ty * 2/100 + 1 = -20 * 0.02 + 1 = 0.6
@@ -914,13 +933,13 @@ describe('useGlProgram', () => {
914
933
  const runtime = getGlRenderStateRuntime(state);
915
934
  runtime.currentProgram = null;
916
935
  useGlProgram(state);
917
- expect(gl.useProgram).toHaveBeenCalledWith(runtime.shaderLoc.program);
936
+ expect(gl.useProgram).toHaveBeenCalledWith(runtime.shaderLoc!.program);
918
937
  });
919
938
 
920
939
  it('does not call useProgram when program is already active', () => {
921
940
  const { state, gl } = createGlState();
922
941
  const runtime = getGlRenderStateRuntime(state);
923
- runtime.currentProgram = runtime.shaderLoc.program;
942
+ runtime.currentProgram = runtime.shaderLoc!.program;
924
943
  useGlProgram(state);
925
944
  expect(gl.useProgram).not.toHaveBeenCalled();
926
945
  });
@@ -930,7 +949,7 @@ describe('useGlProgram', () => {
930
949
  const runtime = getGlRenderStateRuntime(state);
931
950
  runtime.currentProgram = null;
932
951
  useGlProgram(state);
933
- expect(runtime.currentProgram).toBe(runtime.shaderLoc.program);
952
+ expect(runtime.currentProgram).toBe(runtime.shaderLoc!.program);
934
953
  });
935
954
 
936
955
  it('uses the registered bitmap shader program and locations', () => {
@@ -938,7 +957,7 @@ describe('useGlProgram', () => {
938
957
  const runtime = getGlRenderStateRuntime(state);
939
958
  const shader = {
940
959
  bind: vi.fn(),
941
- locations: { ...runtime.shaderLoc, program: {} as WebGLProgram },
960
+ locations: { ...runtime.shaderLoc!, program: {} as WebGLProgram },
942
961
  program: {} as WebGLProgram,
943
962
  };
944
963
  shader.locations.program = shader.program;
@@ -3,6 +3,7 @@ import type { GlMaterialRenderer, Material } from '@flighthq/types/contract';
3
3
  import { RenderRegistry, StandardMaterialKind } from '@flighthq/types/contract';
4
4
 
5
5
  import { getGlMaterialRenderer, registerGlMaterialRenderer, resolveGlMaterialRenderer } from './glMaterialRegistry';
6
+ import { getGlRenderStateRuntime } from './glRenderState';
6
7
  import { createGlState } from './glTestHelper';
7
8
 
8
9
  const TestKind = 'TestMaterial';
@@ -22,8 +23,23 @@ describe('getGlMaterialRenderer', () => {
22
23
  describe('registerGlMaterialRenderer', () => {
23
24
  it('registers a renderer retrievable by kind', () => {
24
25
  const { state } = createGlState();
26
+ const before = getGlRenderStateRuntime(state).registries.materialRenderers;
25
27
  registerGlMaterialRenderer(state, TestKind, testRenderer);
26
28
  expect(getGlMaterialRenderer(state, TestKind)).toBe(testRenderer);
29
+ expect(getGlRenderStateRuntime(state).registries.materialRenderers).not.toBe(before);
30
+ expect(before.entries.size).toBe(0);
31
+ });
32
+
33
+ it('is last-write-wins without mutating the earlier snapshot', () => {
34
+ const { state } = createGlState();
35
+ const replacement: GlMaterialRenderer = { instanceFloatCount: 0, bind() {} };
36
+ registerGlMaterialRenderer(state, TestKind, testRenderer);
37
+ const before = getGlRenderStateRuntime(state).registries.materialRenderers;
38
+
39
+ registerGlMaterialRenderer(state, TestKind, replacement);
40
+
41
+ expect(getGlMaterialRenderer(state, TestKind)).toBe(replacement);
42
+ expect(before.entries.get(TestKind)).toEqual({ state: 'bound', value: testRenderer });
27
43
  });
28
44
  });
29
45