@flighthq/scene2d-wgpu 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.
Files changed (128) hide show
  1. package/dist/contract.d.ts +8 -6
  2. package/dist/contract.d.ts.map +1 -1
  3. package/dist/contract.js +8 -6
  4. package/dist/contract.js.map +1 -1
  5. package/dist/enableWgpuColorAdjustmentGuards.js +2 -2
  6. package/dist/enableWgpuColorAdjustmentGuards.js.map +1 -1
  7. package/dist/enableWgpuStrokePathTessellation.d.ts +3 -0
  8. package/dist/enableWgpuStrokePathTessellation.d.ts.map +1 -0
  9. package/dist/enableWgpuStrokePathTessellation.js +8 -0
  10. package/dist/enableWgpuStrokePathTessellation.js.map +1 -0
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/wgpuBitmapText.d.ts.map +1 -1
  16. package/dist/wgpuBitmapText.js +20 -16
  17. package/dist/wgpuBitmapText.js.map +1 -1
  18. package/dist/wgpuCache.d.ts.map +1 -1
  19. package/dist/wgpuCache.js +19 -16
  20. package/dist/wgpuCache.js.map +1 -1
  21. package/dist/wgpuClipContours.js +3 -3
  22. package/dist/wgpuClipContours.js.map +1 -1
  23. package/dist/wgpuClipRectangle.js +3 -3
  24. package/dist/wgpuClipRectangle.js.map +1 -1
  25. package/dist/wgpuColorAdjustmentMaterialFeature.d.ts.map +1 -1
  26. package/dist/wgpuColorAdjustmentMaterialFeature.js +156 -67
  27. package/dist/wgpuColorAdjustmentMaterialFeature.js.map +1 -1
  28. package/dist/wgpuMeshShapeRenderer.d.ts +4 -0
  29. package/dist/wgpuMeshShapeRenderer.d.ts.map +1 -0
  30. package/dist/wgpuMeshShapeRenderer.js +92 -0
  31. package/dist/wgpuMeshShapeRenderer.js.map +1 -0
  32. package/dist/wgpuNode2D.js +2 -2
  33. package/dist/wgpuNode2D.js.map +1 -1
  34. package/dist/wgpuParticleEmitter2D.d.ts.map +1 -1
  35. package/dist/wgpuParticleEmitter2D.js +26 -10
  36. package/dist/wgpuParticleEmitter2D.js.map +1 -1
  37. package/dist/wgpuQuadBatch.d.ts +1 -1
  38. package/dist/wgpuQuadBatch.d.ts.map +1 -1
  39. package/dist/wgpuQuadBatch.js +18 -13
  40. package/dist/wgpuQuadBatch.js.map +1 -1
  41. package/dist/wgpuQuadBatchWriter.d.ts +12 -0
  42. package/dist/wgpuQuadBatchWriter.d.ts.map +1 -0
  43. package/dist/{wgpuSpriteBatch.js → wgpuQuadBatchWriter.js} +97 -72
  44. package/dist/wgpuQuadBatchWriter.js.map +1 -0
  45. package/dist/wgpuRasterShapeRenderer.d.ts +4 -0
  46. package/dist/wgpuRasterShapeRenderer.d.ts.map +1 -0
  47. package/dist/wgpuRasterShapeRenderer.js +110 -0
  48. package/dist/wgpuRasterShapeRenderer.js.map +1 -0
  49. package/dist/wgpuRichText.d.ts.map +1 -1
  50. package/dist/wgpuRichText.js +7 -4
  51. package/dist/wgpuRichText.js.map +1 -1
  52. package/dist/wgpuScale9Shape.d.ts +1 -3
  53. package/dist/wgpuScale9Shape.d.ts.map +1 -1
  54. package/dist/wgpuScale9Shape.js +36 -33
  55. package/dist/wgpuScale9Shape.js.map +1 -1
  56. package/dist/wgpuShape.d.ts +2 -1
  57. package/dist/wgpuShape.d.ts.map +1 -1
  58. package/dist/wgpuShape.js +19 -153
  59. package/dist/wgpuShape.js.map +1 -1
  60. package/dist/wgpuShapeData.d.ts +6 -0
  61. package/dist/wgpuShapeData.d.ts.map +1 -0
  62. package/dist/wgpuShapeData.js +81 -0
  63. package/dist/wgpuShapeData.js.map +1 -0
  64. package/dist/wgpuShapeMesh.d.ts +2 -1
  65. package/dist/wgpuShapeMesh.d.ts.map +1 -1
  66. package/dist/wgpuShapeMesh.js +74 -62
  67. package/dist/wgpuShapeMesh.js.map +1 -1
  68. package/dist/wgpuShapeRasterizer.d.ts +4 -0
  69. package/dist/wgpuShapeRasterizer.d.ts.map +1 -0
  70. package/dist/wgpuShapeRasterizer.js +11 -0
  71. package/dist/wgpuShapeRasterizer.js.map +1 -0
  72. package/dist/wgpuSprite.d.ts +3 -2
  73. package/dist/wgpuSprite.d.ts.map +1 -1
  74. package/dist/wgpuSprite.js +67 -25
  75. package/dist/wgpuSprite.js.map +1 -1
  76. package/dist/wgpuStandardMaterial.d.ts +1 -1
  77. package/dist/wgpuStandardMaterial.js +3 -3
  78. package/dist/wgpuStandardMaterial.js.map +1 -1
  79. package/dist/wgpuTextLabel.d.ts.map +1 -1
  80. package/dist/wgpuTextLabel.js +15 -12
  81. package/dist/wgpuTextLabel.js.map +1 -1
  82. package/dist/wgpuTilemap.d.ts.map +1 -1
  83. package/dist/wgpuTilemap.js +19 -18
  84. package/dist/wgpuTilemap.js.map +1 -1
  85. package/package.json +22 -18
  86. package/src/enableWgpuColorAdjustmentGuards.test.ts +4 -4
  87. package/src/enableWgpuStrokePathTessellation.test.ts +23 -0
  88. package/src/wgpuBitmapText.test.ts +2 -2
  89. package/src/wgpuCache.test.ts +14 -11
  90. package/src/wgpuColorAdjustmentMaterialFeature.test.ts +52 -46
  91. package/src/wgpuMeshShapeRenderer.test.ts +167 -0
  92. package/src/wgpuParticleEmitter2D.test.ts +16 -7
  93. package/src/wgpuQuadBatch.test.ts +3 -3
  94. package/src/{wgpuSpriteBatch.test.ts → wgpuQuadBatchWriter.test.ts} +79 -70
  95. package/src/wgpuRasterShapeRenderer.test.ts +156 -0
  96. package/src/wgpuScale9Shape.test.ts +0 -13
  97. package/src/wgpuShape.test.ts +169 -15
  98. package/src/wgpuShapeData.test.ts +97 -0
  99. package/src/wgpuShapeMesh.test.ts +170 -15
  100. package/src/wgpuShapeRasterizer.test.ts +36 -0
  101. package/src/wgpuSprite.test.ts +45 -10
  102. package/src/wgpuStandardMaterial.test.ts +3 -3
  103. package/src/wgpuTextLabel.test.ts +7 -7
  104. package/src/wgpuTilemap.test.ts +4 -4
  105. package/src/wgpuVelocity.test.ts +3 -3
  106. package/dist/wgpuBitmap.d.ts +0 -4
  107. package/dist/wgpuBitmap.d.ts.map +0 -1
  108. package/dist/wgpuBitmap.js +0 -84
  109. package/dist/wgpuBitmap.js.map +0 -1
  110. package/dist/wgpuRenderTargetNode2D.d.ts +0 -11
  111. package/dist/wgpuRenderTargetNode2D.d.ts.map +0 -1
  112. package/dist/wgpuRenderTargetNode2D.js +0 -100
  113. package/dist/wgpuRenderTargetNode2D.js.map +0 -1
  114. package/dist/wgpuSpriteBatch.d.ts +0 -12
  115. package/dist/wgpuSpriteBatch.d.ts.map +0 -1
  116. package/dist/wgpuSpriteBatch.js.map +0 -1
  117. package/dist/wgpuSpriteRenderer.d.ts +0 -3
  118. package/dist/wgpuSpriteRenderer.d.ts.map +0 -1
  119. package/dist/wgpuSpriteRenderer.js +0 -55
  120. package/dist/wgpuSpriteRenderer.js.map +0 -1
  121. package/dist/wgpuVideo.d.ts +0 -6
  122. package/dist/wgpuVideo.d.ts.map +0 -1
  123. package/dist/wgpuVideo.js +0 -63
  124. package/dist/wgpuVideo.js.map +0 -1
  125. package/src/wgpuBitmap.test.ts +0 -40
  126. package/src/wgpuRenderTargetNode2D.test.ts +0 -267
  127. package/src/wgpuSpriteRenderer.test.ts +0 -63
  128. package/src/wgpuVideo.test.ts +0 -59
