@flighthq/texture 0.2.0 → 0.2.1-next.410.a23f189

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './cubeTexture';
2
2
  export * from './sampler';
3
3
  export * from './texture';
4
+ export * from './videoTexture';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './cubeTexture';
2
2
  export * from './sampler';
3
3
  export * from './texture';
4
+ export * from './videoTexture';
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
package/dist/texture.d.ts CHANGED
@@ -1,12 +1,13 @@
1
- import type { ImageResource, Matrix3Like, Texture, TextureLike, Vector2Like } from '@flighthq/types';
1
+ import type { ImageResource, Matrix3Like, Texture, TextureLike, TextureUvTransform, Vector2Like } from '@flighthq/types';
2
2
  export declare function cloneTexture(source: Readonly<TextureLike>): Texture;
3
3
  export declare function copyTexture(out: TextureLike, source: Readonly<TextureLike>): void;
4
4
  export declare function createTexture(opts?: Readonly<Partial<TextureLike>>): Texture;
5
5
  export declare function equalsTexture(a: Readonly<TextureLike> | null | undefined, b: Readonly<TextureLike> | null | undefined): boolean;
6
6
  export declare function getTextureHeight(texture: Readonly<TextureLike>): number;
7
7
  export declare function getTextureInverseUvMatrix(out: Matrix3Like, texture: Readonly<TextureLike>): void;
8
- export declare function getTextureUvMatrix(out: Matrix3Like, texture: Readonly<TextureLike>): void;
8
+ export declare function getTextureUvMatrix(out: Matrix3Like, texture: Readonly<TextureUvTransform>): void;
9
9
  export declare function getTextureWidth(texture: Readonly<TextureLike>): number;
10
+ export declare function hasTextureUvTransform(texture: Readonly<TextureUvTransform>): boolean;
10
11
  export declare function isTextureReady(texture: Readonly<TextureLike>): boolean;
11
12
  export declare function resetTextureUvTransform(texture: TextureLike): void;
12
13
  export declare function setTextureImage(texture: TextureLike, image: ImageResource | null): void;
