@woosh/meep-engine 3.0.0 → 3.0.1

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 (122) hide show
  1. package/editor/particles/rebuildParticleEmitter.js +8 -26
  2. package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
  3. package/editor/tools/SelectionTool.js +1 -2
  4. package/editor/tools/TransformToolV2.js +2 -3
  5. package/editor/tools/v2/BlenderCameraOrientationGizmo.js +501 -501
  6. package/editor/tools/v2/TransformControls.js +1 -1
  7. package/package.json +95 -96
  8. package/src/core/geom/3d/mat4/m4_look_at.d.ts +25 -0
  9. package/src/core/geom/3d/mat4/m4_look_at.d.ts.map +1 -0
  10. package/src/core/geom/3d/mat4/m4_look_at.js +96 -0
  11. package/src/core/geom/3d/mat4/m4_make_rotation_x.d.ts +18 -0
  12. package/src/core/geom/3d/mat4/m4_make_rotation_x.d.ts.map +1 -0
  13. package/src/core/geom/3d/mat4/m4_make_rotation_x.js +47 -0
  14. package/src/core/geom/3d/mat4/m4_make_rotation_y.d.ts +18 -0
  15. package/src/core/geom/3d/mat4/m4_make_rotation_y.d.ts.map +1 -0
  16. package/src/core/geom/3d/mat4/m4_make_rotation_y.js +47 -0
  17. package/src/core/geom/3d/mat4/m4_make_rotation_z.d.ts +18 -0
  18. package/src/core/geom/3d/mat4/m4_make_rotation_z.d.ts.map +1 -0
  19. package/src/core/geom/3d/mat4/m4_make_rotation_z.js +47 -0
  20. package/src/core/geom/3d/mat4/m4_perspective.d.ts +25 -0
  21. package/src/core/geom/3d/mat4/m4_perspective.d.ts.map +1 -0
  22. package/src/core/geom/3d/mat4/m4_perspective.js +66 -0
  23. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  24. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2045 -2052
  25. package/src/engine/ecs/gui/hud/testHudEdgeStick.js +2 -2
  26. package/src/engine/ecs/terrain/ecs/TerrainSystem.d.ts.map +1 -1
  27. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +14 -27
  28. package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.d.ts.map +1 -1
  29. package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -126
  30. package/src/engine/graphics/ecs/camera/Camera.d.ts +36 -48
  31. package/src/engine/graphics/ecs/camera/Camera.d.ts.map +1 -1
  32. package/src/engine/graphics/ecs/camera/Camera.js +165 -303
  33. package/src/engine/graphics/ecs/camera/camera_active_frustum.d.ts +14 -0
  34. package/src/engine/graphics/ecs/camera/camera_active_frustum.d.ts.map +1 -0
  35. package/src/engine/graphics/ecs/camera/camera_active_frustum.js +25 -0
  36. package/src/engine/graphics/ecs/camera/camera_find_active.d.ts +16 -0
  37. package/src/engine/graphics/ecs/camera/camera_find_active.d.ts.map +1 -0
  38. package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -0
  39. package/src/engine/graphics/ecs/camera/camera_traverse_active.d.ts +12 -0
  40. package/src/engine/graphics/ecs/camera/camera_traverse_active.d.ts.map +1 -0
  41. package/src/engine/graphics/ecs/camera/camera_traverse_active.js +18 -0
  42. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +170 -170
  43. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +5 -1
  44. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  45. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +296 -281
  46. package/src/engine/graphics/ecs/render_layers_compute_depth_range.d.ts +1 -1
  47. package/src/engine/graphics/ecs/render_layers_compute_depth_range.js +1 -1
  48. package/src/engine/graphics/geometry/AttributeData.d.ts +52 -0
  49. package/src/engine/graphics/geometry/AttributeData.d.ts.map +1 -0
  50. package/src/engine/graphics/geometry/AttributeData.js +84 -0
  51. package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts +1 -14
  52. package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts.map +1 -1
  53. package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +229 -253
  54. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +25 -12
  55. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  56. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1149 -1194
  57. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts +4 -8
  58. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts.map +1 -1
  59. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +472 -540
  60. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts +19 -90
  61. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts.map +1 -1
  62. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.js +135 -514
  63. package/src/engine/graphics3/CameraSystem3.d.ts.map +1 -1
  64. package/src/engine/graphics3/CameraSystem3.js +10 -1
  65. package/src/engine/graphics3/GraphicsEngine3.d.ts +3 -3
  66. package/src/engine/graphics3/GraphicsEngine3.js +3 -3
  67. package/src/engine/graphics3/ParticleEmitterSystem3.d.ts +11 -0
  68. package/src/engine/graphics3/ParticleEmitterSystem3.d.ts.map +1 -1
  69. package/src/engine/graphics3/ParticleEmitterSystem3.js +289 -265
  70. package/src/engine/graphics3/ShadeCameraAdapter.d.ts +3 -3
  71. package/src/engine/graphics3/ShadeCameraAdapter.js +3 -3
  72. package/src/engine/graphics3/camera_sync_from_transform.d.ts +2 -2
  73. package/src/engine/graphics3/camera_sync_from_transform.js +2 -2
  74. package/src/engine/graphics3/shade_camera_projection_ray.js +2 -2
  75. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  76. package/src/shade/renderer/camera/Camera.d.ts +3 -5
  77. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  78. package/src/shade/renderer/camera/Camera.js +281 -280
  79. package/src/shade/renderer/camera/GPUCameraContext.js +233 -233
  80. package/src/shade/renderer/loader/usd/parse_usda.js +1 -1
  81. package/src/shade/renderer/loader/usd/usd_build_scene.d.ts.map +1 -1
  82. package/src/shade/renderer/loader/usd/usd_build_scene.js +658 -652
  83. package/src/shade/renderer/loader/usd/usd_compose_transform.d.ts.map +1 -1
  84. package/src/shade/renderer/loader/usd/usd_compose_transform.js +58 -23
  85. package/src/shade/renderer/particles/prototypeParticleSystem.js +450 -443
  86. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  87. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +7 -3
  88. package/src/view/minimap/dom/MinimapCameraView.d.ts +2 -2
  89. package/src/view/minimap/dom/MinimapCameraView.js +206 -206
  90. package/src/engine/graphics/ecs/camera/CameraSystem.d.ts +0 -74
  91. package/src/engine/graphics/ecs/camera/CameraSystem.d.ts.map +0 -1
  92. package/src/engine/graphics/ecs/camera/CameraSystem.js +0 -331
  93. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts +0 -10
  94. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts.map +0 -1
  95. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js +0 -105
  96. package/src/engine/graphics/ecs/camera/build_three_camera_object.d.ts +0 -7
  97. package/src/engine/graphics/ecs/camera/build_three_camera_object.d.ts.map +0 -1
  98. package/src/engine/graphics/ecs/camera/build_three_camera_object.js +0 -29
  99. package/src/engine/graphics/ecs/camera/frustum_from_camera.d.ts +0 -8
  100. package/src/engine/graphics/ecs/camera/frustum_from_camera.d.ts.map +0 -1
  101. package/src/engine/graphics/ecs/camera/frustum_from_camera.js +0 -20
  102. package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.d.ts +0 -9
  103. package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.d.ts.map +0 -1
  104. package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.js +0 -46
  105. package/src/engine/graphics/ecs/camera/unprojectPoint.d.ts +0 -9
  106. package/src/engine/graphics/ecs/camera/unprojectPoint.d.ts.map +0 -1
  107. package/src/engine/graphics/ecs/camera/unprojectPoint.js +0 -14
  108. package/src/engine/graphics/ecs/camera/update_camera_transform.d.ts +0 -6
  109. package/src/engine/graphics/ecs/camera/update_camera_transform.d.ts.map +0 -1
  110. package/src/engine/graphics/ecs/camera/update_camera_transform.js +0 -17
  111. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts +0 -67
  112. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts.map +0 -1
  113. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.js +0 -291
  114. package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.d.ts +0 -11
  115. package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.d.ts.map +0 -1
  116. package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +0 -497
  117. package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts +0 -40
  118. package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts.map +0 -1
  119. package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.js +0 -47
  120. package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.d.ts +0 -7
  121. package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.d.ts.map +0 -1
  122. package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.js +0 -40
