@woosh/meep-engine 2.55.0 → 2.56.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 (155) hide show
  1. package/editor/view/node-graph/PortView.js +2 -2
  2. package/package.json +1 -1
  3. package/src/core/binary/BinaryBuffer.js +2 -1
  4. package/src/core/cache/LoadingCache.js +10 -5
  5. package/src/core/collection/array/array_remove_element.js +6 -9
  6. package/src/core/collection/array/array_remove_first.js +13 -6
  7. package/src/core/collection/array/array_remove_first.spec.js +39 -0
  8. package/src/core/collection/array/binarySearchHighIndex.spec.js +10 -9
  9. package/src/core/collection/heap/Uin32Heap.spec.js +36 -0
  10. package/src/core/collection/heap/Uint32Heap.js +10 -5
  11. package/src/core/function/FunctionCompiler.js +4 -4
  12. package/src/core/function/Functions.js +0 -19
  13. package/src/core/geom/3d/SurfacePoint3.js +30 -20
  14. package/src/core/geom/3d/SurfacePoint3.spec.js +116 -0
  15. package/src/core/geom/3d/aabb/AABB3.js +10 -9
  16. package/src/core/geom/3d/aabb/{aabb3_array_contains_point.js → aabb3_array_intersects_point.js} +4 -1
  17. package/src/core/geom/3d/aabb/aabb3_from_min_max.js +25 -1
  18. package/src/core/geom/3d/aabb/aabb3_from_threejs_geometry.js +2 -25
  19. package/src/core/geom/3d/aabb/aabb3_signed_distance_sqr_to_point.js +5 -1
  20. package/src/core/geom/3d/apply_mat4_transform_to_direction_v3_array.js +5 -1
  21. package/src/core/geom/3d/apply_mat4_transform_to_v3_array.js +5 -1
  22. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +2 -2
  23. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.spec.js +26 -0
  24. package/src/core/geom/3d/v3_compute_triangle_normal.spec.js +18 -0
  25. package/src/core/geom/Vector2.js +1 -1
  26. package/src/core/geom/Vector3.js +1 -1
  27. package/src/core/geom/packing/miniball/Miniball.spec.js +24 -0
  28. package/src/core/math/statistics/computeStatisticalPartialMedian.js +2 -2
  29. package/src/core/model/object/read_property.js +2 -2
  30. package/src/core/model/object/write_property.js +3 -3
  31. package/src/core/primitives/numbers/compareNumbers.js +4 -4
  32. package/src/core/primitives/numbers/number_compare_ascending.js +9 -0
  33. package/src/core/primitives/numbers/number_compare_ascending.spec.js +9 -0
  34. package/src/core/primitives/numbers/number_compare_descending.js +9 -0
  35. package/src/core/primitives/numbers/number_compare_descending.spec.js +9 -0
  36. package/src/core/primitives/numbers/number_format_by_thousands.spec.js +12 -0
  37. package/src/core/primitives/numbers/number_pretty_print.js +1 -1
  38. package/src/core/primitives/strings/compareStrings.spec.js +12 -0
  39. package/src/core/primitives/strings/string_capitalize.js +15 -0
  40. package/src/core/primitives/strings/string_capitalize.spec.js +13 -0
  41. package/src/core/primitives/strings/string_compute_byte_size.js +21 -0
  42. package/src/core/primitives/strings/string_compute_common_prefix.js +44 -0
  43. package/src/core/primitives/strings/string_compute_common_prefix.spec.js +23 -0
  44. package/src/core/primitives/strings/string_format_camel_to_kebab.js +9 -0
  45. package/src/core/primitives/strings/string_format_camel_to_kebab.spec.js +8 -0
  46. package/src/core/primitives/strings/string_format_kebab_to_underscore.js +8 -0
  47. package/src/core/time/current_time_in_seconds.js +11 -0
  48. package/src/engine/Clock.js +3 -13
  49. package/src/engine/animation/curve/AnimationCurve.spec.js +27 -0
  50. package/src/engine/asset/AssetManager.js +2 -2
  51. package/src/engine/ecs/EntityManager.js +8 -1
  52. package/src/engine/ecs/EntityManager.spec.js +56 -6
  53. package/src/engine/ecs/animation/Animation.spec.js +22 -0
  54. package/src/engine/ecs/attachment/Attachment.js +24 -25
  55. package/src/engine/ecs/attachment/AttachmentBinding.js +27 -30
  56. package/src/engine/ecs/attachment/AttachmentSystem.js +21 -24
  57. package/src/engine/ecs/attachment/BoneAttachmentBinding.js +6 -9
  58. package/src/engine/ecs/attachment/TransformAttachmentBinding.js +0 -3
  59. package/src/engine/ecs/components/CharacterController.js +24 -18
  60. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +3 -2
  61. package/src/engine/ecs/fow/FogOfWarRevealer.js +2 -3
  62. package/src/engine/ecs/ik/IKMath.js +6 -1
  63. package/src/engine/ecs/ik/IKProblem.js +17 -17
  64. package/src/engine/ecs/ik/InverseKinematics.js +6 -7
  65. package/src/engine/ecs/ik/InverseKinematicsSystem.js +24 -26
  66. package/src/engine/ecs/storage/BinaryBufferSerializer.js +3 -3
  67. package/src/engine/ecs/systems/TagSystem.js +1 -6
  68. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  69. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js +2 -2
  70. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.spec.js +14 -0
  71. package/src/engine/graphics/ecs/mesh-v2/render/adapters/SGCacheKey.js +21 -9
  72. package/src/engine/graphics/ecs/mesh-v2/render/adapters/SGCacheKey.spec.js +79 -0
  73. package/src/engine/graphics/render/visibility/IncrementalDeltaSet.spec.js +7 -6
  74. package/src/engine/simulation/Ticker.js +17 -20
  75. package/src/generation/GridTaskGroup.js +5 -9
  76. package/src/generation/filtering/numeric/CellFilterCache.js +12 -16
  77. package/src/generation/filtering/numeric/complex/CellFilterFXAA.js +31 -32
  78. package/src/generation/filtering/numeric/complex/CellFilterLookupTable.js +6 -9
  79. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +7 -10
  80. package/src/generation/filtering/numeric/complex/CellFilterSobel.js +6 -9
  81. package/src/generation/filtering/numeric/math/CellFilterMembershipGeneralizedBell.js +18 -21
  82. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.js +24 -25
  83. package/src/generation/filtering/numeric/sampling/CellFilterSampleLayerLinear.js +1 -1
  84. package/src/generation/grid/GridData.js +23 -22
  85. package/src/generation/grid/GridData.spec.js +41 -0
  86. package/src/generation/grid/GridTaskGenerator.js +7 -8
  87. package/src/generation/grid/layers/GridDataLayer.js +23 -25
  88. package/src/generation/markers/GridActionRuleSet.js +20 -22
  89. package/src/generation/markers/GridCellActionPlaceMarker.js +40 -43
  90. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +7 -9
  91. package/src/generation/markers/MarkerNode.js +44 -44
  92. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +15 -18
  93. package/src/generation/markers/actions/MarkerNodeActionSequence.js +6 -9
  94. package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.js +5 -7
  95. package/src/generation/markers/actions/MarkerProcessingRule.js +25 -26
  96. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +12 -15
  97. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +2 -5
  98. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.js +6 -9
  99. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.js +8 -11
  100. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.js +13 -13
  101. package/src/generation/markers/actions/util/GridCellActionDebugBreak.js +5 -8
  102. package/src/generation/markers/actions/util/GridCellActionLogToConsole.js +1 -4
  103. package/src/generation/markers/emitter/MarkerNodeConsumerBuffer.js +10 -13
  104. package/src/generation/markers/emitter/MarkerNodeEmitterFromAction.js +5 -9
  105. package/src/generation/markers/emitter/MarkerNodeEmitterGridCellAction.js +12 -15
  106. package/src/generation/markers/emitter/MarkerNodeEmitterGroup.js +5 -8
  107. package/src/generation/markers/emitter/MarkerNodeEmitterPredicated.js +18 -21
  108. package/src/generation/markers/matcher/MarkerNodeMatcher.js +2 -1
  109. package/src/generation/markers/matcher/MarkerNodeMatcherBinary.js +12 -13
  110. package/src/generation/markers/matcher/MarkerNodeMatcherContainsTag.js +7 -9
  111. package/src/generation/markers/matcher/MarkerNodeMatcherNot.js +7 -9
  112. package/src/generation/markers/predicate/GridDataNodePredicateBinary.js +10 -14
  113. package/src/generation/markers/predicate/GridDataNodePredicateNot.js +9 -11
  114. package/src/generation/markers/predicate/GridDataNodePredicateOverlaps.js +6 -9
  115. package/src/generation/markers/transform/MarkerNodeTransformRotateRandom.js +2 -6
  116. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +6 -9
  117. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +1 -4
  118. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.js +12 -15
  119. package/src/generation/markers/transform/MarkerNodeTransformerRecordPropertyClosure.js +14 -17
  120. package/src/generation/markers/transform/MarkerNodeTransformerRecordUniqueRandomEnum.js +21 -23
  121. package/src/generation/markers/transform/MarkerNodeTransformerRemoveTag.js +1 -4
  122. package/src/generation/markers/transform/MarkerNodeTransformerSequence.js +6 -9
  123. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +13 -17
  124. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +12 -16
  125. package/src/generation/placement/GridCellActionTransformNearbyMarkers.js +26 -29
  126. package/src/generation/placement/GridCellPlacementRule.js +30 -32
  127. package/src/generation/placement/action/GridCellActionPlaceTags.js +26 -28
  128. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +16 -20
  129. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +13 -16
  130. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.js +11 -14
  131. package/src/generation/placement/action/util/CellMatcherWithinAABB.js +2 -6
  132. package/src/generation/placement/action/util/GridCellActionSequence.js +7 -9
  133. package/src/generation/placement/action/util/GridCellDisplacedAction.js +9 -12
  134. package/src/generation/rules/CellMatcherFromFilter.js +6 -9
  135. package/src/generation/rules/CellMatcherLayerBitMaskTest.js +6 -9
  136. package/src/generation/rules/GridLayerCellMatcher.js +11 -14
  137. package/src/generation/rules/cell/CellMatcherContainsMarkerWithinRadius.js +11 -14
  138. package/src/generation/rules/cell/CellMatcherGridPattern.js +6 -8
  139. package/src/generation/rules/cell/GridPatternMatcherCell.js +11 -12
  140. package/src/generation/rules/logic/CellMatcherBinary.js +10 -14
  141. package/src/generation/rules/logic/CellMatcherDecorator.js +5 -8
  142. package/src/generation/theme/AreaMask.js +15 -17
  143. package/src/generation/theme/AreaTheme.js +7 -8
  144. package/src/generation/theme/TerrainLayerDescription.js +10 -12
  145. package/src/generation/theme/TerrainLayerRule.js +11 -13
  146. package/src/generation/theme/TerrainTheme.js +6 -7
  147. package/src/generation/theme/Theme.js +15 -17
  148. package/src/generation/theme/ThemeEngine.js +16 -18
  149. package/src/view/string_tag_to_css_class_name.js +2 -2
  150. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  151. package/src/core/cache/PersistentCacheAdapter.js +0 -378
  152. package/src/core/primitives/strings/StringUtils.js +0 -105
  153. package/src/core/primitives/strings/StringUtils.spec.js +0 -42
  154. package/src/engine/ecs/components/MonsterAI.js +0 -15
  155. package/src/generation/markers/MarkerRelation.js +0 -13
