@woosh/meep-engine 3.31.0 → 3.33.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 (117) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/collection/table/RowFirstTable.d.ts +8 -0
  4. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  5. package/src/core/collection/table/RowFirstTable.js +40 -11
  6. package/src/engine/graphics/ecs/sprite/Sprite.d.ts +3 -0
  7. package/src/engine/graphics/ecs/sprite/Sprite.d.ts.map +1 -1
  8. package/src/engine/graphics/ecs/sprite/Sprite.js +3 -0
  9. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts +3 -0
  10. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  11. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +3 -0
  12. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/DebugDrawSystem.js +6 -2
  14. package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
  15. package/src/engine/graphics3/PathDisplaySystem.js +311 -307
  16. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  17. package/src/shade/RENDERER_CONTRACT.md +15 -2
  18. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +5 -0
  19. package/src/shade/device/ShadeGPUCommandContext.d.ts +15 -2
  20. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  21. package/src/shade/device/ShadeGPUCommandContext.js +154 -25
  22. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +20 -3
  23. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  24. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +21 -3
  25. package/src/shade/renderer/GraphicsContext.d.ts +20 -1
  26. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  27. package/src/shade/renderer/GraphicsContext.js +105 -52
  28. package/src/shade/renderer/Renderer.d.ts +19 -4
  29. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  30. package/src/shade/renderer/Renderer.js +113 -2
  31. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +10 -7
  32. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  33. package/src/shade/renderer/animation/GPUAnimationManager.js +147 -45
  34. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts +6 -5
  35. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts.map +1 -1
  36. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.js +241 -240
  37. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts +62 -2
  38. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts.map +1 -1
  39. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.js +306 -38
  40. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts +60 -0
  41. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts.map +1 -0
  42. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.js +202 -0
  43. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts +68 -0
  44. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts.map +1 -0
  45. package/src/shade/renderer/buffer/GPUUploadBlock.js +97 -0
  46. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +2 -1
  47. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -1
  48. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +19 -17
  49. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts +70 -0
  50. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts.map +1 -0
  51. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.js +257 -0
  52. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +20 -7
  53. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
  54. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +39 -41
  55. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts +6 -20
  56. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
  57. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +42 -36
  58. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +2 -1
  59. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -1
  60. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +4 -3
  61. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +4 -3
  62. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -1
  63. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +7 -4
  64. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +14 -15
  65. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -1
  66. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +49 -83
  67. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts +19 -3
  68. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
  69. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +26 -6
  70. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +2 -1
  71. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -1
  72. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +12 -6
  73. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +3 -2
  74. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -1
  75. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +21 -13
  76. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +5 -0
  77. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +19 -0
  79. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  80. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  81. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +3 -1
  82. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -1
  83. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +3 -1
  84. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
  85. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +134 -88
  86. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  87. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +57 -26
  88. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  89. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +28 -20
  90. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts +38 -0
  91. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts.map +1 -0
  92. package/src/shade/renderer/rasterize/graph_clear_raster_targets.js +105 -0
  93. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +20 -0
  94. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +1 -1
  95. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  96. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +21 -1
  97. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  98. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +12 -20
  99. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts +2 -1
  100. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts.map +1 -1
  101. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.js +15 -28
  102. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  103. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +8 -1
  104. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +0 -73
  105. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +0 -1
  106. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts +0 -59
  107. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +0 -1
  108. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +0 -22
  109. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +0 -1
  110. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts +0 -26
  111. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts.map +0 -1
  112. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts +0 -25
  113. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts.map +0 -1
  114. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts +0 -26
  115. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts.map +0 -1
  116. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts +0 -29
  117. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts.map +0 -1
