@woosh/meep-engine 2.33.37 → 2.33.41
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/bvh2/binary/2/BinaryUint32BVH.js +3 -3
- package/core/collection/array/typed/typed_array_copy.js +2 -2
- package/core/geom/3d/aabb/aabb3_matrix4_project_by_corners.js +1 -1
- package/core/geom/3d/morton/mortonEncode_magicbits.js +7 -6
- package/core/geom/3d/morton/v3_morton_encode_transformed.js +15 -11
- package/core/geom/3d/plane/orient3d_fast.js +15 -9
- package/core/geom/3d/tetrahedra/GetDepthForTetrahedronProbe.glsl +43 -0
- package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.js +20 -169
- package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.spec.js +9 -0
- package/core/geom/3d/tetrahedra/tetrahedra_collection.js +454 -0
- package/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +2 -1
- package/core/process/undo/ActionProcessor.js +8 -5
- package/engine/asset/loaders/GLTFAssetLoader.js +4 -8
- package/engine/ecs/System.d.ts +24 -1
- package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +1 -1
- package/engine/graphics/micron/prototypeVirtualGeometry.js +4 -1
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +20 -24
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +1 -1
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -2
- package/engine/graphics/render/buffer/simple-fx/DepthLimitedBlur.js +9 -4
- package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +7 -1
- package/engine/graphics/render/forward_plus/LightManager.js +295 -51
- package/engine/graphics/render/forward_plus/LightManager.spec.js +1 -1
- package/engine/graphics/render/forward_plus/PointLightData.js +9 -13
- package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +10 -1
- package/engine/graphics/render/forward_plus/debug/LightClusterVolumeMaterial.js +1 -1
- package/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js +3 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +31 -18
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -0
- package/engine/graphics/render/forward_plus/model/AbstractLight.js +50 -0
- package/engine/graphics/render/forward_plus/model/Decal.js +68 -0
- package/engine/graphics/render/forward_plus/{PointLight.js → model/PointLight.js} +19 -11
- package/engine/graphics/render/forward_plus/{SpotLight.js → model/SpotLight.js} +20 -12
- package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +6 -5
- package/engine/graphics/render/forward_plus/{prototypeLightManager.js → prototype/prototypeLightManager.js} +100 -25
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +29 -20
- package/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +2 -0
- package/engine/graphics/render/visibility/IncrementalDeltaSet.js +1 -0
- package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +19 -0
- package/engine/graphics/texture/atlas/CachingTextureAtlas.js +99 -0
- package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +19 -39
- package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +75 -0
- package/engine/graphics/texture/atlas/TextureAtlas.js +22 -2
- package/engine/reference/v2/Reference.d.ts +4 -0
- package/engine/reference/v2/Reference.js +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,454 @@
|
|
|
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
|
+
import { typed_array_copy } from "../../../collection/array/typed/typed_array_copy.js";
|
|
6
|
+
import { max3 } from "../../../math/max3.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {number}
|
|
11
|
+
*/
|
|
12
|
+
const LAYOUT_TETRA_BYTE_SIZE = 9 * 4;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {number}
|
|
17
|
+
*/
|
|
18
|
+
const INVALID_NEIGHBOUR = 0xFFFFFFFF;
|
|
19
|
+
|
|
20
|
+
class Cavity {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.indices = [];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
this.size = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
update() {
|
|
32
|
+
// compute in/out state for each side of each tetra
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @param {number} i
|
|
38
|
+
*/
|
|
39
|
+
push(i) {
|
|
40
|
+
this.indices[this.size++] = i;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
* @param {number} i
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
includes(i) {
|
|
49
|
+
const n = this.size;
|
|
50
|
+
for (let j = 0; j < n; j++) {
|
|
51
|
+
if (this.indices[j] === i) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
reset() {
|
|
60
|
+
this.size = 0;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const SCRATCH_CAVITY = new Cavity();
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
* Layout:
|
|
69
|
+
* vertex_id_a :: uint
|
|
70
|
+
* vertex_id_b :: uint
|
|
71
|
+
* vertex_id_c :: uint
|
|
72
|
+
* vertex_id_d :: uint
|
|
73
|
+
* neighbour_a :: uint - neighbour tetrahedron, opposite to vertex A
|
|
74
|
+
* neighbour_b :: uint - neighbour tetrahedron, opposite to vertex B
|
|
75
|
+
* neighbour_c :: uint - neighbour tetrahedron, opposite to vertex C
|
|
76
|
+
* neighbour_d :: uint - neighbour tetrahedron, opposite to vertex D
|
|
77
|
+
* sub_determinant :: float - ?
|
|
78
|
+
* Layout is similar to [1], but is interleaved for better cache locality
|
|
79
|
+
*/
|
|
80
|
+
export class TetrahedraCollection {
|
|
81
|
+
constructor(initial_size) {
|
|
82
|
+
this.__buffer = new ArrayBuffer(initial_size * LAYOUT_TETRA_BYTE_SIZE);
|
|
83
|
+
|
|
84
|
+
this.__view = new DataView(this.__buffer);
|
|
85
|
+
|
|
86
|
+
this.__capacity = initial_size;
|
|
87
|
+
this.__length = 0;
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Marks which indices are in use
|
|
92
|
+
* @type {BitSet}
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
this.__occupancy = new BitSet();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
*
|
|
100
|
+
* @param {number} n
|
|
101
|
+
*/
|
|
102
|
+
setCapacity(n) {
|
|
103
|
+
if (n === this.__capacity) {
|
|
104
|
+
// do nothing
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (n < this.__length) {
|
|
109
|
+
throw new Error('Dropping information, not supported');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// allocate new buffer
|
|
113
|
+
const new_buffer = new ArrayBuffer(n * LAYOUT_TETRA_BYTE_SIZE);
|
|
114
|
+
|
|
115
|
+
// move data across from old buffer to the new one
|
|
116
|
+
const destination_uint8 = new Uint8Array(new_buffer);
|
|
117
|
+
const source_uint8 = new Uint8Array(this.__buffer);
|
|
118
|
+
|
|
119
|
+
typed_array_copy(source_uint8, destination_uint8);
|
|
120
|
+
|
|
121
|
+
// set new buffer
|
|
122
|
+
this.__buffer = new_buffer;
|
|
123
|
+
this.__view = new DataView(new_buffer);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
*
|
|
128
|
+
* @param {number} n
|
|
129
|
+
*/
|
|
130
|
+
ensureCapacity(n) {
|
|
131
|
+
|
|
132
|
+
const new_capacity = max3(
|
|
133
|
+
n,
|
|
134
|
+
this.__capacity * 1.2,
|
|
135
|
+
this.__capacity + 32
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
this.setCapacity(new_capacity);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
*
|
|
143
|
+
* @param {number} tetra_index
|
|
144
|
+
* @param {number} neighbour_index
|
|
145
|
+
* @returns {number}
|
|
146
|
+
*/
|
|
147
|
+
getNeighbour(tetra_index, neighbour_index) {
|
|
148
|
+
const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
|
|
149
|
+
return this.__view.getUint32(tetra_address + (4 + neighbour_index) * 4);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
*
|
|
154
|
+
* @param {number} tetra_index
|
|
155
|
+
* @param {number} neighbour_index which neighbour to set (0..11)
|
|
156
|
+
* @param {number} neighbour index of the neighbour
|
|
157
|
+
*/
|
|
158
|
+
setNeighbour(tetra_index, neighbour_index, neighbour) {
|
|
159
|
+
const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
|
|
160
|
+
return this.__view.setUint32(tetra_address + (4 + neighbour_index) * 4, neighbour);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
*
|
|
165
|
+
* @param {number[]|Float32Array} points
|
|
166
|
+
* @param {number} a
|
|
167
|
+
* @param {number} b
|
|
168
|
+
* @param {number} c
|
|
169
|
+
* @param {number} d
|
|
170
|
+
* @returns {number} index of the new tetra
|
|
171
|
+
*/
|
|
172
|
+
append(points, a, b, c, d) {
|
|
173
|
+
const tetra_index = this.__occupancy.nextClearBit(0);
|
|
174
|
+
const address = tetra_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
175
|
+
|
|
176
|
+
if (tetra_index >= this.__capacity) {
|
|
177
|
+
// needs to be increased in size
|
|
178
|
+
this.ensureCapacity(tetra_index);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const view = this.__view;
|
|
182
|
+
|
|
183
|
+
view.setUint32(address, a);
|
|
184
|
+
view.setUint32(address + 4, b);
|
|
185
|
+
view.setUint32(address + 8, c);
|
|
186
|
+
view.setUint32(address + 12, d);
|
|
187
|
+
|
|
188
|
+
// set neighbours
|
|
189
|
+
view.setUint32(address + 16, INVALID_NEIGHBOUR);
|
|
190
|
+
view.setUint32(address + 20, INVALID_NEIGHBOUR);
|
|
191
|
+
view.setUint32(address + 24, INVALID_NEIGHBOUR);
|
|
192
|
+
view.setUint32(address + 28, INVALID_NEIGHBOUR);
|
|
193
|
+
|
|
194
|
+
this.__occupancy.set(tetra_index, true);
|
|
195
|
+
|
|
196
|
+
this.__length++;
|
|
197
|
+
|
|
198
|
+
return tetra_index;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Remove tetrahedron
|
|
203
|
+
* @param {number} tera_index
|
|
204
|
+
*/
|
|
205
|
+
remove(tera_index) {
|
|
206
|
+
|
|
207
|
+
// find neighbours and remove reference to self
|
|
208
|
+
for (let i = 0; i < 4; i++) {
|
|
209
|
+
const neighbour_encoded = this.getNeighbour(tera_index, i);
|
|
210
|
+
|
|
211
|
+
if (neighbour_encoded === INVALID_NEIGHBOUR) {
|
|
212
|
+
// no neighbour
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// get tetrahedra index and point index
|
|
217
|
+
const neighbour_index = neighbour_encoded >> 2;
|
|
218
|
+
const neighbour_point = neighbour_encoded & 4;
|
|
219
|
+
|
|
220
|
+
// clear reference to self
|
|
221
|
+
this.setNeighbour(neighbour_index, neighbour_point, INVALID_NEIGHBOUR);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// mark as dead
|
|
225
|
+
this.__occupancy.clear(tera_index);
|
|
226
|
+
this.__length--;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Remove tetrahedrons who's points touch the "super-tetrahedron's" points that was inserted originally
|
|
231
|
+
* These points are identified by an offset + count parameters
|
|
232
|
+
* @param {number[]|Float32Array} points
|
|
233
|
+
* @param {number} range_start
|
|
234
|
+
* @param {number} range_end
|
|
235
|
+
*/
|
|
236
|
+
removeTetrasConnectedToPoints(points, range_start, range_end) {
|
|
237
|
+
const data_view = this.__view;
|
|
238
|
+
|
|
239
|
+
let i = 0;
|
|
240
|
+
let j = 0;
|
|
241
|
+
|
|
242
|
+
const occupancy = this.__occupancy;
|
|
243
|
+
for (i = occupancy.nextSetBit(0); i !== -1; i = occupancy.nextSetBit(i + 1)) {
|
|
244
|
+
|
|
245
|
+
const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
|
|
246
|
+
|
|
247
|
+
for (j = 0; j < 4; j++) {
|
|
248
|
+
const point_index = data_view.getUint32(tet_address + 4 * i);
|
|
249
|
+
|
|
250
|
+
if (point_index >= range_start && point_index <= range_end) {
|
|
251
|
+
// point index is in range, tetra should be removed
|
|
252
|
+
this.remove(i);
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
*
|
|
261
|
+
* @param {number[]} points
|
|
262
|
+
* @param {number} index
|
|
263
|
+
* @returns {number} index of tetra or -1 if no containing tetra found
|
|
264
|
+
*/
|
|
265
|
+
findTetraContainingPoint(points, index) {
|
|
266
|
+
const data_view = this.__view;
|
|
267
|
+
|
|
268
|
+
// TODO improve this
|
|
269
|
+
const n = this.__length;
|
|
270
|
+
for (let i = 0; i < n; i++) {
|
|
271
|
+
|
|
272
|
+
const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
|
|
273
|
+
|
|
274
|
+
const a = data_view.getUint32(tet_address);
|
|
275
|
+
const b = data_view.getUint32(tet_address + 4);
|
|
276
|
+
const c = data_view.getUint32(tet_address + 8);
|
|
277
|
+
const d = data_view.getUint32(tet_address + 12);
|
|
278
|
+
|
|
279
|
+
if (tetrahedron_contains_point(points, a, b, c, d, index)) {
|
|
280
|
+
return i;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return -1;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
*
|
|
289
|
+
* @param {Cavity} cavity
|
|
290
|
+
* @param {number[]|Float32Array} points
|
|
291
|
+
* @param {number} index
|
|
292
|
+
*/
|
|
293
|
+
computeCavity(cavity, points, index) {
|
|
294
|
+
|
|
295
|
+
// 1.identify tetrahedron that contains this point
|
|
296
|
+
const containing_tetra = this.findTetraContainingPoint(points, index);
|
|
297
|
+
|
|
298
|
+
assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
|
|
299
|
+
|
|
300
|
+
cavity.reset();
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
*
|
|
304
|
+
* @type {number[]}
|
|
305
|
+
*/
|
|
306
|
+
const open_set = [
|
|
307
|
+
containing_tetra
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
*
|
|
312
|
+
* @type {number[]}
|
|
313
|
+
*/
|
|
314
|
+
const closed_set = [];
|
|
315
|
+
|
|
316
|
+
const data_view = this.__view;
|
|
317
|
+
|
|
318
|
+
// 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
|
|
319
|
+
// perform breadth-first expansion on the containing tetra to identify the cavity
|
|
320
|
+
while (open_set.length > 0) {
|
|
321
|
+
const tetra = open_set.pop();
|
|
322
|
+
cavity.push(tetra);
|
|
323
|
+
closed_set.push(tetra);
|
|
324
|
+
|
|
325
|
+
// get neighbours
|
|
326
|
+
for (let i = 0; i < 4; i++) {
|
|
327
|
+
const neighbour_encoded = this.getNeighbour(tetra, i);
|
|
328
|
+
const neighbour_tetra_index = neighbour_encoded >> 2;
|
|
329
|
+
|
|
330
|
+
if (
|
|
331
|
+
(neighbour_encoded === INVALID_NEIGHBOUR) // no neighbour
|
|
332
|
+
|| closed_set.includes(neighbour_tetra_index) // already visited
|
|
333
|
+
|| open_set.includes(neighbour_tetra_index) // already in open set
|
|
334
|
+
) {
|
|
335
|
+
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const neighbour_address = neighbour_tetra_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
340
|
+
|
|
341
|
+
const a = data_view.getUint32(neighbour_address);
|
|
342
|
+
const b = data_view.getUint32(neighbour_address + 4);
|
|
343
|
+
const c = data_view.getUint32(neighbour_address + 8);
|
|
344
|
+
const d = data_view.getUint32(neighbour_address + 12);
|
|
345
|
+
|
|
346
|
+
// check neighbour
|
|
347
|
+
const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, index);
|
|
348
|
+
|
|
349
|
+
if (is_in_sphere) {
|
|
350
|
+
open_set.push(neighbour_tetra_index);
|
|
351
|
+
} else {
|
|
352
|
+
// move directly to closed set
|
|
353
|
+
closed_set.push(neighbour_tetra_index);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
*
|
|
363
|
+
* @param {number[]|Float32Array} points
|
|
364
|
+
* @param {number} index
|
|
365
|
+
*/
|
|
366
|
+
insertPoint(points, index) {
|
|
367
|
+
// Compute the cavity, that is the set of tetrahedra that need to be removed and rebuilt
|
|
368
|
+
this.computeCavity(SCRATCH_CAVITY, points, index);
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
// identify cavity "edge" - the set of tetras that are neighbours of the tetras that form the cavity
|
|
372
|
+
const cavity_size = SCRATCH_CAVITY.size;
|
|
373
|
+
const cavity_indices = SCRATCH_CAVITY.indices;
|
|
374
|
+
const data = this.__view;
|
|
375
|
+
|
|
376
|
+
for (let i = 0; i < cavity_size; i++) {
|
|
377
|
+
const cavity_index = cavity_indices[i];
|
|
378
|
+
|
|
379
|
+
// take each side of the tetra
|
|
380
|
+
const tetra_address = cavity_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
381
|
+
|
|
382
|
+
const a = data.getUint32(tetra_address);
|
|
383
|
+
const b = data.getUint32(tetra_address + 4);
|
|
384
|
+
const c = data.getUint32(tetra_address + 8);
|
|
385
|
+
const d = data.getUint32(tetra_address + 12);
|
|
386
|
+
|
|
387
|
+
// attempt to form 4 tetras using the sides of the cavity
|
|
388
|
+
const a_neighbour = data.getUint32(tetra_address + 16);
|
|
389
|
+
const a_neighbour_index = a_neighbour >> 2;
|
|
390
|
+
|
|
391
|
+
const b_neighbour = data.getUint32(tetra_address + 20);
|
|
392
|
+
const b_neighbour_index = b_neighbour >> 2;
|
|
393
|
+
|
|
394
|
+
const c_neighbour = data.getUint32(tetra_address + 24);
|
|
395
|
+
const c_neighbour_index = c_neighbour >> 2;
|
|
396
|
+
|
|
397
|
+
const d_neighbour = data.getUint32(tetra_address + 28);
|
|
398
|
+
const d_neighbour_index = d_neighbour >> 2;
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
if (a_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(a_neighbour_index) === 0) {
|
|
402
|
+
// ABC is a valid side
|
|
403
|
+
const tet = this.append(points, b, d, c, index);
|
|
404
|
+
// patch in neighbours
|
|
405
|
+
if (a_neighbour !== INVALID_NEIGHBOUR) {
|
|
406
|
+
this.setNeighbour(tet, 3, a_neighbour);
|
|
407
|
+
this.setNeighbour(a_neighbour_index, a_neighbour & 3, tet);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (b_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(b_neighbour_index) === 0) {
|
|
411
|
+
// ABC is a valid side
|
|
412
|
+
const tet = this.append(points, c, d, a, index);
|
|
413
|
+
if (b_neighbour !== INVALID_NEIGHBOUR) {
|
|
414
|
+
this.setNeighbour(tet, 3, b_neighbour);
|
|
415
|
+
this.setNeighbour(b_neighbour_index, b_neighbour & 3, tet);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (c_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(c_neighbour_index) === 0) {
|
|
419
|
+
// ABC is a valid side
|
|
420
|
+
const tet = this.append(points, d, b, a, index);
|
|
421
|
+
if (c_neighbour !== INVALID_NEIGHBOUR) {
|
|
422
|
+
this.setNeighbour(tet, 3, c_neighbour);
|
|
423
|
+
this.setNeighbour(c_neighbour_index, c_neighbour & 3, tet);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (d_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(d_neighbour_index) === 0) {
|
|
427
|
+
// ABC is a valid side
|
|
428
|
+
const tet = this.append(points, a, b, c, index);
|
|
429
|
+
if (d_neighbour !== INVALID_NEIGHBOUR) {
|
|
430
|
+
this.setNeighbour(tet, 3, d_neighbour);
|
|
431
|
+
this.setNeighbour(d_neighbour_index, d_neighbour & 3, tet);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
// 3. remove the cavity tetrahedrons
|
|
438
|
+
for (let i = 0; i < cavity_size; i++) {
|
|
439
|
+
const cavity_index = cavity_indices[i];
|
|
440
|
+
|
|
441
|
+
// clear out cavity, connectivity was already patched in the previous step
|
|
442
|
+
this.__occupancy.set(cavity_index, false);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* optimize tetrahedrons to reduce number of thin and long tetras
|
|
448
|
+
* @see https://gitlab.onelab.info/gmsh/gmsh/-/blob/master/contrib/hxt/tetMesh/src/HXTSPR.c
|
|
449
|
+
*/
|
|
450
|
+
optimize() {
|
|
451
|
+
|
|
452
|
+
throw new Error('Not Implemented');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
@@ -17,7 +17,8 @@ import { orient3d_fast } from "../plane/orient3d_fast.js";
|
|
|
17
17
|
* @returns {boolean}
|
|
18
18
|
*/
|
|
19
19
|
export function tetrahedron_contains_point(points, a, b, c, d, e) {
|
|
20
|
-
return !(
|
|
20
|
+
return !(
|
|
21
|
+
orient3d_fast(points, b, d, c, e) > 0
|
|
21
22
|
|| orient3d_fast(points, c, d, a, e) > 0
|
|
22
23
|
|| orient3d_fast(points, d, b, a, e) > 0
|
|
23
24
|
|| orient3d_fast(points, a, b, c, e) > 0
|
|
@@ -100,20 +100,20 @@ export class ActionProcessor {
|
|
|
100
100
|
*/
|
|
101
101
|
clear() {
|
|
102
102
|
// drop all of the history
|
|
103
|
-
this.dropHistory(
|
|
103
|
+
this.dropHistory(Infinity);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
* Drop
|
|
107
|
+
* Drop number of records from the history
|
|
108
108
|
*
|
|
109
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
|
|
110
110
|
* NOTE this method is used internally by {@link #mark} method
|
|
111
111
|
*
|
|
112
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.
|
|
113
|
-
* @param {number}
|
|
113
|
+
* @param {number} drop_count maximum number of records to drop
|
|
114
114
|
*/
|
|
115
|
-
dropHistory(
|
|
116
|
-
const recordsToDrop = Math.min(
|
|
115
|
+
dropHistory(drop_count) {
|
|
116
|
+
const recordsToDrop = Math.min(drop_count, this.history.length);
|
|
117
117
|
if (recordsToDrop <= 0) {
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
@@ -144,6 +144,9 @@ export class ActionProcessor {
|
|
|
144
144
|
|
|
145
145
|
// dispatch signal
|
|
146
146
|
dropped_marks.forEach(this.onMarkRemoved.send1, this.onMarkRemoved);
|
|
147
|
+
|
|
148
|
+
// update history
|
|
149
|
+
|
|
147
150
|
}
|
|
148
151
|
|
|
149
152
|
/**
|
|
@@ -337,16 +337,12 @@ export class GLTFAssetLoader extends AssetLoader {
|
|
|
337
337
|
return;
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
//find a child that is a mesh
|
|
341
|
-
const meshes = scene.children.filter(isMesh);
|
|
342
340
|
|
|
343
|
-
let root;
|
|
341
|
+
let root = scene;
|
|
344
342
|
|
|
345
|
-
if (
|
|
346
|
-
//use
|
|
347
|
-
root =
|
|
348
|
-
} else {
|
|
349
|
-
root = meshes[0];
|
|
343
|
+
if (children.length === 1 && isMesh(children[0])) {
|
|
344
|
+
// scene only contains a single mesh, use that directly
|
|
345
|
+
root = children[0];
|
|
350
346
|
}
|
|
351
347
|
|
|
352
348
|
traverseThreeObject(root, this.__prepareObjectMaterial, this);
|
package/engine/ecs/System.d.ts
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import {EntityManager} from "./EntityManager";
|
|
2
2
|
|
|
3
|
+
interface Type<T> extends Function {
|
|
4
|
+
new(...args: any[]): T;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class System<A, B = undefined, C = undefined, D = undefined, E = undefined> {
|
|
8
|
+
dependencies: Type<any>[]
|
|
9
|
+
|
|
10
|
+
startup(em: EntityManager, ready_callback: () => void, error_callback: () => void): void
|
|
11
|
+
|
|
12
|
+
shutdown(em: EntityManager, ready_callback: () => void, error_callback: () => void): void
|
|
13
|
+
|
|
14
|
+
link(a: A, entity: number): void
|
|
15
|
+
link(a: A, b: B, entity: number): void
|
|
16
|
+
link(a: A, b: B, c: C, entity: number): void
|
|
17
|
+
link(a: A, b: B, c: C, d: D, entity: number): void
|
|
18
|
+
link(a: A, b: B, c: C, d: D, e: E, entity: number): void
|
|
19
|
+
|
|
20
|
+
unlink(a: A, entity: number): void
|
|
21
|
+
unlink(a: A, b: B, entity: number): void
|
|
22
|
+
unlink(a: A, b: B, c: C, d: D, entity: number): void
|
|
23
|
+
unlink(a: A, b: B, c: C, d: D, e: E, entity: number): void
|
|
24
|
+
|
|
25
|
+
update(time_delta: number): void
|
|
3
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LightBinding } from "../LightBinding.js";
|
|
2
|
-
import { PointLight } from "../../../../render/forward_plus/PointLight.js";
|
|
2
|
+
import { PointLight } from "../../../../render/forward_plus/model/PointLight.js";
|
|
3
3
|
|
|
4
4
|
export class FPLightBinding extends LightBinding {
|
|
5
5
|
constructor() {
|
|
@@ -456,7 +456,7 @@ function init() {
|
|
|
456
456
|
|
|
457
457
|
// sample_gltf_sponza();
|
|
458
458
|
// sample_gltf_rts_factory();
|
|
459
|
-
sample_lucy();
|
|
459
|
+
// sample_lucy();
|
|
460
460
|
// sample_gltf_hapro_2();
|
|
461
461
|
// sample_gltf_hapro_1();
|
|
462
462
|
// sample_gltf_broken_isiflow();
|
|
@@ -465,6 +465,9 @@ function init() {
|
|
|
465
465
|
// gltf_sample('data/models/moicon/08-clickable-assets/model.gltf');
|
|
466
466
|
// gltf_sample('data/models/moicon/05-ground-floor/model.gltf');
|
|
467
467
|
// gltf_sample('data/models/moicon/isiflow_Oct_15_21/0/model.gltf');
|
|
468
|
+
// gltf_sample('moicon/29_Dec_2021_Nammo/1/model.gltf');
|
|
469
|
+
// gltf_sample('moicon/29_Dec_2021_Nammo/1-onematerial/model.gltf');
|
|
470
|
+
gltf_sample('moicon/29_Dec_2021_Nammo/2/model.gltf');
|
|
468
471
|
|
|
469
472
|
document.addEventListener("mousemove", onDocumentMouseMove);
|
|
470
473
|
|
|
@@ -2,7 +2,6 @@ import { inverseLerp } from "../../../../../../core/math/inverseLerp.js";
|
|
|
2
2
|
import { assert } from "../../../../../../core/assert.js";
|
|
3
3
|
import { max2 } from "../../../../../../core/math/max2.js";
|
|
4
4
|
import { min2 } from "../../../../../../core/math/min2.js";
|
|
5
|
-
import { mix } from "../../../../../../core/math/mix.js";
|
|
6
5
|
import { ParameterLookupTableFlags } from "./ParameterLookupTableFlags.js";
|
|
7
6
|
import { ParameterLookupTableSerializationAdapter } from "../emitter/serde/ParameterLookupTableSerializationAdapter.js";
|
|
8
7
|
import { computeHashIntegerArray } from "../../../../../../core/collection/array/computeHashIntegerArray.js";
|
|
@@ -125,7 +124,7 @@ export class ParameterLookupTable {
|
|
|
125
124
|
*/
|
|
126
125
|
sample(position, result) {
|
|
127
126
|
assert.isNumber(position, 'position');
|
|
128
|
-
assert.greaterThanOrEqual(position, 0, 'position');
|
|
127
|
+
// assert.greaterThanOrEqual(position, 0, 'position');
|
|
129
128
|
// assert.ok(position >= 0 && position <= 1, `position must be between 0 and 1, instead was ${position}`);
|
|
130
129
|
|
|
131
130
|
const itemSize = this.itemSize;
|
|
@@ -140,32 +139,28 @@ export class ParameterLookupTable {
|
|
|
140
139
|
let highIndex = lowIndex;
|
|
141
140
|
let fraction = 0;
|
|
142
141
|
|
|
143
|
-
|
|
144
|
-
for (i = 0; i < numValues; i++) {
|
|
145
|
-
//NOTE: no complex search is used, since for small data sizes linear scan is typically faster
|
|
146
|
-
const p = positions[i];
|
|
142
|
+
if (position <= positions[0]) {
|
|
147
143
|
|
|
148
|
-
|
|
144
|
+
// special case, seek position is at or before the start of the table
|
|
145
|
+
lowIndex = 0;
|
|
146
|
+
highIndex = 0;
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
} else {
|
|
149
|
+
|
|
150
|
+
//find position index
|
|
151
|
+
for (i = 1; i < numValues; i++) {
|
|
152
|
+
//NOTE: no complex search is used, since for small data sizes linear scan is typically faster
|
|
153
|
+
const p = positions[i];
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (i === 0) {
|
|
160
|
-
lowIndex = i;
|
|
161
|
-
fraction = 0;
|
|
162
|
-
} else {
|
|
155
|
+
if (p >= position) {
|
|
156
|
+
// next position if over the seek position
|
|
157
|
+
highIndex = i;
|
|
163
158
|
lowIndex = i - 1;
|
|
164
|
-
const prevPosition = positions[lowIndex];
|
|
165
|
-
fraction = inverseLerp(prevPosition, p, position);
|
|
166
|
-
}
|
|
167
159
|
|
|
168
|
-
|
|
160
|
+
fraction = inverseLerp(positions[lowIndex], p, position);
|
|
161
|
+
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
169
164
|
}
|
|
170
165
|
}
|
|
171
166
|
|
|
@@ -177,7 +172,8 @@ export class ParameterLookupTable {
|
|
|
177
172
|
const lowValue = data[low_offset + i];
|
|
178
173
|
const highValue = data[high_offset + i];
|
|
179
174
|
|
|
180
|
-
|
|
175
|
+
// inlined for speed: mix(low, high, fraction)
|
|
176
|
+
const value = lowValue * (1 - fraction) + highValue * fraction;
|
|
181
177
|
|
|
182
178
|
result[i] = value;
|
|
183
179
|
}
|
|
@@ -117,7 +117,7 @@ export class ShaderManager {
|
|
|
117
117
|
generateMipmaps: true,
|
|
118
118
|
minFilter: LinearMipMapLinearFilter,
|
|
119
119
|
magFilter: LinearFilter,
|
|
120
|
-
anisotropy: 0
|
|
120
|
+
anisotropy: 0 // sprites are always facing the screen, anisotropic filtering would be pointless
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
this.spriteTexture.name = 'Sprite sheet';
|
|
@@ -609,8 +609,8 @@ async function main(engine) {
|
|
|
609
609
|
|
|
610
610
|
engine.graphics.renderer.setClearColor('rgba(99,99,99,1)');
|
|
611
611
|
|
|
612
|
-
|
|
613
|
-
await sample_scene_0(engine);
|
|
612
|
+
await sample_scene_nam(engine);
|
|
613
|
+
// await sample_scene_0(engine);
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
/**
|