@flighthq/mesh 0.1.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 (55) hide show
  1. package/dist/index.d.ts +11 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +11 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/meshGeometry.d.ts +15 -0
  6. package/dist/meshGeometry.d.ts.map +1 -0
  7. package/dist/meshGeometry.js +128 -0
  8. package/dist/meshGeometry.js.map +1 -0
  9. package/dist/meshGeometryAttributes.d.ts +28 -0
  10. package/dist/meshGeometryAttributes.d.ts.map +1 -0
  11. package/dist/meshGeometryAttributes.js +144 -0
  12. package/dist/meshGeometryAttributes.js.map +1 -0
  13. package/dist/meshGeometryBuilders.d.ts +19 -0
  14. package/dist/meshGeometryBuilders.d.ts.map +1 -0
  15. package/dist/meshGeometryBuilders.js +772 -0
  16. package/dist/meshGeometryBuilders.js.map +1 -0
  17. package/dist/meshGeometryCompute.d.ts +7 -0
  18. package/dist/meshGeometryCompute.d.ts.map +1 -0
  19. package/dist/meshGeometryCompute.js +299 -0
  20. package/dist/meshGeometryCompute.js.map +1 -0
  21. package/dist/meshGeometryIndex.d.ts +4 -0
  22. package/dist/meshGeometryIndex.d.ts.map +1 -0
  23. package/dist/meshGeometryIndex.js +70 -0
  24. package/dist/meshGeometryIndex.js.map +1 -0
  25. package/dist/meshGeometryLayout.d.ts +4 -0
  26. package/dist/meshGeometryLayout.d.ts.map +1 -0
  27. package/dist/meshGeometryLayout.js +83 -0
  28. package/dist/meshGeometryLayout.js.map +1 -0
  29. package/dist/meshGeometryOperations.d.ts +12 -0
  30. package/dist/meshGeometryOperations.d.ts.map +1 -0
  31. package/dist/meshGeometryOperations.js +209 -0
  32. package/dist/meshGeometryOperations.js.map +1 -0
  33. package/dist/meshGeometrySubset.d.ts +5 -0
  34. package/dist/meshGeometrySubset.d.ts.map +1 -0
  35. package/dist/meshGeometrySubset.js +40 -0
  36. package/dist/meshGeometrySubset.js.map +1 -0
  37. package/dist/meshGeometryTransforms.d.ts +7 -0
  38. package/dist/meshGeometryTransforms.d.ts.map +1 -0
  39. package/dist/meshGeometryTransforms.js +235 -0
  40. package/dist/meshGeometryTransforms.js.map +1 -0
  41. package/dist/meshGeometryUvs.d.ts +5 -0
  42. package/dist/meshGeometryUvs.d.ts.map +1 -0
  43. package/dist/meshGeometryUvs.js +58 -0
  44. package/dist/meshGeometryUvs.js.map +1 -0
  45. package/package.json +39 -0
  46. package/src/meshGeometry.test.ts +155 -0
  47. package/src/meshGeometryAttributes.test.ts +195 -0
  48. package/src/meshGeometryBuilders.test.ts +220 -0
  49. package/src/meshGeometryCompute.test.ts +218 -0
  50. package/src/meshGeometryIndex.test.ts +84 -0
  51. package/src/meshGeometryLayout.test.ts +132 -0
  52. package/src/meshGeometryOperations.test.ts +154 -0
  53. package/src/meshGeometrySubset.test.ts +75 -0
  54. package/src/meshGeometryTransforms.test.ts +169 -0
  55. package/src/meshGeometryUvs.test.ts +128 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometryOperations.d.ts","sourceRoot":"","sources":["../src/meshGeometryOperations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAqC,MAAM,iBAAiB,CAAC;AAcvF,MAAM,WAAW,iCAAiC;IAChD,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,GAAG,WAAW,GAAG,IAAI,CAAC;IAC/D,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;CAChC;AAOD,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,QAAQ,CAAC,iCAAiC,CAAC,GAAG,YAAY,CAkDnH;AAKD,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,MAAM,CAUrF;AAOD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,YAAY,CAAC,EAAE,GAAG,YAAY,GAAG,IAAI,CA4EtG;AAKD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,OAAO,CAgC9E"}
