@woosh/meep-engine 2.29.0 → 2.30.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.
Files changed (27) hide show
  1. package/core/process/worker/WorkerBuilder.js +5 -1
  2. package/engine/Engine.d.ts +5 -1
  3. package/engine/Engine.js +35 -17
  4. package/engine/EngineHarness.js +9 -1
  5. package/engine/asset/loaders/image/codec/CodecWithFallback.js +1 -1
  6. package/engine/asset/loaders/image/png/PNGReader.js +19 -21
  7. package/engine/ecs/EntityManager.js +10 -0
  8. package/engine/graphics/ecs/camera/topdown/ComputeCameraFacingVector.js +21 -0
  9. package/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +10 -14
  10. package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +4 -24
  11. package/engine/graphics/particles/particular/engine/ParticularEngine.js +1 -0
  12. package/engine/graphics/particles/particular/engine/emitter/PARTICLE_ATTRIBUTES.js +3 -0
  13. package/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +27 -15
  14. package/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +30 -10
  15. package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +4 -6
  16. package/engine/graphics/particles/particular/engine/parameter/ParameterTrackSet.js +6 -3
  17. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +271 -1
  18. package/engine/graphics/particles/particular/engine/renderers/billboard/prototypeBillboardRenderer.js +164 -0
  19. package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +10 -555
  20. package/engine/graphics/particles/particular/engine/simulator/AbstractSimulationStep.js +6 -0
  21. package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +16 -1
  22. package/engine/graphics/particles/particular/engine/simulator/update_parameters.js +41 -0
  23. package/engine/graphics/render/buffer/FrameBufferManager.js +2 -0
  24. package/engine/graphics/render/visibility/IncrementalDeltaSet.js +5 -0
  25. package/engine/graphics/render/visibility/VisibilityComputer.js +6 -6
  26. package/engine/graphics/render/visibility/VisibilityFilter.js +10 -0
  27. package/package.json +1 -1
@@ -125,7 +125,11 @@ WorkerBuilder.prototype.build = function () {
125
125
  ' if(method === undefined){',
126
126
  ' sendError(new Error("API named \'"+methodName+"\' was not found."));',
127
127
  ' }else{',
128
- ' method.apply(null,parameters).then(sendResult, sendError);',
128
+ ' try{',
129
+ ' method.apply(null,parameters).then(sendResult, sendError);',
130
+ ' }catch(e){',
131
+ ' sendError(e);',
132
+ ' }',
129
133
  ' }',
130
134
  '};'
131
135
  ]);
@@ -9,8 +9,12 @@ import {EntityManager} from "./ecs/EntityManager";
9
9
  import View from "../view/View";
10
10
  import Ticker from "./simulation/Ticker";
11
11
 
