@woosh/meep-engine 2.33.56 → 2.33.60

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 (49) hide show
  1. package/core/bvh2/aabb3/AABB3.js +4 -1
  2. package/core/bvh2/traversal/traverseBinaryNodeUsingVisitor.js +6 -6
  3. package/core/cache/Cache.js +7 -0
  4. package/core/collection/array/fastArrayEquals.js +17 -0
  5. package/core/collection/array/typed/is_typed_array_equals.js +58 -0
  6. package/core/collection/map/AbstractAsyncMap.js +30 -0
  7. package/core/collection/map/AsyncMapWrapper.js +16 -0
  8. package/core/collection/map/AsyncRemoteHashMap.js +358 -0
  9. package/core/collection/map/CachedAsyncMap.js +34 -0
  10. package/core/geom/Vector4.js +5 -5
  11. package/engine/animation/removeEntityGenericEffect.js +22 -31
  12. package/engine/asset/Asset.js +0 -45
  13. package/engine/asset/AssetDescription.js +51 -0
  14. package/engine/asset/AssetManager.d.ts +7 -0
  15. package/engine/asset/AssetManager.js +98 -2
  16. package/engine/asset/AssetTransformer.d.ts +5 -0
  17. package/engine/asset/AssetTransformer.js +15 -0
  18. package/engine/asset/loaders/GLTFAssetLoader.js +27 -25
  19. package/engine/asset/loaders/material/computeImageBitmapEquality.js +2 -2
  20. package/engine/asset/loaders/material/computeTextureEquality.js +2 -2
  21. package/engine/ecs/gui/GUIElement.js +0 -106
  22. package/engine/ecs/gui/GUIElementSerializationAdapter.js +108 -0
  23. package/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +60 -45
  24. package/engine/ecs/storage/binary/BinaryClassUpgrader.js +1 -0
  25. package/engine/ecs/util/removeComponentsExcept.js +3 -3
  26. package/engine/graphics/GraphicsEngine.js +3 -3
  27. package/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +0 -1
  28. package/engine/graphics/ecs/camera/topdown/TopDownCameraController.spec.js +8 -0
  29. package/engine/graphics/ecs/mesh/Mesh.js +5 -5
  30. package/engine/graphics/ecs/mesh/MeshSystem.js +12 -20
  31. package/engine/graphics/ecs/path/PathDisplaySystem.d.ts +3 -1
  32. package/engine/graphics/ecs/trail2d/Trail2D.js +35 -1
  33. package/engine/graphics/ecs/trail2d/Trail2DSystem.js +26 -19
  34. package/engine/graphics/ecs/trail2d/makeGradientTrail.js +68 -0
  35. package/engine/graphics/micron/convert_three_object_to_micron.js +24 -7
  36. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +107 -4
  37. package/engine/graphics/micron/plugin/serialization/BufferGeometrySerializationAdapter.js +176 -0
  38. package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.d.ts +2 -0
  39. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -2
  40. package/engine/graphics/render/buffer/simple-fx/DepthLimitedBlur.js +2 -2
  41. package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +1 -1
  42. package/engine/graphics/render/buffer/simple-fx/ao/SAOShader.js +9 -15
  43. package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +2 -0
  44. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +3 -1
  45. package/engine/graphics/shadows/ShadowMapRenderer.js +10 -4
  46. package/engine/graphics/texture/sampler/Sampler2D.js +24 -45
  47. package/engine/intelligence/behavior/ecs/WaitForEventBehavior.js +3 -0
  48. package/engine/save/storage/IndexedDBStorage.js +8 -1
  49. package/package.json +1 -1
@@ -6,23 +6,15 @@
6
6
  import { System } from '../../System.js';
7
7
  import HeadsUpDisplay from './HeadsUpDisplay.js';
8
8
  import { Transform } from '../../transform/Transform.js';
9
-
10
- import { Matrix4 } from 'three';
11
9
  import { GraphicsEngine } from "../../../graphics/GraphicsEngine.js";