@@ -1,40 +0,0 @@
1
- import { renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
2
- import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
3
- import { getOrCreateRenderProxy2D, prepareScene2DRender } from '@flighthq/render/contract';
4
- import { createBitmap } from '@flighthq/scene2d/contract';
5
-
6
- import { defaultWgpuBitmapRenderer, drawWgpuBitmap } from './wgpuBitmap';
7
-
8
- beforeAll(() => {
9
- installWgpuMock();
10
- });
11
-
12
- describe('defaultWgpuBitmapRenderer', () => {
13
- it('has createData and draw functions', () => {
14
- expect(typeof defaultWgpuBitmapRenderer.createData).toBe('function');
15
- expect(typeof defaultWgpuBitmapRenderer.submit).toBe('function');
16
- });
17
- });
18
-
19
- describe('drawWgpuBitmap', () => {
20
- it('does not throw when image source is null', async () => {
21
- const state = await createWgpuRenderStateForTest();
22
- renderWgpuBackground(state);
23
-
24
- const bitmap = createBitmap();
25
- prepareScene2DRender(state, bitmap);
26
- const renderProxy = getOrCreateRenderProxy2D(state, bitmap);
27
-
28
- expect(() => drawWgpuBitmap(state, renderProxy)).not.toThrow();
29
- submitWgpuRenderPass(state);
30
- });
31
-
32
- it('does not throw when renderPass is null', async () => {
33
- const state = await createWgpuRenderStateForTest();
34
- const bitmap = createBitmap();
35
- prepareScene2DRender(state, bitmap);
36
- const renderProxy = getOrCreateRenderProxy2D(state, bitmap);
37
-
38
- expect(() => drawWgpuBitmap(state, renderProxy)).not.toThrow();
39
- });
40
- });
@@ -1,267 +0,0 @@
1
- import type * as WgpuRenderWgpuModule from '@flighthq/render-wgpu/contract';
2
- import { createRenderProxy2D, createRenderState, setRenderStateBackgroundColor } from '@flighthq/render/contract';
3
- import { createRenderTargetNode2D } from '@flighthq/scene2d/contract';
4
- import type { WgpuRenderState, WgpuRenderTarget } from '@flighthq/types/contract';
5
- import { EntityRuntimeKey, RenderTargetNode2DKind } from '@flighthq/types/contract';
6
-
7
- import { scopeModuleMocks } from './moduleMockTestHelper';
8
- import type * as WgpuCacheModule from './wgpuCache';
9
- import type * as WgpuRenderTargetNode2DModule from './wgpuRenderTargetNode2D';
10
- import type * as WgpuSpriteBatchModule from './wgpuSpriteBatch';
11
-
12
- let beginWgpuFrame: typeof WgpuRenderWgpuModule.beginWgpuFrame;
13
- let beginWgpuRenderPass: typeof WgpuRenderWgpuModule.beginWgpuRenderPass;
14
- let createWgpuCacheState: typeof WgpuCacheModule.createWgpuCacheState;
15
- let createWgpuRenderStateRuntime: typeof WgpuRenderWgpuModule.createWgpuRenderStateRuntime;
16
- let createWgpuRenderTarget: typeof WgpuRenderWgpuModule.createWgpuRenderTarget;
17
- let defaultWgpuRenderTargetNode2DRenderer: typeof WgpuRenderTargetNode2DModule.defaultWgpuRenderTargetNode2DRenderer;
18
- let destroyWgpuRenderTarget: typeof WgpuRenderWgpuModule.destroyWgpuRenderTarget;
19
- let destroyWgpuRenderTargetNode2D: typeof WgpuRenderTargetNode2DModule.destroyWgpuRenderTargetNode2D;
20
- let drawWgpuRenderTargetResult: typeof WgpuRenderWgpuModule.drawWgpuRenderTargetResult;
21
- let enableWgpuRenderTargetNode2D: typeof WgpuRenderTargetNode2DModule.enableWgpuRenderTargetNode2D;
22
- let endWgpuRenderPass: typeof WgpuRenderWgpuModule.endWgpuRenderPass;
23
- let flushWgpuSpriteBatch: typeof WgpuSpriteBatchModule.flushWgpuSpriteBatch;
24
- let getWgpuRenderStateRuntime: typeof WgpuRenderWgpuModule.getWgpuRenderStateRuntime;
25
- let renderIntoWgpuRenderTargetNode2D: typeof WgpuRenderTargetNode2DModule.renderIntoWgpuRenderTargetNode2D;
26
- let resizeWgpuRenderTarget: typeof WgpuRenderWgpuModule.resizeWgpuRenderTarget;
27
- let submitWgpuRenderPass: typeof WgpuRenderWgpuModule.submitWgpuRenderPass;
28
-
29
- scopeModuleMocks(['./wgpuCache', './wgpuSpriteBatch', '@flighthq/render-wgpu']);
30
-
31
- beforeAll(async () => {
32
- vi.doMock('./wgpuSpriteBatch', async (importOriginal) => {
33
- const actual = await importOriginal<typeof WgpuSpriteBatchModule>();
34
- return { ...actual, flushWgpuSpriteBatch: vi.fn() };
35
- });
36
- vi.doMock('@flighthq/render-wgpu/contract', async (importOriginal) => {
37
- const actual = await importOriginal<typeof WgpuRenderWgpuModule>();
38
- return {
39
- ...actual,
40
- beginWgpuFrame: vi.fn((state: WgpuRenderState) => {
41
- getWgpuRenderStateRuntime(state).commandEncoder = {} as GPUCommandEncoder;
42
- }),
43
- beginWgpuRenderPass: vi.fn(),
44
- createWgpuRenderTarget: vi.fn(
45
- (_state: unknown, width: number, height: number): WgpuRenderTarget => ({
46
- bindGroup: {} as GPUBindGroup,
47
- clearColors: [],
48
- clearDepth: 1,
49
- colorSpace: 'srgb',
50
- depthStencilTexture: {} as GPUTexture,
51
- depthStencilView: {} as GPUTextureView,
52
- format: 'bgra8unorm',
53
- height,
54
- texture: {} as GPUTexture,
55
- view: {} as GPUTextureView,
56
- width,
57
- }),
58
- ),
59
- destroyWgpuRenderTarget: vi.fn(),
60
- drawWgpuRenderTargetResult: vi.fn(),
61
- endWgpuRenderPass: vi.fn(),
62
- resizeWgpuRenderTarget: vi.fn((_state: unknown, target: WgpuRenderTarget, width: number, height: number) => {
63
- target.width = width;
64
- target.height = height;
65
- }),
66
- submitWgpuRenderPass: vi.fn((state: WgpuRenderState) => {
67
- getWgpuRenderStateRuntime(state).commandEncoder = null;
68
- }),
69
- };
70
- });
71
-
72
- ({
73
- beginWgpuFrame,
74
- beginWgpuRenderPass,
75
- createWgpuRenderStateRuntime,
76
- createWgpuRenderTarget,
77
- destroyWgpuRenderTarget,
78
- drawWgpuRenderTargetResult,
79
- endWgpuRenderPass,
80
- getWgpuRenderStateRuntime,
81
- resizeWgpuRenderTarget,
82
- submitWgpuRenderPass,
83
- } = await import('@flighthq/render-wgpu/contract'));
84
- ({ createWgpuCacheState } = await import('./wgpuCache'));
85
- ({ flushWgpuSpriteBatch } = await import('./wgpuSpriteBatch'));
86
- ({
87
- defaultWgpuRenderTargetNode2DRenderer,
88
- destroyWgpuRenderTargetNode2D,
89
- enableWgpuRenderTargetNode2D,
90
- renderIntoWgpuRenderTargetNode2D,
91
- } = await import('./wgpuRenderTargetNode2D'));
92
- });
93
-
94
- beforeEach(() => {
95
- vi.clearAllMocks();
96
- });
97
-
98
- describe('defaultWgpuRenderTargetNode2DRenderer', () => {
99
- it('does nothing before the node has been populated', () => {
100
- const state = createState();
101
-
102
- defaultWgpuRenderTargetNode2DRenderer.submit(
103
- state,
104
- createRenderProxy2D(state, createRenderTargetNode2D({ height: 16, width: 32 })),
105
- );
106
-
107
- expect(flushWgpuSpriteBatch).not.toHaveBeenCalled();
108
- expect(drawWgpuRenderTargetResult).not.toHaveBeenCalled();
109
- });
110
-
111
- it('composites a screen-owned target while a cache state walks the node', () => {
112
- const screenState = createState();
113
- const cacheState = createWgpuCacheState(screenState);
114
- const node = createRenderTargetNode2D({ height: 16, width: 32 });
115
- renderIntoWgpuRenderTargetNode2D(screenState, node, () => {});
116
- const target = vi.mocked(createWgpuRenderTarget).mock.results.at(-1)?.value as WgpuRenderTarget;
117
- vi.mocked(drawWgpuRenderTargetResult).mockClear();
118
-
119
- const renderProxy = createRenderProxy2D(cacheState, node);
120
- defaultWgpuRenderTargetNode2DRenderer.submit(cacheState, renderProxy);
121
-
122
- expect(flushWgpuSpriteBatch).toHaveBeenCalledWith(cacheState);
123
- expect(drawWgpuRenderTargetResult).toHaveBeenCalledWith(cacheState, renderProxy, target, expect.anything());
124
- expect(vi.mocked(flushWgpuSpriteBatch).mock.invocationCallOrder[0]).toBeLessThan(
125
- vi.mocked(drawWgpuRenderTargetResult).mock.invocationCallOrder[0],
126
- );
127
- });
128
- });
129
-
130
- describe('destroyWgpuRenderTargetNode2D', () => {
131
- it('destroys the screen-owned target and recreates it on the next population', () => {
132
- const screenState = createState();
133
- const cacheState = createWgpuCacheState(screenState);
134
- const node = createRenderTargetNode2D({ height: 16, width: 32 });
135
- renderIntoWgpuRenderTargetNode2D(screenState, node, () => {});
136
- const target = vi.mocked(createWgpuRenderTarget).mock.results.at(-1)?.value as WgpuRenderTarget;
137
- vi.mocked(createWgpuRenderTarget).mockClear();
138
-
139
- destroyWgpuRenderTargetNode2D(cacheState, node);
140
-
141
- expect(destroyWgpuRenderTarget).toHaveBeenCalledWith(screenState, target);
142
-
143
- renderIntoWgpuRenderTargetNode2D(screenState, node, () => {});
144
- expect(createWgpuRenderTarget).toHaveBeenCalledTimes(1);
145
- });
146
- });
147
-
148
- describe('enableWgpuRenderTargetNode2D', () => {
149
- it('registers the compositor renderer for the node kind', () => {
150
- const state = createState();
151
-
152
- enableWgpuRenderTargetNode2D(state);
153
-
154
- expect(getWgpuRenderStateRuntime(state).rendererMap.get(RenderTargetNode2DKind)).toBe(
155
- defaultWgpuRenderTargetNode2DRenderer,
156
- );
157
- });
158
- });
159
-
160
- describe('renderIntoWgpuRenderTargetNode2D', () => {
161
- it('clears the target with the owning screen state background', () => {
162
- const state = createState();
163
- setRenderStateBackgroundColor(state, 0x101018ff);
164
-
165
- renderIntoWgpuRenderTargetNode2D(state, createRenderTargetNode2D({ height: 16, width: 32 }), () => {});
166
-
167
- const target = vi.mocked(createWgpuRenderTarget).mock.results.at(-1)?.value as WgpuRenderTarget;
168
- expect(target.clearColors[0]).toBe(0x101018ff);
169
- });
170
-
171
- it('hands the live frame and uniform cursor through a cache render state', () => {
172
- const screenState = createState();
173
- const screenRuntime = getWgpuRenderStateRuntime(screenState);
174
- const encoder = {} as GPUCommandEncoder;
175
- const pass = {} as GPURenderPassEncoder;
176
- screenRuntime.commandEncoder = encoder;
177
- screenRuntime.renderPass = pass;
178
- screenRuntime.uniformOffset = 128;
179
- const cacheState = createWgpuCacheState(screenState);
180
-
181
- renderIntoWgpuRenderTargetNode2D(cacheState, createRenderTargetNode2D({ height: 16, width: 32 }), (targetState) => {
182
- const cacheRuntime = getWgpuRenderStateRuntime(targetState);
183
- expect(cacheRuntime.commandEncoder).toBe(encoder);
184
- expect(cacheRuntime.renderPass).toBe(pass);
185
- expect(cacheRuntime.uniformOffset).toBe(128);
186
- cacheRuntime.uniformOffset = 256;
187
- });
188
-
189
- expect(screenRuntime.commandEncoder).toBe(encoder);
190
- expect(screenRuntime.renderPass).toBe(pass);
191
- expect(screenRuntime.uniformOffset).toBe(256);
192
- expect(beginWgpuFrame).not.toHaveBeenCalled();
193
- expect(submitWgpuRenderPass).not.toHaveBeenCalled();
194
- });
195
-
196
- it('opens and submits a standalone frame outside the visible frame', () => {
197
- const state = createState();
198
-
199
- renderIntoWgpuRenderTargetNode2D(state, createRenderTargetNode2D({ height: 16, width: 32 }), () => {});
200
-
201
- expect(beginWgpuFrame).toHaveBeenCalledWith(state);
202
- expect(submitWgpuRenderPass).toHaveBeenCalledWith(state);
203
- expect(getWgpuRenderStateRuntime(state).commandEncoder).toBeNull();
204
- });
205
-
206
- it('records into an active application frame without submitting it', () => {
207
- const state = createState();
208
- const encoder = {} as GPUCommandEncoder;
209
- getWgpuRenderStateRuntime(state).commandEncoder = encoder;
210
-
211
- renderIntoWgpuRenderTargetNode2D(state, createRenderTargetNode2D({ height: 16, width: 32 }), () => {});
212
-
213
- expect(beginWgpuFrame).not.toHaveBeenCalled();
214
- expect(submitWgpuRenderPass).not.toHaveBeenCalled();
215
- expect(getWgpuRenderStateRuntime(state).commandEncoder).toBe(encoder);
216
- });
217
-
218
- it('restores and submits the frame when the callback throws', () => {
219
- const state = createState();
220
-
221
- expect(() =>
222
- renderIntoWgpuRenderTargetNode2D(state, createRenderTargetNode2D({ height: 16, width: 32 }), () => {
223
- throw new Error('custom WebGPU draw failed');
224
- }),
225
- ).toThrow('custom WebGPU draw failed');
226
-
227
- expect(endWgpuRenderPass).toHaveBeenCalledWith(state);
228
- expect(submitWgpuRenderPass).toHaveBeenCalledWith(state);
229
- });
230
-
231
- it('reuses and resizes the target on later populations', () => {
232
- const state = createState();
233
- const node = createRenderTargetNode2D({ height: 48, width: 64 });
234
- renderIntoWgpuRenderTargetNode2D(state, node, () => {});
235
- const target = vi.mocked(createWgpuRenderTarget).mock.results.at(-1)?.value as WgpuRenderTarget;
236
-
237
- node.data.width = 24;
238
- node.data.height = 12;
239
- renderIntoWgpuRenderTargetNode2D(state, node, () => {});
240
-
241
- expect(createWgpuRenderTarget).toHaveBeenCalledTimes(1);
242
- expect(resizeWgpuRenderTarget).toHaveBeenLastCalledWith(state, target, 24, 12);
243
- });
244
-
245
- it('wraps the callback in a WebGPU render pass', () => {
246
- const state = createState();
247
- const callback = vi.fn();
248
-
249
- renderIntoWgpuRenderTargetNode2D(state, createRenderTargetNode2D({ height: 16, width: 32 }), callback);
250
-
251
- expect(callback).toHaveBeenCalledWith(state);
252
- const order = [
253
- vi.mocked(beginWgpuRenderPass).mock.invocationCallOrder.at(-1),
254
- callback.mock.invocationCallOrder.at(-1),
255
- vi.mocked(endWgpuRenderPass).mock.invocationCallOrder.at(-1),
256
- ];
257
- expect(order).toEqual([...order].sort((a, b) => (a ?? 0) - (b ?? 0)));
258
- });
259
- });
260
-
261
- function createState(): WgpuRenderState {
262
- const state = createRenderState() as WgpuRenderState;
263
- (state as { device: GPUDevice }).device = {} as GPUDevice;
264
- state[EntityRuntimeKey] = createWgpuRenderStateRuntime();
265
- getWgpuRenderStateRuntime(state).commandEncoder = null;
266
- return state;
267
- }
@@ -1,63 +0,0 @@
1
- import { createImageResource } from '@flighthq/image/contract';
2
- import { getWgpuRenderStateRuntime, renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
3
- import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
4
- import { getRenderProxy2D, prepareScene2DRender } from '@flighthq/render/contract';
5
- import { createSprite } from '@flighthq/sprite/contract';
6
- import type { TextureAtlas } from '@flighthq/types/contract';
7
-
8
- import { flushWgpuSpriteBatch } from './wgpuSpriteBatch';
9
- import { defaultWgpuSpriteRenderer } from './wgpuSpriteRenderer';
10
- import { registerStandardWgpuMaterial } from './wgpuStandardMaterial';
11
-
12
- beforeAll(() => {
13
- installWgpuMock();
14
- });
15
-
16
- describe('defaultWgpuSpriteRenderer', () => {
17
- it('has a createData function', () => {
18
- expect(typeof defaultWgpuSpriteRenderer.createData).toBe('function');
19
- });
20
-
21
- it('has a submit function', () => {
22
- expect(typeof defaultWgpuSpriteRenderer.submit).toBe('function');
23
- });
24
- });
25
-
26
- describe('defaultWgpuSpriteRenderer.submit', () => {
27
- it('does not throw when atlas is null', async () => {
28
- const state = await createWgpuRenderStateForTest();
29
- renderWgpuBackground(state);
30
-
31
- const sprite = createSprite();
32
- prepareScene2DRender(state, sprite);
33
- const renderProxy = getRenderProxy2D(state, sprite)!;
34
-
35
- expect(() => {
36
- defaultWgpuSpriteRenderer.submit(state, renderProxy);
37
- flushWgpuSpriteBatch(state as any);
38
- }).not.toThrow();
39
- submitWgpuRenderPass(state);
40
- });
41
-
42
- it('folds the region pivot through the sprite transform into batch translation', async () => {
43
- const state = await createWgpuRenderStateForTest();
44
- renderWgpuBackground(state);
45
- registerStandardWgpuMaterial(state);
46
- const atlas = {
47
- image: createImageResource(document.createElement('img')),
48
- regions: [{ height: 32, id: 0, name: null, pivotX: 7, pivotY: 9, width: 32, x: 0, y: 0 }],
49
- };
50
- const sprite = createSprite();
51
- sprite.data.atlas = atlas as unknown as TextureAtlas;
52
- prepareScene2DRender(state, sprite);
53
- const renderProxy = getRenderProxy2D(state, sprite)!;
54
- Object.assign(renderProxy.transform2D, { a: 2, b: 3, c: 4, d: 5, tx: 100, ty: 200 });
55
-
56
- defaultWgpuSpriteRenderer.submit(state, renderProxy);
57
-
58
- const data = getWgpuRenderStateRuntime(state).spriteBatchInstanceData;
59
- expect(data[4]).toBe(50);
60
- expect(data[5]).toBe(134);
61
- submitWgpuRenderPass(state);
62
- });
63
- });
@@ -1,59 +0,0 @@
1
- import { renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
2
- import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
3
- import { getOrCreateRenderProxy2D, prepareScene2DRender } from '@flighthq/render/contract';
4
- import { createVideo } from '@flighthq/scene2d/contract';
5
-
6
- import { createWgpuVideoData, defaultWgpuVideoRenderer, destroyWgpuVideoData, drawWgpuVideo } from './wgpuVideo';
7
-
8
- beforeAll(() => {
9
- installWgpuMock();
10
- });
11
-
12
- describe('createWgpuVideoData', () => {
13
- it('allocates per-node data with no texture entry yet', () => {
14
- const data = createWgpuVideoData({} as never, {} as never) as unknown as { entry: unknown };
15
- expect(data.entry).toBeNull();
16
- });
17
- });
18
-
19
- describe('defaultWgpuVideoRenderer', () => {
20
- it('has createData and submit functions', () => {
21
- expect(typeof defaultWgpuVideoRenderer.createData).toBe('function');
22
- expect(typeof defaultWgpuVideoRenderer.submit).toBe('function');
23
- });
24
- });
25
-
26
- describe('destroyWgpuVideoData', () => {
27
- it('destroys the GPU texture the node owns', () => {
28
- const destroy = vi.fn();
29
- destroyWgpuVideoData({} as never, { entry: { texture: { destroy } } } as never);
30
- expect(destroy).toHaveBeenCalled();
31
- });
32
-
33
- it('is a no-op when no texture entry was allocated', () => {
34
- expect(() => destroyWgpuVideoData({} as never, { entry: null } as never)).not.toThrow();
35
- });
36
- });
37
-
38
- describe('drawWgpuVideo', () => {
39
- it('does not throw when video source is null', async () => {
40
- const state = await createWgpuRenderStateForTest();
41
- renderWgpuBackground(state);
42
-
43
- const video = createVideo();
44
- prepareScene2DRender(state, video);
45
- const renderProxy = getOrCreateRenderProxy2D(state, video);
46
-
47
- expect(() => drawWgpuVideo(state, renderProxy)).not.toThrow();
48
- submitWgpuRenderPass(state);
49
- });
50
-
51
- it('does not throw when renderPass is null', async () => {
52
- const state = await createWgpuRenderStateForTest();
53
- const video = createVideo();
54
- prepareScene2DRender(state, video);
55
- const renderProxy = getOrCreateRenderProxy2D(state, video);
56
-
57
- expect(() => drawWgpuVideo(state, renderProxy)).not.toThrow();
58
- });
59
- });