@@ -24,17 +24,27 @@ export class GPUDynamicMeshRenderer {
24
24
  * Set before the first draw. Changing it later rebuilds the pipeline, which is cheap but not
25
25
  * free, and the whole batch moves together — this is a property of the pass, not of a mesh.
26
26
  *
27
+ * Solid content belongs at `FramePhase.AfterLighting`, with the depth {@link graph_draw} hands
28
+ * back published: transparency runs after that phase and tests against that depth, so glass in
29
+ * front of the batch covers it. At `AfterTransparency` the glass is already resolved, and the
30
+ * batch is drawn over it.
31
+ *
27
32
  * @type {boolean}
28
33
  */
29
34
  opaque: boolean;
30
35
  /**
31
36
  * Record the draws into `graph`, over the colour it is given.
32
37
  *
33
- * When {@link opaque} is set the pass writes the depth it is given. That write lands in the
34
- * same physical texture the handle names — a written handle is a renamed clone of one resource,
35
- * not a second one — so a later pass reading the handle the caller still holds sees the depth
36
- * this pass left. Only the colour is threaded back, because that is what an injected pass is
37
- * allowed to replace.
38
+ * **Both handles come back, and the caller publishes both** — into `SceneColor` and
39
+ * `ViewTextures` from an extension. The colour is always replaced. The depth is replaced when
40
+ * {@link opaque} is set, since the pass writes it; otherwise it comes back as it was given.
41
+ *
42
+ * A written handle is a renamed clone of the same texture, so a pass that goes on reading the
43
+ * depth handle it held before this draw is reading a version this pass has superseded.
44
+ * `FrameGraph.validate` refuses that, and the frame fails to compile in a development build.
45
+ * A stripped build reads the right contents only because passes run in the order they were
46
+ * recorded. So every reader of the scene depth after this draw has to be handed the new handle:
47
+ * depth of field, motion blur, the NSS upscaler, the next extension along.
38
48
  *
39
49
  * @param {object} args
40
50
  * @param {FrameGraph} args.graph
@@ -42,7 +52,7 @@ export class GPUDynamicMeshRenderer {
42
52
  * @param {number} args.color colour resource handle to draw over
43
53
  * @param {number} args.depth scene depth, written when {@link opaque} and otherwise only tested
44
54
  * @param {GPUBuffer} args.camera
45
- * @returns {number} the colour handle after the draws
55
+ * @returns {{color: number, depth: number}} the colour and depth handles after the draws
46
56
  */
47
57
  graph_draw({ graph, batch, color, depth, camera }: {
48
58
  graph: FrameGraph;
@@ -50,7 +60,10 @@ export class GPUDynamicMeshRenderer {
50
60
  color: number;
51
61
  depth: number;
52
62
  camera: GPUBuffer;
53
- }): number;
63
+ }): {
64
+ color: number;
65
+ depth: number;
66
+ };
54
67
  /**
55
68
  * Release the GPU buffers held for `geometry`. A dynamic mesh that is gone for good should say
56
69
  * so — residency deliberately survives removal from the batch, so nothing else will free it.
@@ -1 +1 @@
1
- {"version":3,"file":"GPUDynamicMeshRenderer.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH;IACI;;;;;;;;;;;;;;OAcG;IACH,QAFU,OAAO,CAEF;IAiBf;;;;;;;;;;;;;;;;OAgBG;IACH;QAP4B,KAAK;QACC,KAAK;QACf,KAAK,EAAlB,MAAM;QACO,KAAK,EAAlB,MAAM;QACU,MAAM;QACpB,MAAM,CAuBlB;IAqHD;;;;;;OAMG;IACH,6BAFa,OAAO,CAInB;IAED,gBAEC;;CACJ"}
1
+ {"version":3,"file":"GPUDynamicMeshRenderer.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;GAWG;AACH;IACI;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAFU,OAAO,CAEF;IA0Bf;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH;QAP4B,KAAK;QACC,KAAK;QACf,KAAK,EAAlB,MAAM;QACO,KAAK,EAAlB,MAAM;QACU,MAAM;QACpB;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CA0B1C;IA4FD;;;;;;OAMG;IACH,6BAFa,OAAO,CAInB;IAED,gBAEC;;CACJ"}
@@ -1,6 +1,7 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
  import { TextureViewDescriptor } from "../../descriptor/texture/TextureViewDescriptor.js";
3
3
  import { DEFAULT_DEPTH_TEXTURE_VIEW } from "../depth/DEFAULT_DEPTH_TEXTURE_VIEW.js";
4
+ import { GPUDynamicMeshDrawList } from "./GPUDynamicMeshDrawList.js";
4
5
  import { GPUDynamicMeshResidencyTable } from "./GPUDynamicMeshResidencyTable.js";
5
6
  import { create_dynamic_mesh_pipeline } from "./shader_dynamic_mesh.js";
6
7
 
@@ -30,6 +31,11 @@ export class GPUDynamicMeshRenderer {
30
31
  * Set before the first draw. Changing it later rebuilds the pipeline, which is cheap but not
31
32
  * free, and the whole batch moves together — this is a property of the pass, not of a mesh.
32
33
  *
34
+ * Solid content belongs at `FramePhase.AfterLighting`, with the depth {@link graph_draw} hands
35
+ * back published: transparency runs after that phase and tests against that depth, so glass in
36
+ * front of the batch covers it. At `AfterTransparency` the glass is already resolved, and the
37
+ * batch is drawn over it.
38
+ *
33
39
  * @type {boolean}
34
40
  */
35
41
  opaque = false;
