@woosh/meep-engine 2.84.10 → 2.85.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/bundle-worker-terrain.js +1 -1
- package/build/meep.cjs +13 -21
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +13 -21
- package/package.json +1 -1
- package/src/core/cache/Cache.js +1 -1
- package/src/core/cache/LoadingCache.js +10 -2
- package/src/core/cache/LoadingCache.spec.js +33 -0
- package/src/core/collection/array/arraySetDiff.js +1 -0
- package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.js +91 -31
- package/src/core/primitives/array/computeIntegerArrayHash.js +3 -16
- package/src/core/primitives/array/computeStridedIntegerArrayHash.js +10 -4
- package/src/engine/graphics/particles/node-based/editor/ParticleSpecificationEditorView.js +10 -10
package/build/meep.module.js
CHANGED
|
@@ -49071,15 +49071,21 @@ function interpolate_bicubic(t, a, b, c, d) {
|
|
|
49071
49071
|
function computeStridedIntegerArrayHash(
|
|
49072
49072
|
array, offset, length, stride
|
|
49073
49073
|
) {
|
|
49074
|
-
let
|
|
49074
|
+
let hash = length;
|
|
49075
49075
|
|
|
49076
49076
|
for (let i = offset; i < length; i += stride) {
|
|
49077
|
-
const value = array[i];
|
|
49077
|
+
const value = array[i] >>> 0; //force int32
|
|
49078
49078
|
|
|
49079
|
-
|
|
49079
|
+
/**
|
|
49080
|
+
* Simple hashing scheme, multiplying existing hash by a prime and adding next value
|
|
49081
|
+
* (h<<5) - h === h*31
|
|
49082
|
+
* @type {number}
|
|
49083
|
+
*/
|
|
49084
|
+
hash = ((hash << 5) - hash) + value;
|
|
49080
49085
|
}
|
|
49081
49086
|
|
|
49082
|
-
|
|
49087
|
+
// force uint32
|
|
49088
|
+
return hash >>> 0;
|
|
49083
49089
|
}
|
|
49084
49090
|
|
|
49085
49091
|
function typedArrayConstructorByInstance(a) {
|
|
@@ -50478,22 +50484,7 @@ Vector1.one = Object.freeze(new Vector1(1));
|
|
|
50478
50484
|
* @param {number} length
|
|
50479
50485
|
*/
|
|
50480
50486
|
function computeIntegerArrayHash(data, offset, length) {
|
|
50481
|
-
|
|
50482
|
-
|
|
50483
|
-
let hash = length;
|
|
50484
|
-
|
|
50485
|
-
for (let i = offset; i < end; i++) {
|
|
50486
|
-
const singleValue = data[i];
|
|
50487
|
-
/**
|
|
50488
|
-
* Simple hashing scheme, multiplying existing hash by a prime and adding next value
|
|
50489
|
-
* (h<<5) - h === h*31
|
|
50490
|
-
* @type {number}
|
|
50491
|
-
*/
|
|
50492
|
-
hash = ((hash << 5) - hash) + singleValue;
|
|
50493
|
-
hash |= 0; // Convert to 32bit integer
|
|
50494
|
-
}
|
|
50495
|
-
|
|
50496
|
-
return hash;
|
|
50487
|
+
return computeStridedIntegerArrayHash(data, offset, length, 1);
|
|
50497
50488
|
}
|
|
50498
50489
|
|
|
50499
50490
|
/**
|
|
@@ -60814,7 +60805,7 @@ class Cache {
|
|
|
60814
60805
|
|
|
60815
60806
|
if (
|
|
60816
60807
|
this.weight > this.maxWeight
|
|
60817
|
-
&& new_weight
|
|
60808
|
+
&& new_weight <= this.maxWeight //make it less likely to drop entire cache
|
|
60818
60809
|
) {
|
|
60819
60810
|
this.evictUntilWeight(this.maxWeight);
|
|
60820
60811
|
}
|
|
@@ -61166,6 +61157,7 @@ function arrayIndexByEquality(array, element, equals) {
|
|
|
61166
61157
|
|
|
61167
61158
|
/**
|
|
61168
61159
|
* Compute a diff between two arrays, result is a 3 way split between common items, unique items in `a` array and unique items in `b` array
|
|
61160
|
+
* @see prefer to use {@link arraySetSortingDiff}, as it's much faster, especially for large sets
|
|
61169
61161
|
* @template T
|
|
61170
61162
|
* @param {T[]} a
|
|
61171
61163
|
* @param {T[]} b
|
package/package.json
CHANGED
package/src/core/cache/Cache.js
CHANGED
|
@@ -216,7 +216,7 @@ export class Cache {
|
|
|
216
216
|
|
|
217
217
|
if (
|
|
218
218
|
this.weight > this.maxWeight
|
|
219
|
-
&& new_weight
|
|
219
|
+
&& new_weight <= this.maxWeight //make it less likely to drop entire cache
|
|
220
220
|
) {
|
|
221
221
|
this.evictUntilWeight(this.maxWeight);
|
|
222
222
|
}
|
|
@@ -41,7 +41,7 @@ function record_get_value_weight(record) {
|
|
|
41
41
|
/**
|
|
42
42
|
* Asynchronous cache capable of resolving its own values by keys
|
|
43
43
|
* Modelled on Guava's LoadingCache concept
|
|
44
|
-
* @template K,V
|
|
44
|
+
* @template K, V
|
|
45
45
|
*/
|
|
46
46
|
export class LoadingCache {
|
|
47
47
|
/**
|
|
@@ -73,7 +73,6 @@ export class LoadingCache {
|
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* @see {@link Cache} for more details on what each parameter means
|
|
76
|
-
* @template K,V
|
|
77
76
|
* @param [maxWeight]
|
|
78
77
|
* @param [keyWeigher]
|
|
79
78
|
* @param [valueWeigher]
|
|
@@ -183,6 +182,15 @@ export class LoadingCache {
|
|
|
183
182
|
this.#internal.put(key, new Record(Promise.resolve(value), current_time_in_seconds()));
|
|
184
183
|
}
|
|
185
184
|
|
|
185
|
+
/**
|
|
186
|
+
*
|
|
187
|
+
* @param {K} key
|
|
188
|
+
* @returns {boolean}
|
|
189
|
+
*/
|
|
190
|
+
contains(key) {
|
|
191
|
+
return this.#internal.contains(key);
|
|
192
|
+
}
|
|
193
|
+
|
|
186
194
|
/**
|
|
187
195
|
*
|
|
188
196
|
* @param {K} key
|
|
@@ -84,3 +84,36 @@ test("clear", async () => {
|
|
|
84
84
|
|
|
85
85
|
expect(await cache.get("x")).toEqual(3);
|
|
86
86
|
});
|
|
87
|
+
|
|
88
|
+
test("eviction", async () => {
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
*
|
|
92
|
+
* @type {LoadingCache<number, number>}
|
|
93
|
+
*/
|
|
94
|
+
const cache = new LoadingCache({
|
|
95
|
+
valueWeigher(num) {
|
|
96
|
+
return num;
|
|
97
|
+
},
|
|
98
|
+
load: async () => {
|
|
99
|
+
return 2;
|
|
100
|
+
},
|
|
101
|
+
maxWeight: 6,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await cache.get(1);
|
|
105
|
+
await cache.get(2);
|
|
106
|
+
await cache.get(3);
|
|
107
|
+
|
|
108
|
+
expect(cache.contains(1)).toBe(true);
|
|
109
|
+
expect(cache.contains(2)).toBe(true);
|
|
110
|
+
expect(cache.contains(3)).toBe(true);
|
|
111
|
+
|
|
112
|
+
await cache.get(4);
|
|
113
|
+
|
|
114
|
+
expect(cache.contains(1)).toBe(false);
|
|
115
|
+
expect(cache.contains(2)).toBe(true);
|
|
116
|
+
expect(cache.contains(3)).toBe(true);
|
|
117
|
+
expect(cache.contains(4)).toBe(true);
|
|
118
|
+
|
|
119
|
+
});
|
|
@@ -5,6 +5,7 @@ import { arrayIndexByEquality } from "./arrayIndexByEquality.js";
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Compute a diff between two arrays, result is a 3 way split between common items, unique items in `a` array and unique items in `b` array
|
|
8
|
+
* @see prefer to use {@link arraySetSortingDiff}, as it's much faster, especially for large sets
|
|
8
9
|
* @template T
|
|
9
10
|
* @param {T[]} a
|
|
10
11
|
* @param {T[]} b
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../../assert.js";
|
|
2
|
-
import { NodeInstance } from "../node/NodeInstance.js";
|
|
3
2
|
import { abstractJSONDeserializer } from "../../../json/abstractJSONDeserializer.js";
|
|
3
|
+
import { NodeInstance } from "../node/NodeInstance.js";
|
|
4
4
|
import { NodeRegistry } from "../node/NodeRegistry.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -25,47 +25,73 @@ function nodeParametersFromJSON(node, json, deserializers) {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
*
|
|
28
|
-
* @param {
|
|
29
|
-
* @param {
|
|
30
|
-
* @param {NodeRegistry}
|
|
31
|
-
* @param {
|
|
32
|
-
* @
|
|
28
|
+
* @param {[]} j_descriptions
|
|
29
|
+
* @param {Map<string,function>} deserializers
|
|
30
|
+
* @param {NodeRegistry} node_registry
|
|
31
|
+
* @param {boolean} allow_node_id_collisions
|
|
32
|
+
* @returns {Promise<NodeDescription[]>}
|
|
33
33
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}) {
|
|
41
|
-
|
|
42
|
-
const j_nodes = json.nodes;
|
|
43
|
-
const j_connections = json.connections;
|
|
44
|
-
const j_descriptions = json.descriptions;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
assert.defined(j_nodes, 'json.nodes');
|
|
48
|
-
assert.defined(j_connections, 'json.connections');
|
|
49
|
-
assert.defined(j_descriptions, 'json.descriptions');
|
|
34
|
+
async function deserializeNodeDescriptors(j_descriptions, deserializers, node_registry, allow_node_id_collisions) {
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @type {NodeDescription[]}
|
|
38
|
+
*/
|
|
39
|
+
const result = [];
|
|
50
40
|
|
|
51
|
-
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
* @type {{index:number, promise:Promise<NodeDescription>}[]}
|
|
44
|
+
*/
|
|
45
|
+
const deferred = [];
|
|
52
46
|
|
|
53
47
|
/**
|
|
54
48
|
*
|
|
55
49
|
* @type {NodeDescription[]}
|
|
56
50
|
*/
|
|
57
|
-
const
|
|
51
|
+
const deserialized = [];
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
|
|
54
|
+
const node_description_count = j_descriptions.length;
|
|
55
|
+
|
|
56
|
+
// parse node result
|
|
57
|
+
for (let i = 0; i < node_description_count; i++) {
|
|
61
58
|
const jDescription = j_descriptions[i];
|
|
62
59
|
|
|
63
|
-
const
|
|
60
|
+
const result = abstractJSONDeserializer(jDescription, deserializers);
|
|
61
|
+
|
|
62
|
+
if (result instanceof Promise) {
|
|
63
|
+
deferred.push({
|
|
64
|
+
index: i,
|
|
65
|
+
promise: result
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
deserialized[i] = result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (deferred.length > 0) {
|
|
74
|
+
const resolved = await Promise.all(deferred.map(m => m.promise));
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < deferred.length; i++) {
|
|
77
|
+
const node_description = resolved[i];
|
|
78
|
+
|
|
79
|
+
const spec = deferred[i];
|
|
80
|
+
|
|
81
|
+
deserialized[spec.index] = node_description;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < node_description_count; i++) {
|
|
86
|
+
|
|
87
|
+
const loaded_node = deserialized[i];
|
|
64
88
|
|
|
65
89
|
if (
|
|
66
90
|
typeof loaded_node !== "object"
|
|
67
91
|
|| loaded_node.isNodeDescription !== true
|
|
68
92
|
) {
|
|
93
|
+
const jDescription = j_descriptions[i];
|
|
94
|
+
|
|
69
95
|
throw new Error(`Deserialized object was expected to be a NodeDescription, instead got something else. Source JSON[${i}]: ${jDescription}`);
|
|
70
96
|
}
|
|
71
97
|
|
|
@@ -73,7 +99,7 @@ export function deserializeNodeGraphFromJSON({
|
|
|
73
99
|
|
|
74
100
|
if (existing_node === undefined) {
|
|
75
101
|
|
|
76
|
-
|
|
102
|
+
result[i] = loaded_node;
|
|
77
103
|
|
|
78
104
|
// make sure to register the node
|
|
79
105
|
node_registry.addNode(loaded_node);
|
|
@@ -85,7 +111,7 @@ export function deserializeNodeGraphFromJSON({
|
|
|
85
111
|
// collision exists
|
|
86
112
|
|
|
87
113
|
if (allow_node_id_collisions) {
|
|
88
|
-
|
|
114
|
+
result[i] = loaded_node;
|
|
89
115
|
} else {
|
|
90
116
|
// illegal collision
|
|
91
117
|
throw new Error(`Loaded node does not match the one in the registry. Loaded: ${loaded_node}, Existing: ${existing_node}`);
|
|
@@ -94,11 +120,45 @@ export function deserializeNodeGraphFromJSON({
|
|
|
94
120
|
} else {
|
|
95
121
|
|
|
96
122
|
// re-use node from registry
|
|
97
|
-
|
|
123
|
+
result[i] = existing_node;
|
|
98
124
|
}
|
|
99
125
|
}
|
|
100
|
-
|
|
101
126
|
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
*
|
|
132
|
+
* @param {NodeGraph} graph
|
|
133
|
+
* @param {{nodes:[], connections:[], descriptions:[]}} json
|
|
134
|
+
* @param {NodeRegistry} [node_registry]
|
|
135
|
+
* @param {Map<string, function>} [deserializers]
|
|
136
|
+
* @param {boolean} [allow_node_id_collisions]
|
|
137
|
+
*/
|
|
138
|
+
export async function deserializeNodeGraphFromJSON({
|
|
139
|
+
graph,
|
|
140
|
+
json,
|
|
141
|
+
node_registry = new NodeRegistry(),
|
|
142
|
+
deserializers = new Map(),
|
|
143
|
+
allow_node_id_collisions = false
|
|
144
|
+
}) {
|
|
145
|
+
|
|
146
|
+
const j_nodes = json.nodes;
|
|
147
|
+
const j_connections = json.connections;
|
|
148
|
+
const j_descriptions = json.descriptions;
|
|
149
|
+
|
|
150
|
+
assert.defined(j_nodes, 'json.nodes');
|
|
151
|
+
assert.defined(j_connections, 'json.connections');
|
|
152
|
+
assert.defined(j_descriptions, 'json.descriptions');
|
|
153
|
+
|
|
154
|
+
graph.reset();
|
|
155
|
+
|
|
156
|
+
const descriptions = await deserializeNodeDescriptors(
|
|
157
|
+
j_descriptions,
|
|
158
|
+
deserializers,
|
|
159
|
+
node_registry,
|
|
160
|
+
allow_node_id_collisions
|
|
161
|
+
);
|
|
102
162
|
|
|
103
163
|
// parse nodes
|
|
104
164
|
const node_count = j_nodes.length;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { computeStridedIntegerArrayHash } from "./computeStridedIntegerArrayHash.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
*
|
|
3
5
|
* @param {Uint8Array|number[]|ArrayLike<number>|IArguments} data
|
|
@@ -5,20 +7,5 @@
|
|
|
5
7
|
* @param {number} length
|
|
6
8
|
*/
|
|
7
9
|
export function computeIntegerArrayHash(data, offset, length) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let hash = length;
|
|
11
|
-
|
|
12
|
-
for (let i = offset; i < end; i++) {
|
|
13
|
-
const singleValue = data[i];
|
|
14
|
-
/**
|
|
15
|
-
* Simple hashing scheme, multiplying existing hash by a prime and adding next value
|
|
16
|
-
* (h<<5) - h === h*31
|
|
17
|
-
* @type {number}
|
|
18
|
-
*/
|
|
19
|
-
hash = ((hash << 5) - hash) + singleValue;
|
|
20
|
-
hash |= 0; // Convert to 32bit integer
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return hash;
|
|
10
|
+
return computeStridedIntegerArrayHash(data, offset, length, 1);
|
|
24
11
|
}
|
|
@@ -9,13 +9,19 @@
|
|
|
9
9
|
export function computeStridedIntegerArrayHash(
|
|
10
10
|
array, offset, length, stride
|
|
11
11
|
) {
|
|
12
|
-
let
|
|
12
|
+
let hash = length;
|
|
13
13
|
|
|
14
14
|
for (let i = offset; i < length; i += stride) {
|
|
15
|
-
const value = array[i];
|
|
15
|
+
const value = array[i] >>> 0; //force int32
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Simple hashing scheme, multiplying existing hash by a prime and adding next value
|
|
19
|
+
* (h<<5) - h === h*31
|
|
20
|
+
* @type {number}
|
|
21
|
+
*/
|
|
22
|
+
hash = ((hash << 5) - hash) + value;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
// force uint32
|
|
26
|
+
return hash >>> 0;
|
|
21
27
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import View from "../../../../../view/View.js";
|
|
2
1
|
import { NodeGraphEditorView } from "../../../../../../editor/view/node-graph/NodeGraphEditorView.js";
|
|
3
2
|
import { NodeGraphCamera } from "../../../../../../editor/view/node-graph/NodeGraphView.js";
|
|
4
|
-
import
|
|
3
|
+
import { downloadAsFile } from "../../../../../core/binary/downloadAsFile.js";
|
|
5
4
|
import List from "../../../../../core/collection/list/List.js";
|
|
6
|
-
import LabelView from "../../../../../view/common/LabelView.js";
|
|
7
|
-
import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
|
|
8
|
-
import InterfaceCommand from "../../../../../view/interaction/InterfaceCommand.js";
|
|
9
|
-
import { InteractionCommand } from "../../../../../view/interaction/InteractionCommand.js";
|
|
10
|
-
import { serializeNodeGraphToJSON } from "../../../../../core/model/node-graph/json/serializeNodeGraphToJSON.js";
|
|
11
5
|
import {
|
|
12
6
|
deserializeNodeGraphFromJSON
|
|
13
7
|
} from "../../../../../core/model/node-graph/json/deserializeNodeGraphFromJSON.js";
|
|
14
|
-
import {
|
|
8
|
+
import { serializeNodeGraphToJSON } from "../../../../../core/model/node-graph/json/serializeNodeGraphToJSON.js";
|
|
9
|
+
import LabelView from "../../../../../view/common/LabelView.js";
|
|
10
|
+
import ListView from "../../../../../view/common/ListView.js";
|
|
11
|
+
import { InteractionCommand } from "../../../../../view/interaction/InteractionCommand.js";
|
|
12
|
+
import InterfaceCommand from "../../../../../view/interaction/InterfaceCommand.js";
|
|
13
|
+
import View from "../../../../../view/View.js";
|
|
14
|
+
import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
|
|
15
15
|
|
|
16
16
|
export class ParticleSpecificationEditorView extends View {
|
|
17
17
|
constructor() {
|
|
@@ -101,13 +101,13 @@ export class ParticleSpecificationEditorView extends View {
|
|
|
101
101
|
function processFile(file) {
|
|
102
102
|
const fr = new FileReader();
|
|
103
103
|
|
|
104
|
-
fr.onload = () => {
|
|
104
|
+
fr.onload = async () => {
|
|
105
105
|
|
|
106
106
|
visual.nodes.clear();
|
|
107
107
|
|
|
108
108
|
const json = JSON.parse(fr.result);
|
|
109
109
|
|
|
110
|
-
deserializeNodeGraphFromJSON({ graph: nodeGraph, json: json, node_registry: nodeRegistry });
|
|
110
|
+
await deserializeNodeGraphFromJSON({ graph: nodeGraph, json: json, node_registry: nodeRegistry });
|
|
111
111
|
|
|
112
112
|
visual.layout(nodeGraph);
|
|
113
113
|
};
|