@woosh/meep-engine 2.39.44 → 2.40.0

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.
@@ -15,7 +15,6 @@ import { MeshPhongMaterial } from 'three';
15
15
  import { assert } from "../../../../core/assert.js";
16
16
  import { Color } from "../../../../core/color/Color.js";
17
17
  import { noop } from "../../../../core/function/Functions.js";
18
- import Vector3 from "../../../../core/geom/Vector3.js";
19
18
  import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
20
19
  import { RaycastBVHVisitor } from "../../../../core/bvh2/traversal/RaycastBVHVisitor.js";
21
20
  import { FirstRayIntersectionTerrainBVHVisitor } from "./FirstRayIntersectionTerrainBVHVisitor.js";
@@ -24,6 +23,8 @@ import { aabb2_overlapExists } from "../../../../core/geom/AABB2.js";
24
23
  import ObservedInteger from "../../../../core/model/ObservedInteger.js";
25
24
  import { NumericInterval } from "../../../../core/math/interval/NumericInterval.js";
26
25
  import { randomFloatBetween } from "../../../../core/math/random/randomFloatBetween.js";
26
+ import { mat4, vec3 } from "gl-matrix";
27
+ import { isArrayEqualStrict } from "../../../../core/collection/array/isArrayEqualStrict.js";
27
28
 
28
29
  class TerrainTileManager {
29
30
  /**
@@ -105,7 +106,30 @@ class TerrainTileManager {
105
106
  this.traverse(this.assignTileMaterial, this);
106
107
  });
107
108
 
109
+ /**
110
+ *
111
+ * @type {Float32Array}
112
+ * @private
113
+ */
114
+ this.__transform = new Float32Array(16);
115
+
116
+ }
117
+
118
+ set transform(m4) {
119
+ if (isArrayEqualStrict(m4, this.__transform)) {
120
+ // no change
121
+ return;
122
+ }
123
+
124
+ mat4.copy(this.__transform, m4);
125
+
126
+ this.traverse(t => {
127
+ t.transform = m4;
128
+ });
129
+ }
108
130
 
131
+ get transform() {
132
+ return this.__transform;
109
133
  }
110
134
 
111
135
  /**
@@ -156,74 +180,6 @@ class TerrainTileManager {
156
180
  this.initializeTiles();
157
181
  }
158
182
 
159
- /**
160
- *
161
- * @param {Vector3} origin
162
- * @param {Vector3} direction
163
- * @param {function} callback
164
- * @param {function} missCallback
165
- */
166
- raycast(origin, direction, callback, missCallback) {
167
- assert.typeOf(callback, 'function', 'callback');
168
- assert.typeOf(missCallback, 'function', 'missCallback');
169
-
170
- let bestHit = null;
171
- let bestNormal = null;
172
- let bestGeometry = null;
173
- let bestDistanceSqr = Number.POSITIVE_INFINITY;
174
-
175
- let firstStageOver = false;
176
-
177
- let tileCount = 0;
178
-
179
- function tryReturn() {
180
- if (tileCount === 0 && firstStageOver) {
181
- callback(bestHit, bestNormal, bestGeometry);
182
- }
183
- }
184
-
185
- function registerHit(hit, normal, geo) {
186
- const d = hit.distanceSqrTo(origin);
187
- if (d < bestDistanceSqr) {
188
- bestDistanceSqr = d;
189
- bestHit = hit;
190
- bestNormal = normal;
191
- bestGeometry = geo;
192
- }
193
- }
194
-
195
-
196
- /**
197
- *
198
- * @param {TerrainTile} tile
199
- */
200
- function doCast(tile) {
201
-
202
- tile.raycast(origin, direction, registerHit, missCallback);
203
- tileCount--;
204
- tryReturn();
205
- }
206
-
207
- this.bvh.traverseRayLeafIntersections(origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, function (leaf) {
208
- /**
209
- *
210
- * @type {TerrainTile}
211
- */
212
- const tile = leaf.object;
213
-
214
- tileCount++;
215
-
216
- if (tile.isBuilt) {
217
- doCast(tile);
218
- } else {
219
- tile.onBuilt.addOne(doCast);
220
- }
221
- });
222
-
223
- firstStageOver = true;
224
- tryReturn();
225
- }
226
-
227
183
  /**
228
184
  *
229
185
  * @param {TerrainTile} tile
@@ -378,7 +334,8 @@ class TerrainTileManager {
378
334
  tile.scale.copy(this.scale);
379
335
  tile.resolution.copy(this.resolution);
380
336
 
381
- tile.createInitialBounds(this.heightRange.min, this.heightRange.max);
337
+ tile.setInitialHeightBounds(this.heightRange.min, this.heightRange.max);
338
+ tile.computeBoundingBox();
382
339
 
383
340
  //hook for building
384
341
  tile.ensureBuilt = ensureBuilt(x, y);
@@ -397,11 +354,8 @@ class TerrainTileManager {
397
354
  * @returns {number}
398
355
  */