12
10
  import { FogOfWarVisibilityPredicate } from "../../fow/FogOfWarVisibilityPredicate.js";
13
- import Vector4 from "../../../../core/geom/Vector4.js";
14
11
  import ViewportPosition from "../position/ViewportPosition.js";
15
12
  import GUIElement from "../GUIElement.js";
16
13
  import { HeadsUpDisplayFlag } from "./HeadsUpDisplayFlag.js";
14
+ import { mat4 } from "gl-matrix";
17
15
 
18
- /**
19
- *
20
- * @type {Vector4}
21
- */
22
- const v4 = new Vector4();
23
- const projectionMatrix = new Matrix4();
16
+ const projection = new Float32Array(16);
24
17
 
25
- const up = new Vector4();
26
18
 
27
19
  /**
28
20
  *
@@ -77,7 +69,7 @@ class HeadsUpDisplaySystem extends System {
77
69
  }
78
70
 
79
71
  /**
80
- *
72
+ * NOTE: for the sake of speed all of the matrix and vector multiplications have been inlined, readability of this method is pretty bad
81
73
  * @param {HeadsUpDisplay} hud
82
74
  * @param {Transform} transform
83
75
  * @param {ViewportPosition} vp
@@ -87,48 +79,69 @@ class HeadsUpDisplaySystem extends System {
87
79
  __apply_entity_transformation(hud, transform, vp, element) {
88
80
  const worldOffset = hud.worldOffset;
89
81
 
90
- let worldOffsetX = worldOffset.x;
91
- let worldOffsetY = worldOffset.y;
92
- let worldOffsetZ = worldOffset.z;
93
-
94
- v4.set(
95
- worldOffsetX,
96
- worldOffsetY,
97
- worldOffsetZ,
98
- 1
99
- );
82
+ let x = worldOffset.x;
83
+ let y = worldOffset.y;
84
+ let z = worldOffset.z;
100
85
 
101
86
  if (hud.getFlag(HeadsUpDisplayFlag.TransformWorldOffset)) {
102
87
  //apply scale and rotation
88
+ const transform_scale = transform.scale;
89
+
90
+ x *= transform_scale.x;
91
+ y *= transform_scale.y;
92
+ z *= transform_scale.y;
103
93
 
104
- v4.multiplyVector3(transform.scale);
94
+ const q = transform.rotation;
95
+
96
+ const qx = q.x;
97
+ const qy = q.y;
98
+ const qz = q.z;
99
+ const qw = q.w;
100
+
101
+ // calculate quat * vec
102
+ const ix = qw * x + qy * z - qz * y;
103
+ const iy = qw * y + qz * x - qx * z;
104
+ const iz = qw * z + qx * y - qy * x;
105
+ const iw = -qx * x - qy * y - qz * z;
106
+
107
+ // calculate result * inverse quat
108
+ x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
109
+ y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
110
+ z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
105
111
 
106
- v4.applyQuaternion(transform.rotation);
107
112
  }
108
113
 
114
+ // add transform position to get final world position
109
115
  const position = transform.position;
110
116
 
111
- v4.add3(position);
112
-
113
- const worldPositionX = v4.x;
114
- const worldPositionY = v4.y;
115
- const worldPositionZ = v4.z;
117
+ x += position.x;
118
+ y += position.y;
119
+ z += position.z;
116
120
 
121
+ const worldPositionX = x;
122
+ const worldPositionY = y;
123
+ const worldPositionZ = z;
117
124
 
118
125
  // Convert the [-1, 1] screen coordinate into a world coordinate on the near plane
119
- v4.threeApplyMatrix4(projectionMatrix);
120
126
 
121
- const d = 1 / Math.abs(v4.w);
122
- v4.x *= d;
123
- v4.y *= d;
124
- v4.z *= d;
127
+ // apply projection matrix
128
+ const _x = projection[0] * x + projection[4] * y + projection[8] * z + projection[12];
129
+ const _y = projection[1] * x + projection[5] * y + projection[9] * z + projection[13];
130
+ const _z = projection[2] * x + projection[6] * y + projection[10] * z + projection[14];
131
+ const _w = projection[3] * x + projection[7] * y + projection[11] * z + projection[15];
132
+
133
+ // apply perspective transform
134
+ const d = 1 / Math.abs(_w);
135
+ x = _x * d;
136
+ y = _y * d;
137
+ z = _z * d;
125
138
 
126
- const ndcX = (v4.x + 1) / 2;
127
- const ndcY = (1 - v4.y) / 2;
139
+ const ndcX = (x + 1) / 2;
140
+ const ndcY = (1 - y) / 2;
128
141
 
129
142
  vp.position.set(ndcX, ndcY);
130
143
 
131
- const trackedPositionOutOfBounds = v4.z > 1 || v4.z < -1;
144
+ const trackedPositionOutOfBounds = z > 1 || z < -1;
132
145
 
133
146
  const visible = (!trackedPositionOutOfBounds || vp.stickToScreenEdge) && this.__visibility_predicate.test(worldPositionX, worldPositionY, worldPositionZ);
134
147
 
@@ -141,18 +154,20 @@ class HeadsUpDisplaySystem extends System {
141
154
  if (hud.getFlag(HeadsUpDisplayFlag.PerspectiveRotation)) {
142
155
  //compute rotation in screen-space
143
156
 
144
- up.set(worldPositionX, worldPositionY + 1, worldPositionZ, 1);
145
- up.threeApplyMatrix4(projectionMatrix);
157
+ const w_y_1 = worldPositionY + 1;
158
+
159
+ const _up_x = projection[0] * worldPositionX + projection[4] * w_y_1 + projection[8] * worldPositionZ + projection[12];
160
+ const _up_y = projection[1] * worldPositionX + projection[5] * w_y_1 + projection[9] * worldPositionZ + projection[13];
161
+ const _up_w = projection[3] * worldPositionX + projection[7] * w_y_1 + projection[11] * worldPositionZ + projection[15];
146
162
 
147
163
  // compute perspective divide
148
- const d = 1 / Math.abs(up.w);
164
+ const d = 1 / Math.abs(_up_w);
149
165
 
150
- up.x *= d;
151
- up.y *= d;
152
- up.z *= d;
166
+ const up_x = _up_x * d;
167
+ const up_y = _up_y * d;
153
168
 
154
- const up_ndcX = (up.x + 1) / 2;
155
- const up_ndcY = (1 - up.y) / 2;
169
+ const up_ndcX = (up_x + 1) / 2;
170
+ const up_ndcY = (1 - up_y) / 2;
156
171
 
157
172
  const angle = Math.atan2(up_ndcY - ndcY, up_ndcX - ndcX);
158
173
 
@@ -176,7 +191,7 @@ class HeadsUpDisplaySystem extends System {
176
191
  */
