@galfus/engine 0.0.0-stage → 0.31.0-alpha

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 (80) hide show
  1. package/README.md +190 -2
  2. package/package.json +59 -4
  3. package/src/anchors/cache.ts +101 -0
  4. package/src/anchors/component.ts +123 -0
  5. package/src/anchors/hierarchy.ts +192 -0
  6. package/src/anchors/index.ts +8 -0
  7. package/src/anchors/solver.ts +247 -0
  8. package/src/anchors/strategy.ts +142 -0
  9. package/src/animation/blending.ts +163 -0
  10. package/src/animation/clip.ts +132 -0
  11. package/src/animation/coordinator.ts +568 -0
  12. package/src/animation/index.ts +7 -0
  13. package/src/animation/native-targets.ts +37 -0
  14. package/src/animation/player.ts +287 -0
  15. package/src/audio/index.ts +4 -0
  16. package/src/audio/manager.ts +371 -0
  17. package/src/collision/components.ts +211 -0
  18. package/src/collision/index.ts +16 -0
  19. package/src/collision/query2d.ts +167 -0
  20. package/src/collision/query3d.ts +170 -0
  21. package/src/ecs/component.ts +130 -0
  22. package/src/ecs/entity.ts +75 -0
  23. package/src/ecs/index.ts +9 -0
  24. package/src/ecs/intent.ts +162 -0
  25. package/src/ecs/metadata.ts +44 -0
  26. package/src/ecs/system.ts +224 -0
  27. package/src/ecs/world.ts +291 -0
  28. package/src/index.ts +19 -0
  29. package/src/interaction/focus.ts +327 -0
  30. package/src/interaction/index.ts +9 -0
  31. package/src/interaction/listener.ts +58 -0
  32. package/src/interaction/snapshot2d.ts +210 -0
  33. package/src/interaction/snapshot3d.ts +214 -0
  34. package/src/interaction/system.ts +544 -0
  35. package/src/interaction/types.ts +27 -0
  36. package/src/math/common.ts +67 -0
  37. package/src/math/index.ts +17 -0
  38. package/src/math/mat2d.ts +320 -0
  39. package/src/math/mat4.ts +576 -0
  40. package/src/math/quat.ts +438 -0
  41. package/src/math/vec2.ts +161 -0
  42. package/src/math/vec3.ts +242 -0
  43. package/src/math/vec4.ts +171 -0
  44. package/src/multiverse/coordinator.ts +540 -0
  45. package/src/multiverse/index.ts +13 -0
  46. package/src/multiverse/presentation-graph.ts +306 -0
  47. package/src/multiverse/presentation-links.ts +134 -0
  48. package/src/multiverse/realm.ts +49 -0
  49. package/src/platform/index.ts +2 -0
  50. package/src/platform/platform.ts +149 -0
  51. package/src/platform/window.ts +181 -0
  52. package/src/realm2d/components.ts +254 -0
  53. package/src/realm2d/index.ts +12 -0
  54. package/src/realm2d/presets/index.ts +36 -0
  55. package/src/realm2d/realm.ts +522 -0
  56. package/src/realm2d/sync.ts +284 -0
  57. package/src/realm2d/utils/index.ts +32 -0
  58. package/src/realm3d/components.ts +341 -0
  59. package/src/realm3d/geometry.ts +224 -0
  60. package/src/realm3d/index.ts +12 -0
  61. package/src/realm3d/presets/index.ts +67 -0
  62. package/src/realm3d/realm.ts +588 -0
  63. package/src/realm3d/resource-ids.ts +62 -0
  64. package/src/realm3d/skinning.ts +128 -0
  65. package/src/realm3d/sync.ts +442 -0
  66. package/src/realm3d/utils/index.ts +26 -0
  67. package/src/resources/index.ts +4 -0
  68. package/src/resources/manager.ts +92 -0
  69. package/src/runtime.ts +588 -0
  70. package/src/spatial/dirty_registry.ts +217 -0
  71. package/src/spatial/flags.ts +14 -0
  72. package/src/spatial/index.ts +6 -0
  73. package/src/spatial/metrics.ts +124 -0
  74. package/src/text/editor.ts +224 -0
  75. package/src/text/encoding.ts +38 -0
  76. package/src/text/index.ts +13 -0
  77. package/src/text/input.ts +160 -0
  78. package/src/text/keyboard.ts +50 -0
  79. package/src/text/svg-decorations.ts +147 -0
  80. package/src/types.ts +85 -0
