@woosh/meep-engine 2.84.9 → 2.84.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.
Files changed (31) hide show
  1. package/README.md +27 -13
  2. package/build/meep.cjs +185 -87
  3. package/build/meep.min.js +1 -1
  4. package/build/meep.module.js +185 -87
  5. package/editor/process/symbolic/makePositionedIconDisplaySymbol.js +2 -4
  6. package/editor/view/EditorView.js +48 -204
  7. package/editor/view/ecs/HierarchicalEntityListView.js +191 -0
  8. package/editor/view/ecs/HierarchicalEntityListView.module.scss +13 -0
  9. package/editor/view/prepareMeshLibrary.js +178 -0
  10. package/editor/view/v2/SplitView.js +104 -0
  11. package/editor/view/v2/ViewManagementSystem.js +0 -0
  12. package/editor/view/v2/prototypeEditor.js +127 -0
  13. package/package.json +1 -1
  14. package/src/core/cache/Cache.d.ts +2 -0
  15. package/src/core/cache/Cache.js +58 -8
  16. package/src/core/cache/Cache.spec.js +38 -0
  17. package/src/core/cache/CacheElement.js +6 -0
  18. package/src/core/cache/LoadingCache.js +25 -2
  19. package/src/core/cache/LoadingCache.spec.js +9 -6
  20. package/src/core/collection/array/arraySetSortingDiff.js +6 -6
  21. package/src/core/collection/table/RowFirstTable.js +364 -368
  22. package/src/core/geom/3d/plane/plane3_compute_ray_intersection.js +3 -1
  23. package/src/core/geom/3d/topology/simplify/prototypeMeshSimplification.js +7 -7
  24. package/src/engine/animation/curve/ecd_bind_animation_curve.js +9 -0
  25. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +8 -1
  26. package/src/engine/graphics/ecs/mesh-v2/aggregate/prototypeSGMesh.js +23 -19
  27. package/src/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +2 -2
  28. package/src/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +3 -1
  29. package/src/view/View.js +64 -95
  30. package/src/view/setElementTransform.js +20 -0
  31. package/src/view/setElementVisibility.js +15 -0
@@ -4,37 +4,26 @@
4
4
 
5
5
 
6
6
  import { passThrough } from "../../src/core/function/passThrough.js";
7
- import { SurfacePoint3 } from "../../src/core/geom/3d/SurfacePoint3.js";
8
- import Vector2 from "../../src/core/geom/Vector2.js";
9
- import Vector3 from "../../src/core/geom/Vector3.js";
10
7
  import { ProcessState } from "../../src/core/process/ProcessState.js";
11
- import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.js";
12
- import { Transform } from "../../src/engine/ecs/transform/Transform.js";
13
- import Mesh from "../../src/engine/graphics/ecs/mesh/Mesh.js";
14
- import { MeshEvents } from "../../src/engine/graphics/ecs/mesh/MeshEvents.js";
15
- import { make_ray_from_viewport_position } from "../../src/engine/graphics/make_ray_from_viewport_position.js";
16
8
  import LabelView from '../../src/view/common/LabelView.js';
17
9
  import ListView from "../../src/view/common/ListView.js";
18
10
  import VirtualListView from '../../src/view/common/VirtualListView.js';
19
11
  import dom from "../../src/view/DOM.js";
20
- import BottomLeftResizeHandleView from "../../src/view/elements/BottomLeftResizeHandleView.js";
12
+ import EmptyView from "../../src/view/elements/EmptyView.js";
21
13
 
22
14
  import SimpleWindow from '../../src/view/elements/SimpleWindow.js';
23
15
  import View from "../../src/view/View.js";
24
- import ComponentAddAction from "../actions/concrete/ComponentAddAction.js";
25
- import EntityCreateAction from "../actions/concrete/EntityCreateAction.js";
26
- import SelectionAddAction from "../actions/concrete/SelectionAddAction.js";
27
- import SelectionClearAction from "../actions/concrete/SelectionClearAction.js";
28
16
  import ComponentControlFactory from './ecs/ComponentControlFactory.js';
29
17
  import EntityEditorView from './ecs/EntityEditor.js';
30
18
 
31
19
  import EntityListView from './ecs/EntityList.js';
20
+ import { HierarchicalEntityListView } from "./ecs/HierarchicalEntityListView.js";
32
21
  import GridPickCoordinateView from "./GridPickCoordinateView.js";
