@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
@@ -1,22 +1,12 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import { FLOAT32_MAX } from "../../../../core/binary/FLOAT32_MAX.js";
3
- import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
4
1
  import { Color } from "../../../../core/color/Color.js";
5
2
  import Vector3 from "../../../../core/geom/Vector3.js";
6
- import { v3_distance } from "../../../../core/geom/vec3/v3_distance.js";
7
- import { v3_length } from "../../../../core/geom/vec3/v3_length.js";
8
- import { clamp01 } from "../../../../core/math/clamp01.js";
9
- import { EPSILON } from "../../../../core/math/EPSILON.js";
10
3
  import { AnimationCurve } from "../../../animation/curve/AnimationCurve.js";
11
4
  import { TrailSpawnMode } from "../../trail/TrailSpawnMode.js";
12
- import { TUBE_ATTRIBUTE_ADDRESS_AGE } from "../../trail/tube/tube_attributes_spec.js";
13
- import { tube_frame_transport } from "../../trail/tube/tube_frame.js";
14
- import { TubeX } from "../../trail/tube/TubeX.js";
15
5
  import { TubeXMaterialSpec } from "../../trail/tube/TubeXMaterialSpec.js";
16
6
  import { TRAIL3D_FADE_LINEAR } from "./TRAIL3D_FADE_LINEAR.js";
17
7
  import { Trail3DFlags } from "./Trail3DFlags.js";
18
8
 
19
- const DEFAULT_FLAGS = Trail3DFlags.Spawning | Trail3DFlags.Aging | Trail3DFlags.BoundsNeedUpdate;
9
+ const DEFAULT_FLAGS = Trail3DFlags.Spawning;
20
10
 
21
11
  const DEFAULT_MAX_AGE = 5;
22
12
 
@@ -26,22 +16,20 @@ const DEFAULT_RADIAL_SEGMENTS = 8;
26
16
 
27
17
  const DEFAULT_SPAWN_DISTANCE = 1;
28
18
 
29
- // module-static scratch — keeps updateHead allocation-free
30
- const v3_head_pos = new Float64Array(3);
31
- const v3_pred_pos = new Float64Array(3);
32
- const v3_pred_n = new Float64Array(3);
33
- const frame_out = new Float32Array(6);
34
-
35
19
  /**
36
- * Tube-based 3D trail — the volumetric counterpart of {@link Trail2D}. Where
37
- * Trail2D extrudes a screen-facing ribbon in the shader, Trail3D lays down a tube
38
- * of {@link TubeX} knots, each carrying a tangent frame so the ring can be
39
- * extruded around the centre-line in world space.
20
+ * A tube left behind an entity — the volumetric counterpart of {@link Trail2D}. The head follows the
21
+ * entity at {@link offset}; knots are laid down behind it as it travels, each with the frame its ring
22
+ * stands in, and fade by {@link fade} as they age towards {@link maxAge}.
23
+ *
24
+ * The component is the trail's description. Its knots live where {@link Trail3DSystem} simulates and
25
+ * draws them, on the GPU; a game writes these fields and the system picks the change up.
40
26
  */
