@woosh/meep-engine 2.43.21 → 2.43.23

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.
Files changed (50) hide show
  1. package/core/collection/HashMap.d.ts +2 -2
  2. package/core/collection/HashMap.js +22 -2
  3. package/core/geom/3d/morton/mortonEncode_magicbits.js +18 -0
  4. package/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.js +2 -2
  5. package/core/geom/3d/topology/struct/TopoEdge.js +4 -0
  6. package/core/geom/3d/topology/struct/TopoMesh.js +25 -0
  7. package/core/geom/3d/topology/struct/TopoTriangle.js +4 -0
  8. package/core/geom/3d/topology/struct/TopoVertex.js +8 -0
  9. package/core/geom/3d/topology/struct/binary/BinaryElementPool.js +288 -0
  10. package/core/geom/3d/topology/struct/binary/BinaryElementPool.spec.js +36 -0
  11. package/core/geom/3d/topology/struct/binary/BinaryTopology.js +617 -0
  12. package/core/geom/3d/topology/struct/binary/BinaryTopology.spec.js +16 -0
  13. package/core/geom/3d/topology/struct/binary/io/OrderedEdge.js +66 -0
  14. package/core/geom/3d/topology/struct/binary/io/bt_index_geometry_to_topology.js +188 -0
  15. package/core/geom/3d/topology/struct/binary/io/bt_index_geometry_to_topology.spec.js +84 -0
  16. package/core/geom/3d/topology/struct/binary/io/bt_mesh_calc_edges.js +51 -0
  17. package/core/geom/3d/topology/struct/binary/io/create_edge.js +106 -0
  18. package/core/geom/3d/topology/struct/binary/io/get_or_create_edge_map.js +26 -0
  19. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_has_vertex.js +16 -0
  20. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_has_vertex.spec.js +15 -0
  21. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_other_vertex.js +21 -0
  22. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_other_vertex.spec.js +16 -0
  23. package/core/geom/3d/topology/struct/prototypeBinaryTopology.js +55 -0
  24. package/core/path/PATH_SEPARATOR.js +1 -0
  25. package/core/path/computeFileExtension.js +24 -0
  26. package/core/path/computeFileExtension.spec.js +13 -0
  27. package/core/path/computePathBase.js +21 -0
  28. package/core/path/computePathBase.spec.js +13 -0
  29. package/core/path/computePathDirectory.js +25 -0
  30. package/editor/view/library/MeshLibraryView.js +1 -1
  31. package/engine/asset/guessAssetType.js +1 -1
  32. package/engine/asset/loaders/image/ImageRGBADataLoader.js +1 -1
  33. package/engine/asset/loaders/texture/TextureAssetLoader.js +1 -1
  34. package/engine/ecs/storage/BinaryBufferSerializer.js +7 -0
  35. package/engine/graphics/material/composeCompile.js +3 -5
  36. package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +90 -65
  37. package/engine/graphics/sh3/README.md +2 -0
  38. package/engine/graphics/sh3/path_tracer/PathTracer.js +2 -15
  39. package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +1 -1
  40. package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +14 -9
  41. package/engine/graphics/texture/cubemap/load_environment_map.js +1 -1
  42. package/engine/graphics/util/makeMeshPreviewScene.js +38 -26
  43. package/engine/network/RemoteController.js +98 -0
  44. package/engine/network/remoteEditor.js +33 -0
  45. package/engine/save/storage/IndexedDBStorage.js +1 -0
  46. package/package.json +1 -1
  47. package/view/elements/MeshPreview.js +5 -1
  48. package/core/FilePath.js +0 -73
  49. package/core/FilePath.spec.js +0 -25
  50. package/core/geom/3d/topology/struct/BinaryTopology.js +0 -112
@@ -5,8 +5,8 @@ export class HashMap<K, V> implements Iterable<[V, K]> {
5
5
  capacity,
6
6
  loadFactor
7
7
  }: {
8
- keyHashFunction: (k: K) => number,
9
- keyEqualityFunction: (a: K, b: K) => boolean,
8
+ keyHashFunction?: (k: K) => number,
9
+ keyEqualityFunction?: (a: K, b: K) => boolean,
10
10
  capacity?: number,
11
11
  loadFactor?: number
12
12
  })
