@woosh/meep-engine 3.18.0 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -1
  3. package/editor/view/particles/effect/ParticleCurveEditorView.js +303 -120
  4. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -1
  5. package/editor/view/particles/effect/ParticleGradientEditorView.js +108 -63
  6. package/editor/view/particles/effect/ParticleGraphEditorView.js +1 -1
  7. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
  8. package/editor/view/particles/effect/ParticleNodeParametersView.js +3 -1
  9. package/editor/view/particles/effect/particle-editor.css +60 -30
  10. package/package.json +1 -2
  11. package/samples/engine/README.md +1 -1
  12. package/src/core/binary/compression/decompress_bytes.d.ts +13 -0
  13. package/src/core/binary/compression/decompress_bytes.d.ts.map +1 -0
  14. package/src/core/binary/compression/decompress_bytes.js +28 -0
  15. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +67 -22
  16. package/src/engine/asset/loaders/image/ImageDecoderWorker.js +12 -27
  17. package/src/engine/asset/loaders/image/prototypePNG.js +8 -7
  18. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  19. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
  20. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +266 -0
  21. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -0
  22. package/src/engine/graphics/ecs/particles/ParticleEffect.js +455 -0
  23. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts +58 -0
  24. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts.map +1 -0
  25. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.js +219 -0
  26. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +178 -25
  27. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  28. package/src/engine/graphics3/GPUParticleEmitterSystem.js +809 -310
  29. package/src/format/image/png/PNGReader.d.ts +7 -6
  30. package/src/format/image/png/PNGReader.d.ts.map +1 -1
  31. package/src/format/image/png/PNGReader.js +13 -12
  32. package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts +3 -2
  33. package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts.map +1 -1
  34. package/src/format/image/png/chunk/png_chunk_decode_iTXt.js +5 -4
  35. package/src/format/image/png/chunk/png_chunk_decode_zTXt.d.ts +3 -2
  36. package/src/format/image/png/chunk/png_chunk_decode_zTXt.d.ts.map +1 -1
  37. package/src/format/image/png/chunk/png_chunk_decode_zTXt.js +5 -4
  38. package/src/format/image/png/png_inflate.d.ts +3 -3
  39. package/src/format/image/png/png_inflate.d.ts.map +1 -1
  40. package/src/format/image/png/png_inflate.js +29 -39
  41. package/src/format/texture/ktx2/ktx2_read.d.ts +4 -4
  42. package/src/format/texture/ktx2/ktx2_read.d.ts.map +1 -1
  43. package/src/format/texture/ktx2/ktx2_read.js +18 -21
  44. package/src/shade/playground/particle_ecs/README.md +203 -0
  45. package/src/shade/playground/particle_ecs/bonfire_editor.d.ts +39 -0
  46. package/src/shade/playground/particle_ecs/bonfire_editor.d.ts.map +1 -0
  47. package/src/shade/playground/particle_ecs/bonfire_editor.js +315 -0
  48. package/src/shade/playground/particle_ecs/bonfire_effects.d.ts +145 -0
  49. package/src/shade/playground/particle_ecs/bonfire_effects.d.ts.map +1 -0
  50. package/src/shade/playground/particle_ecs/bonfire_effects.js +202 -0
  51. package/src/shade/playground/particle_ecs/bonfire_sprites.d.ts +23 -0
  52. package/src/shade/playground/particle_ecs/bonfire_sprites.d.ts.map +1 -0
  53. package/src/shade/playground/particle_ecs/bonfire_sprites.js +315 -0
  54. package/src/shade/playground/particle_ecs/bonfire_world.d.ts +86 -0
  55. package/src/shade/playground/particle_ecs/bonfire_world.d.ts.map +1 -0
  56. package/src/shade/playground/particle_ecs/bonfire_world.js +303 -0
  57. package/src/shade/playground/particle_ecs/effects/embers.json +1634 -0
  58. package/src/shade/playground/particle_ecs/effects/flame.json +1882 -0
  59. package/src/shade/playground/particle_ecs/effects/smoke.json +1860 -0
  60. package/src/shade/playground/particle_ecs/effects/soot.json +1606 -0
  61. package/src/shade/playground/particle_ecs/index.html +330 -0
  62. package/src/shade/playground/particle_ecs/main.d.ts +2 -0
  63. package/src/shade/playground/particle_ecs/main.d.ts.map +1 -0
  64. package/src/shade/playground/particle_ecs/main.js +566 -0
  65. package/src/shade/playground/particle_ecs/moonlit_environment.d.ts +16 -0
  66. package/src/shade/playground/particle_ecs/moonlit_environment.d.ts.map +1 -0
  67. package/src/shade/playground/particle_ecs/moonlit_environment.js +144 -0
  68. package/src/shade/playground/particle_editor/README.md +5 -4
  69. package/src/shade/playground/profile_hotkey.d.ts +58 -0
  70. package/src/shade/playground/profile_hotkey.d.ts.map +1 -0
  71. package/src/shade/playground/profile_hotkey.js +325 -0
  72. package/src/shade/playground/ssr_variance/README.md +105 -0
  73. package/src/shade/playground/ssr_variance/capture.d.ts +16 -0
  74. package/src/shade/playground/ssr_variance/capture.d.ts.map +1 -0
  75. package/src/shade/playground/ssr_variance/capture.js +96 -0
  76. package/src/shade/playground/ssr_variance/index.html +22 -0
  77. package/src/shade/playground/ssr_variance/main.d.ts +2 -0
  78. package/src/shade/playground/ssr_variance/main.d.ts.map +1 -0
  79. package/src/shade/playground/ssr_variance/main.js +246 -0
  80. package/src/shade/playground/ssr_variance/reference.d.ts +18 -0
  81. package/src/shade/playground/ssr_variance/reference.d.ts.map +1 -0
  82. package/src/shade/playground/ssr_variance/reference.js +78 -0
  83. package/src/shade/playground/ssr_variance/scene.d.ts +11 -0
  84. package/src/shade/playground/ssr_variance/scene.d.ts.map +1 -0
  85. package/src/shade/playground/ssr_variance/scene.js +61 -0
  86. package/src/shade/playground/ssr_variance/statistics.d.ts +44 -0
  87. package/src/shade/playground/ssr_variance/statistics.d.ts.map +1 -0
  88. package/src/shade/playground/ssr_variance/statistics.js +51 -0
  89. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts.map +1 -1
  90. package/src/shade/renderer/loader/gltf/tiny-gltf.js +9 -3
  91. package/src/shade/renderer/loader/usd/usd_decode_image.d.ts +4 -4
  92. package/src/shade/renderer/loader/usd/usd_decode_image.d.ts.map +1 -1
  93. package/src/shade/renderer/loader/usd/usd_decode_image.js +4 -4
  94. package/src/shade/renderer/particles/DESIGN.md +748 -703
  95. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +11 -4
  96. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  97. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +431 -424
  98. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  99. package/src/shade/renderer/postprocess/ssr/SSR.js +2 -1
  100. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts.map +1 -1
  101. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js +0 -6
  102. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts.map +1 -1
  103. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.js +19 -5
  104. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts +4 -0
  105. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -0
  106. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +133 -0
  107. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +0 -8
  108. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
  109. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +16 -113
  110. package/src/shade/renderer/texture/source/texel_data_from_ktx2.d.ts +2 -2
  111. package/src/shade/renderer/texture/source/texel_data_from_ktx2.d.ts.map +1 -1
  112. package/src/shade/renderer/texture/source/texel_data_from_ktx2.js +3 -3
  113. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts +0 -20
  114. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts.map +0 -1
  115. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.d.ts +0 -14
  116. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.d.ts.map +0 -1
  117. package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts +0 -50
  118. package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts.map +0 -1
  119. package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts +0 -17
  120. package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts.map +0 -1
