@woosh/meep-engine 3.68.0 → 3.69.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 (190) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts +2 -17
  3. package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts.map +1 -1
  4. package/editor/ecs/component/editors/ecs/Trail3DEditor.js +3 -18
  5. package/package.json +1 -1
  6. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +33 -65
  7. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
  8. package/src/engine/graphics/ecs/trail3d/Trail3D.js +37 -245
  9. package/src/engine/graphics/ecs/trail3d/Trail3DFlags.d.ts +0 -4
  10. package/src/engine/graphics/ecs/trail3d/Trail3DFlags.js +4 -10
  11. package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.d.ts +13 -10
  12. package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.d.ts.map +1 -1
  13. package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.js +28 -37
  14. package/src/engine/graphics/ecs/trail3d/trail_knot_count.d.ts +10 -0
  15. package/src/engine/graphics/ecs/trail3d/trail_knot_count.d.ts.map +1 -0
  16. package/src/engine/graphics/ecs/trail3d/trail_knot_count.js +27 -0
  17. package/src/engine/graphics/trail/TrailKnots.d.ts +62 -0
  18. package/src/engine/graphics/trail/TrailKnots.d.ts.map +1 -0
  19. package/src/engine/graphics/trail/TrailKnots.js +137 -0
  20. package/src/engine/graphics/trail/tube/TubeXMaterialSpec.d.ts +1 -1
  21. package/src/engine/graphics/trail/tube/TubeXMaterialSpec.js +1 -1
  22. package/src/engine/graphics3/EntityRowHold.d.ts +48 -0
  23. package/src/engine/graphics3/EntityRowHold.d.ts.map +1 -0
  24. package/src/engine/graphics3/EntityRowHold.js +128 -0
  25. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +6 -2
  26. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  27. package/src/engine/graphics3/GPUParticleEmitterSystem.js +11 -44
  28. package/src/engine/graphics3/Trail3DSystem.d.ts +69 -35
  29. package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
  30. package/src/engine/graphics3/Trail3DSystem.js +380 -81
  31. package/src/engine/physics/fluid/ecs/FluidObstacle.d.ts +17 -0
  32. package/src/engine/physics/fluid/ecs/FluidObstacle.d.ts.map +1 -1
  33. package/src/engine/physics/fluid/ecs/FluidObstacle.js +22 -2
  34. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +6 -5
  35. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts.map +1 -1
  36. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +14 -3
  37. package/src/engine/physics/fluid/obstacle/FLUID_OBSTACLE_RECORD_STRUCT.d.ts +9 -1
  38. package/src/engine/physics/fluid/obstacle/FLUID_OBSTACLE_RECORD_STRUCT.d.ts.map +1 -1
  39. package/src/engine/physics/fluid/obstacle/FLUID_OBSTACLE_RECORD_STRUCT.js +11 -1
  40. package/src/engine/physics/fluid/obstacle/fluid_obstacle_record_create.d.ts +5 -0
  41. package/src/engine/physics/fluid/obstacle/fluid_obstacle_record_create.d.ts.map +1 -1
  42. package/src/engine/physics/fluid/obstacle/fluid_obstacle_record_create.js +2 -0
  43. package/src/engine/physics/fluid/obstacle/fluid_obstacle_write_gpu_record.d.ts +4 -3
  44. package/src/engine/physics/fluid/obstacle/fluid_obstacle_write_gpu_record.d.ts.map +1 -1
  45. package/src/engine/physics/fluid/obstacle/fluid_obstacle_write_gpu_record.js +11 -3
  46. package/src/shade/playground/trails/index.html +50 -0
  47. package/src/shade/playground/trails/main.d.ts +2 -0
  48. package/src/shade/playground/trails/main.d.ts.map +1 -0
  49. package/src/shade/playground/trails/main.js +258 -0
  50. package/src/shade/renderer/animation/animation_curve_write_keys.d.ts +18 -0
  51. package/src/shade/renderer/animation/animation_curve_write_keys.d.ts.map +1 -0
  52. package/src/shade/renderer/animation/animation_curve_write_keys.js +34 -0
  53. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts.map +1 -1
  54. package/src/shade/renderer/deferred/tonemap/ColorGrade.js +13 -36
  55. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +2 -2
  56. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +2 -13
  57. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -1
  58. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +6 -21
  59. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +17 -6
  60. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -1
  61. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +38 -178
  62. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +7 -9
  63. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -1
  64. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +17 -106
  65. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +7 -17
  66. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -1
  67. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +18 -118
  68. package/src/shade/renderer/fluid/forcing/FLUID_FORCING.d.ts +14 -0
  69. package/src/shade/renderer/fluid/forcing/FLUID_FORCING.d.ts.map +1 -1
  70. package/src/shade/renderer/fluid/forcing/FLUID_FORCING.js +18 -0
  71. package/src/shade/renderer/fluid/forcing/FLUID_FORCING_APPLY_STRUCT.d.ts +3 -1
  72. package/src/shade/renderer/fluid/forcing/FLUID_FORCING_APPLY_STRUCT.d.ts.map +1 -1
  73. package/src/shade/renderer/fluid/forcing/FLUID_FORCING_APPLY_STRUCT.js +4 -1
  74. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +9 -0
  75. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
  76. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +20 -4
  77. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_cell.d.ts +11 -2
  78. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_cell.d.ts.map +1 -1
  79. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_cell.js +59 -2
  80. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +4 -1
  81. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  82. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +367 -341
  83. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +6 -2
  84. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  85. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +339 -282
  86. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +3 -2
  87. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -1
  88. package/src/shade/renderer/grass/press/shader_grass_press_mark.js +5 -3
  89. package/src/shade/renderer/rasterize/native/avboit/avboit_unlit_draw.d.ts +49 -0
  90. package/src/shade/renderer/rasterize/native/avboit/avboit_unlit_draw.d.ts.map +1 -0
  91. package/src/shade/renderer/rasterize/native/avboit/avboit_unlit_draw.js +144 -0
  92. package/src/shade/renderer/rasterize/native/avboit/avboit_unlit_splat.d.ts +71 -0
  93. package/src/shade/renderer/rasterize/native/avboit/avboit_unlit_splat.d.ts.map +1 -0
  94. package/src/shade/renderer/rasterize/native/avboit/avboit_unlit_splat.js +152 -0
  95. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_unlit_varyings.d.ts +21 -0
  96. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_unlit_varyings.d.ts.map +1 -0
  97. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_unlit_varyings.js +30 -0
  98. package/src/shade/renderer/rasterize/native/avboit/graph_avboit_unlit.d.ts +101 -0
  99. package/src/shade/renderer/rasterize/native/avboit/graph_avboit_unlit.d.ts.map +1 -0
  100. package/src/shade/renderer/rasterize/native/avboit/graph_avboit_unlit.js +306 -0
  101. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts +9 -0
  102. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts.map +1 -1
  103. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +11 -4
  104. package/src/shade/renderer/trails/GPUTrailAVBOITChannel.d.ts +69 -0
  105. package/src/shade/renderer/trails/GPUTrailAVBOITChannel.d.ts.map +1 -0
  106. package/src/shade/renderer/trails/GPUTrailAVBOITChannel.js +129 -0
  107. package/src/shade/renderer/trails/GPUTrailSystem.d.ts +164 -0
  108. package/src/shade/renderer/trails/GPUTrailSystem.d.ts.map +1 -0
  109. package/src/shade/renderer/trails/GPUTrailSystem.js +725 -0
  110. package/src/shade/renderer/trails/data/TRAIL_DATABASE_SPEC.d.ts +14 -0
  111. package/src/shade/renderer/trails/data/TRAIL_DATABASE_SPEC.d.ts.map +1 -0
  112. package/src/shade/renderer/trails/data/TRAIL_DATABASE_SPEC.js +38 -0
  113. package/src/shade/renderer/trails/data/TRAIL_KNOT.d.ts +66 -0
  114. package/src/shade/renderer/trails/data/TRAIL_KNOT.d.ts.map +1 -0
  115. package/src/shade/renderer/trails/data/TRAIL_KNOT.js +154 -0
  116. package/src/shade/renderer/trails/data/TRAIL_RECORD.d.ts +19 -0
  117. package/src/shade/renderer/trails/data/TRAIL_RECORD.d.ts.map +1 -0
  118. package/src/shade/renderer/trails/data/TRAIL_RECORD.js +68 -0
  119. package/src/shade/renderer/trails/data/TRAIL_STATE.d.ts +18 -0
  120. package/src/shade/renderer/trails/data/TRAIL_STATE.d.ts.map +1 -0
  121. package/src/shade/renderer/trails/data/TRAIL_STATE.js +43 -0
  122. package/src/shade/renderer/trails/graph_trails.d.ts +58 -0
  123. package/src/shade/renderer/trails/graph_trails.d.ts.map +1 -0
  124. package/src/shade/renderer/trails/graph_trails.js +155 -0
  125. package/src/shade/renderer/trails/graph_trails_avboit.d.ts +126 -0
  126. package/src/shade/renderer/trails/graph_trails_avboit.d.ts.map +1 -0
  127. package/src/shade/renderer/trails/graph_trails_avboit.js +300 -0
  128. package/src/shade/renderer/trails/runtime/TrailFadeCurves.d.ts +56 -0
  129. package/src/shade/renderer/trails/runtime/TrailFadeCurves.d.ts.map +1 -0
  130. package/src/shade/renderer/trails/runtime/TrailFadeCurves.js +220 -0
  131. package/src/shade/renderer/trails/runtime/TrailKnotPool.d.ts +49 -0
  132. package/src/shade/renderer/trails/runtime/TrailKnotPool.d.ts.map +1 -0
  133. package/src/shade/renderer/trails/runtime/TrailKnotPool.js +162 -0
  134. package/src/shade/renderer/trails/runtime/TrailParameters.d.ts +52 -0
  135. package/src/shade/renderer/trails/runtime/TrailParameters.d.ts.map +1 -0
  136. package/src/shade/renderer/trails/runtime/TrailParameters.js +126 -0
  137. package/src/shade/renderer/trails/shaders/chunk_trail_frame_transport.d.ts +23 -0
  138. package/src/shade/renderer/trails/shaders/chunk_trail_frame_transport.d.ts.map +1 -0
  139. package/src/shade/renderer/trails/shaders/chunk_trail_frame_transport.js +57 -0
  140. package/src/shade/renderer/trails/shaders/chunk_trail_knot_alpha.d.ts +14 -0
  141. package/src/shade/renderer/trails/shaders/chunk_trail_knot_alpha.d.ts.map +1 -0
  142. package/src/shade/renderer/trails/shaders/chunk_trail_knot_alpha.js +40 -0
  143. package/src/shade/renderer/trails/shaders/chunk_trail_seed.d.ts +18 -0
  144. package/src/shade/renderer/trails/shaders/chunk_trail_seed.d.ts.map +1 -0
  145. package/src/shade/renderer/trails/shaders/chunk_trail_seed.js +64 -0
  146. package/src/shade/renderer/trails/shaders/chunk_trail_segment.d.ts +14 -0
  147. package/src/shade/renderer/trails/shaders/chunk_trail_segment.d.ts.map +1 -0
  148. package/src/shade/renderer/trails/shaders/chunk_trail_segment.js +51 -0
  149. package/src/shade/renderer/trails/shaders/chunk_trail_update.d.ts +48 -0
  150. package/src/shade/renderer/trails/shaders/chunk_trail_update.d.ts.map +1 -0
  151. package/src/shade/renderer/trails/shaders/chunk_trail_update.js +197 -0
  152. package/src/shade/renderer/trails/shaders/chunk_trail_vertex.d.ts +34 -0
  153. package/src/shade/renderer/trails/shaders/chunk_trail_vertex.d.ts.map +1 -0
  154. package/src/shade/renderer/trails/shaders/chunk_trail_vertex.js +111 -0
  155. package/src/shade/renderer/trails/shaders/shader_trail_avboit.d.ts +24 -0
  156. package/src/shade/renderer/trails/shaders/shader_trail_avboit.d.ts.map +1 -0
  157. package/src/shade/renderer/trails/shaders/shader_trail_avboit.js +78 -0
  158. package/src/shade/renderer/trails/shaders/shader_trail_avboit_segments.d.ts +23 -0
  159. package/src/shade/renderer/trails/shaders/shader_trail_avboit_segments.d.ts.map +1 -0
  160. package/src/shade/renderer/trails/shaders/shader_trail_avboit_segments.js +130 -0
  161. package/src/shade/renderer/trails/shaders/shader_trail_draw_args.d.ts +29 -0
  162. package/src/shade/renderer/trails/shaders/shader_trail_draw_args.d.ts.map +1 -0
  163. package/src/shade/renderer/trails/shaders/shader_trail_draw_args.js +78 -0
  164. package/src/shade/renderer/trails/shaders/shader_trail_seed.d.ts +18 -0
  165. package/src/shade/renderer/trails/shaders/shader_trail_seed.d.ts.map +1 -0
  166. package/src/shade/renderer/trails/shaders/shader_trail_seed.js +79 -0
  167. package/src/shade/renderer/trails/shaders/shader_trail_update.d.ts +20 -0
  168. package/src/shade/renderer/trails/shaders/shader_trail_update.d.ts.map +1 -0
  169. package/src/shade/renderer/trails/shaders/shader_trail_update.js +101 -0
  170. package/src/engine/graphics/ecs/trail3d/advance_trail.d.ts +0 -18
  171. package/src/engine/graphics/ecs/trail3d/advance_trail.d.ts.map +0 -1
  172. package/src/engine/graphics/ecs/trail3d/advance_trail.js +0 -42
  173. package/src/engine/graphics/ecs/trail3d/seed_trail_tube.d.ts +0 -14
  174. package/src/engine/graphics/ecs/trail3d/seed_trail_tube.d.ts.map +0 -1
  175. package/src/engine/graphics/ecs/trail3d/seed_trail_tube.js +0 -75
  176. package/src/engine/graphics/ecs/trail3d/trail_head_position.d.ts +0 -17
  177. package/src/engine/graphics/ecs/trail3d/trail_head_position.d.ts.map +0 -1
  178. package/src/engine/graphics/ecs/trail3d/trail_head_position.js +0 -19
  179. package/src/engine/graphics/trail/tube/TubeX.d.ts +0 -186
  180. package/src/engine/graphics/trail/tube/TubeX.d.ts.map +0 -1
  181. package/src/engine/graphics/trail/tube/TubeX.js +0 -575
  182. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts +0 -16
  183. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts.map +0 -1
  184. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.js +0 -34
  185. package/src/engine/graphics/trail/tube/tube_attributes_spec.d.ts +0 -27
  186. package/src/engine/graphics/trail/tube/tube_attributes_spec.d.ts.map +0 -1
  187. package/src/engine/graphics/trail/tube/tube_attributes_spec.js +0 -70
  188. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts +0 -38
  189. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +0 -1
  190. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +0 -119