@@ -0,0 +1,576 @@
1
+ /**
2
+ * 4x4 matrix operations for 3D graphics.
3
+ * Stored as a 16-element Float32Array in column-major order.
4
+ */
5
+
6
+ import { EPSILON, equalsApprox } from './common';
7
+ import type { Quat, ReadonlyQuat } from './quat';
8
+ import type { ReadonlyVec3, Vec3 } from './vec3';
9
+
10
+ export type Mat4Index = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;
11
+
12
+ export type Mat4 = Float32Array & { [K in Mat4Index]: number };
13
+
14
+ export type ReadonlyMat4 = ArrayLike<number> & { readonly [K in Mat4Index]: number };
15
+
16
+ export function create(): Mat4 {
17
+ const out = new Float32Array(16) as unknown as Mat4;
18
+ out[0] = 1;
19
+ out[5] = 1;
20
+ out[10] = 1;
21
+ out[15] = 1;
22
+ return out;
23
+ }
24
+
25
+ export function identity(out: Mat4): Mat4 {
26
+ out.fill(0);
27
+ out[0] = 1;
28
+ out[5] = 1;
29
+ out[10] = 1;
30
+ out[15] = 1;
31
+ return out;
32
+ }
33
+
34
+ export function copy(out: Mat4, a: ReadonlyMat4): Mat4 {
35
+ out.set(a as ArrayLike<number>);
36
+ return out;
37
+ }
38
+
39
+ export function multiply(out: Mat4, a: ReadonlyMat4, b: ReadonlyMat4): Mat4 {
40
+ const a00 = a[0],
41
+ a01 = a[1],
42
+ a02 = a[2],
43
+ a03 = a[3];
44
+ const a10 = a[4],
45
+ a11 = a[5],
46
+ a12 = a[6],
47
+ a13 = a[7];
48
+ const a20 = a[8],
49
+ a21 = a[9],
50
+ a22 = a[10],
51
+ a23 = a[11];
52
+ const a30 = a[12],
53
+ a31 = a[13],
54
+ a32 = a[14],
55
+ a33 = a[15];
56
+
57
+ for (let i = 0; i < 4; i++) {
58
+ const i4 = i * 4;
59
+ const b0 = (b as ArrayLike<number>)[i4] ?? 0;
60
+ const b1 = (b as ArrayLike<number>)[i4 + 1] ?? 0;
61
+ const b2 = (b as ArrayLike<number>)[i4 + 2] ?? 0;
62
+ const b3 = (b as ArrayLike<number>)[i4 + 3] ?? 0;
63
+ out[i4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
64
+ out[i4 + 1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
65
+ out[i4 + 2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
66
+ out[i4 + 3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
67
+ }
68
+ return out;
69
+ }
70
+
71
+ export function fromTranslation(out: Mat4, v: ReadonlyVec3): Mat4 {
72
+ identity(out);
73
+ out[12] = v[0];
74
+ out[13] = v[1];
75
+ out[14] = v[2];
76
+ return out;
77
+ }
78
+
79
+ export function fromScaling(out: Mat4, v: ReadonlyVec3): Mat4 {
80
+ out.fill(0);
81
+ out[0] = v[0];
82
+ out[5] = v[1];
83
+ out[10] = v[2];
84
+ out[15] = 1;
85
+ return out;
86
+ }
87
+
88
+ export function fromQuat(out: Mat4, q: ReadonlyQuat): Mat4 {
89
+ const x = q[0];
90
+ const y = q[1];
91
+ const z = q[2];
92
+ const w = q[3];
93
+ const x2 = x + x;
94
+ const y2 = y + y;
95
+ const z2 = z + z;
96
+
97
+ const xx = x * x2;
98
+ const yx = y * x2;
99
+ const yy = y * y2;
100
+ const zx = z * x2;
101
+ const zy = z * y2;
102
+ const zz = z * z2;
103
+ const wx = w * x2;
104
+ const wy = w * y2;
105
+ const wz = w * z2;
106
+
107
+ out[0] = 1 - yy - zz;
108
+ out[1] = yx + wz;
109
+ out[2] = zx - wy;
110
+ out[3] = 0;
111
+
112
+ out[4] = yx - wz;
113
+ out[5] = 1 - xx - zz;
114
+ out[6] = zy + wx;
115
+ out[7] = 0;
116
+
117
+ out[8] = zx + wy;
118
+ out[9] = zy - wx;
119
+ out[10] = 1 - xx - yy;
120
+ out[11] = 0;
121
+
122
+ out[12] = 0;
123
+ out[13] = 0;
124
+ out[14] = 0;
125
+ out[15] = 1;
126
+ return out;
127
+ }
128
+
129
+ export function fromRotationTranslationScale(
130
+ out: Mat4,
131
+ q: ReadonlyQuat,
132
+ v: ReadonlyVec3,
133
+ s: ReadonlyVec3
134
+ ): Mat4 {
135
+ const x = q[0],
136
+ y = q[1],
137
+ z = q[2],
138
+ w = q[3];
139
+ const x2 = x + x,
140
+ y2 = y + y,
141
+ z2 = z + z;
142
+ const xx = x * x2,
143
+ xy = x * y2,
144
+ xz = x * z2;
145
+ const yy = y * y2,
146
+ yz = y * z2,
147
+ zz = z * z2;
148
+ const wx = w * x2,
149
+ wy = w * y2,
150
+ wz = w * z2;
151
+ const sx = s[0],
152
+ sy = s[1],
153
+ sz = s[2];
154
+
155
+ out[0] = (1 - (yy + zz)) * sx;
156
+ out[1] = (xy + wz) * sx;
157
+ out[2] = (xz - wy) * sx;
158
+ out[3] = 0;
159
+ out[4] = (xy - wz) * sy;
160
+ out[5] = (1 - (xx + zz)) * sy;
161
+ out[6] = (yz + wx) * sy;
162
+ out[7] = 0;
163
+ out[8] = (xz + wy) * sz;
164
+ out[9] = (yz - wx) * sz;
165
+ out[10] = (1 - (xx + yy)) * sz;
166
+ out[11] = 0;
167
+ out[12] = v[0];
168
+ out[13] = v[1];
169
+ out[14] = v[2];
170
+ out[15] = 1;
171
+ return out;
172
+ }
173
+
174
+ export function translate(out: Mat4, a: ReadonlyMat4, v: ReadonlyVec3): Mat4 {
175
+ const x = v[0];
176
+ const y = v[1];
177
+ const z = v[2];
178
+
179
+ if (a !== out) {
180
+ out[0] = a[0];
181
+ out[1] = a[1];
182
+ out[2] = a[2];
183
+ out[3] = a[3];
184
+ out[4] = a[4];
185
+ out[5] = a[5];
186
+ out[6] = a[6];
187
+ out[7] = a[7];
188
+ out[8] = a[8];
189
+ out[9] = a[9];
190
+ out[10] = a[10];
191
+ out[11] = a[11];
192
+ }
193
+
194
+ out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
195
+ out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
196
+ out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
197
+ out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
198
+ return out;
199
+ }
200
+
201
+ const _scratchRot = new Float32Array(16) as unknown as Mat4;
202
+
203
+ /**
204
+ * Creates a rotation matrix from an angle in radians and an axis.
205
+ */
206
+ export function fromRotation(out: Mat4, rad: number, axis: ReadonlyVec3): Mat4 {
207
+ let x = axis[0];
208
+ let y = axis[1];
209
+ let z = axis[2];
210
+ let len = Math.hypot(x, y, z);
211
+ if (len < EPSILON) return identity(out);
212
+
213
+ len = 1 / len;
214
+ x *= len;
215
+ y *= len;
216
+ z *= len;
217
+ const s = Math.sin(rad);
218
+ const c = Math.cos(rad);
219
+ const t = 1 - c;
220
+
221
+ out[0] = x * x * t + c;
222
+ out[1] = y * x * t + z * s;
223
+ out[2] = z * x * t - y * s;
224
+ out[3] = 0;
225
+ out[4] = x * y * t - z * s;
226
+ out[5] = y * y * t + c;
227
+ out[6] = z * y * t + x * s;
228
+ out[7] = 0;
229
+ out[8] = x * z * t + y * s;
230
+ out[9] = y * z * t - x * s;
231
+ out[10] = z * z * t + c;
232
+ out[11] = 0;
233
+ out[12] = 0;
234
+ out[13] = 0;
235
+ out[14] = 0;
236
+ out[15] = 1;
237
+ return out;
238
+ }
239
+
240
+ /**
241
+ * Rotates a mat4 by the given angle in radians around the given axis.
242
+ */
243
+ export function rotate(out: Mat4, rad: number, axis: ReadonlyVec3): Mat4;
244
+ export function rotate(out: Mat4, a: ReadonlyMat4, rad: number, axis: ReadonlyVec3): Mat4;
245
+ export function rotate(
246
+ out: Mat4,
247
+ aOrRad: ReadonlyMat4 | number,
248
+ radOrAxis: number | ReadonlyVec3,
249
+ maybeAxis?: ReadonlyVec3
250
+ ): Mat4 {
251
+ const a = typeof aOrRad === 'number' ? out : aOrRad;
252
+ const rad = typeof aOrRad === 'number' ? aOrRad : (radOrAxis as number);
253
+ const axis = (typeof aOrRad === 'number' ? radOrAxis : maybeAxis) as ReadonlyVec3;
254
+
255
+ fromRotation(_scratchRot, rad, axis);
256
+ return multiply(out, a, _scratchRot);
257
+ }
258
+
259
+ /**
260
+ * Generates a look-at matrix with the given eye position, focal point, and up-vector.
261
+ */
262
+ export function lookAt(out: Mat4, eye: ReadonlyVec3, center: ReadonlyVec3, up: ReadonlyVec3): Mat4 {
263
+ const eyex = eye[0],
264
+ eyey = eye[1],
265
+ eyez = eye[2];
266
+ const upx = up[0],
267
+ upy = up[1],
268
+ upz = up[2];
269
+ const centerx = center[0],
270
+ centery = center[1],
271
+ centerz = center[2];
272
+
273
+ if (
274
+ Math.abs(eyex - centerx) < EPSILON &&
275
+ Math.abs(eyey - centery) < EPSILON &&
276
+ Math.abs(eyez - centerz) < EPSILON
277
+ ) {
278
+ return identity(out);
279
+ }
280
+
281
+ let z0 = eyex - centerx,
282
+ z1 = eyey - centery,
283
+ z2 = eyez - centerz;
284
+ let len = 1 / Math.hypot(z0, z1, z2);
285
+ z0 *= len;
286
+ z1 *= len;
287
+ z2 *= len;
288
+
289
+ let x0 = upy * z2 - upz * z1,
290
+ x1 = upz * z0 - upx * z2,
291
+ x2 = upx * z1 - upy * z0;
292
+ len = Math.hypot(x0, x1, x2);
293
+ if (!len) {
294
+ x0 = 0;
295
+ x1 = 0;
296
+ x2 = 0;
297
+ } else {
298
+ len = 1 / len;
299
+ x0 *= len;
300
+ x1 *= len;
301
+ x2 *= len;
302
+ }
303
+
304
+ let y0 = z1 * x2 - z2 * x1,
305
+ y1 = z2 * x0 - z0 * x2,
306
+ y2 = z0 * x1 - z1 * x0;
307
+ len = Math.hypot(y0, y1, y2);
308
+ if (!len) {
309
+ y0 = 0;
310
+ y1 = 0;
311
+ y2 = 0;
312
+ } else {
313
+ len = 1 / len;
314
+ y0 *= len;
315
+ y1 *= len;
316
+ y2 *= len;
317
+ }
318
+
319
+ out[0] = x0;
320
+ out[1] = y0;
321
+ out[2] = z0;
322
+ out[3] = 0;
323
+ out[4] = x1;
324
+ out[5] = y1;
325
+ out[6] = z1;
326
+ out[7] = 0;
327
+ out[8] = x2;
328
+ out[9] = y2;
329
+ out[10] = z2;
330
+ out[11] = 0;
331
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
332
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
333
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
334
+ out[15] = 1;
335
+ return out;
336
+ }
337
+
338
+ export function scale(out: Mat4, a: ReadonlyMat4, v: ReadonlyVec3): Mat4 {
339
+ const x = v[0];
340
+ const y = v[1];
341
+ const z = v[2];
342
+
343
+ out[0] = a[0] * x;
344
+ out[1] = a[1] * x;
345
+ out[2] = a[2] * x;
346
+ out[3] = a[3] * x;
347
+ out[4] = a[4] * y;
348
+ out[5] = a[5] * y;
349
+ out[6] = a[6] * y;
350
+ out[7] = a[7] * y;
351
+ out[8] = a[8] * z;
352
+ out[9] = a[9] * z;
353
+ out[10] = a[10] * z;
354
+ out[11] = a[11] * z;
355
+ out[12] = a[12];
356
+ out[13] = a[13];
357
+ out[14] = a[14];
358
+ out[15] = a[15];
359
+ return out;
360
+ }
361
+
362
+ export function invert(out: Mat4, a: ReadonlyMat4): Mat4 | null {
363
+ const a00 = a[0],
364
+ a01 = a[1],
365
+ a02 = a[2],
366
+ a03 = a[3];
367
+ const a10 = a[4],
368
+ a11 = a[5],
369
+ a12 = a[6],
370
+ a13 = a[7];
371
+ const a20 = a[8],
372
+ a21 = a[9],
373
+ a22 = a[10],
374
+ a23 = a[11];
375
+ const a30 = a[12],
376
+ a31 = a[13],
377
+ a32 = a[14],
378
+ a33 = a[15];
379
+
380
+ const b00 = a00 * a11 - a01 * a10;
381
+ const b01 = a00 * a12 - a02 * a10;
382
+ const b02 = a00 * a13 - a03 * a10;
383
+ const b03 = a01 * a12 - a02 * a11;
384
+ const b04 = a01 * a13 - a03 * a11;
385
+ const b05 = a02 * a13 - a03 * a12;
386
+ const b06 = a20 * a31 - a21 * a30;
387
+ const b07 = a20 * a32 - a22 * a30;
388
+ const b08 = a20 * a33 - a23 * a30;
389
+ const b09 = a21 * a32 - a22 * a31;
390
+ const b10 = a21 * a33 - a23 * a31;
391
+ const b11 = a22 * a33 - a23 * a32;
392
+
393
+ let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
394
+ if (!det) {
395
+ return null;
396
+ }
397
+ det = 1.0 / det;
398
+
399
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
400
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
401
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
402
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
403
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
404
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
405
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
406
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
407
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
408
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
409
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
410
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
411
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
412
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
413
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
414
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
415
+ return out;
416
+ }
417
+
418
+ export function getTranslation(out: Vec3, mat: ReadonlyMat4): Vec3 {
419
+ out[0] = mat[12];
420
+ out[1] = mat[13];
421
+ out[2] = mat[14];
422
+ return out;
423
+ }
424
+
425
+ export function getScaling(out: Vec3, mat: ReadonlyMat4): Vec3 {
426
+ out[0] = Math.hypot(mat[0], mat[1], mat[2]);
427
+ out[1] = Math.hypot(mat[4], mat[5], mat[6]);
428
+ out[2] = Math.hypot(mat[8], mat[9], mat[10]);
429
+ return out;
430
+ }
431
+
432
+ export function getRotation(out: Quat, mat: ReadonlyMat4): Quat {
433
+ const scaling = new Float32Array(3) as unknown as Vec3;
434
+ getScaling(scaling, mat);
435
+
436
+ const isx = 1.0 / (scaling[0] || 1);
437
+ const isy = 1.0 / (scaling[1] || 1);
438
+ const isz = 1.0 / (scaling[2] || 1);
439
+
440
+ const sm11 = mat[0] * isx;
441
+ const sm12 = mat[1] * isx;
442
+ const sm13 = mat[2] * isx;
443
+ const sm21 = mat[4] * isy;
444
+ const sm22 = mat[5] * isy;
445
+ const sm23 = mat[6] * isy;
446
+ const sm31 = mat[8] * isz;
447
+ const sm32 = mat[9] * isz;
448
+ const sm33 = mat[10] * isz;
449
+
450
+ const trace = sm11 + sm22 + sm33;
451
+ let s = 0;
452
+
453
+ if (trace > 0) {
454
+ s = Math.sqrt(trace + 1.0) * 2;
455
+ out[3] = 0.25 * s;
456
+ out[0] = (sm23 - sm32) / s;
457
+ out[1] = (sm31 - sm13) / s;
458
+ out[2] = (sm12 - sm21) / s;
459
+ } else if (sm11 > sm22 && sm11 > sm33) {
460
+ s = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
461
+ out[3] = (sm23 - sm32) / s;
462
+ out[0] = 0.25 * s;
463
+ out[1] = (sm12 + sm21) / s;
464
+ out[2] = (sm31 + sm13) / s;
465
+ } else if (sm22 > sm33) {
466
+ s = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
467
+ out[3] = (sm31 - sm13) / s;
468
+ out[0] = (sm12 + sm21) / s;
469
+ out[1] = 0.25 * s;
470
+ out[2] = (sm23 + sm32) / s;
471
+ } else {
472
+ s = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
473
+ out[3] = (sm12 - sm21) / s;
474
+ out[0] = (sm31 + sm13) / s;
475
+ out[1] = (sm23 + sm32) / s;
476
+ out[2] = 0.25 * s;
477
+ }
478
+ return out;
479
+ }
480
+
481
+ export function equals(a: ReadonlyMat4, b: ReadonlyMat4, epsilon: number = EPSILON): boolean {
482
+ for (let i = 0; i < 16; i++) {
483
+ const valA = a[i as keyof ReadonlyMat4] as number;
484
+ const valB = b[i as keyof ReadonlyMat4] as number;
485
+ if (!equalsApprox(valA, valB, epsilon)) return false;
486
+ }
487
+ return true;
488
+ }
489
+
490
+ /**
491
+ * Copies the translation vector components from `from` into `out`.
492
+ */
493
+ export function copyPosition(out: Mat4, from: ReadonlyMat4): Mat4 {
494
+ out[12] = from[12];
495
+ out[13] = from[13];
496
+ out[14] = from[14];
497
+ return out;
498
+ }
499
+
500
+ /**
501
+ * Sets the translation vector components in `out`.
502
+ */
503
+ export function setTranslation(
504
+ out: Mat4,
505
+ xOrVec: number | ReadonlyVec3,
506
+ y?: number,
507
+ z?: number
508
+ ): Mat4 {
509
+ if (typeof xOrVec === 'number') {
510
+ out[12] = xOrVec;
511
+ out[13] = y ?? 0;
512
+ out[14] = z ?? 0;
513
+ } else {
514
+ out[12] = xOrVec[0];
515
+ out[13] = xOrVec[1];
516
+ out[14] = xOrVec[2];
517
+ }
518
+ return out;
519
+ }
520
+
521
+ /**
522
+ * Copies the 3x3 rotation basis from `from` into `out`, preserving the scale of `out`.
523
+ */
524
+ export function copyRotation(out: Mat4, from: ReadonlyMat4): Mat4 {
525
+ const sx = Math.hypot(out[0], out[1], out[2]) || 1;
526
+ const sy = Math.hypot(out[4], out[5], out[6]) || 1;
527
+ const sz = Math.hypot(out[8], out[9], out[10]) || 1;
528
+
529
+ const fsx = Math.hypot(from[0], from[1], from[2]) || 1;
530
+ const fsy = Math.hypot(from[4], from[5], from[6]) || 1;
531
+ const fsz = Math.hypot(from[8], from[9], from[10]) || 1;
532
+
533
+ out[0] = (from[0] / fsx) * sx;
534
+ out[1] = (from[1] / fsx) * sx;
535
+ out[2] = (from[2] / fsx) * sx;
536
+
537
+ out[4] = (from[4] / fsy) * sy;
538
+ out[5] = (from[5] / fsy) * sy;
539
+ out[6] = (from[6] / fsy) * sy;
540
+
541
+ out[8] = (from[8] / fsz) * sz;
542
+ out[9] = (from[9] / fsz) * sz;
543
+ out[10] = (from[10] / fsz) * sz;
544
+
545
+ return out;
546
+ }
547
+
548
+ /**
549
+ * Performs a component-wise linear interpolation between two 4x4 transformation matrices.
550
+ */
551
+ export function lerp(out: Mat4, a: ReadonlyMat4, b: ReadonlyMat4, t: number): Mat4 {
552
+ for (let i = 0; i < 16; i++) {
553
+ const ai = a[i as keyof ReadonlyMat4] as number;
554
+ const bi = b[i as keyof ReadonlyMat4] as number;
555
+ out[i] = ai + t * (bi - ai);
556
+ }
557
+ return out;
558
+ }
559
+
560
+ /**
561
+ * Clamps each component of a 4x4 transformation matrix between min and max.
562
+ */
563
+ export function clamp(
564
+ out: Mat4,
565
+ a: ReadonlyMat4,
566
+ min: ReadonlyMat4 | number,
567
+ max: ReadonlyMat4 | number
568
+ ): Mat4 {
569
+ for (let i = 0; i < 16; i++) {
570
+ const ai = a[i as keyof ReadonlyMat4] as number;
571
+ const minVal = typeof min === 'number' ? min : (min[i as keyof ReadonlyMat4] as number);
572
+ const maxVal = typeof max === 'number' ? max : (max[i as keyof ReadonlyMat4] as number);
573
+ out[i] = Math.min(Math.max(ai, minVal), maxVal);
574
+ }
575
+ return out;
576
+ }