@woosh/meep-engine 2.34.35 → 2.34.39

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/binary/BitSet.js +5 -0
  2. package/core/bvh2/BinaryNode.js +873 -1017
  3. package/core/bvh2/LeafNode.js +82 -75
  4. package/core/bvh2/Node.js +112 -114
  5. package/core/bvh2/aabb3/AABB3.js +46 -1
  6. package/core/bvh2/aabb3/AABB3.spec.js +27 -1
  7. package/core/bvh2/aabb3/aabb3_from_v3_array.js +34 -0
  8. package/core/bvh2/aabb3/aabb3_from_v3_array_transformed.js +39 -0
  9. package/core/bvh2/aabb3/aabb3_intersects_frustum_degree.js +46 -0
  10. package/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +16 -35
  11. package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +52 -0
  12. package/core/geom/3d/aabb/aabb3_computeDistanceAbovePlane.js +1 -1
  13. package/core/geom/3d/aabb/aabb3_matrix4_project.js +3 -4
  14. package/core/geom/3d/aabb/aabb3_matrix4_project.spec.js +13 -0
  15. package/core/geom/3d/triangle/computeTriangleRayIntersection.js +1 -2
  16. package/core/geom/Quaternion.d.ts +2 -0
  17. package/core/geom/Vector3.js +22 -11
  18. package/engine/ecs/attachment/TransformAttachmentBinding.js +0 -1
  19. package/engine/ecs/foliage/FoliageVisibilitySetBuilder.js +1 -31
  20. package/engine/ecs/foliage/InstancedFoliage.js +85 -152
  21. package/engine/ecs/foliage/ViewState.js +165 -0
  22. package/engine/ecs/foliage/ecs/Foliage2System.js +82 -19
  23. package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +30 -0
  24. package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +16 -0
  25. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -2
  26. package/engine/ecs/parent/EntityNode.js +31 -49
  27. package/engine/ecs/transform-attachment/TransformAttachment.js +88 -0
  28. package/engine/ecs/transform-attachment/TransformAttachmentSystem.js +59 -0
  29. package/engine/graphics/GraphicsEngine.js +23 -2
  30. package/engine/graphics/ecs/camera/Camera.js +33 -16
  31. package/engine/graphics/ecs/camera/unprojectPoint.js +14 -0
  32. package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +22 -17
  33. package/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +21 -21
  34. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +9 -1
  35. package/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +4 -1
  36. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +32 -8
  37. package/engine/graphics/ecs/water2/shader/AlexWaterShader.js +7 -1
  38. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +18 -12
  39. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +1 -34
  40. package/engine/graphics/micron/build/fill_patch_geometry_data.js +12 -0
  41. package/engine/graphics/micron/format/MicronGeometry.js +21 -0
  42. package/engine/graphics/micron/format/MicronGeometryPatch.js +0 -7
  43. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +0 -3
  44. package/engine/graphics/micron/prototypeVirtualGeometry.js +69 -1
  45. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +5 -1
  46. package/engine/graphics/render/layers/RenderLayer.js +22 -85
  47. package/engine/graphics/render/visibility/VisibilityComputer.js +23 -103
  48. package/package.json +1 -1
  49. package/samples/terrain/editor.js +0 -1