@@ -0,0 +1,209 @@
1
+ import { createAabb } from '@flighthq/geometry';
2
+ import { createMeshGeometry, getMeshGeometryVertexCount } from './meshGeometry';
3
+ import { computeMeshGeometryBounds, computeMeshGeometryNormals, computeMeshGeometryTangents, } from './meshGeometryCompute';
4
+ import { CANONICAL_MESH_GEOMETRY_LAYOUT } from './meshGeometryLayout';
5
+ // Builds a MeshGeometry from separate position/normal/uv arrays using the canonical 12-float
6
+ // PBR record (position + normal + tangent.w + uv0). Normals are computed when omitted;
7
+ // tangents are always computed from the UV gradient. Promotes indices to Uint32 past 65535
8
+ // vertices. This is the public counterpart to the internal buildCanonicalMeshGeometry used
9
+ // by the primitive builders.
10
+ export function createMeshGeometryFromAttributes(options) {
11
+ const { positions } = options;
12
+ const vertexCount = positions.length / 3;
13
+ const normals = options.normals ?? null;
14
+ const uvs = options.uvs ?? null;
15
+ const vertices = new Float32Array(vertexCount * CANONICAL_FLOATS_PER_VERTEX);
16
+ for (let i = 0; i < vertexCount; i++) {
17
+ const base = i * CANONICAL_FLOATS_PER_VERTEX;
18
+ vertices[base] = positions[i * 3];
19
+ vertices[base + 1] = positions[i * 3 + 1];
20
+ vertices[base + 2] = positions[i * 3 + 2];
21
+ if (normals) {
22
+ vertices[base + 3] = normals[i * 3];
23
+ vertices[base + 4] = normals[i * 3 + 1];
24
+ vertices[base + 5] = normals[i * 3 + 2];
25
+ }
26
+ if (uvs) {
27
+ vertices[base + 10] = uvs[i * 2];
28
+ vertices[base + 11] = uvs[i * 2 + 1];
29
+ }
30
+ }
31
+ let indexArray;
32
+ if (options.indices) {
33
+ const src = options.indices;
34
+ const needsUint32 = vertexCount > UINT16_INDEX_CEILING;
35
+ if (needsUint32) {
36
+ const a = new Uint32Array(src.length);
37
+ for (let i = 0; i < src.length; i++)
38
+ a[i] = src[i];
39
+ indexArray = a;
40
+ }
41
+ else {
42
+ const a = new Uint16Array(src.length);
43
+ for (let i = 0; i < src.length; i++)
44
+ a[i] = src[i];
45
+ indexArray = a;
46
+ }
47
+ }
48
+ const geometry = createMeshGeometry({
49
+ indices: indexArray,
50
+ layout: CANONICAL_MESH_GEOMETRY_LAYOUT,
51
+ vertices: vertices,
52
+ });
53
+ if (!normals) {
54
+ computeMeshGeometryNormals(geometry, geometry);
55
+ }
56
+ computeMeshGeometryTangents(geometry, geometry);
57
+ const bounds = createAabb();
58
+ computeMeshGeometryBounds(bounds, geometry);
59
+ geometry.bounds = bounds;
60
+ return geometry;
61
+ }
62
+ // Returns the number of triangles in the geometry for triangle-list and triangle-strip
63
+ // topologies. Returns 0 for all other topologies (point-list, line-list, line-strip) since
64
+ // those have no well-defined "triangle count".
65
+ export function getMeshGeometryTriangleCount(geometry) {
66
+ if (geometry.topology === 'triangle-list') {
67
+ const indexCount = geometry.indices ? geometry.indices.length : getMeshGeometryVertexCount(geometry);
68
+ return Math.floor(indexCount / 3);
69
+ }
70
+ if (geometry.topology === 'triangle-strip') {
71
+ const indexCount = geometry.indices ? geometry.indices.length : getMeshGeometryVertexCount(geometry);
72
+ return indexCount >= 3 ? indexCount - 2 : 0;
73
+ }
74
+ return 0;
75
+ }
76
+ // Concatenates multiple geometries into a single MeshGeometry. All source geometries must share
77
+ // the same layout (checked by matching stride and attribute count, semantic, and format) — returns
78
+ // null on mismatch. Index buffers are offset so each source's indices remain valid within the
79
+ // merged vertex stream. Subsets are re-based so each source's draw ranges are individually
80
+ // addressable. Bounds are recomputed. An empty array returns null.
81
+ export function mergeMeshGeometries(geometries) {
82
+ if (geometries.length === 0)
83
+ return null;
84
+ const reference = geometries[0];
85
+ const layout = reference.layout;
86
+ for (let i = 1; i < geometries.length; i++) {
87
+ if (!layoutsMatch(layout, geometries[i].layout))
88
+ return null;
89
+ }
90
+ const floatsPerVertex = layout.stride / 4;
91
+ let totalVertexFloats = 0;
92
+ let totalIndexCount = 0;
93
+ let allIndexed = true;
94
+ for (const geo of geometries) {
95
+ const vc = floatsPerVertex > 0 ? Math.floor(geo.vertices.length / floatsPerVertex) : 0;
96
+ totalVertexFloats += vc * floatsPerVertex;
97
+ if (geo.indices) {
98
+ totalIndexCount += geo.indices.length;
99
+ }
100
+ else {
101
+ allIndexed = false;
102
+ totalIndexCount += vc;
103
+ }
104
+ }
105
+ const mergedVertices = new Float32Array(totalVertexFloats);
106
+ const needsUint32 = totalVertexFloats / floatsPerVertex > UINT16_INDEX_CEILING;
107
+ const mergedIndices = allIndexed || totalIndexCount > 0
108
+ ? needsUint32
109
+ ? new Uint32Array(totalIndexCount)
110
+ : new Uint16Array(totalIndexCount)
111
+ : null;
112
+ const mergedSubsets = [];
113
+ let vertexOffset = 0;
114
+ let indexOffset = 0;
115
+ let vertexFloatOffset = 0;
116
+ for (const geo of geometries) {
117
+ const vc = floatsPerVertex > 0 ? Math.floor(geo.vertices.length / floatsPerVertex) : 0;
118
+ mergedVertices.set(geo.vertices.subarray(0, vc * floatsPerVertex), vertexFloatOffset);
119
+ if (mergedIndices) {
120
+ const srcCount = geo.indices ? geo.indices.length : vc;
121
+ for (let j = 0; j < srcCount; j++) {
122
+ const srcIdx = geo.indices ? geo.indices[j] : j;
123
+ mergedIndices[indexOffset + j] = srcIdx + vertexOffset;
124
+ }
125
+ // Carry over per-source subsets with re-based indexOffset.
126
+ for (const subset of geo.subsets) {
127
+ mergedSubsets.push({
128
+ indexCount: subset.indexCount,
129
+ indexOffset: subset.indexOffset + indexOffset,
130
+ });
131
+ }
132
+ indexOffset += srcCount;
133
+ }
134
+ vertexOffset += vc;
135
+ vertexFloatOffset += vc * floatsPerVertex;
136
+ }
137
+ if (mergedSubsets.length === 0) {
138
+ mergedSubsets.push({
139
+ indexCount: mergedIndices ? mergedIndices.length : totalVertexFloats / floatsPerVertex,
140
+ indexOffset: 0,
141
+ });
142
+ }
143
+ const merged = createMeshGeometry({
144
+ indices: mergedIndices ?? undefined,
145
+ layout: layout,
146
+ subsets: mergedSubsets,
147
+ topology: reference.topology,
148
+ vertices: mergedVertices,
149
+ });
150
+ const bounds = createAabb();
151
+ computeMeshGeometryBounds(bounds, merged);
152
+ merged.bounds = bounds;
153
+ return merged;
154
+ }
155
+ // Validates a geometry for common structural errors. Returns true when the geometry is valid.
156
+ // Returns false (does not throw) for: index values out of vertex range, vertex stream length
157
+ // not divisible by the layout stride, and NaN or Infinity in position attributes.
158
+ export function validateMeshGeometry(geometry) {
159
+ const floatsPerVertex = geometry.layout.stride / 4;
160
+ if (floatsPerVertex <= 0)
161
+ return false;
162
+ // Vertex stream must be an exact multiple of the stride.
163
+ if (geometry.vertices.length % floatsPerVertex !== 0)
164
+ return false;
165
+ const vertexCount = Math.floor(geometry.vertices.length / floatsPerVertex);
166
+ // All index values must be within [0, vertexCount).
167
+ if (geometry.indices) {
168
+ for (let i = 0; i < geometry.indices.length; i++) {
169
+ if (geometry.indices[i] >= vertexCount)
170
+ return false;
171
+ }
172
+ }
173
+ // Find the position attribute float offset; only check positions for NaN/Inf.
174
+ let posOffset = -1;
175
+ for (let i = 0; i < geometry.layout.attributes.length; i++) {
176
+ const attr = geometry.layout.attributes[i];
177
+ if (attr.semantic === 'position' && attr.format.startsWith('float32')) {
178
+ posOffset = attr.byteOffset / 4;
179
+ break;
180
+ }
181
+ }
182
+ if (posOffset >= 0) {
183
+ const verts = geometry.vertices;
184
+ for (let i = 0; i < vertexCount; i++) {
185
+ const base = i * floatsPerVertex + posOffset;
186
+ const x = verts[base], y = verts[base + 1], z = verts[base + 2];
187
+ if (!isFinite(x) || !isFinite(y) || !isFinite(z))
188
+ return false;
189
+ }
190
+ }
191
+ return true;
192
+ }
193
+ // Checks whether two VertexAttributeLayouts are compatible for merging: same stride and the
194
+ // same attributes in the same order (same semantic, format, and byteOffset).
195
+ function layoutsMatch(a, b) {
196
+ if (a.stride !== b.stride)
197
+ return false;
198
+ if (a.attributes.length !== b.attributes.length)
199
+ return false;
200
+ for (let i = 0; i < a.attributes.length; i++) {
201
+ const aa = a.attributes[i], ba = b.attributes[i];
202
+ if (aa.semantic !== ba.semantic || aa.format !== ba.format || aa.byteOffset !== ba.byteOffset)
203
+ return false;
204
+ }
205
+ return true;
206
+ }
207
+ const CANONICAL_FLOATS_PER_VERTEX = 12;
208
+ const UINT16_INDEX_CEILING = 65535;
209
+ //# sourceMappingURL=meshGeometryOperations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometryOperations.js","sourceRoot":"","sources":["../src/meshGeometryOperations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { MeshGeometry, MeshSubset } from '@flighthq/types';
2
+ export declare function addMeshGeometrySubset(geometry: MeshGeometry, subset: Readonly<MeshSubset>): void;
3
+ export declare function getMeshGeometrySubsetTriangleCount(geometry: Readonly<MeshGeometry>, subsetIndex: number): number;
4
+ export declare function setMeshGeometrySubsets(geometry: MeshGeometry, subsets: readonly Readonly<MeshSubset>[]): void;
5
+ //# sourceMappingURL=meshGeometrySubset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometrySubset.d.ts","sourceRoot":"","sources":["../src/meshGeometrySubset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAWhE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAOhG;AAKD,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAMhH;AAKD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,CAM7G"}
@@ -0,0 +1,40 @@
1
+ // Subset range management over a MeshGeometry's index buffer. A subset is a contiguous draw range
2
+ // (indexOffset + indexCount) addressing one material binding; a single-material geometry is one
3
+ // subset spanning the whole index buffer. These functions read or replace the geometry's `subsets`
4
+ // array — they never touch vertex or index data, so `version` is unchanged (a re-upload is only
5
+ // needed when the buffers themselves change). Out-of-range subset lookups return the sentinel 0.
6
+ // Appends a subset range to the geometry's subset list, replacing the array reference so existing
7
+ // readers of the old array are unaffected. The new subset is added as-is; the caller owns choosing
8
+ // a non-overlapping range within the index buffer.
9
+ export function addMeshGeometrySubset(geometry, subset) {
10
+ const next = [];
11
+ for (let i = 0; i < geometry.subsets.length; i++) {
12
+ next.push({ indexCount: geometry.subsets[i].indexCount, indexOffset: geometry.subsets[i].indexOffset });
13
+ }
14
+ next.push({ indexCount: subset.indexCount, indexOffset: subset.indexOffset });
15
+ geometry.subsets = next;
16
+ }
17
+ // Returns the number of triangles a subset spans, derived from its `indexCount` and the geometry's
18
+ // topology: triangle-list yields floor(indexCount / 3), triangle-strip yields max(0, indexCount - 2).
19
+ // Non-triangle topologies and out-of-range subset indices return the sentinel 0.
20
+ export function getMeshGeometrySubsetTriangleCount(geometry, subsetIndex) {
21
+ if (subsetIndex < 0 || subsetIndex >= geometry.subsets.length)
22
+ return 0;
23
+ const indexCount = geometry.subsets[subsetIndex].indexCount;
24
+ if (geometry.topology === 'triangle-list')
25
+ return Math.floor(indexCount / 3);
26
+ if (geometry.topology === 'triangle-strip')
27
+ return indexCount >= 2 ? indexCount - 2 : 0;
28
+ return 0;
29
+ }
30
+ // Replaces the geometry's entire subset list with a fresh copy of `subsets`, taking ownership of
31
+ // the range definitions while leaving the vertex/index buffers untouched. Pass a single
32
+ // whole-buffer subset to collapse back to one material binding.
33
+ export function setMeshGeometrySubsets(geometry, subsets) {
34
+ const next = [];
35
+ for (let i = 0; i < subsets.length; i++) {
36
+ next.push({ indexCount: subsets[i].indexCount, indexOffset: subsets[i].indexOffset });
37
+ }
38
+ geometry.subsets = next;
39
+ }
40
+ //# sourceMappingURL=meshGeometrySubset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometrySubset.js","sourceRoot":"","sources":["../src/meshGeometrySubset.ts"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,gGAAgG;AAChG,mGAAmG;AACnG,gGAAgG;AAChG,iGAAiG;AAEjG,kGAAkG;AAClG,mGAAmG;AACnG,mDAAmD;AACnD,MAAM,UAAU,qBAAqB,CAAC,QAAsB,EAAE,MAA4B;IACxF,MAAM,IAAI,GAAiB,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9E,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;AAC1B,CAAC;AAED,mGAAmG;AACnG,sGAAsG;AACtG,iFAAiF;AACjF,MAAM,UAAU,kCAAkC,CAAC,QAAgC,EAAE,WAAmB;IACtG,IAAI,WAAW,GAAG,CAAC,IAAI,WAAW,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC;IAC5D,IAAI,QAAQ,CAAC,QAAQ,KAAK,eAAe;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC7E,IAAI,QAAQ,CAAC,QAAQ,KAAK,gBAAgB;QAAE,OAAO,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iGAAiG;AACjG,wFAAwF;AACxF,gEAAgE;AAChE,MAAM,UAAU,sBAAsB,CAAC,QAAsB,EAAE,OAAwC;IACrG,MAAM,IAAI,GAAiB,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Matrix4Like, MeshGeometry } from '@flighthq/types';
2
+ export declare function centerMeshGeometry(geometry: MeshGeometry): void;
3
+ export declare function scaleMeshGeometry(geometry: MeshGeometry, sx: number, sy: number, sz: number): void;
4
+ export declare function transformMeshGeometry(geometry: MeshGeometry, matrix: Readonly<Matrix4Like>): boolean;
5
+ export declare function transformMeshGeometryInto(out: MeshGeometry, source: Readonly<MeshGeometry>, matrix: Readonly<Matrix4Like>): boolean;
6
+ export declare function translateMeshGeometry(geometry: MeshGeometry, x: number, y: number, z: number): void;
7
+ //# sourceMappingURL=meshGeometryTransforms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometryTransforms.d.ts","sourceRoot":"","sources":["../src/meshGeometryTransforms.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAWjE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAY/D;AAKD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAElG;AAOD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAEpG;AAOD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC5B,OAAO,CAyET;AAID,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAqBnG"}
@@ -0,0 +1,235 @@
1
+ import { createAabb } from '@flighthq/geometry';
2
+ import { getVertexAttributeFloatOffset } from './meshGeometryAttributes';
3
+ import { computeMeshGeometryBounds } from './meshGeometryCompute';
4
+ // Geometry transform operations: apply a Matrix4 to positions and the inverse-transpose to
5
+ // normals and tangent.xyz (tangent.w handedness sign is preserved). All in-place operations
6
+ // bump geometry.version. Out-parameter variants are alias-safe (out === source is valid).
7
+ // Centers the geometry so that the cached AABB's center moves to the origin. If bounds have
8
+ // not been computed yet, they are computed first. Bumps geometry.version.
9
+ export function centerMeshGeometry(geometry) {
10
+ if (!geometry.bounds) {
11
+ const bounds = createAabb();
12
+ computeMeshGeometryBounds(bounds, geometry);
13
+ geometry.bounds = bounds;
14
+ }
15
+ const b = geometry.bounds;
16
+ const cx = (b.min.x + b.max.x) * 0.5;
17
+ const cy = (b.min.y + b.max.y) * 0.5;
18
+ const cz = (b.min.z + b.max.z) * 0.5;
19
+ if (cx === 0 && cy === 0 && cz === 0)
20
+ return;
21
+ translateMeshGeometry(geometry, -cx, -cy, -cz);
22
+ }
23
+ // Scales all vertex positions in-place by (sx, sy, sz). Normals and tangents are transformed
24
+ // via the inverse-transpose of the pure scale matrix (i.e. (1/sx, 1/sy, 1/sz)) and
25
+ // re-normalized. Bumps geometry.version.
26
+ export function scaleMeshGeometry(geometry, sx, sy, sz) {
27
+ transformMeshGeometryPositions(geometry, geometry, sx, sy, sz, 0, 0, 0);
28
+ }
29
+ // Applies a Matrix4 to the geometry's vertices in place. Positions are transformed as points
30
+ // (w=1); normals and tangent.xyz are transformed by the inverse-transpose of the matrix's
31
+ // upper-left 3×3 and re-normalized. Returns false when the matrix is singular. Bumps
32
+ // geometry.version. Alias-safe (this function does not need an alias form because it is
33
+ // always in-place, but positions are read before write in the core loop).
34
+ export function transformMeshGeometry(geometry, matrix) {
35
+ return transformMeshGeometryInto(geometry, geometry, matrix);
36
+ }
37
+ // Applies a Matrix4 to `source` geometry and writes the result into `out`. Positions are
38
+ // transformed as points (w=1), normals and tangent.xyz are transformed by the inverse-transpose
39
+ // of the matrix's upper-left 3×3 (ignoring translation) and re-normalized. tangent.w is
40
+ // preserved. Returns false and leaves `out` unchanged when the matrix has no inverse (singular),
41
+ // because the correct normal transform is undefined. Alias-safe: out === source is valid.
42
+ export function transformMeshGeometryInto(out, source, matrix) {
43
+ // Compute inverse-transpose of the 3×3 upper-left for normals/tangents.
44
+ const invT = computeMatrix3x3InverseTranspose(matrix);
45
+ if (!invT)
46
+ return false;
47
+ const m = matrix.m;
48
+ const posFloatOffset = getVertexAttributeFloatOffset(source.layout, 'position');
49
+ const normFloatOffset = getVertexAttributeFloatOffset(source.layout, 'normal');
50
+ const tanFloatOffset = getVertexAttributeFloatOffset(source.layout, 'tangent');
51
+ const srcVerts = source.vertices;
52
+ const floatsPerVertex = source.layout.stride / 4;
53
+ const vertexCount = floatsPerVertex > 0 ? Math.floor(srcVerts.length / floatsPerVertex) : 0;
54
+ // Allocate output if writing into a different geometry; otherwise work in-place.
55
+ const dstVerts = out === source ? srcVerts : out.vertices;
56
+ if (out !== source) {
57
+ dstVerts.set(srcVerts);
58
+ }
59
+ for (let i = 0; i < vertexCount; i++) {
60
+ const vertBase = i * floatsPerVertex;
61
+ if (posFloatOffset >= 0) {
62
+ const pb = vertBase + posFloatOffset;
63
+ // Read inputs into locals before writing (alias-safe).
64
+ const px = srcVerts[pb], py = srcVerts[pb + 1], pz = srcVerts[pb + 2];
65
+ dstVerts[pb] = m[0] * px + m[4] * py + m[8] * pz + m[12];
66
+ dstVerts[pb + 1] = m[1] * px + m[5] * py + m[9] * pz + m[13];
67
+ dstVerts[pb + 2] = m[2] * px + m[6] * py + m[10] * pz + m[14];
68
+ }
69
+ if (normFloatOffset >= 0) {
70
+ const nb = vertBase + normFloatOffset;
71
+ const nx = srcVerts[nb], ny = srcVerts[nb + 1], nz = srcVerts[nb + 2];
72
+ let tnx = invT[0] * nx + invT[3] * ny + invT[6] * nz;
73
+ let tny = invT[1] * nx + invT[4] * ny + invT[7] * nz;
74
+ let tnz = invT[2] * nx + invT[5] * ny + invT[8] * nz;
75
+ const len = Math.sqrt(tnx * tnx + tny * tny + tnz * tnz);
76
+ if (len > 0) {
77
+ tnx /= len;
78
+ tny /= len;
79
+ tnz /= len;
80
+ }
81
+ dstVerts[nb] = tnx;
82
+ dstVerts[nb + 1] = tny;
83
+ dstVerts[nb + 2] = tnz;
84
+ }
85
+ if (tanFloatOffset >= 0) {
86
+ const tb = vertBase + tanFloatOffset;
87
+ const tx = srcVerts[tb], ty = srcVerts[tb + 1], tz = srcVerts[tb + 2];
88
+ const tw = srcVerts[tb + 3]; // preserve handedness sign
89
+ let ttx = invT[0] * tx + invT[3] * ty + invT[6] * tz;
90
+ let tty = invT[1] * tx + invT[4] * ty + invT[7] * tz;
91
+ let ttz = invT[2] * tx + invT[5] * ty + invT[8] * tz;
92
+ const len = Math.sqrt(ttx * ttx + tty * tty + ttz * ttz);
93
+ if (len > 0) {
94
+ ttx /= len;
95
+ tty /= len;
96
+ ttz /= len;
97
+ }
98
+ dstVerts[tb] = ttx;
99
+ dstVerts[tb + 1] = tty;
100
+ dstVerts[tb + 2] = ttz;
101
+ dstVerts[tb + 3] = tw;
102
+ }
103
+ }
104
+ out.version++;
105
+ // Recompute bounds if they were cached, since all positions have changed.
106
+ if (out.bounds) {
107
+ computeMeshGeometryBounds(out.bounds, out);
108
+ }
109
+ return true;
110
+ }
111
+ // Translates all vertex positions in-place by (x, y, z). Normals and tangents are unaffected
112
+ // by a pure translation. Bumps geometry.version.
113
+ export function translateMeshGeometry(geometry, x, y, z) {
114
+ const posFloatOffset = getVertexAttributeFloatOffset(geometry.layout, 'position');
115
+ if (posFloatOffset < 0)
116
+ return;
117
+ const floatsPerVertex = geometry.layout.stride / 4;
118
+ const vertexCount = floatsPerVertex > 0 ? Math.floor(geometry.vertices.length / floatsPerVertex) : 0;
119
+ const verts = geometry.vertices;
120
+ for (let i = 0; i < vertexCount; i++) {
121
+ const base = i * floatsPerVertex + posFloatOffset;
122
+ verts[base] += x;
123
+ verts[base + 1] += y;
124
+ verts[base + 2] += z;
125
+ }
126
+ geometry.version++;
127
+ if (geometry.bounds) {
128
+ geometry.bounds.min.x += x;
129
+ geometry.bounds.min.y += y;
130
+ geometry.bounds.min.z += z;
131
+ geometry.bounds.max.x += x;
132
+ geometry.bounds.max.y += y;
133
+ geometry.bounds.max.z += z;
134
+ }
135
+ }
136
+ // Computes the 3×3 column-major inverse-transpose of the upper-left 3×3 of a 4×4 matrix.
137
+ // Returns null when the 3×3 is singular (determinant near zero). The 9-element array is
138
+ // column-major: [col0row0, col0row1, col0row2, col1row0, col1row1, col1row2, col2row0, col2row1, col2row2].
139
+ function computeMatrix3x3InverseTranspose(matrix) {
140
+ const m = matrix.m;
141
+ // Column-major upper-left 3×3: columns are (m[0],m[1],m[2]), (m[4],m[5],m[6]), (m[8],m[9],m[10]).
142
+ const a00 = m[0], a01 = m[1], a02 = m[2];
143
+ const a10 = m[4], a11 = m[5], a12 = m[6];
144
+ const a20 = m[8], a21 = m[9], a22 = m[10];
145
+ // Cofactors for the 3×3.
146
+ const c00 = a11 * a22 - a12 * a21;
147
+ const c01 = -(a10 * a22 - a12 * a20);
148
+ const c02 = a10 * a21 - a11 * a20;
149
+ const c10 = -(a01 * a22 - a02 * a21);
150
+ const c11 = a00 * a22 - a02 * a20;
151
+ const c12 = -(a00 * a21 - a01 * a20);
152
+ const c20 = a01 * a12 - a02 * a11;
153
+ const c21 = -(a00 * a12 - a02 * a10);
154
+ const c22 = a00 * a11 - a01 * a10;
155
+ const det = a00 * c00 + a01 * c01 + a02 * c02;
156
+ if (Math.abs(det) < 1e-10)
157
+ return null;
158
+ const invDet = 1 / det;
159
+ // Transpose of cofactor matrix (adjugate), scaled by 1/det.
160
+ // Column-major storage (same convention as Matrix4.m).
161
+ const out = new Float32Array(9);
162
+ out[0] = c00 * invDet;
163
+ out[1] = c10 * invDet;
164
+ out[2] = c20 * invDet;
165
+ out[3] = c01 * invDet;
166
+ out[4] = c11 * invDet;
167
+ out[5] = c21 * invDet;
168
+ out[6] = c02 * invDet;
169
+ out[7] = c12 * invDet;
170
+ out[8] = c22 * invDet;
171
+ return out;
172
+ }
173
+ // Applies a pure-scale transform to positions. Normals/tangents are transformed by the
174
+ // inverse scale and re-normalized. Internal helper used by scaleMeshGeometry.
175
+ function transformMeshGeometryPositions(out, source, sx, sy, sz, tx, ty, tz) {
176
+ const posFloatOffset = getVertexAttributeFloatOffset(source.layout, 'position');
177
+ const normFloatOffset = getVertexAttributeFloatOffset(source.layout, 'normal');
178
+ const tanFloatOffset = getVertexAttributeFloatOffset(source.layout, 'tangent');
179
+ const srcVerts = source.vertices;
180
+ const floatsPerVertex = source.layout.stride / 4;
181
+ const vertexCount = floatsPerVertex > 0 ? Math.floor(srcVerts.length / floatsPerVertex) : 0;
182
+ const dstVerts = out.vertices;
183
+ if (out !== source) {
184
+ dstVerts.set(srcVerts);
185
+ }
186
+ // Inverse scale factors for normals/tangents under a non-uniform scale.
187
+ const invSx = sx !== 0 ? 1 / sx : 0;
188
+ const invSy = sy !== 0 ? 1 / sy : 0;
189
+ const invSz = sz !== 0 ? 1 / sz : 0;
190
+ for (let i = 0; i < vertexCount; i++) {
191
+ const vertBase = i * floatsPerVertex;
192
+ if (posFloatOffset >= 0) {
193
+ const pb = vertBase + posFloatOffset;
194
+ const px = srcVerts[pb], py = srcVerts[pb + 1], pz = srcVerts[pb + 2];
195
+ dstVerts[pb] = px * sx + tx;
196
+ dstVerts[pb + 1] = py * sy + ty;
197
+ dstVerts[pb + 2] = pz * sz + tz;
198
+ }
199
+ if (normFloatOffset >= 0) {
200
+ const nb = vertBase + normFloatOffset;
201
+ const nx = srcVerts[nb], ny = srcVerts[nb + 1], nz = srcVerts[nb + 2];
202
+ let nnx = nx * invSx, nny = ny * invSy, nnz = nz * invSz;
203
+ const len = Math.sqrt(nnx * nnx + nny * nny + nnz * nnz);
204
+ if (len > 0) {
205
+ nnx /= len;
206
+ nny /= len;
207
+ nnz /= len;
208
+ }
209
+ dstVerts[nb] = nnx;
210
+ dstVerts[nb + 1] = nny;
211
+ dstVerts[nb + 2] = nnz;
212
+ }
213
+ if (tanFloatOffset >= 0) {
214
+ const tb = vertBase + tanFloatOffset;
215
+ const ttx = srcVerts[tb], tty = srcVerts[tb + 1], ttz = srcVerts[tb + 2];
216
+ const tw = srcVerts[tb + 3];
217
+ let ntx = ttx * invSx, nty = tty * invSy, ntz = ttz * invSz;
218
+ const len = Math.sqrt(ntx * ntx + nty * nty + ntz * ntz);
219
+ if (len > 0) {
220
+ ntx /= len;
221
+ nty /= len;
222
+ ntz /= len;
223
+ }
224
+ dstVerts[tb] = ntx;
225
+ dstVerts[tb + 1] = nty;
226
+ dstVerts[tb + 2] = ntz;
227
+ dstVerts[tb + 3] = tw;
228
+ }
229
+ }
230
+ out.version++;
231
+ if (out.bounds) {
232
+ computeMeshGeometryBounds(out.bounds, out);
233
+ }
234
+ }
235
+ //# sourceMappingURL=meshGeometryTransforms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometryTransforms.js","sourceRoot":"","sources":["../src/meshGeometryTransforms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAElE,2FAA2F;AAC3F,4FAA4F;AAC5F,0FAA0F;AAE1F,4FAA4F;AAC5F,0EAA0E;AAC1E,MAAM,UAAU,kBAAkB,CAAC,QAAsB;IACvD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,yBAAyB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC;IAC3B,CAAC;IACD,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC1B,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACrC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACrC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACrC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO;IAC7C,qBAAqB,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,6FAA6F;AAC7F,mFAAmF;AACnF,yCAAyC;AACzC,MAAM,UAAU,iBAAiB,CAAC,QAAsB,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;IAC1F,8BAA8B,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,6FAA6F;AAC7F,0FAA0F;AAC1F,qFAAqF;AACrF,wFAAwF;AACxF,0EAA0E;AAC1E,MAAM,UAAU,qBAAqB,CAAC,QAAsB,EAAE,MAA6B;IACzF,OAAO,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED,yFAAyF;AACzF,gGAAgG;AAChG,wFAAwF;AACxF,iGAAiG;AACjG,0FAA0F;AAC1F,MAAM,UAAU,yBAAyB,CACvC,GAAiB,EACjB,MAA8B,EAC9B,MAA6B;IAE7B,wEAAwE;IACxE,MAAM,IAAI,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACnB,MAAM,cAAc,GAAG,6BAA6B,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChF,MAAM,eAAe,GAAG,6BAA6B,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/E,MAAM,cAAc,GAAG,6BAA6B,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5F,iFAAiF;IACjF,MAAM,QAAQ,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC1D,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,CAAC,GAAG,eAAe,CAAC;QACrC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,EAAE,GAAG,QAAQ,GAAG,cAAc,CAAC;YACrC,uDAAuD;YACvD,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACxB,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;YACzD,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7D,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,EAAE,GAAG,QAAQ,GAAG,eAAe,CAAC;YACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrD,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrD,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YACzD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;YACb,CAAC;YACD,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;YACnB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YACvB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QACzB,CAAC;QACD,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,EAAE,GAAG,QAAQ,GAAG,cAAc,CAAC;YACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACxB,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,2BAA2B;YACxD,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrD,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrD,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YACzD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;YACb,CAAC;YACD,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;YACnB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YACvB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YACvB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IACD,GAAG,CAAC,OAAO,EAAE,CAAC;IACd,0EAA0E;IAC1E,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,yBAAyB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6FAA6F;AAC7F,iDAAiD;AACjD,MAAM,UAAU,qBAAqB,CAAC,QAAsB,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS;IAC3F,MAAM,cAAc,GAAG,6BAA6B,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClF,IAAI,cAAc,GAAG,CAAC;QAAE,OAAO;IAC/B,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,CAAC,GAAG,eAAe,GAAG,cAAc,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,QAAQ,CAAC,OAAO,EAAE,CAAC;IACnB,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,wFAAwF;AACxF,4GAA4G;AAC5G,SAAS,gCAAgC,CAAC,MAA6B;IACrE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACnB,kGAAkG;IAClG,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACd,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACV,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACb,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACd,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACV,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACb,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACd,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACV,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACd,yBAAyB;IACzB,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC9C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC;IACvB,4DAA4D;IAC5D,uDAAuD;IACvD,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;IAChC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC;IACtB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,uFAAuF;AACvF,8EAA8E;AAC9E,SAAS,8BAA8B,CACrC,GAAiB,EACjB,MAA8B,EAC9B,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU;IAEV,MAAM,cAAc,GAAG,6BAA6B,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChF,MAAM,eAAe,GAAG,6BAA6B,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/E,MAAM,cAAc,GAAG,6BAA6B,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC9B,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IACD,wEAAwE;IACxE,MAAM,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,CAAC,GAAG,eAAe,CAAC;QACrC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,EAAE,GAAG,QAAQ,GAAG,cAAc,CAAC;YACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACxB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YAC5B,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YAChC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QAClC,CAAC;QACD,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,EAAE,GAAG,QAAQ,GAAG,eAAe,CAAC;YACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,EACrB,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK,EAClB,GAAG,GAAG,EAAE,GAAG,KAAK,EAChB,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;YACnB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YACzD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;YACb,CAAC;YACD,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;YACnB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YACvB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QACzB,CAAC;QACD,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,EAAE,GAAG,QAAQ,GAAG,cAAc,CAAC;YACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC,EACtB,GAAG,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,EACtB,GAAG,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACzB,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5B,IAAI,GAAG,GAAG,GAAG,GAAG,KAAK,EACnB,GAAG,GAAG,GAAG,GAAG,KAAK,EACjB,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC;YACpB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YACzD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;gBACX,GAAG,IAAI,GAAG,CAAC;YACb,CAAC;YACD,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;YACnB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YACvB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YACvB,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IACD,GAAG,CAAC,OAAO,EAAE,CAAC;IACd,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,yBAAyB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { MeshGeometry } from '@flighthq/types';
2
+ export declare function offsetMeshGeometryUvs(geometry: MeshGeometry, du: number, dv: number): void;
3
+ export declare function scaleMeshGeometryUvs(geometry: MeshGeometry, su: number, sv: number): void;
4
+ export declare function wrapMeshGeometryUvs(geometry: MeshGeometry): void;
5
+ //# sourceMappingURL=meshGeometryUvs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometryUvs.d.ts","sourceRoot":"","sources":["../src/meshGeometryUvs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAWpD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAY1F;AAID,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAYzF;AAKD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAYhE"}
@@ -0,0 +1,58 @@
1
+ import { getVertexAttributeFloatOffset } from './meshGeometryAttributes';
2
+ // UV transform helpers for the uv0 channel. All functions write directly into geometry.vertices
3
+ // and bump geometry.version. They operate on whatever attribute is registered under the 'uv0'
4
+ // semantic in the geometry's layout — so they work on canonical-layout geometry and any custom
5
+ // layout that includes uv0. No-ops (with no version bump) when uv0 is absent from the layout.
6
+ // Offsets every uv0 coordinate by (du, dv): u' = u + du, v' = v + dv. Useful for texture atlas
7
+ // panning or tiling offset corrections.
8
+ export function offsetMeshGeometryUvs(geometry, du, dv) {
9
+ const floatOffset = getVertexAttributeFloatOffset(geometry.layout, 'uv0');
10
+ if (floatOffset < 0)
11
+ return;
12
+ const floatsPerVertex = geometry.layout.stride / 4;
13
+ const vertexCount = floatsPerVertex > 0 ? Math.floor(geometry.vertices.length / floatsPerVertex) : 0;
14
+ const verts = geometry.vertices;
15
+ for (let i = 0; i < vertexCount; i++) {
16
+ const base = i * floatsPerVertex + floatOffset;
17
+ verts[base] += du;
18
+ verts[base + 1] += dv;
19
+ }
20
+ if (vertexCount > 0)
21
+ geometry.version++;
22
+ }
23
+ // Scales every uv0 coordinate by (su, sv) around the origin: u' = u * su, v' = v * sv. Useful
24
+ // for tiling — e.g. scaleMeshGeometryUvs(geo, 2, 2) tiles the texture 2× in each direction.
25
+ export function scaleMeshGeometryUvs(geometry, su, sv) {
26
+ const floatOffset = getVertexAttributeFloatOffset(geometry.layout, 'uv0');
27
+ if (floatOffset < 0)
28
+ return;
29
+ const floatsPerVertex = geometry.layout.stride / 4;
30
+ const vertexCount = floatsPerVertex > 0 ? Math.floor(geometry.vertices.length / floatsPerVertex) : 0;
31
+ const verts = geometry.vertices;
32
+ for (let i = 0; i < vertexCount; i++) {
33
+ const base = i * floatsPerVertex + floatOffset;
34
+ verts[base] *= su;
35
+ verts[base + 1] *= sv;
36
+ }
37
+ if (vertexCount > 0)
38
+ geometry.version++;
39
+ }
40
+ // Wraps every uv0 coordinate into [0, 1) using the fractional-part operation: u' = u - floor(u).
41
+ // Useful after scale or offset operations that push coordinates outside the 0..1 atlas tile.
42
+ // Coordinates that are exactly on integer boundaries (e.g. u = 1.0) wrap to 0.0.
43
+ export function wrapMeshGeometryUvs(geometry) {
44
+ const floatOffset = getVertexAttributeFloatOffset(geometry.layout, 'uv0');
45
+ if (floatOffset < 0)
46
+ return;
47
+ const floatsPerVertex = geometry.layout.stride / 4;
48
+ const vertexCount = floatsPerVertex > 0 ? Math.floor(geometry.vertices.length / floatsPerVertex) : 0;
49
+ const verts = geometry.vertices;
50
+ for (let i = 0; i < vertexCount; i++) {
51
+ const base = i * floatsPerVertex + floatOffset;
52
+ verts[base] = verts[base] - Math.floor(verts[base]);
53
+ verts[base + 1] = verts[base + 1] - Math.floor(verts[base + 1]);
54
+ }
55
+ if (vertexCount > 0)
56
+ geometry.version++;
57
+ }
58
+ //# sourceMappingURL=meshGeometryUvs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshGeometryUvs.js","sourceRoot":"","sources":["../src/meshGeometryUvs.ts"],"names":[],"mappings":"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"}