@@ -39,6 +45,15 @@ export class GPUDynamicMeshRenderer {
39
45
  */
40
46
  #residency = new GPUDynamicMeshResidencyTable();
41
47
 
48
+ /**
49
+ * The draws of the frame being executed. Written, drawn and cleared within one pass callback, so
50
+ * one list serves every frame and every graph this renderer draws into, and holds nothing between
51
+ * them.
52
+ *
53
+ * @type {GPUDynamicMeshDrawList}
54
+ */
55
+ #draws = new GPUDynamicMeshDrawList();
56
+
42
57
  /**
43
58
  * @type {RenderPipelineDescriptor|null}
44
59
  */
@@ -52,11 +67,16 @@ export class GPUDynamicMeshRenderer {
52
67
  /**
53
68
  * Record the draws into `graph`, over the colour it is given.
54
69
  *
55
- * When {@link opaque} is set the pass writes the depth it is given. That write lands in the
56
- * same physical texture the handle names — a written handle is a renamed clone of one resource,
57
- * not a second one — so a later pass reading the handle the caller still holds sees the depth
58
- * this pass left. Only the colour is threaded back, because that is what an injected pass is
59
- * allowed to replace.
70
+ * **Both handles come back, and the caller publishes both** — into `SceneColor` and
71
+ * `ViewTextures` from an extension. The colour is always replaced. The depth is replaced when
72
+ * {@link opaque} is set, since the pass writes it; otherwise it comes back as it was given.
73
+ *
74
+ * A written handle is a renamed clone of the same texture, so a pass that goes on reading the
75
+ * depth handle it held before this draw is reading a version this pass has superseded.
76
+ * `FrameGraph.validate` refuses that, and the frame fails to compile in a development build.
77
+ * A stripped build reads the right contents only because passes run in the order they were
78
+ * recorded. So every reader of the scene depth after this draw has to be handed the new handle:
79
+ * depth of field, motion blur, the NSS upscaler, the next extension along.
60
80
  *
61
81
  * @param {object} args
62
82
  * @param {FrameGraph} args.graph
@@ -64,7 +84,7 @@ export class GPUDynamicMeshRenderer {
64
84
  * @param {number} args.color colour resource handle to draw over
65
85
  * @param {number} args.depth scene depth, written when {@link opaque} and otherwise only tested
66
86
  * @param {GPUBuffer} args.camera
67
- * @returns {number} the colour handle after the draws
87
+ * @returns {{color: number, depth: number}} the colour and depth handles after the draws
68
88
  */
69
89
  graph_draw({ graph, batch, color, depth, camera }) {
70
90
  assert.defined(graph, 'graph');
@@ -86,7 +106,10 @@ export class GPUDynamicMeshRenderer {
86
106
  data.depth = data.opaque ? pass.write(depth) : pass.read(depth);
87
107
  data.color = pass.write(pass.read(color));
88
108
 
89
- return data.color;
109
+ return {
110
+ color: data.color,
111
+ depth: data.depth,
112
+ };
90
113
  }
91
114
 
92
115
  /**
@@ -97,38 +120,16 @@ export class GPUDynamicMeshRenderer {
97
120
  * @param {GPUBuffer} camera
98
121
  */
99
122
  #execute(data, resources, context, batch, camera) {
100
- const meshes = batch.meshes;
101
- const count = meshes.length;
102
-
103
- if (count === 0) {
104
- return;
105
- }
106
-
107
123
  const encoder = context.encoder;
108
124
  const graphics = context.graphics;
109
125
 
110
- // Every per-draw resource is built first: staging a uniform records a copy onto the command
111
- // encoder, and the encoder is locked for as long as a render pass is open on it.
112
- const draws = [];
113
-
114
- for (let i = 0; i < count; i++) {
115
- const mesh = meshes[i];
116
-
117
- if (!mesh.visible) {
118
- continue;
119
- }
126
+ // Written before the pass is opened: the constants go up through copies recorded onto the
127
+ // command encoder, and the encoder is locked for as long as a render pass is open on it.
128
+ const draws = this.#draws;
120
129
 
121
- const residency = this.#residency.get(mesh.geometry);
130
+ draws.write(encoder, this.#residency, batch.meshes);
122
131
 
123
- if (residency === undefined || residency.index_count === 0) {
124
- // never uploaded, or empty
125
- continue;
126
- }
127
-
128
- draws.push({ residency, bindings: residency.create_bindings(encoder, mesh, camera) });
129
- }
130
-
131
- if (draws.length === 0) {
132
+ if (draws.count === 0) {
132
133
  return;
133
134
  }
134
135
 
@@ -146,8 +147,7 @@ export class GPUDynamicMeshRenderer {
146
147
  const render_pass = encoder.constructRenderPass({
147
148
  label: "Dynamic Mesh",
148
149
  pipeline,
149
- // Bind groups differ per mesh — each has its own vertex and index buffers — so they are
150
- // set per draw rather than once for the pass.
150
+ // The constants' group is set per chunk and the geometry's per draw, by the draws.
151
151
  bindings: [],
152
152
  colorAttachments: [{
153
153
  loadOp: "load",
@@ -171,13 +171,11 @@ export class GPUDynamicMeshRenderer {
171
171
  },
172
172
  });
173
173
 
174
- for (let i = 0; i < draws.length; i++) {
175
- const entry = draws[i];
176
-
177
- entry.residency.draw(render_pass, graphics, pipeline, entry.bindings);
178
- }
174
+ draws.draw(render_pass, graphics, pipeline, camera);
179
175
 
180
176
  render_pass.end();
177
+
178
+ draws.clear();
181
179
  }
182
180
 
183
181
  /**
@@ -25,29 +25,15 @@ export class GPUDynamicMeshResidency {
25
25
  */
26
26
  write(device: GPUDevice, staging: Float32Array, vertex_float_count: number, indices: Uint32Array): void;
27
27
  /**
28
- * Build this mesh's bind groups for the frame.
28
+ * Draw this geometry: bind its group and draw its indices as the one instance `slot`, which is
29
+ * the row of the constants the pass has bound that the draw reads (`GPUDynamicMeshDrawList`).
29
30
  *
30
- * **Must be called before the render pass is opened.** The per-draw constants are staged through
31
- * a transient buffer, and staging records a copy onto the command encoder — which WebGPU locks
32
- * for as long as a pass is open on it. Doing this lazily at draw time is the obvious shape and
33
- * an invalid one.
34
- *
35
- * The constants are transient because one mesh is one draw and its transform and colour are
36
- * expected to differ every frame, so there is nothing worth keeping between them.
37
- *
38
- * @param {ShadeGPUCommandContext} encoder
39
- * @param {DynamicMesh} mesh
40
- * @param {GPUBuffer} camera
41
- * @returns {Array} bind groups, for {@link draw}
42
- */
43
- create_bindings(encoder: ShadeGPUCommandContext, mesh: DynamicMesh, camera: GPUBuffer): any[];
44
- /**
45
- * @param {ShadeGPURenderPassEncoder} render_pass
31
+ * @param {ShadeGPURenderPassEncoder} render_pass running `pipeline`, with its constants' group set
46
32
  * @param {GraphicsContext} graphics
47
- * @param {RenderPipelineDescriptor} pipeline
48
- * @param {Array} bindings from {@link create_bindings}
33
+ * @param {RenderPipelineDescriptor} pipeline a dynamic-mesh pipeline
34
+ * @param {number} slot this draw's row in the bound chunk of constants
49
35
  */
50
- draw(render_pass: ShadeGPURenderPassEncoder, graphics: GraphicsContext, pipeline: RenderPipelineDescriptor, bindings: any[]): void;
36
+ draw(render_pass: ShadeGPURenderPassEncoder, graphics: GraphicsContext, pipeline: RenderPipelineDescriptor, slot: number): void;
51
37
  destroy(): void;
52
38
  #private;
53
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GPUDynamicMeshResidency.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/GPUDynamicMeshResidency.js"],"names":[],"mappings":"AAwBA;;;;;GAKG;AACH;IAuBI;;;;OAIG;IACH,aAFU,MAAM,CAEA;IAEhB;;;;OAIG;IACH,SAFU,MAAM,CAEH;IAEb;;;;;OAKG;IACH,kCAJW,YAAY,sBACZ,MAAM,WACN,WAAW,QAsDrB;IAED;;;;;;;;;;;;;;;OAeG;IACH,8FAYC;IAED;;;;;OAKG;IACH,mIAIC;IAED,gBAcC;;CACJ"}
1
+ {"version":3,"file":"GPUDynamicMeshResidency.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/GPUDynamicMeshResidency.js"],"names":[],"mappings":"AAyBA;;;;;GAKG;AACH;IAgCI;;;;OAIG;IACH,aAFU,MAAM,CAEA;IAEhB;;;;OAIG;IACH,SAFU,MAAM,CAEH;IAEb;;;;;OAKG;IACH,kCAJW,YAAY,sBACZ,MAAM,WACN,WAAW,QA2DrB;IAED;;;;;;;;OAQG;IACH,kHAFW,MAAM,QAsBhB;IAED,gBAgBC;;CACJ"}
@@ -1,5 +1,6 @@
1
1
  import { round_up } from "../../../core/math/round_up.js";
2
- import { DYNAMIC_MESH_DRAW_STRUCT, DYNAMIC_MESH_RESOURCES } from "./shader_dynamic_mesh.js";
2
+ import { BindGroupDescriptor } from "../binding/BindGroupDescriptor.js";
3
+ import { DYNAMIC_MESH_BIND_GROUP_GEOMETRY, DYNAMIC_MESH_RESOURCES } from "./shader_dynamic_mesh.js";
3
4
 
4
5
  /**
5
6
  * Growth factor for the vertex and index buffers.
@@ -51,6 +52,15 @@ export class GPUDynamicMeshResidency {
51
52
  */
52
53
  #indices_capacity = 0;
53
54
 
55
+ /**
56
+ * The group that binds {@link #vertices} and {@link #indices}, made on the first draw after they
57
+ * were allocated and kept until either is replaced: the geometry's buffers change far less often
58
+ * than their contents, so the group costs one creation per growth rather than a lookup per draw.
59
+ *
60
+ * @type {GPUBindGroup|null}
61
+ */
62
+ #bind_group = null;
63
+
54
64
  /**
55
65
  * How many indices to draw — the count from the last upload, not the buffer's capacity.
56
66
  *
@@ -86,6 +96,9 @@ export class GPUDynamicMeshResidency {
86
96
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
87
97
  label: "DynamicMesh/vertices",
88
98
  });
99
+
100
+ // names the buffer just destroyed
101
+ this.#bind_group = null;
89
102
  }
90
103
 
91
104
  if (this.#indices_capacity < index_bytes) {
@@ -99,6 +112,8 @@ export class GPUDynamicMeshResidency {
99
112
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
100
113
  label: "DynamicMesh/indices",
101
114
  });
115
+
116
+ this.#bind_group = null;
102
117
  }
103
118
 
104
119
  /*
@@ -126,48 +141,39 @@ export class GPUDynamicMeshResidency {
126
141
  }
127
142
 
128
143
  /**
129
- * Build this mesh's bind groups for the frame.
130
- *
131
- * **Must be called before the render pass is opened.** The per-draw constants are staged through
132
- * a transient buffer, and staging records a copy onto the command encoder — which WebGPU locks
133
- * for as long as a pass is open on it. Doing this lazily at draw time is the obvious shape and
134
- * an invalid one.
135
- *
136
- * The constants are transient because one mesh is one draw and its transform and colour are
137
- * expected to differ every frame, so there is nothing worth keeping between them.
144
+ * Draw this geometry: bind its group and draw its indices as the one instance `slot`, which is
145
+ * the row of the constants the pass has bound that the draw reads (`GPUDynamicMeshDrawList`).
138
146
  *
139
- * @param {ShadeGPUCommandContext} encoder
140
- * @param {DynamicMesh} mesh
141
- * @param {GPUBuffer} camera
142
- * @returns {Array} bind groups, for {@link draw}
143
- */
144
- create_bindings(encoder, mesh, camera) {
145
- const draw_buffer = encoder.allocateTransientValueBuffer(DYNAMIC_MESH_DRAW_STRUCT, {
146
- model: mesh.transform.matrix,
147
- color: mesh.color,
148
- });
149
-
150
- return DYNAMIC_MESH_RESOURCES.generateBindings({
151
- camera,
152
- draw: draw_buffer,
153
- vertices: this.#vertices,
154
- indices: this.#indices,
155
- }, encoder);
156
- }
157
-
158
- /**
159
- * @param {ShadeGPURenderPassEncoder} render_pass
147
+ * @param {ShadeGPURenderPassEncoder} render_pass running `pipeline`, with its constants' group set
160
148
  * @param {GraphicsContext} graphics
161
- * @param {RenderPipelineDescriptor} pipeline
162
- * @param {Array} bindings from {@link create_bindings}
149
+ * @param {RenderPipelineDescriptor} pipeline a dynamic-mesh pipeline
150
+ * @param {number} slot this draw's row in the bound chunk of constants
163
151
  */
164
- draw(render_pass, graphics, pipeline, bindings) {
165
- graphics.setPipelineBindings(render_pass, pipeline, bindings);
152
+ draw(render_pass, graphics, pipeline, slot) {
153
+ let group = this.#bind_group;
154
+
155
+ if (group === null) {
156
+ // every dynamic-mesh pipeline declares this group alike, so one made for any of them
157
+ // serves them all
158
+ group = graphics.bind_groups.create(BindGroupDescriptor.from(
159
+ pipeline.layout.bindGroupLayouts[DYNAMIC_MESH_BIND_GROUP_GEOMETRY],
160
+ DYNAMIC_MESH_RESOURCES.groups[DYNAMIC_MESH_BIND_GROUP_GEOMETRY].generateBindings({
161
+ vertices: this.#vertices,
162
+ indices: this.#indices,
163
+ })
164
+ ));
165
+
166
+ this.#bind_group = group;
167
+ }
168
+
169
+ render_pass.setBindGroup(DYNAMIC_MESH_BIND_GROUP_GEOMETRY, group);
166
170
 
167
- render_pass.draw(this.index_count);
171
+ render_pass.draw(this.index_count, 1, 0, slot);
168
172
  }
169
173
 
170
174
  destroy() {
175
+ this.#bind_group = null;
176
+
171
177
  if (this.#vertices !== null) {
172
178
  this.#vertices.destroy();
173
179
  this.#vertices = null;
@@ -15,7 +15,8 @@
15
15
  * nearly edge-on lands the extinction slices away from the ribbon. The draw has one sample, where a
16
16
  * fragment exists only if the centre is covered and the centroid is the centre.
17
17
  *
18
- * The enclosing shader binds the dynamic-mesh group (`DYNAMIC_MESH_RESOURCES`), `camera` included.
18
+ * The enclosing shader binds the dynamic-mesh groups (`DYNAMIC_MESH_RESOURCES`), `camera` included,
19
+ * and hands over `instance_index` as the draw's row, as for {@link chunk_dynamic_mesh_vertex}.
19
20
  *
20
21
  * @type {CodeChunk}
21
22
  */
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_dynamic_mesh_avboit_vertex.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,+CAFU,SAAS,CA0BjB;0BAhDwB,iCAAiC"}
1
+ {"version":3,"file":"chunk_dynamic_mesh_avboit_vertex.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,+CAFU,SAAS,CA0BjB;0BAjDwB,iCAAiC"}
@@ -18,7 +18,8 @@ import { chunk_dynamic_mesh_vertex } from "./chunk_dynamic_mesh_vertex.js";
18
18
  * nearly edge-on lands the extinction slices away from the ribbon. The draw has one sample, where a
19
19
  * fragment exists only if the centre is covered and the centroid is the centre.
20
20
  *
21
- * The enclosing shader binds the dynamic-mesh group (`DYNAMIC_MESH_RESOURCES`), `camera` included.
21
+ * The enclosing shader binds the dynamic-mesh groups (`DYNAMIC_MESH_RESOURCES`), `camera` included,
22
+ * and hands over `instance_index` as the draw's row, as for {@link chunk_dynamic_mesh_vertex}.
22
23
  *
23
24
  * @type {CodeChunk}
24
25
  */
@@ -31,8 +32,8 @@ struct DynamicMeshAVBOITVertexOut {
31
32
  @location(1) @interpolate(perspective, centroid) view_depth : f32,
32
33
  }
33
34
 
34
- fn dynamic_mesh_avboit_vertex(vertex_index : u32) -> DynamicMeshAVBOITVertexOut {
35
- let vertex = dynamic_mesh_vertex(vertex_index);
35
+ fn dynamic_mesh_avboit_vertex(vertex_index : u32, draw_index : u32) -> DynamicMeshAVBOITVertexOut {
36
+ let vertex = dynamic_mesh_vertex(vertex_index, draw_index);
36
37
 
37
38
  var out : DynamicMeshAVBOITVertexOut;
38
39
 
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * One vertex of a {@link DynamicMesh}, pulled from its storage buffers and carried into the world:
3
- * the index at `vertex_index`, the vertex it names, its position through the draw's `model` and its
4
- * colour multiplied by the draw's flat `color`.
3
+ * the index at `vertex_index`, the vertex it names, its position through its draw's `model` and its
4
+ * colour multiplied by its draw's flat `color`. The draw's constants are row `draw_index` of
5
+ * `draws`, which a draw names through its `first_instance` — pass `@builtin(instance_index)`.
5
6
  *
6
7
  * Vertices are pulled from storage rather than bound as vertex buffers, which is how the rest of the
7
8
  * engine reads geometry: one pipeline then serves every dynamic mesh, whatever it holds.
8
9
  *
9
- * The enclosing shader binds the dynamic-mesh group (`DYNAMIC_MESH_RESOURCES`) — `draw`,
10
+ * The enclosing shader binds the dynamic-mesh groups (`DYNAMIC_MESH_RESOURCES`) — `draws`,
10
11
  * `vertices` and `indices` under those names. Shared by every pipeline that draws a dynamic mesh —
11
12
  * the blended and opaque passes over the scene, and the AVBOIT splat and draw — so the one vertex
12
13
  * layout ({@link DYNAMIC_MESH_VERTEX_STRIDE}) is read in exactly one place.
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_dynamic_mesh_vertex.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;GAcG;AACH,wCAFU,SAAS,CAiCjB;0BArDwB,iCAAiC"}
1
+ {"version":3,"file":"chunk_dynamic_mesh_vertex.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;GAeG;AACH,wCAFU,SAAS,CAmCjB;0BAxDwB,iCAAiC"}
@@ -7,13 +7,14 @@ import {
7
7
 
8
8
  /**
9
9
  * One vertex of a {@link DynamicMesh}, pulled from its storage buffers and carried into the world:
10
- * the index at `vertex_index`, the vertex it names, its position through the draw's `model` and its
11
- * colour multiplied by the draw's flat `color`.
10
+ * the index at `vertex_index`, the vertex it names, its position through its draw's `model` and its
11
+ * colour multiplied by its draw's flat `color`. The draw's constants are row `draw_index` of
12
+ * `draws`, which a draw names through its `first_instance` — pass `@builtin(instance_index)`.
12
13
  *
13
14
  * Vertices are pulled from storage rather than bound as vertex buffers, which is how the rest of the
14
15
  * engine reads geometry: one pipeline then serves every dynamic mesh, whatever it holds.
15
16
  *
16
- * The enclosing shader binds the dynamic-mesh group (`DYNAMIC_MESH_RESOURCES`) — `draw`,
17
+ * The enclosing shader binds the dynamic-mesh groups (`DYNAMIC_MESH_RESOURCES`) — `draws`,
17
18
  * `vertices` and `indices` under those names. Shared by every pipeline that draws a dynamic mesh —
18
19
  * the blended and opaque passes over the scene, and the AVBOIT splat and draw — so the one vertex
19
20
  * layout ({@link DYNAMIC_MESH_VERTEX_STRIDE}) is read in exactly one place.
@@ -32,7 +33,9 @@ struct DynamicMeshVertex {
32
33
  color : vec4<f32>,
33
34
  }
34
35
 
35
- fn dynamic_mesh_vertex(vertex_index : u32) -> DynamicMeshVertex {
36
+ fn dynamic_mesh_vertex(vertex_index : u32, draw_index : u32) -> DynamicMeshVertex {
37
+ let draw = draws[draw_index];
38
+
36
39
  let base = indices[vertex_index] * DYNAMIC_MESH_VERTEX_STRIDE;
37
40
 
38
41
  let position = vec3<f32>(
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Upload the live meshes, then mark the depth slices their world boxes span
2
+ * Upload the live meshes and write their draws, then mark the depth slices their world boxes span
3
3
  * (`shader_dynamic_mesh_avboit_occupancy`).
4
4
  *
5
- * **This is the pass that brings the vertices up to date**, being the channel's first: the device is
6
- * only reachable at execution time, and the splat and the draw that read the buffers run later in the
7
- * same frame, behind the warp this pass's output feeds.
5
+ * **This is the pass that brings the vertices and the draws' constants up to date**, being the
6
+ * channel's first: the device is only reachable at execution time, and the splat and the draw that
7
+ * read them run later in the same frame, behind the warp this pass's output feeds.
8
8
  *
9
9
  * @param {object} params
10
10
  * @param {import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
@@ -14,9 +14,11 @@
14
14
  * @param {GPUDynamicMeshResidencyTable} params.residency
15
15
  * @param {DynamicMesh[]} params.meshes the live meshes, one box each
16
16
  * @param {Float32Array} params.boxes world boxes, {@link DYNAMIC_MESH_AVBOIT_BOX_FLOATS} floats per mesh
17
+ * @param {GPUDynamicMeshDrawList} params.draws the frame's draws, written here for the splat and the
18
+ * draw of the same frame
17
19
  * @returns {number} the occupancy handle after the write
18
20
  */
19
- export function graph_dynamic_mesh_avboit_occupancy({ graph, camera, cluster_parameters, occupancy, residency, meshes, boxes, }: {
21
+ export function graph_dynamic_mesh_avboit_occupancy({ graph, camera, cluster_parameters, occupancy, residency, meshes, boxes, draws, }: {
20
22
  graph: import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
21
23
  camera: number;
22
24
  cluster_parameters: ArrayLike<number>;
@@ -24,6 +26,7 @@ export function graph_dynamic_mesh_avboit_occupancy({ graph, camera, cluster_par
24
26
  residency: GPUDynamicMeshResidencyTable;
25
27
  meshes: DynamicMesh[];
26
28
  boxes: Float32Array;
29
+ draws: GPUDynamicMeshDrawList;
27
30
  }): number;
28
31
  /**
29
32
  * Splat the live meshes' extinction into the voxel volume (`shader_dynamic_mesh_avboit_splat`).
@@ -38,11 +41,10 @@ export function graph_dynamic_mesh_avboit_occupancy({ graph, camera, cluster_par
38
41
  * @param {number} params.warp graph handle
39
42
  * @param {number[]} params.voxel_resolution the volume's width and height, which the raster is
40
43
  * @param {{extinction: number, overflow: number, dummy: number}} params.volume the volume, to add to
41
- * @param {GPUDynamicMeshResidencyTable} params.residency
42
- * @param {DynamicMesh[]} params.meshes the live meshes
44
+ * @param {GPUDynamicMeshDrawList} params.draws the frame's draws, as the occupancy wrote them
43
45
  * @returns {{extinction: number, overflow: number, dummy: number}} the volume after the write
44
46
  */
45
- export function graph_dynamic_mesh_avboit_splat({ graph, camera, warp, voxel_resolution, volume, residency, meshes, }: {
47
+ export function graph_dynamic_mesh_avboit_splat({ graph, camera, warp, voxel_resolution, volume, draws, }: {
46
48
  graph: import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
47
49
  camera: number;
48
50
  warp: number;
@@ -52,8 +54,7 @@ export function graph_dynamic_mesh_avboit_splat({ graph, camera, warp, voxel_res
52
54
  overflow: number;
53
55
  dummy: number;
54
56
  };
55
- residency: GPUDynamicMeshResidencyTable;
56
- meshes: DynamicMesh[];
57
+ draws: GPUDynamicMeshDrawList;
57
58
  }): {
58
59
  extinction: number;
59
60
  overflow: number;
@@ -72,11 +73,10 @@ export function graph_dynamic_mesh_avboit_splat({ graph, camera, warp, voxel_res
72
73
  * @param {number} params.volumetrics_lut graph handle
73
74
  * @param {number} params.volumetrics_metadata graph handle
74
75
  * @param {{color: number, norm: number, extinction: number, emission: number}} params.accumulators to add to
75
- * @param {GPUDynamicMeshResidencyTable} params.residency
76
- * @param {DynamicMesh[]} params.meshes the live meshes
76
+ * @param {GPUDynamicMeshDrawList} params.draws the frame's draws, as the occupancy wrote them
77
77
  * @returns {{color: number, norm: number, extinction: number, emission: number}} the accumulators after the draw
78
78
  */
79
- export function graph_dynamic_mesh_avboit_draw({ graph, view_ctx, camera, depth_texture, warp, integral, volumetrics_lut, volumetrics_metadata, accumulators, residency, meshes, }: {
79
+ export function graph_dynamic_mesh_avboit_draw({ graph, view_ctx, camera, depth_texture, warp, integral, volumetrics_lut, volumetrics_metadata, accumulators, draws, }: {
80
80
  graph: import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
81
81
  view_ctx: import("../view/GPUViewContext.js").GPUViewContext;
82
82
  camera: number;
@@ -91,8 +91,7 @@ export function graph_dynamic_mesh_avboit_draw({ graph, view_ctx, camera, depth_
91
91
  extinction: number;
92
92
  emission: number;
93
93
  };
94
- residency: GPUDynamicMeshResidencyTable;
95
- meshes: DynamicMesh[];
94
+ draws: GPUDynamicMeshDrawList;
96
95
  }): {
97
96
  color: number;
98
97
  norm: number;
@@ -1 +1 @@
1
- {"version":3,"file":"graph_dynamic_mesh_avboit.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js"],"names":[],"mappings":"AA2EA;;;;;;;;;;;;;;;;;GAiBG;AACH;IATkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IAC/D,MAAM,EAArB,MAAM;IACoB,kBAAkB,EAA5C,UAAU,MAAM,CAAC;IACF,SAAS,EAAxB,MAAM;IAC+B,SAAS;IACxB,MAAM,EAA5B,aAAa;IACQ,KAAK,EAA1B,YAAY;IACV,MAAM,CAqDlB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH;IATkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IAC/D,MAAM,EAArB,MAAM;IACS,IAAI,EAAnB,MAAM;IACW,gBAAgB,EAAjC,MAAM,EAAE;IACsD,MAAM,EAApE;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC;IAChB,SAAS;IACxB,MAAM,EAA5B,aAAa;IACX;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CA0FjE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH;IAbkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IACnB,QAAQ,EAAnE,OAAO,2BAA2B,EAAE,cAAc;IACnC,MAAM,EAArB,MAAM;IACS,aAAa,EAA5B,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,eAAe,EAA9B,MAAM;IACS,oBAAoB,EAAnC,MAAM;IACsE,YAAY,EAAxF;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC;IAC9B,SAAS;IACxB,MAAM,EAA5B,aAAa;IACX;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CA+F/E"}
1
+ {"version":3,"file":"graph_dynamic_mesh_avboit.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAXkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IAC/D,MAAM,EAArB,MAAM;IACoB,kBAAkB,EAA5C,UAAU,MAAM,CAAC;IACF,SAAS,EAAxB,MAAM;IAC+B,SAAS;IACxB,MAAM,EAA5B,aAAa;IACQ,KAAK,EAA1B,YAAY;IACmB,KAAK;IAElC,MAAM,CAwDlB;AAED;;;;;;;;;;;;;;;GAeG;AACH;IARkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IAC/D,MAAM,EAArB,MAAM;IACS,IAAI,EAAnB,MAAM;IACW,gBAAgB,EAAjC,MAAM,EAAE;IACsD,MAAM,EAApE;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC;IACtB,KAAK;IAClC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAuFjE;AAED;;;;;;;;;;;;;;;GAeG;AACH;IAZkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IACnB,QAAQ,EAAnE,OAAO,2BAA2B,EAAE,cAAc;IACnC,MAAM,EAArB,MAAM;IACS,aAAa,EAA5B,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,eAAe,EAA9B,MAAM;IACS,oBAAoB,EAAnC,MAAM;IACsE,YAAY,EAAxF;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC;IACpC,KAAK;IAClC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CA4F/E"}