@woosh/meep-engine 2.50.3 → 2.51.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 (120) hide show
  1. package/editor/actions/concrete/WriteGridValueAction.js +13 -18
  2. package/editor/ecs/component/editors/Sampler2DEditor.js +2 -2
  3. package/editor/process/SymbolicDisplayProcess.js +1 -1
  4. package/editor/process/symbolic/buildThreeJSHelperEntity.js +1 -1
  5. package/editor/process/symbolic/makeCameraSymbolicDisplay.js +1 -1
  6. package/editor/process/symbolic/makeGridPositionSymbolDisplay.js +1 -1
  7. package/editor/process/symbolic/makeLightSymbolicDisplay.js +1 -1
  8. package/editor/process/symbolic/makePathSymbolicDisplay.js +1 -1
  9. package/editor/process/symbolic/makePositionedIconDisplaySymbol.js +1 -1
  10. package/editor/view/ecs/components/GridObstacleController.js +2 -2
  11. package/editor/view/ecs/components/TerrainController.js +2 -2
  12. package/package.json +1 -1
  13. package/samples/terrain/editor.js +2 -2
  14. package/src/core/UUID.spec.js +8 -0
  15. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +4 -0
  16. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +57 -55
  17. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +54 -0
  18. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js +3 -3
  19. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.spec.js +60 -0
  20. package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +2 -2
  21. package/src/core/cache/Cache.js +3 -5
  22. package/src/core/cache/CacheElement.js +1 -0
  23. package/src/core/geom/2d/quad-tree/PointQuadTree.js +10 -0
  24. package/src/core/geom/3d/aabb/aabb3_array_combine.js +3 -3
  25. package/src/core/graph/{convertGraphToDotString.js → convert_graph_to_dot_string.js} +1 -1
  26. package/src/core/graph/convert_graph_to_dot_string.spec.js +28 -0
  27. package/src/core/math/noise/sdnoise.js +5 -7
  28. package/src/core/math/noise/sdnoise.spec.js +87 -0
  29. package/src/engine/{Platform.js → browserInfo.js} +1 -5
  30. package/src/engine/ecs/fow/FogOfWar.js +48 -54
  31. package/src/engine/ecs/{systems → renderable}/RenderSystem.d.ts +1 -1
  32. package/src/engine/ecs/{systems → renderable}/RenderSystem.js +10 -38
  33. package/src/engine/ecs/renderable/Renderable.d.ts +25 -0
  34. package/src/engine/ecs/{components → renderable}/Renderable.js +18 -83
  35. package/src/engine/ecs/renderable/Renderable.spec.js +10 -0
  36. package/src/engine/ecs/speaker/VoiceSystem.js +15 -9
  37. package/src/engine/ecs/systems/MeshColliderSystem.js +1 -1
  38. package/src/engine/ecs/systems/RangedAttackSystem.js +1 -1
  39. package/src/engine/ecs/systems/ViewportMeshProjectionSystem.js +1 -1
  40. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +2 -2
  41. package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +3 -3
  42. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +2 -2
  43. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +2 -2
  44. package/src/engine/ecs/terrain/util/paintTerrainOverlayViaLookupTable.js +2 -2
  45. package/src/engine/graphics/copy_transform_to_threejs_object.js +12 -0
  46. package/src/engine/graphics/debug/VisualSymbolLine.js +1 -1
  47. package/src/engine/graphics/ecs/decal/DecalSystem.js +1 -1
  48. package/src/engine/graphics/ecs/highlight/renderer/makeGaussianBlurShader.js +1 -4
  49. package/src/engine/graphics/ecs/highlight/system/RenderableHighlightSystem.d.ts +1 -1
  50. package/src/engine/graphics/ecs/highlight/system/RenderableHighlightSystem.js +2 -2
  51. package/src/engine/graphics/ecs/mesh/applyTransformToThreeObject.js +2 -5
  52. package/src/engine/graphics/ecs/path/ribbon/RibbonPathBuilder.js +2 -2
  53. package/src/engine/graphics/geometry/optimization/merge/prototypeGeometryMerge.js +1 -1
  54. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
  55. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
  56. package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +2 -2
  57. package/src/engine/graphics/shaders/SoftOutlineShader.js +2 -4
  58. package/src/engine/graphics/texture/atlas/CachingTextureAtlas.spec.js +24 -0
  59. package/src/engine/graphics/texture/atlas/TextureAtlas.spec.js +46 -0
  60. package/src/engine/graphics/texture/sampler/SampleTraverser.js +1 -1
  61. package/src/engine/graphics/texture/sampler/bicubic.spec.js +13 -0
  62. package/src/engine/graphics/texture/sampler/differenceSampler.js +1 -1
  63. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_NaiveFlood.js +5 -1
  64. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_NaiveFlood.spec.js +183 -0
  65. package/src/engine/graphics/texture/sampler/filter/filter_lanczos3.js +20 -0
  66. package/src/engine/graphics/texture/sampler/filter/mitchell.js +0 -21
  67. package/src/engine/graphics/texture/sampler/filter/mitchell_v1.js +21 -0
  68. package/src/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +17 -16
  69. package/src/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +11 -9
  70. package/src/engine/graphics/texture/sampler/{scaleSampler2D.js → resize/sampler2d_scale.js} +8 -8
  71. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale.spec.js +73 -0
  72. package/src/engine/graphics/texture/sampler/{sampler2_d_scale_down_lanczos.js → resize/sampler2d_scale_down_lanczos.js} +3 -24
  73. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.spec.js +29 -0
  74. package/src/engine/graphics/texture/sampler/{sampler2d_scale_down_linear.js → resize/sampler2d_scale_down_linear.js} +5 -5
  75. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.spec.js +44 -0
  76. package/src/engine/graphics/texture/sampler/resize/{sampler2d_downsample_mipmap.js → sampler2d_scale_down_mipmap.js} +2 -2
  77. package/src/engine/graphics/texture/sampler/resize/{sampler2d_downsample_mipmap.spec.js → sampler2d_scale_down_mipmap.spec.js} +2 -2
  78. package/src/engine/graphics/texture/sampler/{genericResampleSampler2D.js → resize/sampler2d_scale_generic.js} +16 -12
  79. package/src/engine/graphics/texture/sampler/{upsampleSampler2D.js → resize/sampler2d_scale_up_linear.js} +5 -2
  80. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_up_linear.spec.js +14 -0
  81. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +4 -2
  82. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.spec.js +15 -0
  83. package/src/engine/graphics/texture/sampler/util/drawSamplerHTML.js +2 -2
  84. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.js +66 -0
  85. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.spec.js +108 -0
  86. package/src/engine/graphics/trail/TemporalPath.js +83 -78
  87. package/src/engine/graphics/trail/TemporalPath.spec.js +5 -0
  88. package/src/engine/graphics/trail/x/RibbonX.spec.js +5 -0
  89. package/src/engine/input/devices/InputDeviceSwitch.spec.js +5 -0
  90. package/src/engine/input/ecs/{InputBinding.js → components/InputBinding.js} +1 -1
  91. package/src/engine/input/ecs/components/InputController.js +2 -2
  92. package/src/engine/input/ecs/ism/InputBinding.js +2 -2
  93. package/src/engine/input/ecs/util/TerrainCameraTargetSampler.js +1 -1
  94. package/src/engine/input/ecs/util/TopDownCameraControllerHelper.js +1 -1
  95. package/src/engine/intelligence/behavior/behavior_to_dot.spec.js +25 -0
  96. package/src/engine/intelligence/behavior/util/DelayBehavior.js +6 -4
  97. package/src/engine/intelligence/blackboard/Blackboard.d.ts +2 -0
  98. package/src/engine/intelligence/blackboard/Blackboard.js +36 -2
  99. package/src/engine/intelligence/blackboard/Blackboard.spec.js +49 -0
  100. package/src/engine/intelligence/blackboard/BlackboardSerializationAdapter.spec.js +2 -0
  101. package/src/engine/navigation/grid/{AStar.js → find_path_on_grid_astar.js} +21 -18
  102. package/src/engine/navigation/grid/find_path_on_grid_astar.spec.js +7 -0
  103. package/src/engine/sound/ecs/SoundListenerSystem.js +1 -1
  104. package/src/generation/markers/debug/visualizeMarkers.js +1 -1
  105. package/src/engine/MeepSettings.js +0 -9
  106. package/src/engine/User.js +0 -28
  107. package/src/engine/UserController.js +0 -273
  108. package/src/engine/ecs/components/AABB.js +0 -33
  109. package/src/engine/ecs/components/AABBCollider.js +0 -15
  110. package/src/engine/ecs/components/Renderable.d.ts +0 -14
  111. package/src/engine/ecs/grid/Sampler2DDecoder.js +0 -57
  112. package/src/engine/ecs/grid/makeTerrainGeometry.js +0 -110
  113. package/src/engine/ecs/systems/AABBColliderSystem.js +0 -61
  114. package/src/engine/ecs/systems/AABBSystem.js +0 -89
  115. package/src/engine/graphics/texture/sampler/sampler2d_make_array_filler_function.js +0 -65
  116. package/src/engine/graphics/texture/sampler/sampler2d_scale_down_linear.spec.js +0 -17
  117. package/src/engine/graphics/trail/x/simulator/RibbonState.js +0 -10
  118. package/src/engine/grid/Grid.js +0 -131
  119. package/src/engine/navigation/grid/GridField.js +0 -328
  120. /package/src/engine/ecs/{components → renderable}/RenderableFlags.js +0 -0
