@expofp/renderer 0.0.0-experimental.cf063fc

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 (280) hide show
  1. package/README.md +145 -0
  2. package/dist/Renderer.d.ts +102 -0
  3. package/dist/Renderer.js +96 -0
  4. package/dist/controls/CameraControls.d.ts +108 -0
  5. package/dist/controls/CameraControls.js +203 -0
  6. package/dist/controls/Controls.d.ts +53 -0
  7. package/dist/controls/Controls.js +54 -0
  8. package/dist/controls/camera-api.d.ts +226 -0
  9. package/dist/controls/camera-api.js +179 -0
  10. package/dist/controls/gestures.d.ts +71 -0
  11. package/dist/controls/gestures.js +98 -0
  12. package/dist/controls/handlers/DoubleTapZoom.d.ts +23 -0
  13. package/dist/controls/handlers/DoubleTapZoom.js +82 -0
  14. package/dist/controls/handlers/Inertia.d.ts +60 -0
  15. package/dist/controls/handlers/Inertia.js +222 -0
  16. package/dist/controls/handlers/Pan.d.ts +23 -0
  17. package/dist/controls/handlers/Pan.js +212 -0
  18. package/dist/controls/handlers/Pitch.d.ts +19 -0
  19. package/dist/controls/handlers/Pitch.js +200 -0
  20. package/dist/controls/handlers/Roll.d.ts +30 -0
  21. package/dist/controls/handlers/Roll.js +196 -0
  22. package/dist/controls/handlers/Zoom.d.ts +28 -0
  23. package/dist/controls/handlers/Zoom.js +34 -0
  24. package/dist/controls/hooks.d.ts +136 -0
  25. package/dist/controls/hooks.js +200 -0
  26. package/dist/controls/index.d.ts +9 -0
  27. package/dist/controls/index.js +7 -0
  28. package/dist/controls/zoom-to.d.ts +89 -0
  29. package/dist/controls/zoom-to.js +91 -0
  30. package/dist/core/InstanceUniforms.d.ts +108 -0
  31. package/dist/core/InstanceUniforms.js +298 -0
  32. package/dist/core/SquareDataTexture.d.ts +277 -0
  33. package/dist/core/SquareDataTexture.js +476 -0
  34. package/dist/core/batch/BatchedMesh.d.ts +74 -0
  35. package/dist/core/batch/BatchedMesh.js +155 -0
  36. package/dist/core/instanced/FrustumCulling.d.ts +141 -0
  37. package/dist/core/instanced/FrustumCulling.js +246 -0
  38. package/dist/core/instanced/InstancedMesh.d.ts +302 -0
  39. package/dist/core/instanced/InstancedMesh.js +497 -0
  40. package/dist/core/instanced/Instances.d.ts +119 -0
  41. package/dist/core/instanced/Instances.js +230 -0
  42. package/dist/core/instanced/Raycasting.d.ts +118 -0
  43. package/dist/core/instanced/Raycasting.js +134 -0
  44. package/dist/core/instanced/instanced-material.d.ts +77 -0
  45. package/dist/core/instanced/instanced-material.js +228 -0
  46. package/dist/core/lines/BatchedLines.d.ts +137 -0
  47. package/dist/core/lines/BatchedLines.js +215 -0
  48. package/dist/core/lines/FrustumCullingLines.d.ts +44 -0
  49. package/dist/core/lines/FrustumCullingLines.js +85 -0
  50. package/dist/core/lines/RaycastingLines.d.ts +45 -0
  51. package/dist/core/lines/RaycastingLines.js +91 -0
  52. package/dist/core/lines/lines-material.d.ts +47 -0
  53. package/dist/core/lines/lines-material.js +124 -0
  54. package/dist/core/shader-source.d.ts +70 -0
  55. package/dist/core/shader-source.js +110 -0
  56. package/dist/core/sprites/BatchedSprites.d.ts +115 -0
  57. package/dist/core/sprites/BatchedSprites.js +173 -0
  58. package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
  59. package/dist/core/sprites/RaycastingSprites.js +71 -0
  60. package/dist/core/sprites/sprite-material.d.ts +59 -0
  61. package/dist/core/sprites/sprite-material.js +192 -0
  62. package/dist/core/text/BatchedText.d.ts +233 -0
  63. package/dist/core/text/BatchedText.js +473 -0
  64. package/dist/core/text/MemberTexture.d.ts +90 -0
  65. package/dist/core/text/MemberTexture.js +289 -0
  66. package/dist/core/text/Text.d.ts +88 -0
  67. package/dist/core/text/Text.js +230 -0
  68. package/dist/core/text/batched-text-material.d.ts +56 -0
  69. package/dist/core/text/batched-text-material.js +123 -0
  70. package/dist/core/text/glyph-packing.d.ts +17 -0
  71. package/dist/core/text/glyph-packing.js +61 -0
  72. package/dist/core/typed-array.d.ts +16 -0
  73. package/dist/core/typed-array.js +20 -0
  74. package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
  75. package/dist/debug/components/DebugPanelProvider.js +50 -0
  76. package/dist/debug/components/DebugTools.d.ts +22 -0
  77. package/dist/debug/components/DebugTools.js +28 -0
  78. package/dist/debug/components/Gui.d.ts +22 -0
  79. package/dist/debug/components/Gui.js +42 -0
  80. package/dist/debug/components/MemoryInfo.d.ts +22 -0
  81. package/dist/debug/components/MemoryInfo.js +42 -0
  82. package/dist/debug/components/Panel.d.ts +31 -0
  83. package/dist/debug/components/Panel.js +104 -0
  84. package/dist/debug/components/Stats.d.ts +9 -0
  85. package/dist/debug/components/Stats.js +24 -0
  86. package/dist/debug/debug-chunk.d.ts +26 -0
  87. package/dist/debug/debug-chunk.js +32 -0
  88. package/dist/debug/debug-context.d.ts +41 -0
  89. package/dist/debug/debug-context.js +59 -0
  90. package/dist/debug/index.d.ts +41 -0
  91. package/dist/debug/index.js +43 -0
  92. package/dist/events/LayoutDriver.d.ts +36 -0
  93. package/dist/events/LayoutDriver.js +192 -0
  94. package/dist/events/PointerMissed.d.ts +23 -0
  95. package/dist/events/PointerMissed.js +58 -0
  96. package/dist/events/def-culling.d.ts +46 -0
  97. package/dist/events/def-culling.js +69 -0
  98. package/dist/events/layout-targets.d.ts +151 -0
  99. package/dist/events/layout-targets.js +397 -0
  100. package/dist/events/placement/box.d.ts +59 -0
  101. package/dist/events/placement/box.js +96 -0
  102. package/dist/events/placement/grid.d.ts +161 -0
  103. package/dist/events/placement/grid.js +235 -0
  104. package/dist/events/placement/index.d.ts +2 -0
  105. package/dist/events/placement/index.js +1 -0
  106. package/dist/events/placement/pass.d.ts +70 -0
  107. package/dist/events/placement/pass.js +617 -0
  108. package/dist/events/pointer.d.ts +194 -0
  109. package/dist/events/pointer.js +356 -0
  110. package/dist/external/ExternalCanvas.d.ts +56 -0
  111. package/dist/external/ExternalCanvas.js +177 -0
  112. package/dist/external/external-camera.d.ts +18 -0
  113. package/dist/external/external-camera.js +103 -0
  114. package/dist/external/external-events.d.ts +14 -0
  115. package/dist/external/external-events.js +33 -0
  116. package/dist/index.d.ts +13 -0
  117. package/dist/index.js +14 -0
  118. package/dist/objects/Background.d.ts +31 -0
  119. package/dist/objects/Background.js +37 -0
  120. package/dist/objects/containers/SlotContainer.d.ts +312 -0
  121. package/dist/objects/containers/SlotContainer.js +311 -0
  122. package/dist/objects/containers/hooks.d.ts +61 -0
  123. package/dist/objects/containers/hooks.js +196 -0
  124. package/dist/objects/containers/index.d.ts +6 -0
  125. package/dist/objects/containers/index.js +4 -0
  126. package/dist/objects/containers/keys.d.ts +10 -0
  127. package/dist/objects/containers/keys.js +18 -0
  128. package/dist/objects/containers/mesh-writes.d.ts +106 -0
  129. package/dist/objects/containers/mesh-writes.js +97 -0
  130. package/dist/objects/containers/props.d.ts +33 -0
  131. package/dist/objects/containers/props.js +1 -0
  132. package/dist/objects/images/ImageInstance.d.ts +29 -0
  133. package/dist/objects/images/ImageInstance.js +152 -0
  134. package/dist/objects/images/Images.d.ts +49 -0
  135. package/dist/objects/images/Images.js +394 -0
  136. package/dist/objects/images/atlas-packer.d.ts +129 -0
  137. package/dist/objects/images/atlas-packer.js +287 -0
  138. package/dist/objects/images/image-container.d.ts +74 -0
  139. package/dist/objects/images/image-container.js +100 -0
  140. package/dist/objects/images/index.d.ts +2 -0
  141. package/dist/objects/images/index.js +1 -0
  142. package/dist/objects/images/pack-sources.d.ts +190 -0
  143. package/dist/objects/images/pack-sources.js +272 -0
  144. package/dist/objects/images/texture-budget.d.ts +120 -0
  145. package/dist/objects/images/texture-budget.js +215 -0
  146. package/dist/objects/images/worker/atlas-worker.d.ts +56 -0
  147. package/dist/objects/images/worker/atlas-worker.js +123 -0
  148. package/dist/objects/images/worker/client.d.ts +62 -0
  149. package/dist/objects/images/worker/client.js +249 -0
  150. package/dist/objects/images/worker/index.d.ts +10 -0
  151. package/dist/objects/images/worker/index.js +1 -0
  152. package/dist/objects/layer/Layer.d.ts +28 -0
  153. package/dist/objects/layer/Layer.js +134 -0
  154. package/dist/objects/layer/index.d.ts +2 -0
  155. package/dist/objects/layer/index.js +1 -0
  156. package/dist/objects/layer/layer-context.d.ts +74 -0
  157. package/dist/objects/layer/layer-context.js +82 -0
  158. package/dist/objects/layer/mount-scheduler.d.ts +131 -0
  159. package/dist/objects/layer/mount-scheduler.js +289 -0
  160. package/dist/objects/layer/visibility-gui.d.ts +19 -0
  161. package/dist/objects/layer/visibility-gui.js +93 -0
  162. package/dist/objects/lighting/Lighting.d.ts +92 -0
  163. package/dist/objects/lighting/Lighting.js +384 -0
  164. package/dist/objects/lighting/OcclusionPasses.d.ts +23 -0
  165. package/dist/objects/lighting/OcclusionPasses.js +271 -0
  166. package/dist/objects/lighting/index.d.ts +11 -0
  167. package/dist/objects/lighting/index.js +10 -0
  168. package/dist/objects/lighting/lighting-gui.d.ts +24 -0
  169. package/dist/objects/lighting/lighting-gui.js +114 -0
  170. package/dist/objects/lighting/occluder.d.ts +34 -0
  171. package/dist/objects/lighting/occluder.js +62 -0
  172. package/dist/objects/lighting/occlusion-targets.d.ts +143 -0
  173. package/dist/objects/lighting/occlusion-targets.js +276 -0
  174. package/dist/objects/lines/LineInstance.d.ts +21 -0
  175. package/dist/objects/lines/LineInstance.js +73 -0
  176. package/dist/objects/lines/Lines.d.ts +17 -0
  177. package/dist/objects/lines/Lines.js +31 -0
  178. package/dist/objects/lines/index.d.ts +2 -0
  179. package/dist/objects/lines/index.js +1 -0
  180. package/dist/objects/lines/line-container.d.ts +35 -0
  181. package/dist/objects/lines/line-container.js +40 -0
  182. package/dist/objects/materials/ColorMaterial.d.ts +92 -0
  183. package/dist/objects/materials/ColorMaterial.js +124 -0
  184. package/dist/objects/materials/LineMaterial.d.ts +44 -0
  185. package/dist/objects/materials/LineMaterial.js +74 -0
  186. package/dist/objects/materials/ModelMaterial.d.ts +53 -0
  187. package/dist/objects/materials/ModelMaterial.js +111 -0
  188. package/dist/objects/materials/TextureMaterial.d.ts +33 -0
  189. package/dist/objects/materials/TextureMaterial.js +48 -0
  190. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.d.ts +77 -0
  191. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.js +296 -0
  192. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.d.ts +29 -0
  193. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.js +115 -0
  194. package/dist/objects/materials/effects/ao/blur-pass.d.ts +61 -0
  195. package/dist/objects/materials/effects/ao/blur-pass.js +101 -0
  196. package/dist/objects/materials/effects/ao/index.d.ts +129 -0
  197. package/dist/objects/materials/effects/ao/index.js +72 -0
  198. package/dist/objects/materials/effects/color-dim.d.ts +115 -0
  199. package/dist/objects/materials/effects/color-dim.js +206 -0
  200. package/dist/objects/materials/effects/contact-shadow.d.ts +100 -0
  201. package/dist/objects/materials/effects/contact-shadow.js +167 -0
  202. package/dist/objects/materials/effects/effects-context.d.ts +53 -0
  203. package/dist/objects/materials/effects/effects-context.js +24 -0
  204. package/dist/objects/materials/shared.d.ts +24 -0
  205. package/dist/objects/materials/shared.js +72 -0
  206. package/dist/objects/models/ModelInstance.d.ts +22 -0
  207. package/dist/objects/models/ModelInstance.js +33 -0
  208. package/dist/objects/models/Models.d.ts +22 -0
  209. package/dist/objects/models/Models.js +186 -0
  210. package/dist/objects/models/gltf-cache.d.ts +17 -0
  211. package/dist/objects/models/gltf-cache.js +50 -0
  212. package/dist/objects/models/index.d.ts +2 -0
  213. package/dist/objects/models/index.js +1 -0
  214. package/dist/objects/models/model-asset.d.ts +48 -0
  215. package/dist/objects/models/model-asset.js +77 -0
  216. package/dist/objects/models/model-container.d.ts +123 -0
  217. package/dist/objects/models/model-container.js +207 -0
  218. package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
  219. package/dist/objects/shapes/ShapeInstance.js +39 -0
  220. package/dist/objects/shapes/Shapes.d.ts +21 -0
  221. package/dist/objects/shapes/Shapes.js +131 -0
  222. package/dist/objects/shapes/index.d.ts +2 -0
  223. package/dist/objects/shapes/index.js +1 -0
  224. package/dist/objects/shapes/shape-container.d.ts +141 -0
  225. package/dist/objects/shapes/shape-container.js +242 -0
  226. package/dist/objects/shapes/shape-geometry.d.ts +27 -0
  227. package/dist/objects/shapes/shape-geometry.js +94 -0
  228. package/dist/objects/text/TextInstance.d.ts +22 -0
  229. package/dist/objects/text/TextInstance.js +95 -0
  230. package/dist/objects/text/Texts.d.ts +30 -0
  231. package/dist/objects/text/Texts.js +43 -0
  232. package/dist/objects/text/index.d.ts +2 -0
  233. package/dist/objects/text/index.js +1 -0
  234. package/dist/objects/text/text-container.d.ts +121 -0
  235. package/dist/objects/text/text-container.js +229 -0
  236. package/dist/objects/text/text-layout.d.ts +92 -0
  237. package/dist/objects/text/text-layout.js +180 -0
  238. package/dist/space/Camera.d.ts +103 -0
  239. package/dist/space/Camera.js +321 -0
  240. package/dist/space/Scene.d.ts +47 -0
  241. package/dist/space/Scene.js +127 -0
  242. package/dist/space/Space.d.ts +325 -0
  243. package/dist/space/Space.js +359 -0
  244. package/dist/space/VisibleRect.d.ts +45 -0
  245. package/dist/space/VisibleRect.js +129 -0
  246. package/dist/space/camera-handle.d.ts +67 -0
  247. package/dist/space/camera-handle.js +63 -0
  248. package/dist/space/camera-kind.d.ts +26 -0
  249. package/dist/space/camera-kind.js +30 -0
  250. package/dist/space/canvas-size.d.ts +24 -0
  251. package/dist/space/canvas-size.js +20 -0
  252. package/dist/space/clipping.d.ts +69 -0
  253. package/dist/space/clipping.js +130 -0
  254. package/dist/space/layout-measure.d.ts +67 -0
  255. package/dist/space/layout-measure.js +175 -0
  256. package/dist/space/viewport.d.ts +112 -0
  257. package/dist/space/viewport.js +67 -0
  258. package/dist/types/defs.d.ts +234 -0
  259. package/dist/types/defs.js +1 -0
  260. package/dist/types/events.d.ts +198 -0
  261. package/dist/types/events.js +1 -0
  262. package/dist/types/guards.d.ts +21 -0
  263. package/dist/types/guards.js +52 -0
  264. package/dist/update/index.d.ts +3 -0
  265. package/dist/update/index.js +2 -0
  266. package/dist/update/slot-writers.d.ts +30 -0
  267. package/dist/update/slot-writers.js +76 -0
  268. package/dist/update/store.d.ts +41 -0
  269. package/dist/update/store.js +104 -0
  270. package/dist/utils/arrays.d.ts +13 -0
  271. package/dist/utils/arrays.js +20 -0
  272. package/dist/utils/colors.d.ts +19 -0
  273. package/dist/utils/colors.js +27 -0
  274. package/dist/utils/hot-state.d.ts +41 -0
  275. package/dist/utils/hot-state.js +37 -0
  276. package/dist/utils/logging.d.ts +29 -0
  277. package/dist/utils/logging.js +55 -0
  278. package/dist/utils/math.d.ts +52 -0
  279. package/dist/utils/math.js +76 -0
  280. package/package.json +79 -0
