@woosh/meep-engine 2.33.36 → 2.33.40

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 (90) hide show
  1. package/core/bvh2/binary/2/BinaryUint32BVH.js +3 -3
  2. package/core/collection/HashMap.js +19 -12
  3. package/core/collection/array/typed/typed_array_copy.js +2 -2
  4. package/core/collection/table/RowFirstTable.js +13 -8
  5. package/core/collection/table/RowFirstTableSpec.js +6 -0
  6. package/core/color/Color.js +5 -9
  7. package/core/color/ColorUtils.js +4 -150
  8. package/core/color/YCbCr_to_rgb_uint24.js +20 -0
  9. package/core/color/hsv2rgb.js +54 -0
  10. package/core/color/int2rgb.js +12 -0
  11. package/core/color/parseHex.js +18 -0
  12. package/core/color/rgb2hex.js +16 -0
  13. package/core/color/rgb2hsv.js +47 -0
  14. package/core/color/rgb2uint24.js +17 -0
  15. package/core/color/rgb_to_YCbCr_uint24.js +18 -0
  16. package/core/geom/3d/aabb/aabb3_matrix4_project_by_corners.js +1 -1
  17. package/core/geom/3d/aabb/compute_aabb_from_points.js +28 -0
  18. package/core/geom/3d/morton/mortonEncode_magicbits.js +7 -6
  19. package/core/geom/3d/morton/v3_morton_encode_transformed.js +15 -11
  20. package/core/geom/3d/plane/orient3d_fast.js +51 -0
  21. package/core/geom/3d/plane/plane_computeConvex3PlaneIntersection.js +5 -0
  22. package/core/geom/3d/tetrahedra/GetDepthForTetrahedronProbe.glsl +43 -0
  23. package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +177 -0
  24. package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.spec.js +66 -0
  25. package/core/geom/3d/tetrahedra/compute_circumsphere.js +271 -0
  26. package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.js +50 -0
  27. package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.spec.js +14 -0
  28. package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +77 -0
  29. package/core/geom/3d/tetrahedra/tetrahedra_collection.js +454 -0
  30. package/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +26 -0
  31. package/core/geom/Quaternion.js +4 -0
  32. package/core/math/hash/murmur3_32.js +39 -0
  33. package/core/process/undo/ActionProcessor.d.ts +2 -0
  34. package/core/process/undo/ActionProcessor.js +15 -4
  35. package/editor/tools/FoliagePaintTool.js +1 -1
  36. package/editor/tools/GridPaintTool.js +1 -1
  37. package/engine/asset/loaders/GLTFAssetLoader.js +4 -8
  38. package/engine/ecs/System.d.ts +24 -1
  39. package/engine/ecs/foliage/InstancedFoliage.js +45 -0
  40. package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +4 -0
  41. package/engine/ecs/storage/BinaryBufferSerializer.js +48 -38
  42. package/engine/ecs/storage/binary/collection/BinaryCollectionSerializer.js +1 -1
  43. package/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +1 -1
  44. package/engine/ecs/terrain/tiles/TerrainTile.js +1 -1
  45. package/engine/graphics/GraphicsEngine.js +7 -0
  46. package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +1 -1
  47. package/engine/graphics/ecs/mesh/Mesh.js +2 -2
  48. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +13 -0
  49. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +339 -314
  50. package/engine/graphics/micron/prototypeVirtualGeometry.js +4 -1
  51. package/engine/graphics/micron/render/v1/VGThreeRenderer.js +6 -2
  52. package/engine/graphics/particles/node-based/rendering/billboard/ParticleBillboardShader.js +1 -1
  53. package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +20 -24
  54. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +100 -55
  55. package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +7 -2
  56. package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +1 -0
  57. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -2
  58. package/engine/graphics/render/buffer/simple-fx/DepthLimitedBlur.js +9 -4
  59. package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +7 -1
  60. package/engine/graphics/render/forward_plus/LightManager.js +295 -51
  61. package/engine/graphics/render/forward_plus/LightManager.spec.js +1 -1
  62. package/engine/graphics/render/forward_plus/PointLightData.js +9 -13
  63. package/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.js +1 -1
  64. package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +10 -1
  65. package/engine/graphics/render/forward_plus/debug/LightClusterVolumeMaterial.js +1 -1
  66. package/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js +3 -1
  67. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +31 -18
  68. package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +18 -4
  69. package/engine/graphics/render/forward_plus/model/AbstractLight.js +50 -0
  70. package/engine/graphics/render/forward_plus/model/Decal.js +68 -0
  71. package/engine/graphics/render/forward_plus/{PointLight.js → model/PointLight.js} +19 -11
  72. package/engine/graphics/render/forward_plus/{SpotLight.js → model/SpotLight.js} +20 -12
  73. package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +1 -1
  74. package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +6 -5
  75. package/engine/graphics/render/forward_plus/{prototypeLightManager.js → prototype/prototypeLightManager.js} +100 -25
  76. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +29 -20
  77. package/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +2 -0
  78. package/engine/graphics/render/visibility/IncrementalDeltaSet.js +1 -0
  79. package/engine/graphics/render/visibility/VisibilityComputer.js +8 -7
  80. package/engine/graphics/shaders/TerrainShader.js +5 -5
  81. package/engine/graphics/shadows/testShadowMapRendering.js +192 -0
  82. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +19 -0
  83. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +99 -0
  84. package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +19 -39
  85. package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +75 -0
  86. package/engine/graphics/texture/atlas/TextureAtlas.js +22 -2
  87. package/engine/reference/v2/Reference.d.ts +4 -0
  88. package/engine/reference/v2/Reference.js +3 -1
  89. package/package.json +2 -1
  90. package/view/elements/ColorPickerView.js +2 -1