@@ -1,4 +1,3 @@
1
- import GridField from "../../../src/engine/navigation/grid/GridField.js";
2
1
  import GridObstacle from "../../../src/engine/grid/components/GridObstacle.js";
3
2
  import { Action } from "../../../src/core/process/undo/Action.js";
4
3
 
@@ -16,31 +15,27 @@ class WriteGridValueAction extends Action {
16
15
  }
17
16
 
18
17
  async apply(editor) {
19
- const obstacle = editor.engine.entityManager.getComponent(this.entity, GridObstacle);
18
+ /**
19
+ * @type {Engine}
20
+ */
21
+ const engine = editor.engine;
22
+
23
+ /**
24
+ *
25
+ * @type {GridObstacle}
26
+ */
27
+ const obstacle = engine.entityManager.dataset.getComponent(this.entity, GridObstacle);
20
28
  this.obstacle = obstacle;
21
29
 
22
30
 
23
- const gridField = obstacle2grid(obstacle);
24
-
25
- this.oldValue = gridField.read(this.x, this.y);
26
- gridField.pointSet(this.x, this.y, this.value);
31
+ this.oldValue = obstacle.readPoint(this.x, this.y);
32
+ obstacle.writePoint(this.x, this.y, this.value);
27
33
  }
28
34
 