@@ -1 +1 @@
1
- {"version":3,"file":"texture.d.ts","sourceRoot":"","sources":["../src/texture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAOrG,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CASnE;AAKD,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAUjF;AAKD,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAS5E;AAID,wBAAgB,aAAa,CAC3B,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3C,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAaT;AAGD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAEvE;AAQD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAGhG;AAQD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAkBzF;AAGD,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAEtE;AAID,wBAAgB,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAEtE;AAID,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAMlE;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CAEvF;AAID,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGnF;AAGD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhF;AAGD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGlF;AAMD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAU/G"}
1
+ {"version":3,"file":"texture.d.ts","sourceRoot":"","sources":["../src/texture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,OAAO,EACP,WAAW,EACX,kBAAkB,EAClB,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAOzB,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAUnE;AAKD,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAYjF;AAKD,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAU5E;AAID,wBAAgB,aAAa,CAC3B,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3C,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAaT;AAGD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAEvE;AAQD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAGhG;AASD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAkBhG;AAGD,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAEtE;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAQpF;AAID,wBAAgB,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAEtE;AAID,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAMlE;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CAEvF;AAID,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGnF;AAGD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhF;AAGD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGlF;AAMD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAU/G"}
package/dist/texture.js CHANGED
@@ -8,6 +8,7 @@ export function cloneTexture(source) {
8
8
  return createEntity({
9
9
  colorSpace: source.colorSpace,
10
10
  image: source.image,
11
+ resource: source.resource ?? null,
11
12
  sampler: cloneSampler(source.sampler),
12
13
  uvOffset: cloneVector2(source.uvOffset),
13
14
  uvRotation: source.uvRotation,
@@ -20,12 +21,14 @@ export function cloneTexture(source) {
20
21
  export function copyTexture(out, source) {
21
22
  const colorSpace = source.colorSpace;
22
23
  const image = source.image;
24
+ const resource = source.resource ?? null;
23
25
  const uvRotation = source.uvRotation;
24
26
  copySampler(out.sampler, source.sampler);
25
27
  copyVector2(out.uvOffset, source.uvOffset);
26
28
  copyVector2(out.uvScale, source.uvScale);
27
29
  out.colorSpace = colorSpace;
28
30
  out.image = image;
31
+ out.resource = resource;
29
32
  out.uvRotation = uvRotation;
30
33
  }
31
34
  // Builds a Texture: an unbound image slot (null), a default Sampler, 'srgb' color space (the
@@ -35,6 +38,7 @@ export function createTexture(opts) {
35
38
  return createEntity({
36
39
  colorSpace: opts?.colorSpace ?? 'srgb',
37
40
  image: opts?.image ?? null,
41
+ resource: opts?.resource ?? null,
38
42
  sampler: opts?.sampler ? cloneSampler(opts.sampler) : createSampler(),
39
43
  uvOffset: opts?.uvOffset ? cloneVector2(opts.uvOffset) : createVector2(0, 0),
40
44
  uvRotation: opts?.uvRotation ?? 0,
@@ -72,8 +76,9 @@ export function getTextureInverseUvMatrix(out, texture) {
72
76
  inverseMatrix3(out, out);
73
77
  }
74
78
  // Composes the KHR_texture_transform fields (uvOffset, uvRotation, uvScale) into the 3×3 matrix
75
- // a shader consumes at sample time. Row-major layout matching @flighthq/geometry Matrix3.
76
- // The resulting transform applies: scale rotate translate, per the KHR_texture_transform spec:
79
+ // a shader consumes at sample time. Column-major layout matching @flighthq/geometry Matrix3, so it
80
+ // uploads to a GL/WGSL mat3 uniform with no transpose. The resulting transform applies:
81
+ // scale → rotate → translate, per the KHR_texture_transform spec:
77
82
  // row 0 = [sx*cos(r), -sy*sin(r), tx]; row 1 = [sx*sin(r), sy*cos(r), ty]; row 2 = [0, 0, 1].
78
83
  // Out-param form — write result into a pre-allocated Matrix3 to avoid per-call allocation.
79
84
  // Safe when out is an unrelated scratch; not intended for aliased input (no in-param here).
@@ -86,20 +91,31 @@ export function getTextureUvMatrix(out, texture) {
86
91
  const cosR = Math.cos(r);
87
92
  const sinR = Math.sin(r);
88
93
  const m = out.m;
89
- m[0] = sx * cosR;
90
- m[1] = -sy * sinR;
91
- m[2] = tx;
92
- m[3] = sx * sinR;
93
- m[4] = sy * cosR;
94
- m[5] = ty;
95
- m[6] = 0;
96
- m[7] = 0;
97
- m[8] = 1;
94
+ m[0] = sx * cosR; // (0,0)
95
+ m[1] = sx * sinR; // (1,0)
96
+ m[2] = 0; // (2,0)
97
+ m[3] = -sy * sinR; // (0,1)
98
+ m[4] = sy * cosR; // (1,1)
99
+ m[5] = 0; // (2,1)
100
+ m[6] = tx; // (0,2)
101
+ m[7] = ty; // (1,2)
102
+ m[8] = 1; // (2,2)
98
103
  }
99
104
  // Returns the pixel width of the texture's bound image, or -1 when no image is bound.
100
105
  export function getTextureWidth(texture) {
101
106
  return texture.image !== null ? texture.image.width : -1;
102
107
  }
108
+ // True when the texture carries a non-identity KHR_texture_transform — any non-unit scale, non-zero
109
+ // offset, or non-zero rotation. GPU material renderers gate the HAS_UV_TRANSFORM shader variant on
110
+ // this so an untiled surface pays nothing for the uv-transform uniform or the extra vertex multiply;
111
+ // only a texture that actually remaps its uv compiles the transforming path.
112
+ export function hasTextureUvTransform(texture) {
113
+ return (texture.uvScale.x !== 1 ||
114
+ texture.uvScale.y !== 1 ||
115
+ texture.uvOffset.x !== 0 ||
116
+ texture.uvOffset.y !== 0 ||
117
+ texture.uvRotation !== 0);
118
+ }
103
119
  // True once the texture references a pixel source. A texture with a null image is treated as an
104
120
  // absent slot by materials, so this is the gate a material samples behind.
105
121
  export function isTextureReady(texture) {
@@ -1 +1 @@
1
- {"version":3,"file":"texture.js","sourceRoot":"","sources":["../src/texture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"texture.js","sourceRoot":"","sources":["../src/texture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Matrix3Like, VideoResource, VideoTexture, VideoTextureLike } from '@flighthq/types';
2
+ export declare function advanceVideoTexture(videoTexture: VideoTextureLike): number;
3
+ export declare function cloneVideoTexture(source: Readonly<VideoTextureLike>): VideoTexture;
4
+ export declare function copyVideoTexture(out: VideoTextureLike, source: Readonly<VideoTextureLike>): void;
5
+ export declare function createVideoTexture(source: VideoResource, opts?: Readonly<Partial<VideoTextureLike>>): VideoTexture;
6
+ export declare function getVideoTextureHeight(videoTexture: Readonly<VideoTextureLike>): number;
7
+ export declare function getVideoTextureInverseUvMatrix(out: Matrix3Like, videoTexture: Readonly<VideoTextureLike>): void;
8
+ export declare function getVideoTextureUvMatrix(out: Matrix3Like, videoTexture: Readonly<VideoTextureLike>): void;
9
+ export declare function getVideoTextureWidth(videoTexture: Readonly<VideoTextureLike>): number;
10
+ export declare function isVideoTextureFrameReady(videoTexture: Readonly<VideoTextureLike>): boolean;
11
+ export declare function resetVideoTextureFrame(videoTexture: VideoTextureLike): void;
12
+ export declare function setVideoTextureSource(videoTexture: VideoTextureLike, source: VideoResource): void;
13
+ //# sourceMappingURL=videoTexture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"videoTexture.d.ts","sourceRoot":"","sources":["../src/videoTexture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAQlG,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,gBAAgB,GAAG,MAAM,CAG1E;AAMD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAUlF;AAKD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAYhG;AAKD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,YAAY,CAUlH;AAKD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAGtF;AAKD,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAG/G;AAKD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAkBxG;AAID,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAGrF;AAKD,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAK1F;AAID,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAE3E;AAID,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAGjG"}
@@ -0,0 +1,119 @@
1
+ import { createEntity } from '@flighthq/entity';
2
+ import { cloneVector2, copyVector2, createVector2, inverseMatrix3 } from '@flighthq/geometry';
3
+ import { cloneSampler, copySampler, createSampler } from './sampler';
4
+ // Marks a fresh decoded frame as available for upload by bumping `frameId`. A driver calls this once
5
+ // per rendered frame when the backing element reports new pixels (readyState advanced, or a
6
+ // requestVideoFrameCallback fired); the GPU uploader compares the id against the one it last uploaded
7
+ // and re-uploads only on a change, so a paused stream costs no upload. Returns the new id.
8
+ export function advanceVideoTexture(videoTexture) {
9
+ videoTexture.frameId += 1;
10
+ return videoTexture.frameId;
11
+ }
12
+ // Allocates an independent VideoTexture over the SAME video stream: the VideoResource reference is
13
+ // shared (an HTMLVideoElement cannot be duplicated), while the Sampler and uv-transform vectors are
14
+ // deep-cloned so two textures over one stream sample independently. `frameId` resets to -1 so the
15
+ // clone forces its own first upload.
16
+ export function cloneVideoTexture(source) {
17
+ return createEntity({
18
+ colorSpace: source.colorSpace,
19
+ frameId: -1,
20
+ sampler: cloneSampler(source.sampler),
21
+ source: source.source,
22
+ uvOffset: cloneVector2(source.uvOffset),
23
+ uvRotation: source.uvRotation,
24
+ uvScale: cloneVector2(source.uvScale),
25
+ });
26
+ }
27
+ // Copies every VideoTexture field from source into out in place. The VideoResource reference is
28
+ // shared; the Sampler and uv-transform vectors are copied into out's existing entities. Safe when out
29
+ // aliases source.
30
+ export function copyVideoTexture(out, source) {
31
+ const colorSpace = source.colorSpace;
32
+ const frameId = source.frameId;
33
+ const src = source.source;
34
+ const uvRotation = source.uvRotation;
35
+ copySampler(out.sampler, source.sampler);
36
+ copyVector2(out.uvOffset, source.uvOffset);
37
+ copyVector2(out.uvScale, source.uvScale);
38
+ out.colorSpace = colorSpace;
39
+ out.frameId = frameId;
40
+ out.source = src;
41
+ out.uvRotation = uvRotation;
42
+ }
43
+ // Builds a VideoTexture over a VideoResource: a default Sampler, 'srgb' color space (video is
44
+ // display-referred), an identity KHR_texture_transform, and `frameId` -1 (no frame uploaded yet).
45
+ // Pass VideoTextureLike fields to override any of these.
46
+ export function createVideoTexture(source, opts) {
47
+ return createEntity({
48
+ colorSpace: opts?.colorSpace ?? 'srgb',
49
+ frameId: opts?.frameId ?? -1,
50
+ sampler: opts?.sampler ? cloneSampler(opts.sampler) : createSampler(),
51
+ source: opts?.source ?? source,
52
+ uvOffset: opts?.uvOffset ? cloneVector2(opts.uvOffset) : createVector2(0, 0),
53
+ uvRotation: opts?.uvRotation ?? 0,
54
+ uvScale: opts?.uvScale ? cloneVector2(opts.uvScale) : createVector2(1, 1),
55
+ });
56
+ }
57
+ // Returns the pixel height of the current video frame, or -1 when no element is attached or no frame
58
+ // has decoded yet (videoHeight is 0). Reads the element directly, so the value tracks a resolution
59
+ // change mid-stream.
60
+ export function getVideoTextureHeight(videoTexture) {
61
+ const element = videoTexture.source.element;
62
+ return element !== null && element.videoHeight > 0 ? element.videoHeight : -1;
63
+ }
64
+ // Composes the KHR_texture_transform fields and inverts the result, producing the matrix that maps
65
+ // already-transformed uv back to the unit-square source uv. A zero scale is singular, so inverseMatrix3
66
+ // fills the matrix with NaN. Out-param form — write into a pre-allocated Matrix3.
67
+ export function getVideoTextureInverseUvMatrix(out, videoTexture) {
68
+ getVideoTextureUvMatrix(out, videoTexture);
69
+ inverseMatrix3(out, out);
70
+ }
71
+ // Composes the KHR_texture_transform fields (uvOffset, uvRotation, uvScale) into the column-major 3×3
72
+ // matrix a shader consumes at sample time — the same layout getTextureUvMatrix produces, so a material
73
+ // samples a VideoTexture through one uv-transform path. scale → rotate → translate. Out-param form.
74
+ export function getVideoTextureUvMatrix(out, videoTexture) {
75
+ const r = videoTexture.uvRotation;
76
+ const sx = videoTexture.uvScale.x;
77
+ const sy = videoTexture.uvScale.y;
78
+ const tx = videoTexture.uvOffset.x;
79
+ const ty = videoTexture.uvOffset.y;
80
+ const cosR = Math.cos(r);
81
+ const sinR = Math.sin(r);
82
+ const m = out.m;
83
+ m[0] = sx * cosR;
84
+ m[1] = sx * sinR;
85
+ m[2] = 0;
86
+ m[3] = -sy * sinR;
87
+ m[4] = sy * cosR;
88
+ m[5] = 0;
89
+ m[6] = tx;
90
+ m[7] = ty;
91
+ m[8] = 1;
92
+ }
93
+ // Returns the pixel width of the current video frame, or -1 when no element is attached or no frame
94
+ // has decoded yet.
95
+ export function getVideoTextureWidth(videoTexture) {
96
+ const element = videoTexture.source.element;
97
+ return element !== null && element.videoWidth > 0 ? element.videoWidth : -1;
98
+ }
99
+ // True when the backing element has decoded at least the current frame (readyState >=
100
+ // HAVE_CURRENT_DATA) and its dimensions are known — the gate a material samples behind and a driver
101
+ // checks before calling advanceVideoTexture. False while metadata/first-frame is still buffering.
102
+ export function isVideoTextureFrameReady(videoTexture) {
103
+ const element = videoTexture.source.element;
104
+ return (element !== null && element.readyState >= HAVE_CURRENT_DATA && element.videoWidth > 0 && element.videoHeight > 0);
105
+ }
106
+ // Resets `frameId` to -1 so the next upload re-sends the current frame regardless of history. Used
107
+ // after a context loss (the GPU texture is gone) or a source swap to force a re-upload.
108
+ export function resetVideoTextureFrame(videoTexture) {
109
+ videoTexture.frameId = -1;
110
+ }
111
+ // Binds a different video stream and resets `frameId` to -1 so the new stream's first frame uploads.
112
+ // Does not touch sampling state or the uv-transform.
113
+ export function setVideoTextureSource(videoTexture, source) {
114
+ videoTexture.source = source;
115
+ videoTexture.frameId = -1;
116
+ }
117
+ // HTMLMediaElement.HAVE_CURRENT_DATA — data for the current playback position is available.
118
+ const HAVE_CURRENT_DATA = 2;
119
+ //# sourceMappingURL=videoTexture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"videoTexture.js","sourceRoot":"","sources":["../src/videoTexture.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/texture",
3
- "version": "0.2.0",
3
+ "version": "0.2.1-next.410.a23f189",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/flighthq/flight.git",
@@ -32,9 +32,9 @@
32
32
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
33
33
  },
34
34
  "dependencies": {
35
- "@flighthq/entity": "0.2.0",
36
- "@flighthq/geometry": "0.2.0",
37
- "@flighthq/types": "0.2.0"
35
+ "@flighthq/entity": "0.2.1-next.410.a23f189",
36
+ "@flighthq/geometry": "0.2.1-next.410.a23f189",
37
+ "@flighthq/types": "0.2.1-next.410.a23f189"
38
38
  },
39
39
  "devDependencies": {
40
40
  "typescript": "^5.3.0"
@@ -11,6 +11,7 @@ import {
11
11
  getTextureInverseUvMatrix,
12
12
  getTextureUvMatrix,
13
13
  getTextureWidth,
14
+ hasTextureUvTransform,
14
15
  isTextureReady,
15
16
  resetTextureUvTransform,
16
17
  setTextureImage,
@@ -222,7 +223,7 @@ describe('getTextureUvMatrix', () => {
222
223
 
223
224
  getTextureUvMatrix(out, texture);
224
225
 
225
- // Row-major: identity = [1,0,0; 0,1,0; 0,0,1]
226
+ // Identity = [1,0,0; 0,1,0; 0,0,1]
226
227
  expect(out.m[0]).toBeCloseTo(1);
227
228
  expect(out.m[1]).toBeCloseTo(0);
228
229
  expect(out.m[2]).toBeCloseTo(0);
@@ -241,8 +242,9 @@ describe('getTextureUvMatrix', () => {
241
242
 
242
243
  getTextureUvMatrix(out, texture);
243
244
 
244
- expect(out.m[2]).toBeCloseTo(0.25); // tx
245
- expect(out.m[5]).toBeCloseTo(0.75); // ty
245
+ // Column-major: the translation column is m[6], m[7].
246
+ expect(out.m[6]).toBeCloseTo(0.25); // tx
247
+ expect(out.m[7]).toBeCloseTo(0.75); // ty
246
248
  });
247
249
 
248
250
  it('encodes scale in the diagonal', () => {
@@ -267,12 +269,13 @@ describe('getTextureUvMatrix', () => {
267
269
 
268
270
  const cosR = Math.cos(r);
269
271
  const sinR = Math.sin(r);
270
- expect(out.m[0]).toBeCloseTo(2 * cosR); // sx*cos(r)
271
- expect(out.m[1]).toBeCloseTo(-2 * sinR); // -sy*sin(r)
272
- expect(out.m[2]).toBeCloseTo(0.1); // tx
273
- expect(out.m[3]).toBeCloseTo(2 * sinR); // sx*sin(r)
274
- expect(out.m[4]).toBeCloseTo(2 * cosR); // sy*cos(r)
275
- expect(out.m[5]).toBeCloseTo(0.2); // ty
272
+ // Column-major storage of rows [sx·cos, -sy·sin, tx], [sx·sin, sy·cos, ty], [0,0,1].
273
+ expect(out.m[0]).toBeCloseTo(2 * cosR); // (0,0) sx*cos(r)
274
+ expect(out.m[1]).toBeCloseTo(2 * sinR); // (1,0) sx*sin(r)
275
+ expect(out.m[3]).toBeCloseTo(-2 * sinR); // (0,1) -sy*sin(r)
276
+ expect(out.m[4]).toBeCloseTo(2 * cosR); // (1,1) sy*cos(r)
277
+ expect(out.m[6]).toBeCloseTo(0.1); // (0,2) tx
278
+ expect(out.m[7]).toBeCloseTo(0.2); // (1,2) ty
276
279
  });
277
280
  });
278
281
 
@@ -290,6 +293,41 @@ describe('getTextureWidth', () => {
290
293
  });
291
294
  });
292
295
 
296
+ describe('hasTextureUvTransform', () => {
297
+ it('is false for a freshly created identity-transform texture', () => {
298
+ expect(hasTextureUvTransform(createTexture())).toBe(false);
299
+ });
300
+
301
+ it('is true when the scale is non-unit', () => {
302
+ const texture = createTexture();
303
+ setTextureUvScale(texture, 2, 2);
304
+
305
+ expect(hasTextureUvTransform(texture)).toBe(true);
306
+ });
307
+
308
+ it('is true when the offset is non-zero', () => {
309
+ const texture = createTexture();
310
+ setTextureUvOffset(texture, 0.25, 0);
311
+
312
+ expect(hasTextureUvTransform(texture)).toBe(true);
313
+ });
314
+
315
+ it('is true when the rotation is non-zero', () => {
316
+ const texture = createTexture();
317
+ setTextureUvRotation(texture, 0.5);
318
+
319
+ expect(hasTextureUvTransform(texture)).toBe(true);
320
+ });
321
+
322
+ it('is false again after resetTextureUvTransform', () => {
323
+ const texture = createTexture();
324
+ setTextureUvScale(texture, 3, 4);
325
+ resetTextureUvTransform(texture);
326
+
327
+ expect(hasTextureUvTransform(texture)).toBe(false);
328
+ });
329
+ });
330
+
293
331
  describe('isTextureReady', () => {
294
332
  it('is false with a null image and true once bound', () => {
295
333
  const texture = createTexture();
@@ -398,8 +436,9 @@ describe('transformTextureUv', () => {
398
436
  const u = 0.3;
399
437
  const v = 0.8;
400
438
  const m = matrix.m;
401
- const expectedX = m[0] * u + m[1] * v + m[2];
402
- const expectedY = m[3] * u + m[4] * v + m[5];
439
+ // Column-major: row 0 = m[0], m[3], m[6]; row 1 = m[1], m[4], m[7].
440
+ const expectedX = m[0] * u + m[3] * v + m[6];
441
+ const expectedY = m[1] * u + m[4] * v + m[7];
403
442
  const out = createVector2(0, 0);
404
443
 
405
444
  transformTextureUv(out, texture, u, v);
@@ -0,0 +1,157 @@
1
+ import { createMatrix3, createVector2 } from '@flighthq/geometry';
2
+ import type { VideoResource } from '@flighthq/types';
3
+
4
+ import {
5
+ advanceVideoTexture,
6
+ cloneVideoTexture,
7
+ copyVideoTexture,
8
+ createVideoTexture,
9
+ getVideoTextureHeight,
10
+ getVideoTextureInverseUvMatrix,
11
+ getVideoTextureUvMatrix,
12
+ getVideoTextureWidth,
13
+ isVideoTextureFrameReady,
14
+ resetVideoTextureFrame,
15
+ setVideoTextureSource,
16
+ } from './videoTexture';
17
+
18
+ // A minimal element carrier: only the fields the VideoTexture accessors read.
19
+ function makeVideoResource(readyState = 4, videoWidth = 320, videoHeight = 240): VideoResource {
20
+ return {
21
+ element: { readyState, videoWidth, videoHeight } as unknown as HTMLVideoElement,
22
+ };
23
+ }
24
+
25
+ describe('advanceVideoTexture', () => {
26
+ it('bumps frameId and returns the new value', () => {
27
+ const vt = createVideoTexture(makeVideoResource());
28
+ expect(vt.frameId).toBe(-1);
29
+ expect(advanceVideoTexture(vt)).toBe(0);
30
+ expect(advanceVideoTexture(vt)).toBe(1);
31
+ expect(vt.frameId).toBe(1);
32
+ });
33
+ });
34
+
35
+ describe('cloneVideoTexture', () => {
36
+ it('shares the source but deep-clones sampler and uv vectors and resets frameId', () => {
37
+ const source = makeVideoResource();
38
+ const vt = createVideoTexture(source, { uvOffset: createVector2(2, 3) });
39
+ advanceVideoTexture(vt);
40
+ const clone = cloneVideoTexture(vt);
41
+ expect(clone.source).toBe(source);
42
+ expect(clone.sampler).not.toBe(vt.sampler);
43
+ expect(clone.uvOffset).not.toBe(vt.uvOffset);
44
+ expect(clone.uvOffset.x).toBe(2);
45
+ expect(clone.frameId).toBe(-1);
46
+ });
47
+ });
48
+
49
+ describe('copyVideoTexture', () => {
50
+ it('copies fields into out and is safe when out aliases source', () => {
51
+ const a = createVideoTexture(makeVideoResource(), { colorSpace: 'linear', uvScale: createVector2(4, 5) });
52
+ advanceVideoTexture(a);
53
+ const b = createVideoTexture(makeVideoResource());
54
+ copyVideoTexture(b, a);
55
+ expect(b.colorSpace).toBe('linear');
56
+ expect(b.frameId).toBe(0);
57
+ expect(b.source).toBe(a.source);
58
+ expect(b.uvScale.x).toBe(4);
59
+ copyVideoTexture(a, a);
60
+ expect(a.uvScale.x).toBe(4);
61
+ });
62
+ });
63
+
64
+ describe('createVideoTexture', () => {
65
+ it('defaults to srgb, identity uv-transform, and frameId -1', () => {
66
+ const source = makeVideoResource();
67
+ const vt = createVideoTexture(source);
68
+ expect(vt.colorSpace).toBe('srgb');
69
+ expect(vt.source).toBe(source);
70
+ expect(vt.frameId).toBe(-1);
71
+ expect(vt.uvOffset.x).toBe(0);
72
+ expect(vt.uvScale.x).toBe(1);
73
+ expect(vt.uvRotation).toBe(0);
74
+ });
75
+ });
76
+
77
+ describe('getVideoTextureHeight', () => {
78
+ it('returns the element videoHeight when a frame is decoded, else -1', () => {
79
+ expect(getVideoTextureHeight(createVideoTexture(makeVideoResource(4, 320, 240)))).toBe(240);
80
+ expect(getVideoTextureHeight(createVideoTexture(makeVideoResource(0, 0, 0)))).toBe(-1);
81
+ expect(getVideoTextureHeight(createVideoTexture({ element: null }))).toBe(-1);
82
+ });
83
+ });
84
+
85
+ describe('getVideoTextureInverseUvMatrix', () => {
86
+ it('inverts the forward uv-transform', () => {
87
+ const vt = createVideoTexture(makeVideoResource(), { uvScale: createVector2(2, 2), uvOffset: createVector2(1, 0) });
88
+ const forward = createMatrix3();
89
+ const inverse = createMatrix3();
90
+ getVideoTextureUvMatrix(forward, vt);
91
+ getVideoTextureInverseUvMatrix(inverse, vt);
92
+ // forward * inverse should be identity: a point mapped forward then back returns to itself.
93
+ const m = forward.m;
94
+ const i = inverse.m;
95
+ // (forward maps (0,0) -> (1,0); inverse must map (1,0) -> (0,0))
96
+ const px = i[0] * 1 + i[3] * 0 + i[6];
97
+ const py = i[1] * 1 + i[4] * 0 + i[7];
98
+ expect(px).toBeCloseTo(0);
99
+ expect(py).toBeCloseTo(0);
100
+ expect(m[0]).toBe(2);
101
+ });
102
+ });
103
+
104
+ describe('getVideoTextureUvMatrix', () => {
105
+ it('composes scale, rotation, and offset in column-major layout', () => {
106
+ const vt = createVideoTexture(makeVideoResource(), {
107
+ uvScale: createVector2(2, 3),
108
+ uvOffset: createVector2(5, 7),
109
+ });
110
+ const out = createMatrix3();
111
+ getVideoTextureUvMatrix(out, vt);
112
+ expect(out.m[0]).toBe(2);
113
+ expect(out.m[4]).toBe(3);
114
+ expect(out.m[6]).toBe(5);
115
+ expect(out.m[7]).toBe(7);
116
+ expect(out.m[8]).toBe(1);
117
+ });
118
+ });
119
+
120
+ describe('getVideoTextureWidth', () => {
121
+ it('returns the element videoWidth when a frame is decoded, else -1', () => {
122
+ expect(getVideoTextureWidth(createVideoTexture(makeVideoResource(4, 320, 240)))).toBe(320);
123
+ expect(getVideoTextureWidth(createVideoTexture(makeVideoResource(0, 0, 0)))).toBe(-1);
124
+ expect(getVideoTextureWidth(createVideoTexture({ element: null }))).toBe(-1);
125
+ });
126
+ });
127
+
128
+ describe('isVideoTextureFrameReady', () => {
129
+ it('is true only when the element has a decoded frame with known dimensions', () => {
130
+ expect(isVideoTextureFrameReady(createVideoTexture(makeVideoResource(4, 320, 240)))).toBe(true);
131
+ expect(isVideoTextureFrameReady(createVideoTexture(makeVideoResource(1, 320, 240)))).toBe(false);
132
+ expect(isVideoTextureFrameReady(createVideoTexture(makeVideoResource(4, 0, 0)))).toBe(false);
133
+ expect(isVideoTextureFrameReady(createVideoTexture({ element: null }))).toBe(false);
134
+ });
135
+ });
136
+
137
+ describe('resetVideoTextureFrame', () => {
138
+ it('sets frameId back to -1', () => {
139
+ const vt = createVideoTexture(makeVideoResource());
140
+ advanceVideoTexture(vt);
141
+ advanceVideoTexture(vt);
142
+ resetVideoTextureFrame(vt);
143
+ expect(vt.frameId).toBe(-1);
144
+ });
145
+ });
146
+
147
+ describe('setVideoTextureSource', () => {
148
+ it('swaps the source and resets frameId', () => {
149
+ const vt = createVideoTexture(makeVideoResource());
150
+ advanceVideoTexture(vt);
151
+ const next = makeVideoResource(4, 640, 480);
152
+ setVideoTextureSource(vt, next);
153
+ expect(vt.source).toBe(next);
154
+ expect(vt.frameId).toBe(-1);
155
+ expect(getVideoTextureWidth(vt)).toBe(640);
156
+ });
157
+ });