@@ -11,390 +11,415 @@ import { composeCompile } from "../../material/composeCompile.js";
11
11
  import { typed_array_copy } from "../../../../core/collection/array/typed/typed_array_copy.js";
12
12
  import { rewriteMaterial } from "./rewriteMaterial.js";
13
13
 
14
- /**
15
- *
16
- * @constructor
17
- */
18
- function InstancedMeshGroup() {
19
- this.__threeGeometry = null;
20
- this.__threeInstanceGeometry = null;
21
-
22
- /**
23
- * @private
24
- * @type {number}
25
- */
26
- this.count = 0;
27
- this.capacity = 0;
28
-
29
- this.growFactor = 1.1;
14
+ export class InstancedMeshGroup {
30
15
  /**
31
- * Minimum spare capacity increase during growing
32
- * @type {number}
16
+ *
17
+ * @constructor
33
18
  */
34
- this.growConstant = 4;
19
+ constructor() {
20
+ /**
21
+ * Instanced geometry
22
+ * @type {THREE.InstancedBufferGeometry|null}
23
+ * @private
24
+ */
25
+ this.__threeGeometry = null;
26
+
27
+ /**
28
+ * Geometry of a single instance
29
+ * @type {THREE.BufferGeometry|null}
30
+ * @private
31
+ */
32
+ this.__threeInstanceGeometry = null;
33
+
34
+ /**
35
+ * @private
36
+ * @type {number}
37
+ */
38
+ this.count = 0;
39
+
40
+ /**
41
+ *
42
+ * @type {number}
43
+ */
44
+ this.capacity = 0;
45
+
46
+ /**
47
+ *
48
+ * @type {number}
49
+ */
50
+ this.growFactor = 1.1;
51
+ /**
52
+ * Minimum spare capacity increase during growing
53
+ * @type {number}
54
+ */
55
+ this.growConstant = 4;
56
+
57
+ this.shrinkFactor = 0.5;
58
+ /**
59
+ * Minimum capacity reduction for shrinkage to occur
60
+ * @type {number}
61
+ */
62
+ this.shrinkConstant = 64;
63
+
64
+ /**
65
+ *
66
+ * @type {InstancedBufferAttribute}
67
+ * @private
68
+ */
69
+ this.__attributePosition = null;
70
+
71
+ /**
72
+ *
73
+ * @type {InstancedBufferAttribute}
74
+ * @private
75
+ */
76
+ this.__attributeRotation = null;
77
+
78
+ /**
79
+ *
80
+ * @type {InstancedBufferAttribute}
81
+ * @private
82
+ */
83
+ this.__attributeScale = null;
84
+
85
+ /**
86
+ *
87
+ * @type {Material}
88
+ * @private
89
+ */
90
+ this.__material = null;
91
+
92
+ this.indices = [];
93
+ this.references = [];
94
+
95
+ this.mesh = ThreeFactory.createMesh();
96
+ }
35
97
 
36
- this.shrinkFactor = 0.5;
37
- /**
38
- * Minimum capacity reduction for shrinkage to occur
39
- * @type {number}
40
- */
41
- this.shrinkConstant = 64;
98
+ dispose() {
99
+ if (this.__threeGeometry !== null) {
100
+ this.__threeGeometry.dispose();
101
+ }
102
+ }
42
103
 
43
104
  /**
44
105
  *
45
- * @type {InstancedBufferAttribute}
46
- * @private
106
+ * @param {THREE.BufferGeometry} geometry
47
107
  */
48
- this.__attributePosition = null;
108
+ setGeometry(geometry) {
109
+ if (geometry.isBufferGeometry !== true) {
110
+ throw new Error(`Expected THREE.BufferedGeometry, got something else instead.`);
111
+ }
49
112
 
50
- /**
51
- *
52
- * @type {InstancedBufferAttribute}
53
- * @private
54
- */
55
- this.__attributeRotation = null;
113
+ this.__threeInstanceGeometry = geometry;
56
114
 
57
- /**
58
- *
59
- * @type {InstancedBufferAttribute}
60
- * @private
61
- */
62
- this.__attributeScale = null;
115
+ this.build();
116
+ }
63
117
 
64
118
  /**
65
119
  *
66
- * @type {Material}
67
- * @private
120
+ * @param {THREE.Material|THREE.ShaderMaterial} sourceMaterial
68
121
  */
69
- this.__material = null;
122
+ setMaterial(sourceMaterial) {
123
+ const material = sourceMaterial.clone();
124
+
125
+ if (material.isShaderMaterial) {
126
+ // transfer source material uniforms
127
+ for (const uniformsKey in material.uniforms) {
128
+ material.uniforms[uniformsKey] = sourceMaterial.uniforms[uniformsKey];
129
+ }
130
+ }
70
131
 
71
- this.indices = [];
72
- this.references = [];
73
132
 
74
- this.mesh = ThreeFactory.createMesh();
75
- }
133
+ material.onBeforeCompile = composeCompile(sourceMaterial.onBeforeCompile, rewriteMaterial);
76
134
 
77
- InstancedMeshGroup.prototype.dispose = function () {
78
- if (this.__threeGeometry !== null) {
79
- this.__threeGeometry.dispose();
80
- }
81
- }
135
+ //we need a custom depth material to ensure shadows will be drawn correctly
136
+ const depthMaterial = new MeshDepthMaterial({
137
+ depthPacking: RGBADepthPacking,
138
+ });
82
139
 
83
- /**
84
- *
85
- * @param {THREE.BufferGeometry} geometry
86
- */
87
- InstancedMeshGroup.prototype.setGeometry = function (geometry) {
88
- if (!(geometry instanceof BufferGeometry)) {
89
- throw new Error(`Expected THREE.BufferedGeometry, got something else instead.`);
90
- }
140
+ //if the source material uses alpha testing - enable it on the depth material
141
+ if (material.alphaTest !== 0) {
142
+ depthMaterial.alphaTest = material.alphaTest;
143
+ depthMaterial.map = material.map;
144
+ }
91
145
 
92
- this.__threeInstanceGeometry = geometry;
146
+ depthMaterial.onBeforeCompile = rewriteMaterial;
93
147
 
94
- this.build();
95
- };
96
148
 
149
+ const cachedMaterial = StaticMaterialCache.Global.acquire(material);
97
150
 
98
- /**
99
- *
100
- * @param {THREE.Material} sourceMaterial
101
- */
102
- InstancedMeshGroup.prototype.setMaterial = function (sourceMaterial) {
103
- const material = sourceMaterial.clone();
151
+ this.__material = cachedMaterial;
104
152
 
105
- if (material.isShaderMaterial) {
106
- // transfer source material uniforms
107
- for (const uniformsKey in material.uniforms) {
108
- material.uniforms[uniformsKey] = sourceMaterial.uniforms[uniformsKey];
109
- }
153
+ this.mesh.material = cachedMaterial;
154
+ this.mesh.customDepthMaterial = StaticMaterialCache.Global.acquire(depthMaterial);
110
155
  }
111
156
 
157
+ /**
158
+ *
159
+ * @param {number} size
160
+ */
161
+ setCapacity(size) {
162
+ if (this.capacity === size) {
163
+ // no change
164
+ return;
165
+ }
112
166
 
113
- material.onBeforeCompile = composeCompile(sourceMaterial.onBeforeCompile, rewriteMaterial);
114
-
115
- //we need a custom depth material to ensure shadows will be drawn correctly
116
- const depthMaterial = new MeshDepthMaterial({
117
- depthPacking: RGBADepthPacking,
118
- });
167
+ this.capacity = size;
119
168
 
120
- //if the source material uses alpha testing - enable it on the depth material
121
- if (material.alphaTest !== 0) {
122
- depthMaterial.alphaTest = material.alphaTest;
123
- depthMaterial.map = material.map;
169
+ this.build();
124
170
  }
125
171
 
126
- depthMaterial.onBeforeCompile = rewriteMaterial;
127
-
128
-
129
- const cachedMaterial = StaticMaterialCache.Global.acquire(material);
172
+ /**
173
+ *
174
+ * @param {number} size
175
+ */
176
+ ensureCapacity(size) {
130
177
 
131
- this.__material = cachedMaterial;
178
+ const currentCapacity = this.capacity;
132
179
 
133
- this.mesh.material = cachedMaterial;
134
- this.mesh.customDepthMaterial = StaticMaterialCache.Global.acquire(depthMaterial);
135
- };
180
+ if (currentCapacity < size) {
181
+ // grow
136
182
 
137
- /**
138
- *
139
- * @param {number} size
140
- */
141
- InstancedMeshGroup.prototype.setCapacity = function (size) {
142
- this.capacity = size;
143
- this.build();
144
- };
183
+ const newCapacityRaw = Math.max(
184
+ size,
185
+ currentCapacity * this.growFactor,
186
+ currentCapacity + this.growConstant
187
+ );
145
188
 
146
- /**
147
- *
148
- * @param {number} size
149
- */
150
- InstancedMeshGroup.prototype.ensureCapacity = function (size) {
189
+ const newCapacityInteger = Math.ceil(newCapacityRaw);
151
190
 
152
- const currentCapacity = this.capacity;
191
+ this.setCapacity(newCapacityInteger);
153
192
 
154
- if (currentCapacity < size) {
155
- // grow
193
+ } else if (
194
+ currentCapacity * this.shrinkFactor > size
195
+ && currentCapacity - this.shrinkConstant > size
196
+ ) {
197
+ // shrink
198
+ this.setCapacity(size);
199
+ }
156
200
 
157
- const newCapacityRaw = Math.max(
158
- size,
159
- currentCapacity * this.growFactor,
160
- currentCapacity + this.growConstant
161
- );
201
+ }
162
202
 
163
- const newCapacityInteger = Math.ceil(newCapacityRaw);
203
+ /**
204
+ *
205
+ * @param {number} index
206
+ * @param {number} x
207
+ * @param {number} y
208
+ * @param {number} z
209
+ */
210
+ setPositionAt(index, x, y, z) {
211
+ this.__attributePosition.setXYZ(index, x, y, z);
212
+ this.__attributePosition.needsUpdate = true;
213
+ }
164
214
 
165
- this.setCapacity(newCapacityInteger);
215
+ /**
216
+ *
217
+ * @param {number} index
218
+ * @param {number} x
219
+ * @param {number} y
220
+ * @param {number} z
221
+ * @param {number} w
222
+ */
223
+ setRotationAt(index, x, y, z, w) {
224
+ this.__attributeRotation.setXYZW(index, x, y, z, w);
225
+ this.__attributeRotation.needsUpdate = true;
226
+ }
166
227
 
167
- } else if (
168
- currentCapacity * this.shrinkFactor > size
169
- && currentCapacity - this.shrinkConstant > size
170
- ) {
171
- // shrink
172
- this.setCapacity(size);
228
+ /**
229
+ *
230
+ * @param {number} index
231
+ * @param {number} x
232
+ * @param {number} y
233
+ * @param {number} z
234
+ */
235
+ setScaleAt(index, x, y, z) {
236
+ this.__attributeScale.setXYZ(index, x, y, z);
237
+ this.__attributeScale.needsUpdate = true;
173
238
  }
174
239
 
175
- };
176
-
177
- /**
178
- *
179
- * @param {number} index
180
- * @param {number} x
181
- * @param {number} y
182
- * @param {number} z
183
- */
184
- InstancedMeshGroup.prototype.setPositionAt = function (index, x, y, z) {
185
- this.__attributePosition.setXYZ(index, x, y, z);
186
- this.__attributePosition.needsUpdate = true;
187
- };
188
-
189
- /**
190
- *
191
- * @param {number} index
192
- * @param {number} x
193
- * @param {number} y
194
- * @param {number} z
195
- * @param {number} w
196
- */
197
- InstancedMeshGroup.prototype.setRotationAt = function (index, x, y, z, w) {
198
- this.__attributeRotation.setXYZW(index, x, y, z, w);
199
- this.__attributeRotation.needsUpdate = true;
200
- };
201
-
202
- /**
203
- *
204
- * @param {number} index
205
- * @param {number} x
206
- * @param {number} y
207
- * @param {number} z
208
- */
209
- InstancedMeshGroup.prototype.setScaleAt = function (index, x, y, z) {
210
- this.__attributeScale.setXYZ(index, x, y, z);
211
- this.__attributeScale.needsUpdate = true;
212
- };
213
-
214
- /**
215
- * Swap position in attribute arrays of two elements
216
- * @param {int} indexA
217
- * @param {int} indexB
218
- */
219
- InstancedMeshGroup.prototype.swap = function (indexA, indexB) {
220
- throw new Error('Not Implemented Yet');
221
- };
222
-
223
- /**
224
- *
225
- * @param {int} size
226
- */
227
- InstancedMeshGroup.prototype.setCount = function (size) {
228
- this.ensureCapacity(size);
229
-
230
- this.count = size;
231
- this.__threeGeometry.instanceCount = size;
232
- };
233
-
234
- /**
235
- *
236
- * @return {number|int}
237
- */
238
- InstancedMeshGroup.prototype.getCount = function () {
239
- return this.count;
240
- };
241
-
242
- /**
243
- *
244
- * @param {int} reference
245
- * @returns {int}
246
- */
247
- InstancedMeshGroup.prototype.add = function (reference) {
248
- //get index
249
- const index = this.count;
250
- //grow
251
- this.setCount(this.count + 1);
252
-
253
- this.indices[reference] = index;
254
- this.references[index] = reference;
255
-
256
- return index;
257
- };
258
-
259
- /**
260
- *
261
- * @param {function(index:int,reference:int)} visitor
262
- * @param {*} [thisArg]
263
- */
264
- InstancedMeshGroup.prototype.traverseReferences = function (visitor, thisArg) {
265
- const indices = this.indices;
266
- const index_count = indices.length;
267
-
268
- for (let i = 0; i < index_count; i++) {
269
- const index = indices[i];
240
+ /**
241
+ * Swap position in attribute arrays of two elements
242
+ * @param {int} indexA
243
+ * @param {int} indexB
244
+ */
245
+ swap(indexA, indexB) {
246
+ throw new Error('Not Implemented Yet');
247
+ }
270
248
 
271
- if (index === undefined) {
272
- // unoccupied
273
- continue;
274
- }
249
+ /**
250
+ *
251
+ * @param {int} size
252
+ */
253
+ setCount(size) {
254
+ this.ensureCapacity(size);
275
255
 
276
- visitor.call(thisArg, index, i);
256
+ this.count = size;
257
+ this.__threeGeometry.instanceCount = size;
277
258
  }
278
- };
279
-
280
- /**
281
- *
282
- * @param {int} reference
283
- */
284
- InstancedMeshGroup.prototype.remove = function (reference) {
285
- //dereference
286
- const index = this.indices[reference];
287
-
288
- if (index === undefined) {
289
- //reference is not known
290
- throw new Error(`Reference '${reference}' was not found`);
259
+
260
+ /**
261
+ *
262
+ * @return {number|int}
263
+ */
264
+ getCount() {
265
+ return this.count;
291
266
  }
292
267
 
293
- delete this.indices[reference];
268
+ /**
269
+ *
270
+ * @param {int} reference
271
+ * @returns {int}
272
+ */
273
+ add(reference) {
274
+ //get index
275
+ const index = this.count;
276
+ //grow
277
+ this.setCount(this.count + 1);
294
278
 
295
- const lastIndex = this.count - 1;
279
+ this.indices[reference] = index;
280
+ this.references[index] = reference;
296
281
 
297
- if (index === lastIndex) {
298
- //easy case, reference is placed at the end, no swap needed, we can just forget about it
299
- delete this.references[index];
300
- } else {
301
- //not at the end, move end reference to this place
302
- const index3 = index * 3;
303
- const start3 = lastIndex * 3;
304
- const end3 = start3 + 3;
282
+ return index;
283
+ }
305
284
 
306
- const index4 = index * 4;
307
- const start4 = lastIndex * 4;
308
- const end4 = start4 + 4;
285
+ /**
286
+ *
287
+ * @param {function(index:int,reference:int)} visitor
288
+ * @param {*} [thisArg]
289
+ */
290
+ traverseReferences(visitor, thisArg) {
291
+ const indices = this.indices;
292
+ const index_count = indices.length;
309
293
 
310
- this.__attributePosition.array.copyWithin(index3, start3, end3);
311
- this.__attributeRotation.array.copyWithin(index4, start4, end4);
312
- this.__attributeScale.array.copyWithin(index3, start3, end3);
294
+ for (let i = 0; i < index_count; i++) {
295
+ const index = indices[i];
313
296
 
314
- this.__attributePosition.needsUpdate = true;
315
- this.__attributeRotation.needsUpdate = true;
316
- this.__attributeScale.needsUpdate = true;
297
+ if (index === undefined) {
298
+ // unoccupied
299
+ continue;
300
+ }
317
301
 
318
- //update moved reference index
319
- const movedReference = this.references[lastIndex];
302
+ visitor.call(thisArg, index, i);
303
+ }
304
+ }
305
+
306
+ /**
307
+ *
308
+ * @param {int} reference
309
+ */
310
+ remove(reference) {
311
+ //dereference
312
+ const index = this.indices[reference];
320
313
 
321
- if (movedReference === undefined) {
322
- //moved reference not found
323
- throw new Error(`Moved reference was not found`);
314
+ if (index === undefined) {
315
+ //reference is not known
316
+ throw new Error(`Reference '${reference}' was not found`);
324
317
  }
325
318
 
326
- delete this.references[lastIndex];
319
+ delete this.indices[reference];
327
320
 
328
- //assume the place of removed reference
329
- this.references[index] = movedReference;
330
- this.indices[movedReference] = index;
331
- }
321
+ const lastIndex = this.count - 1;
332
322
 
333
- //update size
334
- this.setCount(this.count - 1);
335
- };
323
+ if (index === lastIndex) {
324
+ //easy case, reference is placed at the end, no swap needed, we can just forget about it
325
+ delete this.references[index];
326
+ } else {
327
+ //not at the end, move end reference to this place
328
+ const index3 = index * 3;
329
+ const start3 = lastIndex * 3;
330
+ const end3 = start3 + 3;
336
331
 
337
- InstancedMeshGroup.prototype.build = function () {
338
- if (this.__threeGeometry !== null) {
339
- // dispose old geometry's GPU memory
340
- this.__threeGeometry.dispose();
341
- }
332
+ const index4 = index * 4;
333
+ const start4 = lastIndex * 4;
334
+ const end4 = start4 + 4;
342
335
 
343
- this.__threeGeometry = new InstancedBufferGeometry();
336
+ this.__attributePosition.array.copyWithin(index3, start3, end3);
337
+ this.__attributeRotation.array.copyWithin(index4, start4, end4);
338
+ this.__attributeScale.array.copyWithin(index3, start3, end3);
344
339
 
345
- const instance = this.__threeInstanceGeometry;
346
- const geometry = this.__threeGeometry;
340
+ this.__attributePosition.needsUpdate = true;
341
+ this.__attributeRotation.needsUpdate = true;
342
+ this.__attributeScale.needsUpdate = true;
347
343
 
348
- geometry.instanceCount = this.count;
349
- geometry.dynamic = true;
344
+ //update moved reference index
345
+ const movedReference = this.references[lastIndex];
350
346
 
351
- //copy instance attributes
352
- geometry.index = instance.index;
353
- for (let attributeName in instance.attributes) {
354
- if (!instance.attributes.hasOwnProperty(attributeName)) {
355
- continue;
347
+ if (movedReference === undefined) {
348
+ //moved reference not found
349
+ throw new Error(`Moved reference was not found`);
350
+ }
351
+
352
+ delete this.references[lastIndex];
353
+
354
+ //assume the place of removed reference
355
+ this.references[index] = movedReference;
356
+ this.indices[movedReference] = index;
356
357
  }
357
358
 
358
- geometry.attributes[attributeName] = instance.attributes[attributeName];
359
+ //update size
360
+ this.setCount(this.count - 1);
359
361
  }
360
362
 
361
- //build instanced attributes
362
- const newPositionArray = new Float32Array(this.capacity * 3);
363
- const newRotationArray = new Float32Array(this.capacity * 4);
364
- const newScaleArray = new Float32Array(this.capacity * 3);
363
+ build() {
364
+ if (this.__threeGeometry !== null) {
365
+ // dispose old geometry's GPU memory
366
+ this.__threeGeometry.dispose();
367
+ }
368
+
369
+ this.__threeGeometry = new InstancedBufferGeometry();
365
370
 
366
- if (this.__attributePosition !== null) {
367
- //copy old data
368
- const oldPositionArray = this.__attributePosition.array;
369
- typed_array_copy(oldPositionArray, newPositionArray);
370
- }
371
- if (this.__attributeRotation !== null) {
372
- //copy old data
373
- const oldRotationArray = this.__attributeRotation.array;
374
- typed_array_copy(oldRotationArray, newRotationArray);
375
- }
376
- if (this.__attributeScale !== null) {
377
- const oldScaleArray = this.__attributeScale.array;
378
- typed_array_copy(oldScaleArray, newScaleArray);
371
+ const instance = this.__threeInstanceGeometry;
372
+ const geometry = this.__threeGeometry;
379
373
 
380
- if (newScaleArray.length > oldScaleArray.length) {
381
- //fill the rest of the array with scale factor of 1 as a default
382
- newScaleArray.fill(1, oldScaleArray.length);
374
+ geometry.instanceCount = this.count;
375
+ geometry.dynamic = true;
376
+
377
+ //copy instance attributes
378
+ geometry.index = instance.index;
379
+ for (let attributeName in instance.attributes) {
380
+ if (!instance.attributes.hasOwnProperty(attributeName)) {
381
+ continue;
382
+ }
383
+
384
+ geometry.attributes[attributeName] = instance.attributes[attributeName];
383
385
  }
384
- }
385
386
 
386
- //rewrite old attributes
387
- this.__attributePosition = new InstancedBufferAttribute(newPositionArray, 3);
388
- this.__attributeRotation = new InstancedBufferAttribute(newRotationArray, 4);
389
- this.__attributeScale = new InstancedBufferAttribute(newScaleArray, 3);
387
+ //build instanced attributes
388
+ const newPositionArray = new Float32Array(this.capacity * 3);
389
+ const newRotationArray = new Float32Array(this.capacity * 4);
390
+ const newScaleArray = new Float32Array(this.capacity * 3);
390
391
 
391
- //add attributes to newly created geometry
392
- geometry.setAttribute("instancePosition", this.__attributePosition);
393
- geometry.setAttribute("instanceRotation", this.__attributeRotation);
394
- geometry.setAttribute("instanceScale", this.__attributeScale);
392
+ if (this.__attributePosition !== null) {
393
+ //copy old data
394
+ const oldPositionArray = this.__attributePosition.array;
395
+ typed_array_copy(oldPositionArray, newPositionArray);
396
+ }
397
+ if (this.__attributeRotation !== null) {
398
+ //copy old data
399
+ const oldRotationArray = this.__attributeRotation.array;
400
+ typed_array_copy(oldRotationArray, newRotationArray);
401
+ }
402
+ if (this.__attributeScale !== null) {
403
+ const oldScaleArray = this.__attributeScale.array;
404
+ typed_array_copy(oldScaleArray, newScaleArray);
405
+
406
+ if (newScaleArray.length > oldScaleArray.length) {
407
+ //fill the rest of the array with scale factor of 1 as a default
408
+ newScaleArray.fill(1, oldScaleArray.length);
409
+ }
410
+ }
395
411
 
412
+ //rewrite old attributes
413
+ this.__attributePosition = new InstancedBufferAttribute(newPositionArray, 3);
414
+ this.__attributeRotation = new InstancedBufferAttribute(newRotationArray, 4);
415
+ this.__attributeScale = new InstancedBufferAttribute(newScaleArray, 3);
396
416
 
397
- this.mesh.geometry = geometry;
398
- };
417
+ //add attributes to newly created geometry
418
+ geometry.setAttribute("instancePosition", this.__attributePosition);
419
+ geometry.setAttribute("instanceRotation", this.__attributeRotation);
420
+ geometry.setAttribute("instanceScale", this.__attributeScale);
399
421
 
400
- export { InstancedMeshGroup };
422
+
423
+ this.mesh.geometry = geometry;
424
+ }
425
+ }