@@ -0,0 +1,220 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { ALLOCATOR_NO_SPACE, OffsetAllocator } from "../../../../core/binary/allocator/OffsetAllocator.js";
3
+ import { HashMap } from "../../../../core/collection/map/HashMap.js";
4
+ import {
5
+ ANIMATION_CURVE_KEYFRAME_FLOATS,
6
+ animation_curve_write_keys
7
+ } from "../../animation/animation_curve_write_keys.js";
8
+
9
+ /**
10
+ * Keys the store starts with room for.
11
+ * @type {number}
12
+ */
13
+ const INITIAL_KEY_CAPACITY = 256;
14
+
15
+ /**
16
+ * A curve's place in the key buffer, shared by every trail that fades by an equal curve.
17
+ */
18
+ export class TrailFadeCurve {
19
+ /** @type {number} first key in the buffer */
20
+ first = 0;
21
+
22
+ /** @type {number} keys */
23
+ count = 0;
24
+
25
+ /** @type {number} trails holding it */
26
+ references = 0;
27
+
28
+ /** @type {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null} */
29
+ allocation = null;
30
+
31
+ /** @type {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve|null} the store's own copy */
32
+ curve = null;
33
+ }
34
+
35
+ /**
36
+ * The trails' fade curves on the GPU, one run of keys per distinct curve, in the layout
37
+ * `chunk_animation_curve_evaluate_keys` reads (`ANIMATION_CURVE_KEYFRAME_STRUCT`).
38
+ *
39
+ * A curve is the trails' class data, not theirs alone: every trail on the shared default fade, or on one
40
+ * curve a game hands out, reads one run. Curves are found by content — a curve that equals one held is
41
+ * that one — and kept by reference count, so the last trail to let go frees the run. The key is a copy,
42
+ * because a curve the caller holds can be edited in place.
43
+ *
44
+ * Nothing on the GPU writes the buffer, so it grows by replacement and the whole of it goes up again.
45
+ */
46
+ export class TrailFadeCurves {
47
+ /**
48
+ * @type {GPUDevice}
49
+ */
50
+ #device;
51
+
52
+ /**
53
+ * @type {OffsetAllocator}
54
+ */
55
+ #allocator = new OffsetAllocator(INITIAL_KEY_CAPACITY);
56
+
57
+ /**
58
+ * @type {Float32Array}
59
+ */
60
+ #keys = new Float32Array(INITIAL_KEY_CAPACITY * ANIMATION_CURVE_KEYFRAME_FLOATS);
61
+
62
+ /**
63
+ * @type {HashMap<import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve, TrailFadeCurve>}
64
+ */
65
+ #curves = new HashMap();
66
+
67
+ /**
68
+ * @type {GPUBuffer|null}
69
+ */
70
+ #buffer = null;
71
+
72
+ /**
73
+ * Whether the CPU keys have changed since they last went up.
74
+ * @type {boolean}
75
+ */
76
+ #dirty = true;
77
+
78
+ /**
79
+ * @param {GPUDevice} device
80
+ */
81
+ constructor(device) {
82
+ assert.defined(device, 'device');
83
+
84
+ this.#device = device;
85
+ }
86
+
87
+ /**
88
+ * @returns {number} distinct curves held
89
+ */
90
+ get count() {
91
+ return this.#curves.size;
92
+ }
93
+
94
+ /**
95
+ * The key buffer as the GPU should see it, uploaded first if anything changed.
96
+ *
97
+ * @returns {GPUBuffer}
98
+ */
99
+ flush() {
100
+ const keys = this.#keys;
101
+
102
+ if (this.#buffer !== null && this.#buffer.size !== keys.byteLength) {
103
+ this.#buffer.destroy();
104
+ this.#buffer = null;
105
+ }
106
+
107
+ if (this.#buffer === null) {
108
+ this.#buffer = this.#device.createBuffer({
109
+ label: "Trails / fade keys",
110
+ size: keys.byteLength,
111
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
112
+ });
113
+
114
+ this.#dirty = true;
115
+ }
116
+
117
+ if (this.#dirty) {
118
+ this.#device.queue.writeBuffer(this.#buffer, 0, keys.buffer, keys.byteOffset, keys.byteLength);
119
+ this.#dirty = false;
120
+ }
121
+
122
+ return this.#buffer;
123
+ }
124
+
125
+ /**
126
+ * Hold a curve equal to `curve`, placing its keys if none is held.
127
+ *
128
+ * @param {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve} curve at least one key
129
+ * @returns {TrailFadeCurve}
130
+ */
131
+ acquire(curve) {
132
+ assert.greaterThan(curve.keys.length, 0, 'a fade curve needs a key');
133
+
134
+ let held = this.#curves.get(curve);
135
+
136
+ if (held === undefined) {
137
+ held = this.#place(curve);
138
+ }
139
+
140
+ held.references++;
141
+
142
+ return held;
143
+ }
144
+
145
+ /**
146
+ * @param {TrailFadeCurve} held from {@link acquire}
147
+ */
148
+ release(held) {
149
+ assert.greaterThan(held.references, 0, 'released more often than acquired');
150
+
151
+ held.references--;
152
+
153
+ if (held.references > 0) {
154
+ return;
155
+ }
156
+
157
+ this.#curves.delete(held.curve);
158
+ this.#allocator.free(held.allocation);
159
+
160
+ held.allocation = null;
161
+ held.curve = null;
162
+ }
163
+
164
+ destroy() {
165
+ this.#buffer?.destroy();
166
+ this.#buffer = null;
167
+ this.#dirty = true;
168
+ }
169
+
170
+ /**
171
+ * @param {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve} curve
172
+ * @returns {TrailFadeCurve}
173
+ */
174
+ #place(curve) {
175
+ const count = curve.keys.length;
176
+
177
+ let allocation = this.#allocator.allocate(count);
178
+
179
+ if (allocation.offset === ALLOCATOR_NO_SPACE) {
180
+ this.#grow(count);
181
+
182
+ allocation = this.#allocator.allocate(count);
183
+
184
+ assert.notEqual(allocation.offset, ALLOCATOR_NO_SPACE, 'the fade key store grew and still has no room');
185
+ }
186
+
187
+ animation_curve_write_keys(this.#keys, allocation.offset * ANIMATION_CURVE_KEYFRAME_FLOATS, curve);
188
+
189
+ this.#dirty = true;
190
+
191
+ const held = new TrailFadeCurve();
192
+
193
+ held.first = allocation.offset;
194
+ held.count = count;
195
+ held.allocation = allocation;
196
+ held.curve = curve.clone();
197
+
198
+ this.#curves.set(held.curve, held);
199
+
200
+ return held;
201
+ }
202
+
203
+ /**
204
+ * @param {number} required keys of the curve that did not fit
205
+ */
206
+ #grow(required) {
207
+ const allocator = this.#allocator;
208
+
209
+ const size = Math.max(allocator.size * 2, allocator.grow_target_for(required));
210
+
211
+ allocator.grow(size);
212
+
213
+ const keys = new Float32Array(size * ANIMATION_CURVE_KEYFRAME_FLOATS);
214
+
215
+ keys.set(this.#keys);
216
+
217
+ this.#keys = keys;
218
+ this.#dirty = true;
219
+ }
220
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Every trail's knots, in one storage buffer: a run per trail, handed out by an {@link OffsetAllocator}
3
+ * in knots.
4
+ *
5
+ * The knots are the GPU's — seeded, committed and rewritten on the device — so the pool grows by copy:
6
+ * a larger buffer, the whole old one copied in at offset 0, and {@link OffsetAllocator#grow} appending
7
+ * the new tail as free space. No run moves, so every trail's `knot_base` stays what it was. Growth stops
8
+ * at the device's `maxBufferSize` and `maxStorageBufferBindingSize`; a run that cannot be housed past
9
+ * that is a failed {@link allocate}.
10
+ *
11
+ * Grows outside the frame: the copy is submitted on its own before the next frame records, and the old
12
+ * buffer is destroyed after that submission.
13
+ */
14
+ export class TrailKnotPool {
15
+ /**
16
+ * @param {GPUDevice} device
17
+ */
18
+ constructor(device: GPUDevice);
19
+ /**
20
+ * @returns {GPUBuffer}
21
+ */
22
+ get buffer(): GPUBuffer;
23
+ /**
24
+ * @returns {number} knots the pool has room for
25
+ */
26
+ get capacity(): number;
27
+ /**
28
+ * A run of `count` knots, growing the pool when it has no room.
29
+ *
30
+ * @param {number} count
31
+ * @returns {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation} its offset is in
32
+ * knots; a failed allocation's is `ALLOCATOR_NO_SPACE`
33
+ */
34
+ allocate(count: number): import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation;
35
+ /**
36
+ * @param {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation} allocation from {@link allocate}
37
+ */
38
+ free(allocation: import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation): void;
39
+ /**
40
+ * Write knots laid down on the CPU into the run starting at `knot_offset`.
41
+ *
42
+ * @param {number} knot_offset
43
+ * @param {Uint32Array} words whole knots, `TRAIL_KNOT_WORDS` apiece
44
+ */
45
+ write(knot_offset: number, words: Uint32Array): void;
46
+ destroy(): void;
47
+ #private;
48
+ }
49
+ //# sourceMappingURL=TrailKnotPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrailKnotPool.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/trails/runtime/TrailKnotPool.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;GAYG;AACH;IAgBI;;OAEG;IACH,+BAUC;IAED;;OAEG;IACH,wBAEC;IAED;;OAEG;IACH,uBAEC;IAED;;;;;;OAMG;IACH,gBAJW,MAAM,GACJ,OAAO,sDAAsD,EAAE,UAAU,CAerF;IAED;;OAEG;IACH,iBAFW,OAAO,sDAAsD,EAAE,UAAU,QAInF;IAED;;;;;OAKG;IACH,mBAHW,MAAM,SACN,WAAW,QASrB;IAED,gBAEC;;CAgDJ"}
@@ -0,0 +1,162 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { ALLOCATOR_NO_SPACE, OffsetAllocator } from "../../../../core/binary/allocator/OffsetAllocator.js";
3
+ import { TRAIL_KNOT_BYTES } from "../data/TRAIL_KNOT.js";
4
+
5
+ /**
6
+ * Knots the pool starts with room for.
7
+ * @type {number}
8
+ */
9
+ const INITIAL_KNOT_CAPACITY = 4096;
10
+
11
+ /**
12
+ * Every trail's knots, in one storage buffer: a run per trail, handed out by an {@link OffsetAllocator}
13
+ * in knots.
14
+ *
15
+ * The knots are the GPU's — seeded, committed and rewritten on the device — so the pool grows by copy:
16
+ * a larger buffer, the whole old one copied in at offset 0, and {@link OffsetAllocator#grow} appending
17
+ * the new tail as free space. No run moves, so every trail's `knot_base` stays what it was. Growth stops
18
+ * at the device's `maxBufferSize` and `maxStorageBufferBindingSize`; a run that cannot be housed past
19
+ * that is a failed {@link allocate}.
20
+ *
21
+ * Grows outside the frame: the copy is submitted on its own before the next frame records, and the old
22
+ * buffer is destroyed after that submission.
23
+ */
24
+ export class TrailKnotPool {
25
+ /**
26
+ * @type {GPUDevice}
27
+ */
28
+ #device;
29
+
30
+ /**
31
+ * @type {OffsetAllocator}
32
+ */
33
+ #allocator;
34
+
35
+ /**
36
+ * @type {GPUBuffer}
37
+ */
38
+ #buffer;
39
+
40
+ /**
41
+ * @param {GPUDevice} device
42
+ */
43
+ constructor(device) {
44
+ assert.defined(device, 'device');
45
+
46
+ this.#device = device;
47
+ this.#allocator = new OffsetAllocator(INITIAL_KNOT_CAPACITY);
48
+ this.#buffer = device.createBuffer({
49
+ label: "Trails / knots",
50
+ size: INITIAL_KNOT_CAPACITY * TRAIL_KNOT_BYTES,
51
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
52
+ });
53
+ }
54
+
55
+ /**
56
+ * @returns {GPUBuffer}
57
+ */
58
+ get buffer() {
59
+ return this.#buffer;
60
+ }
61
+
62
+ /**
63
+ * @returns {number} knots the pool has room for
64
+ */
65
+ get capacity() {
66
+ return this.#allocator.size;
67
+ }
68
+
69
+ /**
70
+ * A run of `count` knots, growing the pool when it has no room.
71
+ *
72
+ * @param {number} count
73
+ * @returns {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation} its offset is in
74
+ * knots; a failed allocation's is `ALLOCATOR_NO_SPACE`
75
+ */
76
+ allocate(count) {
77
+ assert.isPositiveInteger(count, 'count');
78
+
79
+ let allocation = this.#allocator.allocate(count);
80
+
81
+ if (allocation.offset === ALLOCATOR_NO_SPACE) {
82
+ this.#grow(count);
83
+
84
+ allocation = this.#allocator.allocate(count);
85
+ }
86
+
87
+ return allocation;
88
+ }
89
+
90
+ /**
91
+ * @param {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation} allocation from {@link allocate}
92
+ */
93
+ free(allocation) {
94
+ this.#allocator.free(allocation);
95
+ }
96
+
97
+ /**
98
+ * Write knots laid down on the CPU into the run starting at `knot_offset`.
99
+ *
100
+ * @param {number} knot_offset
101
+ * @param {Uint32Array} words whole knots, `TRAIL_KNOT_WORDS` apiece
102
+ */
103
+ write(knot_offset, words) {
104
+ assert.isNonNegativeInteger(knot_offset, 'knot_offset');
105
+
106
+ this.#device.queue.writeBuffer(
107
+ this.#buffer, knot_offset * TRAIL_KNOT_BYTES,
108
+ words.buffer, words.byteOffset, words.byteLength
109
+ );
110
+ }
111
+
112
+ destroy() {
113
+ this.#buffer.destroy();
114
+ }
115
+
116
+ /**
117
+ * @param {number} required knots of the run that did not fit
118
+ */
119
+ #grow(required) {
120
+ const device = this.#device;
121
+ const limits = device.limits;
122
+
123
+ const old_buffer = this.#buffer;
124
+ const old_size = old_buffer.size;
125
+
126
+ const ceiling_knots = Math.floor(
127
+ Math.min(limits.maxBufferSize, limits.maxStorageBufferBindingSize) / TRAIL_KNOT_BYTES
128
+ );
129
+
130
+ // the allocator's own answer for a run that size to land, doubled so a stream of short trails
131
+ // does not pay a copy of the whole pool apiece
132
+ const knots = Math.min(
133
+ Math.max(this.#allocator.size * 2, this.#allocator.grow_target_for(required)),
134
+ ceiling_knots
135
+ );
136
+
137
+ if (knots <= this.#allocator.size) {
138
+ // as large as this device allows
139
+ return;
140
+ }
141
+
142
+ const new_buffer = device.createBuffer({
143
+ label: old_buffer.label,
144
+ size: knots * TRAIL_KNOT_BYTES,
145
+ usage: old_buffer.usage,
146
+ });
147
+
148
+ // past the fallible part: OffsetAllocator#grow cannot be undone
149
+ this.#allocator.grow(knots);
150
+
151
+ const encoder = device.createCommandEncoder({ label: "Trails / knots / grow" });
152
+
153
+ // runs did not move, so the bytes land back under the bases the trails already hold
154
+ encoder.copyBufferToBuffer(old_buffer, 0, new_buffer, 0, old_size);
155
+
156
+ device.queue.submit([encoder.finish()]);
157
+
158
+ old_buffer.destroy();
159
+
160
+ this.#buffer = new_buffer;
161
+ }
162
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * What the GPU trail runtime is told about one trail: its look and its rules, as the CPU authors them.
3
+ * Plain data, compared field by field once a frame by whoever owns it, so a game can write a component
4
+ * field from code that has never heard of the renderer.
5
+ *
6
+ * `knot_count`, `radial` and `authored` are build-time: a change to any of them rebuilds the trail.
7
+ */
8
+ export class TrailParameters {
9
+ /** @type {number} knots in the ring, at least 2 */
10
+ knot_count: number;
11
+ /** @type {number} radial segments around the tube, at least 3 */
12
+ radial: number;
13
+ /** @type {number} seconds a knot takes to fade out */
14
+ max_age: number;
15
+ /** @type {number} tube diameter */
16
+ width: number;
17
+ /** @type {boolean} knots are committed by distance travelled rather than by time */
18
+ distance_mode: boolean;
19
+ /** @type {number} distance between commits in distance mode */
20
+ spawn_distance: number;
21
+ /** @type {boolean} the head follows the entity */
22
+ spawning: boolean;
23
+ /** @type {boolean} the trail fades in over its first `max_age` seconds */
24
+ warmup: boolean;
25
+ /** @type {Float32Array} linear RGB, unbounded, and base opacity */
26
+ color: Float32Array;
27
+ /** @type {Float32Array} the head's place in the entity's local frame */
28
+ offset: Float32Array;
29
+ /** @type {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve|null} opacity over a knot's life */
30
+ fade: import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve | null;
31
+ /** @type {import("../../../../engine/graphics/trail/TrailKnots.js").TrailKnots|null} knots laid down by the author, or null for a trail the entity draws */
32
+ authored: import("../../../../engine/graphics/trail/TrailKnots.js").TrailKnots | null;
33
+ /** @type {number} the {@link authored} version these parameters were taken at */
34
+ authored_version: number;
35
+ /**
36
+ * @param {TrailParameters} other
37
+ */
38
+ copy(other: TrailParameters): void;
39
+ /**
40
+ * Whether `other` would build the same trail: same knot count, radial count and authored layout.
41
+ *
42
+ * @param {TrailParameters} other
43
+ * @returns {boolean}
44
+ */
45
+ same_build(other: TrailParameters): boolean;
46
+ /**
47
+ * @param {TrailParameters} other
48
+ * @returns {boolean}
49
+ */
50
+ equals(other: TrailParameters): boolean;
51
+ }
52
+ //# sourceMappingURL=TrailParameters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrailParameters.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/trails/runtime/TrailParameters.js"],"names":[],"mappings":"AAeA;;;;;;GAMG;AACH;IACI,mDAAmD;IACnD,YADW,MAAM,CACF;IAEf,iEAAiE;IACjE,QADW,MAAM,CACN;IAEX,sDAAsD;IACtD,SADW,MAAM,CACL;IAEZ,mCAAmC;IACnC,OADW,MAAM,CACP;IAEV,oFAAoF;IACpF,eADW,OAAO,CACI;IAEtB,+DAA+D;IAC/D,gBADW,MAAM,CACE;IAEnB,kDAAkD;IAClD,UADW,OAAO,CACF;IAEhB,0EAA0E;IAC1E,QADW,OAAO,CACJ;IAEd,mEAAmE;IACnE,OADW,YAAY,CACgB;IAEvC,wEAAwE;IACxE,QADW,YAAY,CACM;IAE7B,4HAA4H;IAC5H,MADW,OAAO,sDAAsD,EAAE,cAAc,GAAC,IAAI,CACjF;IAEZ,4JAA4J;IAC5J,UADW,OAAO,iDAAiD,EAAE,UAAU,GAAC,IAAI,CACpE;IAEhB,iFAAiF;IACjF,kBADW,MAAM,CACK;IAEtB;;OAEG;IACH,YAFW,eAAe,QAwBzB;IAED;;;;;OAKG;IACH,kBAHW,eAAe,GACb,OAAO,CAOnB;IAED;;;OAGG;IACH,cAHW,eAAe,GACb,OAAO,CAoBnB;CACJ"}
@@ -0,0 +1,126 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+
3
+ /**
4
+ * @param {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve|null} a
5
+ * @param {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve|null} b
6
+ * @returns {boolean} whether the two give the same fade
7
+ */
8
+ function same_curve(a, b) {
9
+ if (a === b) {
10
+ return true;
11
+ }
12
+
13
+ return a !== null && b !== null && a.equals(b);
14
+ }
15
+
16
+ /**
17
+ * What the GPU trail runtime is told about one trail: its look and its rules, as the CPU authors them.
18
+ * Plain data, compared field by field once a frame by whoever owns it, so a game can write a component
19
+ * field from code that has never heard of the renderer.
20
+ *
21
+ * `knot_count`, `radial` and `authored` are build-time: a change to any of them rebuilds the trail.
22
+ */
23
+ export class TrailParameters {
24
+ /** @type {number} knots in the ring, at least 2 */
25
+ knot_count = 2;
26
+
27
+ /** @type {number} radial segments around the tube, at least 3 */
28
+ radial = 8;
29
+
30
+ /** @type {number} seconds a knot takes to fade out */
31
+ max_age = 5;
32
+
33
+ /** @type {number} tube diameter */
34
+ width = 1;
35
+
36
+ /** @type {boolean} knots are committed by distance travelled rather than by time */
37
+ distance_mode = false;
38
+
39
+ /** @type {number} distance between commits in distance mode */
40
+ spawn_distance = 1;
41
+
42
+ /** @type {boolean} the head follows the entity */
43
+ spawning = true;
44
+
45
+ /** @type {boolean} the trail fades in over its first `max_age` seconds */
46
+ warmup = true;
47
+
48
+ /** @type {Float32Array} linear RGB, unbounded, and base opacity */
49
+ color = new Float32Array([1, 1, 1, 1]);
50
+
51
+ /** @type {Float32Array} the head's place in the entity's local frame */
52
+ offset = new Float32Array(3);
53
+
54
+ /** @type {import("../../../../engine/animation/curve/AnimationCurve.js").AnimationCurve|null} opacity over a knot's life */
55
+ fade = null;
56
+
57
+ /** @type {import("../../../../engine/graphics/trail/TrailKnots.js").TrailKnots|null} knots laid down by the author, or null for a trail the entity draws */
58
+ authored = null;
59
+
60
+ /** @type {number} the {@link authored} version these parameters were taken at */
61
+ authored_version = -1;
62
+
63
+ /**
64
+ * @param {TrailParameters} other
65
+ */
66
+ copy(other) {
67
+ this.knot_count = other.knot_count;
68
+ this.radial = other.radial;
69
+ this.max_age = other.max_age;
70
+ this.width = other.width;
71
+ this.distance_mode = other.distance_mode;
72
+ this.spawn_distance = other.spawn_distance;
73
+ this.spawning = other.spawning;
74
+ this.warmup = other.warmup;
75
+ this.color.set(other.color);
76
+ this.offset.set(other.offset);
77
+
78
+ // a copy, not the curve: a curve can be edited in place, and a snapshot that shares it would
79
+ // never see the edit
80
+ if (other.fade === null) {
81
+ this.fade = null;
82
+ } else if (this.fade === null || !this.fade.equals(other.fade)) {
83
+ this.fade = other.fade.clone();
84
+ }
85
+
86
+ this.authored = other.authored;
87
+ this.authored_version = other.authored_version;
88
+ }
89
+
90
+ /**
91
+ * Whether `other` would build the same trail: same knot count, radial count and authored layout.
92
+ *
93
+ * @param {TrailParameters} other
94
+ * @returns {boolean}
95
+ */
96
+ same_build(other) {
97
+ return this.knot_count === other.knot_count
98
+ && this.radial === other.radial
99
+ && this.authored === other.authored
100
+ && this.authored_version === other.authored_version;
101
+ }
102
+
103
+ /**
104
+ * @param {TrailParameters} other
105
+ * @returns {boolean}
106
+ */
107
+ equals(other) {
108
+ assert.defined(other, 'other');
109
+
110
+ return this.same_build(other)
111
+ && this.max_age === other.max_age
112
+ && this.width === other.width
113
+ && this.distance_mode === other.distance_mode
114
+ && this.spawn_distance === other.spawn_distance
115
+ && this.spawning === other.spawning
116
+ && this.warmup === other.warmup
117
+ && this.color[0] === other.color[0]
118
+ && this.color[1] === other.color[1]
119
+ && this.color[2] === other.color[2]
120
+ && this.color[3] === other.color[3]
121
+ && this.offset[0] === other.offset[0]
122
+ && this.offset[1] === other.offset[1]
123
+ && this.offset[2] === other.offset[2]
124
+ && same_curve(this.fade, other.fade);
125
+ }
126
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Below this squared length the transported normal is degenerate — the previous normal was nearly
3
+ * parallel to the new tangent — and a fresh basis is built from the tangent instead.
4
+ * @type {number}
5
+ */
6
+ export const TRAIL_FRAME_DEGENERATE_EPSILON_SQR: number;
7
+ /**
8
+ * `trail_frame_transport(tangent, previous_normal) -> TrailFrame`: the rotation-minimising frame of a
9
+ * tube's ring, carried from the previous knot's normal onto the plane perpendicular to the unit
10
+ * `tangent` (Gram-Schmidt), with `binormal = tangent × normal`. The ring keeps its orientation as the
11
+ * tangent turns, with no twist.
12
+ *
13
+ * When the previous normal is (nearly) parallel to the tangent the projection collapses, and the frame
14
+ * is built from the tangent alone, by the construction `v3_orthonormal_matrix_from_normal` uses on the
15
+ * CPU, so both paths bootstrap the same frame.
16
+ *
17
+ * The same arithmetic as `tube_frame_transport`.
18
+ *
19
+ * @type {CodeChunk}
20
+ */
21
+ export const chunk_trail_frame_transport: CodeChunk;
22
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
23
+ //# sourceMappingURL=chunk_trail_frame_transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_trail_frame_transport.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/trails/shaders/chunk_trail_frame_transport.js"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,iDAFU,MAAM,CAEwC;AAExD;;;;;;;;;;;;;GAaG;AACH,0CAFU,SAAS,CAmCjB;0BAxDwB,oCAAoC"}