12
+ export interface IEngineInitializationOptions {
13
+ entityManager?: EntityManager
14
+ }
15
+
12
16
  export default class Engine {
13
- constructor(platform: EnginePlatform);
17
+ constructor(platform: EnginePlatform, options?: IEngineInitializationOptions);
14
18
 
15
19
  public get viewStack(): View
16
20
 
package/engine/Engine.js CHANGED
@@ -52,9 +52,10 @@ class Engine {
52
52
  /**
53
53
  *
54
54
  * @param {EnginePlatform} platform
55
+ * @param {EntityManager} [entityManager]
55
56
  * @constructor
56
57
  */
57
- constructor(platform) {
58
+ constructor(platform, { entityManager } = {}) {
58
59
  assert.defined(platform, 'platform');
59
60
 
60
61
  /**
@@ -81,6 +82,21 @@ class Engine {
81
82
  */
82
83
  this.performance = new MetricCollection();
83
84
 
85
+ const using_external_entity_manager = entityManager !== undefined;
86
+
87
+ //setup entity component system
88
+ if (using_external_entity_manager) {
89
+ // external entity manager provided
90
+ this.entityManager = entityManager;
91
+ } else {
92
+ this.entityManager = new EntityManager();
93
+ }
94
+
95
+ /**
96
+ *
97
+ * @type {Ticker}
98
+ */
99
+ this.ticker = new Ticker();
84
100
 
85
101
  this.__performacne_monitor = new PeriodicConsolePrinter(15, () => {
86
102
  const metrics = this.performance;
@@ -112,6 +128,22 @@ class Engine {
112
128
  return `FPS: ${v_fps}, RENDER: ${v_render}ms, SIMULATION: ${v_sim}ms`;
113
129
  });
114
130
 
131
+
132
+ if (!using_external_entity_manager) {
133
+ // subscribe simulator to common ticker
134
+ this.ticker.subscribe(timeDelta => {
135
+ const t0 = performance.now();
136
+ this.entityManager.simulate(timeDelta);
137
+
138
+ const t1 = performance.now();
139
+ const duration = (t1 - t0) / 1000;
140
+
141
+ // record frame time
142
+ this.performance.get(METRIC_ID_SIMULATION).record(duration);
143
+ });
144
+ }
145
+
146
+
115
147
  this.initialize();
116
148
  }
117
149
 
@@ -168,9 +200,6 @@ class Engine {
168
200
  this.localization = new Localization();
169
201
  this.localization.setAssetManager(this.assetManager);
170
202
 
171
- //setup entity component system
172
- const em = this.entityManager = new EntityManager();
173
-
174
203
 
175
204
  const innerWidth = window.innerWidth / 3;
176
205
  const innerHeight = window.innerHeight / 3;
@@ -182,7 +211,7 @@ class Engine {
182
211
  *
183
212
  * @type {GraphicsEngine}
184
213
  */
185
- const ge = this.graphics = new GraphicsEngine(this.camera, em);
214
+ const ge = this.graphics = new GraphicsEngine(this.camera, this.entityManager);
186
215
 
187
216
  try {
188
217
  ge.start();
@@ -208,18 +237,6 @@ class Engine {
208
237
  */
209
238
  this.gui = new GUIEngine();
210
239
 
211
- this.ticker = new Ticker();
212
- this.ticker.subscribe(timeDelta => {
213
- const t0 = performance.now();
214
- this.entityManager.simulate(timeDelta);
215
-
216
- const t1 = performance.now();
217
- const duration = (t1 - t0) / 1000;
218
-
219
- // record frame time
220
- this.performance.get(METRIC_ID_SIMULATION).record(duration);
221
- });
222
-
223
240
  /**
224
241
  * @readonly
225
242
  * @type {SceneManager}
@@ -492,6 +509,7 @@ class Engine {
492
509
 
493
510
  const frame_delay = (t1 - t0) / 1000;
494
511
 
512
+ // swap variables
495
513
  t0 = t1;
496
514
 
497
515
  // record metric
@@ -24,6 +24,8 @@ import WaterSystem from "./graphics/ecs/water/WaterSystem.js";
24
24
  import KeyboardCameraController from "./input/ecs/controllers/KeyboardCameraController.js";
25
25
  import { EngineConfiguration } from "./EngineConfiguration.js";
26
26
  import { JsonAssetLoader } from "./asset/loaders/JsonAssetLoader.js";
27
+ import { logger } from "./logging/GlobalLogger.js";
28
+ import { ConsoleLoggerBackend } from "./logging/ConsoleLoggerBackend.js";
27
29
 
28
30
  /**
29
31
  *
@@ -77,6 +79,8 @@ export class EngineHarness {
77
79
 
78
80
  window.engine = this.engine;
79
81
 
82
+ logger.addBackend(new ConsoleLoggerBackend());
83
+
80
84
  this.p = null;
81
85
  }
82
86
 
@@ -321,7 +325,7 @@ export class EngineHarness {
321
325
 
322
326
  /**
323
327
  *
324
- * @param {number} cameraEntity
328
+ * @param {number} [cameraEntity]
325
329
  * @param {Engine} engine
326
330
  * @param {number} [sensitivity]
327
331
  * @param {Element} domElement
@@ -335,6 +339,10 @@ export class EngineHarness {
335
339
  sensitivity = 0.01
336
340
  }) {
337
341
 
342
+ if (cameraEntity === undefined) {
343
+ cameraEntity = ecd.getAnyComponent(Camera).entity;
344
+ }
345
+
338
346
  const em = engine.entityManager;
339
347
 
340
348
  if (em.getSystem(InputControllerSystem) === null) {
@@ -17,7 +17,7 @@ export class CodecWithFallback extends Codec {
17
17
  async decode(data) {
18
18
 
19
19
  try {
20
- return this.main.decode(data);
20
+ return await this.main.decode(data);
21
21
  } catch (e) {
22
22
  logger.warn(`Main codec failed, will attempt fallback. Error: ${e}`);
23
23
 
@@ -7,19 +7,6 @@ import { PNG } from './PNG.js';
7
7
  import { BinaryBuffer } from "../../../../../core/binary/BinaryBuffer.js";
8
8
  import { isArrayEqualStrict } from "../../../../../core/collection/array/isArrayEqualStrict.js";
9
9
 
10
- var inflate = function (data, callback) {
11
- let result;
12
-
13
- try {
14
- result = zlib.inflate(new Uint8Array(data));
15
-
16
- callback(null, result);
17
- } catch (e) {
18
- callback(e);
19
- }
20
-
21
- };
22
-
23
10
  function readUInt32(buffer, offset) {
24
11
  return (buffer[offset] << 24) +
25
12
  (buffer[offset + 1] << 16) +
@@ -294,11 +281,14 @@ PNGReader.prototype.unFilterNone = function (scanline, scanline_offset, pixels,
294
281
  PNGReader.prototype.unFilterSub = function (scanline, scanline_offset, pixels, bpp, of, length) {
295
282
  var i = 0;
296
283
 
297
- for (; i < bpp; i++) pixels[of + i] = scanline[i + scanline_offset];
284
+ for (; i < bpp; i++) {
285
+ pixels[of + i] = scanline[i + scanline_offset];
286
+ }
298
287
 
299
288
  for (; i < length; i++) {
300
289
  // Raw(x) + Raw(x - bpp)
301
- pixels[of + i] = (scanline[i + scanline_offset] + pixels[of + i - bpp]) & 0xFF;
290
+ const of_i = of + i;
291
+ pixels[of_i] = (scanline[i + scanline_offset] + pixels[of_i - bpp]) & 0xFF;
302
292
  }
303
293
  };
304
294
 
@@ -336,19 +326,26 @@ PNGReader.prototype.unFilterAverage = function (scanline, scanline_offset, pixel
336
326
  }
337
327
  // Prior(x) == 0 && Raw(x - bpp) != 0 (right shift, prevent doubles)
338
328
  for (; i < length; i++) {
339
- pixels[of + i] = (scanline[i + scanline_offset] + (pixels[of + i - bpp] >> 1)) & 0xFF;
329
+ const of_i = of + i;
330
+ pixels[of_i] = (scanline[i + scanline_offset] + (pixels[of_i - bpp] >> 1)) & 0xFF;
340
331
  }
341
332
  } else {
342
333
  // Prior(x) != 0 && Raw(x - bpp) == 0
343
334
  for (; i < bpp; i++) {
344
- pixels[of + i] = (scanline[i + scanline_offset] + (pixels[of - length + i] >> 1)) & 0xFF;
335
+ const of_i = of + i;
336
+
337
+ pixels[of_i] = (scanline[i + scanline_offset] + (pixels[of_i - length] >> 1)) & 0xFF;
345
338
  }
346
339
  // Prior(x) != 0 && Raw(x - bpp) != 0
347
340
  for (; i < length; i++) {
348
341
  byte = scanline[i + scanline_offset];
349
- prev = pixels[of + i - bpp];
350
- prior = pixels[of + i - length];
351
- pixels[of + i] = (byte + (prev + prior >> 1)) & 0xFF;
342
+
343
+ const of_i = of + i;
344
+
345
+ prev = pixels[of_i - bpp];
346
+ prior = pixels[of_i - length];
347
+
348
+ pixels[of_i] = (byte + (prev + prior >> 1)) & 0xFF;
352
349
  }
353
350
  }
354
351
  };
@@ -387,10 +384,11 @@ PNGReader.prototype.unFilterPaeth = function (scanline, scanline_offset, pixels,
387
384
  pixels[of + i] = (scanline[i + scanline_offset] + pixels[of + i - bpp]) & 0xFF;
388
385
  }
389
386
  } else {
387
+ const of1 = of - length;
390
388
  // Prior(x) != 0 && Raw(x - bpp) == 0
391
389
  // paethPredictor(x, 0, 0) is always x
392
390
  for (; i < bpp; i++) {
393
- pixels[of + i] = (scanline[i + scanline_offset] + pixels[of + i - length]) & 0xFF;
391
+ pixels[of + i] = (scanline[i + scanline_offset] + pixels[of1 + i]) & 0xFF;
394
392
  }
395
393
  // Prior(x) != 0 && Raw(x - bpp) != 0
396
394
  for (; i < length; i++) {
@@ -699,6 +699,16 @@ EntityManager.prototype.startSystem = function (system, successCallback, errorCa
699
699
  * @param {function} errorCallback executed if entity manager encounters an error during startup
700
700
  */
701
701
  EntityManager.prototype.startup = function (readyCallback, errorCallback) {
702
+ if (this.state === EntityManagerState.Starting) {
703
+ throw new IllegalStateException(`System is currently in starting state`);
704
+ }
705
+
706
+ if (this.state === EntityManagerState.Running) {
707
+ // already running, do nothing
708
+ readyCallback();
709
+ return;
710
+ }
711
+
702
712
  assert.isFunction(readyCallback, 'readyCallback');
703
713
  assert.isFunction(errorCallback, 'errorCallback');
704
714
 
@@ -0,0 +1,21 @@
1
+ import Quaternion from "../../../../../core/geom/Quaternion.js";
2
+ import Vector3 from "../../../../../core/geom/Vector3.js";
3
+
4
+ const q = new Quaternion();
5
+
6
+ /**
7
+ *
8
+ * @param {number} yaw
9
+ * @param {number} pitch
10
+ * @param roll
11
+ * @param {Vector3} result
12
+ */
13
+ export function computeCameraFacingVector(yaw, pitch, roll, result) {
14
+ q.__setFromEuler(pitch, yaw, roll, 'ZYX');
15
+ q.normalize();
16
+
17
+ result.copy(Vector3.forward);
18
+ result.applyQuaternion(q);
19
+ result.normalize();
20
+
21
+ }
@@ -10,6 +10,7 @@ import { Euler, Matrix4 } from "three";
10
10
 
11
11
  const m4 = new Matrix4();
12
12
  const euler = new Euler();
13
+ const scratch_vector3 = new Vector3();
13
14
 
14
15
  const panOffset = new Vector3();
15
16
 
@@ -21,25 +22,20 @@ const panOffset = new Vector3();
21
22
  * @param {TopDownCameraController} output rotation delta
22
23
  */
23
24
  export function rotate_from_view(displacement_x, displacement_y, input, output) {
24
- const rotation_matrix = new Matrix4();
25
25
 
26
- const euler = new Euler(-displacement_y, displacement_x, 0, 'ZYX');
27
- rotation_matrix.makeRotationFromEuler(euler);
26
+ euler.set(input.pitch, input.yaw, input.roll)
27
+ m4.makeRotationFromEuler(euler);
28
28
 
29
- // get rotation matrix from controller
30
- const euler1 = new Euler(input.pitch, input.yaw, input.roll, 'ZYX');
29
+ const up = scratch_vector3;
30
+ scratch_vector3.copy(Vector3.up);
31
31
 
32
- const m_original = new Matrix4();
33
- m_original.makeRotationFromEuler(euler1);
32
+ up.applyMatrix4_three(m4);
34
33
 
35
- rotation_matrix.multiplyMatrices(m_original, rotation_matrix);
34
+ // detect when camera is upside-down
35
+ const y_multiplier = up.y <= 0 ? -1 : 1;
36
36
 
37
- // extract new rotation
38
- euler.setFromRotationMatrix(rotation_matrix);
39
-
40
- output.pitch = euler.x;
41
- output.yaw = euler.y;
42
- output.roll = euler.z;
37
+ output.pitch -= displacement_y;
38
+ output.yaw += displacement_x * y_multiplier;
43
39
  }
44
40
 
45
41
  /**
@@ -13,7 +13,6 @@ import { System } from '../../../../ecs/System.js';
13
13
  import TopDownCameraController from './TopDownCameraController.js';
14
14
 
15
15
  import { Euler as ThreeEuler } from 'three';
16
- import Quaternion from "../../../../../core/geom/Quaternion.js";
17
16
 
18
17
 
19
18
  const v3_scratch = new Vector3();
@@ -74,25 +73,6 @@ export function computeTopDownTransform(control, result) {
74
73
  result.position.copy(v3_scratch);
75
74
  }
76
75
 
77
- const q = new Quaternion();
78
-
79
- /**
80
- *
81
- * @param {number} yaw
82
- * @param {number} pitch
83
- * @param roll
84
- * @param {Vector3} result
85
- */
86
- export function computeCameraFacingVector(yaw, pitch, roll, result) {
87
- q.__setFromEuler(pitch, yaw, roll, 'ZYX');
88
- q.normalize();
89
-
90
- result.copy(Vector3.forward);
91
- result.applyQuaternion(q);
92
- result.normalize();
93
-
94
- }
95
-
96
76
  /**
97
77
  *
98
78
  * @param {Transform} transform
@@ -123,11 +103,11 @@ export function setCameraControllerFromTransform(transform, controller, distance
123
103
 
124
104
  controller.distance = distance;
125
105
 
126
- const targetOffset = direction.clone()
127
- .multiplyScalar(controller.distance);
106
+ const targetOffset = direction.clone();
107
+ targetOffset.multiplyScalar(controller.distance);
128
108
 
129
- const target = transform.position.clone()
130
- .sub(targetOffset);
109
+ const target = transform.position.clone();
110
+ target.sub(targetOffset);
131
111
 
132
112
  controller.target.copy(target)
133
113
  }
@@ -132,6 +132,7 @@ ParticularEngine.prototype.advanceEmitter = function (emitter, timeDelta) {
132
132
 
133
133
  const step = steps[type];
134
134
 
135
+ step.emitter = emitter;
135
136
  step.timeDelta = timeDelta;
136
137
  step.particles = emitter.particles;
137
138
  step.layer_parameters[j] = stepDefinition.parameters;
@@ -3,7 +3,10 @@ export const PARTICLE_ATTRIBUTE_AGE = 1;
3
3
  export const PARTICLE_ATTRIBUTE_DEATH_AGE = 2;
4
4
  export const PARTICLE_ATTRIBUTE_UV = 3;
5
5
  export const PARTICLE_ATTRIBUTE_SIZE = 4;
6
+ export const PARTICLE_ATTRIBUTE_SIZE_INITIAL = 11;
6
7
  export const PARTICLE_ATTRIBUTE_LAYER_POSITION = 5;
7
8
  export const PARTICLE_ATTRIBUTE_VELOCITY = 6;
8
9
  export const PARTICLE_ATTRIBUTE_ROTATION = 7;
9
10
  export const PARTICLE_ATTRIBUTE_ROTATION_SPEED = 8;
11
+ export const PARTICLE_ATTRIBUTE_COLOR = 9;
12
+ export const PARTICLE_ATTRIBUTE_BLEND = 10;
@@ -22,12 +22,14 @@ import { ParticleEmitterFlag } from "./ParticleEmitterFlag.js";
22
22
  import { AABB3 } from "../../../../../../core/bvh2/aabb3/AABB3.js";
23
23
  import {
24
24
  PARTICLE_ATTRIBUTE_AGE,
25
+ PARTICLE_ATTRIBUTE_BLEND,
25
26
  PARTICLE_ATTRIBUTE_DEATH_AGE,
26
27
  PARTICLE_ATTRIBUTE_LAYER_POSITION,
27
28
  PARTICLE_ATTRIBUTE_POSITION,
28
29
  PARTICLE_ATTRIBUTE_ROTATION,
29
30
  PARTICLE_ATTRIBUTE_ROTATION_SPEED,
30
31
  PARTICLE_ATTRIBUTE_SIZE,
32
+ PARTICLE_ATTRIBUTE_SIZE_INITIAL,
31
33
  PARTICLE_ATTRIBUTE_UV,
32
34
  PARTICLE_ATTRIBUTE_VELOCITY
33
35
  } from "./PARTICLE_ATTRIBUTES.js";
@@ -39,7 +41,7 @@ import { randomPointInBox } from "../../../../../../core/geom/random/randomPoint
39
41
  import { randomPointOnBox } from "../../../../../../core/geom/random/randomPointOnBox.js";
40
42
  import { EmissionFromType } from "./EmissionFromType.js";
41
43
  import { EmissionShapeType } from "./EmissionShapeType.js";
42
-
44
+ import { update_parameters } from "../simulator/update_parameters.js";
43
45
 
44
46
  const EMPTY_GEOMETRY = new BufferGeometry();
45
47
 
@@ -635,7 +637,7 @@ export class ParticleEmitter {
635
637
 
636
638
  build() {
637
639
 
638
- this.particles = new ParticlePool(particleSpecification);
640
+ this.particles = new ParticlePool(PARTICULAR_PARTICLE_SPECIFICATION);
639
641
 
640
642
  //make overallocation a bit more aggressive to prevent frequent resizing
641
643
  this.particles.shrinkFactor = 0.5;
@@ -1004,7 +1006,7 @@ export class ParticleEmitter {
1004
1006
  //write particle size
1005
1007
  const size = layer.particleSize.sampleRandom(random);
1006
1008
 
1007
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE, size);
1009
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
1008
1010
 
1009
1011
  //write UV
1010
1012
  const atlasPatch = layer.__atlasPatch;
@@ -1027,6 +1029,10 @@ export class ParticleEmitter {
1027
1029
  }
1028
1030
 
1029
1031
  particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerPosition);
1032
+
1033
+ update_parameters(ref, particles, layer, initialAge / deathAge);
1034
+
1035
+ particles.writeAttributeScalar(ref,PARTICLE_ATTRIBUTE_BLEND,this.blendingMode);
1030
1036
  }
1031
1037
 
1032
1038
  //update time buffer
@@ -1124,7 +1130,7 @@ export class ParticleEmitter {
1124
1130
  //write size
1125
1131
  const size = layer.particleSize.sampleRandom(random);
1126
1132
 
1127
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE, size);
1133
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
1128
1134
 
1129
1135
  //write UV
1130
1136
  const atlasPatch = layer.__atlasPatch;
@@ -1151,6 +1157,9 @@ export class ParticleEmitter {
1151
1157
 
1152
1158
  particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerPosition);
1153
1159
 
1160
+ update_parameters(ref, particles, layer, initialAge / deathAge);
1161
+
1162
+ particles.writeAttributeScalar(ref,PARTICLE_ATTRIBUTE_BLEND,this.blendingMode);
1154
1163
  }
1155
1164
 
1156
1165
  if (spritesNeedUpdate) {
@@ -1253,17 +1262,20 @@ const defaultPointsMaterial = new PointsMaterial({ color: 0xFFFFFF });
1253
1262
 
1254
1263
 
1255
1264
  //build particle spec
1256
- const particleSpecification = new ParticleSpecification();
1257
-
1258
- particleSpecification.add(new ParticleAttribute('position', ParticleAttributeType.Vector3, ParticleDataType.Float32));
1259
- particleSpecification.add(new ParticleAttribute('age', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1260
- particleSpecification.add(new ParticleAttribute('deathAge', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1261
- particleSpecification.add(new ParticleAttribute('atlasPatch', ParticleAttributeType.Vector4, ParticleDataType.Float32));
1262
- particleSpecification.add(new ParticleAttribute('size', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1263
- particleSpecification.add(new ParticleAttribute('layerPosition', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1264
- particleSpecification.add(new ParticleAttribute('velocity', ParticleAttributeType.Vector3, ParticleDataType.Float32));
1265
- particleSpecification.add(new ParticleAttribute('rotation', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1266
- particleSpecification.add(new ParticleAttribute('rotationSpeed', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1265
+ export const PARTICULAR_PARTICLE_SPECIFICATION = new ParticleSpecification();
1266
+
1267
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('position', ParticleAttributeType.Vector3, ParticleDataType.Float32));
1268
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('age', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1269
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('deathAge', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1270
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('atlasPatch', ParticleAttributeType.Vector4, ParticleDataType.Float32));
1271
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('size', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1272
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('layerPosition', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1273
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('velocity', ParticleAttributeType.Vector3, ParticleDataType.Float32));
1274
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('rotation', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1275
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('rotationSpeed', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1276
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('color', ParticleAttributeType.Vector4, ParticleDataType.Float32));
1277
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('blending', ParticleAttributeType.Scalar, ParticleDataType.Uint8));
1278
+ PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('size_initial', ParticleAttributeType.Scalar, ParticleDataType.Float32));
1267
1279
 
1268
1280
 
1269
1281
  const frustum = new Frustum();
@@ -74,8 +74,10 @@ export class ParticlePool {
74
74
  this.occupancy.set(index, true);
75
75
 
76
76
  //ensure attribute arrays are large enough
77
- if (this.capacity < index + 1) {
78
- this.growCapacity(index + 1);
77
+ const min_capacity = index + 1;
78
+
79
+ if (this.capacity < min_capacity) {
80
+ this.growCapacity(min_capacity);
79
81
  }
80
82
 
81
83
  return index;
@@ -86,7 +88,9 @@ export class ParticlePool {
86
88
  * @returns {boolean}
87
89
  */
88
90
  hasHoles() {
89
- return this.occupancy.nextClearBit(0) < this.occupancy.size();
91
+ const occupancy = this.occupancy;
92
+
93
+ return occupancy.nextClearBit(0) < occupancy.size();
90
94
  }
91
95
 
92
96
  /**
@@ -111,6 +115,8 @@ export class ParticlePool {
111
115
  holeIndex = occupancy.nextClearBit(0);
112
116
  lastIndex = occupancy.previousSetBit(occupancy.size());
113
117
 
118
+ const attributes = this.attributes;
119
+
114
120
  while (holeIndex < lastIndex) {
115
121
 
116
122
  //move occupancy flag from the last to the hole
@@ -119,7 +125,7 @@ export class ParticlePool {
119
125
 
120
126
  //move attribute values
121
127
  for (attributeIndex = 0; attributeIndex < numAttributes; attributeIndex++) {
122
- const attribute = this.attributes[attributeIndex];
128
+ const attribute = attributes[attributeIndex];
123
129
 
124
130
  const itemSize = attribute.itemSize;
125
131
 
@@ -127,13 +133,13 @@ export class ParticlePool {
127
133
  *
128
134
  * @type {Float32Array}
129
135
  */
130
- const oldArray = attribute.array;
136
+ const attribute_array = attribute.array;
131
137
 
132
138
  //do swaps in the old array
133
139
  const targetIndex = holeIndex * itemSize;
134
140
  const sourceIndex = lastIndex * itemSize;
135
141
 
136
- oldArray.copyWithin(targetIndex, sourceIndex, sourceIndex + itemSize);
142
+ attribute_array.copyWithin(targetIndex, sourceIndex, sourceIndex + itemSize);
137
143
  }
138
144
 
139
145
  //move hole and last cursors
@@ -269,7 +275,14 @@ export class ParticlePool {
269
275
  * @param {number} capacity
270
276
  */
271
277
  growCapacity(capacity) {
272
- const newCapacity = Math.floor(max3(capacity, this.capacity * this.growFactor, this.capacity + GROW_MIN_STEP));
278
+ const newCapacity = Math.floor(
279
+ max3(
280
+ capacity,
281
+ this.capacity * this.growFactor,
282
+ this.capacity + GROW_MIN_STEP
283
+ )
284
+ );
285
+
273
286
  this.setCapacity(newCapacity);
274
287
  }
275
288
 
@@ -278,8 +291,13 @@ export class ParticlePool {
278
291
  * @param {number} newCapacity
279
292
  */
280
293
  shrinkCapacity(newCapacity) {
281
- if (newCapacity < this.capacity * this.shrinkFactor && newCapacity < this.capacity - SHRINK_THRESHOLD) {
294
+ if (
295
+ newCapacity < this.capacity * this.shrinkFactor
296
+ && newCapacity < this.capacity - SHRINK_THRESHOLD
297
+ ) {
298
+
282
299
  this.setCapacity(newCapacity);
300
+
283
301
  }
284
302
  }
285
303
 
@@ -293,8 +311,10 @@ export class ParticlePool {
293
311
  return;
294
312
  }
295
313
 
296
- if (newCapacity < this.occupancy.size()) {
297
- throw new Error(`Can not set capacity (=${newCapacity}) below occupancy set size (=${this.occupancy.size()})`);
314
+ const occupancy_size = this.occupancy.size();
315
+
316
+ if (newCapacity < occupancy_size) {
317
+ throw new Error(`Can not set capacity (=${newCapacity}) below occupancy set size (=${occupancy_size})`);
298
318
  }
299
319
 
300
320
  this.capacity = newCapacity;
@@ -1,8 +1,5 @@
1
1
  import { inverseLerp } from "../../../../../../core/math/inverseLerp.js";
2
- import {
3
- computeHashFloatArray,
4
- computeHashIntegerArray
5
- } from "../../../../../../core/math/MathUtils.js";
2
+ import { computeHashFloatArray, computeHashIntegerArray } from "../../../../../../core/math/MathUtils.js";
6
3
  import { assert } from "../../../../../../core/assert.js";
7
4
  import { max2 } from "../../../../../../core/math/max2.js";
8
5
  import { min2 } from "../../../../../../core/math/min2.js";
@@ -123,11 +120,12 @@ export class ParameterLookupTable {
123
120
  /**
124
121
  *
125
122
  * @param {number} position
126
- * @param {number[]} result
123
+ * @param {number[]|Float32Array|Float64Array} result
127
124
  */
128
125
  sample(position, result) {
129
126
  assert.isNumber(position, 'position');
130
- assert.ok(position >= 0 && position <= 1, `position must be between 0 and 1, instead was ${position}`);
127
+ assert.greaterThanOrEqual(position, 0, 'position');
128
+ // assert.ok(position >= 0 && position <= 1, `position must be between 0 and 1, instead was ${position}`);
131
129
 
132
130
  const itemSize = this.itemSize;
133
131
  const data = this.data;
@@ -37,12 +37,15 @@ ParameterTrackSet.prototype.forEach = function (visitor) {
37
37
  */
38
38
  ParameterTrackSet.prototype.getTrackByName = function (name) {
39
39
  const tracks = this.tracks;
40
- const nTracks = tracks.length;
40
+
41
+ const tracks_array = tracks.asArray();
42
+
43
+ const nTracks = tracks_array.length;
41
44
 
42
45
  for (let i = 0; i < nTracks; i++) {
43
- const parameterTrack = tracks.get(i);
46
+ const parameterTrack = tracks_array[i];
44
47
 
45
- if(parameterTrack.name === name){
48
+ if (parameterTrack.name === name) {
46
49
  return parameterTrack;
47
50
  }
48
51
  }