@woosh/meep-engine 2.109.22 → 2.109.24

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 (24) hide show
  1. package/build/meep.cjs +1 -1
  2. package/build/meep.module.js +1 -1
  3. package/package.json +1 -1
  4. package/src/core/collection/table/bind/TableRecord.d.ts.map +1 -1
  5. package/src/core/collection/table/bind/TableRecord.js +4 -0
  6. package/src/core/model/validate_enum_schema.d.ts +10 -0
  7. package/src/core/model/validate_enum_schema.d.ts.map +1 -0
  8. package/src/core/model/validate_enum_schema.js +31 -0
  9. package/src/core/primitives/array/computeStridedArrayHash.d.ts +13 -0
  10. package/src/core/primitives/array/computeStridedArrayHash.d.ts.map +1 -0
  11. package/src/core/primitives/array/computeStridedArrayHash.js +36 -0
  12. package/src/core/primitives/array/computeStridedIntegerArrayHash.js +2 -1
  13. package/src/engine/animation/async/TimeSeries.d.ts +76 -0
  14. package/src/engine/animation/async/TimeSeries.d.ts.map +1 -0
  15. package/src/engine/animation/async/TimeSeries.js +285 -0
  16. package/src/engine/animation/async/findSampleIndex.d.ts +9 -0
  17. package/src/engine/animation/async/findSampleIndex.d.ts.map +1 -0
  18. package/src/engine/animation/async/findSampleIndex.js +31 -0
  19. package/src/engine/animation/async/prototypeAsyncAnimation.js +31 -83
  20. package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.d.ts.map +1 -1
  21. package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.js +6 -2
  22. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  23. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +14 -11
  24. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +1 -1