@@ -0,0 +1,143 @@
1
+ import { Vector2, type WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ /**
3
+ * The three render targets the occlusion passes draw into, over two color textures.
4
+ *
5
+ * | Target | Color texture | Depth attachment | Written by | Read by |
6
+ * | ------- | ---------------------- | ---------------------- | ---------- | --------------- |
7
+ * | `depth` | its own, never written | `DepthTexture`, 24-bit | prepass | nothing |
8
+ * | `ao` | its own | none | AO pass | the blur pass |
9
+ * | `blur` | the `depth` target's | none | blur pass | the lit shaders |
10
+ *
11
+ * The sharing brings rules, and they live here because this class is the only place that can keep
12
+ * them.
13
+ *
14
+ * A target must not carry a texture that the pass drawing into it samples. WebGL2 calls that a
15
+ * rendering feedback loop, leaves the result undefined, and browsers refuse the draw. Both the AO
16
+ * pass and the blur pass sample the prepass depth, so neither one can bind a target that carries it.
17
+ * That is why two of these three targets carry no depth attachment.
18
+ *
19
+ * Three targets over two color textures. The prepass writes depth with `colorWrite` off, so nothing
20
+ * writes its color attachment and nothing reads it. The blur pass writes what the lit shaders read,
21
+ * so it takes that attachment. The handover costs one framebuffer and no GL texture at all. three's
22
+ * `setupRenderTarget` creates a texture only for a target that has none. `RenderTarget` has a
23
+ * `texture` setter, so this is supported API rather than a reach into internals.
24
+ *
25
+ * Two textures and not one, because the blur pass reads the AO pass's output while it writes its own.
26
+ * One texture for both is the feedback loop above.
27
+ *
28
+ * The set costs `1.5` bytes for each canvas pixel: `1.0` for 24-bit depth and `0.25` for each `R8`
29
+ * color texture, all at a quarter of the canvas area. A `2880 × 1800` canvas therefore holds about
30
+ * `7.8 MB` of them.
31
+ *
32
+ * Never call `setSize`. It calls `dispose()`, and three's deallocation deletes the GL texture of
33
+ * every entry in `renderTarget.textures`, a shared one included. A size change rebuilds all three
34
+ * instead.
35
+ *
36
+ * Dispose all three together, from here. The first disposal of a shared texture deletes it and
37
+ * removes its properties, and the second disposal then finds nothing to delete. No one of the three
38
+ * can outlive the others.
39
+ *
40
+ * The completeness check stays, because a required format is no promise that a particular driver
41
+ * reports the combination complete.
42
+ */
43
+ export declare class OcclusionTargets {
44
+ /** The prepass's target, or `null` until this builds a complete set. */
45
+ private depthTarget;
46
+ /** The AO pass's target, over a color texture of its own, or `null` beside it. */
47
+ private aoTarget;
48
+ /** The blur pass's target, over the prepass's color texture, or `null` beside them. */
49
+ private blurTarget;
50
+ /** The set's pixel size, which is the canvas size at {@link CANVAS_FRACTION}. */
51
+ private readonly targetSize;
52
+ /** Whether this context cannot give a complete set. Once this turns true it stays true. */
53
+ private unavailable;
54
+ /** The prepass's target, or `null` until {@link OcclusionTargets.sync} returns `true`. */
55
+ get depth(): WebGLRenderTarget | null;
56
+ /** The AO pass's target, or `null` until {@link OcclusionTargets.sync} returns `true`. */
57
+ get ao(): WebGLRenderTarget | null;
58
+ /** The blur pass's target, or `null` until {@link OcclusionTargets.sync} returns `true`. */
59
+ get blur(): WebGLRenderTarget | null;
60
+ /** The set's pixel size. Read-only in spirit: the set owns it and rewrites it on a rebuild. */
61
+ get size(): Vector2;
62
+ /**
63
+ * Whether a set is allocated right now.
64
+ *
65
+ * A caller frees the set once when the debug GUI switches occlusion off, rather than on every frame
66
+ * after. This getter tells the caller which frame that is. A flag kept beside the set drifts the
67
+ * first time a sync fails or a rebuild releases the set on its own.
68
+ */
69
+ get held(): boolean;
70
+ /**
71
+ * Frees all three targets and the depth texture, and forgets their size.
72
+ *
73
+ * This takes no renderer. A `RenderTarget` disposal is an event three's own renderer listens for,
74
+ * so an unmount effect with nothing else in hand can call it.
75
+ */
76
+ dispose(): void;
77
+ /**
78
+ * Brings the set to the canvas's current size, and rebuilds it when that size moves.
79
+ * @param gl - The renderer, for the canvas size and for the completeness check.
80
+ * @returns Whether a complete set now exists to draw into.
81
+ */
82
+ sync(gl: WebGLRenderer): boolean;
83
+ /**
84
+ * Allocates the set at a size, at one of the two depth widths.
85
+ * @param width - The set's width in pixels.
86
+ * @param height - Its height.
87
+ * @param depthType - The depth texture's type, which decides its bit width.
88
+ */
89
+ private allocate;
90
+ /**
91
+ * Rebuilds the set, and falls back to 16-bit depth once before it gives up for good.
92
+ * @param gl - The renderer, for the completeness check.
93
+ * @param width - The set's width in pixels.
94
+ * @param height - Its height.
95
+ * @returns Whether a complete set now exists.
96
+ */
97
+ private build;
98
+ /**
99
+ * Frees whatever is allocated, together and in one place, and forgets its size.
100
+ */
101
+ private release;
102
+ /**
103
+ * Asks the driver whether the two framebuffer combinations this set uses came back complete, once
104
+ * per allocation.
105
+ *
106
+ * Binding each target through three is what builds its framebuffer, so the check runs against the
107
+ * real thing rather than against an intention. This puts the previously bound target back, which
108
+ * keeps a shared context unaware that the check ran. The MapLibre embed is that shared context.
109
+ *
110
+ * **Two checks cover three targets, because two of the targets are one combination.** The depth
111
+ * target is a color attachment beside a sampleable depth texture, at whichever of the two widths
112
+ * `build` is trying, and it is the only one of the three carrying depth at all. That is its own
113
+ * risk and it takes its own check. The blur target is a single `R8` color attachment over a
114
+ * texture the depth target already owns. The AO target is that same single `R8` attachment over a
115
+ * texture of its own, so the blur target covers the AO target's combination and adds the sharing,
116
+ * which is the part of this design a driver is most likely to refuse. A third bind would ask a
117
+ * question the second one already answers.
118
+ *
119
+ * **three's own renderer never calls `checkFramebufferStatus`**, so this is the only thing that
120
+ * detects a driver refusing either combination. What it buys is the 16-bit retry and, after that,
121
+ * occlusion switching itself off, rather than a plan drawing out of an incomplete framebuffer.
122
+ *
123
+ * A context that throws while three binds it answers the same question the status code answers, so
124
+ * this catches the throw. Occlusion switching itself off is the documented outcome. Taking the
125
+ * frame loop down with it is the worse one.
126
+ * @param gl - The renderer whose context answers.
127
+ * @returns Whether both combinations are complete.
128
+ */
129
+ private verify;
130
+ }
131
+ /**
132
+ * The share of the canvas size each axis of the set takes.
133
+ *
134
+ * Half, so each pass bills a quarter of the texels a full-size pass bills. Occlusion is a
135
+ * low-frequency signal. The lit read finds its own fragment by normalized coordinates, so the texel
136
+ * count behind that read changes nothing anyone can see.
137
+ *
138
+ * The canvas size and not the drawing buffer's, which is what `gl.getSize()` reports. A device pixel
139
+ * ratio of `2` squares into four times the texels, and both passes bill per texel. A set sized from
140
+ * the buffer therefore costs four times as much on a retina screen, for detail nothing asks of it.
141
+ */
142
+ export declare const CANVAS_FRACTION = 0.5;
143
+ //# sourceMappingURL=occlusion-targets.d.ts.map
@@ -0,0 +1,276 @@
1
+ import { DepthTexture, NearestFilter, RedFormat, UnsignedByteType, UnsignedIntType, UnsignedShortType, Vector2, WebGLRenderTarget, } from 'three';
2
+ import { createLogger } from '../../utils/logging';
3
+ const logger = createLogger('occlusion');
4
+ /**
5
+ * The three render targets the occlusion passes draw into, over two color textures.
6
+ *
7
+ * | Target | Color texture | Depth attachment | Written by | Read by |
8
+ * | ------- | ---------------------- | ---------------------- | ---------- | --------------- |
9
+ * | `depth` | its own, never written | `DepthTexture`, 24-bit | prepass | nothing |
10
+ * | `ao` | its own | none | AO pass | the blur pass |
11
+ * | `blur` | the `depth` target's | none | blur pass | the lit shaders |
12
+ *
13
+ * The sharing brings rules, and they live here because this class is the only place that can keep
14
+ * them.
15
+ *
16
+ * A target must not carry a texture that the pass drawing into it samples. WebGL2 calls that a
17
+ * rendering feedback loop, leaves the result undefined, and browsers refuse the draw. Both the AO
18
+ * pass and the blur pass sample the prepass depth, so neither one can bind a target that carries it.
19
+ * That is why two of these three targets carry no depth attachment.
20
+ *
21
+ * Three targets over two color textures. The prepass writes depth with `colorWrite` off, so nothing
22
+ * writes its color attachment and nothing reads it. The blur pass writes what the lit shaders read,
23
+ * so it takes that attachment. The handover costs one framebuffer and no GL texture at all. three's
24
+ * `setupRenderTarget` creates a texture only for a target that has none. `RenderTarget` has a
25
+ * `texture` setter, so this is supported API rather than a reach into internals.
26
+ *
27
+ * Two textures and not one, because the blur pass reads the AO pass's output while it writes its own.
28
+ * One texture for both is the feedback loop above.
29
+ *
30
+ * The set costs `1.5` bytes for each canvas pixel: `1.0` for 24-bit depth and `0.25` for each `R8`
31
+ * color texture, all at a quarter of the canvas area. A `2880 × 1800` canvas therefore holds about
32
+ * `7.8 MB` of them.
33
+ *
34
+ * Never call `setSize`. It calls `dispose()`, and three's deallocation deletes the GL texture of
35
+ * every entry in `renderTarget.textures`, a shared one included. A size change rebuilds all three
36
+ * instead.
37
+ *
38
+ * Dispose all three together, from here. The first disposal of a shared texture deletes it and
39
+ * removes its properties, and the second disposal then finds nothing to delete. No one of the three
40
+ * can outlive the others.
41
+ *
42
+ * The completeness check stays, because a required format is no promise that a particular driver
43
+ * reports the combination complete.
44
+ */
45
+ export class OcclusionTargets {
46
+ /** The prepass's target, or `null` until this builds a complete set. */
47
+ depthTarget = null;
48
+ /** The AO pass's target, over a color texture of its own, or `null` beside it. */
49
+ aoTarget = null;
50
+ /** The blur pass's target, over the prepass's color texture, or `null` beside them. */
51
+ blurTarget = null;
52
+ /** The set's pixel size, which is the canvas size at {@link CANVAS_FRACTION}. */
53
+ targetSize = new Vector2();
54
+ /** Whether this context cannot give a complete set. Once this turns true it stays true. */
55
+ unavailable = false;
56
+ /** The prepass's target, or `null` until {@link OcclusionTargets.sync} returns `true`. */
57
+ get depth() {
58
+ return this.depthTarget;
59
+ }
60
+ /** The AO pass's target, or `null` until {@link OcclusionTargets.sync} returns `true`. */
61
+ get ao() {
62
+ return this.aoTarget;
63
+ }
64
+ /** The blur pass's target, or `null` until {@link OcclusionTargets.sync} returns `true`. */
65
+ get blur() {
66
+ return this.blurTarget;
67
+ }
68
+ /** The set's pixel size. Read-only in spirit: the set owns it and rewrites it on a rebuild. */
69
+ get size() {
70
+ return this.targetSize;
71
+ }
72
+ /**
73
+ * Whether a set is allocated right now.
74
+ *
75
+ * A caller frees the set once when the debug GUI switches occlusion off, rather than on every frame
76
+ * after. This getter tells the caller which frame that is. A flag kept beside the set drifts the
77
+ * first time a sync fails or a rebuild releases the set on its own.
78
+ */
79
+ get held() {
80
+ return this.depthTarget !== null;
81
+ }
82
+ /**
83
+ * Frees all three targets and the depth texture, and forgets their size.
84
+ *
85
+ * This takes no renderer. A `RenderTarget` disposal is an event three's own renderer listens for,
86
+ * so an unmount effect with nothing else in hand can call it.
87
+ */
88
+ dispose() {
89
+ this.release();
90
+ }
91
+ /**
92
+ * Brings the set to the canvas's current size, and rebuilds it when that size moves.
93
+ * @param gl - The renderer, for the canvas size and for the completeness check.
94
+ * @returns Whether a complete set now exists to draw into.
95
+ */
96
+ sync(gl) {
97
+ if (this.unavailable)
98
+ return false;
99
+ const canvas = gl.getSize(_canvas);
100
+ const width = Math.floor(canvas.x * CANVAS_FRACTION);
101
+ const height = Math.floor(canvas.y * CANVAS_FRACTION);
102
+ // A canvas with no area yet, during a layout or before one. The next resize can undo that, so
103
+ // this is no reason to give up for good.
104
+ if (width < 1 || height < 1)
105
+ return false;
106
+ if (this.depthTarget && this.targetSize.x === width && this.targetSize.y === height) {
107
+ return true;
108
+ }
109
+ return this.build(gl, width, height);
110
+ }
111
+ /**
112
+ * Allocates the set at a size, at one of the two depth widths.
113
+ * @param width - The set's width in pixels.
114
+ * @param height - Its height.
115
+ * @param depthType - The depth texture's type, which decides its bit width.
116
+ */
117
+ allocate(width, height, depthType) {
118
+ this.depthTarget = new WebGLRenderTarget(width, height, {
119
+ ...SINGLE_CHANNEL_TEXTURE,
120
+ depthBuffer: true,
121
+ depthTexture: new DepthTexture(width, height, depthType),
122
+ });
123
+ this.aoTarget = new WebGLRenderTarget(width, height, {
124
+ ...SINGLE_CHANNEL_TEXTURE,
125
+ depthBuffer: false,
126
+ });
127
+ // No format of its own. The next line drops the texture this target is built with, so the
128
+ // missing depth attachment is the only option that outlives the constructor.
129
+ this.blurTarget = new WebGLRenderTarget(width, height, { depthBuffer: false });
130
+ // The sharing, in one line. `RenderTarget` has a `texture` setter, so this is supported API
131
+ // rather than a reach into internals. This drops the target's own fresh texture, which never
132
+ // uploaded. Nothing writes the prepass's color attachment and nothing reads it, so the blur pass
133
+ // can take it.
134
+ this.blurTarget.texture = this.depthTarget.texture;
135
+ this.targetSize.set(width, height);
136
+ }
137
+ /**
138
+ * Rebuilds the set, and falls back to 16-bit depth once before it gives up for good.
139
+ * @param gl - The renderer, for the completeness check.
140
+ * @param width - The set's width in pixels.
141
+ * @param height - Its height.
142
+ * @returns Whether a complete set now exists.
143
+ */
144
+ build(gl, width, height) {
145
+ this.release();
146
+ for (const depthType of DEPTH_TYPES) {
147
+ this.allocate(width, height, depthType);
148
+ if (this.verify(gl))
149
+ return true;
150
+ this.release();
151
+ }
152
+ // Off for good, and silent as far as a caller can tell. The SDK runs in old Android WebViews,
153
+ // and nobody can do anything about a driver that will not report these targets complete. The
154
+ // debug log is for whoever has to find out why a plan shipped without occlusion.
155
+ logger.debug('ambient occlusion off: this context gives no complete render targets');
156
+ this.unavailable = true;
157
+ return false;
158
+ }
159
+ /**
160
+ * Frees whatever is allocated, together and in one place, and forgets its size.
161
+ */
162
+ release() {
163
+ // The order does not matter. The first disposal of the shared texture deletes it and removes its
164
+ // properties, and the second one finds nothing left to delete. All three still have to happen.
165
+ // The AO target's own texture belongs to nobody else, so either order deletes it once.
166
+ this.depthTarget?.dispose();
167
+ this.aoTarget?.dispose();
168
+ this.blurTarget?.dispose();
169
+ this.depthTarget?.depthTexture?.dispose();
170
+ this.depthTarget = null;
171
+ this.aoTarget = null;
172
+ this.blurTarget = null;
173
+ this.targetSize.set(0, 0);
174
+ }
175
+ /**
176
+ * Asks the driver whether the two framebuffer combinations this set uses came back complete, once
177
+ * per allocation.
178
+ *
179
+ * Binding each target through three is what builds its framebuffer, so the check runs against the
180
+ * real thing rather than against an intention. This puts the previously bound target back, which
181
+ * keeps a shared context unaware that the check ran. The MapLibre embed is that shared context.
182
+ *
183
+ * **Two checks cover three targets, because two of the targets are one combination.** The depth
184
+ * target is a color attachment beside a sampleable depth texture, at whichever of the two widths
185
+ * `build` is trying, and it is the only one of the three carrying depth at all. That is its own
186
+ * risk and it takes its own check. The blur target is a single `R8` color attachment over a
187
+ * texture the depth target already owns. The AO target is that same single `R8` attachment over a
188
+ * texture of its own, so the blur target covers the AO target's combination and adds the sharing,
189
+ * which is the part of this design a driver is most likely to refuse. A third bind would ask a
190
+ * question the second one already answers.
191
+ *
192
+ * **three's own renderer never calls `checkFramebufferStatus`**, so this is the only thing that
193
+ * detects a driver refusing either combination. What it buys is the 16-bit retry and, after that,
194
+ * occlusion switching itself off, rather than a plan drawing out of an incomplete framebuffer.
195
+ *
196
+ * A context that throws while three binds it answers the same question the status code answers, so
197
+ * this catches the throw. Occlusion switching itself off is the documented outcome. Taking the
198
+ * frame loop down with it is the worse one.
199
+ * @param gl - The renderer whose context answers.
200
+ * @returns Whether both combinations are complete.
201
+ */
202
+ verify(gl) {
203
+ const context = webgl2(gl);
204
+ if (!context)
205
+ return false;
206
+ const previous = gl.getRenderTarget();
207
+ try {
208
+ let complete = true;
209
+ for (const target of [this.depthTarget, this.blurTarget]) {
210
+ gl.setRenderTarget(target);
211
+ if (context.checkFramebufferStatus(context.FRAMEBUFFER) !== context.FRAMEBUFFER_COMPLETE) {
212
+ complete = false;
213
+ }
214
+ }
215
+ return complete;
216
+ }
217
+ catch {
218
+ return false;
219
+ }
220
+ finally {
221
+ gl.setRenderTarget(previous);
222
+ }
223
+ }
224
+ }
225
+ /**
226
+ * The renderer's context, when it is one these targets can be built on.
227
+ *
228
+ * A runtime feature detection, and not a type narrowing a reader can drop. The SDK still runs in
229
+ * WebViews whose context can be neither WebGL2 nor able to carry a readable depth texture. The
230
+ * constructor itself can be missing, so this checks for it before it uses it.
231
+ * @param gl - The renderer to read.
232
+ * @returns The context, or `undefined` when the targets cannot be built on it.
233
+ */
234
+ function webgl2(gl) {
235
+ const context = gl.getContext();
236
+ if (typeof WebGL2RenderingContext !== 'function')
237
+ return undefined;
238
+ return context instanceof WebGL2RenderingContext ? context : undefined;
239
+ }
240
+ /**
241
+ * The share of the canvas size each axis of the set takes.
242
+ *
243
+ * Half, so each pass bills a quarter of the texels a full-size pass bills. Occlusion is a
244
+ * low-frequency signal. The lit read finds its own fragment by normalized coordinates, so the texel
245
+ * count behind that read changes nothing anyone can see.
246
+ *
247
+ * The canvas size and not the drawing buffer's, which is what `gl.getSize()` reports. A device pixel
248
+ * ratio of `2` squares into four times the texels, and both passes bill per texel. A set sized from
249
+ * the buffer therefore costs four times as much on a retina screen, for detail nothing asks of it.
250
+ */
251
+ export const CANVAS_FRACTION = 0.5;
252
+ /**
253
+ * The depth widths this tries, in order.
254
+ *
255
+ * 24 bits first, because 16-bit depth at this size over a plan's range bands visibly in the
256
+ * occlusion. 16 bits is the one retry worth making before occlusion latches off for good. It saves
257
+ * memory rather than costing it, which makes it a fallback rather than a default.
258
+ */
259
+ const DEPTH_TYPES = [UnsignedIntType, UnsignedShortType];
260
+ /**
261
+ * The shared settings for the two color textures the occlusion passes draw into.
262
+ *
263
+ * `R8` holds one byte a texel. It is a color-renderable sized internal format in WebGL 2, so it is
264
+ * required to work rather than merely likely to.
265
+ *
266
+ * Both the blur pass and the lit read weight their samples by depth, so hardware filtering only
267
+ * smears occlusion across the edges those reads respect.
268
+ */
269
+ const SINGLE_CHANNEL_TEXTURE = {
270
+ format: RedFormat,
271
+ type: UnsignedByteType,
272
+ minFilter: NearestFilter,
273
+ magFilter: NearestFilter,
274
+ };
275
+ /** Scratch for the canvas size, read once per sync. */
276
+ const _canvas = new Vector2();
@@ -0,0 +1,21 @@
1
+ import { type LineDef } from '../../types/defs';
2
+ import { type InstanceProps } from '../containers';
3
+ import { type LineContainer } from './line-container';
4
+ /** Props for {@link LineInstance}. */
5
+ export type LineInstanceProps = InstanceProps<LineDef, LineContainer>;
6
+ /**
7
+ * Keeps one line's instance current: claims a slot on mount, writes the def's endpoints, color,
8
+ * width and visibility on mount and after every `update(def)`, and releases the slot on unmount.
9
+ *
10
+ * Renders no scene node — the batch belongs to the container. Nothing here can force a re-claim:
11
+ * unlike a shape, whose geometry is its slot's resource, a line is the same segment template
12
+ * wherever it runs, so moving one is an ordinary write and its slot survives.
13
+ *
14
+ * Memoized for the same reason as `ShapeInstance`: a structural change hands the layer a fresh
15
+ * `defs` snapshot, so element-identity bailout never applies and only prop equality keeps unchanged
16
+ * siblings from re-rendering. Correctness never depends on it.
17
+ * @param props - The def and its container.
18
+ * @returns `null`; the instance lives in the batch, not the scene graph.
19
+ */
20
+ export declare const LineInstance: import("react").MemoExoticComponent<(props: LineInstanceProps) => null>;
21
+ //# sourceMappingURL=LineInstance.d.ts.map
@@ -0,0 +1,73 @@
1
+ import { memo } from 'react';
2
+ import { Vector3 } from 'three';
3
+ import { createLogger } from '../../utils/logging';
4
+ import { useDefSync, writeColorIfChanged } from '../containers';
5
+ const logger = createLogger('line-instance');
6
+ /**
7
+ * Keeps one line's instance current: claims a slot on mount, writes the def's endpoints, color,
8
+ * width and visibility on mount and after every `update(def)`, and releases the slot on unmount.
9
+ *
10
+ * Renders no scene node — the batch belongs to the container. Nothing here can force a re-claim:
11
+ * unlike a shape, whose geometry is its slot's resource, a line is the same segment template
12
+ * wherever it runs, so moving one is an ordinary write and its slot survives.
13
+ *
14
+ * Memoized for the same reason as `ShapeInstance`: a structural change hands the layer a fresh
15
+ * `defs` snapshot, so element-identity bailout never applies and only prop equality keeps unchanged
16
+ * siblings from re-rendering. Correctness never depends on it.
17
+ * @param props - The def and its container.
18
+ * @returns `null`; the instance lives in the batch, not the scene graph.
19
+ */
20
+ export const LineInstance = memo(function LineInstance(props) {
21
+ const { def, container } = props;
22
+ useDefSync(container, def, null, (slot) => {
23
+ writeLinePoints(container, slot, def);
24
+ writeColorIfChanged(container.mesh, slot, def, logger);
25
+ writeLineWidth(container, slot, def);
26
+ });
27
+ return null;
28
+ });
29
+ /**
30
+ * Writes a line's endpoints into its instance.
31
+ *
32
+ * A `LineLike` is 2D plus an optional elevation, which is what places the segment on its layer's
33
+ * plane; the batch compares and skips, so a def that only changed color pays two vector fills.
34
+ * @param container - The container holding the instance.
35
+ * @param slot - The instance's slot.
36
+ * @param def - The line def supplying the endpoints.
37
+ */
38
+ function writeLinePoints(container, slot, def) {
39
+ const { p0, p1, elevation = 0 } = def.points;
40
+ _start.set(p0.x, p0.y, elevation);
41
+ _end.set(p1.x, p1.y, elevation);
42
+ // Compared before writing, like every other instance write: a color-only `update(def)` re-runs the
43
+ // whole sync, and an unchanged segment costs six comparisons instead of two uniform uploads and a
44
+ // bounds invalidation.
45
+ container.mesh.getPointsAt(slot, _heldStart, _heldEnd);
46
+ if (_heldStart.equals(_start) && _heldEnd.equals(_end))
47
+ return;
48
+ container.mesh.setPointsAt(slot, _start, _end);
49
+ }
50
+ /**
51
+ * Writes a line's width into its instance, skipping the upload when it did not change.
52
+ *
53
+ * Clamped at zero, which is where the def's contract and the batch's part ways: the batch reads a
54
+ * negative width as "this member has none of its own" and falls back to the material's, an
55
+ * affordance for callers that never set one. A `LineDef` always carries a width, so a negative one
56
+ * is bad input rather than a request to inherit — and it must not come out thicker than a zero.
57
+ * @param container - The container holding the instance.
58
+ * @param slot - The instance's slot.
59
+ * @param def - The line def supplying the width.
60
+ */
61
+ function writeLineWidth(container, slot, def) {
62
+ const width = Math.max(def.width, 0);
63
+ if (container.mesh.getWidthAt(slot) === width)
64
+ return;
65
+ container.mesh.setWidthAt(slot, width);
66
+ }
67
+ // Scratch shared by every endpoint write: filled and consumed within a single synchronous
68
+ // statement, so a write costs one buffer upload and no allocation. The `_held*` pair is only ever
69
+ // read back and compared, so it never collides with the endpoints being written.
70
+ const _start = new Vector3();
71
+ const _end = new Vector3();
72
+ const _heldStart = new Vector3();
73
+ const _heldEnd = new Vector3();
@@ -0,0 +1,17 @@
1
+ import { type LineDef } from '../../types/defs';
2
+ import { type DefsProps } from '../containers';
3
+ /** Props for {@link Lines}. */
4
+ export type LinesProps = DefsProps<LineDef>;
5
+ /**
6
+ * Draws a collection of lines as members of one `BatchedLines`, so a layer of route segments
7
+ * renders in a single instanced draw.
8
+ *
9
+ * Membership is reconciled by React exactly as it is for shapes: a new `defs` array re-renders this
10
+ * component and React mounts or unmounts only the delta, with no differ of our own. Order is applied
11
+ * as it is for images — the container labels each slot with its def's place in the layer, and the
12
+ * batch's `customSort` orders the draw list by it, so a reorder writes nothing to the GPU.
13
+ * @param props - The lines to draw.
14
+ * @returns The batch and one instance component per line.
15
+ */
16
+ export declare function Lines(props: LinesProps): import("react").JSX.Element;
17
+ //# sourceMappingURL=Lines.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { BatchedLines } from '../../core/lines/BatchedLines';
3
+ import { defKey, useContainer } from '../containers';
4
+ import { LineMaterial } from '../materials/LineMaterial';
5
+ import { LineContainer } from './line-container';
6
+ import { LineInstance } from './LineInstance';
7
+ /**
8
+ * Draws a collection of lines as members of one `BatchedLines`, so a layer of route segments
9
+ * renders in a single instanced draw.
10
+ *
11
+ * Membership is reconciled by React exactly as it is for shapes: a new `defs` array re-renders this
12
+ * component and React mounts or unmounts only the delta, with no differ of our own. Order is applied
13
+ * as it is for images — the container labels each slot with its def's place in the layer, and the
14
+ * batch's `customSort` orders the draw list by it, so a reorder writes nothing to the GPU.
15
+ * @param props - The lines to draw.
16
+ * @returns The batch and one instance component per line.
17
+ */
18
+ export function Lines(props) {
19
+ const { defs } = props;
20
+ // Only the instances are staged; the container is sized and ordered from the whole membership.
21
+ const mounted = props.mounted ?? defs.length;
22
+ // Sized from the first render's defs; membership changes grow the batch in place, never rebuild
23
+ // it. The container is bookkeeping only, so the copy StrictMode's double-invoked initializer
24
+ // discards is plain garbage.
25
+ const container = useContainer(() => new LineContainer(defs), defs);
26
+ // `args` is diffed element-wise and a change would dispose and rebuild the batch, orphaning every
27
+ // claimed slot — it is a frozen snapshot, so that never happens. The `ref` arrow is
28
+ // deliberate: `ref={container.bind}` would make the React Compiler infer `container` itself as a
29
+ // ref and reject its render-time reads.
30
+ return (_jsxs(_Fragment, { children: [_jsx(BatchedLines, { args: container.args, ref: (mesh) => container.bind(mesh), customSort: container.customSort, children: _jsx(LineMaterial, {}) }), defs.slice(0, mounted).map((def) => (_jsx(LineInstance, { def: def, container: container }, defKey(def))))] }));
31
+ }
@@ -0,0 +1,2 @@
1
+ export { Lines, type LinesProps } from './Lines';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { Lines } from './Lines';
@@ -0,0 +1,35 @@
1
+ import { type InstancedMeshImplParams } from '../../core/instanced/InstancedMesh';
2
+ import { type BatchedLinesImpl } from '../../core/lines/BatchedLines';
3
+ import { type LineDef } from '../../types/defs';
4
+ import { SlotContainer } from '../containers';
5
+ /**
6
+ * The constructor tuple R3F builds a line batch from, passed as `<BatchedLines args={…}>`. R3F diffs
7
+ * `args` element-wise and rebuilds the object when any element changes, so this is snapshotted once
8
+ * and never mutated.
9
+ *
10
+ * Only the options: the batch builds its own segment template and takes its material from the
11
+ * `<LineMaterial>` child R3F mounts under it.
12
+ */
13
+ export type LineMeshArgs = [params: InstancedMeshImplParams];
14
+ /**
15
+ * One line layer's bookkeeping.
16
+ *
17
+ * Thinner than the shape container and the image one alike, because a line has no per-instance
18
+ * resource to allocate against — every member draws the same segment template, placed by its own
19
+ * endpoints. That is why the resource type is `null` here: nothing about a `LineDef` can force a
20
+ * re-claim, so a def keeps its slot for as long as it is mounted, `points` included.
21
+ */
22
+ export declare class LineContainer extends SlotContainer<null, BatchedLinesImpl, LineDef> {
23
+ /** The constructor args R3F builds the batch from; a frozen snapshot, never mutated. */
24
+ readonly args: LineMeshArgs;
25
+ /**
26
+ * Builds a line layer's bookkeeping, sized to hold `defs` exactly so a layer that mounts full
27
+ * never reallocates. The batch itself is R3F's — the component renders `<BatchedLines>` and hands
28
+ * it over through {@link SlotContainer.bind} — so R3F disposes it on unmount.
29
+ * @param defs - The layer's lines, used only to size the initial capacity.
30
+ */
31
+ constructor(defs: readonly LineDef[]);
32
+ protected addInstance(): number;
33
+ protected removeInstance(slot: number): void;
34
+ }
35
+ //# sourceMappingURL=line-container.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { SlotContainer } from '../containers';
2
+ /**
3
+ * One line layer's bookkeeping.
4
+ *
5
+ * Thinner than the shape container and the image one alike, because a line has no per-instance
6
+ * resource to allocate against — every member draws the same segment template, placed by its own
7
+ * endpoints. That is why the resource type is `null` here: nothing about a `LineDef` can force a
8
+ * re-claim, so a def keeps its slot for as long as it is mounted, `points` included.
9
+ */
10
+ export class LineContainer extends SlotContainer {
11
+ /** The constructor args R3F builds the batch from; a frozen snapshot, never mutated. */
12
+ args;
13
+ /**
14
+ * Builds a line layer's bookkeeping, sized to hold `defs` exactly so a layer that mounts full
15
+ * never reallocates. The batch itself is R3F's — the component renders `<BatchedLines>` and hands
16
+ * it over through {@link SlotContainer.bind} — so R3F disposes it on unmount.
17
+ * @param defs - The layer's lines, used only to size the initial capacity.
18
+ */
19
+ constructor(defs) {
20
+ // Reversed, and that is the material's doing rather than this layer's: a line batch stencils
21
+ // first-fragment-wins so translucent lines do not darken where they overlap, which hands the
22
+ // pixel to whichever member rasterizes *first*. Draw order is therefore the reverse of paint
23
+ // order. Slots are still labeled in paint order, so "last sibling on top" holds here as
24
+ // everywhere else.
25
+ super({ reverse: true });
26
+ this.args = [{ capacity: Math.max(defs.length, 1) }];
27
+ }
28
+ addInstance() {
29
+ // The batch grows its own buffers if the layer ever outgrows the capacity it was sized to, so
30
+ // there is nothing to pre-scan; the id is captured from the creation callback.
31
+ let slot = -1;
32
+ this.mesh.addInstances(1, (id) => {
33
+ slot = id;
34
+ });
35
+ return slot;
36
+ }
37
+ removeInstance(slot) {
38
+ this.mesh.removeInstances(slot);
39
+ }
40
+ }