41
27
  class Trail3D {
42
28
 
43
29
  /**
44
- * Age at which a trail knot disappears, in seconds.
30
+ * Age at which a trail knot disappears, in seconds. How many knots the trail holds is fixed when the
31
+ * system registers it: a later change moves the fade and how often a knot is laid down, not the
32
+ * length of the ring.
45
33
  * @type {number}
46
34
  */
47
35
  maxAge = DEFAULT_MAX_AGE;
@@ -53,8 +41,8 @@ class Trail3D {
53
41
  width = DEFAULT_WIDTH;
54
42
 
55
43
  /**
56
- * Number of radial subdivisions around the tube. Higher = rounder tube. This is
57
- * a build-time parameter; changing it after build has no effect until rebuilt.
44
+ * Number of radial subdivisions around the tube. Higher = rounder tube. Fixed when the system
45
+ * registers the trail; re-add the component to change it.
58
46
  * @type {number}
59
47
  */
60
48
  radialSegments = DEFAULT_RADIAL_SEGMENTS;
@@ -72,29 +60,6 @@ class Trail3D {
72
60
  */
73
61
  spawnDistance = DEFAULT_SPAWN_DISTANCE;
74
62
 
75
- /**
76
- * Current simulated time since trail birth.
77
- * @type {number}
78
- */
79
- time = 0;
80
-
81
- /**
82
- * @type {number}
83
- */
84
- trailingIndex = 0;
85
-
86
- /**
87
- * Time elapsed since the last knot was committed.
88
- * @type {number}
89
- */
90
- timeSinceLastUpdate = 0;
91
-
92
- /**
93
- * Distance the head has travelled since the last knot was committed.
94
- * @type {number}
95
- */
96
- distanceSinceLastUpdate = 0;
97
-
98
63
  /**
99
64
  * RGB tints the tube; alpha is the trail's base opacity, which {@link fade}
100
65
  * scales as each knot ages.
@@ -128,32 +93,32 @@ class Trail3D {
128
93
  offset = new Vector3();
129
94
 
130
95
  /**
131
- * transient
132
- * @type {TubeX|null}
96
+ * Whether a new trail fades in over its first {@link maxAge} seconds: its head is born
97
+ * `maxAge - t` old while the trail is `t` seconds old, so the stretch laid down first is the
98
+ * faintest. On by default; turn it off for a trail that must be fully visible from its first
99
+ * frame, a tracer.
100
+ * @type {boolean}
133
101
  */
134
- tube = null;
102
+ warmup = true;
135
103
 
136
104
  /**
137
- * What the legacy renderer draws this tube through — a three mesh over
138
- * {@link TubeXGeometry}'s views, built and owned by {@link Trail3DSystem}. The Shade path
139
- * leaves it null and builds a dynamic mesh of its own from the same knots.
140
- *
141
- * transient
142
- * @type {Mesh|null}
105
+ * Knots laid down whole by the author — a stroke, a helix — instead of by the entity's travel, or
106
+ * null for a trail the entity draws. See {@link TrailKnots}; {@link seed_trail_stroke} writes one.
107
+ * @type {import("../../trail/TrailKnots.js").TrailKnots|null}
143
108
  */
144
- mesh = null;
109
+ knots = null;
145
110
 
146
111
  /**
147
- * transient
148
- * @type {TubeXMaterialSpec}
112
+ * Moved by every {@link clear}, so the system sees the request by comparing it.
113
+ * @type {number}
149
114
  */
150
- material = new TubeXMaterialSpec();
115
+ clearCount = 0;
151
116
 
152
117
  /**
153
- * @readonly
154
- * @type {BvhClient}
118
+ * transient
119
+ * @type {TubeXMaterialSpec}
155
120
  */
156
- bvh = new BvhClient();
121
+ material = new TubeXMaterialSpec();
157
122
 
158
123
  /**
159
124
  * @private
@@ -161,24 +126,6 @@ class Trail3D {
161
126
  */
162
127
  flags = DEFAULT_FLAGS;
163
128
 
164
- dispose() {
165
- if (this.tube === null) {
166
- // nothing to dispose
167
- return;
168
- }
169
-
170
- this.tube = null;
171
-
172
- // The knots the drawable was a view over are gone, so the component must stop claiming to
173
- // be built: link() would otherwise take its "already built" branch, hang a material on the
174
- // dead mesh and leave the tube null, and the first update would hand that null to the
175
- // simulator. Dropping Built makes a re-link rebuild instead. Whatever a renderer made of
176
- // the tube is that renderer's to release; the material is owned by the tube plugin's
177
- // cache, so neither is ours to dispose — only to forget.
178
- this.mesh = null;
179
- this.clearFlag(Trail3DFlags.Built);
180
- }
181
-
182
129
  get textureURL() {
183
130
  return this.material.diffuse;
184
131
  }
@@ -206,8 +153,7 @@ class Trail3D {
206
153
  *
207
154
  * Stored in {@link Trail3DFlags.Lit}. This is a build-time option — it selects
208
155
  * the compiled material and the mesh's shadow settings — so it must be set
209
- * before the trail is built / registered with the system, and cannot change
210
- * afterwards.
156
+ * before the trail is registered with the system.
211
157
  *
212
158
  * @returns {boolean}
213
159
  */
@@ -219,12 +165,6 @@ class Trail3D {
219
165
  * @param {boolean} v
220
166
  */
221
167
  set lightingEnabled(v) {
222
- if (v === this.lightingEnabled) {
223
- return;
224
- }
225
-
226
- assert.notOk(this.getFlag(Trail3DFlags.Built), "lightingEnabled cannot change after the trail is built");
227
-
228
168
  this.writeFlag(Trail3DFlags.Lit, v);
229
169
  }
230
170
 
@@ -265,43 +205,12 @@ class Trail3D {
265
205
  }
266
206
 
267
207
  /**
268
- * Build the knots this trail lays down. What draws them is the registered renderer's system,
269
- * which builds its own representation over these rows — the component holds the trail, not a
270
- * picture of it.
271
- *
272
- * @param {number} segment_count
273
- */
274
- build(segment_count) {
275
-
276
- const tube = new TubeX();
277
-
278
- tube.setCount(segment_count, this.radialSegments);
279
-
280
- this.tube = tube;
281
- }
282
-
283
- /**
284
- * Clear the trail's geometry and reset its state.
208
+ * Erase the trail: at the next frame every knot expires and collapses onto the head where the entity
209
+ * stands, so nothing bridges what comes after to what went before (a teleport leaves no streak). The
210
+ * trail keeps its birth, so its warm-up does not run again.
285
211
  */
286
212
  clear() {
287
- const tube = this.tube;
288
-
289
- if (tube === null) {
290
- // nothing to clear
291
- return;
292
- }
293
-
294
- const n = tube.getCount();
295
-
296
- for (let i = 0; i < n; i++) {
297
- tube.setKnotAttribute_Scalar(i, TUBE_ATTRIBUTE_ADDRESS_AGE, FLOAT32_MAX);
298
- tube.setKnotAlpha(i, 0);
299
- }
300
-
301
- // Ages/alphas alone don't erase the tube: knot POSITIONS still trace the old
302
- // path. Defer a geometry reset to the next updateHead() (the first code to
303
- // know the post-clear position), which collapses the whole tube onto the head.
304
- this.setFlag(Trail3DFlags.Reseed);
213
+ this.clearCount++;
305
214
  }
306
215
 
307
216
  static fromJSON(json) {
@@ -321,6 +230,7 @@ class Trail3D {
321
230
  textureURL,
322
231
  depthWrite = false,
323
232
  lightingEnabled = false,
233
+ warmup = true,
324
234
  offset = Vector3.zero,
325
235
  color = { r: 1, g: 1, b: 1, a: 1 },
326
236
  fade
@@ -334,6 +244,7 @@ class Trail3D {
334
244
  this.textureURL = textureURL;
335
245
  this.depthWrite = depthWrite;
336
246
  this.lightingEnabled = lightingEnabled;
247
+ this.warmup = warmup;
337
248
 
338
249
  this.offset.fromJSON(offset);
339
250
  this.color.fromJSON(color);
@@ -361,6 +272,7 @@ class Trail3D {
361
272
  textureURL: this.textureURL,
362
273
  depthWrite: this.depthWrite,
363
274
  lightingEnabled: this.lightingEnabled,
275
+ warmup: this.warmup,
364
276
  offset: this.offset.toJSON()
365
277
  };
366
278
  }
@@ -372,6 +284,7 @@ class Trail3D {
372
284
  return this.textureURL === other.textureURL
373
285
  && this.depthWrite === other.depthWrite
374
286
  && this.lightingEnabled === other.lightingEnabled
287
+ && this.warmup === other.warmup
375
288
  && this.width === other.width
376
289
  && this.radialSegments === other.radialSegments
377
290
  && this.maxAge === other.maxAge
@@ -382,127 +295,6 @@ class Trail3D {
382
295
  && this.offset.equals(other.offset)
383
296
  ;
384
297
  }
385
-
386
- /**
387
- * Orient the head knot's ring by parallel-transporting the frame from its
388
- * predecessor (the last committed knot). No-op until the head has separated
389
- * from its predecessor (e.g. right after build), preserving the existing frame.
390
- * @param {number} head_index
391
- * @param {number} x
392
- * @param {number} y
393
- * @param {number} z
394
- * @returns {void}
395
- */
396
- #updateHeadFrame(head_index, x, y, z) {
397
- const tube = this.tube;
398
-
399
- const predecessor_index = (head_index + 1) % tube.getCount();
400
-
401
- tube.getKnotPosition(v3_pred_pos, predecessor_index);
402
-
403
- let tx = x - v3_pred_pos[0];
404
- let ty = y - v3_pred_pos[1];
405
- let tz = z - v3_pred_pos[2];
406
-
407
- const t_length = v3_length(tx, ty, tz);
408
-
409
- if (t_length <= EPSILON) {
410
- // head and predecessor coincide (no direction yet) — keep current frame
411
- return;
412
- }
413
-
414
- const inv = 1 / t_length;
415
- tx *= inv;
416
- ty *= inv;
417
- tz *= inv;
418
-
419
- tube.getKnotNormal(v3_pred_n, predecessor_index);
420
-
421
- tube_frame_transport(
422
- frame_out, 0,
423
- tx, ty, tz,
424
- v3_pred_n[0], v3_pred_n[1], v3_pred_n[2]
425
- );
426
-
427
- tube.setKnotFrame(
428
- head_index,
429
- frame_out[0], frame_out[1], frame_out[2],
430
- frame_out[3], frame_out[4], frame_out[5]
431
- );
432
- }
433
-
434
- /**
435
- * @param {number} x
436
- * @param {number} y
437
- * @param {number} z
438
- * @param {number} head_age
439
- * @returns {boolean} whether the head position changed
440
- */
441
- updateHead(x, y, z, head_age) {
442
- const tube = this.tube;
443
-
444
- const maxAge = this.maxAge;
445
-
446
- if (this.getFlag(Trail3DFlags.Reseed)) {
447
- // post-clear() re-seed: collapse every knot onto the new head position so
448
- // no segment bridges post-clear geometry to pre-clear history.
449
- const n = tube.getCount();
450
- for (let i = 0; i < n; i++) {
451
- tube.setKnotPosition(i, x, y, z);
452
- }
453
- this.timeSinceLastUpdate = 0;
454
- this.distanceSinceLastUpdate = 0;
455
- this.clearFlag(Trail3DFlags.Reseed);
456
- }
457
-
458
- const refitTimeDelta = maxAge / tube.getCount();
459
-
460
- let head_index = tube.getHeadIndex();
461
- tube.getKnotPosition(v3_head_pos, head_index);
462
-
463
- const head_position_changed = x !== v3_head_pos[0]
464
- || y !== v3_head_pos[1]
465
- || z !== v3_head_pos[2];
466
-
467
- if (head_position_changed) {
468
- this.distanceSinceLastUpdate += v3_distance(
469
- v3_head_pos[0], v3_head_pos[1], v3_head_pos[2],
470
- x, y, z
471
- );
472
- }
473
-
474
- const should_spawn = this.spawnMode === TrailSpawnMode.Distance
475
- ? this.distanceSinceLastUpdate >= this.spawnDistance
476
- : this.timeSinceLastUpdate >= refitTimeDelta;
477
-
478
- if (should_spawn && head_position_changed) {
479
- // commit a new knot: both accumulators reset so a mid-life mode switch
480
- // can't carry stale accumulation across.
481
- this.timeSinceLastUpdate = 0;
482
- this.distanceSinceLastUpdate = 0;
483
-
484
- tube.rotate();
485
-
486
- head_index = tube.getHeadIndex();
487
- }
488
-
489
- if (head_position_changed) {
490
- this.#updateHeadFrame(head_index, x, y, z);
491
-
492
- tube.setKnotPosition(head_index, x, y, z);
493
-
494
- this.setFlag(Trail3DFlags.BoundsNeedUpdate);
495
- }
496
-
497
- // set head to fresh value; alpha follows the same fade law the simulator
498
- // applies every tick, so the knot doesn't pop when it stops being the head
499
- tube.setKnotAttribute_Scalar(head_index, TUBE_ATTRIBUTE_ADDRESS_AGE, head_age);
500
- tube.setKnotAlpha(head_index, this.fade.evaluate(clamp01(head_age / maxAge)) * this.color.w);
501
- tube.setKnotThickness(head_index, this.width);
502
-
503
- return head_position_changed;
504
- }
505
-
506
298
  }
507
299
 
508
300
  Trail3D.typeName = "Trail3D";
@@ -1,10 +1,6 @@
1
1
  export type Trail3DFlags = number;
2
2
  export namespace Trail3DFlags {
3
3
  let Spawning: number;
4
- let Aging: number;
5
- let Built: number;
6
- let BoundsNeedUpdate: number;
7
- let Reseed: number;
8
4
  let Lit: number;
9
5
  }
10
6
  //# sourceMappingURL=Trail3DFlags.d.ts.map
@@ -3,18 +3,12 @@
3
3
  * @enum {number}
4
4
  */
5
5
  export const Trail3DFlags = {
6
- Spawning: 1,
7
- Aging: 2,
8
- Built: 4,
9
- BoundsNeedUpdate: 8,
10
-
11
6
  /**
12
- * Set by Trail3D.clear(); consumed by the next updateHead(), which collapses
13
- * the whole tube onto the new head position before resuming. Guarantees no
14
- * segment can bridge post-clear geometry to pre-clear history (e.g. a long
15
- * streak after teleporting the entity).
7
+ * The head follows the entity and lays knots down behind it. Clear it to stop the trail where it
8
+ * is and let it fade out; a stroke ({@link seed_trail_stroke}) clears it, having its whole shape at
9
+ * birth.
16
10
  */
17
- Reseed: 16,
11
+ Spawning: 1,
18
12
 
19
13
  /**
20
14
  * The tube processes standard scene lighting (receive-only — it never casts
@@ -1,18 +1,21 @@
1
1
  /**
2
2
  * Lay a trail down as a fixed stroke between two world points.
3
3
  *
4
- * **This is the other kind of trail.** {@link seed_trail_tube} collapses every knot onto the head
5
- * and lets the entity's travel draw the shape — a wake. A stroke has its whole shape at birth and
6
- * only ages: a beam leaves its source and arrives at its target inside one frame, so there is no
7
- * travel to lay it down with. Both are the same tube afterwards, aged by the same simulator and
8
- * drawn by the same renderer, which is what keeps the game to one trail mechanism (D19/I-6c).
4
+ * **This is the other kind of trail.** A wake collapses onto the head and lets the entity's travel draw
5
+ * the shape. A stroke has its whole shape at birth and only ages: a beam leaves its source and arrives at
6
+ * its target inside one frame, so there is no travel to lay it down with. Both are the same tube
7
+ * afterwards, aged and drawn by the same system, which is what keeps the game to one trail mechanism
8
+ * (D19/I-6c).
9
9
  *
10
- * The two ends carry their own starting age, and that is the whole of the gradient: the simulator
11
- * fades a knot's alpha as it approaches `maxAge`, so an end seeded older thins out first. A beam
12
- * whose source end starts most of the way through its life reads as retracting towards its target.
10
+ * The two ends carry their own starting age, and that is the whole of the gradient: a knot fades as it
11
+ * approaches `maxAge`, so an end seeded older thins out first. A beam whose source end starts most of the
12
+ * way through its life reads as retracting towards its target.
13
13
  *
14
- * **The caller must clear {@link Trail3DFlags.Spawning}**, or the per-frame update will drag the
15
- * head onto the entity and the stroke will grow a tail towards it.
14
+ * **The caller must clear {@link Trail3DFlags.Spawning}**, or the head will follow the entity and the
15
+ * stroke will grow a tail towards it.
16
+ *
17
+ * The knots go into {@link Trail3D#knots}, the authored layout the system uploads when the trail is
18
+ * registered.
16
19
  *
17
20
  * @param {Trail3D} trail
18
21
  * @param {Vector3} from world position the stroke starts at
@@ -1 +1 @@
1
- {"version":3,"file":"seed_trail_stroke.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/seed_trail_stroke.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wFAJW,MAAM,UACN,MAAM,GACJ,IAAI,CAqDhB"}
1
+ {"version":3,"file":"seed_trail_stroke.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/seed_trail_stroke.js"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wFAJW,MAAM,UACN,MAAM,GACJ,IAAI,CA0ChB"}
@@ -3,8 +3,7 @@ import { v3_length } from "../../../../core/geom/vec3/v3_length.js";
3
3
  import {
4
4
  v3_orthonormal_matrix_from_normal
5
5
  } from "../../../../core/geom/vec3/v3_orthonormal_matrix_from_normal.js";
6
- import { TUBE_ATTRIBUTE_ADDRESS_AGE, TUBE_ATTRIBUTE_ADDRESS_UV_V } from "../../trail/tube/tube_attributes_spec.js";
7
- import { Trail3DFlags } from "./Trail3DFlags.js";
6
+ import { TrailKnots } from "../../trail/TrailKnots.js";
8
7
 
9
8
  /**
10
9
  * The frame every knot of a straight stroke shares.
@@ -16,18 +15,21 @@ const frame = new Float64Array(9);
16
15
  /**
17
16
  * Lay a trail down as a fixed stroke between two world points.
18
17
  *
19
- * **This is the other kind of trail.** {@link seed_trail_tube} collapses every knot onto the head
20
- * and lets the entity's travel draw the shape — a wake. A stroke has its whole shape at birth and
21
- * only ages: a beam leaves its source and arrives at its target inside one frame, so there is no
22
- * travel to lay it down with. Both are the same tube afterwards, aged by the same simulator and
23
- * drawn by the same renderer, which is what keeps the game to one trail mechanism (D19/I-6c).
18
+ * **This is the other kind of trail.** A wake collapses onto the head and lets the entity's travel draw
19
+ * the shape. A stroke has its whole shape at birth and only ages: a beam leaves its source and arrives at
20
+ * its target inside one frame, so there is no travel to lay it down with. Both are the same tube
21
+ * afterwards, aged and drawn by the same system, which is what keeps the game to one trail mechanism
22
+ * (D19/I-6c).
24
23
  *
25
- * The two ends carry their own starting age, and that is the whole of the gradient: the simulator
26
- * fades a knot's alpha as it approaches `maxAge`, so an end seeded older thins out first. A beam
27
- * whose source end starts most of the way through its life reads as retracting towards its target.
24
+ * The two ends carry their own starting age, and that is the whole of the gradient: a knot fades as it
25
+ * approaches `maxAge`, so an end seeded older thins out first. A beam whose source end starts most of the
26
+ * way through its life reads as retracting towards its target.
28
27
  *
29
- * **The caller must clear {@link Trail3DFlags.Spawning}**, or the per-frame update will drag the
30
- * head onto the entity and the stroke will grow a tail towards it.
28
+ * **The caller must clear {@link Trail3DFlags.Spawning}**, or the head will follow the entity and the
29
+ * stroke will grow a tail towards it.
30
+ *
31
+ * The knots go into {@link Trail3D#knots}, the authored layout the system uploads when the trail is
32
+ * registered.
31
33
  *
32
34
  * @param {Trail3D} trail
33
35
  * @param {Vector3} from world position the stroke starts at
@@ -50,41 +52,30 @@ export function seed_trail_stroke(trail, from, to, age_from, age_to) {
50
52
 
51
53
  assert.greaterThan(length, 0, 'a stroke needs two distinct ends');
52
54
 
53
- const segment_count = 2;
54
-
55
- trail.build(segment_count);
56
-
57
- const tube = trail.tube;
58
-
59
- trail.time = 0;
60
- trail.trailingIndex = 0;
61
- trail.timeSinceLastUpdate = 0;
62
- trail.distanceSinceLastUpdate = 0;
55
+ const knot_count = 2;
63
56
 
64
57
  const inv = 1 / length;
65
58
 
59
+ // the stroke is straight, so every ring shares one frame and no transport is needed
66
60
  v3_orthonormal_matrix_from_normal(frame, 0, dx * inv, dy * inv, dz * inv);
67
61
 
68
- const color = trail.color;
69
-
70
62
  const max_age = trail.maxAge;
71
63
 
72
- for (let i = 0; i < segment_count; i++) {
73
- const f = i / (segment_count - 1);
74
-
75
- const age = (age_from + (age_to - age_from) * f) * max_age;
64
+ const knots = new TrailKnots();
76
65
 
77
- tube.setKnotPosition(i, from.x + dx * f, from.y + dy * f, from.z + dz * f);
66
+ knots.setCount(knot_count);
78
67
 
79
- // the stroke is straight, so every ring shares one frame and no transport is needed
80
- tube.setKnotFrame(i, frame[0], frame[1], frame[2], frame[3], frame[4], frame[5]);
68
+ for (let i = 0; i < knot_count; i++) {
69
+ const f = i / (knot_count - 1);
81
70
 
82
- tube.setKnotColor(i, color.x, color.y, color.z);
83
- tube.setKnotThickness(i, trail.width);
84
- tube.setKnotAttribute_Scalar(i, TUBE_ATTRIBUTE_ADDRESS_UV_V, f);
85
- tube.setKnotAttribute_Scalar(i, TUBE_ATTRIBUTE_ADDRESS_AGE, age);
86
- tube.setKnotAlpha(i, (1 - age / max_age) * color.w);
71
+ knots.setKnot(
72
+ i,
73
+ from.x + dx * f, from.y + dy * f, from.z + dz * f,
74
+ frame[0], frame[1], frame[2], frame[3], frame[4], frame[5],
75
+ trail.width,
76
+ (age_from + (age_to - age_from) * f) * max_age
77
+ );
87
78
  }
88
79
 
89
- trail.setFlag(Trail3DFlags.Built);
80
+ trail.knots = knots;
90
81
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Knots a trail that lasts `max_age` seconds lays down: one per sixtieth of a second, never fewer than 2
3
+ * nor more than 1,024. A trail's knots are a ring of fixed capacity, so this is what turns an age into a
4
+ * length.
5
+ *
6
+ * @param {number} max_age seconds
7
+ * @returns {number}
8
+ */
9
+ export function trail_knot_count(max_age: number): number;
10
+ //# sourceMappingURL=trail_knot_count.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trail_knot_count.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/trail_knot_count.js"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AACH,0CAHW,MAAM,GACJ,MAAM,CAIlB"}
@@ -0,0 +1,27 @@
1
+ import { clamp } from "../../../../core/math/clamp.js";
2
+
3
+ /**
4
+ * Knots laid down per second of trail life.
5
+ *
6
+ * @type {number}
7
+ */
8
+ const KNOTS_PER_SECOND = 60;
9
+
10
+ /**
11
+ * The most knots a trail's ring holds.
12
+ *
13
+ * @type {number}
14
+ */
15
+ const MAX_KNOTS = 1024;
16
+
17
+ /**
18
+ * Knots a trail that lasts `max_age` seconds lays down: one per sixtieth of a second, never fewer than 2
19
+ * nor more than 1,024. A trail's knots are a ring of fixed capacity, so this is what turns an age into a
20
+ * length.
21
+ *
22
+ * @param {number} max_age seconds
23
+ * @returns {number}
24
+ */
25
+ export function trail_knot_count(max_age) {
26
+ return Math.ceil(clamp(max_age * KNOTS_PER_SECOND, 2, MAX_KNOTS));
27
+ }