399
356
  computeTileIndex(x, y) {
400
- assert.ok(Number.isInteger(x), `x must be an integer, instead was ${x}`);
401
- assert.ok(Number.isInteger(y), `x must be an integer, instead was ${y}`);
402
-
403
- assert.ok(x >= 0, `x(=${x}) must be greater or equal to 0`);
404
- assert.ok(y >= 0, `y(=${y}) must be greater or equal to 0`);
357
+ assert.isNonNegativeInteger(x, 'x');
358
+ assert.isNonNegativeInteger(y, 'y');
405
359
 
406
360
  const w = Math.ceil(this.totalSize.x / this.tileSize.x);
407
361
 
@@ -415,9 +369,16 @@ class TerrainTileManager {
415
369
  *
416
370
  * @param {number} x
417
371
  * @param {number} y
418
- * @returns {TerrainTile}
372
+ * @returns {TerrainTile|undefined}
419
373
  */
420
374
  getRaw(x, y) {
375
+ if (
376
+ x < 0
377
+ || x >= Math.ceil(this.totalSize.x / this.tileSize.x)
378
+ || y < 0
379
+ ) {
380
+ return undefined;
381
+ }
421
382
 
422
383
  const tileIndex = this.computeTileIndex(x, y);
423
384
 
@@ -442,6 +403,43 @@ class TerrainTileManager {
442
403
  return this.getRaw(tileX, tileY);
443
404
  }
444
405
 
406
+ /**
407
+ * Given world coordinates in top-down plane, where X runs along X axis and Y runs along Z axis, returns terrain tile that overlaps that 2d region
408
+ * @param {number} x
409
+ * @param {number} y
410
+ * @return {TerrainTile|undefined}
411
+ */
412
+ getTileByWorldPosition2D(x, y) {
413
+ const v3 = vec3.fromValues(x, 0, y);
414
+
415
+ const world_inverse = mat4.create();
416
+
417
+ mat4.invert(world_inverse, this.transform);
418
+
419
+
420
+ vec3.transformMat4(v3, v3, world_inverse);
421
+
422
+ return this.getRawTileByPosition(v3.x, v3.z);
423
+ }
424
+
425
+ /**
426
+ * Builds and returns the tile from world coordinates
427
+ * @param {number} x
428
+ * @param {number} y
429
+ * @returns {Promise<TerrainTile>}
430
+ */
431
+ obtainTileAtWorldPosition2D(x, y) {
432
+ const tile = this.getTileByWorldPosition2D(x, y);
433
+
434
+ return this.obtain(tile.gridPosition.x, tile.gridPosition.y);
435
+ }
436
+
437
+ /**
438
+ * @deprecated use {@link #obtain instead}
439
+ * @param {number} x
440
+ * @param {number} y
441
+ * @param {function(TerrainTile):*} callback
442
+ */
445
443
  processTile(x, y, callback) {
446
444
  const tile = this.getRaw(x, y);
447
445
 
@@ -454,9 +452,10 @@ class TerrainTileManager {
454
452
 
455
453
  /**
456
454
  *
457
- * @param {int} x
458
- * @param {int} y
459
- * @returns {Promise}
455
+ * @param {number} x coordinate
456
+ * @param {number} y coordinate
457
+ * @returns {Promise<TerrainTile>}
458
+ * @throws if no tile exists at given coordinates
460
459
  */
461
460
  obtain(x, y) {
462
461
  const tile = this.getRaw(x, y);
@@ -490,6 +489,10 @@ class TerrainTileManager {
490
489
  * @param {TerrainTile} tile
491
490
  */
492
491
  release(tile) {
492
+ if (tile.referenceCount <= 0) {
493
+ console.warn('Tile already has no references');
494
+ }
495
+
493
496
  tile.referenceCount--;
494
497
 
495
498
  if (tile.referenceCount <= 0) {
@@ -497,7 +500,7 @@ class TerrainTileManager {
497
500
  tile.dispose();
498
501
  }
499
502
 
500
-
503
+ // TODO check tile.isBuilt flag
501
504
  tile.onDestroyed.send1(tile);
502
505
  }
503
506
 
@@ -512,9 +515,17 @@ class TerrainTileManager {
512
515
  }
513
516
  }
514
517
 
518
+ /**
519
+ *
520
+ * @param {number} x
521
+ * @param {number} y
522
+ * @param {TerrainTile} tile
523
+ */
515
524
  stitchTile(x, y, tile) {
516
525
 
517
- const gridSize = this.totalSize.clone().divide(this.tileSize).floor();
526
+ const gridSize = this.totalSize.clone();
527
+ gridSize.divide(this.tileSize);
528
+ gridSize.floor();
518
529
 
519
530
  const self = this;
520
531
  //normal stitching
@@ -569,6 +580,7 @@ class TerrainTileManager {
569
580
  directionZ
570
581
  ) {
571
582
 
583
+ // console.log('+ raycastFirstSync');
572
584
  raycastBVHVisitor.collector = firstRayIntersectionTerrainBVHVisitor;
573
585
  raycastBVHVisitor.setOrigin(originX, originY, originZ);
574
586
  raycastBVHVisitor.setDirection(directionX, directionY, directionZ);
@@ -579,6 +591,8 @@ class TerrainTileManager {
579
591
 
580
592
  traverseBinaryNodeUsingVisitor(this.bvh, raycastBVHVisitor);
581
593
 
594
+ // console.log('- raycastFirstSync');
595
+
582
596
  if (firstRayIntersectionTerrainBVHVisitor.closestDistance !== Number.POSITIVE_INFINITY) {
583
597
  result.copy(firstRayIntersectionTerrainBVHVisitor.closest);
584
598
 
@@ -588,41 +602,6 @@ class TerrainTileManager {
588
602
  return false;
589
603
  }
590
604
 
591
- raycastVertical(x, y, successCallback, missCallback) {
592
- assert.typeOf(missCallback, 'function', 'missCallback');
593
-
594
- /**
595
- *
596
- * @param {TerrainTile} tile
597
- */
598
- function doCast(tile) {
599
- tile.raycastVertical(x, y, successCallback, missCallback);
600
- }
601
-
602
-
603
- let miss = true;
604
-
605
- this.bvh.traverseRayLeafIntersections(x, -10000, y, 0, 1, 0, function (leaf) {
606
- /**
607
- *
608
- * @type {TerrainTile}
609
- */
610
- const tile = leaf.object;
611
-
612
- miss = false;
613
-
614
- if (tile.isBuilt) {
615
- doCast(tile);
616
- } else {
617
- tile.onBuilt.addOne(doCast);
618
- }
619
- });
620
-
621
- if (miss) {
622
- missCallback();
623
- }
624
- }
625
-
626
605
  /**
627
606
  * TODO untested
628
607
  * @param {SurfacePoint3} contact
@@ -631,7 +610,10 @@ class TerrainTileManager {
631
610
  * @return {boolean}
632
611
  */
633
612
  raycastVerticalFirstSync(contact, x, y) {
634
- return this.raycastFirstSync(contact, x, -10000, y, 0, 1, 0);
613
+ // console.log('+ raycastVerticalFirstSync');
614
+ const r = this.raycastFirstSync(contact, x, -10000, y, 0, 1, 0);
615
+ // console.log('- raycastVerticalFirstSync');
616
+ return r;
635
617
  }
636
618
 
637
619
  /**
@@ -697,14 +679,11 @@ class TerrainTileManager {
697
679
 
698
680
  // console.timeEnd(processName);
699
681
 
700
- self.on.tileBuilt.dispatch(tile);
682
+ self.on.tileBuilt.send1(tile);
701
683
  }, reject);
702
684
  }
703
685
  }
704
686
 
705
- const v3_origin = new Vector3();
706
- const v3_direction = new Vector3();
707
-
708
687
  const raycastBVHVisitor = new RaycastBVHVisitor();
709
688
  const firstRayIntersectionTerrainBVHVisitor = new FirstRayIntersectionTerrainBVHVisitor();
710
689
 
@@ -33,7 +33,7 @@ export class Camera {
33
33
  * Whether clipping planes should be automatically calculated or not
34
34
  * @type {boolean}
35
35
  */
36
- this.autoClip = true;
36
+ this.autoClip = false;
37
37
 
38
38
  /**
39
39
  * Tunable parameter to prevent clipping planes from thrashing. Clipping planes must move by a certain portion of the current span before frustum gets shrunken
@@ -9,11 +9,11 @@ export class FPLightBinding extends LightBinding {
9
9
  }
10
10
 
11
11
  /**
12
- *
12
+ * @param {LightContext} ctx
13
13
  * @return {ForwardPlusRenderingPlugin}
14
14
  * @private
15
15
  */
16
- get __plugin(){
16
+ getPlugin(ctx) {
17
17
  return ctx.system.__plugin.getValue();
18
18
  }
19
19
 
@@ -22,7 +22,7 @@ export class FPLightBinding extends LightBinding {
22
22
  *
23
23
  * @type {ForwardPlusRenderingPlugin}
24
24
  */
25
- const fp = this.__plugin;
25
+ const fp = this.getPlugin(ctx);
26
26
 
27
27
  const lightManager = fp.getLightManager();
28
28
 
@@ -52,7 +52,7 @@ export class FPLightBinding extends LightBinding {
52
52
  *
53
53
  * @type {ForwardPlusRenderingPlugin}
54
54
  */
55
- const fp = this.__plugin;
55
+ const fp = this.getPlugin(ctx);
56
56
 
57
57
  const lightManager = fp.getLightManager();
58
58
 
@@ -71,25 +71,6 @@ function bindGeometryFaceNormal(indices, normals, index) {
71
71
  vNormal.set(nx, ny, nz);
72
72
  }
73
73
 
74
- function computeSampleFaceIndex(width, x, y) {
75
-
76
- //get fraction of x and y
77
- const xF = x % 1;
78
- const yF = y % 1;
79
-
80
- //get whole part of x and y
81
- const xW = x | 0;
82
- const yW = y | 0;
83
-
84
- //figure out which quad it is in
85
- const iQuad = yW * (width - 1) + xW;
86
-
87
- //figure out triangle
88
- const index = iQuad * 2 + ((xF + yF) | 0);
89
-
90
- return index;
91
- }
92
-
93
74
 
94
75
  function extractFaceIndexFromLeaf_default(leaf) {
95
76
  return leaf.object;
@@ -172,65 +153,6 @@ export class BVHGeometryRaycaster {
172
153
  }
173
154
  }
174
155
 
175
- /**
176
- *
177
- * @param {number} x
178
- * @param {number} y
179
- * @param callback
180
- * @param missCallback
181
- * @returns {boolean}
182
- */
183
- raycastVertical(x, y, callback, missCallback) {
184
- const position = this.position;
185
- const scale = this.scale;
186
-
187
- //transform position to geometry coordinate system
188
- const resolution = this.resolution;
189
-
190
- const size = this.size;
191
-
192
- const width = size.x * resolution;
193
- const height = size.y * resolution;
194
-
195
-
196
- const gX = ((x - position.x * scale.x) / scale.x) * resolution * ((width - 1) / width);
197
- const gY = ((y - position.y * scale.y) / scale.y) * resolution * ((height - 1) / height);
198
-
199
- const index = computeSampleFaceIndex(width, gX, gY);
200
-
201
-
202
- const geometry = this.geometry;
203
-
204
- const geometryIndices = geometry.getIndex().array;
205
- const geometryVertices = geometry.getAttribute('position').array;
206
- const geometryNormals = geometry.getAttribute('normal').array;
207
-
208
-
209
- if (index * 3 >= geometryIndices.length) {
210
- missCallback();
211
- return false;
212
- }
213
-
214
- bindGeometryFace(geometryIndices, geometryVertices, index);
215
-
216
-
217
- this.direction.set(0, -1, 0);
218
- this.origin.set(x, 1000, y);
219
-
220
- const hitFound = rayTriangleIntersection(hit, this.origin, this.direction, vA, vB, vC);
221
-
222
- if (!hitFound) {
223
- missCallback();
224
- return false;
225
- }
226
-
227
- bindGeometryFaceNormal(geometryIndices, geometryNormals, index);
228
-
229
- callback(hit, vNormal, geometry);
230
-
231
- return true;
232
- }
233
-
234
156
  /**
235
157
  *
236
158
  * @param {SurfacePoint3} hit
@@ -6,8 +6,6 @@ import { array_copy } from "../../../../../core/collection/array/copyArray.js";
6
6
  import { mat4 } from "gl-matrix";
7
7
  import { Group, Matrix4, Mesh } from "three";
8
8
  import { mergeBufferGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
9
- import { groupArrayBy } from "../../../../../core/collection/ArrayUtils.js";
10
- import { collectIteratorValueToArray } from "../../../../../core/collection/IteratorUtils.js";
11
9
 
12
10
  class GeometryContext {
13
11
  constructor() {
@@ -299,13 +297,6 @@ export function merge_geometry_hierarchy(input, context = new Context()) {
299
297
  }
300
298
  });
301
299
 
302
- const materials = collectIteratorValueToArray([], material_cache.materialCache.data.keys());
303
-
304
- const color_groups = groupArrayBy(materials, (m => m.color.getHex()));
305
-
306
- console.warn(color_groups);
307
-
308
-
309
300
  const contexts_merge_stage_0 = [];
310
301
 
311
302
  merge_by_material(contexts, contexts_merge_stage_0, 0);
@@ -1295,9 +1295,9 @@ function draw_camera_view_planes() {
1295
1295
 
1296
1296
  // prepare_scene_2();
1297
1297
  // prepare_scene_decal_0();
1298
- // prepare_scene_decal_1();
1298
+ prepare_scene_decal_1();
1299
1299
  // prepare_scene_9();
1300
- prepare_scene_2();
1300
+ // prepare_scene_2();
1301
1301
  // prepare_scene_0();
1302
1302
  animate();
1303
1303
 
@@ -0,0 +1,29 @@
1
+ import { Behavior } from "../Behavior.js";
2
+ import { BehaviorStatus } from "../BehaviorStatus.js";
3
+
4
+ /**
5
+ * Prints given message into the console
6
+ */
7
+ export class LogMessageBehavior extends Behavior {
8
+ constructor(message = "") {
9
+ super();
10
+
11
+ this.message = message;
12
+ }
13
+
14
+ /**
15
+ *
16
+ * @param {String} message
17
+ * @return {LogMessageBehavior}
18
+ */
19
+ static from(message) {
20
+ return new LogMessageBehavior(message);
21
+ }
22
+
23
+ tick(timeDelta) {
24
+ console.log(this.message);
25
+
26
+ // done
27
+ return BehaviorStatus.Succeeded;
28
+ }
29
+ }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.39.44",
8
+ "version": "2.40.0",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",