33
- import MeshLibraryView from "./library/MeshLibraryView.js";
34
22
  import { makeEntityDecorators } from "./makeEntityDecorators.js";
35
23
  import ProcessView from "./process/ProcessView.js";
36
24
  import ToolSettingsView from "./tools/ToolSettingsView.js";
37
25
  import ToolView from './tools/ToolView.js';
26
+ import { SplitView } from "./v2/SplitView.js";
38
27
 
39
28
 
40
29
  class ViewManager extends View {
@@ -51,7 +40,13 @@ class ViewManager extends View {
51
40
  this.memory = {};
52
41
  }
53
42
 
54
- add(view, title) {
43
+ /**
44
+ *
45
+ * @param {View} view
46
+ * @param {string} [title]
47
+ * @returns {SimpleWindowView}
48
+ */
49
+ add(view, title = "") {
55
50
  const simpleWindow = new SimpleWindow(
56
51
  view,
57
52
  {
@@ -118,171 +113,11 @@ class ViewManager extends View {
118
113
  }
119
114
 
120
115
 
121
- /**
122
- *
123
- * @param {Editor} editor
124
- */
125
- function prepareMeshLibrary(editor) {
126
- let resolveEngine;
127
-
128
- const pEngine = new Promise(function (resolve, reject) {
129
- resolveEngine = resolve;
130
-
131
- });
132
-
133
- /**
134
- *
135
- * @type {Promise<GraphicsEngine>}
136
- */
137
- const pGraphicsEngine = pEngine.then(function (e) {
138
- return e.graphics;
139
- });
140
-
141
- const pRenderer = pGraphicsEngine.then(function (graphicsEngine) {
142
- return graphicsEngine.renderer;
143
- });
144
-
145
- const pAssetManager = pEngine.then(e => e.assetManager);
146
-
147
- const meshLibraryView = new MeshLibraryView(
148
- editor.meshLibrary,
149
- pAssetManager,
150
- pRenderer
151
- );
152
-
153
- function handleDropEvent(event) {
154
- event.stopPropagation();
155
- event.preventDefault();
156
-
157
- const dataText = event.dataTransfer.getData('text/json');
158
- if (dataText === "") {
159
- //no data
160
- return;
161
- }
162
-
163
- const data = JSON.parse(dataText);
164
-
165
- const type = data.type;
166
-
167
- if (type !== "Mesh") {
168
- //wrong type
169
- return;
170
- }
171
-
172
- const url = data.url;
173
-
174
- const engine = editor.engine;
175
- const graphics = engine.graphics;
176
-
177
- const position = new Vector2(event.clientX, event.clientY);
178
-
179
- graphics.viewport.positionGlobalToLocal(position, position);
180
-
181
- const normalizedPosition = new Vector2();
182
-
183
- //compute world position for drop
184
- const ray = make_ray_from_viewport_position(engine, position);
185
-
186
- const source = ray.origin;
187
- const direction = ray.direction;
188
-
189
-
190
- const entityManager = engine.entityManager;
191
- const ecd = entityManager.dataset;
192
-
193
- const terrain = obtainTerrain(ecd);
194
-
195
- const worldPosition = new Vector3();
196
-
197
- const mesh = new Mesh();
198
-
199
- mesh.castShadow = true;
200
- mesh.receiveShadow = true;
201
-
202
- const transform = new Transform();
203
-
204
- const actions = editor.actions;
205
- actions.mark('New Mesh Placed from Library');
206
- const entityCreateAction = new EntityCreateAction();
207
- actions.do(entityCreateAction);
208
-
209
- const sp3 = new SurfacePoint3();
210
-
211
- const hit_found = terrain.raycastFirstSync(sp3, source.x, source.y, source.z, direction.x, direction.y, direction.z);
212
-
213
- function handleMeshSetEvent() {
214
- const bb = mesh.boundingBox;
215
-
216
- const c0 = new Vector3(bb.x0, bb.y0, bb.z0);
217
- const c1 = new Vector3(bb.x1, bb.y1, bb.z1);
218
-
219
- const diagonal = c0.distanceTo(c1);
220
-
221
- const offset = direction.clone().multiplyScalar(diagonal);
222
-
223
- transform.position.add(offset);
224
-
225
- //remove listener
226
- ecd.removeEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
227
- }
228
-
229
- if (hit_found) {
230
- //got a terrain ray hit, set world placement position to that point
231
- worldPosition.copy(sp3.position);
232
- } else {
233
- //set position to the source of the ray pick if there's nothing else available
234
- worldPosition.copy(source);
235
-
236
-
237
- //wait for mesh to load
238
- ecd.addEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
239
- }
240
-
241
- transform.position.copy(worldPosition);
242
-
243
- mesh.url = url;
244
-
245
-
246
- actions.doMany([
247
- new ComponentAddAction(entityCreateAction.entity, transform),
248
- new ComponentAddAction(entityCreateAction.entity, mesh),
249
- //automatically select newly placed object
250
- new SelectionClearAction(),
251
- new SelectionAddAction([entityCreateAction.entity])
252
- ]);
253
-
254
- }
255
-
256
- function handleDragOverEvent(event) {
257
- event.preventDefault();
258
- }
259
-
260
-
261
- meshLibraryView.on.linked.add(function () {
262
- resolveEngine(editor.engine);
263
-
264
- const viewport = editor.engine.graphics.viewport;
265
-
266
- viewport.el.addEventListener('drop', handleDropEvent);
267
- viewport.el.addEventListener('dragover', handleDragOverEvent);
268
- });
269
-
270
- meshLibraryView.on.unlinked.add(function () {
271
- const viewport = editor.engine.graphics.viewport;
272
-
273
- viewport.el.removeEventListener('drop', handleDropEvent);
274
- viewport.el.removeEventListener('dragover', handleDragOverEvent);
275
- });
276
-
277
- meshLibraryView.size.set(400, 400);
116
+ class EditorView extends View {
117
+ main = new EmptyView()
278
118
 
279
- const resizeHandleView = new BottomLeftResizeHandleView(meshLibraryView);
280
- meshLibraryView.addChild(resizeHandleView);
119
+ mainViewport = new EmptyView();
281
120
 
282
- return meshLibraryView;
283
- }
284
-
285
- class EditorView extends View {
286
121
  /**
287
122
  *
288
123
  * @param {Editor} editor
@@ -311,6 +146,11 @@ class EditorView extends View {
311
146
  const decorators = makeEntityDecorators();
312
147
 
313
148
 
149
+ const entity_list_view = new HierarchicalEntityListView();
150
+
151
+ entity_list_view.dataset = editor.engine.entityManager.dataset;
152
+ entity_list_view.on.interact.add(inspectEntity);
153
+
314
154
  const entityListView = new EntityListView({ editor, decorators });
315
155
  this.entityListView = entityListView;
316
156
 
@@ -324,6 +164,8 @@ class EditorView extends View {
324
164
  const em = editor.engine.entityManager;
325
165
  entityEditor.entityManager.set(em);
326
166
  entityEditor.model.set(entity);
167
+
168
+ entity_list_view.selection = [entity];
327
169
  }
328
170
 
329
171
  this.bindSignal(editor.selection.on.added, function (entity) {
@@ -339,7 +181,6 @@ class EditorView extends View {
339
181
  const toolSettings = new ToolSettingsView({});
340
182
  this.toolSettings = toolSettings;
341
183
 
342
- //tool bar
343
184
  const toolBar = new ListView(editor.toolEngine.tools, {
344
185
  elementFactory: function (tool) {
345
186
  const toolView = new ToolView({ tool, editor });
@@ -398,46 +239,46 @@ class EditorView extends View {
398
239
  this.selectionView = selectionView;
399
240
 
400
241
 
401
- const coordinateView = new GridPickCoordinateView(editor);
402
- this.coordinateView = coordinateView;
403
-
404
- this.meshLibraryView = prepareMeshLibrary(editor);
405
- this.meshLibraryView.size.set(340, 200);
242
+ this.coordinateView = new GridPickCoordinateView(editor);
406
243
 
407
244
  //
408
245
  this.bindSignal(this.size.onChanged, this.layout.bind(this));
409
246
 
410
247
 
411
- this.addChild(this.coordinateView);
412
- this.addChild(this.selectionView);
413
- this.addChild(this.entityEditor);
414
- this.addChild(this.entityListView);
415
- this.addChild(this.toolBar);
416
- this.addChild(this.processBar);
417
- this.addChild(this.meshLibraryView);
418
- this.addChild(this.toolSettings);
248
+ this.mainViewport.addChild(this.coordinateView);
249
+ this.mainViewport.addChild(this.selectionView);
250
+ this.mainViewport.addChild(this.toolBar);
251
+ this.mainViewport.addChild(this.processBar);
252
+ this.mainViewport.addChild(this.toolSettings);
253
+
254
+
255
+ const split = SplitView.from({
256
+ fraction: 0.2,
257
+ a: entity_list_view,
258
+ b: SplitView.from({
259
+ fraction: 0.7,
260
+ a: this.mainViewport,
261
+ b: this.entityEditor,
262
+ })
263
+ });
264
+ this.main.addChild(split);
265
+
266
+ this.main.size.onChanged.add(split.size.set, split.size);
267
+
268
+ this.addChild(this.main);
419
269
  }
420
270
 
421
271
  layout() {
422
272
  const size = this.size;
423
273
 
424
- this.entityEditor.size.set(360, size.y);
425
- this.entityEditor.position.set(size.x - this.entityEditor.size.x, 0);
426
-
427
- this.entityListView.size.set(200, size.y);
428
- this.entityListView.position.set(0, 0);
429
-
274
+ this.main.size.copy(size);
430
275
  if (this.gameView !== null) {
431
- this.gameView.position.set(this.entityListView.position.x + this.entityListView.size.x, 0);
432
- this.gameView.size.set(size.x - (this.entityEditor.size.x + this.entityListView.size.x), size.y);
433
-
434
276
  this.toolBar.size.set(this.gameView.size.x, 36);
435
277
  this.toolBar.position.set(this.gameView.position.x + 5, this.gameView.position.y + this.gameView.size.y - (this.toolBar.size.y + 5));
436
278
 
437
279
  // this.processBar.size.set(this.gameView.size.x, 36);
438
280
  // this.processBar.position.set(this.toolBar.position.x, 5);
439
281
 
440
- this.meshLibraryView.position.set(this.gameView.position.x + this.gameView.size.x - (this.meshLibraryView.size.x + 5), 5);
441
282
  }
442
283
  }
443
284
 
@@ -446,7 +287,9 @@ class EditorView extends View {
446
287
 
447
288
  //hijack game view from the engine
448
289
  this.gameView = this.editor.engine.gameView;
449
- this.addChild(this.gameView);
290
+ this.mainViewport.addChild(this.gameView);
291
+
292
+ this.mainViewport.size.onChanged.add(this.gameView.size.set, this.gameView.size);
450
293
 
451
294
  this.layout();
452
295
  }
@@ -455,7 +298,8 @@ class EditorView extends View {
455
298
  super.unlink();
456
299
  if (this.gameView !== null) {
457
300
  //release game view
458
- this.removeChild(this.gameView);
301
+ this.mainViewport.removeChild(this.gameView);
302
+ this.mainViewport.size.onChanged.remove(this.gameView.size.set, this.gameView.size);
459
303
  this.gameView = null;
460
304
  }
461
305
  }
@@ -0,0 +1,191 @@
1
+ import Name from "../../../../model/game/ecs/component/Name.js";
2
+ import { arraySetSortingDiff } from "../../../src/core/collection/array/arraySetSortingDiff.js";
3
+ import List from "../../../src/core/collection/list/List.js";
4
+ import Signal from "../../../src/core/events/signal/Signal.js";
5
+ import { number_compare_ascending } from "../../../src/core/primitives/numbers/number_compare_ascending.js";
6
+ import { ParentEntity } from "../../../src/engine/ecs/parent/ParentEntity.js";
7
+ import { MouseEvents } from "../../../src/engine/input/devices/events/MouseEvents.js";
8
+ import LabelView from "../../../src/view/common/LabelView.js";
9
+ import ListView from "../../../src/view/common/ListView.js";
10
+ import EmptyView from "../../../src/view/elements/EmptyView.js";
11
+ import style from "./HierarchicalEntityListView.module.scss";
12
+
13
+ export class HierarchicalEntityListView extends EmptyView {
14
+
15
+ /**
16
+ *
17
+ * @type {EntityComponentDataset|null}
18
+ */
19
+ #dataset = null;
20
+
21
+ #roots = new List();
22
+
23
+ #child_map = new Map();
24
+
25
+ #selected = new List();
26
+
27
+
28
+ #update_roots() {
29
+ const new_roots = [];
30
+
31
+ const ecd = this.#dataset;
32
+
33
+ ecd.traverseEntityIndices(id => {
34
+
35
+ const parent = ecd.getComponent(id, ParentEntity);
36
+
37
+ if (parent !== undefined) {
38
+ const childMap = this.#child_map;
39
+ let children = childMap.get(parent.entity);
40
+ if (children === undefined) {
41
+ children = [];
42
+ childMap.set(parent.entity, children);
43
+ }
44
+ children.push(id);
45
+
46
+ return;
47
+ }
48
+
49
+ new_roots.push(id);
50
+ });
51
+
52
+ // perform patch
53
+ const diff = arraySetSortingDiff(new_roots, this.#roots.asArray(), number_compare_ascending);
54
+
55
+ for (let i = 0; i < diff.uniqueB.length; i++) {
56
+ const removal_id = diff.uniqueB[i];
57
+
58
+ this.#roots.removeOneOf(removal_id);
59
+ }
60
+
61
+
62
+ for (let i = 0; i < diff.uniqueA.length; i++) {
63
+ const addition_id = diff.uniqueA[i];
64
+
65
+ this.#roots.add(addition_id);
66
+ }
67
+ }
68
+
69
+ set selection(entities) {
70
+ this.#selected.patch(entities);
71
+ }
72
+
73
+ set dataset(v) {
74
+ this.#roots.reset();
75
+
76
+ this.#dataset = v;
77
+
78
+ this.#update_roots();
79
+ }
80
+
81
+ /**
82
+ *
83
+ * @param {number} entity
84
+ */
85
+ #make_entity_view(entity) {
86
+
87
+ const ecd = this.#dataset;
88
+
89
+ const children = this.#child_map.get(entity);
90
+
91
+ const has_children = children !== undefined;
92
+
93
+ const entity_view = new EmptyView({
94
+ classList:[style.entityView],
95
+ css: {
96
+ position: 'relative',
97
+ pointerEvents: "auto",
98
+ }
99
+ });
100
+
101
+ let label_text = `${entity}`;
102
+
103
+ const name = ecd.getComponent(entity, Name);
104
+
105
+ if (name !== undefined) {
106
+ label_text += `: ${name}`
107
+ }
108
+
109
+ entity_view.addChild(new LabelView(label_text, {
110
+ css: {
111
+ position: 'relative'
112
+ }
113
+ }));
114
+
115
+ if (has_children) {
116
+
117
+ const children_container = new EmptyView({
118
+ css: {
119
+ paddingLeft: "8px"
120
+ }
121
+ });
122
+
123
+ for (let i = 0; i < children.length; i++) {
124
+
125
+ const child = children[i];
126
+
127
+ const child_view = this.#make_entity_view(child);
128
+
129
+ children_container.addChild(child_view);
130
+
131
+ }
132
+
133
+ entity_view.addChild(children_container);
134
+
135
+ }
136
+
137
+ entity_view.el.addEventListener(MouseEvents.Click, (evt) => {
138
+ this.on.interact.send1(entity);
139
+
140
+ evt.stopPropagation();
141
+ });
142
+
143
+
144
+ const update_selection = () => {
145
+ const is_selected = this.#selected.contains(entity);
146
+
147
+ entity_view.setClass("selected", is_selected);
148
+ }
149
+
150
+ entity_view.bindSignal(this.#selected.on.added, update_selection);
151
+ entity_view.bindSignal(this.#selected.on.removed, update_selection);
152
+ entity_view.on.linked.add(update_selection);
153
+
154
+ return entity_view;
155
+ }
156
+
157
+ constructor() {
158
+ super();
159
+
160
+ const listView = new ListView(this.#roots, {
161
+ classList: [
162
+ style.main
163
+ ],
164
+ elementFactory: (entity) => {
165
+
166
+ return this.#make_entity_view(entity);
167
+ },
168
+ });
169
+
170
+ listView.css({
171
+ display: 'flex',
172
+ flexDirection: 'column'
173
+ })
174
+
175
+ this.size.onChanged.add(listView.size.set, listView.size);
176
+
177
+ this.on.interact = new Signal();
178
+
179
+ this.addChild(listView);
180
+ }
181
+
182
+ link() {
183
+ super.link();
184
+
185
+ this.#update_roots();
186
+ }
187
+
188
+ unlink() {
189
+ super.unlink();
190
+ }
191
+ }
@@ -0,0 +1,13 @@
1
+ .main {
2
+ padding-left: 2px;
3
+ background: white;
4
+
5
+ overflow-y: auto; // enable scrolling
6
+ pointer-events: auto; // enable scroll-bar to capture pointer events
7
+ }
8
+
9
+ .entityView:nth-child(2n) {
10
+ padding-top: 1px;
11
+ padding-bottom: 1px;
12
+ background: #efefef;
13
+ }