@@ -60,6 +60,8 @@ export class HashMap {
60
60
 
61
61
  assert.isFunction(keyHashFunction, 'keyHashFunction');
62
62
  assert.isFunction(keyEqualityFunction, 'keyEqualityFunction');
63
+ assert.isNonNegativeInteger(capacity, 'capacity');
64
+ assert.isNumber(loadFactor, 'loadFactor');
63
65
 
64
66
  /**
65
67
  *
@@ -275,8 +277,8 @@ export class HashMap {
275
277
 
276
278
  /**
277
279
  *
278
- * @param {Key} key
279
- * @param {function(Key):V} compute
280
+ * @param {K} key
281
+ * @param {function(K):V} compute
280
282
  * @param {*} [compute_context]
281
283
  * @return {V}
282
284
  */
@@ -294,6 +296,24 @@ export class HashMap {
294
296
  return value;
295
297
  }
296
298
 
299
+ /**
300
+ * Returns existing value if key exists, if it doesn't - sets it and returns what was passed in
301
+ * @param {K} key
302
+ * @param {V} value this value will be written at the key location if the key wasn't found in the Map
303
+ * @return {V}
304
+ */
305
+ getOrSet(key, value) {
306
+ const existing = this.get(key);
307
+
308
+ if (existing !== undefined) {
309
+ return existing;
310
+ }
311
+
312
+ this.set(key, value);
313
+
314
+ return value;
315
+ }
316
+
297
317
 
298
318
  /**
299
319
  *
@@ -15,6 +15,24 @@ function split_by_3(a) {
15
15
  return x;
16
16
  }
17
17
 
18
+ /**
19
+ * method to separate bits from a given integer 2 positions apart
20
+ *
21
+ * @example when input is ABC, output bits are A00B00C
22
+ * @see https://github.com/Forceflow/libmorton/blob/234a443ca8e2c64f6385f1a9d6ee10a70d08a3fa/include/libmorton/morton2D.h#L99
23
+ * @param {number} a
24
+ * @returns {number}
25
+ */
26
+ export function split_by_2(a) {
27
+ let x = a;
28
+ x = (x | x << 16) & 0x0000FFFF;
29
+ x = (x | x << 8) & 0x00FF00FF;
30
+ x = (x | x << 4) & 0x0F0F0F0F;
31
+ x = (x | x << 2) & 0x33333333;
32
+ x = (x | x << 1) & 0x55555555;
33
+ return x;
34
+ }
35
+
18
36
  /**
19
37
  * Based on article and C++ source code:
20
38
  * https://www.forceflow.be/2013/10/07/morton-encodingdecoding-through-bit-interleaving-implementations/
@@ -17,10 +17,10 @@ import { assert } from "../../../../assert.js";
17
17
  * @see [1] "One machine, one minute, three billion tetrahedra" by Célestin Marot et al
18
18
  * @param {TetrahedralMesh} mesh
19
19
  * @param {number[]} input serialized set of 3d points (x,y,z)
20
- * @param {number} n number of points in the input
20
+ * @param {number} [n] number of points in the input
21
21
  * @returns {boolean}
22
22
  */
23
- export function compute_delaunay_tetrahedral_mesh(mesh, input, n) {
23
+ export function compute_delaunay_tetrahedral_mesh(mesh, input, n = input.length / 3) {
24
24
  assert.notNull(mesh, 'mesh');
25
25
  assert.defined(mesh, 'mesh');
26
26
 
@@ -41,6 +41,10 @@ export class TopoEdge {
41
41
  this.lengthSqr = -1;
42
42
  }
43
43
 
44
+ get byteSize() {
45
+ return 80+5*4 + 4 + 8 + 8 + 8 + this.faces.length * 8 + 10;
46
+ }
47
+
44
48
  /**
45
49
  *
46
50
  * @param {number} i
@@ -35,6 +35,31 @@ export class TopoMesh {
35
35
  this.__faces = new Set();
36
36
  }
37
37
 
38
+ /**
39
+ * Approximation of memory footprint of this object
40
+ * NOTE: this is highly speculative and will differ from reality depending on VM running the code as well as many other factors
41
+ * @return {number}
42
+ */
43
+ get byteSize() {
44
+ let r = 0;
45
+
46
+ for (let i = 0; i < this.vertices.length; i++) {
47
+ const v = this.vertices[i];
48
+
49
+ r += v.byteSize;
50
+ }
51
+
52
+ for (const edge of this.__edges) {
53
+ r += edge.byteSize;
54
+ }
55
+
56
+ for (const face of this.__faces) {
57
+ r += face.byteSize;
58
+ }
59
+
60
+ return r;
61
+ }
62
+
38
63
  /**
39
64
  *
40
65
  * @returns {Set<TopoEdge>}
@@ -32,6 +32,10 @@ export class TopoTriangle {
32
32
  this.normal = [0, 0, 0];
33
33
  }
34
34
 
35
+ get byteSize() {
36
+ return 80 + 4 * 4 + 4 + this.vertices.length * 8 + 10 + this.edges.length * 8 + 10 + 8 * 3 + 10;
37
+ }
38
+
35
39
  /**
36
40
  *
37
41
  * @param {TopoTriangle} other
@@ -52,6 +52,14 @@ export class TopoVertex {
52
52
  return this.z;
53
53
  }
54
54
 
55
+ /**
56
+ * Estimate of this object's size in RAM, in bytes
57
+ * @return {number}
58
+ */
59
+ get byteSize() {
60
+ return 80 + 6 * 4 + 8 + this.edges.length * 8 + 10 + this.faces.length * 8 + 10;
61
+ }
62
+
55
63
  /**
56
64
  *
57
65
  * @param {TopoVertex} other
@@ -0,0 +1,288 @@
1
+ import { max3 } from "../../../../../math/max3.js";
2
+ import { assert } from "../../../../../assert.js";
3
+ import { typed_array_copy } from "../../../../../collection/array/typed/typed_array_copy.js";
4
+
5
+ /**
6
+ * How many items to reserve by default
7
+ * @readonly
8
+ * @type {number}
9
+ */
10
+ const INITIAL_CAPACITY = 128;
11
+
12
+ /**
13
+ * @readonly
14
+ * @type {number}
15
+ */
16
+ const CAPACITY_GROW_MULTIPLIER = 1.2;
17
+
18
+ /**
19
+ * @readonly
20
+ * @type {number}
21
+ */
22
+ const CAPACITY_GROW_MIN_STEP = 32;
23
+
24
+ /**
25
+ * Align on 4 byte boundary
26
+ * @param {number} n
27
+ * @return {number}
28
+ */
29
+ function align_4(n) {
30
+ const result = ((n + 0x3) >> 2) << 2;
31
+
32
+ assert.greaterThanOrEqual(result, n, 'aligned result must be >= input');
33
+
34
+ return result;
35
+ }
36
+
37
+ /**
38
+ * @see https://github.com/blender/blender/blob/master/source/blender/blenlib/intern/BLI_mempool.c
39
+ */
40
+ export class BinaryElementPool {
41
+
42
+ /**
43
+ *
44
+ * @param {number} item_size in bytes
45
+ * @param {number} initial_capacity how many items to reverse in the newly created pool
46
+ */
47
+ constructor(item_size, initial_capacity = INITIAL_CAPACITY) {
48
+ assert.isNonNegativeInteger(item_size, 'item_size');
49
+ assert.greaterThan(item_size, 0, 'item_size must be greater than 0');
50
+
51
+ /**
52
+ * Size of a single pool item in bytes
53
+ * @type {number}
54
+ * @private
55
+ */
56
+ this.__item_size = item_size;
57
+
58
+ /**
59
+ * Unused slots
60
+ * @type {number[]}
61
+ * @private
62
+ */
63
+ this.__free = [];
64
+
65
+ /**
66
+ * Tracks last unallocated item in the list,
67
+ * this separate cursor is necessary to prevent re-allocation of the 'free' array
68
+ * @type {number}
69
+ * @private
70
+ */
71
+ this.__free_pointer = 0;
72
+
73
+ this.__data_buffer = new ArrayBuffer(align_4(initial_capacity * item_size));
74
+ this.__data_uint8 = new Uint8Array(this.__data_buffer);
75
+ this.__data_uint32 = new Uint32Array(this.__data_buffer);
76
+ this.__data_float32 = new Float32Array(this.__data_buffer);
77
+ this.data_view = new DataView(this.__data_buffer);
78
+
79
+ this.__capacity = initial_capacity;
80
+
81
+ /**
82
+ *
83
+ * @type {number}
84
+ * @private
85
+ */
86
+ this.__size = 0;
87
+ }
88
+
89
+ /**
90
+ * Returns size of used region, this includes both elements that are allocated and those that aren't
91
+ * Please note that this value does not represent number of currently active elements, if you need that - you'll need to use something else
92
+ * @return {number}
93
+ */
94
+ get size() {
95
+ return this.__size;
96
+ }
97
+
98
+ /**
99
+ *
100
+ * @return {number}
101
+ */
102
+ get byteSize() {
103
+ return this.__capacity * this.__item_size;
104
+ }
105
+
106
+ /**
107
+ *
108
+ * @return {Uint32Array}
109
+ */
110
+ get data_uint32() {
111
+ return this.__data_uint32;
112
+ }
113
+
114
+ /**
115
+ *
116
+ * @return {Float32Array}
117
+ */
118
+ get data_float32() {
119
+ return this.__data_float32;
120
+ }
121
+
122
+ /**
123
+ * Get rid of excess capacity
124
+ */
125
+ trim() {
126
+ this.__set_capacity(this.__size);
127
+ }
128
+
129
+ /**
130
+ *
131
+ * @param {number} id
132
+ * @return {number}
133
+ */
134
+ element_address(id) {
135
+ assert.isNonNegativeInteger(id, 'id');
136
+
137
+ return this.__item_size * id;
138
+ }
139
+
140
+ /**
141
+ * Used alongside iterators to check if element is actually allocated or not
142
+ * @param {number} id
143
+ * @return {boolean}
144
+ */
145
+ is_allocated(id) {
146
+ if (id >= this.__size) {
147
+ // ID is past allocated region
148
+ return false;
149
+ }
150
+
151
+ const pointer = this.__free_pointer;
152
+
153
+ for (let i = 0; i < pointer; i++) {
154
+ const _id = this.__free[i];
155
+
156
+ if (id === _id) {
157
+ // found in unallocated set
158
+ return false;
159
+ }
160
+ }
161
+
162
+ return true;
163
+ }
164
+
165
+ /**
166
+ *
167
+ * @param {number} new_capacity
168
+ * @private
169
+ */
170
+ __set_capacity(new_capacity) {
171
+ if (this.__capacity === new_capacity) {
172
+ // no point
173
+ return;
174
+ }
175
+
176
+ const old_data_uint8 = this.__data_uint8;
177
+
178
+ const aligned_byte_size = align_4(new_capacity * this.__item_size);
179
+
180
+ const new_data_buffer = new ArrayBuffer(aligned_byte_size);
181
+
182
+ this.__data_buffer = new_data_buffer;
183
+ this.__data_uint8 = new Uint8Array(new_data_buffer);
184
+ this.__data_uint32 = new Uint32Array(this.__data_buffer);
185
+ this.__data_float32 = new Float32Array(this.__data_buffer);
186
+ this.data_view = new DataView(new_data_buffer);
187
+
188
+ // copy old data
189
+ typed_array_copy(old_data_uint8, this.__data_uint8);
190
+
191
+ this.__capacity = new_capacity;
192
+ }
193
+
194
+ /**
195
+ *
196
+ * @param {number} min_capacity
197
+ * @private
198
+ */
199
+ __grow_capacity(min_capacity) {
200
+ const new_capacity = Math.ceil(max3(
201
+ min_capacity,
202
+ this.__capacity * CAPACITY_GROW_MULTIPLIER,
203
+ this.__capacity + CAPACITY_GROW_MIN_STEP
204
+ ));
205
+
206
+ this.__set_capacity(new_capacity);
207
+ }
208
+
209
+ /**
210
+ *
211
+ * @param {number} capacity
212
+ */
213
+ ensure_capacity(capacity) {
214
+ if (this.__capacity < capacity) {
215
+ this.__grow_capacity(capacity);
216
+ }
217
+ }
218
+
219
+
220
+ /**
221
+ *
222
+ * @return {number} ID of the allocated element
223
+ */
224
+ allocate() {
225
+ if (this.__free_pointer > 0) {
226
+ // get unused slot
227
+ this.__free_pointer--;
228
+ return this.__free[this.__free_pointer];
229
+ }
230
+
231
+ // allocate new
232
+ let result = this.__size;
233
+ this.__size++;
234
+
235
+ if (this.__size >= this.__capacity) {
236
+ // grow if necessary
237
+ this.__grow_capacity(this.__size);
238
+ }
239
+
240
+ // assert.greaterThan(this.__data_buffer.byteLength, result * this.__item_size, 'memory underflow');
241
+
242
+ return result;
243
+ }
244
+
245
+ /**
246
+ * Allocate a continuous range of IDs in bulk
247
+ * @param {number} count
248
+ * @return {number} offset where the range starts, this is your first ID basically
249
+ */
250
+ allocate_continuous(count) {
251
+ const offset = this.__size;
252
+
253
+ this.__size += count;
254
+
255
+ if (this.__size >= this.__capacity) {
256
+ this.__grow_capacity(this.__size);
257
+ }
258
+
259
+ // assert.greaterThanOrEqual(this.__data_buffer.byteLength, (offset + count) * this.__item_size, 'memory underflow');
260
+
261
+ return offset;
262
+ }
263
+
264
+ /**
265
+ * Please note that this method does not perform any checks at all.
266
+ * You have to make sure that the item is actually unneeded and no duplicate calls are made
267
+ * @param {number} id
268
+ */
269
+ release(id) {
270
+ if (id === this.__size - 1) {
271
+ // releasing item at the end of the reserved region, don't have to push it into free set
272
+ this.__size--;
273
+ } else if (id >= this.__size) {
274
+ // do nothing, just throw it away
275
+ // this should never happen
276
+ } else {
277
+ this.__free[this.__free_pointer++] = id;
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Removed all data from the pool
283
+ */
284
+ clear() {
285
+ this.__size = 0;
286
+ this.__free_pointer = 0;
287
+ }
288
+ }
@@ -0,0 +1,36 @@
1
+ import { BinaryElementPool } from "./BinaryElementPool.js";
2
+
3
+ test('Constructor does not throw', () => {
4
+ new BinaryElementPool(1);
5
+ });
6
+
7
+ test('Allocation returns a valid non-negative ID', () => {
8
+ const pool = new BinaryElementPool(1);
9
+
10
+ const id = pool.allocate();
11
+
12
+ expect(id).toBeGreaterThanOrEqual(0);
13
+ expect(Number.isInteger(id)).toBe(true);
14
+ expect(Number.isFinite(id)).toBe(true);
15
+ });
16
+
17
+ test('Consecutive allocations return different IDs', () => {
18
+ const pool = new BinaryElementPool(1);
19
+
20
+ const a = pool.allocate();
21
+ const b = pool.allocate();
22
+
23
+ expect(a).not.toEqual(b);
24
+ });
25
+
26
+ test('Allocate, release, allocate produces the same ID',()=>{
27
+ const pool = new BinaryElementPool(1);
28
+
29
+ const a = pool.allocate();
30
+
31
+ pool.release(a);
32
+
33
+ const b = pool.allocate();
34
+
35
+ expect(a).toEqual(b);
36
+ });