@@ -1,540 +1,472 @@
1
- import { BufferAttribute, BufferGeometry, StreamDrawUsage } from 'three';
2
- import { assert } from "../../../../../../core/assert.js";
3
- import { BitSet } from "../../../../../../core/binary/BitSet.js";
4
- import {
5
- compute_typed_array_constructor_from_data_type
6
- } from "../../../../../../core/binary/type/DataType2TypedArrayConstructorMapping.js";
7
- import { typed_array_copy } from "../../../../../../core/collection/array/typed/typed_array_copy.js";
8
- import { aabb3_from_v3_array } from "../../../../../../core/geom/3d/aabb/aabb3_from_v3_array.js";
9
- import { max3 } from "../../../../../../core/math/max3.js";
10
- import ObservedValue from "../../../../../../core/model/ObservedValue.js";
11
-
12
- const SHRINK_THRESHOLD = 64;
13
- const GROW_MIN_STEP = 32;
14
-
15
- export class ParticlePool {
16
- /**
17
- *
18
- * @type {BitSet}
19
- */
20
- occupancy = new BitSet();
21
-
22
- /**
23
- *
24
- * @type {BufferAttribute[]}
25
- */
26
- attributes = [];
27
-
28
- /**
29
- * @type {ObservedValue.<BufferGeometry>}
30
- */
31
- geometry = new ObservedValue(null);
32
-
33
- /**
34
- *
35
- * @type {number}
36
- */
37
- growFactor = 1.3;
38
-
39
- /**
40
- *
41
- * @type {number}
42
- */
43
- shrinkFactor = 0.5;
44
-
45
- /**
46
- *
47
- * @type {number}
48
- */
49
- capacity = 16;
50
-
51
- /**
52
- *
53
- * @param {AttributeGroupSpec} spec
54
- * @constructor
55
- */
56
- constructor(spec) {
57
- assert.equal(spec.isAttributeGroupSpec, true, 'spec.VertexDataSpec !== true');
58
-
59
- /**
60
- *
61
- * @type {AttributeGroupSpec}
62
- */
63
- this.spec = spec;
64
-
65
-
66
- this.build();
67
- }
68
-
69
- size() {
70
- return this.occupancy.size();
71
- }
72
-
73
- /**
74
- *
75
- * @returns {number}
76
- */
77
- create() {
78
- //find an empty place in the pool
79
- const index = this.occupancy.nextClearBit(0);
80
-
81
- //reserve place
82
- this.occupancy.set(index, true);
83
-
84
- //ensure attribute arrays are large enough
85
- const min_capacity = index + 1;
86
-
87
- if (this.capacity < min_capacity) {
88
- this.growCapacity(min_capacity);
89
- }
90
-
91
- return index;
92
- }
93
-
94
- /**
95
- * Returns true if particle has discontinuous unused slots (holes)
96
- * @returns {boolean}
97
- */
98
- hasHoles() {
99
- const occupancy = this.occupancy;
100
-
101
- return occupancy.nextClearBit(0) < occupancy.size();
102
- }
103
-
104
- /**
105
- *
106
- * @param {number} index
107
- */
108
- remove(index) {
109
- this.occupancy.set(index, false);
110
- }
111
-
112
- /**
113
- * Remove holes from the occupancy set
114
- */
115
- compact() {
116
- const occupancy = this.occupancy;
117
-
118
- const specAttributes = this.spec.attributes;
119
- const numAttributes = specAttributes.length;
120
-
121
- let holeIndex, lastIndex, attributeIndex;
122
-
123
- holeIndex = occupancy.nextClearBit(0);
124
- lastIndex = occupancy.previousSetBit(occupancy.size());
125
-
126
- const attributes = this.attributes;
127
-
128
- while (holeIndex < lastIndex) {
129
-
130
- //move occupancy flag from the last to the hole
131
- occupancy.set(holeIndex, true);
132
- occupancy.set(lastIndex, false);
133
-
134
- //move attribute values
135
- for (attributeIndex = 0; attributeIndex < numAttributes; attributeIndex++) {
136
- const attribute = attributes[attributeIndex];
137
-
138
- const itemSize = attribute.itemSize;
139
-
140
- /**
141
- *
142
- * @type {Float32Array}
143
- */
144
- const attribute_array = attribute.array;
145
-
146
- //do swaps in the old array
147
- const targetIndex = holeIndex * itemSize;
148
- const sourceIndex = lastIndex * itemSize;
149
-
150
- attribute_array.copyWithin(targetIndex, sourceIndex, sourceIndex + itemSize);
151
- }
152
-
153
- //move hole and last cursors
154
- holeIndex = occupancy.nextClearBit(holeIndex + 1);
155
- lastIndex = occupancy.previousSetBit(lastIndex);
156
- }
157
-
158
- this.geometry.getValue().setDrawRange(0, occupancy.size());
159
- }
160
-
161
- updateAttributes() {
162
- const attributes = this.attributes;
163
- const numAttributes = attributes.length;
164
-
165
- const activeParticleLimit = this.occupancy.size();
166
-
167
- if (activeParticleLimit <= 0) {
168
- // no particles, no need to update attributes
169
- return;
170
- }
171
-
172
- let i = 0;
173
-
174
- for (; i < numAttributes; i++) {
175
- const attribute = attributes[i];
176
-
177
- attribute.updateRange.count = activeParticleLimit * attribute.itemSize;
178
- attribute.updateRange.offset = 0;
179
-
180
- //mark attribute for update
181
- attribute.needsUpdate = true;
182
- }
183
- }
184
-
185
- update() {
186
- //some of the particles may have died and formed holes in the data array, compaction removes them
187
- this.compact();
188
-
189
- //attempt attribute size shrinkage
190
- const size = this.occupancy.size();
191
- this.shrinkCapacity(size);
192
-
193
- this.updateAttributes();
194
- }
195
-
196
- /**
197
- * Swap two particles identified by index
198
- * NOTE: Only attributes are swapped, occupancy is unaffected.
199
- * @param {number} indexA
200
- * @param {number} indexB
201
- */
202
- swap(indexA, indexB) {
203
- //assert.ok(this.occupancy.get(indexA), `indexA=${indexA} is unoccupied`);
204
- //assert.ok(this.occupancy.get(indexB), `indexB=${indexB} is unoccupied`);
205
-
206
- const attributes = this.attributes;
207
- const numAttributes = attributes.length;
208
-
209
- let i, j;
210
-
211
- for (i = 0; i < numAttributes; i++) {
212
- const attribute = attributes[i];
213
-
214
- const itemSize = attribute.itemSize;
215
-
216
- const offsetA = indexA * itemSize;
217
- const offsetB = indexB * itemSize;
218
-
219
- const array = attribute.array;
220
-
221
- for (j = 0; j < itemSize; j++) {
222
- const addressA = offsetA + j;
223
- const addressB = offsetB + j;
224
-
225
- const temp = array[addressA];
226
-
227
- array[addressA] = array[addressB];
228
-
229
- array[addressB] = temp;
230
- }
231
- }
232
- }
233
-
234
- build() {
235
- const geometry = new BufferGeometry();
236
- geometry.dynamic = true;
237
-
238
- const spec_attributes = this.spec.attributes;
239
- const l = spec_attributes.length;
240
-
241
- for (let i = 0; i < l; i++) {
242
-
243
- /**
244
- * @type {AttributeSpec}
245
- */
246
- const attributeSpec = spec_attributes[i];
247
-
248
- const itemSize = attributeSpec.itemSize;
249
- const TypedArrayConstructor = compute_typed_array_constructor_from_data_type(attributeSpec.type);
250
-
251
- const newArrayLength = itemSize * this.capacity;
252
- const newArray = new TypedArrayConstructor(newArrayLength);
253
-
254
- const old_attribute = this.attributes[i];
255
-
256
- if (old_attribute !== undefined && old_attribute.count !== 0) {
257
- //copy old data
258
- typed_array_copy(old_attribute.array, newArray);
259
- }
260
-
261
- const newAttribute = new BufferAttribute(newArray, itemSize, attributeSpec.normalized);
262
-
263
- newAttribute.setUsage(StreamDrawUsage);
264
- newAttribute.name = attributeSpec.name;
265
-
266
- this.attributes[i] = newAttribute;
267
-
268
- geometry.setAttribute(attributeSpec.name, newAttribute);
269
- }
270
-
271
- const oldGeometry = this.geometry.getValue();
272
-
273
- this.geometry.set(geometry);
274
-
275
- if (oldGeometry !== null) {
276
- //dispose of old geometry
277
- oldGeometry.dispose();
278
- }
279
-
280
- geometry.setDrawRange(0, this.occupancy.size());
281
- }
282
-
283
- /**
284
- *
285
- * @param {number} capacity
286
- */
287
- growCapacity(capacity) {
288
- const newCapacity = Math.floor(
289
- max3(
290
- capacity,
291
- this.capacity * this.growFactor,
292
- this.capacity + GROW_MIN_STEP
293
- )
294
- );
295
-
296
- this.setCapacity(newCapacity);
297
- }
298
-
299
- /**
300
- *
301
- * @param {number} newCapacity
302
- */
303
- shrinkCapacity(newCapacity) {
304
- if (
305
- newCapacity < this.capacity * this.shrinkFactor
306
- && newCapacity < this.capacity - SHRINK_THRESHOLD
307
- ) {
308
-
309
- this.setCapacity(newCapacity);
310
-
311
- }
312
- }
313
-
314
- /**
315
- *
316
- * @param {number} newCapacity
317
- */
318
- setCapacity(newCapacity) {
319
- if (this.capacity === newCapacity) {
320
- //do nothing
321
- return;
322
- }
323
-
324
- const occupancy_size = this.occupancy.size();
325
-
326
- if (newCapacity < occupancy_size) {
327
- throw new Error(`Can not set capacity (=${newCapacity}) below occupancy set size (=${occupancy_size})`);
328
- }
329
-
330
- this.capacity = newCapacity;
331
-
332
- this.build();
333
- }
334
-
335
- /**
336
- *
337
- * @param {int} particleIndex
338
- * @param {int} attributeIndex
339
- * @returns {number}
340
- */
341
- readAttributeScalar(particleIndex, attributeIndex) {
342
- const attribute = this.attributes[attributeIndex];
343
-
344
- const array = attribute.array;
345
-
346
- return array[particleIndex];
347
- }
348
-
349
- /**
350
- *
351
- * @param {int} particleIndex
352
- * @param {int} attributeIndex
353
- * @param {number} value
354
- */
355
- writeAttributeScalar(particleIndex, attributeIndex, value) {
356
- const attribute = this.attributes[attributeIndex];
357
-
358
- const array = attribute.array;
359
-
360
- array[particleIndex] = value;
361
- }
362
-
363
- /**
364
- *
365
- * @param {int} particleIndex
366
- * @param {int} attributeIndex
367
- * @param {number[]} result
368
- */
369
- readAttributeVector2(particleIndex, attributeIndex, result) {
370
- const attribute = this.attributes[attributeIndex];
371
-
372
- const address = particleIndex * 2;
373
-
374
- const array = attribute.array;
375
-
376
- result[0] = array[address];
377
- result[1] = array[address + 1];
378
- }
379
-
380
- /**
381
- *
382
- * @param {int} particleIndex
383
- * @param {int} attributeIndex
384
- * @param {number} x
385
- * @param {number} y
386
- */
387
- writeAttributeVector2(particleIndex, attributeIndex, x, y) {
388
- const attribute = this.attributes[attributeIndex];
389
-
390
- const address = particleIndex * 2;
391
-
392
- const array = attribute.array;
393
-
394
- array[address] = x;
395
- array[address + 1] = y;
396
- }
397
-
398
- /**
399
- *
400
- * @param {int} particleIndex
401
- * @param {int} attributeIndex
402
- * @param {number[]} result
403
- */
404
- readAttributeVector3(particleIndex, attributeIndex, result) {
405
- const attribute = this.attributes[attributeIndex];
406
-
407
- const address = particleIndex * 3;
408
-
409
- const array = attribute.array;
410
-
411
- result[0] = array[address];
412
- result[1] = array[address + 1];
413
- result[2] = array[address + 2];
414
- }
415
-
416
- /**
417
- *
418
- * @param {int} particleIndex
419
- * @param {int} attributeIndex
420
- * @param {number} x
421
- * @param {number} y
422
- * @param {number} z
423
- */
424
- writeAttributeVector3(particleIndex, attributeIndex, x, y, z) {
425
- const attribute = this.attributes[attributeIndex];
426
-
427
- const address = particleIndex * 3;
428
-
429
- const array = attribute.array;
430
-
431
- array[address] = x;
432
- array[address + 1] = y;
433
- array[address + 2] = z;
434
- }
435
-
436
- /**
437
- *
438
- * @param {int} particleIndex
439
- * @param {int} attributeIndex
440
- * @param {number[]} result
441
- */
442
- readAttributeVector4(particleIndex, attributeIndex, result) {
443
- const attribute = this.attributes[attributeIndex];
444
-
445
- const address = particleIndex * 4;
446
-
447
- const array = attribute.array;
448
-
449
- result[0] = array[address];
450
- result[1] = array[address + 1];
451
- result[2] = array[address + 2];
452
- result[3] = array[address + 3];
453
- }
454
-
455
- /**
456
- *
457
- * @param {int} particleIndex
458
- * @param {int} attributeIndex
459
- * @param {number} x
460
- * @param {number} y
461
- * @param {number} z
462
- * @param {number} w
463
- */
464
- writeAttributeVector4(particleIndex, attributeIndex, x, y, z, w) {
465
- const attribute = this.attributes[attributeIndex];
466
-
467
- const address = particleIndex * 4;
468
-
469
- const array = attribute.array;
470
-
471
- array[address] = x;
472
- array[address + 1] = y;
473
- array[address + 2] = z;
474
- array[address + 3] = w;
475
- }
476
-
477
- /**
478
- * Write the same attribute value for every particle.
479
- * Assumes particles are packed (no holes).
480
- * @param {number} attribute_index
481
- * @param {number[]|Float32Array|Uint8Array|Uint16Array|Int8Array|Int32Array} value
482
- */
483
- writeAttributeForAllArray(attribute_index, value) {
484
- const attribute = this.attributes[attribute_index];
485
-
486
- const itemSize = attribute.itemSize;
487
-
488
- if (value.length < itemSize) {
489
- throw new Error(`Argument underflow, attribute.itemSize is '${itemSize}', but supplier argument's length is '${value.length}'`);
490
- }
491
-
492
- const n = this.size();
493
-
494
- const destination = attribute.array;
495
-
496
- let k;
497
- for (let i = 0; i < n; i++) {
498
- const offset = i * itemSize;
499
-
500
- for (k = 0; k < itemSize; k++) {
501
- destination[offset + k] = value[k];
502
- }
503
- }
504
-
505
- // mark for update
506
- attribute.needsUpdate = true;
507
- attribute.updateRange.count = n * itemSize;
508
- attribute.updateRange.offset = 0;
509
- }
510
-
511
- /**
512
- *
513
- * @param {number} attribute_index
514
- * @param {number[]} result
515
- */
516
- computeAttributeVector3AxisAlignedBoundingBox(attribute_index, result) {
517
- const attribute = this.attributes[attribute_index];
518
- const item_size = attribute.itemSize;
519
-
520
- if (item_size !== 3) {
521
- throw new Error(`Attribute item_size is expected to be 3, instead was '${item_size}'`);
522
- }
523
-
524
- const particle_count = this.size();
525
-
526
- const data = attribute.array;
527
-
528
- aabb3_from_v3_array(result, data, particle_count * 3);
529
-
530
- }
531
-
532
- dispose() {
533
- const bufferGeometry = this.geometry.getValue();
534
-
535
- if (bufferGeometry !== null) {
536
- // release used GPU memory
537
- bufferGeometry.dispose();
538
- }
539
- }
540
- }
1
+ import { assert } from "../../../../../../core/assert.js";
2
+ import { BitSet } from "../../../../../../core/binary/BitSet.js";
3
+ import { typed_array_copy } from "../../../../../../core/collection/array/typed/typed_array_copy.js";
4
+ import { aabb3_from_v3_array } from "../../../../../../core/geom/3d/aabb/aabb3_from_v3_array.js";
5
+ import { max3 } from "../../../../../../core/math/max3.js";
6
+ import { AttributeData } from "../../../../geometry/AttributeData.js";
7
+
8
+ const SHRINK_THRESHOLD = 64;
9
+ const GROW_MIN_STEP = 32;
10
+
11
+ export class ParticlePool {
12
+ /**
13
+ *
14
+ * @type {BitSet}
15
+ */
16
+ occupancy = new BitSet();
17
+
18
+ /**
19
+ * One per attribute of {@link spec}, in the same order, each holding {@link capacity} items.
20
+ *
21
+ * @type {AttributeData[]}
22
+ */
23
+ attributes = [];
24
+
25
+ /**
26
+ *
27
+ * @type {number}
28
+ */
29
+ growFactor = 1.3;
30
+
31
+ /**
32
+ *
33
+ * @type {number}
34
+ */
35
+ shrinkFactor = 0.5;
36
+
37
+ /**
38
+ *
39
+ * @type {number}
40
+ */
41
+ capacity = 16;
42
+
43
+ /**
44
+ *
45
+ * @param {AttributeGroupSpec} spec
46
+ * @constructor
47
+ */
48
+ constructor(spec) {
49
+ assert.equal(spec.isAttributeGroupSpec, true, 'spec.VertexDataSpec !== true');
50
+
51
+ /**
52
+ *
53
+ * @type {AttributeGroupSpec}
54
+ */
55
+ this.spec = spec;
56
+
57
+
58
+ this.build();
59
+ }
60
+
61
+ size() {
62
+ return this.occupancy.size();
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @returns {number}
68
+ */
69
+ create() {
70
+ //find an empty place in the pool
71
+ const index = this.occupancy.nextClearBit(0);
72
+
73
+ //reserve place
74
+ this.occupancy.set(index, true);
75
+
76
+ //ensure attribute arrays are large enough
77
+ const min_capacity = index + 1;
78
+
79
+ if (this.capacity < min_capacity) {
80
+ this.growCapacity(min_capacity);
81
+ }
82
+
83
+ return index;
84
+ }
85
+
86
+ /**
87
+ * Returns true if particle has discontinuous unused slots (holes)
88
+ * @returns {boolean}
89
+ */
90
+ hasHoles() {
91
+ const occupancy = this.occupancy;
92
+
93
+ return occupancy.nextClearBit(0) < occupancy.size();
94
+ }
95
+
96
+ /**
97
+ *
98
+ * @param {number} index
99
+ */
100
+ remove(index) {
101
+ this.occupancy.set(index, false);
102
+ }
103
+
104
+ /**
105
+ * Remove holes from the occupancy set
106
+ */
107
+ compact() {
108
+ const occupancy = this.occupancy;
109
+
110
+ const specAttributes = this.spec.attributes;
111
+ const numAttributes = specAttributes.length;
112
+
113
+ let holeIndex, lastIndex, attributeIndex;
114
+
115
+ holeIndex = occupancy.nextClearBit(0);
116
+ lastIndex = occupancy.previousSetBit(occupancy.size());
117
+
118
+ const attributes = this.attributes;
119
+
120
+ while (holeIndex < lastIndex) {
121
+
122
+ //move occupancy flag from the last to the hole
123
+ occupancy.set(holeIndex, true);
124
+ occupancy.set(lastIndex, false);
125
+
126
+ //move attribute values
127
+ for (attributeIndex = 0; attributeIndex < numAttributes; attributeIndex++) {
128
+ const attribute = attributes[attributeIndex];
129
+
130
+ const itemSize = attribute.itemSize;
131
+
132
+ /**
133
+ *
134
+ * @type {Float32Array}
135
+ */
136
+ const attribute_array = attribute.array;
137
+
138
+ //do swaps in the old array
139
+ const targetIndex = holeIndex * itemSize;
140
+ const sourceIndex = lastIndex * itemSize;
141
+
142
+ attribute_array.copyWithin(targetIndex, sourceIndex, sourceIndex + itemSize);
143
+ }
144
+
145
+ //move hole and last cursors
146
+ holeIndex = occupancy.nextClearBit(holeIndex + 1);
147
+ lastIndex = occupancy.previousSetBit(lastIndex);
148
+ }
149
+
150
+ }
151
+
152
+ update() {
153
+ //some of the particles may have died and formed holes in the data array, compaction removes them
154
+ this.compact();
155
+
156
+ //attempt attribute size shrinkage
157
+ const size = this.occupancy.size();
158
+ this.shrinkCapacity(size);
159
+ }
160
+
161
+ /**
162
+ * Swap two particles identified by index
163
+ * NOTE: Only attributes are swapped, occupancy is unaffected.
164
+ * @param {number} indexA
165
+ * @param {number} indexB
166
+ */
167
+ swap(indexA, indexB) {
168
+ //assert.ok(this.occupancy.get(indexA), `indexA=${indexA} is unoccupied`);
169
+ //assert.ok(this.occupancy.get(indexB), `indexB=${indexB} is unoccupied`);
170
+
171
+ const attributes = this.attributes;
172
+ const numAttributes = attributes.length;
173
+
174
+ let i, j;
175
+
176
+ for (i = 0; i < numAttributes; i++) {
177
+ const attribute = attributes[i];
178
+
179
+ const itemSize = attribute.itemSize;
180
+
181
+ const offsetA = indexA * itemSize;
182
+ const offsetB = indexB * itemSize;
183
+
184
+ const array = attribute.array;
185
+
186
+ for (j = 0; j < itemSize; j++) {
187
+ const addressA = offsetA + j;
188
+ const addressB = offsetB + j;
189
+
190
+ const temp = array[addressA];
191
+
192
+ array[addressA] = array[addressB];
193
+
194
+ array[addressB] = temp;
195
+ }
196
+ }
197
+ }
198
+
199
+ build() {
200
+ const spec_attributes = this.spec.attributes;
201
+ const l = spec_attributes.length;
202
+
203
+ for (let i = 0; i < l; i++) {
204
+
205
+ /**
206
+ * @type {AttributeSpec}
207
+ */
208
+ const attributeSpec = spec_attributes[i];
209
+
210
+ const newAttribute = AttributeData.allocate(attributeSpec, this.capacity);
211
+
212
+ const old_attribute = this.attributes[i];
213
+
214
+ if (old_attribute !== undefined && old_attribute.count !== 0) {
215
+ //copy old data
216
+ typed_array_copy(old_attribute.array, newAttribute.array);
217
+ }
218
+
219
+ this.attributes[i] = newAttribute;
220
+ }
221
+ }
222
+
223
+ /**
224
+ *
225
+ * @param {number} capacity
226
+ */
227
+ growCapacity(capacity) {
228
+ const newCapacity = Math.floor(
229
+ max3(
230
+ capacity,
231
+ this.capacity * this.growFactor,
232
+ this.capacity + GROW_MIN_STEP
233
+ )
234
+ );
235
+
236
+ this.setCapacity(newCapacity);
237
+ }
238
+
239
+ /**
240
+ *
241
+ * @param {number} newCapacity
242
+ */
243
+ shrinkCapacity(newCapacity) {
244
+ if (
245
+ newCapacity < this.capacity * this.shrinkFactor
246
+ && newCapacity < this.capacity - SHRINK_THRESHOLD
247
+ ) {
248
+
249
+ this.setCapacity(newCapacity);
250
+
251
+ }
252
+ }
253
+
254
+ /**
255
+ *
256
+ * @param {number} newCapacity
257
+ */
258
+ setCapacity(newCapacity) {
259
+ if (this.capacity === newCapacity) {
260
+ //do nothing
261
+ return;
262
+ }
263
+
264
+ const occupancy_size = this.occupancy.size();
265
+
266
+ if (newCapacity < occupancy_size) {
267
+ throw new Error(`Can not set capacity (=${newCapacity}) below occupancy set size (=${occupancy_size})`);
268
+ }
269
+
270
+ this.capacity = newCapacity;
271
+
272
+ this.build();
273
+ }
274
+
275
+ /**
276
+ *
277
+ * @param {int} particleIndex
278
+ * @param {int} attributeIndex
279
+ * @returns {number}
280
+ */
281
+ readAttributeScalar(particleIndex, attributeIndex) {
282
+ const attribute = this.attributes[attributeIndex];
283
+
284
+ const array = attribute.array;
285
+
286
+ return array[particleIndex];
287
+ }
288
+
289
+ /**
290
+ *
291
+ * @param {int} particleIndex
292
+ * @param {int} attributeIndex
293
+ * @param {number} value
294
+ */
295
+ writeAttributeScalar(particleIndex, attributeIndex, value) {
296
+ const attribute = this.attributes[attributeIndex];
297
+
298
+ const array = attribute.array;
299
+
300
+ array[particleIndex] = value;
301
+ }
302
+
303
+ /**
304
+ *
305
+ * @param {int} particleIndex
306
+ * @param {int} attributeIndex
307
+ * @param {number[]} result
308
+ */
309
+ readAttributeVector2(particleIndex, attributeIndex, result) {
310
+ const attribute = this.attributes[attributeIndex];
311
+
312
+ const address = particleIndex * 2;
313
+
314
+ const array = attribute.array;
315
+
316
+ result[0] = array[address];
317
+ result[1] = array[address + 1];
318
+ }
319
+
320
+ /**
321
+ *
322
+ * @param {int} particleIndex
323
+ * @param {int} attributeIndex
324
+ * @param {number} x
325
+ * @param {number} y
326
+ */
327
+ writeAttributeVector2(particleIndex, attributeIndex, x, y) {
328
+ const attribute = this.attributes[attributeIndex];
329
+
330
+ const address = particleIndex * 2;
331
+
332
+ const array = attribute.array;
333
+
334
+ array[address] = x;
335
+ array[address + 1] = y;
336
+ }
337
+
338
+ /**
339
+ *
340
+ * @param {int} particleIndex
341
+ * @param {int} attributeIndex
342
+ * @param {number[]} result
343
+ */
344
+ readAttributeVector3(particleIndex, attributeIndex, result) {
345
+ const attribute = this.attributes[attributeIndex];
346
+
347
+ const address = particleIndex * 3;
348
+
349
+ const array = attribute.array;
350
+
351
+ result[0] = array[address];
352
+ result[1] = array[address + 1];
353
+ result[2] = array[address + 2];
354
+ }
355
+
356
+ /**
357
+ *
358
+ * @param {int} particleIndex
359
+ * @param {int} attributeIndex
360
+ * @param {number} x
361
+ * @param {number} y
362
+ * @param {number} z
363
+ */
364
+ writeAttributeVector3(particleIndex, attributeIndex, x, y, z) {
365
+ const attribute = this.attributes[attributeIndex];
366
+
367
+ const address = particleIndex * 3;
368
+
369
+ const array = attribute.array;
370
+
371
+ array[address] = x;
372
+ array[address + 1] = y;
373
+ array[address + 2] = z;
374
+ }
375
+
376
+ /**
377
+ *
378
+ * @param {int} particleIndex
379
+ * @param {int} attributeIndex
380
+ * @param {number[]} result
381
+ */
382
+ readAttributeVector4(particleIndex, attributeIndex, result) {
383
+ const attribute = this.attributes[attributeIndex];
384
+
385
+ const address = particleIndex * 4;
386
+
387
+ const array = attribute.array;
388
+
389
+ result[0] = array[address];
390
+ result[1] = array[address + 1];
391
+ result[2] = array[address + 2];
392
+ result[3] = array[address + 3];
393
+ }
394
+
395
+ /**
396
+ *
397
+ * @param {int} particleIndex
398
+ * @param {int} attributeIndex
399
+ * @param {number} x
400
+ * @param {number} y
401
+ * @param {number} z
402
+ * @param {number} w
403
+ */
404
+ writeAttributeVector4(particleIndex, attributeIndex, x, y, z, w) {
405
+ const attribute = this.attributes[attributeIndex];
406
+
407
+ const address = particleIndex * 4;
408
+
409
+ const array = attribute.array;
410
+
411
+ array[address] = x;
412
+ array[address + 1] = y;
413
+ array[address + 2] = z;
414
+ array[address + 3] = w;
415
+ }
416
+
417
+ /**
418
+ * Write the same attribute value for every particle.
419
+ * Assumes particles are packed (no holes).
420
+ * @param {number} attribute_index
421
+ * @param {number[]|Float32Array|Uint8Array|Uint16Array|Int8Array|Int32Array} value
422
+ */
423
+ writeAttributeForAllArray(attribute_index, value) {
424
+ const attribute = this.attributes[attribute_index];
425
+
426
+ const itemSize = attribute.itemSize;
427
+
428
+ if (value.length < itemSize) {
429
+ throw new Error(`Argument underflow, attribute.itemSize is '${itemSize}', but supplier argument's length is '${value.length}'`);
430
+ }
431
+
432
+ const n = this.size();
433
+
434
+ const destination = attribute.array;
435
+
436
+ let k;
437
+ for (let i = 0; i < n; i++) {
438
+ const offset = i * itemSize;
439
+
440
+ for (k = 0; k < itemSize; k++) {
441
+ destination[offset + k] = value[k];
442
+ }
443
+ }
444
+
445
+ }
446
+
447
+ /**
448
+ *
449
+ * @param {number} attribute_index
450
+ * @param {number[]} result
451
+ */
452
+ computeAttributeVector3AxisAlignedBoundingBox(attribute_index, result) {
453
+ const attribute = this.attributes[attribute_index];
454
+ const item_size = attribute.itemSize;
455
+
456
+ if (item_size !== 3) {
457
+ throw new Error(`Attribute item_size is expected to be 3, instead was '${item_size}'`);
458
+ }
459
+
460
+ const particle_count = this.size();
461
+
462
+ const data = attribute.array;
463
+
464
+ aabb3_from_v3_array(result, data, particle_count * 3);
465
+
466
+ }
467
+
468
+ dispose() {
469
+ // the pool owns nothing but its own arrays, and those go with it
470
+ this.attributes.length = 0;
471
+ }
472
+ }