package/build/meep.cjs CHANGED
@@ -49144,7 +49144,7 @@ function computeStridedIntegerArrayHash(
49144
49144
  let hash = length;
49145
49145
 
49146
49146
  for (let i = offset; i < length; i += stride) {
49147
- const value = array[i] >>> 0; //force int32
49147
+ const value = array[i] >>> 0; //force uint32
49148
49148
 
49149
49149
  /**
49150
49150
  * Simple hashing scheme, multiplying existing hash by a prime and adding next value
@@ -49142,7 +49142,7 @@ function computeStridedIntegerArrayHash(
49142
49142
  let hash = length;
49143
49143
 
49144
49144
  for (let i = offset; i < length; i += stride) {
49145
- const value = array[i] >>> 0; //force int32
49145
+ const value = array[i] >>> 0; //force uint32
49146
49146
 
49147
49147
  /**
49148
49148
  * Simple hashing scheme, multiplying existing hash by a prime and adding next value
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.109.22",
8
+ "version": "2.109.24",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -1 +1 @@
1
- {"version":3,"file":"TableRecord.d.ts","sourceRoot":"","sources":["../../../../../../src/core/collection/table/bind/TableRecord.js"],"names":[],"mappings":"AAGA;IA+DI;;;OAGG;IACH,yBAUC;IA7BD,qBAEC;IAND,kBAEC;IAOD,uBAIC;IAED,YAEC;IAkBD,sCAEC;IAED;;;;OAIG;IACH,sCAFW,MAAM,QAKhB;;CACJ;kCA9FiC,yBAAyB"}
1
+ {"version":3,"file":"TableRecord.d.ts","sourceRoot":"","sources":["../../../../../../src/core/collection/table/bind/TableRecord.js"],"names":[],"mappings":"AAKA;IA+DI;;;OAGG;IACH,yBAYC;IA/BD,qBAEC;IAND,kBAEC;IAOD,uBAIC;IAED,YAEC;IAoBD,sCAEC;IAED;;;;OAIG;IACH,sCAFW,MAAM,QAKhB;;CACJ;kCAhGiC,yBAAyB"}
@@ -1,4 +1,6 @@
1
1
  import { assert } from "../../../assert.js";
2
+ import { BinaryDataType } from "../../../binary/type/BinaryDataType.js";
3
+ import { validate_enum_schema } from "../../../model/validate_enum_schema.js";
2
4
  import { RowFirstTableSpec } from "../RowFirstTableSpec.js";
3
5
 
4
6
  export class TableRecord {
@@ -72,6 +74,8 @@ export class TableRecord {
72
74
  assert.notNull(schema, 'schema');
73
75
  assert.defined(schema, 'schema');
74
76
 
77
+ assert.ok(validate_enum_schema(schema, BinaryDataType, console.warn), 'invalid schema');
78
+
75
79
  this.#schema = schema;
76
80
  const keys = Object.keys(schema);
77
81
 
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @template T
3
+ * @param {Object<BinaryDataType>} schema
4
+ * @param {Object<T>} enumerable
5
+ * @param {function(message:string)} [error_consumer]
6
+ * @param {*} [error_consumer_context]
7
+ */
8
+ export function validate_enum_schema<T>(schema: any, enumerable: any, error_consumer?: typeof noop, error_consumer_context?: any): boolean;
9
+ import { noop } from "../function/noop.js";
10
+ //# sourceMappingURL=validate_enum_schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate_enum_schema.d.ts","sourceRoot":"","sources":["../../../../src/core/model/validate_enum_schema.js"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,2IAoBC;qBA7BoB,qBAAqB"}
@@ -0,0 +1,31 @@
1
+ import { assert } from "../assert.js";
2
+ import { noop } from "../function/noop.js";
3
+
4
+ /**
5
+ * @template T
6
+ * @param {Object<BinaryDataType>} schema
7
+ * @param {Object<T>} enumerable
8
+ * @param {function(message:string)} [error_consumer]
9
+ * @param {*} [error_consumer_context]
10
+ */
11
+ export function validate_enum_schema(schema, enumerable, error_consumer = noop, error_consumer_context) {
12
+
13
+ assert.notNull(schema, 'schema');
14
+ assert.isObject(schema, 'schema');
15
+
16
+ let valid = true;
17
+ const valid_types = Object.values(enumerable);
18
+
19
+ for (const schemaKey in schema) {
20
+
21
+ const type = schema[schemaKey];
22
+
23
+ if (!valid_types.includes(type)) {
24
+ error_consumer.call(error_consumer_context, `Field '${schemaKey}' is expected to have have BinaryDataType value, instead found '${type}'. Valid values are: ${valid_types.join(', ')}.`);
25
+ valid = false;
26
+ }
27
+
28
+ }
29
+
30
+ return valid;
31
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Useful for computing hashes of large arrays, can pick a relevant stride and skip large chunks of memory while still capturing good amount of unique information from evenly-spaced areas of the array
3
+ * @template T
4
+ * @param {T[]|Uint32Array|Uint16Array|Uint8Array} array
5
+ * @param {number} offset
6
+ * @param {number} length
7
+ * @param {number} stride
8
+ * @param {function(T):number} elementHash
9
+ * @param {*} [elementHashContext]
10
+ * @return {number}
11
+ */
12
+ export function computeStridedArrayHash<T>(array: Uint8Array | Uint16Array | Uint32Array | T[], offset: number, length: number, stride: number, elementHash: (arg0: T) => number, elementHashContext?: any): number;
13
+ //# sourceMappingURL=computeStridedArrayHash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computeStridedArrayHash.d.ts","sourceRoot":"","sources":["../../../../../src/core/primitives/array/computeStridedArrayHash.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,wGAPW,MAAM,UACN,MAAM,UACN,MAAM,4BACM,MAAM,6BAEjB,MAAM,CAwBjB"}
@@ -0,0 +1,36 @@
1
+ import { assert } from "../../assert.js";
2
+
3
+ /**
4
+ * Useful for computing hashes of large arrays, can pick a relevant stride and skip large chunks of memory while still capturing good amount of unique information from evenly-spaced areas of the array
5
+ * @template T
6
+ * @param {T[]|Uint32Array|Uint16Array|Uint8Array} array
7
+ * @param {number} offset
8
+ * @param {number} length
9
+ * @param {number} stride
10
+ * @param {function(T):number} elementHash
11
+ * @param {*} [elementHashContext]
12
+ * @return {number}
13
+ */
14
+ export function computeStridedArrayHash(
15
+ array, offset, length, stride,
16
+ elementHash, elementHashContext
17
+ ) {
18
+
19
+ assert.isFunction(elementHash, 'elementHash');
20
+
21
+ let hash = length;
22
+
23
+ for (let i = offset; i < length; i += stride) {
24
+ const value = elementHash.call(elementHashContext, array[i]);
25
+
26
+ /**
27
+ * Simple hashing scheme, multiplying existing hash by a prime and adding next value
28
+ * (h<<5) - h === h*31
29
+ * @type {number}
30
+ */
31
+ hash = ((hash << 5) - hash) + value;
32
+ }
33
+
34
+ // force uint32
35
+ return hash >>> 0;
36
+ }
@@ -12,7 +12,7 @@ export function computeStridedIntegerArrayHash(
12
12
  let hash = length;
13
13
 
14
14
  for (let i = offset; i < length; i += stride) {
15
- const value = array[i] >>> 0; //force int32
15
+ const value = array[i] >>> 0; //force uint32
16
16
 
17
17
  /**
18
18
  * Simple hashing scheme, multiplying existing hash by a prime and adding next value
@@ -25,3 +25,4 @@ export function computeStridedIntegerArrayHash(
25
25
  // force uint32
26
26
  return hash >>> 0;
27
27
  }
28
+
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @template T
3
+ */
4
+ export class TimeSeries<T> {
5
+ /**
6
+ *
7
+ * @param {Object<BinaryDataType>} schema
8
+ * @param {string} [time_column_name]
9
+ */
10
+ constructor(schema: any, time_column_name?: string);
11
+ /**
12
+ * @type {RowFirstTableSpec}
13
+ */
14
+ spec: RowFirstTableSpec;
15
+ /**
16
+ * @type {RowFirstTable}
17
+ */
18
+ table: RowFirstTable;
19
+ time_column_index: number;
20
+ /**
21
+ *
22
+ * @param {number} index
23
+ * @returns {Object}
24
+ */
25
+ getSampleObjectByIndex(index: number): any;
26
+ /**
27
+ *
28
+ * @returns {number}
29
+ */
30
+ get sample_count(): number;
31
+ /**
32
+ *
33
+ * @returns {number}
34
+ */
35
+ get last_timestamp(): number;
36
+ validateNextSample(data: any): void;
37
+ /**
38
+ *
39
+ * @param {number[]} data
40
+ */
41
+ addSample(data: number[]): void;
42
+ /**
43
+ *
44
+ * @param {Object} sample
45
+ */
46
+ addObjectSample(sample: any): void;
47
+ /**
48
+ *
49
+ * @param {number[]} result
50
+ * @param {number} index
51
+ */
52
+ getSampleByIndex(result: number[], index: number): void;
53
+ /**
54
+ *
55
+ * @param {number} time
56
+ * @returns {number}
57
+ */
58
+ findLowSampleIndexByTime(time: number): number;
59
+ /**
60
+ *
61
+ * @param {number[]} result
62
+ * @param {number} result_offset
63
+ * @param {number} time
64
+ */
65
+ sampleLinear(result: number[], result_offset: number, time: number): void;
66
+ /**
67
+ * Get linearly interpolated sample for given time in object form, following supplied schema
68
+ * @param {number} time
69
+ * @returns {Object}
70
+ */
71
+ sampleObjectLinear(time: number): any;
72
+ #private;
73
+ }
74
+ import { RowFirstTableSpec } from "../../../core/collection/table/RowFirstTableSpec.js";
75
+ import { RowFirstTable } from "../../../core/collection/table/RowFirstTable.js";
76
+ //# sourceMappingURL=TimeSeries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeSeries.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/async/TimeSeries.js"],"names":[],"mappings":"AAaA;;GAEG;AACH;IA+BI;;;;OAIG;IACH,4CAFW,MAAM,EAuChB;IAxED;;OAEG;IACH,MAFU,iBAAiB,CAEvB;IAEJ;;OAEG;IACH,OAFU,aAAa,CAElB;IAEL,0BAAsB;IAyHtB;;;;OAIG;IACH,8BAHW,MAAM,OAOhB;IAED;;;OAGG;IACH,2BAEC;IAED;;;OAGG;IACH,6BAWC;IAED,oCAcC;IAED;;;OAGG;IACH,gBAFW,MAAM,EAAE,QAQlB;IAED;;;OAGG;IACH,mCAIC;IAED;;;;OAIG;IACH,yBAHW,MAAM,EAAE,SACR,MAAM,QAIhB;IAED;;;;OAIG;IACH,+BAHW,MAAM,GACJ,MAAM,CAMlB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,EAAE,iBACR,MAAM,QACN,MAAM,QAuBhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,OAShB;;CAEJ;kCAzRiC,qDAAqD;8BADzD,iDAAiD"}
@@ -0,0 +1,285 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import { BinaryDataType } from "../../../core/binary/type/BinaryDataType.js";
3
+ import { RowFirstTable } from "../../../core/collection/table/RowFirstTable.js";
4
+ import { RowFirstTableSpec } from "../../../core/collection/table/RowFirstTableSpec.js";
5
+ import { inverseLerp } from "../../../core/math/inverseLerp.js";
6
+ import { lerp } from "../../../core/math/lerp.js";
7
+ import { max2 } from "../../../core/math/max2.js";
8
+ import { min2 } from "../../../core/math/min2.js";
9
+ import { validate_enum_schema } from "../../../core/model/validate_enum_schema.js";
10
+ import { findSampleIndex } from "./findSampleIndex.js";
11
+
12
+ const scratch_row = [];
13
+
14
+ /**
15
+ * @template T
16
+ */
17
+ export class TimeSeries {
18
+ /**
19
+ * @type {RowFirstTableSpec}
20
+ */
21
+ spec
22
+
23
+ /**
24
+ * @type {RowFirstTable}
25
+ */
26
+ table
27
+
28
+ time_column_index = 0;
29
+
30
+ /**
31
+ *
32
+ * @type {Object<BinaryDataType>}
33
+ */
34
+ #schema = {}
35
+
36
+ /**
37
+ *
38
+ * @type {Object<number>}
39
+ */
40
+ #schema_column_names_to_indices = {};
41
+
42
+ /**
43
+ *
44
+ * @type {string[]}
45
+ */
46
+ #schema_column_indices_to_names = [];
47
+
48
+ /**
49
+ *
50
+ * @param {Object<BinaryDataType>} schema
51
+ * @param {string} [time_column_name]
52
+ */
53
+ constructor(schema, time_column_name = 'time') {
54
+ assert.isString(time_column_name, 'time_column_name');
55
+ assert.notNull(schema, 'schema');
56
+ assert.isObject(schema, 'schema');
57
+
58
+ let issues = [];
59
+
60
+ if (!validate_enum_schema(schema, BinaryDataType, (issue) => issues.push(issue))) {
61
+ throw new TypeError(`Invalid schema. Problems:\n ${issues.join('\n')}`);
62
+ }
63
+
64
+ this.#schema = schema;
65
+
66
+ const schema_keys = Object.keys(schema);
67
+
68
+ const time_row_index = schema_keys.indexOf(time_column_name);
69
+
70
+ if (time_row_index === -1) {
71
+ throw new TypeError(`supplies schema does not include time column '${time_column_name}', exising columns: ${schema_keys.join(', ')}`);
72
+ }
73
+
74
+ this.time_column_index = time_row_index;
75
+
76
+
77
+ this.#schema_column_names_to_indices = {};
78
+
79
+ for (let i = 0; i < schema_keys.length; i++) {
80
+ const key = schema_keys[i];
81
+
82
+ this.#schema_column_names_to_indices[key] = i;
83
+ this.#schema_column_indices_to_names[i] = key;
84
+ }
85
+
86
+ this.spec = RowFirstTableSpec.get(Object.values(schema));
87
+
88
+ this.table = new RowFirstTable(this.spec);
89
+
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @param {number[]} row
95
+ * @param {Object} object
96
+ */
97
+ #object_to_row(row, object) {
98
+
99
+ const columnCount = this.spec.getColumnCount();
100
+
101
+ for (let i = 0; i < columnCount; i++) {
102
+
103
+ const key = this.#schema_column_indices_to_names[i];
104
+
105
+ const value = object[key];
106
+
107
+ const t = typeof value;
108
+
109
+ if (t !== "number") {
110
+ throw new TypeError(`Expected sample.${key} to be a number, instead was ${t} (=${value})`);
111
+ }
112
+
113
+ row[i] = value;
114
+
115
+ }
116
+ }
117
+
118
+ /**
119
+ *
120
+ * @param {Object} object
121
+ * @param {number[]} row
122
+ */
123
+ #row_to_object(object, row) {
124
+
125
+ const columnCount = this.spec.getColumnCount();
126
+ for (let i = 0; i < columnCount; i++) {
127
+
128
+ const key = this.#schema_column_indices_to_names[i];
129
+
130
+ object[key] = row[i];
131
+ }
132
+
133
+ }
134
+
135
+ /**
136
+ *
137
+ * @param {number[]} row
138
+ * @returns {Object}
139
+ */
140
+ #row_to_object_allocating(row) {
141
+
142
+ const result = {};
143
+
144
+ this.#row_to_object(result, row);
145
+
146
+ return result;
147
+ }
148
+
149
+ /**
150
+ *
151
+ * @param {number} index
152
+ * @returns {Object}
153
+ */
154
+ getSampleObjectByIndex(index) {
155
+ this.table.getRow(index, scratch_row);
156
+
157
+ return this.#row_to_object_allocating(scratch_row);
158
+ }
159
+
160
+ /**
161
+ *
162
+ * @returns {number}
163
+ */
164
+ get sample_count() {
165
+ return this.table.length;
166
+ }
167
+
168
+ /**
169
+ *
170
+ * @returns {number}
171
+ */
172
+ get last_timestamp() {
173
+ const table = this.table;
174
+ const record_count = table.length;
175
+
176
+ if (record_count === 0) {
177
+ // default
178
+ return 0;
179
+ }
180
+
181
+ const time_column = this.time_column_index;
182
+ return table.readCellValue(record_count - 1, time_column);
183
+ }
184
+
185
+ validateNextSample(data) {
186
+
187
+ const table = this.table;
188
+ const record_count = table.length;
189
+
190
+ if (record_count > 0) {
191
+ const time_column = this.time_column_index;
192
+ const last_time = table.readCellValue(record_count - 1, time_column);
193
+
194
+ if (data[time_column] <= last_time) {
195
+ throw new Error(`Sample.time[${time_column}] = ${data[time_column]}, which is <= to previous time stamp(=${last_time}). Each sample's time stamp must be strictly greater than the previous one`);
196
+ }
197
+ }
198
+
199
+ }
200
+
201
+ /**
202
+ *
203
+ * @param {number[]} data
204
+ */
205
+ addSample(data) {
206
+ // validate
207
+ this.validateNextSample(data);
208
+
209
+ const table = this.table;
210
+ table.addRow(data);
211
+ }
212
+
213
+ /**
214
+ *
215
+ * @param {Object} sample
216
+ */
217
+ addObjectSample(sample) {
218
+ this.#object_to_row(scratch_row, sample);
219
+
220
+ this.addSample(scratch_row);
221
+ }
222
+
223
+ /**
224
+ *
225
+ * @param {number[]} result
226
+ * @param {number} index
227
+ */
228
+ getSampleByIndex(result, index) {
229
+ this.table.getRow(index, result)
230
+ }
231
+
232
+ /**
233
+ *
234
+ * @param {number} time
235
+ * @returns {number}
236
+ */
237
+ findLowSampleIndexByTime(time) {
238
+ const table = this.table;
239
+ const time_column_index = this.time_column_index;
240
+ return max2(0, findSampleIndex(table, time, time_column_index))
241
+ }
242
+
243
+ /**
244
+ *
245
+ * @param {number[]} result
246
+ * @param {number} result_offset
247
+ * @param {number} time
248
+ */
249
+ sampleLinear(result, result_offset, time) {
250
+ const table = this.table;
251
+ const time_column_index = this.time_column_index;
252
+
253
+ // seek to the right sample
254
+ const sample_index = this.findLowSampleIndexByTime(time);
255
+ const next_sample_index = min2(table.length - 1, sample_index + 1);
256
+
257
+ const prev = table.readCellValue(sample_index, time_column_index);
258
+ const next = table.readCellValue(next_sample_index, time_column_index);
259
+
260
+ const normalized_offset = inverseLerp(prev, next, time);
261
+
262
+ const column_count = this.spec.getColumnCount();
263
+
264
+ for (let i = 0; i < column_count; i++) {
265
+ const v0 = table.readCellValue(sample_index, i);
266
+ const v1 = table.readCellValue(next_sample_index, i);
267
+
268
+ result[result_offset + i] = lerp(v0, v1, normalized_offset)
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Get linearly interpolated sample for given time in object form, following supplied schema
274
+ * @param {number} time
275
+ * @returns {Object}
276
+ */
277
+ sampleObjectLinear(time) {
278
+
279
+ this.sampleLinear(scratch_row, 0, time);
280
+
281
+ return this.#row_to_object_allocating(scratch_row);
282
+
283
+ }
284
+
285
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ *
3
+ * @param {RowFirstTable} table
4
+ * @param {number} time
5
+ * @param {number} [column_index]
6
+ * @return {number}
7
+ */
8
+ export function findSampleIndex(table: RowFirstTable, time: number, column_index?: number): number;
9
+ //# sourceMappingURL=findSampleIndex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findSampleIndex.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/async/findSampleIndex.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,4DAJW,MAAM,iBACN,MAAM,GACL,MAAM,CAuBjB"}
@@ -0,0 +1,31 @@
1
+ import { min2 } from "../../../core/math/min2.js";
2
+
3
+ /**
4
+ *
5
+ * @param {RowFirstTable} table
6
+ * @param {number} time
7
+ * @param {number} [column_index]
8
+ * @return {number}
9
+ */
10
+ export function findSampleIndex(table, time, column_index = 0) {
11
+ let minIndex = 0;
12
+ let maxIndex = table.length - 1;
13
+
14
+ while (minIndex <= maxIndex) {
15
+
16
+ const pivotIndex = (minIndex + maxIndex) >> 1;
17
+
18
+ const cmp = time - table.readCellValue(pivotIndex, column_index);
19
+
20
+ if (cmp > 0) {
21
+ minIndex = pivotIndex + 1;
22
+ } else if (cmp < 0) {
23
+ maxIndex = pivotIndex - 1;
24
+ } else {
25
+ //set low boundary for next step based on assumption that upper bound is higher than lower bound
26
+ return pivotIndex;
27
+ }
28
+ }
29
+
30
+ return min2(minIndex, maxIndex);
31
+ }
@@ -1,11 +1,7 @@
1
1
  import { GUI } from "dat.gui";
2
2
  import { MeshBasicMaterial, MeshStandardMaterial, OctahedronBufferGeometry } from "three";
3
3
  import { BinaryDataType } from "../../../core/binary/type/BinaryDataType.js";
4
- import { RowFirstTable } from "../../../core/collection/table/RowFirstTable.js";
5
- import { RowFirstTableSpec } from "../../../core/collection/table/RowFirstTableSpec.js";
6
4
  import { Color } from "../../../core/color/Color.js";
7
- import { inverseLerp } from "../../../core/math/inverseLerp.js";
8
- import { lerp } from "../../../core/math/lerp.js";
9
5
  import { max2 } from "../../../core/math/max2.js";
10
6
  import { min2 } from "../../../core/math/min2.js";
11
7
  import { randomFloatBetween } from "../../../core/math/random/randomFloatBetween.js";
@@ -27,42 +23,14 @@ import { BehaviorComponent } from "../../intelligence/behavior/ecs/BehaviorCompo
27
23
  import { BehaviorSystem } from "../../intelligence/behavior/ecs/BehaviorSystem.js";
28
24
  import { ActionBehavior } from "../../intelligence/behavior/primitive/ActionBehavior.js";
29
25
  import { RandomDelayBehavior } from "../../intelligence/behavior/util/RandomDelayBehavior.js";
26
+ import { TimeSeries } from "./TimeSeries.js";
30
27
 
31
28
  const harness = new EngineHarness();
32
29
 
33
- /**
34
- *
35
- * @param {RowFirstTable} table
36
- * @param {number} time
37
- * @return {number}
38
- */
39
- function findSampleIndex(table, time) {
40
- let minIndex = 0;
41
- let maxIndex = table.length - 1;
42
-
43
- while (minIndex <= maxIndex) {
44
-
45
- const pivotIndex = (minIndex + maxIndex) >> 1;
46
-
47
- const cmp = time - table.readCellValue(pivotIndex, 0);
48
-
49
- if (cmp > 0) {
50
- minIndex = pivotIndex + 1;
51
- } else if (cmp < 0) {
52
- maxIndex = pivotIndex - 1;
53
- } else {
54
- //set low boundary for next step based on assumption that upper bound is higher than lower bound
55
- return pivotIndex;
56
- }
57
- }
58
-
59
- return min2(minIndex, maxIndex);
60
- }
61
-
62
30
  /**
63
31
  *
64
32
  * @param {EntityComponentDataset} ecd
65
- * @param {RowFirstTable} table
33
+ * @param {TimeSeries} table
66
34
  * @param {number} [count]
67
35
  */
68
36
  function makeGhostMarkers({
@@ -108,10 +76,12 @@ function makeGhostMarkers({
108
76
  return {
109
77
  set time(time) {
110
78
 
111
- const ref_index = findSampleIndex(table, time);
79
+ const sample = table.sampleObjectLinear(time);
80
+
81
+ const ref_index = table.findLowSampleIndexByTime(time);
112
82
 
113
83
  const start_index = max2(0, ref_index - Math.floor(count / 2));
114
- const limit_index = min2(table.length - 1, ref_index + Math.ceil(count / 2));
84
+ const limit_index = min2(table.sample_count - 1, ref_index + Math.ceil(count / 2));
115
85
 
116
86
  for (let i = 0; i < count; i++) {
117
87
 
@@ -137,10 +107,12 @@ function makeGhostMarkers({
137
107
 
138
108
  const transform = entity.getComponentSafe(Transform);
139
109
 
110
+ const sample = table.getSampleObjectByIndex(sample_index);
111
+
140
112
  transform.position.set(
141
- table.readCellValue(sample_index, 1),
142
- table.readCellValue(sample_index, 2),
143
- table.readCellValue(sample_index, 3)
113
+ sample.x,
114
+ sample.y,
115
+ sample.z
144
116
  );
145
117
 
146
118
  }
@@ -158,23 +130,19 @@ async function main(engine) {
158
130
  engine
159
131
  });
160
132
 
161
- const table = new RowFirstTable(
162
- RowFirstTableSpec.get([
163
- BinaryDataType.Float64, // time
164
- BinaryDataType.Float32, // x
165
- BinaryDataType.Float32, //y
166
- BinaryDataType.Float32 //z
167
- ])
168
- );
133
+ const timeSeries = new TimeSeries({
134
+ time: BinaryDataType.Float64,
135
+ x: BinaryDataType.Float32,
136
+ y: BinaryDataType.Float32,
137
+ z: BinaryDataType.Float32,
138
+ }, 'time');
169
139
 
170
140
  const random = seededRandom(42);
171
141
 
172
- table.addRow([
142
+ timeSeries.addSample([
173
143
  0, 0, 1, 0
174
144
  ]);
175
145
 
176
- const sample = [];
177
-
178
146
  const sim_clock = new Clock();
179
147
  sim_clock.start();
180
148
 
@@ -183,9 +151,7 @@ async function main(engine) {
183
151
  const time_delta = sim_clock.getDelta();
184
152
 
185
153
  // get last row
186
- const row_count = table.length;
187
-
188
- table.getRow(row_count - 1, sample);
154
+ const last_record = timeSeries.getSampleObjectByIndex(timeSeries.sample_count - 1);
189
155
 
190
156
  const speed = 7;
191
157
 
@@ -196,15 +162,14 @@ async function main(engine) {
196
162
  const displacement_x = displacement * Math.cos(direction);
197
163
  const displacement_y = displacement * Math.sin(direction);
198
164
 
199
- const new_x = sample[1] + displacement_x;
200
- const new_z = sample[3] + displacement_y;
165
+ const new_x = last_record.x + displacement_x;
166
+ const new_z = last_record.z + displacement_y;
201
167
 
202
- table.addRow([
203
- sample[0] + time_delta,
168
+ timeSeries.addSample([
169
+ last_record.time + time_delta,
204
170
  new_x,
205
171
  1,
206
172
  new_z,
207
-
208
173
  ]);
209
174
  }
210
175
 
@@ -226,14 +191,14 @@ async function main(engine) {
226
191
  playing: true,
227
192
  play_time: -1,
228
193
  get latest_data_time() {
229
- return table.readCellValue(table.length - 1, 0);
194
+ return timeSeries.last_timestamp;
230
195
  },
231
196
  get behind_latest() {
232
- return table.readCellValue(table.length - 1, 0) - this.play_time;
197
+ return timeSeries.last_timestamp - this.play_time;
233
198
  },
234
199
  set behind_latest(v) {
235
200
 
236
- const current_delay = table.readCellValue(table.length - 1, 0) - this.play_time;
201
+ const current_delay = timeSeries.last_timestamp - this.play_time;
237
202
 
238
203
  const delta = v - current_delay;
239
204
 
@@ -260,38 +225,21 @@ async function main(engine) {
260
225
  sim_parameters.play_time += delta;
261
226
  }
262
227
 
263
-
264
- // seek to the right sample
265
- const sample_index = max2(0, findSampleIndex(table, sim_parameters.play_time));
266
- const next_sample_index = min2(table.length - 1, sample_index + 1);
267
-
268
- const prev = table.readCellValue(sample_index, 0);
269
- const next = table.readCellValue(next_sample_index, 0);
270
-
271
- const normalized_offset = inverseLerp(prev, next, sim_parameters.play_time);
228
+ const sample = timeSeries.sampleObjectLinear(sim_parameters.play_time);
272
229
 
273
230
  const transform = subject.getComponentSafe(Transform);
274
231
 
275
- const x0 = table.readCellValue(sample_index, 1);
276
- const x1 = table.readCellValue(next_sample_index, 1);
277
-
278
- const y0 = table.readCellValue(sample_index, 2);
279
- const y1 = table.readCellValue(next_sample_index, 2);
280
-
281
- const z0 = table.readCellValue(sample_index, 3);
282
- const z1 = table.readCellValue(next_sample_index, 3);
283
-
284
232
  transform.position.set(
285
- lerp(x0, x1, normalized_offset),
286
- lerp(y0, y1, normalized_offset),
287
- lerp(z0, z1, normalized_offset),
233
+ sample.x,
234
+ sample.y,
235
+ sample.z,
288
236
  );
289
237
  })
290
238
  )))
291
239
  .build(ecd);
292
240
 
293
241
  const markers = makeGhostMarkers({
294
- ecd, table, count: 5
242
+ ecd, table: timeSeries, count: 5
295
243
  });
296
244
 
297
245
  engine.ticker.onTick.add(() => markers.time = sim_parameters.play_time);
@@ -1 +1 @@
1
- {"version":3,"file":"computeBufferAttributeHash.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/geometry/buffered/computeBufferAttributeHash.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,sDAHW,MAAM,eAAe,GACnB,MAAM,CAsBlB"}
1
+ {"version":3,"file":"computeBufferAttributeHash.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/geometry/buffered/computeBufferAttributeHash.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,sDAHW,MAAM,eAAe,GACnB,MAAM,CAyBlB"}
@@ -1,5 +1,6 @@
1
1
  import { min2 } from "../../../../core/math/min2.js";
2
- import { computeStridedIntegerArrayHash } from "../../../../core/primitives/array/computeStridedIntegerArrayHash.js";
2
+ import { computeStridedArrayHash } from "../../../../core/primitives/array/computeStridedArrayHash.js";
3
+ import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
3
4
 
4
5
  /**
5
6
  *
@@ -21,7 +22,10 @@ export function computeBufferAttributeHash(attribute) {
21
22
  // compute stride so that we don't have to iterate over the entire buffer, instead picking at most X(509) values to consider
22
23
  const stride = Math.max(1, Math.ceil(hash_evaluation_length / 31));
23
24
 
24
- result ^= computeStridedIntegerArrayHash(data, 0, hash_evaluation_length, stride);
25
+ result ^= computeStridedArrayHash(
26
+ data, 0, hash_evaluation_length, stride,
27
+ computeHashFloat
28
+ );
25
29
 
26
30
  }
27
31
 
@@ -1 +1 @@
1
- {"version":3,"file":"ParticleEmitter.d.ts","sourceRoot":"","sources":["../../../../../../../../src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js"],"names":[],"mappings":"AA0FA;IAuiCI;;;;OAIG;IACH,4BAFa,eAAe,CAM3B;IA/iCD;;OAEG;IACH,IAFU,MAAM,CAEE;IAElB;;;;OAIG;IACH,wBAAoB;IAEpB;;;OAGG;IACH,UAFU,OAAO,CAEe;IAChC,eAA6B;IAC7B,qBAAsC;IAEtC;;;;;OAKG;IACH,qCAA2C;IAE3C;;;;OAIG;IACH,WAFU,MAAM,CAEF;IAEd;;;OAGG;IACH,cAFU,YAAY,GAAC,MAAM,CAEM;IAEnC;;;OAGG;IACH,WAFU,YAAY,GAAC,IAAI,CAEV;IAEjB;;;OAGG;IACH,MAFU,WAAS,IAAI,CAEX;IAEZ;;;OAGG;IACH,mBAFU,SAAS,CAEQ;IAG3B;;;;OAIG;IACH,yBAFU,KAAK,CAE2E;IAE1F;;;OAGG;IACH,yBAFU,KAAK,CAE8B;IAG7C;;;OAGG;IACH,OAFU,MAAM,CAE6F;IAE7G;;;;OAIG;IACH,eAAW;IAGX;;;OAGG;IACH,qBAFU,YAAY,CAEU;IAWhC,wBAIC;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,SAC1B,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,OAAO,CAInB;IAED;;OAEG;IACH,gCAaC;IAED;;;;;;;;;;;;;MAeC;IAED,0BAkEC;IAGD;;;OAGG;IACH,gBAFW,aAAa,QASvB;IAED;;;;OAIG;IACH,kDAUC;IAED;;;;OAIG;IACH,iCAHW,aAAa,GACZ,MAAM,CA2CjB;IAED,8BA0DC;IAED,8BAmBC;IAED,2BAmBC;IAED,6BAkBC;IAED;;;OAGG;IACH,uCAHW,MAAM,GACJ,MAAM,CA+BlB;IAED,cAuCC;IAED,mBA6BC;IAuBD,eAOC;IAED;;;;OAIG;IACH,cAHW,eAAe,GACb,OAAO,CAQnB;IAED;;;;OAIG;IACH,qCAyFC;IAED,eAOC;IAED;;;OAGG;IACH,4BAFY,MAAM,CAejB;IAED;;;OAGG;IACH,mBAFW,MAAM,QAMhB;IAiCD;;;;OAIG;IACH,sCA+GC;IAED;;;;OAIG;IACH,qCA6GC;IAED;;;OAGG;IACH,aA4CC;IAGD;;OAEG;IACH,gBAIC;;CAYJ;;;;;;;;;;;;;;;;oBAhoCmB,wCAAwC;uBAFrC,2CAA2C;6BAOrC,6CAA6C;6BAqB7C,mBAAmB;0BAnCtB,+CAA+C;sBAGnD,8CAA8C;6BAYvC,8BAA8B;oCAiBvB,0BAA0B;8BAChC,oBAAoB;uCAF3C,0BAA0B;6CAA1B,0BAA0B;kDAA1B,0BAA0B;4CAA1B,0BAA0B;4CAA1B,0BAA0B;kDAA1B,0BAA0B;wCAA1B,0BAA0B;sCAA1B,0BAA0B;4CAA1B,0BAA0B;AAWjC,yCAKC"}
1
+ {"version":3,"file":"ParticleEmitter.d.ts","sourceRoot":"","sources":["../../../../../../../../src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js"],"names":[],"mappings":"AA2FA;IAyiCI;;;;OAIG;IACH,4BAFa,eAAe,CAM3B;IAjjCD;;OAEG;IACH,IAFU,MAAM,CAEE;IAElB;;;;OAIG;IACH,wBAAoB;IAEpB;;;OAGG;IACH,UAFU,OAAO,CAEe;IAChC,eAA6B;IAC7B,qBAAsC;IAEtC;;;;;OAKG;IACH,qCAA2C;IAE3C;;;;OAIG;IACH,WAFU,MAAM,CAEF;IAEd;;;OAGG;IACH,cAFU,YAAY,GAAC,MAAM,CAEM;IAEnC;;;OAGG;IACH,WAFU,YAAY,GAAC,IAAI,CAEV;IAEjB;;;OAGG;IACH,MAFU,WAAS,IAAI,CAEX;IAEZ;;;OAGG;IACH,mBAFU,SAAS,CAEQ;IAG3B;;;;OAIG;IACH,yBAFU,KAAK,CAE2E;IAE1F;;;OAGG;IACH,yBAFU,KAAK,CAE8B;IAG7C;;;OAGG;IACH,OAFU,MAAM,CAE6F;IAE7G;;;;OAIG;IACH,eAAW;IAGX;;;OAGG;IACH,qBAFU,YAAY,CAEU;IAWhC,wBAIC;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,SAC1B,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,OAAO,CAInB;IAED;;OAEG;IACH,gCAaC;IAED;;;;;;;;;;;;;MAeC;IAED,0BAkEC;IAGD;;;OAGG;IACH,gBAFW,aAAa,QASvB;IAED;;;;OAIG;IACH,kDAUC;IAED;;;;OAIG;IACH,iCAHW,aAAa,GACZ,MAAM,CA2CjB;IAED,8BA0DC;IAED,8BAmBC;IAED,2BAmBC;IAED,6BAkBC;IAED;;;OAGG;IACH,uCAHW,MAAM,GACJ,MAAM,CA+BlB;IAED,cAuCC;IAED,mBA6BC;IAuBD,eAOC;IAED;;;;OAIG;IACH,cAHW,eAAe,GACb,OAAO,CAQnB;IAED;;;;OAIG;IACH,qCA2FC;IAED,eAOC;IAED;;;OAGG;IACH,4BAFY,MAAM,CAejB;IAED;;;OAGG;IACH,mBAFW,MAAM,QAMhB;IAiCD;;;;OAIG;IACH,sCA+GC;IAED;;;;OAIG;IACH,qCA6GC;IAED;;;OAGG;IACH,aA4CC;IAGD;;OAEG;IACH,gBAIC;;CAYJ;;;;;;;;;;;;;;;;oBAloCmB,wCAAwC;uBAFrC,2CAA2C;6BAOrC,6CAA6C;6BAqB7C,mBAAmB;0BApCtB,+CAA+C;sBAInD,8CAA8C;6BAYvC,8BAA8B;oCAiBvB,0BAA0B;8BAChC,oBAAoB;uCAF3C,0BAA0B;6CAA1B,0BAA0B;kDAA1B,0BAA0B;4CAA1B,0BAA0B;4CAA1B,0BAA0B;kDAA1B,0BAA0B;wCAA1B,0BAA0B;sCAA1B,0BAA0B;4CAA1B,0BAA0B;AAWjC,yCAKC"}
@@ -3,6 +3,7 @@ import { assert } from "../../../../../../core/assert.js";
3
3
  import { BvhClient } from "../../../../../../core/bvh2/bvh3/BvhClient.js";
4
4
  import { computeHashIntegerArray } from "../../../../../../core/collection/array/computeHashIntegerArray.js";
5
5
  import List from "../../../../../../core/collection/list/List.js";
6
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../../../../core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
6
7
  import { AABB3 } from "../../../../../../core/geom/3d/aabb/AABB3.js";
7
8
  import { aabb3_array_combine } from "../../../../../../core/geom/3d/aabb/aabb3_array_combine.js";
8
9
  import { aabb3_expand_array } from "../../../../../../core/geom/3d/aabb/aabb3_expand_array.js";
@@ -60,9 +61,9 @@ const scratch_near_plane_normal = new Float32Array(3);
60
61
 
61
62
  /**
62
63
  *
63
- * @type {number[]}
64
+ * @type {Float32Array}
64
65
  */
65
- const scratch_array = [];
66
+ const scratch_aabb3 = new Float32Array(6);
66
67
 
67
68
  /**
68
69
  *
@@ -484,17 +485,17 @@ export class ParticleEmitter {
484
485
  //retire dead particles
485
486
  const particles = this.particles;
486
487
 
487
- particles.computeAttributeVector3AxisAlignedBoundingBox(PARTICLE_ATTRIBUTE_POSITION, scratch_array);
488
+ particles.computeAttributeVector3AxisAlignedBoundingBox(PARTICLE_ATTRIBUTE_POSITION, scratch_aabb3);
488
489
 
489
490
  //expand bounds by maximum sprite size
490
491
  const extents = this.computeSpriteMaxHalfSize();
491
492
 
492
- aabb3_expand_array(scratch_array, scratch_array, extents);
493
+ aabb3_expand_array(scratch_aabb3, scratch_aabb3, extents);
493
494
 
494
495
  //write updated bonds
495
496
  const bb = this.particleBounds;
496
497
 
497
- bb.readFromArray(scratch_array);
498
+ bb.readFromArray(scratch_aabb3);
498
499
 
499
500
  this.updateGeometryBounds();
500
501
 
@@ -516,7 +517,7 @@ export class ParticleEmitter {
516
517
  const ebb = this.emissionBounds;
517
518
  const pbb = this.particleBounds;
518
519
 
519
- aabb3_array_combine(this.bvh_leaf.bounds,0, ebb,0, pbb,0);
520
+ aabb3_array_combine(this.bvh_leaf.bounds, 0, ebb, 0, pbb, 0);
520
521
 
521
522
  this.bvh_leaf.write_bounds();
522
523
 
@@ -732,15 +733,17 @@ export class ParticleEmitter {
732
733
  }
733
734
 
734
735
  //Stack-based implementation, avoiding recursion for performance improvement
735
- const stack = scratch_array;
736
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
737
+
738
+ const stack_top = stack.pointer;
739
+ let stackPointer = stack_top;
736
740
 
737
- stack[0] = 0;
738
- stack[1] = particleCount - 1;
741
+ stack[stackPointer++] = 0;
742
+ stack[stackPointer++] = particleCount - 1;
739
743
 
740
- let stackPointer = 2;
741
744
  let i, j;
742
745
 
743
- while (stackPointer > 0) {
746
+ while (stackPointer > stack_top) {
744
747
  stackPointer -= 2;
745
748
 
746
749
  const right = stack[stackPointer + 1];
@@ -525,7 +525,7 @@ export class ParticlePool {
525
525
 
526
526
  const data = attribute.array;
527
527
 
528
- aabb3_from_v3_array(result,data,particle_count*3);
528
+ aabb3_from_v3_array(result, data, particle_count * 3);
529
529
 
530
530
  }
531
531