@@ -347,11 +347,13 @@ function align(graph, layer_count, order, rank, layer_start, neighbours, marked,
347
347
  * Push the blocks of one pass as far towards the top as the boxes below them allow, and read off a
348
348
  * coordinate for every box.
349
349
  *
350
- * Blocks are placed by longest path through the constraints between neighbours in a column, which
351
- * is what makes the arrangement as tight as the ordering permits. Blocks that turn out not to
352
- * constrain each other at all form separate classes, and a class is then shifted up until it meets
353
- * whatever is above it — without that, a block hanging off the bottom of the drawing pins every
354
- * class that follows it down there too.
350
+ * First place blocks relative to the sink of their class, then solve the separation constraints
351
+ * between classes. A class above another must carry that neighbour's final shift: treating a
352
+ * relative shift as absolute can move the lower class into the upper one. These constraints form
353
+ * a DAG, so a topological pass propagates every shift before the classes depending on it are placed.
354
+ * Both stages take linear time and preserve the port offsets within each block.
355
+ *
356
+ * @see https://arxiv.org/abs/2008.01252 — Brandes, Walter, Zink, correction to shift accumulation
355
357
  *
356
358
  * @param {LayoutBoxGraph} graph
357
359
  * @param {Int32Array} order
@@ -428,13 +430,7 @@ function compact(graph, order, rank, layer_start, block, options) {
428
430
  if (place[u] + need > place[v]) {
429
431
  place[v] = place[u] + need;
430
432
  }
431
- } else {
432
- const slack = place[v] - place[u] - need;
433
-
434
- if (slack < shift[sink[u]]) {
435
- shift[sink[u]] = slack;
436
- }
437
- }
433
+ }
438
434
  }
