@flighthq/scene2d-gl 0.3.0-next.906.07cea63 → 0.3.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.
- package/dist/contract.d.ts +9 -6
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +9 -6
- package/dist/contract.js.map +1 -1
- package/dist/enableGlColorAdjustmentGuards.js +2 -2
- package/dist/enableGlColorAdjustmentGuards.js.map +1 -1
- package/dist/enableGlStrokePathTessellation.d.ts +3 -0
- package/dist/enableGlStrokePathTessellation.d.ts.map +1 -0
- package/dist/enableGlStrokePathTessellation.js +8 -0
- package/dist/enableGlStrokePathTessellation.js.map +1 -0
- package/dist/explainGlScene2DCoverage.d.ts +4 -0
- package/dist/explainGlScene2DCoverage.d.ts.map +1 -0
- package/dist/explainGlScene2DCoverage.js +63 -0
- package/dist/explainGlScene2DCoverage.js.map +1 -0
- package/dist/glBitmapText.d.ts.map +1 -1
- package/dist/glBitmapText.js +20 -15
- package/dist/glBitmapText.js.map +1 -1
- package/dist/glCache.d.ts +2 -2
- package/dist/glCache.d.ts.map +1 -1
- package/dist/glCache.js +24 -92
- package/dist/glCache.js.map +1 -1
- package/dist/glClipContours.js +3 -3
- package/dist/glClipContours.js.map +1 -1
- package/dist/glClipRectangle.js +10 -8
- package/dist/glClipRectangle.js.map +1 -1
- package/dist/glColorAdjustmentMaterialFeature.d.ts.map +1 -1
- package/dist/glColorAdjustmentMaterialFeature.js +79 -76
- package/dist/glColorAdjustmentMaterialFeature.js.map +1 -1
- package/dist/glMeshShapeRenderer.d.ts +4 -0
- package/dist/glMeshShapeRenderer.d.ts.map +1 -0
- package/dist/glMeshShapeRenderer.js +89 -0
- package/dist/glMeshShapeRenderer.js.map +1 -0
- package/dist/glNode2D.js +2 -2
- package/dist/glNode2D.js.map +1 -1
- package/dist/glParticleEmitter2D.js +10 -9
- package/dist/glParticleEmitter2D.js.map +1 -1
- package/dist/glQuadBatch.d.ts.map +1 -1
- package/dist/glQuadBatch.js +18 -12
- package/dist/glQuadBatch.js.map +1 -1
- package/dist/{glSpriteBatch.d.ts → glQuadBatchWriter.d.ts} +6 -6
- package/dist/glQuadBatchWriter.d.ts.map +1 -0
- package/dist/{glSpriteBatch.js → glQuadBatchWriter.js} +84 -73
- package/dist/glQuadBatchWriter.js.map +1 -0
- package/dist/glRasterShapeRenderer.d.ts +4 -0
- package/dist/glRasterShapeRenderer.d.ts.map +1 -0
- package/dist/glRasterShapeRenderer.js +103 -0
- package/dist/glRasterShapeRenderer.js.map +1 -0
- package/dist/glRichText.js +2 -2
- package/dist/glRichText.js.map +1 -1
- package/dist/glScale9Shape.d.ts +1 -3
- package/dist/glScale9Shape.d.ts.map +1 -1
- package/dist/glScale9Shape.js +27 -29
- package/dist/glScale9Shape.js.map +1 -1
- package/dist/glShape.d.ts +2 -1
- package/dist/glShape.d.ts.map +1 -1
- package/dist/glShape.js +19 -135
- package/dist/glShape.js.map +1 -1
- package/dist/glShapeData.d.ts +7 -0
- package/dist/glShapeData.d.ts.map +1 -0
- package/dist/glShapeData.js +57 -0
- package/dist/glShapeData.js.map +1 -0
- package/dist/glShapeMesh.js +5 -5
- package/dist/glShapeMesh.js.map +1 -1
- package/dist/glShapeRasterizer.d.ts +4 -0
- package/dist/glShapeRasterizer.d.ts.map +1 -0
- package/dist/glShapeRasterizer.js +11 -0
- package/dist/glShapeRasterizer.js.map +1 -0
- package/dist/glSprite.d.ts +3 -2
- package/dist/glSprite.d.ts.map +1 -1
- package/dist/glSprite.js +64 -24
- package/dist/glSprite.js.map +1 -1
- package/dist/glStandardMaterial.d.ts +1 -1
- package/dist/glStandardMaterial.js +2 -2
- package/dist/glStandardMaterial.js.map +1 -1
- package/dist/glTestHelper.d.ts +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/glTextLabel.d.ts.map +1 -1
- package/dist/glTextLabel.js +14 -12
- package/dist/glTextLabel.js.map +1 -1
- package/dist/glTilemap.d.ts.map +1 -1
- package/dist/glTilemap.js +19 -17
- package/dist/glTilemap.js.map +1 -1
- package/dist/glVelocity.js +2 -2
- package/dist/glVelocity.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +22 -19
- package/src/enableGlColorAdjustmentGuards.test.ts +4 -4
- package/src/enableGlStrokePathTessellation.test.ts +16 -0
- package/src/explainGlScene2DCoverage.test.ts +99 -0
- package/src/glBitmapText.test.ts +18 -17
- package/src/glCache.test.ts +24 -11
- package/src/glClipContours.test.ts +57 -2
- package/src/glClipRectangle.test.ts +9 -0
- package/src/glColorAdjustmentMaterialFeature.test.ts +74 -71
- package/src/glMeshShapeRenderer.test.ts +112 -0
- package/src/glParticleEmitter2D.test.ts +38 -22
- package/src/glQuadBatch.test.ts +40 -28
- package/src/{glSpriteBatch.test.ts → glQuadBatchWriter.test.ts} +74 -53
- package/src/glRasterShapeRenderer.test.ts +109 -0
- package/src/glScale9Shape.test.ts +0 -13
- package/src/glShape.test.ts +166 -21
- package/src/glShapeData.test.ts +74 -0
- package/src/glShapeMesh.test.ts +1 -1
- package/src/glShapeRasterizer.test.ts +32 -0
- package/src/glSprite.test.ts +71 -62
- package/src/glStandardMaterial.test.ts +3 -3
- package/src/glTextLabel.test.ts +16 -16
- package/src/glTilemap.test.ts +44 -47
- package/src/glVelocity.test.ts +4 -4
- package/dist/glBitmap.d.ts +0 -4
- package/dist/glBitmap.d.ts.map +0 -1
- package/dist/glBitmap.js +0 -93
- package/dist/glBitmap.js.map +0 -1
- package/dist/glRenderTargetNode2D.d.ts +0 -11
- package/dist/glRenderTargetNode2D.d.ts.map +0 -1
- package/dist/glRenderTargetNode2D.js +0 -78
- package/dist/glRenderTargetNode2D.js.map +0 -1
- package/dist/glSpriteBatch.d.ts.map +0 -1
- package/dist/glSpriteBatch.js.map +0 -1
- package/dist/glSpriteRenderer.d.ts +0 -3
- package/dist/glSpriteRenderer.d.ts.map +0 -1
- package/dist/glSpriteRenderer.js +0 -54
- package/dist/glSpriteRenderer.js.map +0 -1
- package/dist/glVideo.d.ts +0 -6
- package/dist/glVideo.d.ts.map +0 -1
- package/dist/glVideo.js +0 -63
- package/dist/glVideo.js.map +0 -1
- package/src/glBitmap.test.ts +0 -136
- package/src/glRenderTargetNode2D.test.ts +0 -328
- package/src/glSpriteRenderer.test.ts +0 -89
- package/src/glVideo.test.ts +0 -99
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { getGlRenderStateRuntime } from '@flighthq/render-gl/contract';
|
|
2
|
+
import type { GlShapeRendererData } from '@flighthq/types/contract';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
acquireGlShapeRasterSurface,
|
|
6
|
+
createGlShapeData,
|
|
7
|
+
destroyGlShapeData,
|
|
8
|
+
getGlShapeData,
|
|
9
|
+
toGlShapeRendererData,
|
|
10
|
+
} from './glShapeData';
|
|
11
|
+
import { createGlState } from './glTestHelper';
|
|
12
|
+
|
|
13
|
+
function emptyData(): GlShapeRendererData {
|
|
14
|
+
return { surface: null, lastContentId: -1, lastPixelRatio: 0, lastW: 0, lastH: 0, meshVersion: -1, meshes: null };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('acquireGlShapeRasterSurface', () => {
|
|
18
|
+
it('allocates once and returns the same surface thereafter', () => {
|
|
19
|
+
const data = emptyData();
|
|
20
|
+
const first = acquireGlShapeRasterSurface(data);
|
|
21
|
+
expect(data.surface).toBe(first);
|
|
22
|
+
expect(acquireGlShapeRasterSurface(data)).toBe(first);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('wraps the canvas as an Image so the quad batch treats it like any other texture source', () => {
|
|
26
|
+
const surface = acquireGlShapeRasterSurface(emptyData());
|
|
27
|
+
expect(surface.image.source).toBe(surface.canvas);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('createGlShapeData', () => {
|
|
32
|
+
it('starts with neither cache populated, so a shape allocates nothing until a strategy needs it', () => {
|
|
33
|
+
const { state } = createGlState();
|
|
34
|
+
const data = getGlShapeData(createGlShapeData(state, {} as never)!);
|
|
35
|
+
expect(data.surface).toBeNull();
|
|
36
|
+
expect(data.meshes).toBeNull();
|
|
37
|
+
expect(data.meshVersion).toBe(-1);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('destroyGlShapeData', () => {
|
|
42
|
+
it('does nothing when the shape only ever tessellated, since there is no surface to free', () => {
|
|
43
|
+
const { state, gl } = createGlState();
|
|
44
|
+
destroyGlShapeData(state, toGlShapeRendererData(emptyData()));
|
|
45
|
+
expect(gl.deleteTexture).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('frees the cached GPU texture keyed on the raster surface', () => {
|
|
49
|
+
const { state, gl } = createGlState();
|
|
50
|
+
const data = emptyData();
|
|
51
|
+
const surface = acquireGlShapeRasterSurface(data);
|
|
52
|
+
const texture = {} as WebGLTexture;
|
|
53
|
+
getGlRenderStateRuntime(state).textureSourcePremultipliedTextureCache.set(surface.image, { texture } as never);
|
|
54
|
+
|
|
55
|
+
destroyGlShapeData(state, toGlShapeRendererData(data));
|
|
56
|
+
|
|
57
|
+
expect(gl.deleteTexture).toHaveBeenCalledWith(texture);
|
|
58
|
+
expect(getGlRenderStateRuntime(state).textureSourcePremultipliedTextureCache.has(surface.image)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('getGlShapeData', () => {
|
|
63
|
+
it('round-trips through the opaque RendererData slot', () => {
|
|
64
|
+
const data = emptyData();
|
|
65
|
+
expect(getGlShapeData(toGlShapeRendererData(data))).toBe(data);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('toGlShapeRendererData', () => {
|
|
70
|
+
it('is the inverse of getGlShapeData', () => {
|
|
71
|
+
const data = emptyData();
|
|
72
|
+
expect(toGlShapeRendererData(getGlShapeData(toGlShapeRendererData(data)))).toBe(toGlShapeRendererData(data));
|
|
73
|
+
});
|
|
74
|
+
});
|
package/src/glShapeMesh.test.ts
CHANGED
|
@@ -127,7 +127,7 @@ describe('drawGlShapeMeshes', () => {
|
|
|
127
127
|
const shader = getGlRenderStateRuntime(state).shapeMeshColorScaleBiasShader!;
|
|
128
128
|
expect(shader).toBeDefined();
|
|
129
129
|
// Scale and bias are uploaded verbatim — identical to glColorAdjustmentMaterialFeature's
|
|
130
|
-
//
|
|
130
|
+
// bindGlQuadBatchWriterUniformColorScaleBias.
|
|
131
131
|
expect(gl.uniform4f).toHaveBeenCalledWith(shader.colorScaleLocation, 0.5, 0.5, 0.5, 1);
|
|
132
132
|
expect(gl.uniform4f).toHaveBeenCalledWith(shader.colorBiasLocation, 0.5, 0, 0, 0);
|
|
133
133
|
// Flat mesh color still uploaded premultiplied (white, alpha 1); the shader un/re-premultiplies.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createRenderState, enableRenderRegistryGuards, explainRenderRegistryMisses } from '@flighthq/render/contract';
|
|
2
|
+
import { RenderRegistry } from '@flighthq/types/contract';
|
|
3
|
+
|
|
4
|
+
import { getGlShapeRasterizer, registerGlShapeRasterizer } from './glShapeRasterizer';
|
|
5
|
+
import { createGlState } from './glTestHelper';
|
|
6
|
+
|
|
7
|
+
describe('getGlShapeRasterizer', () => {
|
|
8
|
+
it('reports none until one is registered', () => {
|
|
9
|
+
const state = createGlState().state;
|
|
10
|
+
expect(getGlShapeRasterizer(state)).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('registerGlShapeRasterizer', () => {
|
|
15
|
+
it('installs the rasterizer the shape path draws non-solid fills through', () => {
|
|
16
|
+
const state = createGlState().state;
|
|
17
|
+
const rasterizer = (): void => {};
|
|
18
|
+
|
|
19
|
+
registerGlShapeRasterizer(state, rasterizer);
|
|
20
|
+
|
|
21
|
+
expect(getGlShapeRasterizer(state)).toBe(rasterizer);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('removes one again, so a state can drop back to tessellation only', () => {
|
|
25
|
+
const state = createGlState().state;
|
|
26
|
+
registerGlShapeRasterizer(state, (): void => {});
|
|
27
|
+
|
|
28
|
+
registerGlShapeRasterizer(state, null);
|
|
29
|
+
|
|
30
|
+
expect(getGlShapeRasterizer(state)).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
package/src/glSprite.test.ts
CHANGED
|
@@ -1,79 +1,88 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import {
|
|
2
|
+
getGlRenderStateRuntime,
|
|
3
|
+
registerGlBitmapTextureResolver,
|
|
4
|
+
registerGlRenderTextureResolver,
|
|
5
|
+
renderIntoGlRenderTexture,
|
|
6
|
+
} from '@flighthq/render-gl/contract';
|
|
7
|
+
import { createRenderTexture, createTexture, setTextureUvFromPixelRect } from '@flighthq/texture/contract';
|
|
8
|
+
import type { Bitmap, RenderProxy2D, Sprite } from '@flighthq/types/contract';
|
|
9
|
+
import { BatchFormat, BitmapTextureSourceKind } from '@flighthq/types/contract';
|
|
10
|
+
|
|
11
|
+
import { flushGlQuadBatchWriter } from './glQuadBatchWriter';
|
|
12
|
+
import { defaultGlSpriteRenderer, drawGlSprite } from './glSprite';
|
|
13
|
+
import { registerGlStandardMaterial } from './glStandardMaterial';
|
|
7
14
|
import { createGlState } from './glTestHelper';
|
|
8
15
|
|
|
9
|
-
function
|
|
10
|
-
|
|
16
|
+
function makeSprite(width = 64, height = 48): Sprite {
|
|
17
|
+
const image = {
|
|
18
|
+
alphaType: 'straight',
|
|
19
|
+
colorSpace: 'srgb',
|
|
20
|
+
data: new Uint8ClampedArray(width * height * 4),
|
|
21
|
+
format: 'rgba8unorm',
|
|
22
|
+
height,
|
|
23
|
+
kind: BitmapTextureSourceKind,
|
|
24
|
+
version: 1,
|
|
25
|
+
width,
|
|
26
|
+
} as unknown as Bitmap;
|
|
27
|
+
return {
|
|
28
|
+
data: { texture: createTexture({ dimension: '2d', source: image }) },
|
|
29
|
+
} as Sprite;
|
|
11
30
|
}
|
|
12
31
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const renderer = makeRenderer();
|
|
26
|
-
registerRenderer(state, SpriteKind, renderer);
|
|
27
|
-
|
|
28
|
-
const sprite = createSprite();
|
|
29
|
-
const data = getOrCreateRenderProxy2D(state, sprite);
|
|
30
|
-
|
|
31
|
-
prepareScene2DRender(state, sprite);
|
|
32
|
-
renderGlSprite(state, sprite);
|
|
32
|
+
function makeRenderProxy(sprite: Sprite): RenderProxy2D {
|
|
33
|
+
return {
|
|
34
|
+
alpha: 1,
|
|
35
|
+
blendMode: 0,
|
|
36
|
+
colorMatrix: null,
|
|
37
|
+
colorScaleBias: null,
|
|
38
|
+
material: null,
|
|
39
|
+
materialData: null,
|
|
40
|
+
source: sprite,
|
|
41
|
+
transform2D: { a: 1, b: 0, c: 0, d: 1, tx: 10, ty: 20 },
|
|
42
|
+
} as unknown as RenderProxy2D;
|
|
43
|
+
}
|
|
33
44
|
|
|
34
|
-
|
|
45
|
+
describe('defaultGlSpriteRenderer', () => {
|
|
46
|
+
it('declares the quad format and submit function', () => {
|
|
47
|
+
expect(defaultGlSpriteRenderer.format).toBe(BatchFormat.Quad);
|
|
48
|
+
expect(typeof defaultGlSpriteRenderer.isDirty).toBe('function');
|
|
49
|
+
expect(defaultGlSpriteRenderer.submit).toBe(drawGlSprite);
|
|
35
50
|
});
|
|
51
|
+
});
|
|
36
52
|
|
|
37
|
-
|
|
53
|
+
describe('drawGlSprite', () => {
|
|
54
|
+
it('writes natural size and uv window into the shared batch', () => {
|
|
38
55
|
const { state } = createGlState();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
sprite
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
renderGlSprite(state, sprite);
|
|
47
|
-
|
|
48
|
-
expect(renderer.submit).not.toHaveBeenCalled();
|
|
56
|
+
registerGlBitmapTextureResolver(state);
|
|
57
|
+
registerGlStandardMaterial(state);
|
|
58
|
+
const sprite = makeSprite(128, 64);
|
|
59
|
+
setTextureUvFromPixelRect(sprite.data.texture!, 16, 8, 32, 16);
|
|
60
|
+
drawGlSprite(state, makeRenderProxy(sprite));
|
|
61
|
+
const data = getGlRenderStateRuntime(state).quadBatchWriterInstanceData;
|
|
62
|
+
expect(Array.from(data.slice(6, 12))).toEqual([32, 16, 0.125, 0.125, 0.375, 0.375]);
|
|
49
63
|
});
|
|
50
64
|
|
|
51
|
-
it('
|
|
65
|
+
it('uses the physical slab once and reflects a render-target sub-view into GL coordinates', () => {
|
|
52
66
|
const { state } = createGlState();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
registerGlRenderTextureResolver(state);
|
|
68
|
+
registerGlStandardMaterial(state);
|
|
69
|
+
const renderTexture = createRenderTexture({ height: 480, width: 720 });
|
|
70
|
+
setTextureUvFromPixelRect(renderTexture, 140, 160, 100, 80);
|
|
71
|
+
renderIntoGlRenderTexture(state, renderTexture, () => {});
|
|
72
|
+
const sprite = { data: { texture: renderTexture } } as Sprite;
|
|
58
73
|
|
|
59
|
-
|
|
60
|
-
renderGlSprite(state, sprite);
|
|
74
|
+
drawGlSprite(state, makeRenderProxy(sprite));
|
|
61
75
|
|
|
62
|
-
|
|
76
|
+
const data = getGlRenderStateRuntime(state).quadBatchWriterInstanceData;
|
|
77
|
+
expect(data.slice(6, 12)).toEqual(new Float32Array([100, 80, 140 / 720, 1 - 160 / 480, 240 / 720, 1 - 240 / 480]));
|
|
63
78
|
});
|
|
64
79
|
|
|
65
|
-
it('
|
|
66
|
-
const { state } = createGlState();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
addNodeChild(parent, child);
|
|
73
|
-
|
|
74
|
-
prepareScene2DRender(state, parent);
|
|
75
|
-
renderGlSprite(state, parent);
|
|
76
|
-
|
|
77
|
-
expect(renderer.submit).toHaveBeenCalledTimes(2);
|
|
80
|
+
it('resolves and draws the texture on flush', () => {
|
|
81
|
+
const { gl, state } = createGlState();
|
|
82
|
+
registerGlBitmapTextureResolver(state);
|
|
83
|
+
registerGlStandardMaterial(state);
|
|
84
|
+
drawGlSprite(state, makeRenderProxy(makeSprite()));
|
|
85
|
+
flushGlQuadBatchWriter(state);
|
|
86
|
+
expect(gl.drawElementsInstanced).toHaveBeenCalledOnce();
|
|
78
87
|
});
|
|
79
88
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { getGlMaterialRenderer } from '@flighthq/render-gl/contract';
|
|
2
2
|
import { StandardMaterialKind } from '@flighthq/types/contract';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { registerGlStandardMaterial, standardGlMaterialRenderer } from './glStandardMaterial';
|
|
5
5
|
import { createGlState } from './glTestHelper';
|
|
6
6
|
|
|
7
|
-
describe('
|
|
7
|
+
describe('registerGlStandardMaterial', () => {
|
|
8
8
|
it('registers the default renderer under StandardMaterialKind', () => {
|
|
9
9
|
const { state } = createGlState();
|
|
10
|
-
|
|
10
|
+
registerGlStandardMaterial(state);
|
|
11
11
|
expect(getGlMaterialRenderer(state, StandardMaterialKind)).toBe(standardGlMaterialRenderer);
|
|
12
12
|
});
|
|
13
13
|
});
|
package/src/glTextLabel.test.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { createTextLabel, setTextLabelString } from '@flighthq/text/contract';
|
|
|
4
4
|
import type { RenderProxy2D, TextLabel } from '@flighthq/types/contract';
|
|
5
5
|
import { BatchFormat } from '@flighthq/types/contract';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { flushGlQuadBatchWriter } from './glQuadBatchWriter';
|
|
8
|
+
import { registerGlStandardMaterial } from './glStandardMaterial';
|
|
9
9
|
import { createGlState } from './glTestHelper';
|
|
10
10
|
import type * as GlTextLabelModule from './glTextLabel';
|
|
11
11
|
import { scopeModuleMocks } from './moduleMockTestHelper';
|
|
@@ -83,46 +83,46 @@ describe('defaultGlTextLabelRenderer', () => {
|
|
|
83
83
|
describe('drawGlTextLabel', () => {
|
|
84
84
|
it('returns early without writing to batch when text is empty', () => {
|
|
85
85
|
const { state } = createGlState();
|
|
86
|
-
|
|
86
|
+
registerGlStandardMaterial(state);
|
|
87
87
|
drawGlTextLabel(state, makeTextProxy('', makeTextData()));
|
|
88
|
-
expect(getGlRenderStateRuntime(state).
|
|
88
|
+
expect(getGlRenderStateRuntime(state).quadBatchWriterCount).toBe(0);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
it('returns early without writing to batch when rendererData is null', () => {
|
|
92
92
|
const { state } = createGlState();
|
|
93
|
-
|
|
93
|
+
registerGlStandardMaterial(state);
|
|
94
94
|
drawGlTextLabel(state, makeTextProxy('hello', null));
|
|
95
|
-
expect(getGlRenderStateRuntime(state).
|
|
95
|
+
expect(getGlRenderStateRuntime(state).quadBatchWriterCount).toBe(0);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
it('returns early without writing to batch when no material renderer is registered', () => {
|
|
99
99
|
const { state } = createGlState();
|
|
100
100
|
drawGlTextLabel(state, makeTextProxy('hello', makeTextData()));
|
|
101
|
-
expect(getGlRenderStateRuntime(state).
|
|
101
|
+
expect(getGlRenderStateRuntime(state).quadBatchWriterCount).toBe(0);
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
-
it('writes one instance to the
|
|
104
|
+
it('writes one instance to the quad-batch writer when text has content', () => {
|
|
105
105
|
const { state } = createGlState();
|
|
106
|
-
|
|
106
|
+
registerGlStandardMaterial(state);
|
|
107
107
|
drawGlTextLabel(state, makeTextProxy('hello', makeTextData()));
|
|
108
|
-
expect(getGlRenderStateRuntime(state).
|
|
108
|
+
expect(getGlRenderStateRuntime(state).quadBatchWriterCount).toBe(1);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
it('draws via drawElementsInstanced after flush', () => {
|
|
112
112
|
const { state, gl } = createGlState();
|
|
113
|
-
|
|
113
|
+
registerGlStandardMaterial(state);
|
|
114
114
|
drawGlTextLabel(state, makeTextProxy('hello', makeTextData()));
|
|
115
|
-
|
|
115
|
+
flushGlQuadBatchWriter(state);
|
|
116
116
|
expect(gl.drawElementsInstanced).toHaveBeenCalled();
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
it('skips layout and rasterization on repeated calls when the content version is unchanged', () => {
|
|
120
120
|
const { state } = createGlState();
|
|
121
|
-
|
|
121
|
+
registerGlStandardMaterial(state);
|
|
122
122
|
const data = makeTextData();
|
|
123
123
|
const proxy = makeTextProxy('hello', data);
|
|
124
124
|
drawGlTextLabel(state, proxy);
|
|
125
|
-
// Rasterization bumps the canvas resource's version (
|
|
125
|
+
// Rasterization bumps the canvas resource's version (invalidateImageResource); a skipped raster leaves
|
|
126
126
|
// it untouched. First draw rasterizes (version → 1); the repeat is skipped.
|
|
127
127
|
const rasterized = data.image.version;
|
|
128
128
|
drawGlTextLabel(state, proxy);
|
|
@@ -131,7 +131,7 @@ describe('drawGlTextLabel', () => {
|
|
|
131
131
|
|
|
132
132
|
it('re-rasterizes when the content version is bumped', () => {
|
|
133
133
|
const { state } = createGlState();
|
|
134
|
-
|
|
134
|
+
registerGlStandardMaterial(state);
|
|
135
135
|
const data = makeTextData();
|
|
136
136
|
const proxy = makeTextProxy('hello', data);
|
|
137
137
|
drawGlTextLabel(state, proxy);
|
|
@@ -143,7 +143,7 @@ describe('drawGlTextLabel', () => {
|
|
|
143
143
|
|
|
144
144
|
it('does not re-rasterize when only alpha changes (version unchanged)', () => {
|
|
145
145
|
const { state } = createGlState();
|
|
146
|
-
|
|
146
|
+
registerGlStandardMaterial(state);
|
|
147
147
|
const data = makeTextData();
|
|
148
148
|
const proxy = makeTextProxy('hello', data);
|
|
149
149
|
drawGlTextLabel(state, proxy);
|
package/src/glTilemap.test.ts
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import type { RenderProxy2D } from '@flighthq/types/contract';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { flushGlQuadBatchWriter } from './glQuadBatchWriter';
|
|
4
|
+
import { registerGlStandardMaterial } from './glStandardMaterial';
|
|
5
5
|
import { createGlState } from './glTestHelper';
|
|
6
6
|
import { defaultGlTilemapRenderer } from './glTilemap';
|
|
7
7
|
|
|
8
8
|
function makeAtlas() {
|
|
9
9
|
const img = document.createElement('img');
|
|
10
|
+
const image = createImageResource(img);
|
|
11
|
+
image.width = 64;
|
|
12
|
+
image.height = 64;
|
|
10
13
|
return {
|
|
11
|
-
image: { source: img, width: 64, height: 64 },
|
|
12
14
|
regions: [{ x: 0, y: 0, width: 16, height: 16 }],
|
|
15
|
+
texture: createTexture({ dimension: '2d', source: image }),
|
|
13
16
|
};
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
tileHeight: 16,
|
|
21
|
-
};
|
|
19
|
+
function createAtlasGlState() {
|
|
20
|
+
const result = createGlState();
|
|
21
|
+
registerGlImageTextureResolver(result.state);
|
|
22
|
+
return result;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
function makeTilemapNode(data: Record<string, unknown> = {}): RenderProxy2D {
|
|
25
26
|
return {
|
|
26
27
|
source: {
|
|
27
28
|
data: {
|
|
28
|
-
|
|
29
|
+
atlas: makeAtlas(),
|
|
29
30
|
columns: 2,
|
|
30
31
|
rows: 2,
|
|
32
|
+
tileHeight: 16,
|
|
33
|
+
tileWidth: 16,
|
|
31
34
|
tiles: [0, 0, 0, 0],
|
|
32
35
|
...data,
|
|
33
36
|
},
|
|
@@ -53,75 +56,69 @@ describe('defaultGlTilemapRenderer', () => {
|
|
|
53
56
|
});
|
|
54
57
|
|
|
55
58
|
describe('defaultGlTilemapRenderer.submit', () => {
|
|
56
|
-
it('returns early without drawing when tileset is null', () => {
|
|
57
|
-
const { state, gl } = createGlState();
|
|
58
|
-
registerStandardGlMaterial(state);
|
|
59
|
-
defaultGlTilemapRenderer.submit(state, makeTilemapNode({ tileset: null }));
|
|
60
|
-
flushGlSpriteBatch(state);
|
|
61
|
-
expect(gl.drawElementsInstanced).not.toHaveBeenCalled();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
59
|
it('returns early without drawing when atlas is null', () => {
|
|
65
|
-
const { state, gl } =
|
|
66
|
-
|
|
67
|
-
defaultGlTilemapRenderer.submit(state, makeTilemapNode({
|
|
68
|
-
|
|
60
|
+
const { state, gl } = createAtlasGlState();
|
|
61
|
+
registerGlStandardMaterial(state);
|
|
62
|
+
defaultGlTilemapRenderer.submit(state, makeTilemapNode({ atlas: null }));
|
|
63
|
+
flushGlQuadBatchWriter(state);
|
|
69
64
|
expect(gl.drawElementsInstanced).not.toHaveBeenCalled();
|
|
70
65
|
});
|
|
71
66
|
|
|
72
|
-
it('returns early without drawing when atlas.
|
|
73
|
-
const { state, gl } =
|
|
74
|
-
|
|
75
|
-
defaultGlTilemapRenderer.submit(
|
|
76
|
-
|
|
77
|
-
makeTilemapNode({ tileset: { atlas: { image: null, regions: [] }, tileWidth: 16, tileHeight: 16 } }),
|
|
78
|
-
);
|
|
79
|
-
flushGlSpriteBatch(state);
|
|
67
|
+
it('returns early without drawing when atlas.texture is null', () => {
|
|
68
|
+
const { state, gl } = createAtlasGlState();
|
|
69
|
+
registerGlStandardMaterial(state);
|
|
70
|
+
defaultGlTilemapRenderer.submit(state, makeTilemapNode({ atlas: { regions: [], texture: null } }));
|
|
71
|
+
flushGlQuadBatchWriter(state);
|
|
80
72
|
expect(gl.drawElementsInstanced).not.toHaveBeenCalled();
|
|
81
73
|
});
|
|
82
74
|
|
|
83
|
-
it('returns early without drawing when atlas
|
|
84
|
-
const { state, gl } =
|
|
85
|
-
|
|
75
|
+
it('returns early without drawing when atlas Texture is unbound', () => {
|
|
76
|
+
const { state, gl } = createAtlasGlState();
|
|
77
|
+
registerGlStandardMaterial(state);
|
|
86
78
|
defaultGlTilemapRenderer.submit(
|
|
87
79
|
state,
|
|
88
|
-
makeTilemapNode({
|
|
80
|
+
makeTilemapNode({
|
|
81
|
+
atlas: { regions: [], texture: createTexture() },
|
|
82
|
+
}),
|
|
89
83
|
);
|
|
90
|
-
|
|
84
|
+
flushGlQuadBatchWriter(state);
|
|
91
85
|
expect(gl.drawElementsInstanced).not.toHaveBeenCalled();
|
|
92
86
|
});
|
|
93
87
|
|
|
94
88
|
it('returns early without drawing when columns is 0', () => {
|
|
95
|
-
const { state, gl } =
|
|
96
|
-
|
|
89
|
+
const { state, gl } = createAtlasGlState();
|
|
90
|
+
registerGlStandardMaterial(state);
|
|
97
91
|
defaultGlTilemapRenderer.submit(state, makeTilemapNode({ columns: 0 }));
|
|
98
|
-
|
|
92
|
+
flushGlQuadBatchWriter(state);
|
|
99
93
|
expect(gl.drawElementsInstanced).not.toHaveBeenCalled();
|
|
100
94
|
});
|
|
101
95
|
|
|
102
96
|
it('returns early without drawing when rows is 0', () => {
|
|
103
|
-
const { state, gl } =
|
|
104
|
-
|
|
97
|
+
const { state, gl } = createAtlasGlState();
|
|
98
|
+
registerGlStandardMaterial(state);
|
|
105
99
|
defaultGlTilemapRenderer.submit(state, makeTilemapNode({ rows: 0 }));
|
|
106
|
-
|
|
100
|
+
flushGlQuadBatchWriter(state);
|
|
107
101
|
expect(gl.drawElementsInstanced).not.toHaveBeenCalled();
|
|
108
102
|
});
|
|
109
103
|
|
|
110
104
|
it('draws all valid tiles in a single instanced call', () => {
|
|
111
|
-
const { state, gl } =
|
|
112
|
-
|
|
105
|
+
const { state, gl } = createAtlasGlState();
|
|
106
|
+
registerGlStandardMaterial(state);
|
|
113
107
|
defaultGlTilemapRenderer.submit(state, makeTilemapNode());
|
|
114
|
-
|
|
108
|
+
flushGlQuadBatchWriter(state);
|
|
115
109
|
expect(gl.drawElementsInstanced).toHaveBeenCalledTimes(1);
|
|
116
110
|
expect(gl.drawElementsInstanced).toHaveBeenCalledWith(expect.anything(), 6, expect.anything(), 0, 4);
|
|
117
111
|
});
|
|
118
112
|
|
|
119
113
|
it('excludes out-of-range tile ids from the instanced draw count', () => {
|
|
120
|
-
const { state, gl } =
|
|
121
|
-
|
|
114
|
+
const { state, gl } = createAtlasGlState();
|
|
115
|
+
registerGlStandardMaterial(state);
|
|
122
116
|
defaultGlTilemapRenderer.submit(state, makeTilemapNode({ tiles: [0, 99, 99, 0] }));
|
|
123
|
-
|
|
117
|
+
flushGlQuadBatchWriter(state);
|
|
124
118
|
expect(gl.drawElementsInstanced).toHaveBeenCalledTimes(1);
|
|
125
119
|
expect(gl.drawElementsInstanced).toHaveBeenCalledWith(expect.anything(), 6, expect.anything(), 0, 2);
|
|
126
120
|
});
|
|
127
121
|
});
|
|
122
|
+
import { createImageResource } from '@flighthq/image/contract';
|
|
123
|
+
import { registerGlImageTextureResolver } from '@flighthq/render-gl/contract';
|
|
124
|
+
import { createTexture } from '@flighthq/texture/contract';
|
package/src/glVelocity.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createParticleEmitter2D, reserveParticleEmitter2D } from '@flighthq/particleemitter/contract';
|
|
2
|
+
import { createQuadBatch, getQuadBatchRuntime } from '@flighthq/quadbatch/contract';
|
|
2
3
|
import { createDisplayObject } from '@flighthq/scene2d/contract';
|
|
3
|
-
import { createQuadBatch, getQuadBatchRuntime } from '@flighthq/sprite/contract';
|
|
4
4
|
import type { QuadBatchRuntime, TextureAtlas, TextureAtlasRegion } from '@flighthq/types/contract';
|
|
5
5
|
import { QuadBatchKind } from '@flighthq/types/contract';
|
|
6
6
|
import { beginVelocityFrame, contributeVelocity, createVelocityField } from '@flighthq/velocity/contract';
|
|
@@ -42,7 +42,7 @@ describe('defaultGlParticleEmitter2DVelocityWriter', () => {
|
|
|
42
42
|
const { state } = createGlState();
|
|
43
43
|
const target = createGlVelocityTarget(state, 128, 64);
|
|
44
44
|
const region = { id: 0, x: 0, y: 0, width: 16, height: 16, pivotX: null, pivotY: null } as TextureAtlasRegion;
|
|
45
|
-
const atlas = {
|
|
45
|
+
const atlas = { texture: null, regions: [region] } as TextureAtlas;
|
|
46
46
|
const emitter = createParticleEmitter2D();
|
|
47
47
|
reserveParticleEmitter2D(emitter, 2);
|
|
48
48
|
emitter.data.atlas = atlas;
|
|
@@ -69,7 +69,7 @@ describe('defaultGlQuadBatchVelocityWriter', () => {
|
|
|
69
69
|
const { state } = createGlState();
|
|
70
70
|
const target = createGlVelocityTarget(state, 128, 64);
|
|
71
71
|
const region = { id: 0, x: 0, y: 0, width: 32, height: 32, pivotX: null, pivotY: null } as TextureAtlasRegion;
|
|
72
|
-
const atlas = {
|
|
72
|
+
const atlas = { texture: null, regions: [region] } as TextureAtlas;
|
|
73
73
|
// Two vector2 instances at distinct positions, each moving independently.
|
|
74
74
|
const batch = createQuadBatch({
|
|
75
75
|
data: {
|
|
@@ -94,7 +94,7 @@ describe('defaultGlQuadBatchVelocityWriter', () => {
|
|
|
94
94
|
const { state } = createGlState();
|
|
95
95
|
const target = createGlVelocityTarget(state, 128, 64);
|
|
96
96
|
const region = { id: 0, x: 0, y: 0, width: 32, height: 32, pivotX: null, pivotY: null } as TextureAtlasRegion;
|
|
97
|
-
const atlas = {
|
|
97
|
+
const atlas = { texture: null, regions: [region] } as TextureAtlas;
|
|
98
98
|
const batch = createQuadBatch({
|
|
99
99
|
data: { atlas, ids: new Uint16Array([0]), instanceCount: 1, transforms: new Float32Array([0, 0]) },
|
|
100
100
|
});
|
package/dist/glBitmap.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Scene2DRenderer, GlRenderState, RenderProxy2D } from '@flighthq/types/contract';
|
|
2
|
-
export declare function drawGlBitmap(state: GlRenderState, renderProxy: RenderProxy2D): void;
|
|
3
|
-
export declare const defaultGlBitmapRenderer: Scene2DRenderer;
|
|
4
|
-
//# sourceMappingURL=glBitmap.d.ts.map
|
package/dist/glBitmap.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"glBitmap.d.ts","sourceRoot":"","sources":["../src/glBitmap.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAIb,aAAa,EACd,MAAM,0BAA0B,CAAC;AAgClC,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,GAAG,IAAI,CAwEnF;AAED,eAAO,MAAM,uBAAuB,EAAE,eAKrC,CAAC"}
|