29
35
  async revert(editor) {
30
- const gridField = obstacle2grid(this.obstacle);
31
36
 
32
- gridField.pointSet(this.x, this.y, this.oldValue);
37
+ this.obstacle.writePoint(this.x, this.y, this.oldValue);
33
38
  }
34
39
  }
35
40
 
36
- function obstacle2grid(obstacle) {
37
- const gridField = new GridField();
38
-
39
- gridField.width = obstacle.size.x;
40
- gridField.height = obstacle.size.y;
41
- gridField.data = obstacle.data;
42
-
43
- return gridField;
44
- }
45
-
46
41
  export default WriteGridValueAction;
@@ -1,7 +1,7 @@
1
1
  import { TypeEditor } from "../TypeEditor.js";
2
2
  import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
3
3
  import sampler2D2Canvas from "../../../../src/engine/graphics/texture/sampler/Sampler2D2Canvas.js";
4
- import { scaleSampler2D } from "../../../../src/engine/graphics/texture/sampler/scaleSampler2D.js";
4
+ import { sampler2d_scale } from "../../../../src/engine/graphics/texture/sampler/resize/sampler2d_scale.js";
5
5
  import { Sampler2D } from "../../../../src/engine/graphics/texture/sampler/Sampler2D.js";
6
6
  import {
7
7
  typedArrayConstructorByInstance
@@ -38,7 +38,7 @@ function draw_sampler(sampler, domElement) {
38
38
  const res = 32;
39
39
  const result_sampler = new Sampler2D(new TypedArrayConstructor(sampler.itemSize * res * res), sampler.itemSize, res, res);
40
40
 
41
- scaleSampler2D(sampler, result_sampler);
41
+ sampler2d_scale(sampler, result_sampler);
42
42
 
43
43
 
44
44
  const { scale, offset } = sampler2d_compute_texel_value_conversion_scale_to_uint8(result_sampler);
@@ -1,6 +1,6 @@
1
1
  import { EditorProcess } from "./EditorProcess.js";
2
2
  import { ParticleEmitter } from "../../src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js";
3
- import RenderSystem from "../../src/engine/ecs/systems/RenderSystem.js";
3
+ import RenderSystem from "../../src/engine/ecs/renderable/RenderSystem.js";
4
4
  import { Camera } from "../../src/engine/graphics/ecs/camera/Camera.js";
5
5
  import { Light } from "../../src/engine/graphics/ecs/light/Light.js";
6
6
  import { ComponentSymbolicDisplay } from "./symbolic/ComponentSymbolicDisplay.js";
@@ -1,5 +1,5 @@
1
1
  import EntityBuilder from "../../../src/engine/ecs/EntityBuilder.js";
2
- import Renderable from "../../../src/engine/ecs/components/Renderable.js";
2
+ import Renderable from "../../../src/engine/ecs/renderable/Renderable.js";
3
3
  import { Transform } from "../../../src/engine/ecs/transform/Transform.js";
4
4
  import EditorEntity from "../../ecs/EditorEntity.js";
5
5
  import Script from "../../../src/engine/ecs/components/Script.js";
@@ -1,7 +1,7 @@
1
1
  import { make3DSymbolicDisplay } from "./make3DSymbolicDisplay.js";
2
2
  import { CameraHelper } from "three";
3
3
  import { buildThreeJSHelperEntity } from "./buildThreeJSHelperEntity.js";
4
- import Renderable from "../../../src/engine/ecs/components/Renderable.js";
4
+ import Renderable from "../../../src/engine/ecs/renderable/Renderable.js";
5
5
  import { Camera } from "../../../src/engine/graphics/ecs/camera/Camera.js";
6
6
  import { Transform } from "../../../src/engine/ecs/transform/Transform.js";
7
7
 
@@ -4,7 +4,7 @@ import Task from "../../../src/core/process/task/Task.js";
4
4
  import { TaskSignal } from "../../../src/core/process/task/TaskSignal.js";
5
5
  import EntityBuilder from "../../../src/engine/ecs/EntityBuilder.js";
6
6
  import { BufferGeometry, Float32BufferAttribute, Line, LineBasicMaterial } from "three";
7
- import Renderable from "../../../src/engine/ecs/components/Renderable.js";
7
+ import Renderable from "../../../src/engine/ecs/renderable/Renderable.js";
8
8
  import { SurfacePoint3 } from "../../../src/core/geom/3d/SurfacePoint3.js";
9
9
  import Vector3 from "../../../src/core/geom/Vector3.js";
10
10
  import { Transform } from "../../../src/engine/ecs/transform/Transform.js";
@@ -2,7 +2,7 @@ import { Light } from "../../../src/engine/graphics/ecs/light/Light.js";
2
2
  import { DirectionalLightHelper, PointLightHelper, SpotLightHelper } from "three";
3
3
  import { make3DSymbolicDisplay } from "./make3DSymbolicDisplay.js";
4
4
  import { buildThreeJSHelperEntity } from "./buildThreeJSHelperEntity.js";
5
- import Renderable from "../../../src/engine/ecs/components/Renderable.js";
5
+ import Renderable from "../../../src/engine/ecs/renderable/Renderable.js";
6
6
  import { Transform } from "../../../src/engine/ecs/transform/Transform.js";
7
7
 
8
8
  /**
@@ -1,7 +1,7 @@
1
1
  import { BufferGeometry, Float32BufferAttribute, Group, Line, LineBasicMaterial } from "three";
2
2
  import Vector3 from "../../../src/core/geom/Vector3.js";
3
3
  import { min2 } from "../../../src/core/math/min2.js";
4
- import Renderable from "../../../src/engine/ecs/components/Renderable.js";
4
+ import Renderable from "../../../src/engine/ecs/renderable/Renderable.js";
5
5
  import { buildThreeJSHelperEntity } from "./buildThreeJSHelperEntity.js";
6
6
  import { make3DSymbolicDisplay } from "./make3DSymbolicDisplay.js";
7
7
  import Path from "../../../src/engine/navigation/ecs/components/Path.js";
@@ -2,7 +2,7 @@ import { assert } from "../../../src/core/assert.js";
2
2
  import { Sprite, SpriteMaterial } from "three";
3
3
  import { make3DSymbolicDisplay } from "./make3DSymbolicDisplay.js";
4
4
  import EntityBuilder from "../../../src/engine/ecs/EntityBuilder.js";
5
- import Renderable from "../../../src/engine/ecs/components/Renderable.js";
5
+ import Renderable from "../../../src/engine/ecs/renderable/Renderable.js";
6
6
  import { Transform } from "../../../src/engine/ecs/transform/Transform.js";
7
7
  import { synchronizeTransform } from "./synchronizeTransform.js";
8
8
 
@@ -4,7 +4,7 @@ import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
4
4
  import DatGuiController from "./DatGuiController.js";
5
5
  import convertSampler2D2Canvas from "../../../../src/engine/graphics/texture/sampler/Sampler2D2Canvas.js";
6
6
  import { Sampler2D } from "../../../../src/engine/graphics/texture/sampler/Sampler2D.js";
7
- import { scaleSampler2D } from "../../../../src/engine/graphics/texture/sampler/scaleSampler2D.js";
7
+ import { sampler2d_scale } from "../../../../src/engine/graphics/texture/sampler/resize/sampler2d_scale.js";
8
8
  import Vector2 from "../../../../src/core/geom/Vector2.js";
9
9
 
10
10
  /**
@@ -17,7 +17,7 @@ export function buildGridObstaclePreview(grid, canvas) {
17
17
 
18
18
  const target = Sampler2D.uint8(1, canvas.width, canvas.height);
19
19
 
20
- scaleSampler2D(source, target);
20
+ sampler2d_scale(source, target);
21
21
 
22
22
  convertSampler2D2Canvas(target, 255, 0, canvas);
23
23
  }
@@ -7,7 +7,7 @@ import CheckersTextureURI from "../../../../src/engine/graphics/texture/Checkers
7
7
  import EmptyView from "../../../../src/view/elements/EmptyView.js";
8
8
  import convertSampler2D2Canvas from "../../../../src/engine/graphics/texture/sampler/Sampler2D2Canvas.js";
9
9
  import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
10
- import { scaleSampler2D } from "../../../../src/engine/graphics/texture/sampler/scaleSampler2D.js";
10
+ import { sampler2d_scale } from "../../../../src/engine/graphics/texture/sampler/resize/sampler2d_scale.js";
11
11
  import { Sampler2D } from "../../../../src/engine/graphics/texture/sampler/Sampler2D.js";
12
12
  import Signal from "../../../../src/core/events/signal/Signal.js";
13
13
  import Vector2Control from "../../../../src/view/controller/controls/Vector2Control.js";
@@ -93,7 +93,7 @@ class LayersController extends View {
93
93
 
94
94
  function update() {
95
95
 
96
- scaleSampler2D(layer.diffuse, t);
96
+ sampler2d_scale(layer.diffuse, t);
97
97
 
98
98
  convertSampler2D2Canvas(t, 1, 0, vCanvas.el);
99
99
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.50.3",
8
+ "version": "2.51.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -11,7 +11,7 @@ import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.j
11
11
  import { Cache } from "../../src/core/cache/Cache.js";
12
12
  import { computeStringHash } from "../../src/core/primitives/strings/computeStringHash.js";
13
13
  import { noop, strictEquals } from "../../src/core/function/Functions.js";
14
- import { scaleSampler2D } from "../../src/engine/graphics/texture/sampler/scaleSampler2D.js";
14
+ import { sampler2d_scale } from "../../src/engine/graphics/texture/sampler/resize/sampler2d_scale.js";
15
15
  import { Sampler2D } from "../../src/engine/graphics/texture/sampler/Sampler2D.js";
16
16
  import { BinaryDataType } from "../../src/core/binary/type/BinaryDataType.js";
17
17
  import {
@@ -205,7 +205,7 @@ function makeTerrainEditor(root, terrain, engine) {
205
205
 
206
206
  const preview = Sampler2D.uint8(4, PREVIEW_SIZE, PREVIEW_SIZE);
207
207
 
208
- scaleSampler2D(source, preview);
208
+ sampler2d_scale(source, preview);
209
209
 
210
210
  PREVIEW_CACHE.put(url, preview);
211
211
 
@@ -0,0 +1,8 @@
1
+ import UUID from "./UUID.js";
2
+
3
+ test("valid string is produced", () => {
4
+ const id = UUID.generate();
5
+
6
+ expect(typeof id).toBe("string");
7
+ expect(id.trim().length).toBeGreaterThan(0);
8
+ });
@@ -11,6 +11,8 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
11
11
 
12
12
  remove_leaf(node: number): void
13
13
 
14
+ node_is_leaf(node: number): boolean
15
+
14
16
  collect_nodes_all(destination: ArrayLike<number>, destination_offset: number): void
15
17
 
16
18
  node_set_aabb_primitive(node_id: number, x0: number, y0: number, z0: number, x1: number, y1: number, z1: number): void
@@ -39,6 +41,8 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
39
41
 
40
42
  node_get_height(node: number): number
41
43
 
44
+ node_move_aabb(node: number, new_aabb: ArrayLike<number>): void
45
+
42
46
  swap_nodes(node_a_id: number, node_b_id: number): boolean
43
47
 
44
48
  release_all(): void
@@ -54,65 +54,67 @@ const INITIAL_CAPACITY = 128;
54
54
  /**
55
55
  * Bounding Volume Hierarchy implementation. Stores unsigned integer values at leaves, these are typically IDs or Index values.
56
56
  * Highly optimized both in terms of memory usage and CPU. Most of the code inlined. No allocation are performed during usage (except for growing the tree capacity).
57
- * RAM usage: 40 bytes per node. Compared with V8s per-object allocation size of 80 bytes (see https://blog.dashlane.com/how-is-data-stored-in-v8-js-engine-memory)
57
+ * RAM usage: 40 bytes per node. Compared with V8s per-object allocation size of 80 bytes
58
+ * @see https://blog.dashlane.com/how-is-data-stored-in-v8-js-engine-memory
59
+ * @class
58
60
  */
59
61
  export class ExplicitBinaryBoundingVolumeHierarchy {
60
- constructor() {
61
- /**
62
- *
63
- * @type {ArrayBuffer}
64
- * @private
65
- */
66
- this.__data_buffer = new ArrayBuffer(INITIAL_CAPACITY * ELEMENT_WORD_COUNT * 4);
67
-
68
- /**
69
- *
70
- * @type {Float32Array}
71
- * @private
72
- */
73
- this.__data_float32 = new Float32Array(this.__data_buffer);
74
-
75
- /**
76
- *
77
- * @type {Uint32Array}
78
- * @private
79
- */
80
- this.__data_uint32 = new Uint32Array(this.__data_buffer);
81
-
82
- /**
83
- * How many nodes are currently reserved, this will grow automatically through {@link #allocate_node} method usage
84
- * @type {number}
85
- * @private
86
- */
87
- this.__capacity = INITIAL_CAPACITY;
88
-
89
- /**
90
- * Number of used nodes. These are either live nodes, or node sitting in the {@link #__free} pool
91
- * @type {number}
92
- * @private
93
- */
94
- this.__size = 0;
95
62
 
96
- /**
97
- * Indices of released nodes. Nodes are pulled from here first if available, before the whole tree gets resized
98
- * @type {number[]}
99
- * @private
100
- */
101
- this.__free = [];
102
- /**
103
- * Pointer into __free array that's used as a stack, so this pointer represents top of the stack
104
- * @type {number}
105
- * @private
106
- */
107
- this.__free_pointer = 0;
63
+ /**
64
+ *
65
+ * @type {ArrayBuffer}
66
+ * @private
67
+ */
68
+ __data_buffer = new ArrayBuffer(INITIAL_CAPACITY * ELEMENT_WORD_COUNT * 4);
108
69
 
109
- /**
110
- * Root node of the hierarchy
111
- * @type {number}
112
- * @private
113
- */
114
- this.__root = NULL_NODE;
115
- }
70
+ /**
71
+ *
72
+ * @type {Float32Array}
73
+ * @private
74
+ */
75
+ __data_float32 = new Float32Array(this.__data_buffer);
76
+
77
+ /**
78
+ *
79
+ * @type {Uint32Array}
80
+ * @private
81
+ */
82
+ __data_uint32 = new Uint32Array(this.__data_buffer);
83
+
84
+ /**
85
+ * How many nodes are currently reserved, this will grow automatically through {@link #allocate_node} method usage
86
+ * @type {number}
87
+ * @private
88
+ */
89
+ __capacity = INITIAL_CAPACITY;
90
+
91
+ /**
92
+ * Number of used nodes. These are either live nodes, or node sitting in the {@link #__free} pool
93
+ * @type {number}
94
+ * @private
95
+ */
96
+ __size = 0;
97
+
98
+ /**
99
+ * Indices of released nodes. Nodes are pulled from here first if available, before the whole tree gets resized
100
+ * @type {number[]}
101
+ * @private
102
+ */
103
+ __free = [];
104
+
105
+ /**
106
+ * Pointer into __free array that's used as a stack, so this pointer represents top of the stack
107
+ * @type {number}
108
+ * @private
109
+ */
110
+ __free_pointer = 0;
111
+
112
+ /**
113
+ * Root node of the hierarchy
114
+ * @type {number}
115
+ * @private
116
+ */
117
+ __root = NULL_NODE;
116
118
 
117
119
  /**
118
120
  *
@@ -248,3 +248,57 @@ test("swap two detached nodes", () => {
248
248
  expect(bvh.node_get_user_data(a)).toBe(11);
249
249
  expect(bvh.node_get_user_data(b)).toBe(7);
250
250
  });
251
+
252
+ test("setting capacity", () => {
253
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
254
+
255
+ bvh.node_capacity = 3;
256
+
257
+ expect(bvh.node_capacity).toEqual(3);
258
+
259
+ bvh.node_capacity = 3;
260
+
261
+ expect(bvh.node_capacity).toEqual(3);
262
+
263
+ bvh.node_capacity = 0;
264
+
265
+ expect(bvh.node_capacity).toEqual(0);
266
+
267
+ bvh.allocate_node();
268
+
269
+ bvh.node_capacity = 3;
270
+
271
+ expect(bvh.node_capacity).toEqual(3);
272
+
273
+ bvh.node_capacity = 1;
274
+
275
+ expect(bvh.node_capacity).toEqual(1);
276
+
277
+ expect(() => bvh.node_capacity = 0).toThrow();
278
+ });
279
+
280
+ test("move leaf node", () => {
281
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
282
+
283
+ const a = bvh.allocate_node();
284
+ const b = bvh.allocate_node();
285
+
286
+ bvh.node_set_aabb(a, [-1.1, -1.2, -1.3, 2.1, 2.2, 2.3]);
287
+ bvh.node_set_aabb(b, [3.1, 3.2, 3.2, 5.1, 5.2, 5.2]);
288
+
289
+ bvh.insert_leaf(a);
290
+ bvh.insert_leaf(b);
291
+
292
+ // convert to float32 and back to account for rounding errors when checking results
293
+ const a_new_bounds = Array.from(new Float32Array([
294
+ 7.1, 7.2, 7.3,
295
+ 11.1, 11.2, 11.3
296
+ ]));
297
+
298
+ bvh.node_move_aabb(a, a_new_bounds);
299
+
300
+ const actual_bounds = [];
301
+ bvh.node_get_aabb(a, actual_bounds);
302
+
303
+ expect(actual_bounds).toEqual(a_new_bounds);
304
+ });
@@ -1,4 +1,4 @@
1
- import { AABB3 } from "../aabb3/AABB3.js";
1
+ import { AABB3 } from "../../geom/3d/aabb/AABB3.js";
2
2
  import { aabb3_from_v3_array } from "../../geom/3d/aabb/aabb3_from_v3_array.js";
3
3
  import morton from "../../geom/3d/morton/Morton.js";
4
4
  import { arrayQuickSort } from "../../collection/array/arrayQuickSort.js";
@@ -37,14 +37,14 @@ export function ebvh_build_for_geometry_morton(bvh, index_array, position_array)
37
37
  // allocate nodes
38
38
  const tri_count = index_array.length / 3;
39
39
  const node_leaf_count = tri_count;
40
- const node_bin_count = Math.ceil(node_leaf_count / 2) * 2 - 1;
40
+ const node_bin_count = max2(0, node_leaf_count - 1);
41
41
 
42
42
  const node_total_count = node_leaf_count + node_bin_count;
43
43
 
44
44
  const nodes = new Uint32Array(node_total_count);
45
45
 
46
46
  // skip allocation calls, allocate exactly as many nodes as we need
47
- bvh.__set_capacity(node_total_count);
47
+ bvh.node_capacity = node_total_count;
48
48
  bvh.__size = node_total_count;
49
49
 
50
50
  for (let i = 0; i < node_total_count; i++) {
@@ -0,0 +1,60 @@
1
+ import { ebvh_build_for_geometry_morton } from "./ebvh_build_for_geometry_morton.js";
2
+ import { ExplicitBinaryBoundingVolumeHierarchy, NULL_NODE } from "./ExplicitBinaryBoundingVolumeHierarchy.js";
3
+
4
+ test("sanity check with 1 triangle", () => {
5
+
6
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
7
+
8
+ ebvh_build_for_geometry_morton(bvh, [0, 1, 2], [
9
+ 0, 1, 3,
10
+ 13, 17, 19,
11
+ 5, 7, 11
12
+ ]);
13
+
14
+ expect(bvh.root).not.toEqual(NULL_NODE);
15
+
16
+ const actual_bounds = [];
17
+ bvh.node_get_aabb(bvh.root, actual_bounds);
18
+
19
+ expect(actual_bounds).toEqual(
20
+ Array.from(new Float32Array([
21
+ 0, 1, 3,
22
+ 13, 17, 19
23
+ ]))
24
+ );
25
+
26
+ // check that first and only node has out triangle index stored
27
+ expect(bvh.node_is_leaf(bvh.root)).toEqual(true);
28
+ expect(bvh.node_get_user_data(bvh.root)).toEqual(0);
29
+ });
30
+
31
+ test("sanity check with 2 triangles", () => {
32
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
33
+
34
+ ebvh_build_for_geometry_morton(
35
+ bvh,
36
+ [
37
+ 0, 0, 0,
38
+ 1, 1, 1
39
+ ],
40
+ [
41
+ 0, 1, 3,
42
+ 5, 7, 11
43
+ ]
44
+ );
45
+
46
+ expect(bvh.root).not.toEqual(NULL_NODE);
47
+
48
+ const actual_bounds = [];
49
+ bvh.node_get_aabb(bvh.root, actual_bounds);
50
+
51
+ expect(actual_bounds).toEqual(
52
+ Array.from(new Float32Array([
53
+ 0, 1, 3,
54
+ 5, 7, 11
55
+ ]))
56
+ );
57
+
58
+ // check that first and only node has out triangle index stored
59
+ expect(bvh.node_is_leaf(bvh.root)).toEqual(false);
60
+ });
@@ -1,4 +1,4 @@
1
- import { convertGraphToDotString } from "../../graph/convertGraphToDotString.js";
1
+ import { convert_graph_to_dot_string } from "../../graph/convert_graph_to_dot_string.js";
2
2
  import { bvh_traverse_pre_order_using_stack } from "../traversal/bvh_traverse_pre_order_using_stack.js";
3
3
  import { Graph } from "../../graph/v2/Graph.js";
4
4
  import { Edge, EdgeDirectionType } from "../../graph/Edge.js";
@@ -46,5 +46,5 @@ export function bvh_to_graph(bvh) {
46
46
  */
47
47
  export function convert_bvh_to_dot_format_string(bvh) {
48
48
  const graph = bvh_to_graph(bvh);
49
- return convertGraphToDotString({ graph: graph });
49
+ return convert_graph_to_dot_string({ graph: graph });
50
50
  }
@@ -5,9 +5,10 @@ import { returnOne, returnZero, strictEquals } from "../function/Functions.js";
5
5
  import { CacheElement } from "./CacheElement.js";
6
6
  import { collectIteratorValueToArray } from "../collection/collectIteratorValueToArray.js";
7
7
 
8
+ // TODO validate hashes of held elements to keep them up to date. Keys are assumed to be immutable, but this assumption may be broken by users
9
+
8
10
  /**
9
11
  * Hash-based cache, uses LRU (least-recently-used) eviction policy
10
- * TODO validate hashes of held elements to keep them up to date. Keys are assumed to be immutable, but this assumption may be broken by users
11
12
  * @template Key, Value
12
13
  * @extends Map<Key,Value>
13
14
  */
@@ -403,7 +404,7 @@ export class Cache {
403
404
  }
404
405
 
405
406
  /**
406
- * Remove without triggering {@link #removeListener}
407
+ * Remove without triggering {@link #onRemoved}
407
408
  * NOTE: please be sure you understand what you're doing when you use this method
408
409
  * @param {Key} key
409
410
  * @returns {boolean} true if element was removed, false otherwise
@@ -469,20 +470,17 @@ export class Cache {
469
470
  /**
470
471
  * Shortcut for "Map" class spec compliance
471
472
  * @readonly
472
- * @type {Cache.put}
473
473
  */
474
474
  Cache.prototype.set = Cache.prototype.put;
475
475
 
476
476
  /**
477
477
  * Shortcut for "Map" class spec compliance
478
478
  * @readonly
479
- * @type {Cache.remove}
480
479
  */
481
480
  Cache.prototype.delete = Cache.prototype.remove;
482
481
 
483
482
  /**
484
483
  * Shortcut for "Map" class spec compliance
485
484
  * @readonly
486
- * @type {Cache.contains}
487
485
  */
488
486
  Cache.prototype.has = Cache.prototype.contains;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Doubly-linked list implementation for key-value pairs
3
3
  * @template Key, Value
4
+ * @class
4
5
  */
5
6
  export class CacheElement {
6
7
  /**
@@ -170,7 +170,17 @@ class PointQuadTree {
170
170
  this.br = undefined;
171
171
  }
172
172
 
173
+ /**
174
+ *
175
+ * @param {T} p
176
+ * @param {number} x
177
+ * @param {number} y
178
+ * @return {Element}
179
+ */
173
180
  insert(p, x, y) {
181
+ assert.isNumber(x, 'x');
182
+ assert.isNumber(y, 'y');
183
+
174
184
  const element = new Element(p, x, y);
175
185
 
176
186
  this.resizeToFit(x, y); //adjust size if needed
@@ -5,9 +5,9 @@ import { max2 } from "../../../math/max2.js";
5
5
 
6
6
  /**
7
7
  * Merge bounds of two axis-aligned bounding boxes, the result is a box that tightly bounds inputs
8
- * @param {ArrayLike<number>|number[]} result where resulting value is written to
9
- * @param {ArrayLike<number>|number[]} a
10
- * @param {ArrayLike<number>|number[]} b
8
+ * @param {ArrayLike<number>|number[]|Float32Array} result where resulting value is written to
9
+ * @param {ArrayLike<number>|number[]|Float32Array} a
10
+ * @param {ArrayLike<number>|number[]|Float32Array} b
11
11
  */
12
12
  export function aabb3_array_combine(result, a, b) {
13
13
  result[0] = min2(a[0], b[0]);
@@ -13,7 +13,7 @@ function defaultNodeToDot(node){
13
13
  * @param {function(Node):string} nodeToDot
14
14
  * @returns {string}
15
15
  */
16
- export function convertGraphToDotString({
16
+ export function convert_graph_to_dot_string({
17
17
  graph,
18
18
  nodeToDot=defaultNodeToDot
19
19
  }) {
@@ -0,0 +1,28 @@
1
+ import { convert_graph_to_dot_string } from "./convert_graph_to_dot_string.js";
2
+ import { Graph } from "./v2/Graph.js";
3
+ import { EdgeDirectionType } from "./Edge.js";
4
+
5
+ test("empty graph should produce valid string", () => {
6
+ const dot = convert_graph_to_dot_string({
7
+ graph: new Graph()
8
+ });
9
+
10
+ expect(typeof dot).toEqual("string");
11
+ expect(dot.trim().length).toBeGreaterThan(0);
12
+ });
13
+
14
+ test("graph with 2 nodes and an edge should produce valid string", () => {
15
+ const graph = new Graph();
16
+
17
+ graph.addNode(1);
18
+ graph.addNode(2);
19
+
20
+ graph.createEdge(1, 2, EdgeDirectionType.Forward);
21
+
22
+ const dot = convert_graph_to_dot_string({
23
+ graph: graph
24
+ });
25
+
26
+ expect(typeof dot).toEqual("string");
27
+ expect(dot.trim().length).toBeGreaterThan(0);
28
+ });