@woosh/meep-engine 2.33.34 → 2.33.38
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/collection/HashMap.js +19 -12
- package/core/collection/table/RowFirstTable.js +13 -8
- package/core/collection/table/RowFirstTableSpec.js +6 -0
- package/core/color/Color.js +5 -9
- package/core/color/ColorUtils.js +4 -150
- package/core/color/YCbCr_to_rgb_uint24.js +20 -0
- package/core/color/hsv2rgb.js +54 -0
- package/core/color/int2rgb.js +12 -0
- package/core/color/parseHex.js +18 -0
- package/core/color/rgb2hex.js +16 -0
- package/core/color/rgb2hsv.js +47 -0
- package/core/color/rgb2uint24.js +17 -0
- package/core/color/rgb_to_YCbCr_uint24.js +18 -0
- package/core/geom/3d/aabb/compute_aabb_from_points.js +28 -0
- package/core/geom/3d/plane/orient3d_fast.js +51 -0
- package/core/geom/3d/plane/plane_computeConvex3PlaneIntersection.js +5 -0
- package/core/geom/3d/tetrahedra/GetDepthForTetrahedronProbe.glsl +43 -0
- package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +177 -0
- package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.spec.js +66 -0
- package/core/geom/3d/tetrahedra/compute_circumsphere.js +271 -0
- package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.js +50 -0
- package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.spec.js +14 -0
- package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +77 -0
- package/core/geom/3d/tetrahedra/tetrahedra_collection.js +279 -0
- package/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +25 -0
- package/core/geom/Quaternion.js +4 -0
- package/core/math/hash/murmur3_32.js +39 -0
- package/core/process/undo/ActionProcessor.d.ts +2 -0
- package/core/process/undo/ActionProcessor.js +15 -4
- package/editor/tools/FoliagePaintTool.js +1 -1
- package/editor/tools/GridPaintTool.js +1 -1
- package/engine/ecs/foliage/InstancedFoliage.js +45 -0
- package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +4 -0
- package/engine/ecs/storage/BinaryBufferSerializer.js +48 -38
- package/engine/ecs/storage/binary/collection/BinaryCollectionSerializer.js +1 -1
- package/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +1 -1
- package/engine/ecs/terrain/tiles/TerrainTile.js +1 -1
- package/engine/graphics/GraphicsEngine.js +7 -0
- package/engine/graphics/ecs/mesh/Mesh.js +2 -2
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +13 -0
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +339 -314
- package/engine/graphics/micron/build/PatchRepresentation.js +1 -1
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +1 -1
- package/engine/graphics/micron/build/fill_patch_geometry_data.js +1 -1
- package/engine/graphics/micron/format/serialization/deserialize_patch.js +1 -1
- package/engine/graphics/micron/format/serialization/serialize_patch.js +1 -1
- package/engine/graphics/micron/prototypeVirtualGeometry.js +4 -1
- package/engine/graphics/micron/render/instanced/PatchDataTextures.js +3 -3
- package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +1 -1
- package/engine/graphics/micron/render/instanced/shader/shader_rewrite_standard.js +1 -1
- package/engine/graphics/micron/render/makeThreeMeshFromVirtualGeometry.js +1 -1
- package/engine/graphics/micron/render/v1/MaterialContext.js +0 -24
- package/engine/graphics/micron/render/v1/MaterialVertexSpec.js +2 -2
- package/engine/graphics/micron/render/v1/ThreeVirtualGeometryAdapter.js +1 -1
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +7 -3
- package/engine/graphics/particles/node-based/rendering/billboard/ParticleBillboardShader.js +1 -1
- package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +100 -55
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +6 -1
- package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +1 -0
- package/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.js +1 -1
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +17 -4
- package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +1 -1
- package/engine/graphics/render/visibility/VisibilityComputer.js +8 -7
- package/engine/graphics/shaders/TerrainShader.js +5 -5
- package/engine/graphics/shadows/testShadowMapRendering.js +192 -0
- package/package.json +3 -1
- package/view/elements/ColorPickerView.js +2 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { tetrahedron_contains_point } from "./tetrahedron_contains_point.js";
|
|
2
|
+
import { assert } from "../../../assert.js";
|
|
3
|
+
import { point_in_tetrahedron_circumsphere } from "./point_in_tetrahedron_circumsphere.js";
|
|
4
|
+
import { BitSet } from "../../../binary/BitSet.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @readonly
|
|
8
|
+
* @type {number}
|
|
9
|
+
*/
|
|
10
|
+
const LAYOUT_TETRA_BYTE_SIZE = 9 * 4;
|
|
11
|
+
const INVALID_NEIGHBOUR = 0xFFFFFFFF;
|
|
12
|
+
|
|
13
|
+
class Cavity {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.indices = [];
|
|
16
|
+
this.__size = 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param {number} i
|
|
22
|
+
*/
|
|
23
|
+
push(i) {
|
|
24
|
+
this.indices[this.__size++] = i;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param {number} i
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
includes(i) {
|
|
33
|
+
const n = this.__size;
|
|
34
|
+
for (let j = 0; j < n; j++) {
|
|
35
|
+
if (this.indices[j] === i) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
reset() {
|
|
44
|
+
this.__size = 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const SCRATCH_CAVITY = new Cavity();
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* Layout:
|
|
53
|
+
* vertex_id_a :: uint
|
|
54
|
+
* vertex_id_b :: uint
|
|
55
|
+
* vertex_id_c :: uint
|
|
56
|
+
* vertex_id_d :: uint
|
|
57
|
+
* neighbour_a :: uint - neighbour tetrahedron, opposite to vertex A
|
|
58
|
+
* neighbour_b :: uint - neighbour tetrahedron, opposite to vertex B
|
|
59
|
+
* neighbour_c :: uint - neighbour tetrahedron, opposite to vertex C
|
|
60
|
+
* neighbour_d :: uint - neighbour tetrahedron, opposite to vertex D
|
|
61
|
+
* sub_determinant :: float - ?
|
|
62
|
+
* Layout is similar to [1], but is interleaved for better cache locality
|
|
63
|
+
*/
|
|
64
|
+
export class TetrahedraCollection {
|
|
65
|
+
constructor(initial_size) {
|
|
66
|
+
this.__buffer = new ArrayBuffer(initial_size * 4 * 9);
|
|
67
|
+
|
|
68
|
+
this.__view = new DataView(this.__buffer);
|
|
69
|
+
|
|
70
|
+
this.__capacity = initial_size;
|
|
71
|
+
this.__length = 0;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Marks which indices are in use
|
|
76
|
+
* @type {BitSet}
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
this.__occupancy = new BitSet();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @param {number} tetra_index
|
|
85
|
+
* @param {number} neighbour_index
|
|
86
|
+
* @returns {number}
|
|
87
|
+
*/
|
|
88
|
+
getNeighbour(tetra_index, neighbour_index) {
|
|
89
|
+
const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
|
|
90
|
+
return this.__view.getUint32(tetra_address + (4 + neighbour_index) * 4);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
*
|
|
95
|
+
* @param {number[]|Float32Array} points
|
|
96
|
+
* @param {number} a
|
|
97
|
+
* @param {number} b
|
|
98
|
+
* @param {number} c
|
|
99
|
+
* @param {number} d
|
|
100
|
+
*/
|
|
101
|
+
append(points, a, b, c, d) {
|
|
102
|
+
const tetra_index = this.__length;
|
|
103
|
+
const address = tetra_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
104
|
+
|
|
105
|
+
// TODO check if there's enough room
|
|
106
|
+
|
|
107
|
+
const view = this.__view;
|
|
108
|
+
|
|
109
|
+
view.setUint32(address, a);
|
|
110
|
+
view.setUint32(address + 4, b);
|
|
111
|
+
view.setUint32(address + 8, c);
|
|
112
|
+
view.setUint32(address + 12, d);
|
|
113
|
+
|
|
114
|
+
// set neighbours
|
|
115
|
+
view.setUint32(address + 16, INVALID_NEIGHBOUR);
|
|
116
|
+
view.setUint32(address + 20, INVALID_NEIGHBOUR);
|
|
117
|
+
view.setUint32(address + 24, INVALID_NEIGHBOUR);
|
|
118
|
+
view.setUint32(address + 28, INVALID_NEIGHBOUR);
|
|
119
|
+
|
|
120
|
+
this.__occupancy.set(tetra_index, true);
|
|
121
|
+
|
|
122
|
+
this.__length++;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Remove tetrahedron
|
|
127
|
+
* @param {number} tera_index
|
|
128
|
+
*/
|
|
129
|
+
remove(tera_index) {
|
|
130
|
+
this.__occupancy.clear(tera_index);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Remove tetrahedrons who's points touch the "super-tetrahedron's" points that was inserted originally
|
|
135
|
+
* These points are identified by an offset + count parameters
|
|
136
|
+
* @param {number[]|Float32Array} points
|
|
137
|
+
* @param {number} range_start
|
|
138
|
+
* @param {number} range_end
|
|
139
|
+
*/
|
|
140
|
+
removeTetrasConnectedToPoints(points, range_start, range_end) {
|
|
141
|
+
const data_view = this.__view;
|
|
142
|
+
|
|
143
|
+
const n = this.__length;
|
|
144
|
+
|
|
145
|
+
let i = 0;
|
|
146
|
+
let j = 0;
|
|
147
|
+
|
|
148
|
+
for (; i < n; i++) {
|
|
149
|
+
|
|
150
|
+
const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
|
|
151
|
+
|
|
152
|
+
for (j = 0; j < 4; j++) {
|
|
153
|
+
const point_index = data_view.getUint32(tet_address + 4 * i);
|
|
154
|
+
|
|
155
|
+
if (point_index >= range_start && point_index <= range_end) {
|
|
156
|
+
// point index is in range, tetra should be removed
|
|
157
|
+
this.remove(i);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
*
|
|
165
|
+
* @param {number[]} points
|
|
166
|
+
* @param {number} index
|
|
167
|
+
* @returns {number} index of tetra or -1 if no containing tetra found
|
|
168
|
+
*/
|
|
169
|
+
findTetraContainingPoint(points, index) {
|
|
170
|
+
const data_view = this.__view;
|
|
171
|
+
|
|
172
|
+
// TODO improve this
|
|
173
|
+
const n = this.__length;
|
|
174
|
+
for (let i = 0; i < n; i++) {
|
|
175
|
+
|
|
176
|
+
const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
|
|
177
|
+
|
|
178
|
+
const a = data_view.getUint32(tet_address);
|
|
179
|
+
const b = data_view.getUint32(tet_address + 4);
|
|
180
|
+
const c = data_view.getUint32(tet_address + 8);
|
|
181
|
+
const d = data_view.getUint32(tet_address + 12);
|
|
182
|
+
|
|
183
|
+
if (tetrahedron_contains_point(points, a, b, c, d, index)) {
|
|
184
|
+
return i;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return -1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
* @param {Cavity} cavity
|
|
194
|
+
* @param {number[]|Float32Array} points
|
|
195
|
+
* @param {number} index
|
|
196
|
+
*/
|
|
197
|
+
computeCavity(cavity, points, index) {
|
|
198
|
+
|
|
199
|
+
// 1.identify tetrahedron that contains this point
|
|
200
|
+
const containing_tetra = this.findTetraContainingPoint(points, index);
|
|
201
|
+
|
|
202
|
+
assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
|
|
203
|
+
|
|
204
|
+
cavity.reset();
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
*
|
|
208
|
+
* @type {number[]}
|
|
209
|
+
*/
|
|
210
|
+
const open_set = [
|
|
211
|
+
containing_tetra
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
*
|
|
216
|
+
* @type {number[]}
|
|
217
|
+
*/
|
|
218
|
+
const closed_set = [];
|
|
219
|
+
|
|
220
|
+
const data_view = this.__view;
|
|
221
|
+
|
|
222
|
+
// 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
|
|
223
|
+
// perform breadth-first expansion on the containing tetra to identify the cavity
|
|
224
|
+
while (open_set.length > 0) {
|
|
225
|
+
const tetra = open_set.pop();
|
|
226
|
+
cavity.push(tetra);
|
|
227
|
+
closed_set.push(tetra);
|
|
228
|
+
|
|
229
|
+
// get neighbours
|
|
230
|
+
for (let i = 0; i < 4; i++) {
|
|
231
|
+
const neighbour = this.getNeighbour(tetra, i);
|
|
232
|
+
|
|
233
|
+
if (
|
|
234
|
+
(neighbour === INVALID_NEIGHBOUR) // no neighbour
|
|
235
|
+
|| closed_set.includes(neighbour) // already visited
|
|
236
|
+
|| open_set.includes(neighbour) // already in open set
|
|
237
|
+
) {
|
|
238
|
+
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const neighbour_address = neighbour * LAYOUT_TETRA_BYTE_SIZE;
|
|
243
|
+
|
|
244
|
+
const a = data_view.getUint32(neighbour_address);
|
|
245
|
+
const b = data_view.getUint32(neighbour_address + 4);
|
|
246
|
+
const c = data_view.getUint32(neighbour_address + 8);
|
|
247
|
+
const d = data_view.getUint32(neighbour_address + 12);
|
|
248
|
+
|
|
249
|
+
// check neighbour
|
|
250
|
+
const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, index);
|
|
251
|
+
|
|
252
|
+
if (is_in_sphere) {
|
|
253
|
+
open_set.push(neighbour);
|
|
254
|
+
} else {
|
|
255
|
+
// move directly to closed set
|
|
256
|
+
closed_set.push(neighbour);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
*
|
|
266
|
+
* @param {number[]|Float32Array} points
|
|
267
|
+
* @param {number} index
|
|
268
|
+
*/
|
|
269
|
+
insertPoint(points, index) {
|
|
270
|
+
// Compute the cavity, that is the set of tetrahedra that need to be removed and rebuilt
|
|
271
|
+
this.computeCavity(SCRATCH_CAVITY, points, index);
|
|
272
|
+
|
|
273
|
+
// identify cavity "edge" - the set of tetras that are neighbours of the tetras that form the cavity
|
|
274
|
+
|
|
275
|
+
// 3. remove the cavity tetrahedrons
|
|
276
|
+
|
|
277
|
+
// 4. fill the cavity by creating new tetrahedrons connecting the point to the faces of cavity boundary
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { orient3d_fast } from "../plane/orient3d_fast.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Containment test, whether tetrahedron defined by A,B,C,D contains point E or not
|
|
5
|
+
* Implemented using planar tests on each of side of the tetrahedron
|
|
6
|
+
*
|
|
7
|
+
* NOTE: similar to https://gitlab.onelab.info/gmsh/gmsh/-/blob/master/contrib/hxt/tetMesh/src/HXTSPR.c
|
|
8
|
+
* We skip identity checks and bounding box checks. Identity is a waste of time when building tetrahedral mesh,
|
|
9
|
+
* since each inserted point will be new to the mesh, box checks are not relevant as we don't track those
|
|
10
|
+
*
|
|
11
|
+
* @param {number[]} points
|
|
12
|
+
* @param {number} a
|
|
13
|
+
* @param {number} b
|
|
14
|
+
* @param {number} c
|
|
15
|
+
* @param {number} d
|
|
16
|
+
* @param {number} e
|
|
17
|
+
* @returns {boolean}
|
|
18
|
+
*/
|
|
19
|
+
export function tetrahedron_contains_point(points, a, b, c, d, e) {
|
|
20
|
+
return !(orient3d_fast(points, b, d, c, e) > 0
|
|
21
|
+
|| orient3d_fast(points, c, d, a, e) > 0
|
|
22
|
+
|| orient3d_fast(points, d, b, a, e) > 0
|
|
23
|
+
|| orient3d_fast(points, a, b, c, e) > 0
|
|
24
|
+
);
|
|
25
|
+
}
|
package/core/geom/Quaternion.js
CHANGED
|
@@ -1298,6 +1298,10 @@ class Quaternion {
|
|
|
1298
1298
|
this.set(x, y, z, w);
|
|
1299
1299
|
}
|
|
1300
1300
|
|
|
1301
|
+
/**
|
|
1302
|
+
* Based on GDC talk from Bungie on destiny, compressing quaternions for animation
|
|
1303
|
+
* @param value
|
|
1304
|
+
*/
|
|
1301
1305
|
decodeFromUint32(value) {
|
|
1302
1306
|
//read components
|
|
1303
1307
|
const max = value & 0x3;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NOTE: based on https://github.com/garycourt/murmurhash-js/blob/master/murmurhash3_gc.js
|
|
3
|
+
* @param {Uint32Array} key
|
|
4
|
+
* @param {number} seed
|
|
5
|
+
* @returns {number}
|
|
6
|
+
*/
|
|
7
|
+
export function murmur3_32(key, seed) {
|
|
8
|
+
let h1 = seed;
|
|
9
|
+
let k1;
|
|
10
|
+
let i = 0;
|
|
11
|
+
|
|
12
|
+
const bytes = key.length;
|
|
13
|
+
|
|
14
|
+
while (i < bytes) {
|
|
15
|
+
k1 = key[i];
|
|
16
|
+
++i;
|
|
17
|
+
|
|
18
|
+
k1 = ((((k1 & 0xffff) * 0xcc9e2d51) + ((((k1 >>> 16) * 0xcc9e2d51) & 0xffff) << 16)));
|
|
19
|
+
k1 = (k1 << 15) | (k1 >>> 17);
|
|
20
|
+
k1 = ((((k1 & 0xffff) * 0x1b873593) + ((((k1 >>> 16) * 0x1b873593) & 0xffff) << 16)));
|
|
21
|
+
|
|
22
|
+
h1 ^= k1;
|
|
23
|
+
h1 = (h1 << 13) | (h1 >>> 19);
|
|
24
|
+
h1 = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16)));
|
|
25
|
+
h1 = (((h1 & 0xffff) + 0x6b64) + ((((h1 >>> 16) + 0xe654) & 0xffff) << 16));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// mix in array length
|
|
29
|
+
h1 ^= bytes;
|
|
30
|
+
|
|
31
|
+
h1 ^= h1 >>> 16;
|
|
32
|
+
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16));
|
|
33
|
+
h1 ^= h1 >>> 13;
|
|
34
|
+
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)));
|
|
35
|
+
h1 ^= h1 >>> 16;
|
|
36
|
+
|
|
37
|
+
// cast to uint32
|
|
38
|
+
return h1 >>> 0;
|
|
39
|
+
}
|
|
@@ -96,16 +96,24 @@ export class ActionProcessor {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
99
|
+
* Remove all of the history
|
|
100
|
+
*/
|
|
101
|
+
clear() {
|
|
102
|
+
// drop all of the history
|
|
103
|
+
this.dropHistory(Infinity);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Drop number of records from the history
|
|
100
108
|
*
|
|
101
109
|
* NOTE valid use-cases for this method from the outside are: 1) memory management and 1) removing access to a set of previous actions
|
|
102
110
|
* NOTE this method is used internally by {@link #mark} method
|
|
103
111
|
*
|
|
104
112
|
* @example if there are 2 marks A at record 9 and B at record 11, and requested limit is 10 - 9 records will be kept as records 10 and 11 belong to the same batch and will be removed together.
|
|
105
|
-
* @param {number}
|
|
113
|
+
* @param {number} drop_count maximum number of records to drop
|
|
106
114
|
*/
|
|
107
|
-
dropHistory(
|
|
108
|
-
const recordsToDrop = Math.min(
|
|
115
|
+
dropHistory(drop_count) {
|
|
116
|
+
const recordsToDrop = Math.min(drop_count, this.history.length);
|
|
109
117
|
if (recordsToDrop <= 0) {
|
|
110
118
|
return;
|
|
111
119
|
}
|
|
@@ -136,6 +144,9 @@ export class ActionProcessor {
|
|
|
136
144
|
|
|
137
145
|
// dispatch signal
|
|
138
146
|
dropped_marks.forEach(this.onMarkRemoved.send1, this.onMarkRemoved);
|
|
147
|
+
|
|
148
|
+
// update history
|
|
149
|
+
|
|
139
150
|
}
|
|
140
151
|
|
|
141
152
|
/**
|
|
@@ -2,11 +2,11 @@ import Tool from "./engine/Tool.js";
|
|
|
2
2
|
import Vector1 from "../../core/geom/Vector1.js";
|
|
3
3
|
import { obtainTerrain } from "../../../model/game/scenes/SceneUtils.js";
|
|
4
4
|
import ObservedValue from "../../core/model/ObservedValue.js";
|
|
5
|
-
import { parseHex } from "../../core/color/ColorUtils.js";
|
|
6
5
|
import Vector4 from "../../core/geom/Vector4.js";
|
|
7
6
|
import loadSampler2D from "../../engine/graphics/texture/sampler/loadSampler2D.js";
|
|
8
7
|
import convertSampler2D2Canvas from "../../engine/graphics/texture/sampler/Sampler2D2Canvas.js";
|
|
9
8
|
import { InstancedMeshComponent } from "../../engine/ecs/foliage/ecs/InstancedMeshComponent.js";
|
|
9
|
+
import { parseHex } from "../../core/color/parseHex.js";
|
|
10
10
|
|
|
11
11
|
class FoliagePaintTool extends Tool {
|
|
12
12
|
constructor() {
|
|
@@ -3,7 +3,6 @@ import GridPosition from "../../engine/grid/components/GridPosition.js";
|
|
|
3
3
|
import GridObstacle from "../../engine/grid/components/GridObstacle.js";
|
|
4
4
|
import { pick } from "../../../model/game/util/ScreenGridPicker.js";
|
|
5
5
|
import Vector4 from "../../core/geom/Vector4.js";
|
|
6
|
-
import { parseHex } from "../../core/color/ColorUtils.js";
|
|
7
6
|
import ObservedValue from "../../core/model/ObservedValue.js";
|
|
8
7
|
import Vector1 from "../../core/geom/Vector1.js";
|
|
9
8
|
import WriteGridValueAction from "../actions/concrete/WriteGridValueAction.js";
|
|
@@ -12,6 +11,7 @@ import PaintTerrainOverlayAction from "../actions/concrete/PaintTerrainOverlayAc
|
|
|
12
11
|
import { decodeMouseEventButtons, PointerDevice } from "../../engine/input/devices/PointerDevice.js";
|
|
13
12
|
import Vector2 from "../../core/geom/Vector2.js";
|
|
14
13
|
import TopDownCameraControllerSystem from "../../engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js";
|
|
14
|
+
import { parseHex } from "../../core/color/parseHex.js";
|
|
15
15
|
|
|
16
16
|
class GridPaintTool extends Tool {
|
|
17
17
|
constructor() {
|
|
@@ -61,12 +61,29 @@ export class InstancedFoliage {
|
|
|
61
61
|
*/
|
|
62
62
|
this.instances = new InstancedMeshGroup();
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
* @type {THREE.BufferGeometry|null}
|
|
67
|
+
*/
|
|
64
68
|
this.geometry = null;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @type {Vector4|Vector4}
|
|
73
|
+
*/
|
|
65
74
|
this.instanceBoundingSphere = new Vector4(0, 0, 0, 0);
|
|
66
75
|
|
|
67
76
|
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @type {ThreeFrustumsIntersectionBVHVisitor}
|
|
80
|
+
*/
|
|
68
81
|
this.bvhVisibilityVisitor = new ThreeFrustumsIntersectionBVHVisitor();
|
|
69
82
|
|
|
83
|
+
/**
|
|
84
|
+
*
|
|
85
|
+
* @type {FoliageVisibilitySetBuilder}
|
|
86
|
+
*/
|
|
70
87
|
this.visibilitySetBuilder = new FoliageVisibilitySetBuilder();
|
|
71
88
|
this.bvhVisibilityVisitor.collector = this.visibilitySetBuilder;
|
|
72
89
|
|
|
@@ -84,6 +101,10 @@ export class InstancedFoliage {
|
|
|
84
101
|
this.__garbagePointer = 0;
|
|
85
102
|
}
|
|
86
103
|
|
|
104
|
+
/**
|
|
105
|
+
*
|
|
106
|
+
* @returns {number}
|
|
107
|
+
*/
|
|
87
108
|
hash() {
|
|
88
109
|
return this.data.hash();
|
|
89
110
|
}
|
|
@@ -95,6 +116,25 @@ export class InstancedFoliage {
|
|
|
95
116
|
|
|
96
117
|
}
|
|
97
118
|
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
* @param {SurfacePoint3} contact
|
|
122
|
+
* @param {number} origin_x
|
|
123
|
+
* @param {number} origin_y
|
|
124
|
+
* @param {number} origin_z
|
|
125
|
+
* @param {number} direction_x
|
|
126
|
+
* @param {number} direction_y
|
|
127
|
+
* @param {number} direction_z
|
|
128
|
+
* @returns {number} index of the contact instance, or -1 if no hit found
|
|
129
|
+
*/
|
|
130
|
+
raypick(
|
|
131
|
+
contact,
|
|
132
|
+
origin_x, origin_y, origin_z,
|
|
133
|
+
direction_x, direction_y, direction_z
|
|
134
|
+
) {
|
|
135
|
+
throw new Error('Not implemented');
|
|
136
|
+
}
|
|
137
|
+
|
|
98
138
|
dispose() {
|
|
99
139
|
this.instances.dispose();
|
|
100
140
|
}
|
|
@@ -212,6 +252,11 @@ export class InstancedFoliage {
|
|
|
212
252
|
this.instanceBoundingSphere = computeGeometryBoundingSphereMiniball(this.geometry);
|
|
213
253
|
}
|
|
214
254
|
|
|
255
|
+
/**
|
|
256
|
+
*
|
|
257
|
+
* @param {BufferGeometry} geometry
|
|
258
|
+
* @param {Material} material
|
|
259
|
+
*/
|
|
215
260
|
setInstance(geometry, material) {
|
|
216
261
|
if (material === undefined) {
|
|
217
262
|
throw new Error(`Material is undefined`);
|
|
@@ -5,6 +5,48 @@ import { COMPONENT_SERIALIZATION_TRANSIENT_FIELD } from "./COMPONENT_SERIALIZATI
|
|
|
5
5
|
import { currentTimeInSeconds } from "../../Clock.js";
|
|
6
6
|
import { BinaryObjectSerializationAdapter } from "./binary/object/BinaryObjectSerializationAdapter.js";
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @template T
|
|
10
|
+
* @param {Class<T>|constructor|function|{serializable?:boolean}} componentClass
|
|
11
|
+
* @returns {boolean}
|
|
12
|
+
*/
|
|
13
|
+
function isComponentClassSerializable(componentClass) {
|
|
14
|
+
return componentClass.serializable !== false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether or not an entity should be serialized at all
|
|
19
|
+
* @param {number} entity
|
|
20
|
+
* @param {EntityComponentDataset} dataset
|
|
21
|
+
* @param {number} smComponentIndex
|
|
22
|
+
* @param {Object} componentInstance
|
|
23
|
+
* @returns {boolean}
|
|
24
|
+
*/
|
|
25
|
+
function isEntityTransient(entity, dataset, smComponentIndex, componentInstance) {
|
|
26
|
+
if (smComponentIndex === -1) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//check component instance flag
|
|
31
|
+
if (componentInstance[COMPONENT_SERIALIZATION_TRANSIENT_FIELD] === true) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @type {SerializationMetadata}
|
|
39
|
+
*/
|
|
40
|
+
const serializationMetadata = dataset.getComponentByIndex(entity, smComponentIndex);
|
|
41
|
+
|
|
42
|
+
if (serializationMetadata === undefined) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const isTransient = serializationMetadata.getFlag(SerializationFlags.Transient);
|
|
47
|
+
|
|
48
|
+
return isTransient;
|
|
49
|
+
}
|
|
8
50
|
|
|
9
51
|
class BinaryBufferSerialization {
|
|
10
52
|
constructor() {
|
|
@@ -27,9 +69,8 @@ class BinaryBufferSerialization {
|
|
|
27
69
|
|
|
28
70
|
const smComponentIndex = dataset.computeComponentTypeIndex(SerializationMetadata);
|
|
29
71
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
72
|
+
// get a list of serializable component classes
|
|
73
|
+
const serializableComponentTypes = dataset.getComponentTypeMap().filter(isComponentClassSerializable);
|
|
33
74
|
|
|
34
75
|
const numSerializableTypes = serializableComponentTypes.length;
|
|
35
76
|
|
|
@@ -59,6 +100,9 @@ class BinaryBufferSerialization {
|
|
|
59
100
|
|
|
60
101
|
const className = componentType.typeName;
|
|
61
102
|
|
|
103
|
+
if (className === undefined) {
|
|
104
|
+
throw new Error(`Component type has no .typeName property`);
|
|
105
|
+
}
|
|
62
106
|
|
|
63
107
|
collectionSerializer.setClass(className);
|
|
64
108
|
collectionSerializer.initialize({
|
|
@@ -83,7 +127,7 @@ class BinaryBufferSerialization {
|
|
|
83
127
|
return;
|
|
84
128
|
}
|
|
85
129
|
|
|
86
|
-
assert.ok(entity >= lastEntity, `entity
|
|
130
|
+
assert.ok(entity >= lastEntity, `entity[=${entity}] < lastEntity[=${lastEntity}]`);
|
|
87
131
|
|
|
88
132
|
//write only the entity step
|
|
89
133
|
const step = entity - lastEntity;
|
|
@@ -127,38 +171,4 @@ class BinaryBufferSerialization {
|
|
|
127
171
|
}
|
|
128
172
|
}
|
|
129
173
|
|
|
130
|
-
/**
|
|
131
|
-
* Whether or not an entity should be serialized at all
|
|
132
|
-
* @param {number} entity
|
|
133
|
-
* @param {EntityComponentDataset} dataset
|
|
134
|
-
* @param {number} smComponentIndex
|
|
135
|
-
* @param {Object} componentInstance
|
|
136
|
-
* @returns {boolean}
|
|
137
|
-
*/
|
|
138
|
-
function isEntityTransient(entity, dataset, smComponentIndex, componentInstance) {
|
|
139
|
-
if (smComponentIndex === -1) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
//check component instance flag
|
|
144
|
-
if (componentInstance[COMPONENT_SERIALIZATION_TRANSIENT_FIELD] === true) {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
*
|
|
151
|
-
* @type {SerializationMetadata}
|
|
152
|
-
*/
|
|
153
|
-
const serializationMetadata = dataset.getComponentByIndex(entity, smComponentIndex);
|
|
154
|
-
|
|
155
|
-
if (serializationMetadata === undefined) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const isTransient = serializationMetadata.getFlag(SerializationFlags.Transient);
|
|
160
|
-
|
|
161
|
-
return isTransient;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
174
|
export default BinaryBufferSerialization;
|
|
@@ -10,8 +10,8 @@ import SVG from "../../../../../view/SVG.js";
|
|
|
10
10
|
import Vector2 from "../../../../../core/geom/Vector2.js";
|
|
11
11
|
import Vector4 from "../../../../../core/geom/Vector4.js";
|
|
12
12
|
import { MersenneTwister } from "../../../../../core/math/random/MersenneTwister.js";
|
|
13
|
-
import { hsv2rgb } from "../../../../../core/color/ColorUtils.js";
|
|
14
13
|
import { arrayPickBestElement } from "../../../../../core/collection/array/arrayPickBestElement.js";
|
|
14
|
+
import { hsv2rgb } from "../../../../../core/color/hsv2rgb.js";
|
|
15
15
|
|
|
16
16
|
function removeAllChildren(node) {
|
|
17
17
|
const children = node.children;
|