@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,514 +1,135 @@
1
- import {
2
- ClampToEdgeWrapping,
3
- DataTexture,
4
- LinearFilter,
5
- LinearMipMapLinearFilter,
6
- Matrix4,
7
- RGBAFormat,
8
- UnsignedByteType,
9
- Vector2 as ThreeVector2
10
- } from "three";
11
- import { assert } from "../../../../../../core/assert.js";
12
- import { HashMap } from "../../../../../../core/collection/map/HashMap.js";
13
- import Vector2 from "../../../../../../core/geom/Vector2.js";
14
- import { ManagedAtlas } from "../../../../texture/atlas/ManagedTextureAtlas.js";
15
- import { writeSample2DDataToDataTexture } from "../../../../texture/sampler/writeSampler2DDataToDataTexture.js";
16
- import { ParticleEmitterFlag } from "../emitter/ParticleEmitterFlag.js";
17
- import { make_particle_billboard_shader } from "../renderers/billboard/ParticleBillboardMaterial.js";
18
- import { MaterialRecord } from "./MaterialRecord.js";
19
-
20
- const EMITTER_MATERIAL_FLAGS =
21
- ParticleEmitterFlag.DepthSoftDisabled
22
- | ParticleEmitterFlag.DepthReadDisabled
23
- | ParticleEmitterFlag.AlignOnVelocity
24
- | ParticleEmitterFlag.Lit
25
- ;
26
-
27
- /**
28
- *
29
- * @param {ParticleEmitter} emitter
30
- * @returns {number}
31
- */
32
- function computeEmitterMaterialHash(emitter) {
33
-
34
- return (emitter.flags & EMITTER_MATERIAL_FLAGS);
35
- }
36
-
37
- /**
38
- *
39
- * @param {ParticleEmitter} a
40
- * @param {ParticleEmitter} b
41
- * @returns {boolean}
42
- */
43
- function computeEmitterMaterialEquality(a, b) {
44
- const aFlags = a.flags & EMITTER_MATERIAL_FLAGS;
45
- const bFlags = b.flags & EMITTER_MATERIAL_FLAGS;
46
-
47
- return (aFlags === bFlags);
48
- }
49
-
50
-
51
- /**
52
- * Used for placeholder texture value
53
- * @readonly
54
- * @type {Uint8Array}
55
- */
56
- const FOUR_BYTE_UINT8_ARRAY = new Uint8Array(4);
57
-
58
- /**
59
- * @returns {DataTexture}
60
- */
61
- function buildDataTexture(
62
- {
63
- anisotropy = 4,
64
- generateMipmaps = false,
65
- minFilter = LinearFilter,
66
- magFilter = LinearFilter
67
- }
68
- ) {
69
- const result = new DataTexture(FOUR_BYTE_UINT8_ARRAY, 1, 1, RGBAFormat);
70
-
71
- result.type = UnsignedByteType;
72
- result.flipY = false;
73
- result.wrapS = ClampToEdgeWrapping;
74
- result.wrapT = ClampToEdgeWrapping;
75
-
76
- result.minFilter = minFilter;
77
- result.magFilter = magFilter;
78
-
79
- // possibly not-power-of-two
80
- result.generateMipmaps = generateMipmaps;
81
-
82
- result.repeat.set(1, 1);
83
-
84
- result.anisotropy = anisotropy;
85
-
86
- result.needsUpdate = true;
87
-
88
- return result;
89
- }
90
-
91
- export class ShaderManager {
92
- /**
93
- *
94
- * @type {Map<ParticleLayer, Reference<AtlasPatch>>}
95
- */
96
- #sprite_references = new Map();
97
-
98
- /**
99
- *
100
- * @type {Texture|null}
101
- */
102
- depthTexture = null;
103
-
104
- /**
105
- * Number of unused records to keep, this allows reused of records avoiding shader recompilation
106
- * @type {number}
107
- */
108
- recordGraveyardSize = 10;
109
-
110
- /**
111
- *
112
- * @param {AssetManager} asset_manager
113
- * @param {MaterialManager} material_manager
114
- * @constructor
115
- */
116
- constructor(asset_manager, material_manager) {
117
- assert.defined(asset_manager, "asset_manager");
118
- assert.defined(material_manager, "material_manager");
119
-
120
- /**
121
- *
122
- * @type {MaterialManager}
123
- * @private
124
- */
125
- this.__material_manager = material_manager;
126
-
127
- /**
128
- *
129
- * @type {ManagedAtlas}
130
- */
131
- this.spriteAtlas = new ManagedAtlas(asset_manager);
132
-
133
- /**
134
- *
135
- * @type {DataTexture|null}
136
- */
137
- this.spriteTexture = buildDataTexture({
138
- generateMipmaps: true,
139
- minFilter: LinearMipMapLinearFilter,
140
- magFilter: LinearFilter,
141
- anisotropy: 0 // sprites are always facing the screen, anisotropic filtering would be pointless
142
- });
143
-
144
- this.spriteTexture.name = 'Sprite sheet';
145
-
146
- /**
147
- * material map is identified by parameter hash
148
- * @readonly
149
- * @private
150
- * @type {HashMap<ParticleEmitter, MaterialRecord>}
151
- */
152
- this.materialMap = new HashMap({
153
- keyHashFunction: computeEmitterMaterialHash,
154
- keyEqualityFunction: computeEmitterMaterialEquality
155
- });
156
-
157
- /**
158
- * @readonly
159
- * @private
160
- * @type {HashMap<ParticleEmitter, MaterialRecord>}
161
- */
162
- this.recordGraveyard = new HashMap({
163
- keyHashFunction: computeEmitterMaterialHash,
164
- keyEqualityFunction: computeEmitterMaterialEquality
165
- });
166
-
167
- /**
168
- *
169
- * @type {Vector2}
170
- */
171
- this.viewportSize = new Vector2(0, 0);
172
-
173
- //watch atlas updates
174
- this.spriteAtlas.atlas.on.painted.add(this.updateSpriteTexture, this);
175
-
176
- /**
177
- * Common shader uniforms, inherited by every material and updated centrally (here)
178
- * @private
179
- */
180
- this.__common_uniforms = {
181
- tSpriteAtlas: {
182
- value: this.spriteTexture
183
- },
184
- tDepth: {
185
- value: null
186
- },
187
- resolution: {
188
- value: new ThreeVector2()
189
- },
190
- projectionMatrix: {
191
- value: null
192
- },
193
- modelViewMatrix: {
194
- value: null
195
- },
196
- cameraNear: {
197
- value: 0
198
- },
199
- cameraFar: {
200
- value: 0
201
- },
202
- uViewInverse: { type: 'm4', value: new Matrix4() },
203
- uProjectionInverse: { type: 'm4', value: new Matrix4() },
204
- };
205
-
206
- // debugAtlas(this.spriteAtlas.atlas, { scale: new Vector2(1, 1) });
207
- }
208
-
209
- /**
210
- * Should be called before using shaders managed by this
211
- */
212
- update() {
213
- this.spriteAtlas.atlas.update();
214
- }
215
-
216
-
217
- /**
218
- * @private
219
- */
220
- updateSpriteTexture() {
221
- // console.time("ShaderManager.updateSpriteTexture");
222
-
223
- const atlas = this.spriteAtlas.atlas.sampler;
224
-
225
- const dataTexture = this.spriteTexture;
226
-
227
- writeSample2DDataToDataTexture(atlas, dataTexture);
228
-
229
- this.materialMap.forEach(function (entry) {
230
-
231
- const emitters = entry.emitters;
232
- const emitter_count = emitters.length;
233
-
234
- for (let i = 0; i < emitter_count; i++) {
235
- const emitter = emitters[i];
236
- //mark sprites for an update
237
- emitter.setFlag(ParticleEmitterFlag.SpritesNeedUpdate);
238
- }
239
-
240
- });
241
-
242
- // console.timeEnd("ShaderManager.updateSpriteTexture");
243
- }
244
-
245
- /**
246
- * @private
247
- * @returns {Reference<Material>}
248
- * @param {ParticleEmitter} emitter
249
- */
250
- buildMaterial(emitter) {
251
- const lights_enabled = emitter.getFlag(ParticleEmitterFlag.Lit);
252
-
253
- const shader = make_particle_billboard_shader({ lights: lights_enabled });
254
-
255
- shader.uniforms = Object.assign(shader.uniforms, this.__common_uniforms);
256
-
257
- // write defines
258
- const defs = shader.defines;
259
-
260
- defs.DEPTH_READ_ENABLED = !emitter.getFlag(ParticleEmitterFlag.DepthReadDisabled);
261
- defs.DEPTH_SOFT_ENABLED = !emitter.getFlag(ParticleEmitterFlag.DepthSoftDisabled);
262
- defs.ALIGN_DIRECTION_ENABLED = emitter.getFlag(ParticleEmitterFlag.AlignOnVelocity);
263
-
264
- return this.__material_manager.obtain(shader);
265
- }
266
-
267
- /**
268
- *
269
- * @param {ParticleEmitter} emitter
270
- */
271
- register(emitter) {
272
- const spriteAtlas = this.spriteAtlas;
273
-
274
- // load sprites
275
- const particle_layers = emitter.layers;
276
- const layer_count = particle_layers.length;
277
-
278
- for (let i = 0; i < layer_count; i++) {
279
- const layer = particle_layers.get(i);
280
-
281
- const patchPromise = spriteAtlas.acquire(layer.imageURL);
282
-
283
- patchPromise.then(ref => {
284
- this.#sprite_references.set(layer, ref);
285
- layer.setAtlasPatch(ref.getValue());
286
- });
287
-
288
- patchPromise.catch((e) => {
289
- console.warn(`Failed to load sprite '${layer.imageURL}':`, e);
290
- });
291
- }
292
-
293
- // obtain material
294
- let material, entry;
295
- if (this.materialMap.has(emitter)) {
296
- entry = this.materialMap.get(emitter);
297
-
298
- // the record is in use again, so it is no longer a candidate for the graveyard eviction in
299
- // `cleanup`, which releases the material reference the record still hands to live emitters
300
- this.recordGraveyard.delete(emitter);
301
-
302
- material = entry.material;
303
- } else {
304
-
305
- // entry is not in the cache, create it
306
- entry = createShaderEntry(emitter, this);
307
-
308
- material = entry.material;
309
-
310
- this.materialMap.set(emitter, entry);
311
- }
312
-
313
- entry.lastAccessTime = performance.now();
314
-
315
- entry.count++;
316
-
317
- entry.emitters.push(emitter);
318
-
319
- // assign material
320
- emitter.mesh.material = material;
321
- }
322
-
323
- /**
324
- * Perform intenal cleanup, remove unused material records
325
- */
326
- cleanup() {
327
- const recordGraveyardSize = this.recordGraveyardSize;
328
-
329
- while (this.recordGraveyard.size > recordGraveyardSize) {
330
- let bestAccessTime = Infinity;
331
- let bestKey = null;
332
-
333
- this.recordGraveyard.forEach(function (value, key) {
334
- if (value.lastAccessTime < bestAccessTime) {
335
- bestAccessTime = value.lastAccessTime;
336
- bestKey = key;
337
- }
338
- });
339
-
340
- const evicted = this.recordGraveyard.get(bestKey);
341
-
342
- if (!this.recordGraveyard.delete(bestKey)) {
343
- console.error(`Failed to remove record from the graveyard`, bestKey, this.recordGraveyard);
344
-
345
- this.recordGraveyard.verifyHashes(console.error);
346
-
347
- console.warn('Recomputing hashes ... ');
348
-
349
- this.recordGraveyard.rebuild();
350
- this.materialMap.rebuild();
351
- }
352
-
353
- this.materialMap.delete(bestKey);
354
-
355
- // the record is leaving both maps, so this is the last chance to hand the material back;
356
- // only unused records reach the graveyard, `register` takes a resurrected one back out of it
357
- evicted.material_reference.release();
358
- }
359
- }
360
-
361
- /**
362
- *
363
- * @param {ParticleEmitter} emitter
364
- */
365
- deregister(emitter) {
366
- const entry = this.materialMap.get(emitter);
367
-
368
- if (entry === undefined) {
369
- console.error(`Attempted to deregister emitter that was not registered (not found in materialMap). Request ignored.`, emitter);
370
- return;
371
- }
372
-
373
- entry.count--;
374
-
375
- //release material
376
- const spriteAtlas = this.spriteAtlas;
377
-
378
- //release sprites
379
- const particle_layers = emitter.layers;
380
- const layer_count = particle_layers.length;
381
- for (let i = 0; i < layer_count; i++) {
382
- const layer = particle_layers.get(i);
383
-
384
- // TODO deal with the case where we remove the layer before sprite is loaded
385
- const ref = this.#sprite_references.get(layer);
386
-
387
- if (ref !== undefined) {
388
- ref.release();
389
-
390
- // the reference is spent, and the map is what keeps the layer reachable
391
- this.#sprite_references.delete(layer);
392
- }
393
-
394
- layer.setAtlasPatch(null); // clear patch
395
- }
396
-
397
- if (entry.count <= 0) {
398
- //last usage removed
399
- this.recordGraveyard.set(emitter, entry);
400
- this.cleanup();
401
-
402
- } else {
403
- //remove reference to material from the entry
404
- const emitterIndex = entry.emitters.indexOf(emitter);
405
-
406
- if (emitterIndex === -1) {
407
- console.warn('Emitter was not found in the shader manager');
408
- return;
409
- }
410
-
411
- //remove
412
- entry.emitters.splice(emitterIndex, 1);
413
- }
414
- }
415
-
416
- /**
417
- *
418
- * @param {Camera} camera THREE.js Camera object
419
- */
420
- setCamera(camera) {
421
- this.camera = camera;
422
-
423
- const projectionMatrix = camera.projectionMatrix;
424
- const modelViewMatrix = (new Matrix4()).multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
425
- const cameraNear = camera.near;
426
- const cameraFar = camera.far;
427
-
428
- const uniforms = this.__common_uniforms;
429
-
430
- uniforms.projectionMatrix.value = projectionMatrix;
431
- uniforms.modelViewMatrix.value = modelViewMatrix;
432
- uniforms.cameraNear.value = cameraNear;
433
- uniforms.cameraFar.value = cameraFar;
434
-
435
- uniforms.uProjectionInverse.value.copy(camera.projectionMatrixInverse);
436
- uniforms.uViewInverse.value.copy(camera.matrixWorld);
437
- }
438
-
439
- /**
440
- *
441
- * @param {Texture} texture
442
- */
443
- setDepthTexture(texture) {
444
- this.depthTexture = texture;
445
-
446
- this.__common_uniforms.tDepth.value = texture;
447
-
448
- }
449
-
450
- /**
451
- *
452
- * @param {number} x
453
- * @param {number} y
454
- */
455
- setViewportSize(x, y) {
456
- this.viewportSize.set(x, y);
457
-
458
- this.__common_uniforms.resolution.value.set(x, y);
459
- }
460
-
461
- /**
462
- * Hand back every resource this manager acquired.
463
- *
464
- * Materials are given back to the {@link MaterialManager} rather than disposed here: the compiled
465
- * material is shared by content hash with every other consumer that asked for the same shader, so the
466
- * manager is the only thing that can know when the last user is gone. Releasing is therefore safe
467
- * whichever way the teardown ordering falls, even for a material a live mesh still points at.
468
- *
469
- * The manager is left able to re-acquire, so a system that starts up again gets working materials and
470
- * a working sprite sheet without being rebuilt.
471
- */
472
- dispose() {
473
- // the graveyard is a subset of `materialMap` - `deregister` adds an unused record to the graveyard
474
- // without taking it out of the material map, and `cleanup` is what drops it from both
475
- this.materialMap.forEach(record => {
476
- record.material_reference.release();
477
- });
478
-
479
- this.materialMap.clear();
480
- this.recordGraveyard.clear();
481
-
482
- for (const reference of this.#sprite_references.values()) {
483
- reference.release();
484
- }
485
-
486
- this.#sprite_references.clear();
487
-
488
- this.spriteTexture.dispose();
489
- }
490
- }
491
-
492
- /**
493
- *
494
- * @param {ParticleEmitter} emitter
495
- * @param {ShaderManager} shaderManager
496
- * @returns {MaterialRecord}
497
- */
498
- function createShaderEntry(emitter, shaderManager) {
499
- const entry = new MaterialRecord();
500
- entry.count = 0;
501
- entry.parameters = emitter.parameters;
502
-
503
- const material_reference = shaderManager.buildMaterial(emitter);
504
-
505
- entry.material_reference = material_reference;
506
- entry.material = material_reference.getValue();
507
-
508
- //link all signal bindings
509
- entry.signalBindings.forEach(function (b) {
510
- b.link();
511
- });
512
-
513
- return entry;
514
- }
1
+ import { assert } from "../../../../../../core/assert.js";
2
+ import { ManagedAtlas } from "../../../../texture/atlas/ManagedTextureAtlas.js";
3
+ import { ParticleEmitterFlag } from "../emitter/ParticleEmitterFlag.js";
4
+
5
+ /**
6
+ * The sprite sheet the particle system draws from.
7
+ *
8
+ * **Every emitter's layers share one atlas**, so a hundred effects using the same puff of smoke pay
9
+ * for one image; a layer holds a reference to the patch it was given and hands it back when the
10
+ * emitter is deregistered, and the atlas repacks when the set of patches changes.
11
+ *
12
+ * The class used to carry a second job — a compiled shader per emitter, keyed on the four flags
13
+ * that change the shader, with a graveyard of unused records to avoid recompiling. That was three's
14
+ * `ShaderMaterial`, and it is gone: the particles are drawn by a Shade pass that owns its own
15
+ * pipeline and reads the atlas sampler directly.
16
+ */
17
+ export class ShaderManager {
18
+ /**
19
+ * The atlas patch each registered layer holds, so that deregistering can give it back.
20
+ *
21
+ * @type {Map<ParticleLayer, Reference<AtlasPatch>>}
22
+ */
23
+ #sprite_references = new Map();
24
+
25
+ /**
26
+ * The emitters currently drawing from the atlas. A repack has to reach all of them, and a
27
+ * layer does not know which emitter it belongs to.
28
+ *
29
+ * @type {Set<ParticleEmitter>}
30
+ */
31
+ #emitters = new Set();
32
+
33
+ /**
34
+ * @param {AssetManager} asset_manager
35
+ */
36
+ constructor(asset_manager) {
37
+ assert.defined(asset_manager, "asset_manager");
38
+
39
+ /**
40
+ *
41
+ * @type {ManagedAtlas}
42
+ */
43
+ this.spriteAtlas = new ManagedAtlas(asset_manager);
44
+
45
+ this.spriteAtlas.atlas.on.painted.add(this.#handleAtlasPainted, this);
46
+ }
47
+
48
+ /**
49
+ * Should be called before using the sprite sheet.
50
+ */
51
+ update() {
52
+ this.spriteAtlas.atlas.update();
53
+ }
54
+
55
+ /**
56
+ * A repack moves every patch, so every particle already carrying UVs is carrying the wrong ones.
57
+ */
58
+ #handleAtlasPainted() {
59
+ for (const emitter of this.#emitters) {
60
+ emitter.setFlag(ParticleEmitterFlag.SpritesNeedUpdate);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Take out a reference to every sprite the emitter's layers name.
66
+ *
67
+ * @param {ParticleEmitter} emitter
68
+ */
69
+ register(emitter) {
70
+ const spriteAtlas = this.spriteAtlas;
71
+
72
+ this.#emitters.add(emitter);
73
+
74
+ const particle_layers = emitter.layers;
75
+ const layer_count = particle_layers.length;
76
+
77
+ for (let i = 0; i < layer_count; i++) {
78
+ const layer = particle_layers.get(i);
79
+
80
+ const patchPromise = spriteAtlas.acquire(layer.imageURL);
81
+
82
+ patchPromise.then(ref => {
83
+ this.#sprite_references.set(layer, ref);
84
+ layer.setAtlasPatch(ref.getValue());
85
+ });
86
+
87
+ patchPromise.catch((e) => {
88
+ console.warn(`Failed to load sprite '${layer.imageURL}':`, e);
89
+ });
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Hand back every sprite the emitter's layers hold.
95
+ *
96
+ * @param {ParticleEmitter} emitter
97
+ */
98
+ deregister(emitter) {
99
+ this.#emitters.delete(emitter);
100
+
101
+ const particle_layers = emitter.layers;
102
+ const layer_count = particle_layers.length;
103
+
104
+ for (let i = 0; i < layer_count; i++) {
105
+ const layer = particle_layers.get(i);
106
+
107
+ // TODO deal with the case where we remove the layer before sprite is loaded
108
+ const ref = this.#sprite_references.get(layer);
109
+
110
+ if (ref !== undefined) {
111
+ ref.release();
112
+
113
+ // the reference is spent, and the map is what keeps the layer reachable
114
+ this.#sprite_references.delete(layer);
115
+ }
116
+
117
+ layer.setAtlasPatch(null); // clear patch
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Hand back every sprite this manager acquired.
123
+ *
124
+ * The manager is left able to re-acquire, so a system that starts up again gets a working
125
+ * sprite sheet without being rebuilt.
126
+ */
127
+ dispose() {
128
+ for (const reference of this.#sprite_references.values()) {
129
+ reference.release();
130
+ }
131
+
132
+ this.#sprite_references.clear();
133
+ this.#emitters.clear();
134
+ }
135
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"CameraSystem3.d.ts","sourceRoot":"","sources":["../../../../src/engine/graphics3/CameraSystem3.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;GAgBG;AACH;IAoBI;;OAEG;IACH,uCAQC;IADG,mDAAuC;IAG3C,2CAEC;IAED,4CAIC;IAED;;;;OAIG;IACH,4BAEC;IAED;;;;OAIG;IACH,aAJW,MAAM,aACN,SAAS,UACT,MAAM,QAUhB;IAED;;;;OAIG;IACH,eAJW,MAAM,aACN,SAAS,UACT,MAAM,QAIhB;;CA6DJ;uBA7JsB,kBAAkB;0BACf,+BAA+B;uBAClC,kCAAkC"}
1
+ {"version":3,"file":"CameraSystem3.d.ts","sourceRoot":"","sources":["../../../../src/engine/graphics3/CameraSystem3.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;GAgBG;AACH;IAoBI;;OAEG;IACH,uCAQC;IADG,mDAAuC;IAG3C,2CAEC;IAED,4CAIC;IAED;;;;OAIG;IACH,4BAEC;IAED;;;;OAIG;IACH,aAJW,MAAM,aACN,SAAS,UACT,MAAM,QAUhB;IAED;;;;OAIG;IACH,eAJW,MAAM,aACN,SAAS,UACT,MAAM,QAIhB;;CAsEJ;uBAtKsB,kBAAkB;0BACf,+BAA+B;uBAClC,kCAAkC"}
@@ -100,7 +100,7 @@ export class CameraSystem3 extends System {
100
100
  }
101
101
 
102
102
  /**
103
- * Copy the active camera entity onto the camera Shade draws with.
103
+ * Copy the active camera entity onto the camera Shade draws with, and its frustum back.
104
104
  *
105
105
  * @param {number} time_delta
106
106
  */
@@ -122,6 +122,15 @@ export class CameraSystem3 extends System {
122
122
  target.far = entry.camera.clip_far;
123
123
 
124
124
  camera_sync_from_transform(target, entry.transform);
125
+
126
+ /*
127
+ The return trip. Gameplay asks what the camera can see — which armies to generate now,
128
+ which terrain tiles a scene has to have before it is shown — and the honest answer is the
129
+ frustum the renderer is drawing with, not a second one derived from the component. It is
130
+ copied rather than aliased because the renderer's camera is one object and any number of
131
+ camera entities can pass through it.
132
+ */
133
+ entry.camera.publishFrustum(target.frustum);
125
134
  }
126
135
 
127
136
  /**