@@ -1,4 +1,5 @@
1
1
  import { assert } from "../../../assert.js";
2
+ import { aabb3_from_min_max } from "./aabb3_from_min_max.js";
2
3
 
3
4
  /**
4
5
  *
@@ -13,29 +14,5 @@ export function aabb3_from_threejs_geometry(result, geometry) {
13
14
  const min = gbb.min;
14
15
  const max = gbb.max;
15
16
 
16
- const x0 = min.x;
17
- const y0 = min.y;
18
- const z0 = min.z;
19
-
20
- const x1 = max.x;
21
- const y1 = max.y;
22
- const z1 = max.z;
23
-
24
- // validate bounds
25
- assert.notNaN(x0, 'x0');
26
- assert.notNaN(y0, 'y0');
27
- assert.notNaN(z0, 'z0');
28
-
29
- assert.notNaN(x1, 'x1');
30
- assert.notNaN(y1, 'y1');
31
- assert.notNaN(z1, 'z1');
32
-
33
- // marshal into transform-accepted format
34
- result[0] = x0;
35
- result[1] = y0;
36
- result[2] = z0;
37
-
38
- result[3] = x1;
39
- result[4] = y1;
40
- result[5] = z1;
17
+ aabb3_from_min_max(result, min, max);
41
18
  }
@@ -13,7 +13,11 @@ import { max2 } from "../../../math/max2.js";
13
13
  * @param {number} point_z
14
14
  * @returns {number}
15
15
  */