439
435
 
440
436
  w = next[w];
@@ -450,15 +446,62 @@ function compact(graph, order, rank, layer_start, block, options) {
450
446
  const y = new Float64Array(box_count);
451
447
 
452
448
  for (let box = 0; box < box_count; box++) {
453
- const r = root[box];
454
-
455
- y[box] = place[r] + offset[box];
456
-
457
- const carried = shift[sink[r]];
458
-
459
- if (carried < Infinity) {
460
- y[box] += carried;
461
- }
449
+ const r = root[box];
450
+
451
+ y[box] = place[r] + offset[box];
452
+ }
453
+
454
+ // Record every boundary between classes, directed from the lower class to the upper one.
455
+ // Use the position of the lower box in `order` as the edge index; its predecessor is `at - 1`.
456
+ // Parallel boundaries matter: different box heights and ports can make either one tighter.
457
+ const first_boundary = new Int32Array(box_count).fill(-1);
458
+ const next_boundary = new Int32Array(box_count);
459
+ const pending = new Int32Array(box_count);
460
+
461
+ for (let layer = 0; layer + 1 < layer_start.length; layer++) {
462
+ for (let at = layer_start[layer] + 1; at < layer_start[layer + 1]; at++) {
463
+ const upper = sink[root[order[at - 1]]];
464
+ const lower = sink[root[order[at]]];
465
+
466
+ if (upper !== lower) {
467
+ next_boundary[at] = first_boundary[lower];
468
+ first_boundary[lower] = at;
469
+ pending[upper]++;
470
+ }
471
+ }
472
+ }
473
+
474
+ const ready = new Int32Array(box_count);
475
+ let end = 0;
476
+
477
+ for (let box = 0; box < box_count; box++) {
478
+ if (root[box] === box && sink[box] === box && pending[box] === 0) {
479
+ shift[box] = 0;
480
+ ready[end++] = box;
481
+ }
482
+ }
483
+
484
+ for (let cursor = 0; cursor < end; cursor++) {
485
+ const lower = ready[cursor];
486
+
487
+ for (let at = first_boundary[lower]; at !== -1; at = next_boundary[at]) {
488
+ const above = order[at - 1];
489
+ const below = order[at];
490
+ const upper = sink[root[above]];
491
+
492
+ // y[above] + shift[upper] + separation <= y[below] + shift[lower]
493
+ const limit = shift[lower] + y[below] - y[above] - separation(above, below);
494
+
495
+ shift[upper] = Math.min(shift[upper], limit);
496
+
497
+ if (--pending[upper] === 0) {
498
+ ready[end++] = upper;
499
+ }
500
+ }
501
+ }
502
+
503
+ for (let box = 0; box < box_count; box++) {
504
+ y[box] += shift[sink[root[box]]];
462
505
  }
463
506
 
464
507
  return y;
@@ -471,7 +514,9 @@ function compact(graph, order, rank, layer_start, block, options) {
471
514
  * top edge, the ones biased towards the bottom by their bottom edge — against whichever of them
472
515
  * came out shortest. Only then can they be compared box by box, and each box takes the average of
473
516
  * the middle two of its four candidates: an average of all four is pulled about by whichever single
474
- * pass went furthest astray, and the middle two are the ones the passes agree on.
517
+ * pass went furthest astray, and the middle two are the ones the passes agree on.
518
+ * Each candidate must already satisfy every separation constraint. Taking the same order
519
+ * statistics for both ends of an inequality preserves it; balancing cannot repair an invalid pass.
475
520
  *
476
521
  * @param {LayoutBoxGraph} graph mutated: `box_y` is written
477
522
  * @param {Float64Array[]} candidates
@@ -1,32 +1,17 @@
1
1
  import { PNGReader } from "../../../../format/image/png/PNGReader.js";
2
2
 
3
- async function decode_png(png_bytes) {
4
- return new Promise((resolve, reject) => {
5
-
6
- const reader = new PNGReader(png_bytes);
7
-
8
- // console.time('decode');
9
- // console.profile('decode');
10
-
11
- const png = reader.parse();
12
-
13
- const uint_channels = png.getUint8Data();
14
-
15
- const width = png.getWidth();
16
- const height = png.getHeight();
17
-
18
- // console.timeEnd('decode');
19
- // console.profileEnd('decode');
20
-
21
- resolve({
22
- data: uint_channels.data.buffer,
23
- width,
24
- height,
25
- itemSize: uint_channels.itemSize,
26
- bitDepth: png.getBitDepth()
27
- });
28
- });
29
- }
3
+ async function decode_png(png_bytes) {
4
+ const png = await new PNGReader(png_bytes).parse();
5
+ const uint_channels = png.getUint8Data();
6
+
7
+ return {
8
+ data: uint_channels.data.buffer,
9
+ width: png.getWidth(),
10
+ height: png.getHeight(),
11
+ itemSize: uint_channels.itemSize,
12
+ bitDepth: png.getBitDepth()
13
+ };
14
+ }
30
15
 
31
16
  /**
32
17
  *
@@ -16,22 +16,23 @@ const array_loader = new ArrayBufferLoader();
16
16
  // const path = 'data/textures/utility/vt/uv_map_reference/5-21-14.png';
17
17
  const path = 'data/textures/utility/vt/uv_map_reference/6-39-33.png';
18
18
 
19
- array_loader.load(new AssetRequestScope(), path, (asset) => {
19
+ array_loader.load(new AssetRequestScope(), path, (asset) => {
20
20
 
21
21
  const array = asset.create();
22
22
 
23
23
  const reader = new PNGReader(array);
24
24
 
25
- const png = reader.parse();
25
+ reader.parse().then(png => {
26
26
 
27
- console.log(png);
27
+ console.log(png);
28
28
 
29
- const uint8Data = png.getUint8Data();
29
+ const uint8Data = png.getUint8Data();
30
30
 
31
- const sampler = new Sampler2D(uint8Data.data, uint8Data.itemSize, png.getWidth(), png.getHeight());
31
+ const sampler = new Sampler2D(uint8Data.data, uint8Data.itemSize, png.getWidth(), png.getHeight());
32
32
 
33
- const canvas = sampler2D2Canvas(sampler, 1, 0);
33
+ const canvas = sampler2D2Canvas(sampler, 1, 0);
34
34
 
35
- document.body.appendChild(canvas);
35
+ document.body.appendChild(canvas);
36
+ }).catch(error => console.error('Failed to decode PNG', error));
36
37
 
37
38
  });
@@ -1 +1 @@
1
- {"version":3,"file":"populateEngineSerializationRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/storage/populateEngineSerializationRegistry.js"],"names":[],"mappings":"AAmLA;;;;;;;;GAQG;AACH,iGA2GC"}
1
+ {"version":3,"file":"populateEngineSerializationRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/storage/populateEngineSerializationRegistry.js"],"names":[],"mappings":"AAsLA;;;;;;;;GAQG;AACH,iGA4GC"}
@@ -45,6 +45,9 @@ import {
45
45
  } from "../../graphics3/VolumetricLightMapSerializationAdapter.js";
46
46
  import { Transform } from "../transform/Transform.js";
47
47
  import { Transform64SerializationAdapter } from "../transform/Transform64SerializationAdapter.js";
48
+ import {
49
+ ParticleEffectSerializationAdapter
50
+ } from "../../graphics/ecs/particles/ParticleEffectSerializationAdapter.js";
48
51
  import { TransformSerializationAdapter } from "../transform/TransformSerializationAdapter.js";
49
52
  import { TransformSerializationUpgrader_0_1 } from "../transform/TransformSerializationUpgrader_0_1.js";
50
53
  import {
@@ -206,6 +209,7 @@ export function populateEngineSerializationRegistry(registry) {
206
209
  new PathSerializationAdapter(),
207
210
  new TagSerializationAdapter(),
208
211
  new ParticleEmitterSerializationAdapter(),
212
+ new ParticleEffectSerializationAdapter(),
209
213
  new SoundEmitterSerializationAdapter(),
210
214
  new SoundControllerSerializationAdapter(),
211
215
  new SoundListenerSerializationAdapter(),
@@ -0,0 +1,266 @@
1
+ /**
2
+ * What an entity emits. Paired with a {@link ../../../ecs/transform/Transform64.js Transform64},
3
+ * which says where, this is the whole of an emitter in the ECS:
4
+ *
5
+ * ```js
6
+ * new Entity()
7
+ * .add(new Transform64())
8
+ * .add(ParticleEffect.from({ ...create_particle_effect({ layout, init, update }), spawn_rate: 400 }))
9
+ * .build(dataset);
10
+ * ```
11
+ *
12
+ * {@link ../../../graphics3/GPUParticleEmitterSystem.js GPUParticleEmitterSystem} is what turns the
13
+ * pair into particles: it gives the entity a
14
+ * {@link ../../../../shade/renderer/particles/runtime/ParticleEmitter.js ParticleEmitter} node in
15
+ * the scene it owns, keeps that node where the transform says, packs {@link texture} into the
16
+ * scene's sprite atlas, and follows every field below. Nothing here reaches a device by itself, and
17
+ * an entity carrying one of these with no such system in the profile simply emits nothing.
18
+ *
19
+ * ## It is a description, and only a description
20
+ *
21
+ * Everything on it means the same thing with no renderer present: the attribute {@link layout} and
22
+ * the compiled {@link program} that make up an effect, the {@link texture} to draw with, the rate,
23
+ * the pre-warm, the blend / projection / feature {@link flags}, the render-attribute bindings and
24
+ * the flipbook grid. That is deliberate, and it is what makes the component the unit an editor
25
+ * inspects, a prefab carries and a system diffs.
26
+ *
27
+ * What is **not** here: the scene node the system built, the emitter's row in the GPU emitter table,
28
+ * the generation of that row, where the program was placed in the program heap, and where the
29
+ * texture landed in the atlas. All of that belongs to whoever registered the emitter — see
30
+ * {@link ../../../../shade/renderer/particles/runtime/GPUParticleEmitterContext.js} — and none of it
31
+ * survives a device restart, which is exactly why it is not on a component that does.
32
+ *
33
+ * There are no bounds here either. An emitter's particles are moved by arbitrary bytecode, so the
34
+ * box is **measured** from the live particles by a GPU pass at the end of every frame rather than
35
+ * authored; the one authored part of it is whether this effect opts into culling at all
36
+ * (`cull` in {@link flags}).
37
+ *
38
+ * ## Sharing
39
+ *
40
+ * {@link layout} and {@link program} are immutable once compiled and are meant to be shared: fifty
41
+ * campfires hold fifty components pointing at one compiled effect, which is what puts them on one id
42
+ * in the program heap and therefore in one simulation bucket. {@link copy} shares them rather than
43
+ * duplicating them for that reason.
44
+ *
45
+ * ## Changing one
46
+ *
47
+ * Assign to the fields. The system compares what it holds against what it last wrote to the scene
48
+ * node, once per frame per entity, so there is no flag to set and no signal to fire — a component
49
+ * whose fields have not moved costs a run of comparisons and no upload. That is a deliberate trade
50
+ * against the observable-per-field shape the older components use: an effect has fifteen fields,
51
+ * gameplay writes them in bursts, and a row is restaged whole either way.
52
+ *
53
+ * ## Saving one
54
+ *
55
+ * {@link ./ParticleEffectSerializationAdapter.js} writes all of it, the compiled program included.
56
+ * The VM's instruction set is a durable format by design — fixed-width opcodes and a constant pool —
57
+ * so a level carries the bytecode the way it carries a mesh's indices, and a shipped build needs
58
+ * neither the graph the effect was compiled from nor a compiler at runtime. Authoring belongs to an
59
+ * editor.
60
+ *
61
+ * Two things are consequently wire format: the opcode numbers, and the **order** of the attributes
62
+ * in {@link layout}, because the offsets in the render bindings are assigned from that order.
63
+ */
64
+ export class ParticleEffect {
65
+ /**
66
+ * Build a component from a plain description. Every field is optional — a component with no
67
+ * effect is a placeholder waiting for one — so an effect goes in by spreading what
68
+ * {@link ../../../../shade/renderer/particles/runtime/create_particle_effect.js create_particle_effect}
69
+ * returns: `ParticleEffect.from({ ...effect, spawn_rate: 100 })`.
70
+ *
71
+ * @param {object} [config]
72
+ * @param {import("../../../../shade/renderer/particles/layout/ParticleLayout.js").ParticleLayout} [config.layout]
73
+ * @param {import("../../../../shade/renderer/particles/isa/ParticleProgram.js").ParticleProgram} [config.program]
74
+ * @param {string|null} [config.texture] image URL to draw with
75
+ * @param {number} [config.seed]
76
+ * @param {number} [config.spawn_rate] particles/second
77
+ * @param {boolean} [config.emitting]
78
+ * @param {number} [config.prewarm] seconds of emission to run forward before the first frame
79
+ * @param {object} [config.flags] passed to `make_emitter_flags`
80
+ * @param {Object<string,string>} [config.render] render channel -> attribute name
81
+ * @param {ArrayLike<number>} [config.flipbook] `[columns, rows]`
82
+ * @returns {ParticleEffect}
83
+ */
84
+ static from(config?: {
85
+ layout?: import("../../../../shade/renderer/particles/layout/ParticleLayout.js").ParticleLayout;
86
+ program?: import("../../../../shade/renderer/particles/isa/ParticleProgram.js").ParticleProgram;
87
+ texture?: string | null;
88
+ seed?: number;
89
+ spawn_rate?: number;
90
+ emitting?: boolean;
91
+ prewarm?: number;
92
+ flags?: object;
93
+ render?: {
94
+ [x: string]: string;
95
+ };
96
+ flipbook?: ArrayLike<number>;
97
+ }): ParticleEffect;
98
+ /**
99
+ * The per-particle attribute schema: which named attributes a particle of this effect has, how
100
+ * wide each is, and what word of the record it sits at.
101
+ *
102
+ * `null` until an effect is assigned. An entity whose component has none is linked and idle
103
+ * rather than an error — an effect that is still compiling or still loading is ordinary — and it
104
+ * starts emitting on the frame after both this and {@link program} are set.
105
+ *
106
+ * @type {import("../../../../shade/renderer/particles/layout/ParticleLayout.js").ParticleLayout|null}
107
+ */
108
+ layout: import("../../../../shade/renderer/particles/layout/ParticleLayout.js").ParticleLayout | null;
109
+ /**
110
+ * The compiled INIT/UPDATE bytecode run for every particle. Replace the immutable program to
111
+ * edit the effect; do not mutate its bytecode in place.
112
+ *
113
+ * @type {import("../../../../shade/renderer/particles/isa/ParticleProgram.js").ParticleProgram|null}
114
+ */
115
+ program: import("../../../../shade/renderer/particles/isa/ParticleProgram.js").ParticleProgram | null;
116
+ /**
117
+ * Image to draw the particles with, by URL, or `null` to draw against a single white texel — so
118
+ * an untextured effect is a flat quad of its own colour.
119
+ *
120
+ * The system loads this through `AssetManager` and packs it into the sprite atlas its scene
121
+ * shares, one patch per distinct URL however many entities name it. Where it lands is the
122
+ * system's answer and changes on every repack, without this component changing.
123
+ *
124
+ * @type {string|null}
125
+ */
126
+ texture: string | null;
127
+ /**
128
+ * Base RNG seed.
129
+ *
130
+ * Two entities running one program produce identical particles from identical seeds. `0` reads
131
+ * as "unset", and the emitter then takes its registration's generation instead, which no other
132
+ * live emitter shares — so leaving this alone is what makes fifty campfires burn differently.
133
+ *
134
+ * @type {number}
135
+ */
136
+ seed: number;
137
+ /**
138
+ * Continuous emission rate, particles per second. Integrated on the GPU; the CPU never counts
139
+ * particles.
140
+ *
141
+ * @type {number}
142
+ */
143
+ spawn_rate: number;
144
+ /**
145
+ * Whether the effect is currently emitting.
146
+ *
147
+ * Turning it off holds {@link spawn_rate} at zero without the caller having to remember what the
148
+ * rate was — which is the whole reason it exists, because "put the torch out and light it again"
149
+ * otherwise means every caller keeping a shadow copy of the number. Particles already alive are
150
+ * **not** killed: a fire that stops emitting burns down, which is what stopping a fire looks
151
+ * like. Kill them from the effect's own UPDATE program if an effect wants to vanish.
152
+ *
153
+ * @type {boolean}
154
+ */
155
+ emitting: boolean;
156
+ /**
157
+ * Seconds this effect is run forward before it is first shown, `0` for none.
158
+ *
159
+ * A continuous effect starts empty and grows into its steady state over one particle lifetime,
160
+ * in front of whoever is watching. Setting this to about the effect's particle lifetime means
161
+ * the population on the first visible frame is the one the emitter would have had by then —
162
+ * spawned, aged and thinned by its own program over that long.
163
+ *
164
+ * It is paid once, on the frame the emitter is registered, by a pipeline of its own that
165
+ * simulates a private population and moves the result into the scene. Longer costs a longer loop
166
+ * on that one frame and nothing after it.
167
+ *
168
+ * @type {number}
169
+ */
170
+ prewarm: number;
171
+ /**
172
+ * Packed feature / blend / projection bits — see
173
+ * {@link ../../../../shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js make_emitter_flags}.
174
+ *
175
+ * @type {number}
176
+ */
177
+ flags: number;
178
+ /**
179
+ * Flipbook grid: columns, rows, over whatever region {@link texture} was packed into. `[1, 1]`
180
+ * is a single frame.
181
+ *
182
+ * @type {Float32Array}
183
+ */
184
+ flipbook: Float32Array;
185
+ /** @type {number} record word offset of world position, or {@link EMITTER_ATTRIBUTE_ABSENT} */
186
+ render_position: number;
187
+ /** @type {number} record word offset of size */
188
+ render_size: number;
189
+ /** @type {number} record word offset of rgba colour */
190
+ render_color: number;
191
+ /** @type {number} record word offset of roll angle, radians */
192
+ render_rotation: number;
193
+ /** @type {number} record word offset of flipbook frame index */
194
+ render_frame: number;
195
+ /** @type {number} record word offset of velocity, read by the STRETCHED projection */
196
+ render_velocity: number;
197
+ /**
198
+ * The rate the emitter actually runs at: {@link spawn_rate} while {@link emitting}, and zero
199
+ * otherwise. What the system writes to the GPU record.
200
+ *
201
+ * @returns {number}
202
+ */
203
+ get effective_spawn_rate(): number;
204
+ /**
205
+ * Bind render channels to per-particle attributes of this effect, by attribute name.
206
+ *
207
+ * Channels left out of `channels` keep whatever they had; a channel that was never bound stays
208
+ * at {@link EMITTER_ATTRIBUTE_ABSENT}, which the passes read as "this effect has no such
209
+ * attribute" — the render pass substitutes a default and the sort pass treats the particle as
210
+ * being at the origin.
211
+ *
212
+ * Word offsets are stored rather than names because that is what the render and sort passes
213
+ * index a particle record with; resolving here is the only place a name is involved, which is
214
+ * also why this needs {@link layout} to have been set first.
215
+ *
216
+ * @param {Object<string,string>} channels channel name (see `EMITTER_RENDER_CHANNELS`) ->
217
+ * attribute name in this effect's layout
218
+ * @returns {ParticleEffect} this
219
+ */
220
+ bind_render(channels: {
221
+ [x: string]: string;
222
+ }): ParticleEffect;
223
+ /**
224
+ * Structural equality over everything the component *is*. Two components that compare equal
225
+ * describe one effect, and one emitter row would serve both.
226
+ *
227
+ * The compiled program compares by its own bytecode rather than by object identity, so two
228
+ * components separately compiled from one graph compare equal.
229
+ *
230
+ * @param {ParticleEffect} other
231
+ * @returns {boolean}
232
+ */
233
+ equals(other: ParticleEffect): boolean;
234
+ /**
235
+ * Hash over everything {@link equals} compares, in the same terms.
236
+ *
237
+ * @returns {number} int32
238
+ */
239
+ hash(): number;
240
+ /**
241
+ * Make this a copy of `other`: same effect, same settings.
242
+ *
243
+ * The layout and the compiled program are **shared** rather than duplicated — both are immutable
244
+ * once compiled, and sharing them is what puts two entities of one effect on one program id in
245
+ * the heap, hence in one simulation bucket.
246
+ *
247
+ * @param {ParticleEffect} other
248
+ * @returns {ParticleEffect} this
249
+ */
250
+ copy(other: ParticleEffect): ParticleEffect;
251
+ /**
252
+ * @returns {ParticleEffect}
253
+ */
254
+ clone(): ParticleEffect;
255
+ /**
256
+ * Enables a fast type check, without having to import the class separately.
257
+ *
258
+ * @readonly
259
+ * @type {boolean}
260
+ */
261
+ readonly isParticleEffect: boolean;
262
+ }
263
+ export namespace ParticleEffect {
264
+ let typeName: string;
265
+ }
266
+ //# sourceMappingURL=ParticleEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParticleEffect.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/particles/ParticleEffect.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH;IAoRI;;;;;;;;;;;;;;;;;;OAkBG;IACH;QAZ2G,MAAM,GAAtG,OAAO,+DAA+D,EAAE,cAAc;QACS,OAAO,GAAtG,OAAO,6DAA6D,EAAE,eAAe;QAChE,OAAO,GAA5B,MAAM,GAAC,IAAI;QACK,IAAI,GAApB,MAAM;QACU,UAAU,GAA1B,MAAM;QACW,QAAQ,GAAzB,OAAO;QACS,OAAO,GAAvB,MAAM;QACU,KAAK,GAArB,MAAM;QACyB,MAAM;gBAA9B,MAAM,GAAC,MAAM;;QACO,QAAQ,GAAnC,UAAU,MAAM,CAAC;QACf,cAAc,CA8C1B;IAjVD;;;;;;;;;OASG;IACH,QAFU,OAAO,+DAA+D,EAAE,cAAc,GAAC,IAAI,CAEvF;IAEd;;;;;OAKG;IACH,SAFU,OAAO,6DAA6D,EAAE,eAAe,GAAC,IAAI,CAErF;IAEf;;;;;;;;;OASG;IACH,SAFU,MAAM,GAAC,IAAI,CAEN;IAEf;;;;;;;;OAQG;IACH,MAFU,MAAM,CAEP;IAET;;;;;OAKG;IACH,YAFU,MAAM,CAED;IAEf;;;;;;;;;;OAUG;IACH,UAFU,OAAO,CAED;IAEhB;;;;;;;;;;;;;OAaG;IACH,SAFU,MAAM,CAEJ;IAEZ;;;;;OAKG;IACH,OAFU,MAAM,CAEN;IAEV;;;;;OAKG;IACH,UAFU,YAAY,CAEc;IAEpC,+FAA+F;IAC/F,iBADW,MAAM,CAC0B;IAC3C,gDAAgD;IAChD,aADW,MAAM,CACsB;IACvC,uDAAuD;IACvD,cADW,MAAM,CACuB;IACxC,+DAA+D;IAC/D,iBADW,MAAM,CAC0B;IAC3C,gEAAgE;IAChE,cADW,MAAM,CACuB;IACxC,sFAAsF;IACtF,iBADW,MAAM,CAC0B;IAE3C;;;;;OAKG;IACH,mCAEC;IAED;;;;;;;;;;;;;;;OAeG;IACH;YAJkB,MAAM,GAAC,MAAM;QAElB,cAAc,CAuC1B;IAED;;;;;;;;;OASG;IACH,cAHW,cAAc,GACZ,OAAO,CAsBnB;IAED;;;;OAIG;IACH,QAFa,MAAM,CAuBlB;IAED;;;;;;;;;OASG;IACH,YAHW,cAAc,GACZ,cAAc,CAuB1B;IAED;;OAEG;IACH,SAFa,cAAc,CAI1B;IAkGL;;;;;OAKG;IACH,2BAFU,OAAO,CAEwB;CAtCxC;;kBA4BS,MAAM"}