@drawcall/lod 0.2.0 → 0.4.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 (355) hide show
  1. package/README.md +6 -7
  2. package/dist/bake.d.ts +36 -0
  3. package/dist/bake.js +176 -0
  4. package/dist/bake.js.map +1 -0
  5. package/dist/baked/codec.d.ts +3 -6
  6. package/dist/baked/codec.js +48 -154
  7. package/dist/baked/codec.js.map +1 -1
  8. package/dist/baked/coverage.d.ts +6 -3
  9. package/dist/baked/coverage.js +6 -3
  10. package/dist/baked/coverage.js.map +1 -1
  11. package/dist/baked/fields.d.ts +9 -0
  12. package/dist/baked/fields.js +22 -0
  13. package/dist/baked/fields.js.map +1 -0
  14. package/dist/baked/index.d.ts +14 -8
  15. package/dist/baked/index.js +24 -22
  16. package/dist/baked/index.js.map +1 -1
  17. package/dist/baked/interior/faces.d.ts +4 -3
  18. package/dist/baked/interior/faces.js +16 -11
  19. package/dist/baked/interior/faces.js.map +1 -1
  20. package/dist/baked/interior/material.d.ts +7 -10
  21. package/dist/baked/interior/material.js +29 -36
  22. package/dist/baked/interior/material.js.map +1 -1
  23. package/dist/baked/interior/rooms.d.ts +1 -1
  24. package/dist/baked/interior/rooms.js +2 -2
  25. package/dist/baked/interior/rooms.js.map +1 -1
  26. package/dist/baked/low.js +5 -4
  27. package/dist/baked/low.js.map +1 -1
  28. package/dist/baked/raster.js +6 -6
  29. package/dist/baked/raster.js.map +1 -1
  30. package/dist/baked/textures.d.ts +17 -0
  31. package/dist/baked/textures.js +95 -0
  32. package/dist/baked/textures.js.map +1 -0
  33. package/dist/baked/transfer.js +19 -18
  34. package/dist/baked/transfer.js.map +1 -1
  35. package/dist/baked/unwrap.js +4 -3
  36. package/dist/baked/unwrap.js.map +1 -1
  37. package/dist/baked/xatlas.js.map +1 -1
  38. package/dist/codec/container.d.ts +8 -0
  39. package/dist/codec/container.js +63 -0
  40. package/dist/codec/container.js.map +1 -0
  41. package/dist/codec/mesh.d.ts +8 -0
  42. package/dist/{mesh/codec.js → codec/mesh.js} +80 -52
  43. package/dist/codec/mesh.js.map +1 -0
  44. package/dist/dispose.d.ts +8 -5
  45. package/dist/dispose.js +22 -24
  46. package/dist/dispose.js.map +1 -1
  47. package/dist/foliage.d.ts +32 -0
  48. package/dist/foliage.js +137 -0
  49. package/dist/foliage.js.map +1 -0
  50. package/dist/impostor/bake/atlas.d.ts +4 -4
  51. package/dist/impostor/bake/atlas.js +12 -12
  52. package/dist/impostor/bake/atlas.js.map +1 -1
  53. package/dist/impostor/bake/fit.d.ts +8 -0
  54. package/dist/impostor/bake/fit.js +28 -0
  55. package/dist/impostor/bake/fit.js.map +1 -0
  56. package/dist/impostor/bake/index.d.ts +22 -14
  57. package/dist/impostor/bake/index.js +50 -134
  58. package/dist/impostor/bake/index.js.map +1 -1
  59. package/dist/impostor/bake/materials.d.ts +3 -3
  60. package/dist/impostor/bake/materials.js +51 -13
  61. package/dist/impostor/bake/materials.js.map +1 -1
  62. package/dist/impostor/bake/sheet.d.ts +8 -0
  63. package/dist/impostor/bake/sheet.js +90 -0
  64. package/dist/impostor/bake/sheet.js.map +1 -0
  65. package/dist/impostor/bake/source.d.ts +3 -2
  66. package/dist/impostor/bake/source.js +9 -20
  67. package/dist/impostor/bake/source.js.map +1 -1
  68. package/dist/impostor/codec.d.ts +4 -5
  69. package/dist/impostor/codec.js +36 -109
  70. package/dist/impostor/codec.js.map +1 -1
  71. package/dist/impostor/impostor.d.ts +31 -7
  72. package/dist/impostor/impostor.js +21 -6
  73. package/dist/impostor/impostor.js.map +1 -1
  74. package/dist/impostor/ktx2/encode.d.ts +26 -0
  75. package/dist/impostor/ktx2/encode.js +120 -0
  76. package/dist/impostor/ktx2/encode.js.map +1 -0
  77. package/dist/impostor/ktx2/transcode.d.ts +3 -0
  78. package/dist/impostor/ktx2/transcode.js +99 -0
  79. package/dist/impostor/ktx2/transcode.js.map +1 -0
  80. package/dist/impostor/ktx2/uastc.d.ts +7 -0
  81. package/dist/impostor/ktx2/uastc.js +65 -0
  82. package/dist/impostor/ktx2/uastc.js.map +1 -0
  83. package/dist/impostor/ktx2/wasm/encoder.d.ts +4 -0
  84. package/dist/impostor/ktx2/wasm/encoder.js +10 -0
  85. package/dist/impostor/ktx2/wasm/encoder.js.map +1 -0
  86. package/dist/impostor/ktx2/wasm/transcoder.d.ts +3 -0
  87. package/dist/impostor/ktx2/wasm/transcoder.js +9 -0
  88. package/dist/impostor/ktx2/wasm/transcoder.js.map +1 -0
  89. package/dist/impostor/ktx2/worker.d.ts +1 -0
  90. package/dist/impostor/ktx2/worker.js +10 -0
  91. package/dist/impostor/ktx2/worker.js.map +1 -0
  92. package/dist/impostor/mesh/card.d.ts +4 -4
  93. package/dist/impostor/mesh/card.js +7 -7
  94. package/dist/impostor/mesh/card.js.map +1 -1
  95. package/dist/impostor/mesh/index.d.ts +7 -6
  96. package/dist/impostor/mesh/index.js +10 -11
  97. package/dist/impostor/mesh/index.js.map +1 -1
  98. package/dist/impostor/mesh/material.d.ts +18 -9
  99. package/dist/impostor/mesh/material.js +40 -27
  100. package/dist/impostor/mesh/material.js.map +1 -1
  101. package/dist/impostor/mesh/surface.d.ts +1 -1
  102. package/dist/impostor/mesh/surface.js +13 -9
  103. package/dist/impostor/mesh/surface.js.map +1 -1
  104. package/dist/impostor/mesh/textures.d.ts +3 -3
  105. package/dist/impostor/mesh/textures.js +24 -34
  106. package/dist/impostor/mesh/textures.js.map +1 -1
  107. package/dist/index.d.ts +13 -11
  108. package/dist/index.js +12 -10
  109. package/dist/index.js.map +1 -1
  110. package/dist/instanced/camera.d.ts +34 -0
  111. package/dist/instanced/camera.js +45 -0
  112. package/dist/instanced/camera.js.map +1 -0
  113. package/dist/instanced/clusters.d.ts +54 -0
  114. package/dist/instanced/clusters.js +151 -0
  115. package/dist/instanced/clusters.js.map +1 -0
  116. package/dist/instanced/cull.d.ts +28 -0
  117. package/dist/instanced/cull.js +22 -0
  118. package/dist/instanced/cull.js.map +1 -0
  119. package/dist/instanced/instances.d.ts +39 -0
  120. package/dist/instanced/instances.js +104 -0
  121. package/dist/instanced/instances.js.map +1 -0
  122. package/dist/instanced/key.d.ts +19 -0
  123. package/dist/instanced/key.js +45 -0
  124. package/dist/instanced/key.js.map +1 -0
  125. package/dist/instanced/levels.d.ts +60 -0
  126. package/dist/instanced/levels.js +131 -0
  127. package/dist/instanced/levels.js.map +1 -0
  128. package/dist/instanced/lists.d.ts +57 -0
  129. package/dist/instanced/lists.js +114 -0
  130. package/dist/instanced/lists.js.map +1 -0
  131. package/dist/instanced/measure.d.ts +28 -0
  132. package/dist/instanced/measure.js +203 -0
  133. package/dist/instanced/measure.js.map +1 -0
  134. package/dist/instanced/meshes.d.ts +44 -51
  135. package/dist/instanced/meshes.js +167 -179
  136. package/dist/instanced/meshes.js.map +1 -1
  137. package/dist/instanced/mirror.d.ts +24 -0
  138. package/dist/instanced/mirror.js +76 -0
  139. package/dist/instanced/mirror.js.map +1 -0
  140. package/dist/instanced/raycast.d.ts +10 -11
  141. package/dist/instanced/raycast.js +31 -41
  142. package/dist/instanced/raycast.js.map +1 -1
  143. package/dist/instanced/rows.d.ts +50 -0
  144. package/dist/instanced/rows.js +36 -0
  145. package/dist/instanced/rows.js.map +1 -0
  146. package/dist/instanced/shape.d.ts +27 -0
  147. package/dist/instanced/shape.js +54 -0
  148. package/dist/instanced/shape.js.map +1 -0
  149. package/dist/instanced/sort.d.ts +61 -0
  150. package/dist/instanced/sort.js +192 -0
  151. package/dist/instanced/sort.js.map +1 -0
  152. package/dist/instanced/update.d.ts +34 -0
  153. package/dist/instanced/update.js +180 -0
  154. package/dist/instanced/update.js.map +1 -0
  155. package/dist/levels/bounds.d.ts +21 -0
  156. package/dist/levels/bounds.js +42 -0
  157. package/dist/levels/bounds.js.map +1 -0
  158. package/dist/levels/cameras.d.ts +48 -0
  159. package/dist/levels/cameras.js +122 -0
  160. package/dist/levels/cameras.js.map +1 -0
  161. package/dist/levels/compile/contexts.d.ts +30 -0
  162. package/dist/levels/compile/contexts.js +18 -0
  163. package/dist/levels/compile/contexts.js.map +1 -0
  164. package/dist/levels/compile/index.d.ts +41 -0
  165. package/dist/levels/compile/index.js +193 -0
  166. package/dist/levels/compile/index.js.map +1 -0
  167. package/dist/levels/compile/pipelines.d.ts +26 -0
  168. package/dist/levels/compile/pipelines.js +172 -0
  169. package/dist/levels/compile/pipelines.js.map +1 -0
  170. package/dist/levels/compiles.d.ts +29 -0
  171. package/dist/levels/compiles.js +50 -0
  172. package/dist/levels/compiles.js.map +1 -0
  173. package/dist/levels/draw.d.ts +102 -0
  174. package/dist/levels/draw.js +401 -0
  175. package/dist/levels/draw.js.map +1 -0
  176. package/dist/levels/fade.d.ts +60 -0
  177. package/dist/levels/fade.js +129 -0
  178. package/dist/levels/fade.js.map +1 -0
  179. package/dist/levels/index.d.ts +99 -0
  180. package/dist/levels/index.js +155 -0
  181. package/dist/levels/index.js.map +1 -0
  182. package/dist/levels/item.d.ts +38 -0
  183. package/dist/levels/item.js +89 -0
  184. package/dist/levels/item.js.map +1 -0
  185. package/dist/levels/load.d.ts +31 -0
  186. package/dist/levels/load.js +144 -0
  187. package/dist/levels/load.js.map +1 -0
  188. package/dist/levels/manager.d.ts +158 -0
  189. package/dist/levels/manager.js +352 -0
  190. package/dist/levels/manager.js.map +1 -0
  191. package/dist/{material.d.ts → levels/material.d.ts} +2 -2
  192. package/dist/{material.js → levels/material.js} +6 -5
  193. package/dist/levels/material.js.map +1 -0
  194. package/dist/levels/renderer.d.ts +32 -0
  195. package/dist/levels/renderer.js +57 -0
  196. package/dist/levels/renderer.js.map +1 -0
  197. package/dist/levels/requests.d.ts +52 -0
  198. package/dist/levels/requests.js +97 -0
  199. package/dist/levels/requests.js.map +1 -0
  200. package/dist/levels/screen.d.ts +14 -0
  201. package/dist/levels/screen.js +21 -0
  202. package/dist/levels/screen.js.map +1 -0
  203. package/dist/loader/build.d.ts +10 -0
  204. package/dist/loader/build.js +28 -0
  205. package/dist/loader/build.js.map +1 -0
  206. package/dist/loader/context.d.ts +44 -0
  207. package/dist/loader/context.js +96 -0
  208. package/dist/loader/context.js.map +1 -0
  209. package/dist/loader/entry.d.ts +4 -0
  210. package/dist/loader/entry.js +43 -0
  211. package/dist/loader/entry.js.map +1 -0
  212. package/dist/loader/index.d.ts +76 -0
  213. package/dist/loader/index.js +272 -0
  214. package/dist/loader/index.js.map +1 -0
  215. package/dist/loader/level.d.ts +41 -0
  216. package/dist/loader/level.js +140 -0
  217. package/dist/loader/level.js.map +1 -0
  218. package/dist/loader/node.d.ts +26 -0
  219. package/dist/loader/node.js +199 -0
  220. package/dist/loader/node.js.map +1 -0
  221. package/dist/loader/request.d.ts +54 -0
  222. package/dist/loader/request.js +19 -0
  223. package/dist/loader/request.js.map +1 -0
  224. package/dist/loader/url.d.ts +10 -6
  225. package/dist/loader/url.js +22 -14
  226. package/dist/loader/url.js.map +1 -1
  227. package/dist/lod.d.ts +144 -43
  228. package/dist/lod.js +354 -163
  229. package/dist/lod.js.map +1 -1
  230. package/dist/meshopt.d.ts +6 -0
  231. package/dist/meshopt.js +20 -0
  232. package/dist/meshopt.js.map +1 -0
  233. package/dist/node-process.d.ts +5 -0
  234. package/dist/node-process.js +6 -0
  235. package/dist/node-process.js.map +1 -0
  236. package/dist/node.d.ts +2 -0
  237. package/dist/node.js +5 -0
  238. package/dist/node.js.map +1 -0
  239. package/dist/simplify/cards.d.ts +14 -0
  240. package/dist/simplify/cards.js +128 -0
  241. package/dist/simplify/cards.js.map +1 -0
  242. package/dist/{simplify.d.ts → simplify/index.d.ts} +8 -5
  243. package/dist/{simplify.js → simplify/index.js} +45 -27
  244. package/dist/simplify/index.js.map +1 -0
  245. package/dist/{bounds.d.ts → source/detail.d.ts} +9 -23
  246. package/dist/{bounds.js → source/detail.js} +28 -58
  247. package/dist/source/detail.js.map +1 -0
  248. package/dist/source/deviation.js +6 -6
  249. package/dist/source/deviation.js.map +1 -1
  250. package/dist/source/{shading.d.ts → evaluator.d.ts} +10 -10
  251. package/dist/source/{shading.js → evaluator.js} +5 -5
  252. package/dist/source/evaluator.js.map +1 -0
  253. package/dist/source/{trace.d.ts → raycaster.d.ts} +6 -6
  254. package/dist/source/{trace.js → raycaster.js} +8 -8
  255. package/dist/source/raycaster.js.map +1 -0
  256. package/dist/source/{texels.d.ts → sampler.d.ts} +1 -1
  257. package/dist/source/{texels.js → sampler.js} +8 -5
  258. package/dist/source/sampler.js.map +1 -0
  259. package/dist/source/source.d.ts +1 -1
  260. package/dist/source/source.js +1 -1
  261. package/dist/source/source.js.map +1 -1
  262. package/dist/source/surface.js +1 -1
  263. package/dist/source/surface.js.map +1 -1
  264. package/dist/task.d.ts +6 -0
  265. package/dist/{pause.js → task.js} +5 -5
  266. package/dist/task.js.map +1 -0
  267. package/dist/three.d.ts +19 -30
  268. package/dist/three.js +30 -57
  269. package/dist/three.js.map +1 -1
  270. package/dist/tsl.d.ts +8 -12
  271. package/dist/tsl.js +11 -39
  272. package/dist/tsl.js.map +1 -1
  273. package/dist/typegpu.d.ts +37 -0
  274. package/dist/typegpu.js +37 -0
  275. package/dist/typegpu.js.map +1 -0
  276. package/dist/wind/bounds.js +3 -3
  277. package/dist/wind/bounds.js.map +1 -1
  278. package/dist/wind/hooks.d.ts +7 -4
  279. package/dist/wind/hooks.js +5 -2
  280. package/dist/wind/hooks.js.map +1 -1
  281. package/dist/wind/index.d.ts +4 -4
  282. package/dist/wind/index.js +25 -23
  283. package/dist/wind/index.js.map +1 -1
  284. package/dist/wind/sway.d.ts +2 -0
  285. package/dist/wind/sway.js +4 -1
  286. package/dist/wind/sway.js.map +1 -1
  287. package/package.json +24 -10
  288. package/skills/lod/SKILL.md +120 -32
  289. package/dist/bounds.js.map +0 -1
  290. package/dist/compile.d.ts +0 -4
  291. package/dist/compile.js +0 -100
  292. package/dist/compile.js.map +0 -1
  293. package/dist/deferred.d.ts +0 -12
  294. package/dist/deferred.js +0 -27
  295. package/dist/deferred.js.map +0 -1
  296. package/dist/fade.d.ts +0 -36
  297. package/dist/fade.js +0 -112
  298. package/dist/fade.js.map +0 -1
  299. package/dist/instanced/args.d.ts +0 -20
  300. package/dist/instanced/args.js +0 -77
  301. package/dist/instanced/args.js.map +0 -1
  302. package/dist/instanced/blocks.d.ts +0 -66
  303. package/dist/instanced/blocks.js +0 -294
  304. package/dist/instanced/blocks.js.map +0 -1
  305. package/dist/instanced/dirty.d.ts +0 -15
  306. package/dist/instanced/dirty.js +0 -96
  307. package/dist/instanced/dirty.js.map +0 -1
  308. package/dist/instanced/index.d.ts +0 -90
  309. package/dist/instanced/index.js +0 -349
  310. package/dist/instanced/index.js.map +0 -1
  311. package/dist/instanced/parts.d.ts +0 -14
  312. package/dist/instanced/parts.js +0 -79
  313. package/dist/instanced/parts.js.map +0 -1
  314. package/dist/instanced/select.d.ts +0 -92
  315. package/dist/instanced/select.js +0 -315
  316. package/dist/instanced/select.js.map +0 -1
  317. package/dist/instanced/store.d.ts +0 -31
  318. package/dist/instanced/store.js +0 -96
  319. package/dist/instanced/store.js.map +0 -1
  320. package/dist/levels.d.ts +0 -95
  321. package/dist/levels.js +0 -171
  322. package/dist/levels.js.map +0 -1
  323. package/dist/loader/bundle.d.ts +0 -25
  324. package/dist/loader/bundle.js +0 -241
  325. package/dist/loader/bundle.js.map +0 -1
  326. package/dist/loader/cache.d.ts +0 -15
  327. package/dist/loader/cache.js +0 -75
  328. package/dist/loader/cache.js.map +0 -1
  329. package/dist/loader/provenance.d.ts +0 -30
  330. package/dist/loader/provenance.js +0 -105
  331. package/dist/loader/provenance.js.map +0 -1
  332. package/dist/loader.d.ts +0 -55
  333. package/dist/loader.js +0 -239
  334. package/dist/loader.js.map +0 -1
  335. package/dist/material.js.map +0 -1
  336. package/dist/mesh/codec.d.ts +0 -4
  337. package/dist/mesh/codec.js.map +0 -1
  338. package/dist/pause.d.ts +0 -6
  339. package/dist/pause.js.map +0 -1
  340. package/dist/queue.d.ts +0 -2
  341. package/dist/queue.js +0 -33
  342. package/dist/queue.js.map +0 -1
  343. package/dist/renderer.d.ts +0 -21
  344. package/dist/renderer.js +0 -83
  345. package/dist/renderer.js.map +0 -1
  346. package/dist/residency.d.ts +0 -44
  347. package/dist/residency.js +0 -205
  348. package/dist/residency.js.map +0 -1
  349. package/dist/simplify.js.map +0 -1
  350. package/dist/source/shading.js.map +0 -1
  351. package/dist/source/texels.js.map +0 -1
  352. package/dist/source/trace.js.map +0 -1
  353. package/dist/view.d.ts +0 -45
  354. package/dist/view.js +0 -131
  355. package/dist/view.js.map +0 -1