@@ -0,0 +1,165 @@
1
+ import { BitSet } from "../../../core/binary/BitSet.js";
2
+ import { InstancedMeshGroup } from "../../graphics/geometry/instancing/InstancedMeshGroup.js";
3
+ import { queryBinaryNode_FrustumIntersections_Data } from "../../../core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js";
4
+ import Quaternion from "../../../core/geom/Quaternion.js";
5
+
6
+ /**
7
+ *
8
+ * @type {number[]}
9
+ */
10
+ const scratch_array = [];
11
+
12
+ export class ViewState {
13
+ constructor() {
14
+ /**
15
+ *
16
+ * @type {CameraView|null}
17
+ * @private
18
+ */
19
+ this.__view = null;
20
+
21
+ this.__visible_set = new BitSet();
22
+
23
+ //prevent re-allocation
24
+ this.__visible_set.preventShrink();
25
+
26
+ /**
27
+ *
28
+ * @type {InstancedMeshGroup}
29
+ */
30
+ this.instances = new InstancedMeshGroup();
31
+
32
+ /**
33
+ *
34
+ * @type {number[]}
35
+ * @private
36
+ */
37
+ this.__garbage = [];
38
+ /**
39
+ *
40
+ * @type {number}
41
+ * @private
42
+ */
43
+ this.__garbagePointer = 0;
44
+ }
45
+
46
+ dispose() {
47
+ this.instances.dispose();
48
+ }
49
+
50
+ __compute_visibility_update() {
51
+ const instances = this.instances;
52
+
53
+ const indices = instances.indices;
54
+
55
+ const index_count = indices.length;
56
+
57
+ /**
58
+ *
59
+ * @type {BitSet}
60
+ */
61
+ const visible_set = this.__visible_set;
62
+
63
+ const garbage = this.__garbage;
64
+
65
+ for (let ref = 0; ref < index_count; ref++) {
66
+ const index = indices[ref];
67
+
68
+ if (index === undefined) {
69
+ // unoccupied
70
+ continue;
71
+ }
72
+
73
+ if (!visible_set.get(ref)) {
74
+ //no longer visible
75
+ garbage[this.__garbagePointer++] = ref;
76
+ } else {
77
+ //visible, and is already in the group, update the set
78
+ visible_set.set(ref, false);
79
+ }
80
+ }
81
+ }
82
+
83
+ __removeGarbage() {
84
+
85
+ const garbagePointer = this.__garbagePointer;
86
+ const instances = this.instances;
87
+
88
+
89
+ const garbage = this.__garbage;
90
+
91
+ for (let i = 0; i < garbagePointer; i++) {
92
+ const ref = garbage[i];
93
+ instances.remove(ref);
94
+ }
95
+
96
+ }
97
+
98
+ /**
99
+ *
100
+ * @param {BinaryNode<number>} bvh
101
+ * @param {RowFirstTable} data
102
+ */
103
+ update(bvh, data) {
104
+
105
+ const visible_instance_set = this.__visible_set;
106
+
107
+ const instances = this.instances;
108
+
109
+ // reset visible set
110
+ visible_instance_set.reset();
111
+
112
+ //reset garbage pointer
113
+ this.__garbagePointer = 0;
114
+
115
+
116
+ // collect visible instances
117
+ const collected_nodes = queryBinaryNode_FrustumIntersections_Data(scratch_array, 0, bvh, this.__view.frustum);
118
+
119
+ for (let i = 0; i < collected_nodes; i++) {
120
+ const instance_id = scratch_array[i];
121
+
122
+ // mark them as visible
123
+ visible_instance_set.set(instance_id, true);
124
+ }
125
+
126
+ //remove those that are no longer visible
127
+ this.__compute_visibility_update();
128
+
129
+ //cull instances that are no longer visible
130
+ this.__removeGarbage();
131
+
132
+ //process entities that have become newly visible
133
+ for (
134
+ let index = visible_instance_set.nextSetBit(0);
135
+ index !== -1;
136
+ index = visible_instance_set.nextSetBit(index + 1)
137
+ ) {
138
+ //read transform data for instance
139
+ data.getRow(index, rowData);
140
+
141
+ const positionX = rowData[0];
142
+ const positionY = rowData[1];
143
+ const positionZ = rowData[2];
144
+
145
+ const encodedRotation = rowData[3];
146
+
147
+
148
+ const scaleX = rowData[4];
149
+ const scaleY = rowData[5];
150
+ const scaleZ = rowData[6];
151
+
152
+ const i = instances.add(index);
153
+
154
+ tempQuaternion.decodeFromUint32(encodedRotation);
155
+
156
+ //apply instance transforms
157
+ instances.setPositionAt(i, positionX, positionY, positionZ);
158
+ instances.setRotationAt(i, tempQuaternion.x, tempQuaternion.y, tempQuaternion.z, tempQuaternion.w);
159
+ instances.setScaleAt(i, scaleX, scaleY, scaleZ);
160
+ }
161
+ }
162
+ }
163
+
164
+ const tempQuaternion = new Quaternion();
165
+ const rowData = [];
@@ -26,13 +26,8 @@ function cleanupLayer(layerData, renderLayer) {
26
26
  export function loadFoliageLayer(layer, assetManager) {
27
27
  const instancedFoliage = layer.data;
28
28
 
29
- /**
30
- * @type {THREE.Mesh}
31
- */
32
- const threeMesh = instancedFoliage.instances.mesh;
33
-
34
- threeMesh.castShadow = layer.castShadow.getValue();
35
- threeMesh.receiveShadow = layer.receiveShadow.getValue();
29
+ instancedFoliage.castShadow = layer.castShadow.getValue();
30
+ instancedFoliage.receiveShadow = layer.receiveShadow.getValue();
36
31
 
37
32
  const modelURL = layer.modelURL.getValue();
38
33
 
@@ -112,15 +107,24 @@ export class Foliage2System extends System {
112
107
  startup(entityManager, readyCallback, errorCallback) {
113
108
  this.entityManager = entityManager;
114
109
 
115
- this.renderLayer = this.graphics.layers.create('instanced-mesh-system');
116
- this.renderLayer.buildVisibleSet = (frustums, filters, visitObject, thisArg) => {
110
+ const graphics = this.graphics;
111
+
112
+ this.renderLayer = graphics.layers.create('instanced-mesh-system');
113
+
114
+ graphics.views.elements.forEach(this.__handle_view_added, this);
115
+
116
+ graphics.views.elements.on.added.add(this.__handle_view_added, this);
117
+ graphics.views.elements.on.removed.add(this.__handle_view_removed, this);
118
+
119
+ this.renderLayer.buildVisibleSet = (view, visitObject, thisArg) => {
117
120
  const data = this.data;
118
121
 
119
122
  for (let entity in data) {
120
123
 
121
124
  const layers = data[entity];
125
+ const layer_count = layers.length;
122
126
 
123
- for (let i = 0, numLayers = layers.length; i < numLayers; i++) {
127
+ for (let i = 0; i < layer_count; i++) {
124
128
  /**
125
129
  * @type {{instances:InstancedFoliage}}
126
130
  */
@@ -133,9 +137,9 @@ export class Foliage2System extends System {
133
137
  */
134
138
  const instances = layerData.instances;
135
139
 
136
- instances.update(frustums, filters);
140
+ const view_state = instances.update(view);
137
141
 
138
- const group = instances.instances;
142
+ const group = view_state.instances;
139
143
 
140
144
  if (group.getCount() <= 0) {
141
145
  //no visible instances, skip
@@ -153,9 +157,61 @@ export class Foliage2System extends System {
153
157
  readyCallback();
154
158
  }
155
159
 
160
+ /**
161
+ *
162
+ * @param {CameraView} view
163
+ * @private
164
+ */
165
+ __handle_view_added(view) {
166
+ const em = this.entityManager;
167
+
168
+ if (em === null) {
169
+ return;
170
+ }
171
+
172
+ const ecd = em.dataset;
173
+
174
+ if (ecd === null) {
175
+ return;
176
+ }
177
+
178
+ ecd.traverseComponents(InstancedMeshComponent, im => {
179
+ im.add_view(view);
180
+ });
181
+ }
182
+
183
+
184
+ /**
185
+ *
186
+ * @param {CameraView} view
187
+ * @private
188
+ */
189
+ __handle_view_removed(view) {
190
+
191
+ const em = this.entityManager;
192
+
193
+ if (em === null) {
194
+ return;
195
+ }
196
+
197
+ const ecd = em.dataset;
198
+
199
+ if (ecd === null) {
200
+ return;
201
+ }
202
+
203
+ ecd.traverseComponents(InstancedMeshComponent, im => {
204
+ im.remove_view(view);
205
+ });
206
+ }
207
+
156
208
  shutdown(entityManager, readyCallback, errorCallback) {
157
209
  this.graphics.layers.remove(this.renderLayer);
158
210
 
211
+ this.graphics.views.elements.forEach(this.__handle_view_removed, this);
212
+ this.graphics.views.elements.on.added.remove(this.__handle_view_added, this);
213
+ this.graphics.views.elements.on.removed.remove(this.__handle_view_removed, this);
214
+
159
215
  readyCallback();
160
216
  }
161
217
 
@@ -166,16 +222,16 @@ export class Foliage2System extends System {
166
222
 
167
223
  /**
168
224
  *
169
- * @param {InstancedMeshComponent} foliage
225
+ * @param {InstancedMeshComponent} instances
170
226
  * @param entity
171
227
  */
172
- link(foliage, entity) {
228
+ link(instances, entity) {
173
229
  const layers = [];
174
230
  const data = this.data;
175
231
 
176
232
  data[entity] = layers;
177
233
 
178
- const layerList = foliage.layers;
234
+ const layerList = instances.layers;
179
235
  const layer_count = layerList.length;
180
236
 
181
237
  for (let i = 0; i < layer_count; i++) {
@@ -215,11 +271,16 @@ export class Foliage2System extends System {
215
271
  }
216
272
  }
217
273
 
218
- //TODO need to expose InstancedMesh BVH to let camera frustum calculation work correctly
219
-
274
+ //
275
+ this.graphics.views.elements.forEach(instances.add_view, instances);
220
276
  }
221
277
 
222
- unlink(foliage, entity) {
278
+ /**
279
+ *
280
+ * @param {InstancedMeshComponent} instances
281
+ * @param {number} entity
282
+ */
283
+ unlink(instances, entity) {
223
284
  const renderLayer = this.renderLayer;
224
285
  const layers = this.data[entity];
225
286
 
@@ -230,7 +291,9 @@ export class Foliage2System extends System {
230
291
  cleanupLayer(layerData, renderLayer);
231
292
  }
232
293
 
233
- foliage.dispose();
294
+ this.graphics.views.elements.forEach(instances.remove_view, instances);
295
+
296
+ instances.dispose();
234
297
 
235
298
  delete this.data[entity];
236
299
  }
@@ -12,6 +12,36 @@ export class InstancedMeshComponent {
12
12
  this.layers = new List();
13
13
  }
14
14
 
15
+ /**
16
+ *
17
+ * @param {CameraView} view
18
+ */
19
+ add_view(view) {
20
+ const layers = this.layers;
21
+ const layer_count = layers.length;
22
+
23
+ for (let i = 0; i < layer_count; i++) {
24
+ const layer = layers.get(i);
25
+
26
+ layer.add_view(view);
27
+ }
28
+ }
29
+
30
+ /**
31
+ *
32
+ * @param {CameraView} view
33
+ */
34
+ remove_view(view) {
35
+ const layers = this.layers;
36
+ const layer_count = layers.length;
37
+
38
+ for (let i = 0; i < layer_count; i++) {
39
+ const layer = layers.get(i);
40
+
41
+ layer.remove_view(view);
42
+ }
43
+ }
44
+
15
45
  toJSON() {
16
46
  return this.layers.toJSON();
17
47
  }
@@ -36,6 +36,22 @@ export class InstancedMeshLayer {
36
36
  this.receiveShadow = new ObservedBoolean(false);
37
37
  }
38
38
 
39
+ /**
40
+ *
41
+ * @param {CameraView} view
42
+ */
43
+ add_view(view) {
44
+ this.data.add_view(view);
45
+ }
46
+
47
+ /**
48
+ *
49
+ * @param {CameraView} view
50
+ */
51
+ remove_view(view) {
52
+ this.data.remove_view(view);
53
+ }
54
+
39
55
  dispose() {
40
56
  this.data.dispose();
41
57
  }
@@ -223,8 +223,8 @@ export function optimizeIndividualMeshesEntitiesToInstances(dataset, threshold =
223
223
  layer.castShadow.set(true);
224
224
  layer.receiveShadow.set(true);
225
225
 
226
- instancedFoliage.instances.mesh.castShadow = layer.castShadow.getValue();
227
- instancedFoliage.instances.mesh.receiveShadow = layer.receiveShadow.getValue();
226
+ instancedFoliage.castShadow = layer.castShadow.getValue();
227
+ instancedFoliage.receiveShadow = layer.receiveShadow.getValue();
228
228
 
229
229
  foliage2.layers.add(layer);
230
230
 
@@ -3,10 +3,8 @@ import EntityBuilder from "../EntityBuilder.js";
3
3
  import { array_remove_first } from "../../../core/collection/array/array_remove_first.js";
4
4
  import { assert } from "../../../core/assert.js";
5
5
  import { array_push_if_unique } from "../../../core/collection/array/array_push_if_unique.js";
6
- import { Attachment } from "../attachment/Attachment.js";
7
- import { AttachmentSockets } from "../sockets/AttachmentSockets.js";
8
- import { AttachmentSocket } from "../sockets/AttachmentSocket.js";
9
6
  import { Transform } from "../transform/Transform.js";
7
+ import { TransformAttachment } from "../transform-attachment/TransformAttachment.js";
10
8
 
11
9
  export class EntityNode {
12
10
  /**
@@ -81,14 +79,15 @@ export class EntityNode {
81
79
  * @private
82
80
  */
83
81
  __safe_get_attachment() {
84
- let attachment = this.__entity.getComponent(Attachment);
82
+ const entity = this.__entity;
83
+
84
+ let attachment = entity.getComponent(TransformAttachment);
85
85
 
86
86
  if (attachment === null) {
87
- attachment = new Attachment();
88
- attachment.socket = "root";
87
+ attachment = new TransformAttachment();
89
88
  attachment.immediate = true;
90
89
 
91
- this.__entity.add(attachment);
90
+ entity.add(attachment);
92
91
  }
93
92
 
94
93
  return attachment;
@@ -114,43 +113,44 @@ export class EntityNode {
114
113
  * @param {EntityNode|null} node
115
114
  */
116
115
  set parent(node) {
116
+ this.__parent = node;
117
+
117
118
  // check if entity is built
118
- if (this.__entity.isBuilt) {
119
- // live re-wiring
120
- let parent_entity = this.__entity.removeComponent(ParentEntity);
121
- let attachment = this.__entity.removeComponent(Attachment);
119
+ if (!this.__entity.isBuilt) {
120
+ return;
121
+ }
122
122
 
123
- if (node !== null) {
123
+ let parent_entity = this.__entity.removeComponent(ParentEntity);
124
+ let attachment = this.__entity.removeComponent(TransformAttachment);
124
125
 
125
- // handle component ParentEntity
126
+ if (node !== null) {
126
127
 
127
- if (parent_entity === null) {
128
- parent_entity = new ParentEntity();
129
- }
128
+ // handle component ParentEntity
130
129
 
131
- const parent_entity_builder = node.entity;
130
+ if (parent_entity === null) {
131
+ parent_entity = new ParentEntity();
132
+ }
132
133
 
133
- if (!parent_entity_builder.isBuilt) {
134
- throw new Error('Parent entity is not built');
135
- }
134
+ const parent_entity_builder = node.entity;
136
135
 
137
- const parent_entity_id = parent_entity_builder.entity;
138
- parent_entity.entity = parent_entity_id;
136
+ if (!parent_entity_builder.isBuilt) {
137
+ throw new Error('Parent entity is not built');
138
+ }
139
139
 
140
- // add component back
141
- this.__entity.add(parent_entity);
140
+ const parent_entity_id = parent_entity_builder.entity;
141
+ parent_entity.entity = parent_entity_id;
142
142
 
143
+ // add component back
144
+ this.__entity.add(parent_entity);
143
145
 
144
- // handle component Attachment
145
- if (attachment === null) {
146
- attachment = this.__safe_get_attachment();
147
- }
148
146
 
149
- attachment.parent = parent_entity_id;
147
+ // handle component Attachment
148
+ if (attachment === null) {
149
+ attachment = this.__safe_get_attachment();
150
150
  }
151
- }
152
151
 
153
- this.__parent = node;
152
+ attachment.parent = parent_entity_id;
153
+ }
154
154
  }
155
155
 
156
156
  get entity() {
@@ -229,24 +229,6 @@ export class EntityNode {
229
229
  attachment.parent = parent_entity_id;
230
230
  }
231
231
 
232
- // ensure "root" socket exists for transform parenting
233
- /**
234
- *
235
- * @type {AttachmentSockets}
236
- */
237
- let sockets = this.__entity.getComponent(AttachmentSockets);
238
- if (sockets === null) {
239
- sockets = new AttachmentSockets();
240
- this.__entity.add(sockets);
241
- }
242
-
243
- if (sockets.get("root") === undefined) {
244
- const socket = new AttachmentSocket();
245
- socket.id = "root";
246
-
247
- sockets.add(socket);
248
- }
249
-
250
232
  this.__transform_sync_down();
251
233
  this.__transform.position.onChanged.add(this.__transform_sync_down, this);
252
234
  this.__transform.scale.onChanged.add(this.__transform_sync_down, this);
@@ -0,0 +1,88 @@
1
+ import { Transform } from "../transform/Transform.js";
2
+
3
+ export const TransformAttachmentFlags = {
4
+ /**
5
+ * Update will be performed when component is attached.
6
+ * It's used to turn this flag off when you know that the child's transform is already correct to save some computations
7
+ */
8
+ Immediate: 1
9
+ };
10
+
11
+ const DEFAULT_FLAGS = TransformAttachmentFlags.Immediate;
12
+
13
+ export class TransformAttachment {
14
+ constructor() {
15
+ /**
16
+ * transform relative to the attachment target
17
+ * @type {Transform}
18
+ */
19
+ this.transform = new Transform();
20
+
21
+ /**
22
+ * Which entity to attach to
23
+ * @type {number}
24
+ */
25
+ this.parent = -1;
26
+
27
+ /**
28
+ *
29
+ * @type {number}
30
+ */
31
+ this.flags = DEFAULT_FLAGS;
32
+ }
33
+
34
+ get immediate() {
35
+ return this.getFlag(TransformAttachmentFlags.Immediate);
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @param {boolean} v
41
+ */
42
+ set immediate(v) {
43
+ this.writeFlag(TransformAttachmentFlags.Immediate, v);
44
+ }
45
+
46
+ /**
47
+ *
48
+ * @param {number|TransformAttachmentFlags} flag
49
+ * @returns {void}
50
+ */
51
+ setFlag(flag) {
52
+ this.flags |= flag;
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @param {number|TransformAttachmentFlags} flag
58
+ * @returns {void}
59
+ */
60
+ clearFlag(flag) {
61
+ this.flags &= ~flag;
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @param {number|TransformAttachmentFlags} flag
67
+ * @param {boolean} value
68
+ */
69
+ writeFlag(flag, value) {
70
+ if (value) {
71
+ this.setFlag(flag);
72
+ } else {
73
+ this.clearFlag(flag);
74
+ }
75
+ }
76
+
77
+ /**
78
+ *
79
+ * @param {number|TransformAttachmentFlags} flag
80
+ * @returns {boolean}
81
+ */
82
+ getFlag(flag) {
83
+ return (this.flags & flag) === flag;
84
+ }
85
+
86
+ }
87
+
88
+ TransformAttachment.typeName = "TransformAttachment"
@@ -0,0 +1,59 @@
1
+ import { System } from "../System.js";
2
+ import { TransformAttachment, TransformAttachmentFlags } from "./TransformAttachment.js";
3
+ import { Transform } from "../transform/Transform.js";
4
+
5
+ /**
6
+ *
7
+ * @param {Transform} parent_transform
8
+ * @param {Transform} attachment_transform
9
+ * @param {Transform} child_transform
10
+ */
11
+ function update(parent_transform, attachment_transform, child_transform) {
12
+ child_transform.multiplyTransforms(parent_transform, attachment_transform);
13
+ }
14
+
15
+ export class TransformAttachmentSystem extends System {
16
+ constructor() {
17
+ super();
18
+
19
+ this.dependencies = [TransformAttachment, Transform];
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @param {TransformAttachment} attachment
25
+ * @param {Transform} transform
26
+ * @param {number} entity
27
+ */
28
+ __update_one(attachment, transform, entity) {
29
+
30
+ const em = this.entityManager;
31
+ const ecd = em.dataset;
32
+
33
+ const parent_transform = ecd.getComponent(attachment.parent, Transform);
34
+
35
+ update(parent_transform, attachment.transform, transform);
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @param {TransformAttachment} attachment
41
+ * @param {Transform} transform
42
+ * @param {number} entity
43
+ */
44
+ link(attachment, transform, entity) {
45
+ if ((attachment.flags & TransformAttachmentFlags.Immediate) !== 0) {
46
+ this.__update_one(attachment, transform, entity);
47
+ }
48
+ }
49
+
50
+ /**
51
+ *
52
+ * @param {TransformAttachment} attachment
53
+ * @param {Transform} transform
54
+ * @param {number} entity
55
+ */
56
+ unlink(attachment, transform, entity) {
57
+
58
+ }
59
+ }