@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.
- package/core/binary/BitSet.js +5 -0
- package/core/bvh2/BinaryNode.js +873 -1017
- package/core/bvh2/LeafNode.js +82 -75
- package/core/bvh2/Node.js +112 -114
- package/core/bvh2/aabb3/AABB3.js +46 -1
- package/core/bvh2/aabb3/AABB3.spec.js +27 -1
- package/core/bvh2/aabb3/aabb3_from_v3_array.js +34 -0
- package/core/bvh2/aabb3/aabb3_from_v3_array_transformed.js +39 -0
- package/core/bvh2/aabb3/aabb3_intersects_frustum_degree.js +46 -0
- package/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +16 -35
- package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +52 -0
- package/core/geom/3d/aabb/aabb3_computeDistanceAbovePlane.js +1 -1
- package/core/geom/3d/aabb/aabb3_matrix4_project.js +3 -4
- package/core/geom/3d/aabb/aabb3_matrix4_project.spec.js +13 -0
- package/core/geom/3d/triangle/computeTriangleRayIntersection.js +1 -2
- package/core/geom/Quaternion.d.ts +2 -0
- package/core/geom/Vector3.js +22 -11
- package/engine/ecs/attachment/TransformAttachmentBinding.js +0 -1
- package/engine/ecs/foliage/FoliageVisibilitySetBuilder.js +1 -31
- package/engine/ecs/foliage/InstancedFoliage.js +85 -152
- package/engine/ecs/foliage/ViewState.js +165 -0
- package/engine/ecs/foliage/ecs/Foliage2System.js +82 -19
- package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +30 -0
- package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +16 -0
- package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -2
- package/engine/ecs/parent/EntityNode.js +31 -49
- package/engine/ecs/transform-attachment/TransformAttachment.js +88 -0
- package/engine/ecs/transform-attachment/TransformAttachmentSystem.js +59 -0
- package/engine/graphics/GraphicsEngine.js +23 -2
- package/engine/graphics/ecs/camera/Camera.js +33 -16
- package/engine/graphics/ecs/camera/unprojectPoint.js +14 -0
- package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +22 -17
- package/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +21 -21
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +9 -1
- package/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +4 -1
- package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +32 -8
- package/engine/graphics/ecs/water2/shader/AlexWaterShader.js +7 -1
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +18 -12
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +1 -34
- package/engine/graphics/micron/build/fill_patch_geometry_data.js +12 -0
- package/engine/graphics/micron/format/MicronGeometry.js +21 -0
- package/engine/graphics/micron/format/MicronGeometryPatch.js +0 -7
- package/engine/graphics/micron/plugin/MicronRenderPlugin.js +0 -3
- package/engine/graphics/micron/prototypeVirtualGeometry.js +69 -1
- package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +5 -1
- package/engine/graphics/render/layers/RenderLayer.js +22 -85
- package/engine/graphics/render/visibility/VisibilityComputer.js +23 -103
- package/package.json +1 -1
- 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
|
-
|
|
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
|
-
|
|
116
|
-
|
|
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
|
|
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(
|
|
140
|
+
const view_state = instances.update(view);
|
|
137
141
|
|
|
138
|
-
const group =
|
|
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}
|
|
225
|
+
* @param {InstancedMeshComponent} instances
|
|
170
226
|
* @param entity
|
|
171
227
|
*/
|
|
172
|
-
link(
|
|
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 =
|
|
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
|
-
//
|
|
219
|
-
|
|
274
|
+
//
|
|
275
|
+
this.graphics.views.elements.forEach(instances.add_view, instances);
|
|
220
276
|
}
|
|
221
277
|
|
|
222
|
-
|
|
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
|
-
|
|
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.
|
|
227
|
-
instancedFoliage.
|
|
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
|
-
|
|
82
|
+
const entity = this.__entity;
|
|
83
|
+
|
|
84
|
+
let attachment = entity.getComponent(TransformAttachment);
|
|
85
85
|
|
|
86
86
|
if (attachment === null) {
|
|
87
|
-
attachment = new
|
|
88
|
-
attachment.socket = "root";
|
|
87
|
+
attachment = new TransformAttachment();
|
|
89
88
|
attachment.immediate = true;
|
|
90
89
|
|
|
91
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
let attachment = this.__entity.removeComponent(Attachment);
|
|
119
|
+
if (!this.__entity.isBuilt) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
let parent_entity = this.__entity.removeComponent(ParentEntity);
|
|
124
|
+
let attachment = this.__entity.removeComponent(TransformAttachment);
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
if (node !== null) {
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
parent_entity = new ParentEntity();
|
|
129
|
-
}
|
|
128
|
+
// handle component ParentEntity
|
|
130
129
|
|
|
131
|
-
|
|
130
|
+
if (parent_entity === null) {
|
|
131
|
+
parent_entity = new ParentEntity();
|
|
132
|
+
}
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
throw new Error('Parent entity is not built');
|
|
135
|
-
}
|
|
134
|
+
const parent_entity_builder = node.entity;
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
if (!parent_entity_builder.isBuilt) {
|
|
137
|
+
throw new Error('Parent entity is not built');
|
|
138
|
+
}
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
147
|
+
// handle component Attachment
|
|
148
|
+
if (attachment === null) {
|
|
149
|
+
attachment = this.__safe_get_attachment();
|
|
150
150
|
}
|
|
151
|
-
}
|
|
152
151
|
|
|
153
|
-
|
|
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
|
+
}
|