@@ -0,0 +1,57 @@
1
+ import { isScene, isShadowPass } from "../three.js";
2
+ // What a Lod learns of the renderer drawing it, and when. three r186 shows much of it through no public API: each
3
+ // read of one of its private fields below says why none serves.
4
+ /**
5
+ * How deep in renders `renderer` is: -1 outside them, 0 in a render of its own, 1 in one it draws inside another, as it
6
+ * draws shadow maps and post-processing. Read from r186's `_callDepth`: three keeps a draw's built shader per depth,
7
+ * and no public API tells which.
8
+ */
9
+ export function callDepth(renderer) {
10
+ const depth = Reflect.get(renderer, "_callDepth");
11
+ if (typeof depth !== "number")
12
+ throw new Error("Lod: three's renderer keeps no call depth (lod mirrors three r186)");
13
+ return depth;
14
+ }
15
+ /**
16
+ * Whether `renderer` is rendering or compiling now, as it is while it updates what it draws; not while an app calls
17
+ * `update` itself or another renderer draws. A compile is told by r186's `_compilationPromises`, which no public API
18
+ * shows.
19
+ */
20
+ export const busy = (renderer) => callDepth(renderer) >= 0 || Reflect.get(renderer, "_compilationPromises") != null;
21
+ /**
22
+ * Throws unless `renderer` can draw a Lod, `who`: three's WebGPU backend, whose device has indirect-first-instance, as
23
+ * each level's draws start at its list (see update.ts).
24
+ */
25
+ export function checkRenderer(renderer, who) {
26
+ if (Reflect.get(renderer.backend, "isWebGPUBackend") !== true)
27
+ throw new Error(`${who}: draws with WebGPU only, but its renderer runs another backend (WebGPURenderer falls back to WebGL2 where WebGPU is missing)`);
28
+ if (!renderer.hasFeature("indirect-first-instance"))
29
+ throw new Error(`${who}: needs the GPU feature indirect-first-instance, which this device lacks`);
30
+ }
31
+ /** The largest storage binding `renderer`'s device takes: r186's WebGPU backend's `device`, which three's types omit. */
32
+ export function maxStorageBinding(renderer) {
33
+ const device = Reflect.get(renderer.backend, "device");
34
+ const limits = typeof device === "object" && device !== null ? Reflect.get(device, "limits") : null;
35
+ const size = typeof limits === "object" && limits !== null ? Reflect.get(limits, "maxStorageBufferBindingSize") : null;
36
+ if (typeof size !== "number")
37
+ throw new Error("Lod: its renderer has no WebGPU device (lod mirrors three r186)");
38
+ return size;
39
+ }
40
+ /**
41
+ * Whether the scene `node` is in is being drawn into a shadow map: three's shadow map render
42
+ * draws it with its own override material, and calls `update` on every LOD with the
43
+ * light's camera, which must not switch the levels the scene's camera chose.
44
+ */
45
+ export function inShadowMap(node) {
46
+ for (let scene = node; scene; scene = scene.parent)
47
+ if (isScene(scene) && isShadowPass(scene.overrideMaterial))
48
+ return true;
49
+ return false;
50
+ }
51
+ /**
52
+ * Whether `target` is the framebuffer target r186 draws the canvas (or output target) through when tone mapping or
53
+ * the output colour space needs a final pass. A draw meant for the output sees it as the active target; a compile for
54
+ * the output leaves the target unset and lets three resolve it.
55
+ */
56
+ export const isOutputPass = (target) => typeof target === "object" && target !== null && Reflect.get(target, "isPostProcessingRenderTarget") === true;
57
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/levels/renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEpD,kHAAkH;AAClH,gEAAgE;AAEhE;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,QAAkB;IAC1C,MAAM,KAAK,GAAY,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACrH,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,QAAkB,EAAW,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,sBAAsB,CAAC,IAAI,IAAI,CAAC;AAEvI;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAkB,EAAE,GAAW;IAC3D,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,KAAK,IAAI;QAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,+HAA+H,CAAC,CAAC;IACzJ,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,yBAAyB,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,0EAA0E,CAAC,CAAC;AACzJ,CAAC;AAED,yHAAyH;AACzH,MAAM,UAAU,iBAAiB,CAAC,QAAkB;IAClD,MAAM,MAAM,GAAY,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAChE,MAAM,MAAM,GAAY,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7G,MAAM,IAAI,GAAY,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACjH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,KAAK,IAAI,KAAK,GAAoB,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM;QAAE,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7I,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAe,EAAW,EAAE,CACvD,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,8BAA8B,CAAC,KAAK,IAAI,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { Camera, Renderer, Scene } from "three/webgpu";
2
+ import type { CameraRenders } from "./cameras.js";
3
+ /**
4
+ * What the cameras rendering a Lod asked of it: per camera the levels it wants, and whether it still renders the Lod.
5
+ * The renderer's updates of the Lod are counted in rounds: a round ends when a camera updates it a second time, so a
6
+ * round holds one update by each camera that renders it once a frame, whatever their order. Shadow maps do not count.
7
+ */
8
+ export declare class CameraRequests {
9
+ /** The renderer drawing the Lod. */
10
+ private readonly renderer;
11
+ /** What renders told of the cameras that drew the Lod. */
12
+ private readonly seen;
13
+ /** The frame a camera, not a shadow map's, last updated the Lod in. */
14
+ cameraFrame: number | null;
15
+ /** The cameras still rendering the Lod (see `fresh`), and what they asked for. */
16
+ private readonly requests;
17
+ private round;
18
+ /** The cameras that updated the Lod in the round under way. */
19
+ private readonly inRound;
20
+ constructor(
21
+ /** The renderer drawing the Lod. */
22
+ renderer: Renderer,
23
+ /** What renders told of the cameras that drew the Lod. */
24
+ seen: CameraRenders);
25
+ /**
26
+ * `camera`, a shadow map's when `shadow`, rendering `scene`, wants the levels of the bits `wanted`: note it, drop the
27
+ * cameras that stopped rendering the Lod, and answer the renderer's frame.
28
+ */
29
+ set(scene: Scene, camera: Camera, wanted: number, shadow: boolean): number;
30
+ /** Note what a render of `scene` with `camera` tells: nothing outside the renderer's renders. */
31
+ private see;
32
+ /** The cameras still rendering the Lod. */
33
+ cameras(): Camera[];
34
+ /**
35
+ * The bits of the levels wanted by the cameras still rendering the Lod (see `rendering`): each camera that renders
36
+ * the scene once a frame counts, whatever their order, and one that stopped rendering it drops out.
37
+ */
38
+ needed(): number;
39
+ /**
40
+ * Whether `camera` still renders the Lod: it updated it in the current or last round, or it is a shadow map's whose
41
+ * target is not disposed (see `fresh`).
42
+ */
43
+ rendering(camera: Camera): boolean;
44
+ /**
45
+ * Whether `camera`'s `request` still counts: made in the current or last round, or a shadow map's while its map's
46
+ * target is not disposed, as the scene's cameras draw what its last update filled however seldom it is redrawn
47
+ * (three redraws a map whose `autoUpdate` is off only when asked). A shadow map's made this frame counts too, before
48
+ * a render notes its target: three draws a map at most once a frame, so a camera rendered again in the frame draws
49
+ * the map the update filled.
50
+ */
51
+ private fresh;
52
+ }
@@ -0,0 +1,97 @@
1
+ import { busy, inShadowMap } from "./renderer.js";
2
+ /**
3
+ * What the cameras rendering a Lod asked of it: per camera the levels it wants, and whether it still renders the Lod.
4
+ * The renderer's updates of the Lod are counted in rounds: a round ends when a camera updates it a second time, so a
5
+ * round holds one update by each camera that renders it once a frame, whatever their order. Shadow maps do not count.
6
+ */
7
+ export class CameraRequests {
8
+ renderer;
9
+ seen;
10
+ /** The frame a camera, not a shadow map's, last updated the Lod in. */
11
+ cameraFrame = null;
12
+ /** The cameras still rendering the Lod (see `fresh`), and what they asked for. */
13
+ requests = new Map();
14
+ round = 0;
15
+ /** The cameras that updated the Lod in the round under way. */
16
+ inRound = new Set();
17
+ constructor(
18
+ /** The renderer drawing the Lod. */
19
+ renderer,
20
+ /** What renders told of the cameras that drew the Lod. */
21
+ seen) {
22
+ this.renderer = renderer;
23
+ this.seen = seen;
24
+ }
25
+ /**
26
+ * `camera`, a shadow map's when `shadow`, rendering `scene`, wants the levels of the bits `wanted`: note it, drop the
27
+ * cameras that stopped rendering the Lod, and answer the renderer's frame.
28
+ */
29
+ set(scene, camera, wanted, shadow) {
30
+ this.see(scene, camera);
31
+ for (const [other, request] of this.requests)
32
+ if (!this.fresh(other, request))
33
+ this.requests.delete(other);
34
+ let request = this.requests.get(camera);
35
+ if (!request)
36
+ this.requests.set(camera, (request = { levels: 0, round: this.round, frame: null }));
37
+ request.round = this.round;
38
+ const frame = this.renderer.info.frame;
39
+ request.frame = shadow ? frame : null;
40
+ if (!shadow)
41
+ this.cameraFrame = frame;
42
+ request.levels = wanted;
43
+ return frame;
44
+ }
45
+ /** Note what a render of `scene` with `camera` tells: nothing outside the renderer's renders. */
46
+ see(scene, camera) {
47
+ const { renderer } = this;
48
+ if (!busy(renderer))
49
+ return;
50
+ this.seen.note(renderer, scene, camera);
51
+ if (inShadowMap(scene))
52
+ return;
53
+ if (this.inRound.has(camera)) {
54
+ this.round++;
55
+ this.inRound.clear();
56
+ }
57
+ this.inRound.add(camera);
58
+ }
59
+ /** The cameras still rendering the Lod. */
60
+ cameras() {
61
+ return [...this.requests].flatMap(([camera, request]) => (this.fresh(camera, request) ? [camera] : []));
62
+ }
63
+ /**
64
+ * The bits of the levels wanted by the cameras still rendering the Lod (see `rendering`): each camera that renders
65
+ * the scene once a frame counts, whatever their order, and one that stopped rendering it drops out.
66
+ */
67
+ needed() {
68
+ let bits = 0;
69
+ for (const [camera, request] of this.requests)
70
+ if (this.fresh(camera, request))
71
+ bits |= request.levels;
72
+ return bits;
73
+ }
74
+ /**
75
+ * Whether `camera` still renders the Lod: it updated it in the current or last round, or it is a shadow map's whose
76
+ * target is not disposed (see `fresh`).
77
+ */
78
+ rendering(camera) {
79
+ const request = this.requests.get(camera);
80
+ return request !== undefined && this.fresh(camera, request);
81
+ }
82
+ /**
83
+ * Whether `camera`'s `request` still counts: made in the current or last round, or a shadow map's while its map's
84
+ * target is not disposed, as the scene's cameras draw what its last update filled however seldom it is redrawn
85
+ * (three redraws a map whose `autoUpdate` is off only when asked). A shadow map's made this frame counts too, before
86
+ * a render notes its target: three draws a map at most once a frame, so a camera rendered again in the frame draws
87
+ * the map the update filled.
88
+ */
89
+ fresh(camera, request) {
90
+ if (request.round >= this.round - 1)
91
+ return true;
92
+ if (request.frame === null)
93
+ return false;
94
+ return request.frame === this.renderer.info.frame || this.seen.drawsShadowMap(camera);
95
+ }
96
+ }
97
+ //# sourceMappingURL=requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requests.js","sourceRoot":"","sources":["../../src/levels/requests.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Vector3, type Camera, type Matrix4, type Sphere } from "three/webgpu";
2
+ /** How a camera measures heights: from where, and pixels per unit of subtense (perspective) or of size (orthographic). */
3
+ export interface Screen {
4
+ readonly eye: Vector3;
5
+ ortho: boolean;
6
+ scale: number;
7
+ }
8
+ /** `camera`'s screen at `height`, the one it draws at, into `out`. */
9
+ export declare function screenOf(camera: Camera, height: number, out?: Screen): Screen;
10
+ /**
11
+ * The height on `screen` of `sphere`, given in the space `root` maps to world: its diameter, scaled by the largest axis
12
+ * scale of `root`, over its distance (small-angle), or its diameter alone in an orthographic camera.
13
+ */
14
+ export declare function screenHeight(sphere: Sphere, root: Matrix4, screen: Screen): number;
@@ -0,0 +1,21 @@
1
+ import { Vector3 } from "three/webgpu";
2
+ /** `camera`'s screen at `height`, the one it draws at, into `out`. */
3
+ export function screenOf(camera, height, out = { eye: new Vector3(), ortho: false, scale: 0 }) {
4
+ const projection = camera.projectionMatrix.elements;
5
+ out.ortho = projection[15] === 1;
6
+ out.scale = ((projection[5] ?? 0) * height) / 2;
7
+ out.eye.setFromMatrixPosition(camera.matrixWorld);
8
+ return out;
9
+ }
10
+ const centre = new Vector3();
11
+ /**
12
+ * The height on `screen` of `sphere`, given in the space `root` maps to world: its diameter, scaled by the largest axis
13
+ * scale of `root`, over its distance (small-angle), or its diameter alone in an orthographic camera.
14
+ */
15
+ export function screenHeight(sphere, root, screen) {
16
+ const size = 2 * sphere.radius * root.getMaxScaleOnAxis();
17
+ if (screen.ortho)
18
+ return size * screen.scale;
19
+ return (size * screen.scale) / Math.max(screen.eye.distanceTo(centre.copy(sphere.center).applyMatrix4(root)), 1e-6);
20
+ }
21
+ //# sourceMappingURL=screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/levels/screen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA0C,MAAM,cAAc,CAAC;AAW/E,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,MAAc,EAAE,MAAc,EAAE,GAAG,EAAE,IAAI,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;IACnH,MAAM,UAAU,GAAG,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC;IACpD,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACjC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAClD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;AAE7B;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,IAAa,EAAE,MAAc;IACxE,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC1D,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;IAC7C,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AACtH,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Object3D, Renderer } from "three/webgpu";
2
+ import type { Derived } from "./level.js";
3
+ /**
4
+ * Build the level `request` asks for from `source`, with the baked level's `low` shell and `interior` rooms if it names
5
+ * them. `renderer` answers the renderer to bake with, asked for only by a bake that draws.
6
+ */
7
+ export declare function buildLevel(source: Object3D, request: Derived, { low, interior }: {
8
+ low: Object3D | undefined;
9
+ interior: Object3D | undefined;
10
+ }, renderer: () => Promise<Renderer>): Promise<Object3D>;
@@ -0,0 +1,28 @@
1
+ import { bakeMesh } from "../baked/index.js";
2
+ import { bakeImpostor } from "../impostor/bake/index.js";
3
+ import { ImpostorMesh } from "../impostor/mesh/index.js";
4
+ import { simplify } from "../simplify/index.js";
5
+ import { placeLike } from "../three.js";
6
+ /**
7
+ * Build the level `request` asks for from `source`, with the baked level's `low` shell and `interior` rooms if it names
8
+ * them. `renderer` answers the renderer to bake with, asked for only by a bake that draws.
9
+ */
10
+ export async function buildLevel(source, request, { low, interior }, renderer) {
11
+ switch (request.type) {
12
+ case "simplify":
13
+ return simplify(source, { ratio: request.ratio });
14
+ case "impostor": {
15
+ const { type: _, draw: __, ...options } = request;
16
+ const object = new ImpostorMesh(await bakeImpostor(source, await renderer(), options));
17
+ object.name = `${source.name || "object"} impostor`;
18
+ placeLike(object, source);
19
+ return object;
20
+ }
21
+ case "baked": {
22
+ const shell = low ? { low } : { ratio: request.ratio };
23
+ const rooms = interior ? { interior, renderer: await renderer() } : {};
24
+ return bakeMesh(source, { textureSize: request.textureSize, ...shell, ...rooms });
25
+ }
26
+ }
27
+ }
28
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/loader/build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAgB,EAChB,OAAgB,EAChB,EAAE,GAAG,EAAE,QAAQ,EAAiE,EAChF,QAAiC;IAEjC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACpD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC;YAClD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;YACvF,MAAM,CAAC,IAAI,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,QAAQ,WAAW,CAAC;YACpD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC1B,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,OAAO,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { Object3D } from "three/webgpu";
2
+ import { type DisposeOptions } from "../dispose.js";
3
+ /**
4
+ * What one ladder's loads share: the source loaded to measure or build the ladder with, handed to the first level load
5
+ * (the source level draws it, a build uses it, a stored level disposes it; onLevel has not changed it), the levels built
6
+ * with the ladder, each handed to its first load, and every level object loaded. Those are freed if describing the
7
+ * ladder fails, else when the last Lod holding the levels is disposed (see `hold`), which spends them.
8
+ */
9
+ export declare class LodLoadContext {
10
+ private readonly load;
11
+ private readonly onLevel;
12
+ /** Called once what the ladder loaded is freed. */
13
+ private readonly onFree;
14
+ /** Level bytes built while describing the ladder, by index: a stored level is read again when it loads. */
15
+ private readonly built;
16
+ private spare;
17
+ /** Every level object loaded, and what freeing it frees: a simplified level draws with its source's materials. */
18
+ private readonly loaded;
19
+ /** How many Lods hold the levels, and whether the last has let go, which freed them. */
20
+ private holders;
21
+ private spent;
22
+ constructor(load: () => Promise<Object3D>, onLevel: ((object: Object3D, index: number) => void | Promise<void>) | undefined,
23
+ /** Called once what the ladder loaded is freed. */
24
+ onFree: () => void);
25
+ /** The spare source, loaded once. */
26
+ source(): Promise<Object3D>;
27
+ /** The spare source, for the first level load to take. */
28
+ take(): Object3D | undefined;
29
+ /** Hold the bytes of level `index`, built while describing the ladder, for its first load to take. */
30
+ setBuilt(index: number, bytes: Uint8Array): void;
31
+ /** The bytes of level `index` built while describing the ladder, once: undefined if none were, or once taken. */
32
+ takeBuilt(index: number): Uint8Array | undefined;
33
+ /** Apply onLevel to a level's arriving object, freeing it as `options` say if that fails. */
34
+ arrive(object: Object3D, index: number, options: DisposeOptions): Promise<Object3D>;
35
+ /** Describing the ladder failed: free what it loaded. */
36
+ fail(): void;
37
+ /**
38
+ * A Lod made from the levels holds them; the release it answers lets go, and the last frees what was loaded. Levels
39
+ * no Lod ever held are never freed. Freed levels are spent: a Lod made from them later throws.
40
+ */
41
+ readonly hold: () => (() => void);
42
+ /** Free the spare source and every level object loaded with `dispose`. */
43
+ private free;
44
+ }
@@ -0,0 +1,96 @@
1
+ import { disposeRejected, disposeRecursive } from "../dispose.js";
2
+ /**
3
+ * What one ladder's loads share: the source loaded to measure or build the ladder with, handed to the first level load
4
+ * (the source level draws it, a build uses it, a stored level disposes it; onLevel has not changed it), the levels built
5
+ * with the ladder, each handed to its first load, and every level object loaded. Those are freed if describing the
6
+ * ladder fails, else when the last Lod holding the levels is disposed (see `hold`), which spends them.
7
+ */
8
+ export class LodLoadContext {
9
+ load;
10
+ onLevel;
11
+ onFree;
12
+ /** Level bytes built while describing the ladder, by index: a stored level is read again when it loads. */
13
+ built = new Map();
14
+ spare;
15
+ /** Every level object loaded, and what freeing it frees: a simplified level draws with its source's materials. */
16
+ loaded = new Map();
17
+ /** How many Lods hold the levels, and whether the last has let go, which freed them. */
18
+ holders = 0;
19
+ spent = false;
20
+ constructor(load, onLevel,
21
+ /** Called once what the ladder loaded is freed. */
22
+ onFree) {
23
+ this.load = load;
24
+ this.onLevel = onLevel;
25
+ this.onFree = onFree;
26
+ }
27
+ /** The spare source, loaded once. */
28
+ async source() {
29
+ this.spare ??= await this.load();
30
+ return this.spare;
31
+ }
32
+ /** The spare source, for the first level load to take. */
33
+ take() {
34
+ const taken = this.spare;
35
+ this.spare = undefined;
36
+ return taken;
37
+ }
38
+ /** Hold the bytes of level `index`, built while describing the ladder, for its first load to take. */
39
+ setBuilt(index, bytes) {
40
+ this.built.set(index, bytes);
41
+ }
42
+ /** The bytes of level `index` built while describing the ladder, once: undefined if none were, or once taken. */
43
+ takeBuilt(index) {
44
+ const bytes = this.built.get(index);
45
+ this.built.delete(index);
46
+ return bytes;
47
+ }
48
+ /** Apply onLevel to a level's arriving object, freeing it as `options` say if that fails. */
49
+ async arrive(object, index, options) {
50
+ try {
51
+ this.loaded.set(object, options);
52
+ await this.onLevel?.(object, index);
53
+ return object;
54
+ }
55
+ catch (error) {
56
+ this.loaded.delete(object);
57
+ disposeRejected(object, options);
58
+ throw error;
59
+ }
60
+ }
61
+ /** Describing the ladder failed: free what it loaded. */
62
+ fail() {
63
+ this.free(disposeRejected);
64
+ }
65
+ /**
66
+ * A Lod made from the levels holds them; the release it answers lets go, and the last frees what was loaded. Levels
67
+ * no Lod ever held are never freed. Freed levels are spent: a Lod made from them later throws.
68
+ */
69
+ hold = () => {
70
+ if (this.spent)
71
+ throw new Error("CachedLodLoader: these levels were freed with the last Lod that held them; call loadAsync again");
72
+ this.holders++;
73
+ let held = true;
74
+ return () => {
75
+ if (!held)
76
+ return;
77
+ held = false;
78
+ if (--this.holders > 0)
79
+ return;
80
+ this.spent = true;
81
+ this.free(disposeRecursive);
82
+ };
83
+ };
84
+ /** Free the spare source and every level object loaded with `dispose`. */
85
+ free(dispose) {
86
+ const taken = this.take();
87
+ if (taken)
88
+ dispose(taken, { materials: true });
89
+ for (const [object, options] of this.loaded)
90
+ dispose(object, options);
91
+ this.loaded.clear();
92
+ this.built.clear();
93
+ this.onFree();
94
+ }
95
+ }
96
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/loader/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { CacheEntry, type CacheEntryOptions } from "vitecache";
2
+ import { type Ladder } from "./request.js";
3
+ /** The entry of derived level `of` of `ladder`, or of its source's shape, keyed by the request alone. */
4
+ export declare function entryOf(ladder: Ladder, of: number | "shape", { basePath, root }: Pick<CacheEntryOptions, "basePath" | "root">): CacheEntry;
@@ -0,0 +1,43 @@
1
+ import { CacheEntry } from "vitecache";
2
+ import { derived } from "./request.js";
3
+ // What a level is stored under.
4
+ /**
5
+ * What builds and lays out a stored level, and so what identifies it beside its request: bump it with any change to
6
+ * the bytes a level or shape entry holds.
7
+ */
8
+ const version = "lod-level@25";
9
+ /** The entry of derived level `of` of `ladder`, or of its source's shape, keyed by the request alone. */
10
+ export function entryOf(ladder, of, { basePath, root }) {
11
+ const level = of === "shape" ? { type: of } : parameters(derived(ladder.levels, of));
12
+ return new CacheEntry({ basePath, root, version, dependencies: { level: { value: { url: ladder.key, level } } } });
13
+ }
14
+ /**
15
+ * What derives a level's content, by its role rather than its ladder position, so adding or removing another level
16
+ * keeps this one's entry. Switch thresholds and impostor draw options apply at decode, so changing one reuses it.
17
+ */
18
+ function parameters(level) {
19
+ switch (level.type) {
20
+ case "simplify":
21
+ return { type: level.type, ratio: level.ratio ?? null };
22
+ case "baked":
23
+ return {
24
+ type: level.type,
25
+ ratio: level.ratio ?? null,
26
+ textureSize: level.textureSize ?? null,
27
+ low: level.low ?? null,
28
+ interior: level.interior ?? null,
29
+ };
30
+ case "impostor":
31
+ return {
32
+ type: level.type,
33
+ // The impostor bakes its top mip for this height too.
34
+ maxPixels: level.maxPixels ?? null,
35
+ layout: level.layout ?? null,
36
+ frames: level.frames ?? null,
37
+ resolution: level.resolution ?? null,
38
+ emissive: level.emissive ?? null,
39
+ supersample: level.supersample ?? null,
40
+ };
41
+ }
42
+ }
43
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/loader/entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA0C,MAAM,WAAW,CAAC;AAE/E,OAAO,EAAE,OAAO,EAAe,MAAM,cAAc,CAAC;AAEpD,gCAAgC;AAEhC;;;GAGG;AACH,MAAM,OAAO,GAAG,cAAc,CAAC;AAE/B,yGAAyG;AACzG,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,EAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAgD;IAC5H,MAAM,KAAK,GAAG,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IACrF,OAAO,IAAI,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACrH,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,KAAc;IAChC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,UAAU;YACb,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QAC1D,KAAK,OAAO;YACV,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI;gBAC1B,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;gBACtC,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,IAAI;gBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;aACjC,CAAC;QACJ,KAAK,UAAU;YACb,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,sDAAsD;gBACtD,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;gBAClC,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;gBAC5B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;gBAC5B,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;gBACpC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;gBAChC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;aACvC,CAAC;IACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { Loader, LoadingManager, type Object3D, type WebGPURenderer } from "three/webgpu";
2
+ import type { CacheEntryOptions, Input } from "vitecache";
3
+ import { type LodLevel } from "../levels/index.js";
4
+ import { type LodRequest } from "./request.js";
5
+ export interface CachedLodLoaderOptions extends Pick<CacheEntryOptions, "basePath" | "root"> {
6
+ /**
7
+ * Apply runtime effects when a level arrives, before draws compile. Does not change built content or bounds.
8
+ * `index` is the returned ladder's: 0 is the source, and `levels[i]` arrives as `i + 1`. Set `castShadow` and
9
+ * `shadowSide` here: a level compiles its draws, shadow maps' included, before it arrives, so a shadow setting
10
+ * changed later compiles mid-frame.
11
+ */
12
+ onLevel?: (object: Object3D, index: number) => void | Promise<void>;
13
+ }
14
+ /**
15
+ * Loads levels of detail from asset URLs, storing each derived level, and the source's shape, in vitecache, keyed by
16
+ * the request alone. Load it as a vitecache cached loader, with literal requests, so that the vitecache plugin finds
17
+ * every load and builds its levels in Node, saving them with the files they were built from; browsers read them, and
18
+ * one that misses builds the level itself.
19
+ *
20
+ * Loads asset URLs through manager handlers, else with a GLTFLoader of its own, which decodes meshopt only: register
21
+ * a GLTFLoader configured with Draco or KTX2 decoders for models compressed with them, and a GLTSLoader for .glts
22
+ * sources. Impostor and interior bakes draw with a renderer of the loader's own, made at its first bake and freed with
23
+ * what the last of the ladders it describes loaded (see `loadAsync`), or by `dispose`.
24
+ */
25
+ export declare class CachedLodLoader extends Loader<LodLevel[], LodRequest> {
26
+ protected readonly options: CachedLodLoaderOptions;
27
+ private gltf;
28
+ /**
29
+ * The renderer this loader bakes with, made at its first bake. Its own, not the app's: a canvas the size of a bake
30
+ * frame would draw that frame over the whole target (see `bakeImpostor`).
31
+ */
32
+ private renderer;
33
+ /** How many ladders it described whose loads are not yet freed. */
34
+ private ladders;
35
+ /** Whether `loadAsync` builds every level with the ladder rather than when a camera first needs it. */
36
+ protected readonly buildsAll: boolean;
37
+ constructor(manager?: LoadingManager, options?: CachedLodLoaderOptions);
38
+ load(request: LodRequest, onLoad: (levels: LodLevel[]) => void, _onProgress?: (event: ProgressEvent) => void, onError?: (error: unknown) => void): void;
39
+ /**
40
+ * Describes the ladder from its source, which the first level loaded then takes. Empty levels load with it, as does
41
+ * the source when it is the only drawable; other levels load when a camera needs them, including a coarse stand-in
42
+ * while its first detail arrives, and each derived level is built when first loaded. A level whose default threshold
43
+ * is measured from it is built with the ladder, and in Node every level is.
44
+ *
45
+ * What the levels load is freed when the last Lod holding them is disposed (see `LodLevel.hold`), which spends them:
46
+ * a Lod made from them later throws, so call loadAsync again. Levels no Lod ever holds are never freed: they are
47
+ * yours until a Lod holds them. Once every ladder it described is freed, so is its bake renderer.
48
+ */
49
+ loadAsync(request: LodRequest): Promise<LodLevel[]>;
50
+ /** The stored bytes of derived level `of`, or of the source's shape, else what `build` makes, saved. */
51
+ private cached;
52
+ /**
53
+ * The path below the app's base that `url`, as the manager resolved it, loads, such as `/tree/model.glts`: what its
54
+ * levels are stored under, alike wherever the app is served. The manager of a .glts script resolves URLs against the
55
+ * script.
56
+ */
57
+ protected publicPath(url: string): string;
58
+ /** The files and packages what this loader built so far was built from: none in browsers, which do not save. */
59
+ protected inputs(): Input[];
60
+ /** A deferred level's bytes, built from `spare`, the ladder's source, or from a source of its own. Disposes `spare` either way. */
61
+ private levelBytes;
62
+ /** Build level `index` from `source`, encoded. */
63
+ private build;
64
+ /** The renderer this loader bakes with, made at its first bake. */
65
+ private bakeRenderer;
66
+ protected newBakeRenderer(): Promise<WebGPURenderer>;
67
+ /**
68
+ * Free the renderer this loader made for its bakes, resolving once freed; a bake under way fails. Levels it loaded
69
+ * stay as they are, and a later bake makes a new renderer. In Node each `loadAsync` frees what it made to load and
70
+ * bake with, the scenes of its GLTSLoader included, before it resolves, so there this frees nothing.
71
+ */
72
+ dispose(): Promise<void>;
73
+ /** Free the bake renderer, once made. */
74
+ private freeRenderer;
75
+ protected loadAsset(url: string): Promise<Object3D>;
76
+ }