177
192
  const camera = this.graphics.camera;
178
193
 
179
- projectionMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
194
+ mat4.multiply(projection, camera.projectionMatrix.elements, camera.matrixWorldInverse.elements);
180
195
 
181
196
  const visibilityPredicate = this.__visibility_predicate;
182
197
 
@@ -82,6 +82,7 @@ export class BinaryClassUpgrader {
82
82
  *
83
83
  * @param {BinaryBuffer} source
84
84
  * @param {BinaryBuffer} target
85
+ * @returns {void}
85
86
  */
86
87
  upgrade(source, target) {
87
88
  throw new Error('Not Implemented');
@@ -10,7 +10,7 @@ export function removeComponentsExcept(ecd, entity, whitelist) {
10
10
  const components = ecd.getAllComponents(entity);
11
11
  const component_count = components.length;
12
12
 
13
- for (let i = 0; i < component_count; i++) {
13
+ l0:for (let i = 0; i < component_count; i++) {
14
14
  const component = components[i];
15
15
 
16
16
  if (component === undefined) {
@@ -21,7 +21,7 @@ export function removeComponentsExcept(ecd, entity, whitelist) {
21
21
  for (let i = 0; i < exception_count; i++) {
22
22
  if (component instanceof whitelist[i]) {
23
23
  //keep
24
- continue;
24
+ continue l0;
25
25
  }
26
26
  }
27
27
 
@@ -29,4 +29,4 @@ export function removeComponentsExcept(ecd, entity, whitelist) {
29
29
  ecd.removeComponentFromEntityByIndex(entity, i);
30
30
  }
31
31
 
32
- }
32
+ }
@@ -35,7 +35,6 @@ import { MetricsCategory } from "../metrics/MetricsCategory.js";
35
35
  import Vector1 from "../../core/geom/Vector1.js";
36
36
  import { NormalFrameBuffer } from "./render/buffer/buffers/NormalFrameBuffer.js";
37
37
  import { MaterialManager } from "./material/manager/MaterialManager.js";
38
- import { CoalesceTextures } from "./material/manager/compilers/CoalesceTextures.js";
39
38
  import { ShadowMapRenderer } from "./shadows/ShadowMapRenderer.js";
40
39
  import { CameraViewManager } from "./render/view/CameraViewManager.js";
41
40
  import { StandardFrameBuffers } from "./StandardFrameBuffers.js";
@@ -91,14 +90,15 @@ function GraphicsEngine(camera, entityManger) {
91
90
  */
92
91
  this.__material_manager = new MaterialManager();
93
92
 
94
- this.__material_manager.addCompileStep(new CoalesceTextures());
93
+ // The line below would de-dupe textures, it is a rather slow process however
94
+ // this.__material_manager.addCompileStep(new CoalesceTextures());
95
95
 
96
96
  this.on = {
97
97
  preRender: new Signal(),
98
98
  postRender: new Signal(),
99
99
 
100
100
  preOpaquePass: new Signal(),
101
- postOpaquePass : new Signal(),
101
+ postOpaquePass: new Signal(),
102
102
 
103
103
  /**
104
104
  * @deprecated
@@ -11,7 +11,6 @@ import { PI2 } from "../../../../../core/math/MathUtils.js";
11
11
 
12
12
  const m4 = new Matrix4();
13
13
  const euler = new Euler();
14
- const scratch_vector3 = new Vector3();
15
14
 
16
15
  const panOffset = new Vector3();
17
16
 
@@ -3,6 +3,14 @@ import Vector3 from "../../../../../core/geom/Vector3.js";
3
3
  import { computeTopDownTransform } from "./TopDownCameraControllerSystem.js";
4
4
  import { Transform } from "../../../../ecs/transform/Transform.js";
5
5
 
6
+ test('setFromEyeAndTarget does not introduce roll when UP is aligned with +Y', () => {
7
+ const ut = new TopDownCameraController();
8
+
9
+ ut.setFromEyeAndTarget(new Vector3(0, 1, -1), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
10
+
11
+ expect(ut.roll).toBe(0);
12
+ });
13
+
6
14
  test('setFromEyeAndTarget results in roll respecting UP vector', () => {
7
15
  const eye = new Vector3();
8
16
  const target = new Vector3();
@@ -52,10 +52,10 @@ class Mesh {
52
52
  this.mesh = null;
53
53
 
54
54
  /**
55
- * Mesh with micron data, if available
55
+ * Override Mesh data, if available. Typically set via plugins
56
56
  * @type {Object3D|null}
57
57
  */
58
- this.micron_mesh = null;
58
+ this.override_mesh = null;
59
59
 
60
60
  /**
61
61
  * @transient
@@ -128,9 +128,9 @@ class Mesh {
128
128
  //set bvh
129
129
  updateNodeByTransformAndBBB(this.bvh, this.boundingBox, _t);
130
130
 
131
- // micron
132
- if (this.micron_mesh !== null) {
133
- applyTransformToThreeObject(this.micron_mesh, _t);
131
+ // override
132
+ if (this.override_mesh !== null) {
133
+ applyTransformToThreeObject(this.override_mesh, _t);
134
134
  }
135
135
  }
136
136
 
@@ -18,7 +18,6 @@ import Mesh, { MeshFlags } from "./Mesh.js";
18
18
  import { applyComponentPropertiesToThreeObject, setMesh } from "./setMesh.js";
19
19
  import { GLTFAssetLoader } from "../../../asset/loaders/GLTFAssetLoader.js";
20
20
  import { MeshEvents } from "./MeshEvents.js";
21
- import { MicronRenderPlugin } from "../../micron/plugin/MicronRenderPlugin.js";
22
21
  import { assert } from "../../../../core/assert.js";
23
22
 
24
23
  const placeholderGeometry = new BoxBufferGeometry(1, 1, 1);
@@ -86,13 +85,6 @@ export class MeshSystem extends System {
86
85
  * @type {BinaryNode}
87
86
  */
88
87
  this.bvh = null;
89
-
90
- /**
91
- *
92
- * @type {boolean}
93
- * @private
94
- */
95
- this.__use_micron = false;
96
88
  }
97
89
 
98
90
  /**
@@ -126,11 +118,11 @@ export class MeshSystem extends System {
126
118
 
127
119
  component.setFlag(MeshFlags.Loaded);
128
120
 
129
- // micron
130
- if (asset.micron !== undefined && this.__use_micron) {
131
- component.micron_mesh = asset.micron.clone();
121
+ // override
122
+ if (asset.override_mesh !== undefined ) {
123
+ component.override_mesh = asset.override_mesh.clone();
132
124
 
133
- applyComponentPropertiesToThreeObject(component, component.micron_mesh, entity);
125
+ applyComponentPropertiesToThreeObject(component, component.override_mesh, entity);
134
126
  }
135
127
 
136
128
  setMesh(dataset, entity, component, mesh);
@@ -141,11 +133,6 @@ export class MeshSystem extends System {
141
133
  }
142
134
 
143
135
  async startup(entityManager, readyCallback, errorCallback) {
144
- const engine = this.__engine;
145
-
146
- // is micron supported here?
147
- this.__use_micron = engine.plugins.getPlugin(MicronRenderPlugin) !== undefined;
148
-
149
136
  const am = this.assetManager;
150
137
 
151
138
  this.entityManager = entityManager;
@@ -158,10 +145,15 @@ export class MeshSystem extends System {
158
145
  const graphics = this.graphics;
159
146
  this.renderLayer = graphics.layers.create("mesh-system");
160
147
 
148
+ /**
149
+ *
150
+ * @param {Mesh} component
151
+ * @return {Object3D}
152
+ */
161
153
  const extractRenderable = (component) => {
162
- if (this.__use_micron && component.micron_mesh !== null) {
163
- // use micron mesh
164
- return component.micron_mesh;
154
+ if (component.override_mesh !== null) {
155
+ // use override mesh
156
+ return component.override_mesh;
165
157
  } else {
166
158
  // use standard mesh
167
159
  return component.mesh;
@@ -1,5 +1,7 @@
1
1
  import Engine from "../../../Engine";
2
+ import {System} from "../../../ecs/System";
3
+ import {PathDisplay} from "./PathDisplay";
2
4
 
3
- export class PathDisplaySystem {
5
+ export class PathDisplaySystem extends System<PathDisplay> {
4
6
  constructor(engine: Engine)
5
7
  }
@@ -6,6 +6,10 @@
6
6
  import Vector3 from "../../../../core/geom/Vector3.js";
7
7
  import Vector4 from "../../../../core/geom/Vector4.js";
8
8
  import { RibbonXMaterialSpec } from "../../trail/x/RibbonXMaterialSpec.js";
9
+ import { LeafNode } from "../../../../core/bvh2/LeafNode.js";
10
+ import { makeGradientTrail } from "./makeGradientTrail.js";
11
+ import { RibbonX } from "../../trail/x/RibbonX.js";
12
+ import ThreeFactory from "../../three/ThreeFactory.js";
9
13
 
10
14
  /**
11
15
  * @readonly
@@ -14,6 +18,7 @@ import { RibbonXMaterialSpec } from "../../trail/x/RibbonXMaterialSpec.js";
14
18
  export const Trail2DFlags = {
15
19
  Spawning: 1,
16
20
  Aging: 2,
21
+ Built: 4,
17
22
  };
18
23
 
19
24
  class Trail2D {
@@ -37,6 +42,12 @@ class Trail2D {
37
42
  */
38
43
  this.time = 0;
39
44
 
45
+ /**
46
+ *
47
+ * @type {number}
48
+ */
49
+ this.trailingIndex = 0;
50
+
40
51
  /**
41
52
  * Time elapsed since last update
42
53
  * @type {number}
@@ -72,7 +83,11 @@ class Trail2D {
72
83
  * transient
73
84
  * @type {LeafNode|null}
74
85
  */
75
- this.bvhLeaf = null;
86
+ this.bvhLeaf = new LeafNode(
87
+ this,
88
+ 0, 0, 0,
89
+ 0, 0, 0
90
+ );
76
91
 
77
92
  /**
78
93
  * @private
@@ -165,6 +180,21 @@ class Trail2D {
165
180
  }
166
181
  }
167
182
 
183
+ build(segment_count) {
184
+
185
+ const ribbon = new RibbonX();
186
+
187
+ ribbon.buildGeometry();
188
+ ribbon.setCount(segment_count);
189
+
190
+ const geometry = ribbon.getGeometry();
191
+
192
+ const mesh = ThreeFactory.createMesh(geometry, null);
193
+
194
+ this.ribbon = ribbon;
195
+ this.mesh = mesh;
196
+ }
197
+
168
198
  toJSON() {
169
199
  return {
170
200
  maxAge: this.maxAge,
@@ -187,10 +217,14 @@ class Trail2D {
187
217
  && this.offset.equals(other.offset)
188
218
  ;
189
219
  }
220
+
221
+
190
222
  }
191
223
 
192
224
  Trail2D.typeName = "Trail2D";
193
225
 
194
226
  Trail2D.serializable = false;
195
227
 
228
+ Trail2D.makeGradientTrail = makeGradientTrail;
229
+
196
230
  export default Trail2D;
@@ -10,9 +10,6 @@ import { Transform } from '../../../ecs/transform/Transform.js';
10
10
  import Vector3 from '../../../../core/geom/Vector3.js';
11
11
 
12
12
  import Trail2D, { Trail2DFlags } from './Trail2D.js';
13
-
14
- import { LeafNode } from '../../../../core/bvh2/LeafNode.js';
15
- import ThreeFactory from '../../three/ThreeFactory.js';
16
13
  import { GraphicsEngine } from "../../GraphicsEngine.js";
17
14
  import { RibbonXFixedPhysicsSimulator } from "../../trail/x/simulator/RibbonXFixedPhysicsSimulator.js";
18
15
  import { RibbonX } from "../../trail/x/RibbonX.js";
@@ -118,11 +115,11 @@ class Trail2DSystem extends System {
118
115
 
119
116
  /**
120
117
  *
121
- * @param {Transform} transform
122
118
  * @param {Trail2D} trail
123
- * @param {number} entityId
119
+ * @param {Transform} transform
120
+ * @private
124
121
  */
125
- link(trail, transform, entityId) {
122
+ __build_trail(trail, transform) {
126
123
  const segmentsPerSecond = 60;
127
124
  const maxSegments = 1000;
128
125
  //instantiation
@@ -130,24 +127,19 @@ class Trail2DSystem extends System {
130
127
  //make a mesh
131
128
  const segment_count = Math.ceil(clamp(trail.maxAge * segmentsPerSecond, 2, maxSegments));
132
129
 
133
- const ribbon = new RibbonX();
134
-
135
- ribbon.buildGeometry();
136
- ribbon.setCount(segment_count);
130
+ trail.build(segment_count);
137
131
 
138
-
139
- const geometry = ribbon.getGeometry();
132
+ const ribbon = trail.ribbon;
140
133
 
141
134
  const ribbons = this.__ribbon_plugin.getValue();
142
135
 
143
136
  const material = ribbons.obtain_material_x(trail.material);
144
137
 
145
- const mesh = ThreeFactory.createMesh(geometry, material);
138
+ trail.mesh.material = material;
146
139
 
147
140
  trail.time = 0;
148
141
  trail.trailingIndex = 0;
149
142
  trail.ribbon = ribbon;
150
- trail.mesh = mesh;
151
143
  trail.timeSinceLastUpdate = 0;
152
144
 
153
145
 
@@ -173,16 +165,31 @@ class Trail2DSystem extends System {
173
165
 
174
166
  }
175
167
 
176
- const leafNode = new LeafNode(
177
- trail,
178
-
168
+ trail.bvhLeaf.resize(
179
169
  position_x, position_y, position_z,
180
170
  position_x, position_y, position_z
181
171
  );
182
172
 
183
- trail.bvhLeaf = leafNode;
173
+ trail.setFlag(Trail2DFlags.Built);
174
+ }
175
+
176
+ /**
177
+ *
178
+ * @param {Transform} transform
179
+ * @param {Trail2D} trail
180
+ * @param {number} entityId
181
+ */
182
+ link(trail, transform, entityId) {
183
+ if (!trail.getFlag(Trail2DFlags.Built)) {
184
+ this.__build_trail(trail, transform);
185
+ } else {
186
+
187
+ const material = this.__ribbon_plugin.getValue().obtain_material_x(trail.material);
188
+ trail.mesh.material = material;
189
+ }
190
+
184
191
 
185
- this.bvh.insertNode(leafNode);
192
+ this.bvh.insertNode(trail.bvhLeaf);
186
193
  }
187
194
 
188
195
  /**
@@ -0,0 +1,68 @@
1
+ import Trail2D, { Trail2DFlags } from "./Trail2D.js";
2
+ import {
3
+ RIBBON_ATTRIBUTE_ADDRESS_AGE,
4
+ RIBBON_ATTRIBUTE_ADDRESS_COLOR,
5
+ RIBBON_ATTRIBUTE_ADDRESS_THICKNESS,
6
+ RIBBON_ATTRIBUTE_ADDRESS_UV_OFFSET
7
+ } from "../../trail/x/ribbon_attributes_spec.js";
8
+ import { assert } from "../../../../core/assert.js";
9
+
10
+ /**
11
+ *
12
+ * @param {number[]} color
13
+ * @param {number[]} thickness
14
+ * @param {number} [duration]
15
+ * @param {number} [scale]
16
+ * @param {number[]} position
17
+ * @param {number[]} ages
18
+ * @param {string} texture
19
+ * @returns {Trail2D}
20
+ */
21
+ export function makeGradientTrail({
22
+ color,
23
+ thickness,
24
+ position,
25
+ duration = 1,
26
+ scale = 1,
27
+ ages,
28
+ texture
29
+ }) {
30
+
31
+ const trail2D = new Trail2D();
32
+ trail2D.maxAge = duration;
33
+ trail2D.width = 1;
34
+ trail2D.textureURL = texture;
35
+
36
+ const point_count = thickness.length;
37
+
38
+ trail2D.build(point_count);
39
+
40
+ const ribbon = trail2D.ribbon;
41
+
42
+ for (let i = 0; i < point_count; i++) {
43
+
44
+ const f = i / (point_count - 1);
45
+ const i3 = i * 3;
46
+
47
+ ribbon.setPointAlpha(i, 0);
48
+ ribbon.setPointPosition(i, position[i3], position[i3 + 1], position[i3 + 2]);
49
+
50
+ ribbon.setPointAttribute_Scalar(i, RIBBON_ATTRIBUTE_ADDRESS_AGE, ages[i] * duration);
51
+ ribbon.setPointAttribute_Scalar(i, RIBBON_ATTRIBUTE_ADDRESS_UV_OFFSET, f);
52
+ ribbon.setPointAttribute_Scalar(i, RIBBON_ATTRIBUTE_ADDRESS_THICKNESS, thickness[i]);
53
+
54
+ const c_0 = color[i];
55
+
56
+ assert.isNumber(c_0, `color[i]`);
57
+
58
+ ribbon.setPointAttribute_Vector3(i, RIBBON_ATTRIBUTE_ADDRESS_COLOR, c_0 >> 16, c_0 >> 8, c_0);
59
+ }
60
+
61
+ // don't spawn more trail segments
62
+ trail2D.clearFlag(Trail2DFlags.Spawning);
63
+ trail2D.setFlag(Trail2DFlags.Built);
64
+
65
+ ribbon.computeBoundingBox(trail2D.bvhLeaf);
66
+
67
+ return trail2D;
68
+ }
@@ -3,12 +3,18 @@ import { computeGeometryHash } from "../../asset/loaders/geometry/geometry/compu
3
3
  import { computeGeometryEquality } from "../../asset/loaders/geometry/geometry/computeGeometryEquality.js";
4
4
  import { buildMicronGeometryFromBufferGeometry } from "./build/buildMicronGeometryFromBufferGeometry.js";
5
5
  import { ThreeMicronMesh } from "./format/ThreeMicronMesh.js";
6
+ import { AsyncMapWrapper } from "../../../core/collection/map/AsyncMapWrapper.js";
6
7
 
7
8
  /**
8
9
  *
9
10
  * @type {HashMap<THREE.BufferGeometry, MicronGeometry>}
10
11
  */
11
- const micron_cache = new HashMap({
12
+ const default_micron_cache = new AsyncMapWrapper(new HashMap({
13
+ keyHashFunction: computeGeometryHash,
14
+ keyEqualityFunction: computeGeometryEquality
15
+ }));
16
+
17
+ const pending_cache = new HashMap({
12
18
  keyHashFunction: computeGeometryHash,
13
19
  keyEqualityFunction: computeGeometryEquality
14
20
  });
@@ -17,9 +23,10 @@ const micron_cache = new HashMap({
17
23
  /**
18
24
  *
19
25
  * @param {THREE.Object3D} object
26
+ * @param {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>} micron_cache
20
27
  * @returns {THREE.Object3D}
21
28
  */
22
- export async function convert_three_object_to_micron(object) {
29
+ export async function convert_three_object_to_micron(object, micron_cache = default_micron_cache) {
23
30
 
24
31
  const promises = [];
25
32
 
@@ -29,19 +36,29 @@ export async function convert_three_object_to_micron(object) {
29
36
  * @returns {MicronGeometry}
30
37
  */
31
38
  async function obtain_geometry(g) {
32
- const existing = micron_cache.get(g);
39
+ const existing = await micron_cache.get(g);
40
+
41
+ if (existing !== undefined && existing !== null) {
42
+ return existing;
43
+ }
44
+
45
+ const pending = pending_cache.get(g);
33
46
 
34
- if (existing !== undefined) {
35
- return await existing;
47
+ if (pending !== undefined) {
48
+ return await pending;
36
49
  }
37
50
 
38
51
  const micron_geometry_promise = buildMicronGeometryFromBufferGeometry(g);
39
52
 
40
- micron_cache.set(g, micron_geometry_promise);
53
+ pending_cache.set(g, micron_geometry_promise);
41
54
 
42
55
  promises.push(micron_geometry_promise);
43
56
 
44
- return await micron_geometry_promise;
57
+ const micron_geometry = await micron_geometry_promise;
58
+
59
+ await micron_cache.set(g, micron_geometry);
60
+
61
+ return micron_geometry;
45
62
  }
46
63
 
47
64