@woosh/meep-engine 2.33.67 → 2.33.71

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.
@@ -0,0 +1,115 @@
1
+ //
2
+
3
+ import { v2_magnitude } from "../Vector2.js";
4
+
5
+ function atan2(a, b) {
6
+ return Math.atan2(a, b);
7
+ }
8
+
9
+ /**
10
+ *
11
+ * @param {number[]} mat4
12
+ * @param {number} row_index
13
+ * @param {number} column_index
14
+ * @return {number}
15
+ */
16
+ function coeff(mat4, row_index, column_index) {
17
+ return mat4[row_index + column_index * 4];
18
+ }
19
+
20
+ function sin(a) {
21
+ return Math.sin(a);
22
+ }
23
+
24
+ function cos(a) {
25
+ return Math.cos(a);
26
+ }
27
+
28
+ const EIGEN_PI = Math.PI;
29
+
30
+ /**
31
+ *
32
+ * \returns the Euler-angles of the rotation matrix \c *this using the convention defined by the triplet (\a a0,\a a1,\a a2)
33
+ *
34
+ * Each of the three parameters \a a0,\a a1,\a a2 represents the respective rotation axis as an integer in {0,1,2}.
35
+ * For instance, in:
36
+ * \code Vector3f ea = mat.eulerAngles(2, 0, 2); \endcode
37
+ * "2" represents the z axis and "0" the x axis, etc. The returned angles are such that
38
+ * we have the following equality:
39
+ * \code
40
+ * mat == AngleAxisf(ea[0], Vector3f::UnitZ())
41
+ * * AngleAxisf(ea[1], Vector3f::UnitX())
42
+ * * AngleAxisf(ea[2], Vector3f::UnitZ()); \endcode
43
+ * This corresponds to the right-multiply conventions (with right hand side frames).
44
+ *
45
+ * The returned angles are in the ranges [0:pi]x[-pi:pi]x[-pi:pi].
46
+
47
+ * NOTE: ported from Eigen C++ library
48
+ * @see https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Geometry/EulerAngles.h
49
+ * @see https://stackoverflow.com/questions/11514063/extract-yaw-pitch-and-roll-from-a-rotationmatrix
50
+ * @param {number[]} res
51
+ * @param {number[]|Float32Array|mat4} m4
52
+ * @param {number} a0 axis index
53
+ * @param {number} a1
54
+ * @param {number} a2
55
+ */
56
+ export function eulerAnglesFromMatrix(res, m4, a0, a1, a2) {
57
+ const odd = ((a0 + 1) % 3 === a1) ? 0 : 1;
58
+
59
+ const i = a0;
60
+ const j = (a0 + 1 + odd) % 3;
61
+ const k = (a0 + 2 - odd) % 3;
62
+
63
+ if (a0 === a2) {
64
+ res[0] = atan2(coeff(m4, j, i), coeff(m4, k, i));
65
+ if ((odd && res[0] < 0) || ((!odd) && res[0] > 0)) {
66
+ if (res[0] > 0) {
67
+ res[0] -= EIGEN_PI;
68
+ } else {
69
+ res[0] += EIGEN_PI;
70
+ }
71
+ const s2 = v2_magnitude(coeff(m4, j, i), coeff(m4, k, i));
72
+ res[1] = -atan2(s2, coeff(m4, i, i));
73
+ } else {
74
+ const s2 = v2_magnitude(coeff(m4, j, i), coeff(m4, k, i));
75
+ res[1] = atan2(s2, coeff(m4, i, i));
76
+ }
77
+
78
+ // With a=(0,1,0), we have i=0; j=1; k=2, and after computing the first two angles,
79
+ // we can compute their respective rotation, and apply its inverse to M. Since the result must
80
+ // be a rotation around x, we have:
81
+ //
82
+ // c2 s1.s2 c1.s2 1 0 0
83
+ // 0 c1 -s1 * M = 0 c3 s3
84
+ // -s2 s1.c2 c1.c2 0 -s3 c3
85
+ //
86
+ // Thus: m11.c1 - m21.s1 = c3 & m12.c1 - m22.s1 = s3
87
+
88
+ const s1 = sin(res[0]);
89
+ const c1 = cos(res[0]);
90
+ res[2] = atan2(c1 * coeff(m4, j, k) - s1 * coeff(m4, k, k), c1 * coeff(m4, j, j) - s1 * coeff(m4, k, j));
91
+ } else {
92
+ res[0] = atan2(coeff(m4, j, k), coeff(m4, k, k));
93
+ const c2 = v2_magnitude(coeff(m4, i, i), coeff(m4, i, j));
94
+ if ((odd && res[0] < 0) || ((!odd) && res[0] > 0)) {
95
+ if (res[0] > 0) {
96
+ res[0] -= EIGEN_PI;
97
+ } else {
98
+ res[0] += EIGEN_PI;
99
+ }
100
+ res[1] = atan2(-coeff(m4, i, k), -c2);
101
+ } else
102
+ res[1] = atan2(-coeff(m4, i, k), c2);
103
+ const s1 = sin(res[0]);
104
+ const c1 = cos(res[0]);
105
+ res[2] = atan2(s1 * coeff(m4, k, i) - c1 * coeff(m4, j, i), c1 * coeff(m4, j, j) - s1 * coeff(m4, k, j));
106
+ }
107
+
108
+ if (!odd) {
109
+ // invert result
110
+ res[0] = -res[0];
111
+ res[1] = -res[1];
112
+ res[2] = -res[2];
113
+ }
114
+
115
+ }
@@ -482,7 +482,7 @@ export class TopoMesh {
482
482
  assert.equal(a.isTopoVertex, true, 'a.isTopoVertex !== true');
483
483
  assert.equal(b.isTopoVertex, true, 'b.isTopoVertex !== true');
484
484
 
485
- assert.notEqual(a, b, 'a === b, attempting to create an edge from vertex to itself')
485
+ assert.notEqual(a, b, 'a === b, attempting to create an edge from vertex to itself');
486
486
 
487
487
  const aEdges = a.edges;
488
488
  const n = aEdges.length;
@@ -25,15 +25,9 @@ export function computeTriangleRayIntersection(
25
25
  result,
26
26
  origin_x, origin_y, origin_z,
27
27
  direction_x, direction_y, direction_z,
28
- ax,
29
- ay,
30
- az,
31
- bx,
32
- by,
33
- bz,
34
- cx,
35
- cy,
36
- cz
28
+ ax, ay, az,
29
+ bx, by, bz,
30
+ cx, cy, cz
37
31
  ) {
38
32
 
39
33
  // edge1 = a - b
@@ -0,0 +1,18 @@
1
+ import { PI2 } from "../math/MathUtils.js";
2
+
3
+ /**
4
+ * Force angle to [-PI, +PI] range
5
+ * based on answer https://stackoverflow.com/a/2323034/3973586
6
+ * @param {number} angle in radians
7
+ * @return {number} in radians
8
+ */
9
+ export function normalize_angle_rad(angle) {
10
+ let r = angle % PI2;
11
+ r = (r + PI2) % PI2;
12
+
13
+ if (r > Math.PI) {
14
+ r -= PI2;
15
+ }
16
+
17
+ return r;
18
+ }
@@ -0,0 +1,45 @@
1
+ import { normalize_angle_rad } from "./normalize_angle_rad.js";
2
+
3
+ test('0', () => {
4
+ expect(normalize_angle_rad(0)).toBe(0);
5
+ });
6
+
7
+ test('PI', () => {
8
+ expect(normalize_angle_rad(Math.PI)).toBe(Math.PI);
9
+ });
10
+
11
+ test('-PI', () => {
12
+ expect(normalize_angle_rad(-Math.PI)).toBeCloseTo(Math.PI);
13
+ });
14
+
15
+ test('2*PI', () => {
16
+ expect(normalize_angle_rad(Math.PI * 2)).toBeCloseTo(0);
17
+ });
18
+
19
+ test('-2*PI', () => {
20
+ expect(normalize_angle_rad(-Math.PI * 2)).toBeCloseTo(0);
21
+ });
22
+
23
+ test('-1', () => {
24
+ expect(normalize_angle_rad(-1)).toBeCloseTo(-1);
25
+ });
26
+
27
+ test('-3', () => {
28
+ expect(normalize_angle_rad(-3)).toBeCloseTo(-3);
29
+ });
30
+
31
+ test('1', () => {
32
+ expect(normalize_angle_rad(1)).toBeCloseTo(1);
33
+ });
34
+
35
+ test('3', () => {
36
+ expect(normalize_angle_rad(3)).toBeCloseTo(3);
37
+ });
38
+
39
+ test('2*PI + 1', () => {
40
+ expect(normalize_angle_rad(Math.PI * 2 + 1)).toBeCloseTo(1);
41
+ });
42
+
43
+ test('- ( 2*PI + 1)', () => {
44
+ expect(normalize_angle_rad(-(Math.PI * 2 + 1))).toBeCloseTo(-1);
45
+ });
@@ -26,7 +26,6 @@ import { traverseThreeObject } from "../../graphics/ecs/highlight/renderer/trave
26
26
  import { computeTextureHash } from "./material/computeTextureHash.js";
27
27
  import { computeTextureEquality } from "./material/computeTextureEquality.js";
28
28
  import { async_traverse_three_object } from "./async_traverse_three_object.js";
29
- import { deinterleaveBufferGeometry } from "../../graphics/geometry/buffered/deinterleaveBufferGeometry.js";
30
29
 
31
30
  const animationOptimizer = new AnimationOptimizer();
32
31
  const materialCache = StaticMaterialCache.Global;
@@ -294,9 +293,6 @@ export class GLTFAssetLoader extends AssetLoader {
294
293
  mesh.geometry = geometry;
295
294
  }
296
295
 
297
- mesh.geometry = deinterleaveBufferGeometry(geometry);
298
-
299
-
300
296
  if (this.__enable_texture_cache) {
301
297
  // replace textures from cache
302
298
  replace_material_textures_from_cache(mesh.material, texture_cache);
@@ -10,6 +10,10 @@ import { obtainTerrain } from "../terrain/util/obtainTerrain.js";
10
10
  const v2 = new Vector2();
11
11
 
12
12
  export class FogOfWarRevealerSystem extends System {
13
+ /**
14
+ *
15
+ * @param {number} team
16
+ */
13
17
  constructor(team) {
14
18
  super();
15
19
 
@@ -19,6 +23,10 @@ export class FogOfWarRevealerSystem extends System {
19
23
 
20
24
  this.data = [];
21
25
 
26
+ /**
27
+ *
28
+ * @type {number}
29
+ */
22
30
  this.team = team;
23
31
  }
24
32
 
@@ -7,30 +7,14 @@ import Vector3 from '../../../../../core/geom/Vector3.js';
7
7
  import { assert } from "../../../../../core/assert.js";
8
8
  import { lerp } from "../../../../../core/math/lerp.js";
9
9
  import { Euler, Matrix4 } from "three";
10
- import { PI2 } from "../../../../../core/math/MathUtils.js";
10
+ import { normalize_angle_rad } from "../../../../../core/geom/normalize_angle_rad.js";
11
+ import { eulerAnglesFromMatrix } from "../../../../../core/geom/3d/eulerAnglesFromMatrix.js";
11
12
 
12
13
  const m4 = new Matrix4();
13
14
  const euler = new Euler();
14
15
 
15
16
  const panOffset = new Vector3();
16
17
 
17
- /**
18
- * Force angle to [-PI, +PI] range
19
- * based on answer https://stackoverflow.com/a/2323034/3973586
20
- * @param {number} angle in radians
21
- * @return {number} in radians
22
- */
23
- function normalize_angle(angle) {
24
- let r = angle % PI2;
25
- r = (r + PI2) % PI2;
26
-
27
- if (r > Math.PI) {
28
- r -= PI2;
29
- }
30
-
31
- return r;
32
- }
33
-
34
18
  /**
35
19
  *
36
20
  * @param {number} displacement_x
@@ -40,8 +24,8 @@ function normalize_angle(angle) {
40
24
  */
41
25
  export function rotate_from_view(displacement_x, displacement_y, input, output) {
42
26
  // crop yaw and pitch to safe range of -PI to PI
43
- const i_pitch = normalize_angle(input.pitch);
44
- const i_yaw = normalize_angle(input.yaw);
27
+ const i_pitch = normalize_angle_rad(input.pitch);
28
+ const i_yaw = normalize_angle_rad(input.yaw);
45
29
 
46
30
  // flip rotation axis when pitch is over 90deg in either direction, that is UP vector is pointing down
47
31
  const d_yaw = ((i_pitch > Math.PI || i_pitch < -Math.PI) ? -1 : 1) * displacement_x;
@@ -146,9 +130,29 @@ class TopDownCameraController {
146
130
 
147
131
  euler.setFromRotationMatrix(m4, 'ZYX');
148
132
 
149
- this.pitch = normalize_angle(euler.x);
150
- this.yaw = normalize_angle(euler.y);
151
- this.roll = normalize_angle(euler.z);
133
+ const angles = [];
134
+ eulerAnglesFromMatrix(angles, m4.elements, 2, 1, 0);
135
+
136
+ const _p0 = normalize_angle_rad(euler.x);
137
+ const _y0 = normalize_angle_rad(euler.y);
138
+ const _r0 = normalize_angle_rad(euler.z);
139
+
140
+ this.pitch = _p0;
141
+ this.yaw = _y0;
142
+ this.roll = _r0;
143
+
144
+
145
+ const _p1 = angles[2];
146
+ const _y1 = angles[1];
147
+ const _r1 = angles[0];
148
+
149
+ if (_p0 !== _p0 || _y0 !== _y1 || _r0 !== _r1) {
150
+ console.warn('Angular discrepancy');
151
+ }
152
+
153
+ this.pitch = _p1;
154
+ this.yaw = _y1;
155
+ this.roll = _r1;
152
156
 
153
157
  this.distance = eye.distanceTo(target);
154
158
 
@@ -11,6 +11,15 @@ test('setFromEyeAndTarget does not introduce roll when UP is aligned with +Y', (
11
11
  expect(ut.roll).toBe(0);
12
12
  });
13
13
 
14
+ test('setFromEyeAndTarget, with different directional axial combinations', () => {
15
+ const ut = new TopDownCameraController();
16
+
17
+ ut.setFromEyeAndTarget(new Vector3(0, 1, -1), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
18
+ ut.setFromEyeAndTarget(new Vector3(0, 1, -1), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
19
+
20
+ expect(ut.roll).toBe(0);
21
+ });
22
+
14
23
  test('setFromEyeAndTarget results in roll respecting UP vector', () => {
15
24
  const eye = new Vector3();
16
25
  const target = new Vector3();
@@ -28,9 +28,10 @@ export function deinterleaveBufferAttribute(source_attribute) {
28
28
  attribute.normalized = source_attribute.normalized;
29
29
  attribute.name = source_attribute.name;
30
30
 
31
+ let i = 0, j = 0;
31
32
  // copy data
32
- for (let i = 0; i < item_count; i++) {
33
- for (let j = 0; j < itemSize; j++) {
33
+ for (; i < item_count; i++) {
34
+ for (j = 0; j < itemSize; j++) {
34
35
  destination_array[i * itemSize + j] = source_data_array[i * stride + offset + j];
35
36
  }
36
37
  }
@@ -79,21 +79,32 @@ export class ClippingPlaneContainmentComputingVisitor extends GeometrySpatialAcc
79
79
 
80
80
  const index3 = index * 3;
81
81
 
82
- const a = this.__buffer_indices[index3] * 3;
83
- const b = this.__buffer_indices[index3 + 1] * 3;
84
- const c = this.__buffer_indices[index3 + 2] * 3;
82
+ const indices = this.__buffer_indices;
85
83
 
86
- const ax = this.__buffer_vertices[a];
87
- const ay = this.__buffer_vertices[a + 1];
88
- const az = this.__buffer_vertices[a + 2];
84
+ const a = indices[index3];
85
+ const b = indices[index3 + 1];
86
+ const c = indices[index3 + 2];
89
87
 
90
- const bx = this.__buffer_vertices[b];
91
- const by = this.__buffer_vertices[b + 1];
92
- const bz = this.__buffer_vertices[b + 2];
88
+ const vertices = this.__buffer_vertices;
93
89
 
94
- const cx = this.__buffer_vertices[c];
95
- const cy = this.__buffer_vertices[c + 1];
96
- const cz = this.__buffer_vertices[c + 2];
90
+ const stride = this.__buffer_vertex_stride;
91
+ const offset = this.__buffer_position_offset;
92
+
93
+ const a_address = a * stride + offset;
94
+ const b_address = b * stride + offset;
95
+ const c_address = c * stride + offset;
96
+
97
+ const ax = vertices[a_address];
98
+ const ay = vertices[a_address + 1];
99
+ const az = vertices[a_address + 2];
100
+
101
+ const bx = vertices[b_address];
102
+ const by = vertices[b_address + 1];
103
+ const bz = vertices[b_address + 2];
104
+
105
+ const cx = vertices[c_address];
106
+ const cy = vertices[c_address + 1];
107
+ const cz = vertices[c_address + 2];
97
108
 
98
109
  for (let i = 0; i < plane_count; i++) {
99
110
  const plane = planes[i];
@@ -108,15 +119,9 @@ export class ClippingPlaneContainmentComputingVisitor extends GeometrySpatialAcc
108
119
  plane_normal_y,
109
120
  plane_normal_z,
110
121
  plane_constant,
111
- ax,
112
- ay,
113
- az,
114
- bx,
115
- by,
116
- bz,
117
- cx,
118
- cy,
119
- cz
122
+ ax, ay, az,
123
+ bx, by, bz,
124
+ cx, cy, cz
120
125
  );
121
126
 
122
127
  if (side === -3) {
@@ -163,12 +168,8 @@ export class ClippingPlaneContainmentComputingVisitor extends GeometrySpatialAcc
163
168
  plane_normal_z,
164
169
  plane_constant,
165
170
 
166
- x0,
167
- y0,
168
- z0,
169
- x1,
170
- y1,
171
- z1
171
+ x0, y0, z0,
172
+ x1, y1, z1
172
173
  );
173
174
 
174
175
  if (side === -2) {
@@ -1,6 +1,6 @@
1
1
  import { IndexedBinaryBVHVisitor } from "../../../../../core/bvh2/binary/IndexedBinaryBVHVisitor.js";
2
2
 
3
- export class GeometrySpatialAcceleratorVisitor extends IndexedBinaryBVHVisitor{
3
+ export class GeometrySpatialAcceleratorVisitor extends IndexedBinaryBVHVisitor {
4
4
  constructor() {
5
5
  super();
6
6
 
@@ -25,6 +25,20 @@ export class GeometrySpatialAcceleratorVisitor extends IndexedBinaryBVHVisitor{
25
25
  */
26
26
  this.__buffer_vertices = null;
27
27
 
28
+ /**
29
+ *
30
+ * @type {number}
31
+ * @protected
32
+ */
33
+ this.__buffer_vertex_stride = 3;
34
+
35
+ /**
36
+ *
37
+ * @type {number}
38
+ * @protected
39
+ */
40
+ this.__buffer_position_offset = 0;
41
+
28
42
  /**
29
43
  * @protected
30
44
  * @type {IndexedBinaryBVH}
@@ -47,7 +61,20 @@ export class GeometrySpatialAcceleratorVisitor extends IndexedBinaryBVHVisitor{
47
61
  this.geometry = geometry;
48
62
 
49
63
  this.__buffer_indices = geometry.getIndex().array;
50
- this.__buffer_vertices = geometry.getAttribute('position').array;
64
+
65
+ const position_attribute = geometry.getAttribute('position');
66
+
67
+ if (position_attribute.isInterleavedBufferAttribute) {
68
+ const data = position_attribute.data;
69
+
70
+ this.__buffer_vertices = data.array;
71
+ this.__buffer_vertex_stride = data.stride;
72
+ this.__buffer_position_offset = position_attribute.offset;
73
+ } else {
74
+ this.__buffer_vertices = position_attribute.array;
75
+ this.__buffer_vertex_stride = 3;
76
+ this.__buffer_position_offset = 0;
77
+ }
51
78
  }
52
79
 
53
80
  }
@@ -96,21 +96,32 @@ export class RaycastNearestHitComputingVisitor extends GeometrySpatialAccelerato
96
96
 
97
97
  const index3 = index * 3;
98
98
 
99
- const a = this.__buffer_indices[index3] * 3;
100
- const b = this.__buffer_indices[index3 + 1] * 3;
101
- const c = this.__buffer_indices[index3 + 2] * 3;
99
+ const indices = this.__buffer_indices;
102
100
 
103
- const ax = this.__buffer_vertices[a];
104
- const ay = this.__buffer_vertices[a + 1];
105
- const az = this.__buffer_vertices[a + 2];
101
+ const a = indices[index3];
102
+ const b = indices[index3 + 1];
103
+ const c = indices[index3 + 2];
106
104
 
107
- const bx = this.__buffer_vertices[b];
108
- const by = this.__buffer_vertices[b + 1];
109
- const bz = this.__buffer_vertices[b + 2];
105
+ const vertices = this.__buffer_vertices;
110
106
 
111
- const cx = this.__buffer_vertices[c];
112
- const cy = this.__buffer_vertices[c + 1];
113
- const cz = this.__buffer_vertices[c + 2];
107
+ const stride = this.__buffer_vertex_stride;
108
+ const offset = this.__buffer_position_offset;
109
+
110
+ const a_address = a * stride + offset;
111
+ const b_address = b * stride + offset;
112
+ const c_address = c * stride + offset;
113
+
114
+ const ax = vertices[a_address];
115
+ const ay = vertices[a_address + 1];
116
+ const az = vertices[a_address + 2];
117
+
118
+ const bx = vertices[b_address];
119
+ const by = vertices[b_address + 1];
120
+ const bz = vertices[b_address + 2];
121
+
122
+ const cx = vertices[c_address];
123
+ const cy = vertices[c_address + 1];
124
+ const cz = vertices[c_address + 2];
114
125
 
115
126
  if (computeTriangleRayIntersection(
116
127
  this.__temp_hit,
@@ -120,15 +131,9 @@ export class RaycastNearestHitComputingVisitor extends GeometrySpatialAccelerato
120
131
  rayDirection.x,
121
132
  rayDirection.y,
122
133
  rayDirection.z,
123
- ax,
124
- ay,
125
- az,
126
- bx,
127
- by,
128
- bz,
129
- cx,
130
- cy,
131
- cz
134
+ ax, ay, az,
135
+ bx, by, bz,
136
+ cx, cy, cz
132
137
  )) {
133
138
  const d = this.__temp_hit.position.distanceSqrTo(rayOrigin);
134
139
 
@@ -154,12 +159,8 @@ export class RaycastNearestHitComputingVisitor extends GeometrySpatialAccelerato
154
159
  const z1 = data[address + 5];
155
160
 
156
161
  return intersectRay(
157
- x0,
158
- y0,
159
- z0,
160
- x1,
161
- y1,
162
- z1,
162
+ x0, y0, z0,
163
+ x1, y1, z1,
163
164
 
164
165
  rayOrigin.x,
165
166
  rayOrigin.y,
@@ -21,7 +21,6 @@ import { matcher_tag_traversable } from "./rules/matcher_tag_traversable.js";
21
21
  import { GridTaskGenerateRoads } from "../grid/generation/road/GridTaskGenerateRoads.js";
22
22
  import { mir_generator_place_road_decorators } from "./generators/mir_generator_place_road_decorators.js";
23
23
  import { MarkerNodeMatcherByType } from "../markers/matcher/MarkerNodeMatcherByType.js";
24
- import { mir_generator_place_buff_objects } from "./generators/interactive/mir_generator_place_buff_objects.js";
25
24
  import { GridTaskDensityMarkerDistribution } from "../grid/generation/GridTaskDensityMarkerDistribution.js";
26
25
  import { CellFilterSimplexNoise } from "../filtering/numeric/complex/CellFilterSimplexNoise.js";
27
26
  import { NumericInterval } from "../../core/math/interval/NumericInterval.js";
@@ -211,12 +210,11 @@ const prEnemyCorridorGuard = GridCellPlacementRule.from(
211
210
  ), actions: [
212
211
  ACTION_PLACE_ENEMY_MARKER,
213
212
  ACTION_PLACE_ENEMY_TAG
214
- ]
213
+ ],
214
+ probability: CellFilterLiteralFloat.from(0.5)
215
215
  }
216
216
  );
217
217
 
218
- prEnemyCorridorGuard.probability = 0.5;
219
-
220
218
  const gRuleSet2 = GridTaskActionRuleSet.from({ rules: GridActionRuleSet.from({ rules: [prEnemyTreasureGuard, prEnemyCorridorGuard] }) });
221
219
 
222
220
  gRuleSet2.addDependency(gRuleSetTreasureGuards);
@@ -226,7 +224,11 @@ const gPlaceStartingPoint = mir_generator_place_starting_point();
226
224
 
227
225
  gPlaceStartingPoint.addDependency(gConnectRooms);
228
226
 
229
- const gBuildDistanceMap = GridTaskBuildSourceDistanceMap.from({ source: MATCH_STARTING_POINT, pass: MATCH_EMPTY });
227
+ const gBuildDistanceMap = GridTaskBuildSourceDistanceMap.from({
228
+ source: MATCH_STARTING_POINT,
229
+ pass: MATCH_EMPTY,
230
+ layer: MirGridLayers.DistanceFromStart
231
+ });
230
232
 
231
233
  gBuildDistanceMap.addDependency(gPlaceStartingPoint);
232
234
 
@@ -235,11 +237,8 @@ gRuleSet1.addDependency(gBuildDistanceMap);
235
237
  const gBases = mir_generator_place_bases();
236
238
  gBases.addDependency(gMakeEmpty);
237
239
 
238
- const gBuffObjects = mir_generator_place_buff_objects();
239
- gBuffObjects.addDependency(gBases);
240
240
 
241
241
  gConnectRooms.addDependency(gBases);
242
- gConnectRooms.addDependency(gBuffObjects);
243
242
 
244
243
  gPlaceStartingPoint.addDependency(gBases);
245
244
 
@@ -250,7 +249,6 @@ const gRoads = new GridTaskGenerateRoads();
250
249
 
251
250
  gRoads.addDependency(gConnectRooms);
252
251
  gRoads.addDependency(gBases);
253
- gRoads.addDependency(gBuffObjects);
254
252
 
255
253
  const gRoadDecorators = mir_generator_place_road_decorators();
256
254
 
@@ -540,7 +538,6 @@ gFoliageLarge.addDependencies([
540
538
  gRuleSet1,
541
539
  gRuleSet2,
542
540
  gRuleSetTreasureGuards,
543
- gBuffObjects,
544
541
  gBases
545
542
  ]);
546
543
 
@@ -555,7 +552,6 @@ SampleGenerator0.addGenerator(gConnectRooms);
555
552
  SampleGenerator0.addGenerator(gRoads);
556
553
  SampleGenerator0.addGenerator(gRoadDecorators);
557
554
  SampleGenerator0.addGenerator(gBases);
558
- SampleGenerator0.addGenerator(gBuffObjects);
559
555
  SampleGenerator0.addGenerator(gPlaceStartingPoint);
560
556
  SampleGenerator0.addGenerator(gBuildDistanceMap);
561
557
  SampleGenerator0.addGenerator(gRuleSet1);
@@ -0,0 +1,215 @@
1
+ import { EngineHarness } from "../../engine/EngineHarness.js";
2
+ import RenderSystem from "../../engine/ecs/systems/RenderSystem.js";
3
+ import { Camera } from "../../engine/graphics/ecs/camera/Camera.js";
4
+ import TopDownCameraController from "../../engine/graphics/ecs/camera/topdown/TopDownCameraController.js";
5
+ import Vector3 from "../../core/geom/Vector3.js";
6
+ import { TopDownCameraLander } from "../../engine/graphics/ecs/camera/topdown/TopDownCameraLander.js";
7
+ import Terrain from "../../engine/ecs/terrain/ecs/Terrain.js";
8
+ import { TerrainFlags } from "../../engine/ecs/terrain/ecs/TerrainFlags.js";
9
+ import Water from "../../engine/graphics/ecs/water/Water.js";
10
+ import GridObstacle from "../../engine/grid/components/GridObstacle.js";
11
+ import EntityBuilder from "../../engine/ecs/EntityBuilder.js";
12
+ import GridPosition from "../../engine/grid/components/GridPosition.js";
13
+ import { Transform } from "../../engine/ecs/transform/Transform.js";
14
+ import { GridData } from "../grid/GridData.js";
15
+ import { computeStringHash } from "../../core/primitives/strings/computeStringHash.js";
16
+ import { ThemeEngine } from "../theme/ThemeEngine.js";
17
+ import { AreaTheme } from "../theme/AreaTheme.js";
18
+ import TaskGroup from "../../core/process/task/TaskGroup.js";
19
+ import { actionTask } from "../../core/process/task/TaskUtils.js";
20
+ import { generateTerrainPreview } from "../../../../generator/generator/generateTerrainPreview.js";
21
+ import { SampleTheme0 } from "./themes/SampleTheme0.js";
22
+ import { SampleGenerator0 } from "./SampleGenerator0.js";
23
+ import { configureMirGrid } from "./grid/configureMirGrid.js";
24
+ import { EngineConfiguration } from "../../engine/EngineConfiguration.js";
25
+ import TerrainSystem from "../../engine/ecs/terrain/ecs/TerrainSystem.js";
26
+ import WaterSystem from "../../engine/graphics/ecs/water/WaterSystem.js";
27
+ import { MeshSystem } from "../../engine/graphics/ecs/mesh/MeshSystem.js";
28
+ import TopDownCameraControllerSystem from "../../engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js";
29
+ import { TopDownCameraLanderSystem } from "../../engine/graphics/ecs/camera/topdown/TopDownCameraLanderSystem.js";
30
+ import LightSystem from "../../engine/graphics/ecs/light/LightSystem.js";
31
+
32
+ function makeEngineConfig(engine) {
33
+ const config = new EngineConfiguration();
34
+
35
+ const graphics = engine.graphics;
36
+
37
+ config.addSystem(new RenderSystem(graphics));
38
+ config.addSystem(new TerrainSystem(graphics, engine.assetManager));
39
+ config.addSystem(new WaterSystem(graphics));
40
+ config.addSystem(new MeshSystem(engine));
41
+ config.addSystem(new TopDownCameraControllerSystem());
42
+ config.addSystem(new TopDownCameraLanderSystem());
43
+ config.addSystem(new LightSystem(engine))
44
+
45
+ return config;
46
+ }
47
+
48
+
49
+ /**
50
+ *
51
+ * @param {EngineHarness} harness
52
+ * @return {Promise<void>}
53
+ */
54
+ async function init(harness) {
55
+ const engine = harness.engine;
56
+
57
+ await makeEngineConfig(engine).apply(engine);
58
+
59
+ await harness.initialize();
60
+
61
+ main(engine);
62
+ }
63
+
64
+ function prepare_gen_task({
65
+ SIZE_X = 64,
66
+ SIZE_Y = 64,
67
+ ecd
68
+ }) {
69
+
70
+ const camera = EngineHarness.buildCamera({
71
+ engine,
72
+ target: new Vector3(15, 0, 16),
73
+ // pitch: -PI_HALF,
74
+ pitch: 1.1,
75
+ yaw: 3.14,
76
+ distance: 13,
77
+ ecd,
78
+ distanceMin: 5,
79
+ distanceMax: 30
80
+ });
81
+
82
+ camera.add(new TopDownCameraLander());
83
+
84
+ // build lights
85
+ EngineHarness.buildLights({ engine })
86
+
87
+
88
+ // build terrain
89
+ const terrain = new Terrain();
90
+
91
+ terrain.resolution = 4;
92
+
93
+ terrain.size.set(SIZE_X, SIZE_Y);
94
+ terrain.samplerHeight.resize(SIZE_X, SIZE_Y);
95
+ terrain.splat.resize(SIZE_X * 4, SIZE_Y * 4, 0);
96
+
97
+ terrain.layers.resolution.set(512, 512);
98
+
99
+ terrain.clearFlag(TerrainFlags.Built);
100
+ terrain.build(engine.assetManager);
101
+
102
+ const water = new Water();
103
+
104
+ water.color.setRGB(0.2, 0.0, 0.5);
105
+ water.shoreColor.setRGB(0.3, 0.3, 1);
106
+ water.shoreDepthTransition.set(0.16, 0.5);
107
+ water.waveFrequency.set(1.3);
108
+ water.waveAmplitude.set(0.15);
109
+ water.waveSpeed.set(1.2);
110
+ water.scattering.set(1.2);
111
+ water.level.set(-0.3);
112
+
113
+ const obstacle = new GridObstacle();
114
+ obstacle.resize(terrain.size.x, terrain.size.y);
115
+
116
+ const terrainBuilder = new EntityBuilder();
117
+
118
+ terrainBuilder
119
+ .add(terrain)
120
+ .add(water)
121
+ .add(obstacle)
122
+ .add(new GridPosition())
123
+ .add(new Transform())
124
+ .build(ecd);
125
+
126
+
127
+ const gridData = new GridData();
128
+
129
+ configureMirGrid(gridData);
130
+
131
+ gridData.resize(terrain.size.x, terrain.size.y);
132
+ gridData.computeScale(1);
133
+
134
+ const generator = SampleGenerator0;
135
+
136
+ const tGenerationTask = generator.generate(ecd, gridData, computeStringHash('alexx855'));
137
+
138
+
139
+ const themeEngine = new ThemeEngine();
140
+ themeEngine.assetManager = engine.assetManager;
141
+
142
+ const theme0 = new AreaTheme();
143
+
144
+ const width = gridData.width;
145
+ const height = gridData.height;
146
+
147
+ theme0.mask.resize(width, height);
148
+ theme0.mask.mask.fill(0, 0, width, height, [1]);
149
+ theme0.theme = SampleTheme0;
150
+
151
+ themeEngine.add(theme0);
152
+
153
+
154
+ themeEngine.random.setCurrentSeed(1);
155
+ const tTheme = themeEngine.apply(gridData, ecd);
156
+
157
+ tTheme.addDependency(tGenerationTask);
158
+
159
+
160
+ const tBuildLevel = new TaskGroup([tGenerationTask, tTheme]);
161
+
162
+
163
+ const tAddGameplayElements = actionTask(() => {
164
+ // prepare gameplay-specific things on top of the generated level
165
+
166
+ //build minimap
167
+ const terrainPreview = generateTerrainPreview(terrainBuilder.entity, ecd);
168
+ terrain.preview.copy(terrainPreview);
169
+ });
170
+
171
+ tAddGameplayElements.addDependency(tBuildLevel);
172
+
173
+ return new TaskGroup([tBuildLevel, tAddGameplayElements]);
174
+ }
175
+
176
+ /**
177
+ *
178
+ * @param {Engine} engine
179
+ */
180
+ function main(engine) {
181
+ const ecd = engine.entityManager.dataset;
182
+
183
+ const tBuildLevel = prepare_gen_task({ ecd });
184
+
185
+ engine.loadSlowTask(tBuildLevel);
186
+
187
+ engine.executor.runGroup(tBuildLevel);
188
+
189
+ tBuildLevel.promise().then(() => {
190
+ console.log('Generation took ', tBuildLevel.getExecutedCpuTime(), 'ms');
191
+
192
+ const camera = ecd.getAnyComponent(Camera);
193
+
194
+ EngineHarness.buildOrbitalCameraController({
195
+ cameraEntity: camera.entity,
196
+ engine
197
+ });
198
+
199
+ // tweak camera for prototyping
200
+ const ctrl = ecd.getComponent(camera.entity, TopDownCameraController);
201
+ if (ctrl !== undefined) {
202
+ ctrl.distanceMax = 200;
203
+ }
204
+
205
+ });
206
+
207
+ // Resume audio context
208
+ engine.devices.pointer.on.down.addOne(engine.sound.resumeContext, engine.sound);
209
+ engine.devices.pointer.on.wheel.addOne(engine.sound.resumeContext, engine.sound);
210
+
211
+ }
212
+
213
+ const engineHarness = new EngineHarness();
214
+
215
+ init(engineHarness);
@@ -46,6 +46,8 @@ import { SoundEmitter } from "../../../engine/sound/ecs/emitter/SoundEmitter.js"
46
46
  import { SampleGroundMoistureFilter } from "../filters/SampleGroundMoistureFilter.js";
47
47
  import GeneratedArmy from "../../../../model/game/ecs/component/generator/army/GeneratedArmy.js";
48
48
  import { MirMarkerTypes } from "../../../../generator/MirMarkerTypes.js";
49
+ import { TerrainLayerDescription } from "../../theme/TerrainLayerDescription.js";
50
+ import Vector2 from "../../../core/geom/Vector2.js";
49
51
 
50
52
  export const SampleTheme0 = new Theme();
51
53
 
@@ -123,10 +125,6 @@ const filterSand = CellFilterMultiply.from(
123
125
  filterNotRockAndNotRoad
124
126
  );
125
127
 
126
- const TERRAIN_LAYER_GRASS = 0;
127
- const TERRAIN_LAYER_ROCK = 1;
128
- const TERRAIN_LAYER_SAND = 3;
129
-
130
128
  terrainTheme.rules.push(TerrainLayerRule.from(
131
129
  CellFilterMultiply.from(
132
130
  CellFilterMultiply.from(
@@ -135,22 +133,34 @@ terrainTheme.rules.push(TerrainLayerRule.from(
135
133
  ),
136
134
  filterNotRockAndNotRoad
137
135
  ),
138
- TERRAIN_LAYER_GRASS
136
+ TerrainLayerDescription.from({
137
+ diffuse:'data/textures/materials/Sci-Fi Planet/Grass_02.png',
138
+ size:new Vector2(7,7)
139
+ })
139
140
  ));
140
141
 
141
142
  terrainTheme.rules.push(TerrainLayerRule.from(
142
143
  filterRock,
143
- TERRAIN_LAYER_ROCK
144
+ TerrainLayerDescription.from({
145
+ diffuse:'data/textures/Materials_Stylized/4k JPEG/Stylized_04_Rocks/Stylized_04_Rocks_basecolor.jpg',
146
+ size:new Vector2(7,7)
147
+ })
144
148
  ));
145
149
 
146
150
  terrainTheme.rules.push(TerrainLayerRule.from(
147
151
  filterSand,
148
- TERRAIN_LAYER_SAND
152
+ TerrainLayerDescription.from({
153
+ diffuse:'data/textures/Materials_Stylized/4k JPEG/Stylized_06_Sand/Stylized_06_Sand_basecolor.jpg',
154
+ size:new Vector2(7,7)
155
+ })
149
156
  ));
150
157
 
151
158
  terrainTheme.rules.push(TerrainLayerRule.from(
152
159
  filterRoad,
153
- 2,
160
+ TerrainLayerDescription.from({
161
+ diffuse:'data/textures/Materials_Stylized/4k JPEG/Stylized_02_Stone_Ground/Stylized_02_Stone_Ground_basecolor.jpg',
162
+ size:new Vector2(7,7)
163
+ })
154
164
  ));
155
165
 
156
166
  terrainTheme.rules.push(TerrainLayerRule.from(
@@ -158,7 +168,10 @@ terrainTheme.rules.push(TerrainLayerRule.from(
158
168
  ROAD_FILTER,
159
169
  CellFilterLerp.from(CellFilterLiteralFloat.from(1), CellFilterLiteralFloat.from(0.3), NOISE_10_a)
160
170
  ),
161
- TERRAIN_LAYER_GRASS,
171
+ TerrainLayerDescription.from({
172
+ diffuse:'data/textures/materials/Sci-Fi Planet/Grass_02.png',
173
+ size:new Vector2(7,7)
174
+ }),
162
175
  ));
163
176
 
164
177
  SampleTheme0.terrain = terrainTheme;
@@ -44,7 +44,7 @@ export class GridCellPlacementRule {
44
44
  * @param {Vector2} [offset]
45
45
  * @returns {GridCellPlacementRule}
46
46
  */
47
- static from({ matcher, actions, probability, offset = Vector2.zero }) {
47
+ static from({ matcher, actions, probability = CellFilterLiteralFloat.from(1), offset = Vector2.zero }) {
48
48
 
49
49
  assert.defined(matcher);
50
50
  assert.defined(actions);
@@ -56,10 +56,8 @@ export class GridCellPlacementRule {
56
56
  r.pattern = matcher;
57
57
  r.actions = actions;
58
58
 
59
- if (probability !== undefined) {
60
- assert.equal(probability.isCellFilter, true, 'probability.isCellFilter !== true');
61
- r.probability = probability;
62
- }
59
+ assert.equal(probability.isCellFilter, true, 'probability.isCellFilter !== true');
60
+ r.probability = probability;
63
61
 
64
62
  r.positionOffset.copy(offset);
65
63
 
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.33.67",
8
+ "version": "2.33.71",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",