@woosh/meep-engine 2.126.64 → 2.126.66

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Pure JavaScript game engine. Fully featured and production ready.",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.126.64",
8
+ "version": "2.126.66",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -19,7 +19,7 @@ export function spline3_hermite(t, p0, p1, m0, m1) {
19
19
  const a = 2 * t3 - 3 * t2 + 1;
20
20
  const b = t3 - 2 * t2 + t;
21
21
  const c = t3 - t2;
22
- const d = -2 * t3 + 3 * t2;
22
+ const d = 3 * t2 - 2 * t3;
23
23
 
24
24
  return a * p0 + b * m0 + c * m1 + d * p1;
25
25
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Finds the parameter 't' of the nearest point on a 1D Hermite spline
3
+ * function graph to a reference point. The curve is defined by (t, p(t)).
4
+ * This version is optimized to avoid allocations.
5
+ *
6
+ * @param {number} ref_t - The 't' coordinate of the reference point.
7
+ * @param {number} ref_p - The 'p' coordinate of the reference point.
8
+ * @param {number} p0 - The start value of the spline (at t=0).
9
+ * @param {number} p1 - The end value of the spline (at t=1).
10
+ * @param {number} m0 - The tangent at the start.
11
+ * @param {number} m1 - The tangent at the end.
12
+ * @returns {number} The parameter 't' of the nearest point. This value is always in [0..1] range
13
+ */
14
+ export function spline3_hermite_nearest_point(ref_t: number, ref_p: number, p0: number, p1: number, m0: number, m1: number): number;
15
+ //# sourceMappingURL=spline3_hermite_nearest_point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spline3_hermite_nearest_point.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_nearest_point.js"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;GAYG;AACH,qDARW,MAAM,SACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,MAAM,CAuFlB"}
@@ -0,0 +1,124 @@
1
+ import { spline3_hermite } from "./spline3_hermite.js";
2
+
3
+ /**
4
+ * Helper to evaluate a polynomial given its coefficients.
5
+ * @param {Float32Array} p - Polynomial coefficients [c0, c1, c2, ...]
6
+ * @param {number} t - The value at which to evaluate.
7
+ * @param {number} size
8
+ * @returns {number}
9
+ */
10
+ function polyval(p, t, size) {
11
+ let result = 0;
12
+
13
+ for (let i = size - 1; i >= 0; i--) {
14
+ result = result * t + p[i];
15
+ }
16
+
17
+ return result;
18
+ }
19
+
20
+ const quintic_coeffs = new Float32Array(6);
21
+ const quartic_coeffs = new Float32Array(5);
22
+
23
+ const NEWTON_STEPS = 3;
24
+ const START_ROOT_COUNT = 5;
25
+
26
+ /**
27
+ * Finds the parameter 't' of the nearest point on a 1D Hermite spline
28
+ * function graph to a reference point. The curve is defined by (t, p(t)).
29
+ * This version is optimized to avoid allocations.
30
+ *
31
+ * @param {number} ref_t - The 't' coordinate of the reference point.
32
+ * @param {number} ref_p - The 'p' coordinate of the reference point.
33
+ * @param {number} p0 - The start value of the spline (at t=0).
34
+ * @param {number} p1 - The end value of the spline (at t=1).
35
+ * @param {number} m0 - The tangent at the start.
36
+ * @param {number} m1 - The tangent at the end.
37
+ * @returns {number} The parameter 't' of the nearest point. This value is always in [0..1] range
38
+ */
39
+ export function spline3_hermite_nearest_point(
40
+ ref_t, ref_p,
41
+ p0, p1, m0, m1
42
+ ) {
43
+
44
+ // 1. Calculate polynomial coefficients A, B, C for p(t)
45
+ const A = 2 * p0 - 2 * p1 + m0 + m1;
46
+ const B = -3 * p0 + 3 * p1 - 2 * m0 - m1;
47
+ const C = m0;
48
+ const D_minus_Rp = p0 - ref_p;
49
+
50
+ // 2. Form the quintic polynomial f(t) = c5*t^5 + ... + c0
51
+
52
+ quintic_coeffs[0] = (C * D_minus_Rp - ref_t)
53
+ quintic_coeffs[1] = (C * C + 2 * B * D_minus_Rp + 1)
54
+ quintic_coeffs[2] = (3 * B * C + 3 * A * D_minus_Rp)
55
+ quintic_coeffs[3] = (4 * A * C + 2 * B * B)
56
+ quintic_coeffs[4] = (5 * A * B)
57
+ quintic_coeffs[5] = (3 * A * A)
58
+
59
+ // Derivative of the quintic (a quartic) for Newton's method
60
+
61
+ quartic_coeffs[0] = quintic_coeffs[1]
62
+ quartic_coeffs[1] = 2 * quintic_coeffs[2]
63
+ quartic_coeffs[2] = 3 * quintic_coeffs[3]
64
+ quartic_coeffs[3] = 4 * quintic_coeffs[4]
65
+ quartic_coeffs[4] = 5 * quintic_coeffs[5]
66
+
67
+
68
+ // 3. Initialize by checking the endpoints t=0 and t=1
69
+ let best_t = 0;
70
+ let dt = 0 - ref_t;
71
+ let dp = p0 - ref_p;
72
+ let min_dist_sq = dt * dt + dp * dp;
73
+
74
+ dt = 1 - ref_t;
75
+ dp = p1 - ref_p;
76
+ const dist_sq_at_1 = dt * dt + dp * dp;
77
+ if (dist_sq_at_1 < min_dist_sq) {
78
+ min_dist_sq = dist_sq_at_1;
79
+ best_t = 1;
80
+ }
81
+
82
+ // 4. Find roots and check them on the fly
83
+ const tolerance = 1e-7;
84
+
85
+
86
+ // Start Newton's method from several points to find multiple roots
87
+ for (let i = 0; i <= START_ROOT_COUNT; i++) {
88
+ let t = i / START_ROOT_COUNT; // Starting guess for the root
89
+
90
+ for (let j = NEWTON_STEPS; j > 0; j--) {
91
+
92
+ const f_t = polyval(quintic_coeffs, t, 6);
93
+ const fp_t = polyval(quartic_coeffs, t, 5);
94
+
95
+ if (Math.abs(fp_t) < tolerance) {
96
+ break;
97
+ }
98
+
99
+ const t_new = t - f_t / fp_t;
100
+
101
+ if (Math.abs(t_new - t) < tolerance) {
102
+ break;
103
+ }
104
+
105
+ t = t_new;
106
+ }
107
+
108
+ // Check if the found root is valid and yields a better distance
109
+ if (t > 0 && t < 1) {
110
+ // Endpoints already checked
111
+ const p = spline3_hermite(t, p0, p1, m0, m1);
112
+ const current_dt = t - ref_t;
113
+ const current_dp = p - ref_p;
114
+ const dist_sq = current_dt * current_dt + current_dp * current_dp;
115
+
116
+ if (dist_sq < min_dist_sq) {
117
+ min_dist_sq = dist_sq;
118
+ best_t = t;
119
+ }
120
+ }
121
+ }
122
+
123
+ return best_t;
124
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"AnimationCurve.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/curve/AnimationCurve.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;GAgBG;AACH;IAkXI;;;;OAIG;IACH,kBAHW,QAAQ,EAAE,GACR,cAAc,CAQ1B;IAED;;;;;;;;OAQG;IACH,6BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAUzB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,YACN,MAAM,UACN,MAAM,GACL,cAAc,CAOzB;IAED;;;;;;;OAOG;IACH,0BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAYzB;IAjbD;;;;;OAKG;IACH,eAFU,QAAQ,EAAE,CAEV;IAEV;;;;;OAKG;IACH,SAHW,QAAQ,GACN,MAAM,CAiClB;IAED;;;OAGG;IACH,cAFW,QAAQ,EAAE,QAUpB;IAED;;;;OAIG;IACH,YAHW,QAAQ,GACN,OAAO,CAYnB;IAED;;OAEG;IACH,cAEC;IAGD;;;OAGG;IACH,WAFY,OAAO,CAIlB;IAED;;;OAGG;IACH,qBAEC;IAED;;;;OAIG;IACH,yBAUC;IAED;;;;OAIG;IACH,uBAUC;IAED;;;;OAIG;IACH,uBAcC;IAED;;;;OAIG;IACH,wBAHW,MAAM,GACJ,MAAM,CA0ClB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACL,MAAM,CAoCjB;IAED;;;;OAIG;IACH,qBAFW,MAAM,QAmChB;IAED;;;;OAIG;IACH,sBAHW,MAAM,UACN,MAAM,QAWhB;IAED,0BAKC;IAGD;;;OAGG;IACH,YAFW,cAAc,QAIxB;IAED;;;OAGG;IACH,SAFY,cAAc,CAQzB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACb,OAAO,CAIlB;IAED;;;OAGG;IACH,QAFY,MAAM,CAIjB;IAED;;MAIC;IAED;;aAeC;IAsEL;;;;OAIG;IACH,2BAFU,OAAO,CAEwB;CARxC;yBAhdwB,eAAe"}
1
+ {"version":3,"file":"AnimationCurve.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/curve/AnimationCurve.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;GAgBG;AACH;IAkXI;;;;OAIG;IACH,kBAHW,QAAQ,EAAE,GACR,cAAc,CAQ1B;IAED;;;;;;;;OAQG;IACH,6BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAUzB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,YACN,MAAM,UACN,MAAM,GACL,cAAc,CAOzB;IAED;;;;;;;OAOG;IACH,0BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAezB;IApbD;;;;;OAKG;IACH,eAFU,QAAQ,EAAE,CAEV;IAEV;;;;;OAKG;IACH,SAHW,QAAQ,GACN,MAAM,CAiClB;IAED;;;OAGG;IACH,cAFW,QAAQ,EAAE,QAUpB;IAED;;;;OAIG;IACH,YAHW,QAAQ,GACN,OAAO,CAYnB;IAED;;OAEG;IACH,cAEC;IAGD;;;OAGG;IACH,WAFY,OAAO,CAIlB;IAED;;;OAGG;IACH,qBAEC;IAED;;;;OAIG;IACH,yBAUC;IAED;;;;OAIG;IACH,uBAUC;IAED;;;;OAIG;IACH,uBAcC;IAED;;;;OAIG;IACH,wBAHW,MAAM,GACJ,MAAM,CA0ClB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACL,MAAM,CAoCjB;IAED;;;;OAIG;IACH,qBAFW,MAAM,QAmChB;IAED;;;;OAIG;IACH,sBAHW,MAAM,UACN,MAAM,QAWhB;IAED,0BAKC;IAGD;;;OAGG;IACH,YAFW,cAAc,QAIxB;IAED;;;OAGG;IACH,SAFY,cAAc,CAQzB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACb,OAAO,CAIlB;IAED;;;OAGG;IACH,QAFY,MAAM,CAIjB;IAED;;MAIC;IAED;;aAeC;IAyEL;;;;OAIG;IACH,2BAFU,OAAO,CAEwB;CARxC;yBAndwB,eAAe"}
@@ -464,7 +464,10 @@ export class AnimationCurve {
464
464
  timeStart = 0, valueStart = 0,
465
465
  timeEnd = 1, valueEnd = 1
466
466
  ) {
467
- const tangent = valueEnd - valueStart;
467
+ const time_delta = timeEnd - timeStart;
468
+
469
+ // tangent needs to be normalized
470
+ const tangent = time_delta === 0 ? 0 : (valueEnd - valueStart) / time_delta;
468
471
 
469
472
  return AnimationCurve.from([
470
473
  Keyframe.from(timeStart, valueStart, 0, tangent),
@@ -120,7 +120,7 @@ export class Keyframe {
120
120
  */
121
121
  hash() {
122
122
  return computeHashFloat(this.time)
123
- ^ computeHashFloat(this.value);
123
+ ^ (computeHashFloat(this.value) * 31);
124
124
  }
125
125
 
126
126
  toJSON() {
@@ -0,0 +1,13 @@
1
+ /**
2
+ * NOTE: this operation has O(n) complexity, where n is the number of keys in the curve.
3
+ * @param {AnimationCurve} curve
4
+ * @param {number} ref_time
5
+ * @param {number} ref_value
6
+ * @returns {number} time of the nearest point on the curve
7
+ * @see AnimationCurve
8
+ * @example
9
+ * const nearest_time = animation_curve_nearest_point(curve, 0.5, 10);
10
+ * const nearest_value = curve.evaluate(nearest_time);
11
+ */
12
+ export function animation_curve_nearest_point(curve: AnimationCurve, ref_time: number, ref_value: number): number;
13
+ //# sourceMappingURL=animation_curve_nearest_point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation_curve_nearest_point.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/curve/animation_curve_nearest_point.js"],"names":[],"mappings":"AAMA;;;;;;;;;;GAUG;AACH,+EARW,MAAM,aACN,MAAM,GACJ,MAAM,CA2DlB"}
@@ -0,0 +1,71 @@
1
+ import { v2_distance_sqr } from "../../../core/geom/vec2/v2_distance_sqr.js";
2
+ import { inverseLerp } from "../../../core/math/inverseLerp.js";
3
+ import { lerp } from "../../../core/math/lerp.js";
4
+ import { spline3_hermite } from "../../../core/math/spline/spline3_hermite.js";
5
+ import { spline3_hermite_nearest_point } from "../../../core/math/spline/spline3_hermite_nearest_point.js";
6
+
7
+ /**
8
+ * NOTE: this operation has O(n) complexity, where n is the number of keys in the curve.
9
+ * @param {AnimationCurve} curve
10
+ * @param {number} ref_time
11
+ * @param {number} ref_value
12
+ * @returns {number} time of the nearest point on the curve
13
+ * @see AnimationCurve
14
+ * @example
15
+ * const nearest_time = animation_curve_nearest_point(curve, 0.5, 10);
16
+ * const nearest_value = curve.evaluate(nearest_time);
17
+ */
18
+ export function animation_curve_nearest_point(curve, ref_time, ref_value) {
19
+
20
+ const keys = curve.keys;
21
+ const key_count = keys.length;
22
+
23
+ if (key_count === 0) {
24
+ // special case: empty curve
25
+ return ref_time;
26
+ }
27
+
28
+ if (key_count === 1) {
29
+ // special case: single key
30
+ return keys[0].time;
31
+ }
32
+
33
+ let nearest_time = keys[0].time;
34
+ let nearest_value = keys[0].value;
35
+ let nearest_distance_sqr = v2_distance_sqr(nearest_time, nearest_value, ref_time, ref_value);
36
+
37
+ for (let i = 0; i <= key_count - 2; i++) {
38
+ const key0 = keys[i];
39
+ const key1 = keys[i + 1];
40
+
41
+ const time_delta = key1.time - key0.time;
42
+
43
+ // Normalize reference time to the segment's [0, 1] space
44
+ const ref_t = inverseLerp(key0.time, key1.time, ref_time);
45
+
46
+ // Scale tangents by the segment duration
47
+ const m0 = key0.outTangent * time_delta;
48
+ const m1 = key1.inTangent * time_delta;
49
+
50
+ const t = spline3_hermite_nearest_point(
51
+ ref_t, ref_value,
52
+ key0.value, key1.value,
53
+ m0, m1
54
+ );
55
+
56
+ // De-normalize the resulting time back to the global timeline
57
+ const curve_time = lerp(key0.time, key1.time, t);
58
+ const curve_value = spline3_hermite(t, key0.value, key1.value, m0, m1);
59
+
60
+ const distance_sqr = v2_distance_sqr(curve_time, curve_value, ref_time, ref_value);
61
+
62
+ if (distance_sqr < nearest_distance_sqr) {
63
+ nearest_time = curve_time;
64
+ nearest_value = curve_value;
65
+ nearest_distance_sqr = distance_sqr;
66
+ }
67
+
68
+ }
69
+
70
+ return nearest_time;
71
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Subdivide a curve segment by introducing a new keyframe at a given normalized time.
3
+ * Subdivision does not alter the curve shape in any way, it is intended primarily for editing purposes.
4
+ * @param {Keyframe} out keyframe to be added at the point of subdivision, its tangents, time and value will be overwritten
5
+ * @param {Keyframe} key0
6
+ * @param {Keyframe} key1
7
+ * @param {number} t normalized time in [0..1] between key0 and key1 where new frame is to be inserted
8
+ * @returns {Keyframe} `out`, for convenience
9
+ * @see AnimationCurve
10
+ * @example
11
+ * const new_frame = animation_curve_subdivide(new Keyframe(), key0, key1, 0.5);
12
+ * curve.add(new_frame);
13
+ */
14
+ export function animation_curve_subdivide(out: Keyframe, key0: Keyframe, key1: Keyframe, t: number): Keyframe;
15
+ //# sourceMappingURL=animation_curve_subdivide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation_curve_subdivide.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/curve/animation_curve_subdivide.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,+CAVW,QAAQ,QACR,QAAQ,QACR,QAAQ,KACR,MAAM,GACJ,QAAQ,CAqDpB"}
@@ -0,0 +1,66 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import { lerp } from "../../../core/math/lerp.js";
3
+ import { spline3_hermite } from "../../../core/math/spline/spline3_hermite.js";
4
+ import { spline3_hermite_derivative } from "../../../core/math/spline/spline3_hermite_derivative.js";
5
+
6
+ /**
7
+ * Subdivide a curve segment by introducing a new keyframe at a given normalized time.
8
+ * Subdivision does not alter the curve shape in any way, it is intended primarily for editing purposes.
9
+ * @param {Keyframe} out keyframe to be added at the point of subdivision, its tangents, time and value will be overwritten
10
+ * @param {Keyframe} key0
11
+ * @param {Keyframe} key1
12
+ * @param {number} t normalized time in [0..1] between key0 and key1 where new frame is to be inserted
13
+ * @returns {Keyframe} `out`, for convenience
14
+ * @see AnimationCurve
15
+ * @example
16
+ * const new_frame = animation_curve_subdivide(new Keyframe(), key0, key1, 0.5);
17
+ * curve.add(new_frame);
18
+ */
19
+ export function animation_curve_subdivide(
20
+ out,
21
+ key0,
22
+ key1,
23
+ t
24
+ ) {
25
+ assert.isObject(out, 'out');
26
+ assert.isObject(key0, 'key0');
27
+ assert.isObject(key1, 'key1');
28
+
29
+ assert.equal(out.isKeyframe,true,'out.isKeyframe !== true');
30
+ assert.equal(key0.isKeyframe,true,'key0.isKeyframe !== true');
31
+ assert.equal(key1.isKeyframe,true,'key1.isKeyframe !== true');
32
+
33
+ assert.isNumber(t, 't');
34
+ assert.ok(t >= 0 && t <= 1);
35
+
36
+ const v0 = key0.value;
37
+ const v1 = key1.value;
38
+
39
+ const time_span = key1.time - key0.time;
40
+
41
+ // Note that Keyframe tangents are normalized, so we denomalize them before using them
42
+ const m0 = key0.outTangent * time_span;
43
+ const m1 = key1.inTangent * time_span;
44
+
45
+ const xm = spline3_hermite(
46
+ t,
47
+ v0, v1,
48
+ m0, m1
49
+ );
50
+ const vm = spline3_hermite_derivative(
51
+ t,
52
+ v0, v1,
53
+ m0, m1
54
+ );
55
+
56
+ out.time = lerp(key0.time, key1.time, t);
57
+ out.value = xm;
58
+
59
+ // re-normalize tangent
60
+ const new_tangent = vm / time_span;
61
+
62
+ out.inTangent = new_tangent;
63
+ out.outTangent = new_tangent;
64
+
65
+ return out;
66
+ }