@flighthq/texture 0.3.0-next.1032.e2b99fc → 0.3.0-next.1220.6982c21

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.
@@ -1,6 +1,7 @@
1
+ import { createEntity } from '@flighthq/entity/contract';
1
2
  import { createMatrix3, createVector2, inverseMatrix3 } from '@flighthq/geometry/contract';
2
- import type { ImageResource } from '@flighthq/types/contract';
3
- import { ImageTextureBackingKind, RenderTextureBackingKind } from '@flighthq/types/contract';
3
+ import type { Image, RenderTarget, Texture2D } from '@flighthq/types/contract';
4
+ import { ImageTextureSourceKind, RenderTargetTextureSourceKind } from '@flighthq/types/contract';
4
5
 
5
6
  import { createSampler, equalsSampler } from './sampler';
6
7
  import {
@@ -8,17 +9,18 @@ import {
8
9
  copyTexture,
9
10
  createTexture,
10
11
  equalsTexture,
11
- getTextureBackingKind,
12
+ getTextureSource,
13
+ getTextureSourceKind,
12
14
  getTextureHeight,
13
15
  getTextureInverseUvMatrix,
14
16
  getTextureUvMatrix,
15
17
  getTextureWidth,
16
- hasTextureBacking,
18
+ hasTextureSource,
17
19
  hasTextureUvTransform,
18
20
  isTextureReady,
19
21
  resetTextureUvTransform,
20
22
  setTextureFlip,
21
- setTextureImage,
23
+ setTextureSource,
22
24
  setTextureUvOffset,
23
25
  setTextureUvFromPixelRect,
24
26
  setTextureUvRotation,
@@ -26,7 +28,16 @@ import {
26
28
  transformTextureUv,
27
29
  } from './texture';
28
30
 
29
- const fakeImage = { height: 64, kind: ImageTextureBackingKind, width: 32 } as ImageResource;
31
+ const fakeImage = { height: 64, kind: ImageTextureSourceKind, width: 32 } as Image;
32
+
33
+ function makeRenderTarget(width: number, height: number): RenderTarget {
34
+ return createEntity({
35
+ height,
36
+ kind: RenderTargetTextureSourceKind,
37
+ version: 0,
38
+ width,
39
+ }) as RenderTarget;
40
+ }
30
41
 
31
42
  // Applies a column-major 3×3 uv matrix to (u, v, 1), writing the transformed coordinate into out.
32
43
  function multiplyMatrix3Uv(out: { x: number; y: number }, matrix: { m: ArrayLike<number> }, u: number, v: number) {
@@ -39,7 +50,8 @@ describe('cloneTexture', () => {
39
50
  it('shares the image but deep-clones the sampler and uv vectors', () => {
40
51
  const source = createTexture({
41
52
  colorSpace: 'linear',
42
- storage: { dimension: '2d', image: fakeImage },
53
+ dimension: '2d',
54
+ source: fakeImage,
43
55
  uvRotation: 0.5,
44
56
  });
45
57
  source.uvOffset.x = 0.25;
@@ -48,8 +60,8 @@ describe('cloneTexture', () => {
48
60
  const copy = cloneTexture(source);
49
61
 
50
62
  expect(copy).not.toBe(source);
51
- expect(copy.storage).not.toBe(source.storage);
52
- expect(copy.storage.image).toBe(fakeImage);
63
+ expect(copy.dimension).toBe('2d');
64
+ expect(getTextureSource(copy)).toBe(fakeImage);
53
65
  expect(copy.colorSpace).toStrictEqual('linear');
54
66
  expect(copy.uvRotation).toStrictEqual(0.5);
55
67
  expect(copy.sampler).not.toBe(source.sampler);
@@ -63,18 +75,13 @@ describe('cloneTexture', () => {
63
75
  });
64
76
 
65
77
  it('preserves a render-target descriptor while cloning sampling state', () => {
66
- const target = {
67
- colorSpace: 'linear' as const,
68
- height: 32,
69
- kind: RenderTextureBackingKind,
70
- width: 64,
71
- };
72
- const source = createTexture({ storage: { dimension: '2d', image: null, target } });
78
+ const target = makeRenderTarget(64, 32);
79
+ target.colorSpace = 'linear';
80
+ const source = createTexture({ dimension: '2d', source: target });
73
81
 
74
82
  const copy = cloneTexture(source);
75
83
 
76
- expect(copy.storage.target).toBe(target);
77
- expect(copy.storage).not.toBe(source.storage);
84
+ expect(getTextureSource(copy)).toBe(target);
78
85
  expect(copy.sampler).not.toBe(source.sampler);
79
86
  });
80
87
  });
@@ -83,30 +90,30 @@ describe('copyTexture', () => {
83
90
  it('writes every field from source into a distinct out, preserving out entity identities', () => {
84
91
  const source = createTexture({
85
92
  colorSpace: 'linear',
86
- storage: { dimension: '2d', image: fakeImage },
93
+ dimension: '2d',
94
+ source: fakeImage,
87
95
  uvRotation: 1,
88
96
  });
89
97
  source.uvScale.x = 4;
90
98
  const out = createTexture();
91
99
  const outSampler = out.sampler;
92
100
  const outOffset = out.uvOffset;
93
- const outStorage = out.storage;
94
101
 
95
102
  copyTexture(out, source);
96
103
 
97
- expect(out.storage.image).toBe(fakeImage);
104
+ expect(getTextureSource(out)).toBe(fakeImage);
98
105
  expect(out.colorSpace).toStrictEqual('linear');
99
106
  expect(out.uvRotation).toStrictEqual(1);
100
107
  expect(out.uvScale.x).toStrictEqual(4);
101
108
  expect(out.sampler).toBe(outSampler);
102
- expect(out.storage).toBe(outStorage);
103
109
  expect(out.uvOffset).toBe(outOffset);
104
110
  });
105
111
 
106
112
  it('is safe when out aliases source', () => {
107
113
  const source = createTexture({
108
114
  colorSpace: 'linear',
109
- storage: { dimension: '2d', image: fakeImage },
115
+ dimension: '2d',
116
+ source: fakeImage,
110
117
  uvRotation: 2,
111
118
  });
112
119
  source.uvScale.x = 7;
@@ -114,18 +121,30 @@ describe('copyTexture', () => {
114
121
  copyTexture(source, source);
115
122
 
116
123
  expect(source.colorSpace).toStrictEqual('linear');
117
- expect(source.storage.image).toBe(fakeImage);
124
+ expect(getTextureSource(source)).toBe(fakeImage);
118
125
  expect(source.uvRotation).toStrictEqual(2);
119
126
  expect(source.uvScale.x).toStrictEqual(7);
120
127
  });
128
+
129
+ it('refuses to change the creation-time dimension', () => {
130
+ const out = createTexture();
131
+ const cube = createTexture({ dimension: 'cube' });
132
+
133
+ expect(() => copyTexture(out, cube)).toThrow('copyTexture requires matching dimensions');
134
+ expect(out.dimension).toBe('2d');
135
+ expect(out.source).toBeNull();
136
+ });
121
137
  });
122
138
 
123
139
  describe('createTexture', () => {
124
- it('applies the default unbound, srgb, identity-transform state', () => {
140
+ it('creates a flat Texture2D with the default unbound, srgb, identity-transform state', () => {
125
141
  const texture = createTexture();
126
142
 
127
- expect(texture.storage.image).toBeNull();
128
- expect(texture.storage.dimension).toStrictEqual('2d');
143
+ expectTypeOf(texture).toEqualTypeOf<Texture2D>();
144
+ expect(texture).not.toHaveProperty('storage');
145
+ expect(texture.dimension).toStrictEqual('2d');
146
+ expect(texture.source).toBeNull();
147
+ expect(getTextureSource(texture)).toBeNull();
129
148
  expect(texture.colorSpace).toStrictEqual('srgb');
130
149
  expect(texture.version).toStrictEqual(0);
131
150
  expect(texture.uvRotation).toStrictEqual(0);
@@ -147,17 +166,17 @@ describe('createTexture', () => {
147
166
 
148
167
  describe('equalsTexture', () => {
149
168
  it('is true for textures with identical state and same image reference', () => {
150
- const a = createTexture({ colorSpace: 'linear', storage: { dimension: '2d', image: fakeImage } });
151
- const b = createTexture({ colorSpace: 'linear', storage: { dimension: '2d', image: fakeImage } });
169
+ const a = createTexture({ colorSpace: 'linear', dimension: '2d', source: fakeImage });
170
+ const b = createTexture({ colorSpace: 'linear', dimension: '2d', source: fakeImage });
152
171
 
153
172
  expect(equalsTexture(a, b)).toBe(true);
154
173
  expect(equalsTexture(a, a)).toBe(true);
155
174
  });
156
175
 
157
176
  it('is false when the image reference differs', () => {
158
- const other = { width: 4, height: 4 } as ImageResource;
159
- const a = createTexture({ storage: { dimension: '2d', image: fakeImage } });
160
- const b = createTexture({ storage: { dimension: '2d', image: other } });
177
+ const other = { width: 4, height: 4 } as Image;
178
+ const a = createTexture({ dimension: '2d', source: fakeImage });
179
+ const b = createTexture({ dimension: '2d', source: other });
161
180
 
162
181
  expect(equalsTexture(a, b)).toBe(false);
163
182
  });
@@ -208,29 +227,9 @@ describe('equalsTexture', () => {
208
227
  });
209
228
  });
210
229
 
211
- describe('getTextureBackingKind', () => {
212
- it('reads the key from the active image or target backing', () => {
213
- expect(getTextureBackingKind(createTexture())).toBeNull();
214
- expect(getTextureBackingKind(createTexture({ storage: { dimension: '2d', image: fakeImage } }))).toBe(
215
- ImageTextureBackingKind,
216
- );
217
- expect(
218
- getTextureBackingKind(
219
- createTexture({
220
- storage: {
221
- dimension: '2d',
222
- image: null,
223
- target: { height: 8, kind: RenderTextureBackingKind, width: 8 },
224
- },
225
- }),
226
- ),
227
- ).toBe(RenderTextureBackingKind);
228
- });
229
- });
230
-
231
230
  describe('getTextureHeight', () => {
232
231
  it('returns the image height when an image is bound', () => {
233
- const texture = createTexture({ storage: { dimension: '2d', image: fakeImage } });
232
+ const texture = createTexture({ dimension: '2d', source: fakeImage });
234
233
 
235
234
  expect(getTextureHeight(texture)).toStrictEqual(64);
236
235
  });
@@ -241,13 +240,10 @@ describe('getTextureHeight', () => {
241
240
  expect(getTextureHeight(texture)).toStrictEqual(-1);
242
241
  });
243
242
 
244
- it('returns the render target height when there is no CPU image', () => {
243
+ it('returns the render-target source height', () => {
245
244
  const texture = createTexture({
246
- storage: {
247
- dimension: '2d',
248
- image: null,
249
- target: { height: 48, kind: RenderTextureBackingKind, width: 96 },
250
- },
245
+ dimension: '2d',
246
+ source: makeRenderTarget(96, 48),
251
247
  });
252
248
 
253
249
  expect(getTextureHeight(texture)).toStrictEqual(48);
@@ -289,6 +285,36 @@ describe('getTextureInverseUvMatrix', () => {
289
285
  });
290
286
  });
291
287
 
288
+ describe('getTextureSource', () => {
289
+ it('returns the direct source and the first bound source in a layered texture', () => {
290
+ const direct = createTexture({ dimension: '2d', source: fakeImage });
291
+ const layered = createTexture({ dimension: '2d-array', sources: [null, fakeImage] });
292
+
293
+ expect(getTextureSource(direct)).toBe(fakeImage);
294
+ expect(getTextureSource(layered)).toBe(fakeImage);
295
+ });
296
+
297
+ it('returns null when every source slot is unbound', () => {
298
+ expect(getTextureSource(createTexture())).toBeNull();
299
+ expect(getTextureSource(createTexture({ dimension: '2d-array', sources: [null] }))).toBeNull();
300
+ });
301
+ });
302
+
303
+ describe('getTextureSourceKind', () => {
304
+ it('reads the key from the active source', () => {
305
+ expect(getTextureSourceKind(createTexture())).toBeNull();
306
+ expect(getTextureSourceKind(createTexture({ dimension: '2d', source: fakeImage }))).toBe(ImageTextureSourceKind);
307
+ expect(
308
+ getTextureSourceKind(
309
+ createTexture({
310
+ dimension: '2d',
311
+ source: makeRenderTarget(8, 8),
312
+ }),
313
+ ),
314
+ ).toBe(RenderTargetTextureSourceKind);
315
+ });
316
+ });
317
+
292
318
  describe('getTextureUvMatrix', () => {
293
319
  it('produces the identity matrix for the default uv transform', () => {
294
320
  const texture = createTexture();
@@ -385,7 +411,7 @@ describe('getTextureUvMatrix', () => {
385
411
 
386
412
  describe('getTextureWidth', () => {
387
413
  it('returns the image width when an image is bound', () => {
388
- const texture = createTexture({ storage: { dimension: '2d', image: fakeImage } });
414
+ const texture = createTexture({ dimension: '2d', source: fakeImage });
389
415
 
390
416
  expect(getTextureWidth(texture)).toStrictEqual(32);
391
417
  });
@@ -396,31 +422,25 @@ describe('getTextureWidth', () => {
396
422
  expect(getTextureWidth(texture)).toStrictEqual(-1);
397
423
  });
398
424
 
399
- it('returns the render target width when there is no CPU image', () => {
425
+ it('returns the render-target source width', () => {
400
426
  const texture = createTexture({
401
- storage: {
402
- dimension: '2d',
403
- image: null,
404
- target: { height: 48, kind: RenderTextureBackingKind, width: 96 },
405
- },
427
+ dimension: '2d',
428
+ source: makeRenderTarget(96, 48),
406
429
  });
407
430
 
408
431
  expect(getTextureWidth(texture)).toStrictEqual(96);
409
432
  });
410
433
  });
411
434
 
412
- describe('hasTextureBacking', () => {
413
- it('detects image and target backings without duplicating their discriminant', () => {
414
- expect(hasTextureBacking(createTexture())).toBe(false);
415
- expect(hasTextureBacking(createTexture({ storage: { dimension: '2d', image: fakeImage } }))).toBe(true);
435
+ describe('hasTextureSource', () => {
436
+ it('detects CPU and GPU sources through the same field', () => {
437
+ expect(hasTextureSource(createTexture())).toBe(false);
438
+ expect(hasTextureSource(createTexture({ dimension: '2d', source: fakeImage }))).toBe(true);
416
439
  expect(
417
- hasTextureBacking(
440
+ hasTextureSource(
418
441
  createTexture({
419
- storage: {
420
- dimension: '2d',
421
- image: null,
422
- target: { height: 8, kind: RenderTextureBackingKind, width: 8 },
423
- },
442
+ dimension: '2d',
443
+ source: makeRenderTarget(8, 8),
424
444
  }),
425
445
  ),
426
446
  ).toBe(true);
@@ -473,14 +493,14 @@ describe('isTextureReady', () => {
473
493
 
474
494
  expect(isTextureReady(texture)).toBe(false);
475
495
 
476
- texture.storage.image = fakeImage;
496
+ setTextureSource(texture, fakeImage);
477
497
  expect(isTextureReady(texture)).toBe(true);
478
498
  });
479
499
  });
480
500
 
481
501
  describe('resetTextureUvTransform', () => {
482
502
  it('restores the identity transform while leaving image, color space, and sampler untouched', () => {
483
- const texture = createTexture({ colorSpace: 'linear', storage: { dimension: '2d', image: fakeImage } });
503
+ const texture = createTexture({ colorSpace: 'linear', dimension: '2d', source: fakeImage });
484
504
  const sampler = texture.sampler;
485
505
  setTextureUvOffset(texture, 0.4, 0.6);
486
506
  setTextureUvRotation(texture, Math.PI);
@@ -494,7 +514,7 @@ describe('resetTextureUvTransform', () => {
494
514
  expect(texture.uvScale.x).toStrictEqual(1);
495
515
  expect(texture.uvScale.y).toStrictEqual(1);
496
516
  expect(texture.colorSpace).toStrictEqual('linear');
497
- expect(texture.storage.image).toBe(fakeImage);
517
+ expect(getTextureSource(texture)).toBe(fakeImage);
498
518
  expect(texture.sampler).toBe(sampler);
499
519
  });
500
520
  });
@@ -512,19 +532,19 @@ describe('setTextureFlip', () => {
512
532
  });
513
533
  });
514
534
 
515
- describe('setTextureImage', () => {
535
+ describe('setTextureSource', () => {
516
536
  it('binds and clears the image in place and advances the u32 version', () => {
517
537
  const texture = createTexture();
518
538
 
519
- setTextureImage(texture, fakeImage);
520
- expect(texture.storage.image).toBe(fakeImage);
539
+ setTextureSource(texture, fakeImage);
540
+ expect(getTextureSource(texture)).toBe(fakeImage);
521
541
  expect(texture.version).toStrictEqual(1);
522
542
 
523
- setTextureImage(texture, fakeImage);
543
+ setTextureSource(texture, fakeImage);
524
544
  expect(texture.version).toStrictEqual(1);
525
545
 
526
- setTextureImage(texture, null);
527
- expect(texture.storage.image).toBeNull();
546
+ setTextureSource(texture, null);
547
+ expect(getTextureSource(texture)).toBeNull();
528
548
  expect(texture.version).toStrictEqual(2);
529
549
  });
530
550
  });
@@ -532,7 +552,8 @@ describe('setTextureImage', () => {
532
552
  describe('setTextureUvFromPixelRect', () => {
533
553
  it('normalizes a pixel rectangle against the texture dimensions', () => {
534
554
  const texture = createTexture({
535
- storage: { dimension: '2d', image: { height: 100, width: 200 } as ImageResource },
555
+ dimension: '2d',
556
+ source: { height: 100, width: 200 } as Image,
536
557
  });
537
558
  setTextureUvFromPixelRect(texture, 20, 10, 50, 25);
538
559
  expect(texture.uvOffset.x).toBeCloseTo(0.1);
@@ -1,6 +1,7 @@
1
1
  import { createMatrix3, createVector2 } from '@flighthq/geometry/contract';
2
- import type { ImageResource, VideoResource } from '@flighthq/types/contract';
2
+ import type { Image, VideoResource } from '@flighthq/types/contract';
3
3
 
4
+ import { getTextureSource } from './texture';
4
5
  import {
5
6
  advanceVideoTexture,
6
7
  cloneVideoTexture,
@@ -19,27 +20,28 @@ import {
19
20
  function makeVideoResource(readyState = 4, videoWidth = 320, videoHeight = 240): VideoResource {
20
21
  return {
21
22
  element: { readyState, videoWidth, videoHeight } as unknown as HTMLVideoElement,
23
+ objectUrl: null,
22
24
  };
23
25
  }
24
26
 
25
27
  describe('advanceVideoTexture', () => {
26
- it('bumps the backing and Texture versions and returns the new value', () => {
28
+ it('bumps the source and Texture versions and returns the new value', () => {
27
29
  const vt = createVideoTexture(makeVideoResource());
28
30
  expect(vt.version).toBe(0xffffffff);
29
31
  expect(advanceVideoTexture(vt)).toBe(0);
30
32
  expect(advanceVideoTexture(vt)).toBe(1);
31
33
  expect(vt.version).toBe(1);
32
- expect(vt.storage.image?.version).toBe(1);
34
+ expect(getTextureSource(vt)?.version).toBe(1);
33
35
  });
34
36
  });
35
37
 
36
38
  describe('cloneVideoTexture', () => {
37
- it('shares the backing but deep-clones sampler and uv vectors', () => {
39
+ it('shares the source but deep-clones sampler and uv vectors', () => {
38
40
  const source = makeVideoResource();
39
41
  const vt = createVideoTexture(source, { uvOffset: createVector2(2, 3) });
40
42
  advanceVideoTexture(vt);
41
43
  const clone = cloneVideoTexture(vt);
42
- expect(clone.storage.image).toBe(vt.storage.image);
44
+ expect(getTextureSource(clone)).toBe(getTextureSource(vt));
43
45
  expect(clone.sampler).not.toBe(vt.sampler);
44
46
  expect(clone.uvOffset).not.toBe(vt.uvOffset);
45
47
  expect(clone.uvOffset.x).toBe(2);
@@ -55,7 +57,7 @@ describe('copyVideoTexture', () => {
55
57
  copyVideoTexture(b, a);
56
58
  expect(b.colorSpace).toBe('linear');
57
59
  expect(b.version).toBe(0);
58
- expect(b.storage.image).toBe(a.storage.image);
60
+ expect(getTextureSource(b)).toBe(getTextureSource(a));
59
61
  expect(b.uvScale.x).toBe(4);
60
62
  copyVideoTexture(a, a);
61
63
  expect(a.uvScale.x).toBe(4);
@@ -63,11 +65,11 @@ describe('copyVideoTexture', () => {
63
65
  });
64
66
 
65
67
  describe('createVideoTexture', () => {
66
- it('returns a universal srgb Texture with a borrowed host-image backing', () => {
68
+ it('returns a universal srgb Texture with a borrowed host-image source', () => {
67
69
  const source = makeVideoResource();
68
70
  const vt = createVideoTexture(source);
69
71
  expect(vt.colorSpace).toBe('srgb');
70
- expect((vt.storage.image as ImageResource).source).toBe(source.element);
72
+ expect((getTextureSource(vt) as Image).source).toBe(source.element);
71
73
  expect(vt.version).toBe(0xffffffff);
72
74
  expect(vt.uvOffset.x).toBe(0);
73
75
  expect(vt.uvScale.x).toBe(1);
@@ -79,7 +81,7 @@ describe('getVideoTextureHeight', () => {
79
81
  it('returns the element videoHeight when a frame is decoded, else -1', () => {
80
82
  expect(getVideoTextureHeight(createVideoTexture(makeVideoResource(4, 320, 240)))).toBe(240);
81
83
  expect(getVideoTextureHeight(createVideoTexture(makeVideoResource(0, 0, 0)))).toBe(-1);
82
- expect(getVideoTextureHeight(createVideoTexture({ element: null }))).toBe(-1);
84
+ expect(getVideoTextureHeight(createVideoTexture({ element: null, objectUrl: null }))).toBe(-1);
83
85
  });
84
86
  });
85
87
 
@@ -122,7 +124,7 @@ describe('getVideoTextureWidth', () => {
122
124
  it('returns the element videoWidth when a frame is decoded, else -1', () => {
123
125
  expect(getVideoTextureWidth(createVideoTexture(makeVideoResource(4, 320, 240)))).toBe(320);
124
126
  expect(getVideoTextureWidth(createVideoTexture(makeVideoResource(0, 0, 0)))).toBe(-1);
125
- expect(getVideoTextureWidth(createVideoTexture({ element: null }))).toBe(-1);
127
+ expect(getVideoTextureWidth(createVideoTexture({ element: null, objectUrl: null }))).toBe(-1);
126
128
  });
127
129
  });
128
130
 
@@ -131,7 +133,7 @@ describe('isVideoTextureFrameReady', () => {
131
133
  expect(isVideoTextureFrameReady(createVideoTexture(makeVideoResource(4, 320, 240)))).toBe(true);
132
134
  expect(isVideoTextureFrameReady(createVideoTexture(makeVideoResource(1, 320, 240)))).toBe(false);
133
135
  expect(isVideoTextureFrameReady(createVideoTexture(makeVideoResource(4, 0, 0)))).toBe(false);
134
- expect(isVideoTextureFrameReady(createVideoTexture({ element: null }))).toBe(false);
136
+ expect(isVideoTextureFrameReady(createVideoTexture({ element: null, objectUrl: null }))).toBe(false);
135
137
  });
136
138
  });
137
139
 
@@ -142,7 +144,7 @@ describe('resetVideoTextureFrame', () => {
142
144
  advanceVideoTexture(vt);
143
145
  resetVideoTextureFrame(vt);
144
146
  expect(vt.version).toBe(0xffffffff);
145
- expect(vt.storage.image?.version).toBe(0xffffffff);
147
+ expect(getTextureSource(vt)?.version).toBe(0xffffffff);
146
148
  });
147
149
  });
148
150
 
@@ -152,7 +154,7 @@ describe('setVideoTextureSource', () => {
152
154
  advanceVideoTexture(vt);
153
155
  const next = makeVideoResource(4, 640, 480);
154
156
  setVideoTextureSource(vt, next);
155
- expect((vt.storage.image as ImageResource).source).toBe(next.element);
157
+ expect((getTextureSource(vt) as Image).source).toBe(next.element);
156
158
  expect(vt.version).toBe(0xffffffff);
157
159
  expect(getVideoTextureWidth(vt)).toBe(640);
158
160
  });
@@ -0,0 +1,37 @@
1
+ import { createEntity } from '@flighthq/entity/contract';
2
+ import type { VoxelGrid } from '@flighthq/types/contract';
3
+ import { VoxelGridTextureSourceKind } from '@flighthq/types/contract';
4
+
5
+ import { invalidateVoxelGrid } from './voxelGrid';
6
+
7
+ function voxelGrid(version: number): VoxelGrid {
8
+ return createEntity({
9
+ data: new Uint8Array(32),
10
+ depth: 2,
11
+ format: 'rgba8unorm' as const,
12
+ height: 2,
13
+ kind: VoxelGridTextureSourceKind,
14
+ version,
15
+ width: 2,
16
+ }) as VoxelGrid;
17
+ }
18
+
19
+ describe('invalidateVoxelGrid', () => {
20
+ it('advances the shared content version without replacing voxel bytes', () => {
21
+ const grid = voxelGrid(0);
22
+ const data = grid.data;
23
+
24
+ invalidateVoxelGrid(grid);
25
+
26
+ expect(grid.version).toBe(1);
27
+ expect(grid.data).toBe(data);
28
+ });
29
+
30
+ it('wraps the content version as u32', () => {
31
+ const grid = voxelGrid(0xffffffff);
32
+
33
+ invalidateVoxelGrid(grid);
34
+
35
+ expect(grid.version).toBe(0);
36
+ });
37
+ });