@woosh/meep-engine 2.76.3 → 2.77.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.
- package/build/meep.cjs +202 -621
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +202 -621
- package/editor/view/ecs/components/TerrainController.js +9 -16
- package/package.json +1 -1
- package/src/core/collection/heap/Uint32Heap.js +10 -1
- package/src/core/graph/Edge.js +20 -0
- package/src/core/graph/Graph.js +1 -0
- package/src/core/graph/SquareMatrix.js +4 -2
- package/src/core/graph/WeightedEdge.js +5 -9
- package/src/core/graph/coloring/validateGraphColoring.js +1 -1
- package/src/core/graph/eigen/matrix_eigenvalues_in_place.js +21 -0
- package/src/core/graph/eigen/{eigen.spec.js → matrix_eigenvalues_in_place.spec.js} +2 -2
- package/src/core/graph/eigen/matrix_householder_in_place.js +92 -0
- package/src/core/graph/eigen/{eigen.js → matrix_qr_in_place.js} +2 -113
- package/src/core/graph/v2/Graph.js +16 -9
- package/src/core/graph/v2/NodeContainer.js +120 -22
- package/src/engine/ecs/storage/binary/BinarySerializationRegistry.js +8 -6
- package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleRegistry.js +1 -1
- package/src/engine/navigation/grid/find_path_on_grid_astar.js +30 -27
- package/src/engine/navigation/grid/find_path_on_grid_astar.spec.js +2 -2
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +17 -33
- package/src/core/graph/GraphUtils.js +0 -284
- package/src/engine/ecs/terrain/ecs/splat/SplatMapMaterialPatch.js +0 -464
- package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +0 -622
- package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +0 -383
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
import { BitSet } from "../../../../../core/binary/BitSet.js";
|
|
2
|
-
import AABB2 from "../../../../../core/geom/AABB2.js";
|
|
3
|
-
import { max2 } from "../../../../../core/math/max2.js";
|
|
4
|
-
import { min2 } from "../../../../../core/math/min2.js";
|
|
5
|
-
import { Sampler2D } from "../../../../graphics/texture/sampler/Sampler2D.js";
|
|
6
|
-
import {
|
|
7
|
-
sampler2d_sub_copy_same_item_size
|
|
8
|
-
} from "../../../../graphics/texture/sampler/sampler2d_sub_copy_same_item_size.js";
|
|
9
|
-
|
|
10
|
-
export class SplatMapMaterialPatch {
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
13
|
-
* @param {number} width
|
|
14
|
-
* @param {number} height
|
|
15
|
-
*/
|
|
16
|
-
constructor(width, height) {
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @type {number}
|
|
21
|
-
*/
|
|
22
|
-
this.width = width;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
* @type {number}
|
|
27
|
-
*/
|
|
28
|
-
this.height = height;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Material that the patch is using
|
|
32
|
-
* @type {number}
|
|
33
|
-
*/
|
|
34
|
-
this.materialIndex = 0;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Which channel should the patch be assigned to
|
|
38
|
-
* @note materials are mapped to one of RGBA channels in the material texture
|
|
39
|
-
* @type {number}
|
|
40
|
-
*/
|
|
41
|
-
this.channel = 0;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Mask representing coverage of the patch
|
|
45
|
-
* @type {BitSet}
|
|
46
|
-
*/
|
|
47
|
-
this.mask = new BitSet();
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
* @type {AABB2}
|
|
52
|
-
*/
|
|
53
|
-
this.aabb = new AABB2();
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
57
|
-
* @type {Uint8Array}
|
|
58
|
-
*/
|
|
59
|
-
this.weights = null;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
*
|
|
63
|
-
* @type {number}
|
|
64
|
-
*/
|
|
65
|
-
this.area = 0;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
69
|
-
* @type {QuadTreeDatum}
|
|
70
|
-
*/
|
|
71
|
-
this.quad = null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
* @param {Sampler2D} materialSampler
|
|
77
|
-
* @param {BitSet} occupancy
|
|
78
|
-
* @returns {number}
|
|
79
|
-
*/
|
|
80
|
-
writeByOccupancy(materialSampler, occupancy) {
|
|
81
|
-
const itemSize = materialSampler.itemSize;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const materialData = materialSampler.data;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const o_bb = this.aabb;
|
|
88
|
-
|
|
89
|
-
const x0 = o_bb.x0;
|
|
90
|
-
const x1 = o_bb.x1;
|
|
91
|
-
|
|
92
|
-
const y0 = o_bb.y0;
|
|
93
|
-
const y1 = o_bb.y1;
|
|
94
|
-
|
|
95
|
-
let failed = 0;
|
|
96
|
-
|
|
97
|
-
for (let y = y0; y < y1; y++) {
|
|
98
|
-
loop_x: for (let x = x0; x < x1; x++) {
|
|
99
|
-
|
|
100
|
-
const masked = this.test(x, y);
|
|
101
|
-
|
|
102
|
-
if (!masked) {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const index = y * this.width + x;
|
|
107
|
-
const address = index * itemSize;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
let targetChannelAddress = 0;
|
|
111
|
-
|
|
112
|
-
for (let i = 0; i < itemSize; i++) {
|
|
113
|
-
targetChannelAddress = address + i;
|
|
114
|
-
|
|
115
|
-
if (!occupancy.get(targetChannelAddress)) {
|
|
116
|
-
|
|
117
|
-
//found a free channel, lets write here
|
|
118
|
-
|
|
119
|
-
materialData[targetChannelAddress] = this.materialIndex;
|
|
120
|
-
occupancy.set(targetChannelAddress, true);
|
|
121
|
-
|
|
122
|
-
continue loop_x;
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
//couldn't find a free channel
|
|
129
|
-
failed++;
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return failed;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
*
|
|
139
|
-
* @param {number} channel
|
|
140
|
-
* @param {Sampler2D} materialSampler
|
|
141
|
-
* @param {BitSet} occupancy
|
|
142
|
-
*/
|
|
143
|
-
write(channel, materialSampler, occupancy) {
|
|
144
|
-
const itemSize = materialSampler.itemSize;
|
|
145
|
-
|
|
146
|
-
if (channel >= itemSize) {
|
|
147
|
-
//channel index is too high, can't write
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const materialData = materialSampler.data;
|
|
152
|
-
|
|
153
|
-
const o_bb = this.aabb;
|
|
154
|
-
|
|
155
|
-
const x0 = o_bb.x0;
|
|
156
|
-
const x1 = o_bb.x1;
|
|
157
|
-
|
|
158
|
-
const y0 = o_bb.y0;
|
|
159
|
-
const y1 = o_bb.y1;
|
|
160
|
-
|
|
161
|
-
for (let y = y0; y < y1; y++) {
|
|
162
|
-
for (let x = x0; x < x1; x++) {
|
|
163
|
-
|
|
164
|
-
const masked = this.test(x, y);
|
|
165
|
-
|
|
166
|
-
if (!masked) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const index = y * this.width + x;
|
|
171
|
-
const address = index * itemSize;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
let targetChannelAddress = address + channel;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
materialData[targetChannelAddress] = this.materialIndex;
|
|
178
|
-
occupancy.set(targetChannelAddress, true);
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Set weights to 0 when their overall contribution is below a given fraction
|
|
187
|
-
* @param {number} fraction
|
|
188
|
-
* @param {Sampler2D} materialSampler
|
|
189
|
-
* @param {Sampler2D} weightSampler
|
|
190
|
-
*/
|
|
191
|
-
clearWeightsBelowContribution(fraction, materialSampler, weightSampler) {
|
|
192
|
-
throw new Error('NIY');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* @param {Uint8Array} weightData
|
|
197
|
-
* @param {number} depth
|
|
198
|
-
*/
|
|
199
|
-
computeMaxWeightContribution(weightData, depth) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const o_bb = this.aabb;
|
|
203
|
-
|
|
204
|
-
const x0 = o_bb.x0;
|
|
205
|
-
const x1 = o_bb.x1;
|
|
206
|
-
|
|
207
|
-
const y0 = o_bb.y0;
|
|
208
|
-
const y1 = o_bb.y1;
|
|
209
|
-
|
|
210
|
-
const width = this.width;
|
|
211
|
-
const height = this.height;
|
|
212
|
-
|
|
213
|
-
const layerSize = width * height;
|
|
214
|
-
|
|
215
|
-
let bestContribution = 0;
|
|
216
|
-
|
|
217
|
-
for (let y = y0; y < y1; y++) {
|
|
218
|
-
for (let x = x0; x < x1; x++) {
|
|
219
|
-
|
|
220
|
-
const masked = this.test(x, y);
|
|
221
|
-
|
|
222
|
-
if (!masked) {
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
let weight = 0;
|
|
227
|
-
|
|
228
|
-
let totalWeight = 0;
|
|
229
|
-
|
|
230
|
-
const texelIndex = y * width + x;
|
|
231
|
-
|
|
232
|
-
//get other weights
|
|
233
|
-
for (let i = 0; i < depth; i++) {
|
|
234
|
-
|
|
235
|
-
const address = i * layerSize + texelIndex;
|
|
236
|
-
|
|
237
|
-
const cW = weightData[address];
|
|
238
|
-
|
|
239
|
-
totalWeight += cW;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (i === this.materialIndex) {
|
|
243
|
-
weight = cW;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const contribution = weight / totalWeight;
|
|
248
|
-
|
|
249
|
-
bestContribution = max2(contribution, bestContribution);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return bestContribution;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
*
|
|
258
|
-
* @param {Uint8Array} weightData
|
|
259
|
-
*/
|
|
260
|
-
readWeights(weightData) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const o_bb = this.aabb;
|
|
264
|
-
|
|
265
|
-
const x0 = o_bb.x0;
|
|
266
|
-
const x1 = o_bb.x1;
|
|
267
|
-
|
|
268
|
-
const y0 = o_bb.y0;
|
|
269
|
-
const y1 = o_bb.y1;
|
|
270
|
-
|
|
271
|
-
const w = x1 - x0;
|
|
272
|
-
const h = y1 - y0;
|
|
273
|
-
|
|
274
|
-
this.weights = new Uint8Array((w) * (h));
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const width = this.width;
|
|
278
|
-
|
|
279
|
-
const layerByteSize = width * this.height;
|
|
280
|
-
|
|
281
|
-
const layerAddress = layerByteSize * this.materialIndex;
|
|
282
|
-
|
|
283
|
-
for (let y = y0; y < y1; y++) {
|
|
284
|
-
for (let x = x0; x < x1; x++) {
|
|
285
|
-
|
|
286
|
-
const masked = this.test(x, y);
|
|
287
|
-
|
|
288
|
-
if (!masked) {
|
|
289
|
-
continue;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const index = y * width + x;
|
|
294
|
-
const address = index + layerAddress;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
//read weight
|
|
298
|
-
|
|
299
|
-
const weight = weightData[address];
|
|
300
|
-
|
|
301
|
-
const _y = y - y0;
|
|
302
|
-
const _x = x - x0;
|
|
303
|
-
|
|
304
|
-
const targetAddress = _y * w + _x;
|
|
305
|
-
|
|
306
|
-
this.weights[targetAddress] = weight;
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
*
|
|
314
|
-
* @param {number} channel
|
|
315
|
-
* @param {Sampler2D} weightSampler
|
|
316
|
-
* @param {Sampler2D} materialSampler
|
|
317
|
-
* @returns {boolean}
|
|
318
|
-
*/
|
|
319
|
-
writeReplace(channel, weightSampler, materialSampler) {
|
|
320
|
-
const itemSize = materialSampler.itemSize;
|
|
321
|
-
|
|
322
|
-
if (channel >= itemSize) {
|
|
323
|
-
//channel index is too high, can't write
|
|
324
|
-
return false;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
const materialData = materialSampler.data;
|
|
328
|
-
const weightData = weightSampler.data;
|
|
329
|
-
|
|
330
|
-
const o_bb = this.aabb;
|
|
331
|
-
|
|
332
|
-
const x0 = o_bb.x0;
|
|
333
|
-
const x1 = o_bb.x1;
|
|
334
|
-
|
|
335
|
-
const y0 = o_bb.y0;
|
|
336
|
-
const y1 = o_bb.y1;
|
|
337
|
-
|
|
338
|
-
for (let y = y0; y < y1; y++) {
|
|
339
|
-
for (let x = x0; x < x1; x++) {
|
|
340
|
-
|
|
341
|
-
const masked = this.test(x, y);
|
|
342
|
-
|
|
343
|
-
if (!masked) {
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const index = y * this.width + x;
|
|
348
|
-
const address = index * itemSize;
|
|
349
|
-
|
|
350
|
-
//find original channel
|
|
351
|
-
for (let c = 0; c < itemSize; c++) {
|
|
352
|
-
|
|
353
|
-
const sourceChannelAddress = address + c;
|
|
354
|
-
|
|
355
|
-
if (materialData[sourceChannelAddress] === this.materialIndex) {
|
|
356
|
-
//found the original channel
|
|
357
|
-
|
|
358
|
-
if (c === channel) {
|
|
359
|
-
//already in the right channel
|
|
360
|
-
break;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const targetChannelAddress = address + channel;
|
|
364
|
-
|
|
365
|
-
//read target values
|
|
366
|
-
const targetWeight = weightData[targetChannelAddress];
|
|
367
|
-
const targetMaterial = materialData[targetChannelAddress];
|
|
368
|
-
|
|
369
|
-
//read weight
|
|
370
|
-
const sourceWeight = weightData[sourceChannelAddress];
|
|
371
|
-
|
|
372
|
-
//perform swap
|
|
373
|
-
weightData[targetChannelAddress] = sourceWeight;
|
|
374
|
-
weightData[sourceChannelAddress] = targetWeight;
|
|
375
|
-
|
|
376
|
-
materialData[targetChannelAddress] = this.materialIndex;
|
|
377
|
-
materialData[sourceChannelAddress] = targetMaterial;
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
*
|
|
389
|
-
* @param {SplatMapMaterialPatch} other
|
|
390
|
-
*/
|
|
391
|
-
add(other) {
|
|
392
|
-
if (this.materialIndex !== other.materialIndex) {
|
|
393
|
-
throw new Error(`Material index does not match, expected '${this.materialIndex}', instead got '${other.materialIndex}'`);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const o_bb = other.aabb;
|
|
397
|
-
|
|
398
|
-
const t_bb = this.aabb;
|
|
399
|
-
|
|
400
|
-
const nBB_x0 = min2(t_bb.x0, o_bb.x0);
|
|
401
|
-
const nBB_x1 = max2(t_bb.x1, o_bb.x1);
|
|
402
|
-
|
|
403
|
-
const nBB_y0 = min2(t_bb.y0, o_bb.y0);
|
|
404
|
-
const nBB_y1 = max2(t_bb.y1, o_bb.y1);
|
|
405
|
-
|
|
406
|
-
//resize weights
|
|
407
|
-
if (this.weights !== null) {
|
|
408
|
-
const nW = nBB_x1 - nBB_x0;
|
|
409
|
-
const nH = nBB_y1 - nBB_y0;
|
|
410
|
-
|
|
411
|
-
const newWeights = new Uint8Array(nW * nH);
|
|
412
|
-
|
|
413
|
-
const t_Source = new Sampler2D(this.weights, 1, t_bb.getWidth(), t_bb.getHeight());
|
|
414
|
-
const o_Source = new Sampler2D(other.weights, 1, o_bb.getWidth(), o_bb.getHeight());
|
|
415
|
-
|
|
416
|
-
const target = new Sampler2D(newWeights, 1, nW, nH);
|
|
417
|
-
|
|
418
|
-
//copy both sources to the new weights target
|
|
419
|
-
sampler2d_sub_copy_same_item_size(target,t_Source, 0, 0, nBB_x0 - t_bb.x0, nBB_y0 - t_bb.y0, t_bb.getHeight(), t_bb.getHeight());
|
|
420
|
-
sampler2d_sub_copy_same_item_size(target,o_Source, 0, 0, nBB_x0 - o_bb.x0, nBB_y0 - o_bb.y0, o_bb.getHeight(), o_bb.getHeight());
|
|
421
|
-
|
|
422
|
-
this.weights = newWeights;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
t_bb.set(nBB_x0, nBB_y0, nBB_x1, nBB_y1);
|
|
426
|
-
|
|
427
|
-
const y0 = o_bb.y0;
|
|
428
|
-
const y1 = o_bb.y1;
|
|
429
|
-
const x0 = o_bb.x0;
|
|
430
|
-
const x1 = o_bb.x1;
|
|
431
|
-
|
|
432
|
-
for (let y = y0; y < y1; y++) {
|
|
433
|
-
for (let x = x0; x < x1; x++) {
|
|
434
|
-
|
|
435
|
-
const address = y * this.width + x;
|
|
436
|
-
|
|
437
|
-
const f = other.mask.get(address);
|
|
438
|
-
|
|
439
|
-
if (f && !this.mask.get(address)) {
|
|
440
|
-
|
|
441
|
-
this.mask.set(address, true);
|
|
442
|
-
this.area++;
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (this.quad !== null) {
|
|
450
|
-
this.quad.resize(t_bb.x0, t_bb.y0, t_bb.x1, t_bb.y1);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
*
|
|
456
|
-
* @param {number} x
|
|
457
|
-
* @param {number} y
|
|
458
|
-
* @return {boolean}
|
|
459
|
-
*/
|
|
460
|
-
test(x, y) {
|
|
461
|
-
return this.mask.get(this.width * y + x);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
}
|