16
- export function aabb3_signed_distance_sqr_to_point(x0, y0, z0, x1, y1, z1, point_x, point_y, point_z) {
16
+ export function aabb3_signed_distance_sqr_to_point(
17
+ x0, y0, z0,
18
+ x1, y1, z1,
19
+ point_x, point_y, point_z
20
+ ) {
17
21
  //do projection
18
22
  const xp0 = x0 - point_x;
19
23
  const xp1 = point_x - x1;
@@ -8,7 +8,11 @@
8
8
  * @param {number} vertex_count
9
9
  * @param {mat4|number[]|Float32Array} mat4
10
10
  */
11
- export function apply_mat4_transform_to_direction_v3_array(source, source_offset, destination, destination_offset, vertex_count, mat4) {
11
+ export function apply_mat4_transform_to_direction_v3_array(
12
+ source, source_offset,
13
+ destination, destination_offset,
14
+ vertex_count, mat4
15
+ ) {
12
16
 
13
17
  const a0 = mat4[0];
14
18
  const a1 = mat4[1];
@@ -8,7 +8,11 @@
8
8
  * @param {number} vertex_count
9
9
  * @param {mat4|number[]|Float32Array} mat4
10
10
  */
11
- export function apply_mat4_transform_to_v3_array(source, source_offset, destination, destination_offset, vertex_count, mat4) {
11
+ export function apply_mat4_transform_to_v3_array(
12
+ source, source_offset,
13
+ destination, destination_offset,
14
+ vertex_count, mat4
15
+ ) {
12
16
 
13
17
  const a0 = mat4[0];
14
18
  const a1 = mat4[1];
@@ -4,9 +4,9 @@ import { max3 } from "../../../math/max3.js";
4
4
  import { assert } from "../../../assert.js";
5
5
  import { array_copy } from "../../../collection/array/array_copy.js";
6
6
  import { array_quick_sort_by_comparator } from "../../../collection/array/arrayQuickSort.js";
7
- import { compareNumbersDescending } from "../../../function/Functions.js";
8
7
  import { BinaryBuffer } from "../../../binary/BinaryBuffer.js";
9
8
  import { Base64 } from "../../../binary/Base64.js";
9
+ import { number_compare_descending } from "../../../primitives/numbers/number_compare_descending.js";
10
10
 
11
11
  /**
12
12
  * @readonly
@@ -546,7 +546,7 @@ export class TetrahedralMesh {
546
546
  */
547
547
  compact() {
548
548
  // sort free
549
- array_quick_sort_by_comparator(this.__free, compareNumbersDescending, null, 0, this.__free_pointer - 1);
549
+ array_quick_sort_by_comparator(this.__free, number_compare_descending, null, 0, this.__free_pointer - 1);
550
550
 
551
551
  let relocation_count = 0;
552
552
  let free_head_pointer = 0;
@@ -0,0 +1,26 @@
1
+ import { computeTriangleRayIntersectionBarycentric } from "./computeTriangleRayIntersectionBarycentric.js";
2
+
3
+ test("orthogonal, through center", () => {
4
+
5
+ const result = [];
6
+
7
+ const hit_found = computeTriangleRayIntersectionBarycentric(
8
+ result,
9
+ 0, 0, 3,
10
+ 0, 0, -1,
11
+ -1, -1, 0,
12
+ 1, -1, 0,
13
+ 1, 1, 0
14
+ );
15
+
16
+ expect(hit_found).toBe(true);
17
+
18
+ expect(result[0]).toBeCloseTo(3);
19
+
20
+ // note that UVs are just checked for sanity
21
+ expect(result[1]).toBeGreaterThanOrEqual(0);
22
+ expect(result[1]).toBeLessThanOrEqual(1);
23
+
24
+ expect(result[2]).toBeGreaterThanOrEqual(0);
25
+ expect(result[2]).toBeLessThanOrEqual(1);
26
+ });
@@ -25,3 +25,21 @@ test("axis aligned triangles on -X plane", () => {
25
25
 
26
26
  expect(result).toEqual([-1, 0, 0]);
27
27
  });
28
+
29
+ test("degenerate triangle with all points at the same position", () => {
30
+ const result = [];
31
+
32
+ v3_compute_triangle_normal(
33
+ result, 0,
34
+ 1, 3, 5,
35
+ 1, 3, 5,
36
+ 1, 3, 5,
37
+ );
38
+
39
+ expect(result[0]).not.toBeNaN();
40
+ expect(result[1]).not.toBeNaN();
41
+ expect(result[2]).not.toBeNaN();
42
+
43
+ // normal vector length should be 1
44
+ expect(Math.hypot(result[0], result[1], result[2])).toBeCloseTo(1);
45
+ });
@@ -581,7 +581,7 @@ class Vector2 {
581
581
  }
582
582
 
583
583
  toString() {
584
- return `Vector2{x:${this.x}, y:${this.y}}`;
584
+ return `Vector2{ x:${this.x}, y:${this.y} }`;
585
585
  }
586
586
 
587
587
  /**
@@ -806,7 +806,7 @@ class Vector3 {
806
806
  }
807
807
 
808
808
  toString() {
809
- return `{ x:${this.x}, y:${this.y}, z:${this.z} }`;
809
+ return `Vector3{ x:${this.x}, y:${this.y}, z:${this.z} }`;
810
810
  }
811
811
 
812
812
  /**
@@ -1,6 +1,13 @@
1
1
  import { Miniball } from "./Miniball.js";
2
2
  import { PointSet } from "./PointSet.js";
3
3
 
4
+
5
+ test("empty point set in 1d", () => {
6
+
7
+ new Miniball(new PointSet(0, 1, []));
8
+
9
+ });
10
+
4
11
  test("single point in 1d", () => {
5
12
 
6
13
  const miniball = new Miniball(new PointSet(1, 1, [7]));
@@ -9,3 +16,20 @@ test("single point in 1d", () => {
9
16
  expect(miniball.radius()).toEqual(0);
10
17
 
11
18
  });
19
+
20
+ test("3 points in 1d", () => {
21
+ const miniball = new Miniball(new PointSet(3, 1, [-3, 7, 11]));
22
+
23
+ expect(miniball.center()[0]).toBeCloseTo(4);
24
+ expect(miniball.radius()).toBeCloseTo(7);
25
+ });
26
+
27
+ test("toString produces a valid string", () => {
28
+
29
+ const miniball = new Miniball(new PointSet(1, 1, [7]));
30
+
31
+ const s = miniball.toString();
32
+
33
+ expect(typeof s).toBe("string");
34
+ expect(s.trim().length).toBeGreaterThan(0);
35
+ });
@@ -1,5 +1,5 @@
1
- import { compareNumbersAscending } from "../../function/Functions.js";
2
1
  import { assert } from "../../assert.js";
2
+ import { number_compare_ascending } from "../../primitives/numbers/number_compare_ascending.js";
3
3
 
4
4
  /**
5
5
  *
@@ -14,7 +14,7 @@ export function computeStatisticalPartialMedian(values, start, end) {
14
14
 
15
15
  const copy = values.slice();
16
16
 
17
- copy.sort(compareNumbersAscending);
17
+ copy.sort(number_compare_ascending);
18
18
 
19
19
  const range = end - start;
20
20
 
@@ -1,4 +1,4 @@
1
- import { capitalize } from "../../primitives/strings/StringUtils.js";
1
+ import { string_capitalize } from "../../primitives/strings/string_capitalize.js";
2
2
 
3
3
  /**
4
4
  * @template T
@@ -19,7 +19,7 @@ export function read_property(root, parts, part_offset, part_count) {
19
19
  if (typeof thing[part] !== 'undefined') {
20
20
  thing = thing[part];
21
21
  } else {
22
- const getter_name = `get${capitalize(part)}`;
22
+ const getter_name = `get${string_capitalize(part)}`;
23
23
  const getter = thing[getter_name];
24
24
 
25
25
  if (typeof getter === "function") {
@@ -1,4 +1,4 @@
1
- import { capitalize } from "../../primitives/strings/StringUtils.js";
1
+ import { string_capitalize } from "../../primitives/strings/string_capitalize.js";
2
2
 
3
3
  /**
4
4
  * @template T
@@ -23,7 +23,7 @@ export function write_property(root, parts, part_offset, part_count, value) {
23
23
  thing = thing_part;
24
24
  } else {
25
25
 
26
- const getter_name = `get${capitalize(part)}`;
26
+ const getter_name = `get${string_capitalize(part)}`;
27
27
  const getter = thing[getter_name];
28
28
 
29
29
  if (typeof getter === "function") {
@@ -38,7 +38,7 @@ export function write_property(root, parts, part_offset, part_count, value) {
38
38
 
39
39
  const last_part = parts[last_index];
40
40
 
41
- const setter_name = `set${capitalize(last_part)}`;
41
+ const setter_name = `set${string_capitalize(last_part)}`;
42
42
  const setter = thing[setter_name];
43
43
 
44
44
  if (typeof setter === "function") {
@@ -1,9 +1,9 @@
1
+ import { number_compare_ascending } from "./number_compare_ascending.js";
2
+
1
3
  /**
2
- *
4
+ * @deprecated use {@link number_compare_ascending} directly
3
5
  * @param {number} a
4
6
  * @param {number} b
5
7
  * @returns {number}
6
8
  */
7
- export function compareNumbers(a, b) {
8
- return a - b;
9
- }
9
+ export const compareNumbers = number_compare_ascending;
@@ -0,0 +1,9 @@
1
+ /**
2
+ *
3
+ * @param {number} a
4
+ * @param {number} b
5
+ * @return {number}
6
+ */
7
+ export function number_compare_ascending(a, b) {
8
+ return a - b;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { number_compare_ascending } from "./number_compare_ascending.js";
2
+
3
+ test("basics", () => {
4
+
5
+ expect([1, 2].sort(number_compare_ascending)).toEqual([1, 2]);
6
+
7
+ expect([2, 1].sort(number_compare_ascending)).toEqual([1, 2]);
8
+
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ *
3
+ * @param {number} a
4
+ * @param {number} b
5
+ * @return {number}
6
+ */
7
+ export function number_compare_descending(a, b) {
8
+ return b - a;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { number_compare_descending } from "./number_compare_descending.js";
2
+
3
+ test("basics", () => {
4
+
5
+ expect([2, 1].sort(number_compare_descending)).toEqual([2, 1]);
6
+
7
+ expect([1, 2].sort(number_compare_descending)).toEqual([2, 1]);
8
+
9
+ });
@@ -0,0 +1,12 @@
1
+ import { number_format_by_thousands } from "./number_format_by_thousands.js";
2
+
3
+ test("basics", () => {
4
+
5
+ expect(number_format_by_thousands(0, ',')).toEqual("0");
6
+ expect(number_format_by_thousands(987, ',')).toEqual("987");
7
+ expect(number_format_by_thousands(1234, ',')).toEqual("1,234");
8
+ expect(number_format_by_thousands(987654321, ',')).toEqual("987,654,321");
9
+
10
+ // different separator
11
+ expect(number_format_by_thousands(1234, ' -> ')).toEqual("1 -> 234");
12
+ });
@@ -29,7 +29,7 @@ function countDecimals(value) {
29
29
  /**
30
30
  *
31
31
  * @param {number} value
32
- * @returns {string|number}
32
+ * @returns {string}
33
33
  */
34
34
  export function number_pretty_print(value) {
35
35
  assert.isNumber(value, 'value');
@@ -0,0 +1,12 @@
1
+ import { compareStrings } from "./compareStrings.js";
2
+
3
+ test("stability", () => {
4
+
5
+ const array_a = ["a", undefined, "test", null, ""];
6
+ const array_b = [null, undefined, "", "a", "test"];
7
+
8
+ array_a.sort(compareStrings);
9
+ array_b.sort(compareStrings);
10
+
11
+ expect(array_a).toEqual(array_b);
12
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Turn first letter in the string to capital
3
+ * @example "text" will become "Text"
4
+ * @param {string} string
5
+ * @returns {string}
6
+ */
7
+ export function string_capitalize(string) {
8
+ const length = string.length;
9
+
10
+ if (length === 0) {
11
+ return string;
12
+ } else {
13
+ return string.charAt(0).toLocaleUpperCase() + string.substring(1);
14
+ }
15
+ }
@@ -0,0 +1,13 @@
1
+ import { string_capitalize } from "./string_capitalize.js";
2
+
3
+ test("capitalize", () => {
4
+ expect(string_capitalize("")).toBe("");
5
+
6
+ expect(string_capitalize("a")).toBe("A");
7
+
8
+ expect(string_capitalize("A")).toBe("A");
9
+
10
+ expect(string_capitalize("aa")).toBe("Aa");
11
+
12
+ expect(string_capitalize("AA")).toBe("AA");
13
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Compute byte size of a UTF8 string
3
+ * @param {string} value
4
+ * @returns {number}
5
+ */
6
+ export function string_compute_byte_size(value) {
7
+ const length = value.length;
8
+
9
+ let p = 0;
10
+
11
+ for (let i = 0; i < length; i++) {
12
+ let c = value.charCodeAt(i);
13
+ while (c > 0xff) {
14
+ p++;
15
+ c >>= 8;
16
+ }
17
+ p++;
18
+ }
19
+
20
+ return p;
21
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @example: ['abra', 'abc', 'abode'] => 'ab'
3
+ * @param {String[]} strings
4
+ * @returns string
5
+ */
6
+ export function string_compute_common_prefix(strings) {
7
+ let i, j;
8
+
9
+ const numInputs = strings.length;
10
+
11
+ let result = "";
12
+
13
+ if (numInputs === 0) {
14
+ return result;
15
+ }
16
+
17
+ const firstString = strings[0];
18
+
19
+ let lengthLimit = firstString.length;
20
+
21
+ for (i = 1; i < numInputs; i++) {
22
+ lengthLimit = Math.min(strings[i].length, lengthLimit);
23
+ }
24
+
25
+
26
+ main_loop:for (i = 0; i < lengthLimit; i++) {
27
+ const letter0 = firstString.charAt(i);
28
+
29
+ for (j = 1; j < numInputs; j++) {
30
+
31
+ const string = strings[j];
32
+
33
+ const letter1 = string.charAt(i);
34
+
35
+ if (letter0 !== letter1) {
36
+ break main_loop;
37
+ }
38
+ }
39
+
40
+ result += letter0;
41
+ }
42
+
43
+ return result;
44
+ }
@@ -0,0 +1,23 @@
1
+ import { string_compute_common_prefix } from "./string_compute_common_prefix.js";
2
+
3
+ test("common prefix", () => {
4
+ expect(string_compute_common_prefix([])).toBe("");
5
+
6
+ expect(string_compute_common_prefix([""])).toBe("");
7
+
8
+ expect(string_compute_common_prefix(["a"])).toBe("a");
9
+
10
+ expect(string_compute_common_prefix(["abc"])).toBe("abc");
11
+
12
+ expect(string_compute_common_prefix(["aa"])).toBe("aa");
13
+
14
+ expect(string_compute_common_prefix(["aa", "ab"])).toBe("a");
15
+
16
+ expect(string_compute_common_prefix(["abc", "abb"])).toBe("ab");
17
+
18
+ expect(string_compute_common_prefix(["abc", "abc"])).toBe("abc");
19
+
20
+ expect(string_compute_common_prefix(["abc", "abc", "a"])).toBe("a");
21
+
22
+ expect(string_compute_common_prefix(["abc", "abc", ""])).toBe("");
23
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Convert camelCaseString to kebab-format-string
3
+ * useful for resolving CSS property names
4
+ * @param {string} string
5
+ * @returns {string}
6
+ */
7
+ export function string_format_camel_to_kebab(string) {
8
+ return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
9
+ }
@@ -0,0 +1,8 @@
1
+ import { string_format_camel_to_kebab } from "./string_format_camel_to_kebab.js";
2
+
3
+ test('camelToKebab', () => {
4
+ expect(string_format_camel_to_kebab('a')).toBe('a');
5
+ expect(string_format_camel_to_kebab('aA')).toBe('a-a');
6
+ expect(string_format_camel_to_kebab('helloWoRLD')).toBe('hello-wo-rld');
7
+ expect(string_format_camel_to_kebab('A')).toBe('a');
8
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Convert kebab-format-string to underscore_format_string
3
+ * @param {string} string
4
+ * @returns {string}
5
+ */
6
+ export function string_format_kebab_to_underscore(string) {
7
+ return string.replace('-', '_');
8
+ }
@@ -0,0 +1,11 @@
1
+
2
+ //Use highest available resolution time source
3
+ const source = typeof performance === "undefined" ? Date : performance;
4
+
5
+ /**
6
+ * Current time in seconds
7
+ * @returns {number}
8
+ */
9
+ export function current_time_in_seconds() {
10
+ return source.now() * 1e-3;
11
+ }
@@ -4,24 +4,14 @@
4
4
 
5
5
 
6
6
  import Stat from "../core/model/stat/Stat.js";
7
-
8
- //Use highest available resolution time source
9
- const source = typeof performance === "undefined" ? Date : performance;
10
-
11
- /**
12
- *
13
- * @returns {number}
14
- */
15
- export function currentTimeInSeconds() {
16
- return source.now() * 0.001;
17
- }
7
+ import { current_time_in_seconds } from "../core/time/current_time_in_seconds.js";
18
8
 
19
9
  /**
20
10
  *
21
11
  * @param {Clock} clock
22
12
  */
23
13
  function updateElapsedTime(clock) {
24
- const now = currentTimeInSeconds();
14
+ const now = current_time_in_seconds();
25
15
  const delta = (now - clock.__lastMeasurement) * clock.speed;
26
16
  clock.__lastMeasurement = now;
27
17
  clock.elapsedTime += delta;
@@ -79,7 +69,7 @@ class Clock {
79
69
  }
80
70
 
81
71
  start() {
82
- this.__lastMeasurement = currentTimeInSeconds();
72
+ this.__lastMeasurement = current_time_in_seconds();
83
73
  this.timeAtDelta = this.updateElapsedTime();
84
74
  this.__isRunning = true;
85
75
  }
@@ -46,6 +46,19 @@ test("removing exising key", () => {
46
46
  expect(curve.length).toBe(0);
47
47
  });
48
48
 
49
+ test("evaluate on empty curve", () => {
50
+ const curve = new AnimationCurve();
51
+
52
+ expect(curve.evaluate(0)).toBe(0);
53
+ });
54
+
55
+ test("evaluate before first frame", () => {
56
+ const curve = new AnimationCurve();
57
+
58
+ curve.add(Keyframe.from(1, 7));
59
+
60
+ expect(curve.evaluate(0.9)).toEqual(7);
61
+ });
49
62
 
50
63
  test("sample linear curve with 2 points", () => {
51
64
  const curve = new AnimationCurve();
@@ -78,6 +91,20 @@ test("smooth tangents with a single keyframe does not throw", () => {
78
91
 
79
92
  expect(() => curve.smoothTangents(0, 1)).not.toThrow()
80
93
  });
94
+ test("smooth tangents on a middle frame", () => {
95
+ const curve = new AnimationCurve();
96
+
97
+ curve.add(Keyframe.from(0, 1));
98
+ curve.add(Keyframe.from(1, 2));
99
+ curve.add(Keyframe.from(2, 3));
100
+
101
+ curve.smoothTangents(1, 1);
102
+
103
+ const key = curve.keys[1];
104
+
105
+ expect(key.inTangent).toEqual(key.outTangent);
106
+ });
107
+
81
108
 
82
109
  test("to/from JSON consistency", () => {
83
110
 
@@ -9,7 +9,6 @@ import { extractAssetListFromManager } from "./preloader/extractAssetListFromMan
9
9
  import { assert } from "../../core/assert.js";
10
10
  import { HashSet } from "../../core/collection/set/HashSet.js";
11
11
  import { CrossOriginConfig } from "./CORS/CrossOriginConfig.js";
12
- import { array_remove_element } from "../../core/collection/array/array_remove_element.js";
13
12
  import { AssetDescription } from "./AssetDescription.js";
14
13
  import { noop } from "../../core/function/Functions.js";
15
14
  import { Deque } from "../../core/collection/queue/Deque.js";
@@ -23,6 +22,7 @@ import ConcurrentExecutor from "../../core/process/executor/ConcurrentExecutor.j
23
22
  import { AssetLoader } from "./loaders/AssetLoader.js";
24
23
  import { array_push_if_unique } from "../../core/collection/array/array_push_if_unique.js";
25
24
  import { AssetRequestScope } from "./AssetRequestScope.js";
25
+ import { array_remove_first } from "../../core/collection/array/array_remove_first.js";
26
26
 
27
27
 
28
28
  class Response {
@@ -701,7 +701,7 @@ export class AssetManager {
701
701
  return false;
702
702
  }
703
703
 
704
- if (!array_remove_element(transformers, 0, transformers.length, transformer)) {
704
+ if (!array_remove_first(transformers, transformer)) {
705
705
  // not found
706
706
  return false;
707
707
  }
@@ -202,7 +202,7 @@ EntityManager.prototype.detachDataSet = function () {
202
202
  };
203
203
 
204
204
  /**
205
- *
205
+ * Get list of all components referenced by active systems
206
206
  * @returns {Class[]}
207
207
  */
208
208
  EntityManager.prototype.getComponentTypeMap = function () {
@@ -237,6 +237,12 @@ EntityManager.prototype.getComponentTypeMap = function () {
237
237
  EntityManager.prototype.attachDataSet = function (dataset) {
238
238
  //check if another dataset is attached
239
239
  if (this.dataset !== null) {
240
+
241
+ if (this.dataset === dataset) {
242
+ // special case, we already have this dataset attached. Nothing to more to do
243
+ return;
244
+ }
245
+
240
246
  throw new Error("Illegal status, another dataset is currently attached");
241
247
  }
242
248
 
@@ -285,6 +291,7 @@ EntityManager.prototype.getSystem = function (systemClass) {
285
291
 
286
292
 
287
293
  /**
294
+ * @deprecated use {@link EntityComponentDataset.getComponentClassByName} instead
288
295
  * @template T
289
296
  * @param {string} className
290
297
  * @returns {null|Class<T>}