@woosh/meep-engine 2.31.6 → 2.31.10

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.
@@ -204,22 +204,23 @@ EntityManager.prototype.entityExists = function (entityIndex) {
204
204
  * @param {Number} entityId
205
205
  * @param {Class} componentClass
206
206
  * @param {function} callback
207
+ * @param {*} [thisArg]
207
208
  */
208
- EntityManager.prototype.getComponentAsync = function (entityId, componentClass, callback) {
209
+ EntityManager.prototype.getComponentAsync = function (entityId, componentClass, callback, thisArg) {
209
210
  const self = this;
210
211
  const component = this.getComponent(entityId, componentClass);
211
212
 
212
213
  function handler(options) {
213
214
  if (options.klass === componentClass) {
214
215
  self.removeEntityEventListener(entityId, EventType.ComponentAdded, handler);
215
- callback(options.instance);
216
+ callback.call(thisArg, options.instance);
216
217
  }
217
218
  }
218
219
 
219
220
  if (component === void 0 || component === null) {
220
221
  this.addEntityEventListener(entityId, EventType.ComponentAdded, handler);
221
222
  } else {
222
- callback(component);
223
+ callback.call(thisArg, component);
223
224
  }
224
225
  };
225
226
 
@@ -7,6 +7,9 @@ import { computeHashFloat, computeHashIntegerArray } from "../../../../core/math
7
7
  import { getSkeletonBoneByType } from "./SkeletonUtils.js";
8
8
  import { assert } from "../../../../core/assert.js";
9
9
  import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
10
+ import { Transform } from "../../../ecs/transform/Transform.js";
11
+ import { updateNodeByTransformAndBBB } from "./updateNodeByTransformAndBBB.js";
12
+ import { applyTransformToThreeObject } from "./applyTransformToThreeObject.js";
10
13
 
11
14
  /**
12
15
  *
@@ -27,6 +30,12 @@ const DEFAULT_FLAGS = 0;
27
30
  */
28
31
  const scratch_stack = [];
29
32
 
33
+ /**
34
+ * @readonly
35
+ * @type {Transform}
36
+ */
37
+ const scratch_transform = new Transform();
38
+
30
39
  class Mesh {
31
40
  constructor() {
32
41
  /**
@@ -63,7 +72,7 @@ class Mesh {
63
72
  * Managed by MeshSystem, do not change
64
73
  * @type {LeafNode}
65
74
  */
66
- this.bvh = new LeafNode(null, 0, 0, 0, 0, 0, 0);
75
+ this.bvh = new LeafNode(this, 0, 0, 0, 0, 0, 0);
67
76
 
68
77
  /**
69
78
  * Initialized to size 1x1x1
@@ -78,6 +87,52 @@ class Mesh {
78
87
  this.flags = DEFAULT_FLAGS;
79
88
  }
80
89
 
90
+ /**
91
+ *
92
+ * @param {Transform} transform
93
+ */
94
+ internalApplyTransform(transform) {
95
+ assert.equal(transform.isTransform, true, 'transform.isTransform! == true');
96
+
97
+ if (!this.hasMesh()) {
98
+ // not loaded, can't apply anything
99
+ return;
100
+ }
101
+
102
+ /**
103
+ * @type {Transform}
104
+ */
105
+ let _t;
106
+
107
+ const asset = this.asset;
108
+
109
+ if (asset.has_root_transform) {
110
+ _t = scratch_transform;
111
+
112
+ _t.multiplyTransforms(transform, asset.root_transform);
113
+
114
+ // console.log("root transform");
115
+ } else {
116
+ _t = transform;
117
+ }
118
+
119
+ /**
120
+ *
121
+ * @type {Object3D}
122
+ */
123
+ const m = this.mesh;
124
+
125
+ applyTransformToThreeObject(m, _t);
126
+
127
+ //set bvh
128
+ updateNodeByTransformAndBBB(this.bvh, this.boundingBox, _t);
129
+
130
+ // micron
131
+ if (this.micron_mesh !== null) {
132
+ applyTransformToThreeObject(this.micron_mesh, _t);
133
+ }
134
+ }
135
+
81
136
  /**
82
137
  *
83
138
  * @param {AABB3} destination
@@ -13,10 +13,9 @@ import { Transform } from "../../../ecs/transform/Transform.js";
13
13
  import checkerTexture from "../../texture/CheckersTexture.js";
14
14
 
15
15
  import ThreeFactory from "../../three/ThreeFactory.js";
16
- import { applyTransform } from "./applyTransform.js";
17
16
  import { assetTypeByPath } from "./assetTypeByPath.js";
18
17
  import Mesh, { MeshFlags } from "./Mesh.js";
19
- import { setMesh } from "./setMesh.js";
18
+ import { applyComponentPropertiesToThreeObject, setMesh } from "./setMesh.js";
20
19
  import { GLTFAssetLoader } from "../../../asset/loaders/GLTFAssetLoader.js";
21
20
  import { MeshEvents } from "./MeshEvents.js";
22
21
  import { MicronRenderPlugin } from "../../micron/plugin/MicronRenderPlugin.js";
@@ -103,15 +102,9 @@ export class MeshSystem extends System {
103
102
  */
104
103
  __set_mesh_from_asset(entity, dataset, asset, component) {
105
104
 
106
- let mesh;
107
105
 
108
- if (asset.micron !== undefined && this.__use_micron) {
109
- mesh = asset.micron.clone();
110
- } else {
111
- mesh = asset.create();
112
- }
106
+ const mesh = asset.create(); // remember the asset
113
107
 
114
- // remember the asset
115
108
  component.asset = asset;
116
109
 
117
110
  if (asset.boundingBox !== undefined) {
@@ -131,8 +124,16 @@ export class MeshSystem extends System {
131
124
 
132
125
  component.setFlag(MeshFlags.Loaded);
133
126
 
127
+ // micron
128
+ if (asset.micron !== undefined && this.__use_micron) {
129
+ component.micron_mesh = asset.micron.clone();
130
+
131
+ applyComponentPropertiesToThreeObject(component, component.micron_mesh, entity);
132
+ }
133
+
134
134
  setMesh(dataset, entity, component, mesh);
135
135
 
136
+
136
137
  // send event about asset being attached
137
138
  dataset.sendEvent(entity, MeshEvents.AssetLoaded);
138
139
  }
@@ -155,6 +156,23 @@ export class MeshSystem extends System {
155
156
  const graphics = this.graphics;
156
157
  this.renderLayer = graphics.layers.create("mesh-system");
157
158
 
159
+ const extractRenderable = (component) => {
160
+ if (this.__use_micron && component.micron_mesh !== null) {
161
+ // use micron mesh
162
+ return component.micron_mesh;
163
+ } else {
164
+ // use standard mesh
165
+ return component.mesh;
166
+ }
167
+ };
168
+
169
+ /**
170
+ *
171
+ * @param {Mesh} component
172
+ * @return {Object3D|null}
173
+ */
174
+ this.renderLayer.extractRenderable = extractRenderable;
175
+
158
176
  this.bvh = this.renderLayer.bvh;
159
177
 
160
178
  const visibleSet = this.renderLayer.visibleSet;
@@ -257,7 +275,7 @@ export class MeshSystem extends System {
257
275
  this.process(entity, model);
258
276
 
259
277
  function apply_transform() {
260
- applyTransform(model, transform);
278
+ model.internalApplyTransform(transform);
261
279
  }
262
280
 
263
281
  const bPosition = new SignalBinding(
@@ -407,11 +425,7 @@ export class MeshSystem extends System {
407
425
  }
408
426
  }
409
427
 
410
- em.getComponentAsync(entity, Transform, function (t) {
411
- if (component.hasMesh()) {
412
- applyTransform(component, t);
413
- }
414
- });
428
+ em.getComponentAsync(entity, Transform, component.internalApplyTransform, component);
415
429
  }
416
430
 
417
431
  update(timeDelta) {
@@ -0,0 +1,14 @@
1
+ import { rootObject3DFastMatrixUpdate } from "./rootObject3DFastMatrixUpdate.js";
2
+
3
+ /**
4
+ *
5
+ * @param {Object3D} m
6
+ * @param {Transform} t
7
+ */
8
+ export function applyTransformToThreeObject(m, t) {
9
+ m.position.copy(t.position);
10
+ t.rotation.__setThreeEuler(m.rotation);
11
+ m.scale.copy(t.scale);
12
+
13
+ rootObject3DFastMatrixUpdate(m);
14
+ }
@@ -1,46 +1,50 @@
1
1
  import { Transform } from "../../../ecs/transform/Transform.js";
2
- import { applyTransform } from "./applyTransform.js";
3
- import { setTransform } from "./setTransform.js";
4
2
  import { MeshEvents } from "./MeshEvents.js";
5
3
 
6
4
  /**
7
5
  *
8
- * @param {EntityComponentDataset} dataset
9
- * @param {number} entity
10
6
  * @param {Mesh} component
11
- * @param {Object3D} mesh
7
+ * @param {THREE.Object3D} mesh
8
+ * @param {number} entity
12
9
  */
13
- export function setMesh(dataset, entity, component, mesh) {
14
-
10
+ export function applyComponentPropertiesToThreeObject(component, mesh, entity) {
15
11
  mesh.traverse(o => {
16
12
  o.castShadow = component.castShadow;
17
13
  o.receiveShadow = component.receiveShadow;
18
14
  });
19
15
 
20
- let object = mesh;
21
-
22
16
  /*
23
17
  disable auto updates. We know when transform changes and thus we can avoid unnecessary matrix computations
24
18
  @see https://threejs.org/docs/index.html#api/core/Object3D.matrixWorldNeedsUpdate
25
19
  */
26
- object.matrixWorldNeedsUpdate = false;
20
+ mesh.matrixWorldNeedsUpdate = false;
27
21
 
28
22
  if (component.opacity === 0) {
29
- object.visible = false;
23
+ mesh.visible = false;
30
24
  }
31
25
 
32
- object.__meep_ecs_component = component;
33
- object.__meep_ecs_entity = entity;
26
+ mesh.__meep_ecs_component = component;
27
+ mesh.__meep_ecs_entity = entity;
28
+
29
+ }
34
30
 
35
- component.mesh = object;
36
- component.bvh.object = component.mesh;
31
+ /**
32
+ *
33
+ * @param {EntityComponentDataset} dataset
34
+ * @param {number} entity
35
+ * @param {Mesh} component
36
+ * @param {Object3D} mesh
37
+ */
38
+ export function setMesh(dataset, entity, component, mesh) {
39
+ applyComponentPropertiesToThreeObject(component, mesh, entity);
37
40
 
41
+ component.mesh = mesh;
38
42
 
39
43
  const transform = dataset.getComponent(entity, Transform);
40
44
 
41
45
  if (transform !== undefined) {
42
46
  // transform component found, apply transform
43
- applyTransform( component,transform);
47
+ component.internalApplyTransform(transform);
44
48
  }
45
49
 
46
50
  // scene.add(object);
@@ -259,6 +259,9 @@ export async function buildMicronGeometryFromBufferGeometry(input) {
259
259
  }
260
260
 
261
261
  const r = new MicronGeometry();
262
+
263
+ r.proxy = input; // TODO use r.buildProxy(1) instead
264
+
262
265
  r.source_triangle_count = index_attribute.count / 3;
263
266
  r.source_vertex_count = input.getAttribute('position').count;
264
267
  r.source_byte_size = compute_buffer_geometry_byte_size(input);
@@ -2,68 +2,9 @@ import { Graph } from "../../../../../core/graph/v2/Graph.js";
2
2
  import { MultiNode } from "./MultiNode.js";
3
3
  import { compute_face_connection_weight } from "../clustering/compute_face_connection_weight.js";
4
4
  import { WeightedEdge } from "./WeightedEdge.js";
5
+ import { graph_compute_disconnected_clusters } from "./graph_compute_disconnected_clusters.js";
5
6
 
6
7
 
7
- /**
8
- * @template T
9
- * @param {Graph<T>} graph
10
- * @returns {T[][]}
11
- */
12
- function graph_compute_disconnected_clusters(graph) {
13
-
14
- // discover disconnected clusters
15
- const unprocessed = new Set(graph.getNodes());
16
-
17
- /**
18
- *
19
- * @type {T[][]}
20
- */
21
- const clusters = [];
22
-
23
- while (unprocessed.size > 0) {
24
- /**
25
- *
26
- * @type {T[]}
27
- */
28
- const cluster = [];
29
-
30
- const next = unprocessed.values().next().value;
31
-
32
- const open = [next];
33
-
34
- while (open.length > 0) {
35
- const node = open.pop();
36
-
37
- unprocessed.delete(node);
38
- cluster.push(node);
39
-
40
- const container = graph.getNodeContainer(node);
41
-
42
- const edges = container.getEdges();
43
-
44
- const edge_count = edges.length;
45
-
46
- for (let i = 0; i < edge_count; i++) {
47
- const edge = edges[i];
48
-
49
- const neighbour = edge.other(node);
50
-
51
- if (!unprocessed.has(neighbour)) {
52
- continue;
53
- }
54
-
55
- unprocessed.delete(neighbour);
56
-
57
- open.push(neighbour);
58
- }
59
- }
60
-
61
- clusters.push(cluster);
62
- }
63
-
64
- return clusters;
65
- }
66
-
67
8
  /**
68
9
  * Given that the input graph is disconnected - makes it connected by adding very heavy edges between disconnected node clusters
69
10
  * If the graph is connected already - no change will be made
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @template T
3
+ * @param {Graph<T>} graph
4
+ * @returns {T[][]}
5
+ */
6
+ export function graph_compute_disconnected_clusters(graph) {
7
+
8
+ // discover disconnected clusters
9
+ const unprocessed = new Set(graph.getNodes());
10
+
11
+ /**
12
+ *
13
+ * @type {T[][]}
14
+ */
15
+ const clusters = [];
16
+
17
+ while (unprocessed.size > 0) {
18
+ /**
19
+ *
20
+ * @type {T[]}
21
+ */
22
+ const cluster = [];
23
+
24
+ const next = unprocessed.values().next().value;
25
+
26
+ const open = [next];
27
+
28
+ while (open.length > 0) {
29
+ const node = open.pop();
30
+
31
+ unprocessed.delete(node);
32
+ cluster.push(node);
33
+
34
+ const container = graph.getNodeContainer(node);
35
+
36
+ const edges = container.getEdges();
37
+
38
+ const edge_count = edges.length;
39
+
40
+ for (let i = 0; i < edge_count; i++) {
41
+ const edge = edges[i];
42
+
43
+ const neighbour = edge.other(node);
44
+
45
+ if (!unprocessed.has(neighbour)) {
46
+ continue;
47
+ }
48
+
49
+ unprocessed.delete(neighbour);
50
+
51
+ open.push(neighbour);
52
+ }
53
+ }
54
+
55
+ clusters.push(cluster);
56
+ }
57
+
58
+ return clusters;
59
+ }
@@ -0,0 +1,5 @@
1
+ import {BufferGeometry} from "three";
2
+
3
+ export class MicronGeometry {
4
+ public proxy: BufferGeometry
5
+ }
@@ -46,6 +46,36 @@ export class MicronGeometry {
46
46
  * @private
47
47
  */
48
48
  this.__patches = [];
49
+
50
+ /**
51
+ * Physical proxy geometry, useful for raycasting and other spatial queries
52
+ * @type {THREE.BufferGeometry|null}
53
+ * @private
54
+ */
55
+ this.__proxy = null;
56
+ }
57
+
58
+ /**
59
+ * @param {THREE.BufferGeometry} geometry
60
+ */
61
+ set proxy(geometry) {
62
+ this.__proxy = geometry;
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @return {THREE.BufferGeometry|null}
68
+ */
69
+ get proxy() {
70
+ return this.__proxy;
71
+ }
72
+
73
+ /**
74
+ * Build geometry proxy from the patches
75
+ * @param {number} percent percentage of the original geometry to keep
76
+ */
77
+ buildProxy(percent) {
78
+ throw new Error('Not Implemented');
49
79
  }
50
80
 
51
81
  computeByteSize() {
@@ -0,0 +1,10 @@
1
+ import {Material, Object3D} from "three";
2
+ import {MicronGeometry} from "./MicronGeometry";
3
+
4
+ export class ThreeMicronMesh extends Object3D {
5
+ readonly instance_id: number
6
+ material: Material
7
+ geometry: MicronGeometry
8
+
9
+ readonly isMicronMesh: boolean
10
+ }
@@ -0,0 +1 @@
1
+ export const VIRTUAL_MESH_FLAG: string
@@ -0,0 +1 @@
1
+ export const VIRTUAL_MESH_FLAG = '@meep/is-virtual';
@@ -1,8 +1,10 @@
1
1
  import { ThreeInstancedAdapter } from "../instanced/ThreeInstancedAdapter.js";
2
2
  import { composeCompile } from "../../../material/composeCompile.js";
3
3
  import { Mesh, MeshDepthMaterial, MeshNormalMaterial, RGBADepthPacking } from "three";
4
+ import { VIRTUAL_MESH_FLAG } from "../VIRTUAL_MESH_FLAG.js";
4
5
 
5
6
  const MATERIAL_FLAG = '@micron_instanced_rewritten';
7
+ const MATERIAL_VERTEX_DISPLACED = '@meep/vertex-displaced';
6
8
 
7
9
  export class MaterialContext {
8
10
  /**
@@ -73,6 +75,7 @@ export class MaterialContext {
73
75
  if (material[MATERIAL_FLAG] === undefined) {
74
76
  material.onBeforeCompile = composeCompile(material.onBeforeCompile, rewrite_material);
75
77
  material[MATERIAL_FLAG] = true;
78
+ material[MATERIAL_VERTEX_DISPLACED] = true;
76
79
  } else {
77
80
  throw new Error(`Material was already processed by micron, this is an illegal state`);
78
81
  }
@@ -82,6 +85,8 @@ export class MaterialContext {
82
85
 
83
86
  const m = new Mesh();
84
87
 
88
+ m[VIRTUAL_MESH_FLAG] = true;
89
+
85
90
  m.name = 'Materialized Micron Mesh';
86
91
 
87
92
  m.geometry = null;
@@ -59,11 +59,20 @@ class VisibleLeafCollector extends BVHVisitor {
59
59
 
60
60
  const object = leaf.object;
61
61
 
62
- if (object !== null) {
63
- this.count++;
64
- const renderable = this.reader(object);
65
- this.callback.call(this.callbackContext, renderable, leaf);
62
+ if (object === null) {
63
+ // no payload on the BVH leaf
64
+ return;
66
65
  }
66
+
67
+ const renderable = this.reader(object);
68
+
69
+ if (renderable === null) {
70
+ // no renderable on the payload
71
+ return;
72
+ }
73
+
74
+ this.count++;
75
+ this.callback.call(this.callbackContext, renderable, leaf);
67
76
  }
68
77
  }
69
78
 
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "productName": "Meep",
5
5
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
6
6
  "author": "Alexander Goldring",
7
- "version": "2.31.6",
7
+ "version": "2.31.10",
8
8
  "dependencies": {
9
9
  "fast-levenshtein": "2.0.6",
10
10
  "opentype.js": "1.3.3",
@@ -1,39 +0,0 @@
1
- import { Transform } from "../../../ecs/transform/Transform.js";
2
- import { setTransform } from "./setTransform.js";
3
-
4
- /**
5
- * @readonly
6
- * @type {Transform}
7
- */
8
- const scratch_transform = new Transform();
9
-
10
- /**
11
- *
12
- * @param {Mesh} component
13
- * @param {Transform} transform
14
- */
15
- export function applyTransform(component, transform) {
16
- if (!component.hasMesh()) {
17
- // not loaded, can't apply anything
18
- return;
19
- }
20
-
21
- /**
22
- * @type {Transform}
23
- */
24
- let _t;
25
-
26
- const asset = component.asset;
27
-
28
- if (asset.has_root_transform) {
29
- _t = scratch_transform;
30
-
31
- _t.multiplyTransforms(transform, asset.root_transform);
32
-
33
- // console.log("root transform");
34
- } else {
35
- _t = transform;
36
- }
37
-
38
- setTransform(_t, component);
39
- }
@@ -1,47 +0,0 @@
1
- import { MeshFlags } from "./Mesh.js";
2
- import { MeshEvents } from "./MeshEvents.js";
3
- import { setMesh } from "./setMesh.js";
4
-
5
- /**
6
- *
7
- * @param {number} entity
8
- * @param {EntityComponentDataset} dataset
9
- * @param {Asset} asset
10
- * @param {Mesh} component
11
- */
12
- export function setMeshFromAsset(entity, dataset, asset, component) {
13
-
14
- let mesh;
15
-
16
- if (asset.micron !== undefined) {
17
- mesh = asset.micron.clone();
18
- } else {
19
- mesh = asset.create();
20
- }
21
-
22
- // remember the asset
23
- component.asset = asset;
24
-
25
- if (asset.boundingBox !== undefined) {
26
- component.boundingBox.copy(asset.boundingBox);
27
- } else if (mesh.isMesh) {
28
- const geometry = mesh.geometry;
29
- const bb = geometry.boundingBox;
30
- component.boundingBox.setBounds(
31
- bb.min.x,
32
- bb.min.y,
33
- bb.min.z,
34
- bb.max.x,
35
- bb.max.y,
36
- bb.max.z
37
- );
38
- }
39
-
40
- component.setFlag(MeshFlags.Loaded);
41
-
42
- setMesh(dataset, entity, component, mesh);
43
-
44
- // send event about asset being attached
45
- dataset.sendEvent(entity, MeshEvents.AssetLoaded);
46
-
47
- }
@@ -1,30 +0,0 @@
1
- import { updateMeshTransform } from "./updateMeshTransform.js";
2
- import { updateNodeByTransformAndBBB } from "./updateNodeByTransformAndBBB.js";
3
-
4
- /**
5
- *
6
- * @param {Transform} t
7
- * @param {Mesh} component
8
- */
9
- export function setTransform(t, component) {
10
- /**
11
- *
12
- * @type {Object3D}
13
- */
14
- const m = component.mesh;
15
-
16
- /**
17
- *
18
- * @type {Vector3}
19
- */
20
- const position = t.position;
21
-
22
- m.position.copy(position);
23
- t.rotation.__setThreeEuler(m.rotation);
24
- m.scale.copy(t.scale);
25
-
26
- updateMeshTransform(component);
27
-
28
- //set bvh
29
- updateNodeByTransformAndBBB(component.bvh, component.boundingBox, t);
30
- }