leaflet-city-mapper 0.0.1 → 0.0.2

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 (472) hide show
  1. package/README.md +15 -13
  2. package/cucumber.mjs +4 -0
  3. package/dist/leaflet-city-mapper.js +1 -1
  4. package/dist/leaflet-city-mapper.js.map +4 -4
  5. package/dist/utils/CELL.js +2 -0
  6. package/dist/utils/CELL.js.map +7 -0
  7. package/dist/utils/addBridges.js +2 -0
  8. package/dist/utils/addBridges.js.map +7 -0
  9. package/dist/utils/addRasterTile.js +2 -0
  10. package/dist/utils/addRasterTile.js.map +7 -0
  11. package/dist/utils/along.js +2 -0
  12. package/dist/utils/along.js.map +7 -0
  13. package/dist/utils/atmosphere.js +2 -0
  14. package/dist/utils/atmosphere.js.map +7 -0
  15. package/dist/utils/attach.js +2 -0
  16. package/dist/utils/attach.js.map +7 -0
  17. package/dist/utils/bindSunlight.js +2 -0
  18. package/dist/utils/bindSunlight.js.map +7 -0
  19. package/dist/utils/box.js +2 -0
  20. package/dist/utils/box.js.map +7 -0
  21. package/dist/utils/bridgeElevation.js +2 -0
  22. package/dist/utils/bridgeElevation.js.map +7 -0
  23. package/dist/utils/build.js +2 -0
  24. package/dist/utils/build.js.map +7 -0
  25. package/dist/utils/cameraControls.js +2 -0
  26. package/dist/utils/cameraControls.js.map +7 -0
  27. package/dist/utils/channel.js +2 -0
  28. package/dist/utils/channel.js.map +7 -0
  29. package/dist/utils/collider.js +2 -0
  30. package/dist/utils/collider.js.map +7 -0
  31. package/dist/utils/colliders.js +2 -0
  32. package/dist/utils/colliders.js.map +7 -0
  33. package/dist/utils/computeBounds.js +2 -0
  34. package/dist/utils/computeBounds.js.map +7 -0
  35. package/dist/utils/conformModelToTerrain.js +2 -0
  36. package/dist/utils/conformModelToTerrain.js.map +7 -0
  37. package/dist/utils/createMesh.js +2 -0
  38. package/dist/utils/createMesh.js.map +7 -0
  39. package/dist/utils/createProgram.js +3 -0
  40. package/dist/utils/createProgram.js.map +7 -0
  41. package/dist/utils/decodeDirectory.js +2 -0
  42. package/dist/utils/decodeDirectory.js.map +7 -0
  43. package/dist/utils/decodeHeader.js +2 -0
  44. package/dist/utils/decodeHeader.js.map +7 -0
  45. package/dist/utils/decodeModel.js +2 -0
  46. package/dist/utils/decodeModel.js.map +7 -0
  47. package/dist/utils/decompress.js +2 -0
  48. package/dist/utils/decompress.js.map +7 -0
  49. package/dist/utils/destroyTexture.js +2 -0
  50. package/dist/utils/destroyTexture.js.map +7 -0
  51. package/dist/utils/disposeMesh.js +2 -0
  52. package/dist/utils/disposeMesh.js.map +7 -0
  53. package/dist/utils/drawGeometry.js +2 -0
  54. package/dist/utils/drawGeometry.js.map +7 -0
  55. package/dist/utils/elevationWGSL.js +24 -0
  56. package/dist/utils/elevationWGSL.js.map +7 -0
  57. package/dist/utils/emptyNode.js +2 -0
  58. package/dist/utils/emptyNode.js.map +7 -0
  59. package/dist/utils/endZoom.js +2 -0
  60. package/dist/utils/endZoom.js.map +7 -0
  61. package/dist/utils/findFeature.js +2 -0
  62. package/dist/utils/findFeature.js.map +7 -0
  63. package/dist/utils/geometry.js +0 -1
  64. package/dist/utils/geometry.js.map +4 -4
  65. package/dist/utils/getElevation.js +2 -0
  66. package/dist/utils/getElevation.js.map +7 -0
  67. package/dist/utils/getHeader.js +2 -0
  68. package/dist/utils/getHeader.js.map +7 -0
  69. package/dist/utils/getZxy.js +2 -0
  70. package/dist/utils/getZxy.js.map +7 -0
  71. package/dist/utils/glass.js +2 -0
  72. package/dist/utils/glass.js.map +7 -0
  73. package/dist/utils/headlight.js +2 -0
  74. package/dist/utils/headlight.js.map +7 -0
  75. package/dist/utils/hit.js +2 -0
  76. package/dist/utils/hit.js.map +7 -0
  77. package/dist/utils/horizontalPosition.js +2 -0
  78. package/dist/utils/horizontalPosition.js.map +7 -0
  79. package/dist/utils/horizontalRay.js +2 -0
  80. package/dist/utils/horizontalRay.js.map +7 -0
  81. package/dist/utils/hull.js +2 -0
  82. package/dist/utils/hull.js.map +7 -0
  83. package/dist/utils/initSunlight.js +2 -0
  84. package/dist/utils/initSunlight.js.map +7 -0
  85. package/dist/utils/initTerrain.js +2 -0
  86. package/dist/utils/initTerrain.js.map +7 -0
  87. package/dist/utils/initTraffic.js +40 -0
  88. package/dist/utils/initTraffic.js.map +7 -0
  89. package/dist/utils/initWalk.js +2 -0
  90. package/dist/utils/initWalk.js.map +7 -0
  91. package/dist/utils/intersectMeshes.js +2 -0
  92. package/dist/utils/intersectMeshes.js.map +7 -0
  93. package/dist/utils/isClockWise.js +2 -0
  94. package/dist/utils/isClockWise.js.map +7 -0
  95. package/dist/utils/lampPostGeometry.js +2 -0
  96. package/dist/utils/lampPostGeometry.js.map +7 -0
  97. package/dist/utils/lightGeometry.js +2 -0
  98. package/dist/utils/lightGeometry.js.map +7 -0
  99. package/dist/utils/lightGrid.js +2 -0
  100. package/dist/utils/lightGrid.js.map +7 -0
  101. package/dist/utils/limbs.js +2 -0
  102. package/dist/utils/limbs.js.map +7 -0
  103. package/dist/utils/loadModel.js +2 -0
  104. package/dist/utils/loadModel.js.map +7 -0
  105. package/dist/utils/loadSource.js +2 -0
  106. package/dist/utils/loadSource.js.map +7 -0
  107. package/dist/utils/loadTerrain.js +2 -0
  108. package/dist/utils/loadTerrain.js.map +7 -0
  109. package/dist/utils/mapCamera.js +2 -0
  110. package/dist/utils/mapCamera.js.map +7 -0
  111. package/dist/utils/{shaders.js → materialShaders.js} +16 -8
  112. package/dist/utils/materialShaders.js.map +7 -0
  113. package/dist/utils/mirror.js +2 -0
  114. package/dist/utils/mirror.js.map +7 -0
  115. package/dist/utils/moonPosition.js +2 -0
  116. package/dist/utils/moonPosition.js.map +7 -0
  117. package/dist/utils/moves.js +2 -0
  118. package/dist/utils/moves.js.map +7 -0
  119. package/dist/utils/nativeEvents.js +2 -0
  120. package/dist/utils/nativeEvents.js.map +7 -0
  121. package/dist/utils/nativeGeometry.js +2 -0
  122. package/dist/utils/nativeGeometry.js.map +7 -0
  123. package/dist/utils/nativeLayer.js +2 -0
  124. package/dist/utils/nativeLayer.js.map +7 -0
  125. package/dist/utils/nodeMatrix.js +2 -0
  126. package/dist/utils/nodeMatrix.js.map +7 -0
  127. package/dist/utils/onAdd3DLayer.js +2 -0
  128. package/dist/utils/onAdd3DLayer.js.map +7 -0
  129. package/dist/utils/onAddSun.js +2 -0
  130. package/dist/utils/onAddSun.js.map +7 -0
  131. package/dist/utils/onClick.js +2 -0
  132. package/dist/utils/onClick.js.map +7 -0
  133. package/dist/utils/onMapChange.js +2 -0
  134. package/dist/utils/onMapChange.js.map +7 -0
  135. package/dist/utils/onPMTileAdd.js +2 -0
  136. package/dist/utils/onPMTileAdd.js.map +7 -0
  137. package/dist/utils/onPMTileRemove.js +2 -0
  138. package/dist/utils/onPMTileRemove.js.map +7 -0
  139. package/dist/utils/onPointerLeave.js +2 -0
  140. package/dist/utils/onPointerLeave.js.map +7 -0
  141. package/dist/utils/onPointerMove.js +2 -0
  142. package/dist/utils/onPointerMove.js.map +7 -0
  143. package/dist/utils/onRemove3DLayer.js +2 -0
  144. package/dist/utils/onRemove3DLayer.js.map +7 -0
  145. package/dist/utils/onRemoveSun.js +2 -0
  146. package/dist/utils/onRemoveSun.js.map +7 -0
  147. package/dist/utils/onTerrainAdd.js +2 -0
  148. package/dist/utils/onTerrainAdd.js.map +7 -0
  149. package/dist/utils/onTerrainChange.js +2 -0
  150. package/dist/utils/onTerrainChange.js.map +7 -0
  151. package/dist/utils/onTerrainRemove.js +2 -0
  152. package/dist/utils/onTerrainRemove.js.map +7 -0
  153. package/dist/utils/onZoomAnim.js +2 -0
  154. package/dist/utils/onZoomAnim.js.map +7 -0
  155. package/dist/utils/paints.js +2 -0
  156. package/dist/utils/paints.js.map +7 -0
  157. package/dist/utils/parseColor.js +2 -0
  158. package/dist/utils/parseColor.js.map +7 -0
  159. package/dist/utils/parts.js +2 -0
  160. package/dist/utils/parts.js.map +7 -0
  161. package/dist/utils/projectCelestialBody.js +2 -0
  162. package/dist/utils/projectCelestialBody.js.map +7 -0
  163. package/dist/utils/pump.js +2 -0
  164. package/dist/utils/pump.js.map +7 -0
  165. package/dist/utils/rasterTiles.js +2 -0
  166. package/dist/utils/rasterTiles.js.map +7 -0
  167. package/dist/utils/raycast.js +2 -0
  168. package/dist/utils/raycast.js.map +7 -0
  169. package/dist/utils/read.js +2 -0
  170. package/dist/utils/read.js.map +7 -0
  171. package/dist/utils/readAccessor.js +2 -0
  172. package/dist/utils/readAccessor.js.map +7 -0
  173. package/dist/utils/releaseArea.js +2 -0
  174. package/dist/utils/releaseArea.js.map +7 -0
  175. package/dist/utils/removeRasterTile.js +2 -0
  176. package/dist/utils/removeRasterTile.js.map +7 -0
  177. package/dist/utils/render.js +15 -0
  178. package/dist/utils/render.js.map +7 -0
  179. package/dist/utils/renderSunlight.js +13 -0
  180. package/dist/utils/renderSunlight.js.map +7 -0
  181. package/dist/utils/renderers.js +2 -0
  182. package/dist/utils/renderers.js.map +7 -0
  183. package/dist/utils/resizeSunlight.js +2 -0
  184. package/dist/utils/resizeSunlight.js.map +7 -0
  185. package/dist/utils/roofCoverage.js +2 -0
  186. package/dist/utils/roofCoverage.js.map +7 -0
  187. package/dist/utils/routeGeometry.js +2 -0
  188. package/dist/utils/routeGeometry.js.map +7 -0
  189. package/dist/utils/scheduledTrips.js +2 -0
  190. package/dist/utils/scheduledTrips.js.map +7 -0
  191. package/dist/utils/setGeoJSONData.js +2 -0
  192. package/dist/utils/setGeoJSONData.js.map +7 -0
  193. package/dist/utils/setHighlight.js +2 -0
  194. package/dist/utils/setHighlight.js.map +7 -0
  195. package/dist/utils/setPMTileOpacity.js +2 -0
  196. package/dist/utils/setPMTileOpacity.js.map +7 -0
  197. package/dist/utils/setPMTileZIndex.js +2 -0
  198. package/dist/utils/setPMTileZIndex.js.map +7 -0
  199. package/dist/utils/setParent.js +2 -0
  200. package/dist/utils/setParent.js.map +7 -0
  201. package/dist/utils/setTerrainHeight.js +2 -0
  202. package/dist/utils/setTerrainHeight.js.map +7 -0
  203. package/dist/utils/setVertexColor.js +2 -0
  204. package/dist/utils/setVertexColor.js.map +7 -0
  205. package/dist/utils/showFeature.js +2 -0
  206. package/dist/utils/showFeature.js.map +7 -0
  207. package/dist/utils/sizes.js +2 -0
  208. package/dist/utils/sizes.js.map +7 -0
  209. package/dist/utils/skin.js +2 -0
  210. package/dist/utils/skin.js.map +7 -0
  211. package/dist/utils/solarPosition.js +2 -0
  212. package/dist/utils/solarPosition.js.map +7 -0
  213. package/dist/utils/sortMeshes.js +2 -0
  214. package/dist/utils/sortMeshes.js.map +7 -0
  215. package/dist/utils/speed.js +2 -0
  216. package/dist/utils/speed.js.map +7 -0
  217. package/dist/utils/startZoom.js +2 -0
  218. package/dist/utils/startZoom.js.map +7 -0
  219. package/dist/utils/taillight.js +2 -0
  220. package/dist/utils/taillight.js.map +7 -0
  221. package/dist/utils/terrainAtlas.js +2 -0
  222. package/dist/utils/terrainAtlas.js.map +7 -0
  223. package/dist/utils/terrainElevation.js +2 -0
  224. package/dist/utils/terrainElevation.js.map +7 -0
  225. package/dist/utils/terrainGrid.js +2 -0
  226. package/dist/utils/terrainGrid.js.map +7 -0
  227. package/dist/utils/textureSampler.js +2 -0
  228. package/dist/utils/textureSampler.js.map +7 -0
  229. package/dist/utils/tileId.js +2 -0
  230. package/dist/utils/tileId.js.map +7 -0
  231. package/dist/utils/toLanes.js +2 -0
  232. package/dist/utils/toLanes.js.map +7 -0
  233. package/dist/utils/toSRGB.js +2 -0
  234. package/dist/utils/toSRGB.js.map +7 -0
  235. package/dist/utils/tooltip.js +3 -0
  236. package/dist/utils/tooltip.js.map +7 -0
  237. package/dist/utils/traffic.js +1 -1
  238. package/dist/utils/traffic.js.map +3 -3
  239. package/dist/utils/traverse.js +2 -0
  240. package/dist/utils/traverse.js.map +7 -0
  241. package/dist/utils/treeGeometry.js +2 -0
  242. package/dist/utils/treeGeometry.js.map +7 -0
  243. package/dist/utils/triangulate.js +2 -0
  244. package/dist/utils/triangulate.js.map +7 -0
  245. package/dist/utils/tripsAt.js +2 -0
  246. package/dist/utils/tripsAt.js.map +7 -0
  247. package/dist/utils/types.js +2 -0
  248. package/dist/utils/types.js.map +7 -0
  249. package/dist/utils/underEntry.js +2 -0
  250. package/dist/utils/underEntry.js.map +7 -0
  251. package/dist/utils/update.js +2 -0
  252. package/dist/utils/update.js.map +7 -0
  253. package/dist/utils/updateArea.js +2 -0
  254. package/dist/utils/updateArea.js.map +7 -0
  255. package/dist/utils/updateCamera.js +2 -0
  256. package/dist/utils/updateCamera.js.map +7 -0
  257. package/dist/utils/updatePointLights.js +2 -0
  258. package/dist/utils/updatePointLights.js.map +7 -0
  259. package/dist/utils/updateWorldMatrix.js +2 -0
  260. package/dist/utils/updateWorldMatrix.js.map +7 -0
  261. package/dist/utils/vehicleOffsets.js +2 -0
  262. package/dist/utils/vehicleOffsets.js.map +7 -0
  263. package/dist/utils/vehicles.js +1 -1
  264. package/dist/utils/vehicles.js.map +3 -3
  265. package/dist/utils/vertexNormals.js +2 -0
  266. package/dist/utils/vertexNormals.js.map +7 -0
  267. package/dist/utils/walk.js +1 -1
  268. package/dist/utils/walk.js.map +3 -3
  269. package/dist/utils/white.js +2 -0
  270. package/dist/utils/white.js.map +7 -0
  271. package/dist/utils/worldLights.js +2 -0
  272. package/dist/utils/worldLights.js.map +7 -0
  273. package/dist/utils/wrap.js +2 -0
  274. package/dist/utils/wrap.js.map +7 -0
  275. package/package.json +2 -4
  276. package/src/index.js +365 -50
  277. package/src/utils/CELL.js +4 -0
  278. package/src/utils/addBridges.js +66 -0
  279. package/src/utils/addRasterTile.js +112 -0
  280. package/src/utils/along.js +9 -0
  281. package/src/utils/atmosphere.js +20 -0
  282. package/src/utils/attach.js +255 -0
  283. package/src/utils/bindSunlight.js +12 -0
  284. package/src/utils/box.js +1 -0
  285. package/src/utils/bridgeElevation.js +18 -0
  286. package/src/utils/build.js +20 -0
  287. package/src/utils/cameraControls.js +287 -0
  288. package/src/utils/channel.js +4 -0
  289. package/src/utils/collider.js +62 -0
  290. package/src/utils/colliders.js +2 -0
  291. package/src/utils/computeBounds.js +17 -0
  292. package/src/utils/conformModelToTerrain.js +69 -0
  293. package/src/utils/createMesh.js +31 -0
  294. package/src/utils/createProgram.js +92 -0
  295. package/src/utils/decodeDirectory.js +40 -0
  296. package/src/utils/decodeHeader.js +15 -0
  297. package/src/utils/decodeModel.js +43 -0
  298. package/src/utils/decompress.js +5 -0
  299. package/src/utils/destroyTexture.js +7 -0
  300. package/src/utils/disposeMesh.js +13 -0
  301. package/src/utils/drawGeometry.js +122 -0
  302. package/src/utils/elevationWGSL.js +27 -0
  303. package/src/utils/emptyNode.js +9 -0
  304. package/src/utils/endZoom.js +15 -0
  305. package/src/utils/findFeature.js +49 -0
  306. package/src/utils/geometry.js +0 -254
  307. package/src/utils/getElevation.js +10 -0
  308. package/src/utils/getHeader.js +9 -0
  309. package/src/utils/getZxy.js +76 -0
  310. package/src/utils/glass.js +1 -0
  311. package/src/utils/headlight.js +1 -0
  312. package/src/utils/hit.js +41 -0
  313. package/src/utils/horizontalPosition.js +16 -0
  314. package/src/utils/horizontalRay.js +12 -0
  315. package/src/utils/hull.js +1 -0
  316. package/src/utils/initSunlight.js +9 -0
  317. package/src/utils/initTerrain.js +19 -0
  318. package/src/utils/initTraffic.js +93 -0
  319. package/src/utils/initWalk.js +72 -0
  320. package/src/utils/{picking.js → intersectMeshes.js} +121 -119
  321. package/src/utils/isClockWise.js +12 -0
  322. package/src/utils/lampPostGeometry.js +26 -0
  323. package/src/utils/lightGeometry.js +22 -0
  324. package/src/utils/{lighting.js → lightGrid.js} +50 -51
  325. package/src/utils/limbs.js +9 -0
  326. package/src/{scene/model.js → utils/loadModel.js} +37 -24
  327. package/src/utils/loadSource.js +17 -0
  328. package/src/utils/loadTerrain.js +65 -0
  329. package/src/utils/mapCamera.js +432 -0
  330. package/src/utils/{shaders.js → materialShaders.js} +243 -237
  331. package/src/utils/mirror.js +6 -0
  332. package/src/utils/moonPosition.js +17 -0
  333. package/src/utils/moves.js +11 -0
  334. package/src/utils/nativeEvents.js +77 -0
  335. package/src/utils/nativeGeometry.js +131 -0
  336. package/src/utils/nativeLayer.js +317 -0
  337. package/src/utils/nodeMatrix.js +22 -0
  338. package/src/utils/onAdd3DLayer.js +31 -0
  339. package/src/utils/onAddSun.js +147 -0
  340. package/src/utils/onClick.js +13 -0
  341. package/src/utils/onMapChange.js +16 -0
  342. package/src/utils/onPMTileAdd.js +15 -0
  343. package/src/utils/onPMTileRemove.js +8 -0
  344. package/src/utils/onPointerLeave.js +11 -0
  345. package/src/utils/onPointerMove.js +15 -0
  346. package/src/utils/onRemove3DLayer.js +78 -0
  347. package/src/utils/onRemoveSun.js +3 -0
  348. package/src/utils/onTerrainAdd.js +18 -0
  349. package/src/utils/onTerrainChange.js +13 -0
  350. package/src/utils/onTerrainRemove.js +40 -0
  351. package/src/utils/onZoomAnim.js +14 -0
  352. package/src/utils/paints.js +10 -0
  353. package/src/utils/parseColor.js +42 -0
  354. package/src/utils/parts.js +16 -0
  355. package/src/utils/projectCelestialBody.js +13 -0
  356. package/src/{scene/sources.js → utils/pump.js} +59 -98
  357. package/src/utils/rasterTiles.js +285 -0
  358. package/src/utils/raycast.js +60 -0
  359. package/src/utils/read.js +29 -0
  360. package/src/utils/readAccessor.js +68 -0
  361. package/src/utils/releaseArea.js +34 -0
  362. package/src/utils/removeRasterTile.js +13 -0
  363. package/src/{scene → utils}/render.js +112 -173
  364. package/src/utils/renderSunlight.js +170 -0
  365. package/src/utils/renderers.js +2 -0
  366. package/src/utils/resizeSunlight.js +15 -0
  367. package/src/utils/roofCoverage.js +47 -0
  368. package/src/utils/routeGeometry.js +22 -0
  369. package/src/utils/scheduledTrips.js +29 -0
  370. package/src/utils/setGeoJSONData.js +11 -0
  371. package/src/utils/setHighlight.js +13 -0
  372. package/src/utils/setPMTileOpacity.js +7 -0
  373. package/src/utils/setPMTileZIndex.js +7 -0
  374. package/src/utils/setParent.js +7 -0
  375. package/src/utils/setTerrainHeight.js +10 -0
  376. package/src/utils/setVertexColor.js +14 -0
  377. package/src/utils/showFeature.js +27 -0
  378. package/src/utils/sizes.js +1 -0
  379. package/src/utils/skin.js +2 -0
  380. package/src/utils/solarPosition.js +17 -0
  381. package/src/utils/sortMeshes.js +12 -0
  382. package/src/utils/speed.js +3 -0
  383. package/src/utils/startZoom.js +5 -0
  384. package/src/utils/taillight.js +1 -0
  385. package/src/utils/terrainAtlas.js +21 -0
  386. package/src/utils/terrainElevation.js +20 -0
  387. package/src/utils/terrainGrid.js +23 -0
  388. package/src/utils/textureSampler.js +10 -0
  389. package/src/utils/tileId.js +18 -0
  390. package/src/utils/toLanes.js +7 -0
  391. package/src/utils/toSRGB.js +1 -0
  392. package/src/utils/tooltip.js +6 -0
  393. package/src/utils/traffic.js +310 -85
  394. package/src/utils/traverse.js +6 -0
  395. package/src/utils/treeGeometry.js +45 -0
  396. package/src/utils/triangulate.js +100 -0
  397. package/src/utils/tripsAt.js +16 -0
  398. package/src/utils/types.js +8 -0
  399. package/src/utils/{control.js → underEntry.js} +1 -2
  400. package/src/utils/update.js +18 -0
  401. package/src/utils/updateArea.js +40 -0
  402. package/src/utils/updateCamera.js +32 -0
  403. package/src/utils/updatePointLights.js +38 -0
  404. package/src/utils/updateWorldMatrix.js +47 -0
  405. package/src/utils/vehicleOffsets.js +8 -0
  406. package/src/utils/vehicles.js +65 -69
  407. package/src/utils/vertexNormals.js +30 -0
  408. package/src/utils/walk.js +181 -66
  409. package/src/utils/white.js +1 -0
  410. package/src/utils/worldLights.js +25 -0
  411. package/src/utils/wrap.js +1 -0
  412. package/dist/scene/gpu.js +0 -3
  413. package/dist/scene/gpu.js.map +0 -7
  414. package/dist/scene/lighting.js +0 -9
  415. package/dist/scene/lighting.js.map +0 -7
  416. package/dist/scene/model.js +0 -2
  417. package/dist/scene/model.js.map +0 -7
  418. package/dist/scene/picking.js +0 -2
  419. package/dist/scene/picking.js.map +0 -7
  420. package/dist/scene/pmtiles.js +0 -2
  421. package/dist/scene/pmtiles.js.map +0 -7
  422. package/dist/scene/render.js +0 -15
  423. package/dist/scene/render.js.map +0 -7
  424. package/dist/scene/sources.js +0 -2
  425. package/dist/scene/sources.js.map +0 -7
  426. package/dist/types/3d.js +0 -2
  427. package/dist/types/3d.js.map +0 -7
  428. package/dist/types/geojson.js +0 -2
  429. package/dist/types/geojson.js.map +0 -7
  430. package/dist/types/pmtiles.js +0 -2
  431. package/dist/types/pmtiles.js.map +0 -7
  432. package/dist/types/sunlight.js +0 -2
  433. package/dist/types/sunlight.js.map +0 -7
  434. package/dist/types/terrain.js +0 -24
  435. package/dist/types/terrain.js.map +0 -7
  436. package/dist/types/traffic.js +0 -41
  437. package/dist/types/traffic.js.map +0 -7
  438. package/dist/types/walk.js +0 -2
  439. package/dist/types/walk.js.map +0 -7
  440. package/dist/utils/control.js +0 -2
  441. package/dist/utils/control.js.map +0 -7
  442. package/dist/utils/lighting.js +0 -2
  443. package/dist/utils/lighting.js.map +0 -7
  444. package/dist/utils/model.js +0 -2
  445. package/dist/utils/model.js.map +0 -7
  446. package/dist/utils/picking.js +0 -2
  447. package/dist/utils/picking.js.map +0 -7
  448. package/dist/utils/pmtiles.js +0 -2
  449. package/dist/utils/pmtiles.js.map +0 -7
  450. package/dist/utils/scene.js +0 -2
  451. package/dist/utils/scene.js.map +0 -7
  452. package/dist/utils/shaders.js.map +0 -7
  453. package/dist/utils/sun.js +0 -2
  454. package/dist/utils/sun.js.map +0 -7
  455. package/dist/utils/terrain.js +0 -2
  456. package/dist/utils/terrain.js.map +0 -7
  457. package/src/scene/gpu.js +0 -438
  458. package/src/scene/lighting.js +0 -193
  459. package/src/scene/picking.js +0 -150
  460. package/src/scene/pmtiles.js +0 -94
  461. package/src/types/3d.js +0 -337
  462. package/src/types/geojson.js +0 -42
  463. package/src/types/pmtiles.js +0 -143
  464. package/src/types/sunlight.js +0 -142
  465. package/src/types/terrain.js +0 -331
  466. package/src/types/traffic.js +0 -356
  467. package/src/types/walk.js +0 -219
  468. package/src/utils/model.js +0 -178
  469. package/src/utils/pmtiles.js +0 -79
  470. package/src/utils/scene.js +0 -102
  471. package/src/utils/sun.js +0 -71
  472. package/src/utils/terrain.js +0 -78
@@ -1,79 +1,39 @@
1
- import { computeBounds } from '../utils/geometry.js';
2
- import { traverse, updateWorldMatrix, updateCamera } from '../utils/scene.js';
3
-
4
- /** Scene graph, shared camera and frame rendering. */
5
- /** Content changes: render once on the next animation frame. */
6
- export function update(backend) {
7
- const shared = backend._shared;
8
- if (!shared) return backend;
9
- if (shared !== backend) {
10
- shared.update();
11
- return backend;
12
- }
13
- backend._frame ||= requestAnimationFrame(() => {
14
- backend._frame = null;
15
- if (backend._shared === backend && backend.renderer) backend._render();
16
- });
17
- return backend;
18
- }
19
-
20
- /** Map movement: render within the frame of Leaflet's CSS transforms, coalescing same-tick events. */
21
- export function onMapChange(backend) {
22
- if (backend._queued) return;
23
- backend._queued = true;
24
- queueMicrotask(() => {
25
- backend._queued = false;
26
- if (backend._shared !== backend || !backend.renderer) return;
27
- if (backend._map._animatingZoom) backend.update();
28
- else backend._render();
29
- });
30
- }
31
-
32
- /** Find a raster tile's active CSS level to reproduce Leaflet's animated scale/rounding. */
33
- export function getTileLevel(backend) {
34
- let level;
35
- backend._map.eachLayer(layer => {
36
- if (!level && layer instanceof L.TileLayer && layer._levels) {
37
- level = layer._levels[layer._tileZoom];
38
- }
39
- });
40
- return level;
41
- }
42
-
43
- /** Preserve the outgoing tile level before Leaflet changes its logical zoom. */
44
- export function startZoom(backend) {
45
- backend._zoomLevel = backend._getTileLevel();
46
- }
47
-
48
- /** Stop using the outgoing level after zoomend; the next redraw uses current tiles. */
49
- export function endZoom(backend) {
50
- for (const animation of backend._zoomTransitions?.keys() || []) animation.finish();
51
- backend._zoomTransitions = null;
52
- backend._zoomLevel = null;
53
- backend.update();
54
- }
1
+ import { computeBounds } from "./computeBounds.js";
2
+ import { traverse } from "./traverse.js";
3
+ import { updateCamera } from "./updateCamera.js";
4
+ import { updateWorldMatrix } from "./updateWorldMatrix.js";
5
+ import { destroyTexture } from './destroyTexture.js';
6
+ import { drawGeometry } from './drawGeometry.js';
7
+ import { updatePointLights } from './updatePointLights.js';
8
+ import { renderSunlight } from './renderSunlight.js';
9
+ import { sortMeshes } from "./sortMeshes.js";
10
+ import { update } from "./update.js";
11
+ import { getRasterTileSize, pruneRasterTiles } from "./rasterTiles.js";
12
+ import { getElevation } from "./getElevation.js";
13
+ import { roofCoverage } from "./roofCoverage.js";
55
14
 
56
15
  /**
57
16
  * Rendering owner: CSS pixels -> scene metres -> perspective camera.
58
17
  * Lights and transparent sort centers are converted into the current camera space.
59
18
  * Without raster tiles, logical map projection supplies the same static alignment.
60
19
  */
20
+
61
21
  export function render(backend) {
62
22
  cancelAnimationFrame(backend._frame);
63
23
  backend._frame = null;
64
24
  if (backend._shared !== backend || !backend.renderer) return;
65
25
  const map = backend._map;
26
+ const now = performance.now();
27
+ let appearing = false;
66
28
  const size = map.getSize();
67
29
  if (!size.x || !size.y) return;
68
30
  if (map._animatingZoom) {
69
31
  backend._zoomTransitions ||= new Map();
70
- const now = performance.now();
71
32
  for (const animation of map.getContainer().getAnimations({ subtree: true })) {
72
33
  if (!(animation instanceof CSSTransition) || animation.transitionProperty !== 'transform' ||
73
34
  !animation.effect.target.classList.contains('leaflet-zoom-animated') ||
74
- backend._zoomTransitions.has(animation)
75
- ) {
76
- continue;
35
+ backend._zoomTransitions.has(animation)) {
36
+ continue;
77
37
  }
78
38
  const time = animation.currentTime || 0;
79
39
  animation.pause();
@@ -83,44 +43,42 @@ export function render(backend) {
83
43
  for (const [animation, { start, time }] of backend._zoomTransitions) {
84
44
  animation.currentTime = Math.min(animation.effect.getComputedTiming().endTime, time + now - start);
85
45
  }
46
+ if (backend._zoomView) {
47
+ const view = backend._zoomView;
48
+ const proxy = [...backend._zoomTransitions.keys()].find(animation => animation.effect.target === map._proxy);
49
+ const progress = proxy?.effect.getComputedTiming().progress ?? Math.min(1, (now - view.start) / 250);
50
+ const targetScale = map.getZoomScale(view.targetZoom, view.zoom), scale = 1 + (targetScale - 1) * progress;
51
+ const from = map.project(view.from, view.zoom), to = map.project(view.to, view.zoom);
52
+ map._cameraView = { zoom: map.getScaleZoom(scale, view.zoom),
53
+ center: map.unproject(from.add(to.subtract(from).multiplyBy(targetScale * progress / scale)), view.zoom) };
54
+ map._updateCameraOverlays();
55
+ }
86
56
  }
87
57
  if (!backend._size || !backend._size.equals(size)) {
88
- backend.renderer.width = size.x;
89
- backend.renderer.height = size.y;
90
- backend.renderer.canvas.width = Math.round(size.x * backend.renderer.dpr);
91
- backend.renderer.canvas.height = Math.round(size.y * backend.renderer.dpr);
92
- backend.renderer.canvas.style.width = `${size.x}px`;
58
+ backend.renderer.width = size.x;
59
+ backend.renderer.height = size.y;
60
+ backend.renderer.canvas.width = Math.round(size.x * backend.renderer.dpr);
61
+ backend.renderer.canvas.height = Math.round(size.y * backend.renderer.dpr);
62
+ backend.renderer.canvas.style.width = `${size.x}px`;
93
63
  backend.renderer.canvas.style.height = `${size.y}px`;
94
- if (backend.renderer.depthTexture) backend._destroyTexture(backend.renderer.depthTexture);
64
+ if (backend.renderer.depthTexture) destroyTexture(backend, backend.renderer.depthTexture);
95
65
  backend.renderer.depthTexture = backend.renderer.device.createTexture({
96
66
  size: [backend.renderer.canvas.width, backend.renderer.canvas.height],
97
67
  format: 'depth24plus',
98
68
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
99
69
  });
100
- backend._size = size;
70
+ backend._size = size;
101
71
  }
102
72
 
103
- // Match the map's CSS camera: a perspective distance of 1.5 viewport heights.
104
- let pixelsPerMeter = map.options.crs.scale(map.getZoom()) / (40075016.68557849 * Math.cos(backend._sceneOrigin.lat * Math.PI / 180));
105
- let origin = map.project(backend._sceneOrigin).subtract(map.getPixelOrigin());
106
- const level = backend._zoomLevel?.el.isConnected ? backend._zoomLevel : backend._getTileLevel();
107
- if (level && map._animatingZoom) {
108
- backend._zoomLevel = level;
109
- }
110
- // Leaflet's logical zoom jumps before its tile CSS transition finishes.
111
- // Use the rendered tile transform, including its rounding, on every animation frame.
112
- if (level) {
113
- const transform = new DOMMatrix(map._animatingZoom ? getComputedStyle(level.el).transform : level.el.style.transform);
114
- const point = map.project(backend._sceneOrigin, level.zoom).subtract(level.origin);
115
- origin = new L.Point(point.x * transform.a + transform.e, point.y * transform.d + transform.f);
116
- pixelsPerMeter *= map.getZoomScale(level.zoom, map.getZoom()) * transform.a;
117
- }
73
+ // Match the map's perspective, including the intermediate view of an animated zoom.
74
+ const zoom = map._cameraView?.zoom ?? map.getZoom(), center = map._cameraView?.center ?? map.getCenter();
75
+ const pixelsPerMeter = map.options.crs.scale(zoom) / (40075016.68557849 * Math.cos(backend._sceneOrigin.lat * Math.PI / 180));
76
+ const offset = map.project(center, zoom).subtract(map.project(backend._sceneOrigin, zoom));
118
77
  const distance = size.y * 1.5 / pixelsPerMeter;
119
- const center = map.containerPointToLayerPoint(size.divideBy(2));
120
- const target = [
121
- (center.x - origin.x) / pixelsPerMeter,
122
- map._terrain3D?._getElevation(map.getCenter()) ?? 0,
123
- (center.y - origin.y) / pixelsPerMeter
78
+ const target = [
79
+ offset.x / pixelsPerMeter,
80
+ (map._terrain3D ? getElevation(map._terrain3D, center): undefined) ?? 0,
81
+ offset.y / pixelsPerMeter
124
82
  ];
125
83
  const pitch = map.getPitch() * Math.PI / 180;
126
84
  const bearing = map.getBearing() * Math.PI / 180;
@@ -138,6 +96,8 @@ export function render(backend) {
138
96
  camera.target[0] = target[0]; camera.target[1] = target[1]; camera.target[2] = target[2];
139
97
  // Refresh the camera view, projection and combined projection-view matrices.
140
98
  updateCamera(camera);
99
+ updateWorldMatrix(backend.scene);
100
+ for (const layer of backend._layers) layer._beforeRender?.();
141
101
  const sunlight = map._sunlight;
142
102
  const lightPoint = new DOMPoint(...(sunlight?.direction || [-300, 500, 300]), 0).matrixTransform(new DOMMatrix(camera.viewMatrix));
143
103
  const lightLength = Math.hypot(lightPoint.x, lightPoint.y, lightPoint.z) || 1;
@@ -173,6 +133,9 @@ export function render(backend) {
173
133
  const x = world[0] * center[0] + world[4] * center[1] + world[8] * center[2] + world[12];
174
134
  const y = world[1] * center[0] + world[5] * center[1] + world[9] * center[2] + world[13];
175
135
  const z = world[2] * center[0] + world[6] * center[1] + world[10] * center[2] + world[14];
136
+ const clipZ = projection[2] * x + projection[6] * y + projection[10] * z + projection[14];
137
+ const clipW = projection[3] * x + projection[7] * y + projection[11] * z + projection[15];
138
+ mesh._sortDepth = clipZ / clipW;
176
139
  const radius = bounds.radius * Math.max(
177
140
  Math.hypot(world[0], world[1], world[2]),
178
141
  Math.hypot(world[4], world[5], world[6]),
@@ -187,46 +150,32 @@ export function render(backend) {
187
150
  frustum[5][0] * x + frustum[5][1] * y + frustum[5][2] * z + frustum[5][3] >= -radius * frustumLengths[5];
188
151
  if (!mesh._visibleInFrame) return;
189
152
  }
190
- if (mesh.program?.transparent) {
191
- if (!mesh.geometry.bounds) computeBounds(mesh.geometry);
192
- const center = mesh.geometry.bounds.center, world = mesh.worldMatrix;
193
- const x = world[0] * center[0] + world[4] * center[1] + world[8] * center[2] + world[12];
194
- const y = world[1] * center[0] + world[5] * center[1] + world[9] * center[2] + world[13];
195
- const z = world[2] * center[0] + world[6] * center[1] + world[10] * center[2] + world[14];
196
- const projection = camera.projectionViewMatrix;
197
- const clipZ = projection[2] * x + projection[6] * y + projection[10] * z + projection[14];
198
- const clipW = projection[3] * x + projection[7] * y + projection[11] * z + projection[15];
199
- mesh._sortDepth = clipZ / clipW;
200
- }
201
153
  });
202
154
  const renderer = backend.renderer;
155
+ let rasters = [];
203
156
  if ([...backend._layers].some(layer => layer.options.roofTexture)) {
204
- const rasters = Object.values(map._layers).filter(layer =>
205
- layer instanceof L.Layer.types.pmtiles && layer._tiles && layer.options.opacity > 0);
206
- const tiles = rasters.flatMap(layer => Object.values(layer._tiles)
207
- .filter(tile => tile.el.done && !tile.el.request.signal.aborted && tile.el.isConnected)
208
- .map(tile => ({ ...tile, layer })));
209
- const signature = tiles.map(({ el, coords, layer }) =>
210
- `${L.Util.stamp(el)}:${coords.z}:${coords.x}:${coords.y}:${layer.options.opacity}:${layer.options.zIndex}`).join('|');
211
- const selection = rasters.map(layer =>
212
- `${L.Util.stamp(layer)}:${layer.options.opacity}:${layer.options.zIndex}`).join('|');
213
- // Retain the geographically aligned atlas until a tile batch finishes loading.
214
- if (!backend._roofRaster || backend._roofRaster.selection !== selection ||
215
- (!rasters.some(layer => layer.isLoading()) && backend._roofRaster.signature !== signature)) {
216
- const zoom = tiles.length ? Math.max(...tiles.map(tile => tile.coords.z)) : map.getZoom();
157
+ rasters = Object.values(map._layers).filter(layer => layer._type === 'pmtiles' && layer._rasterTiles && layer.options.opacity > 0);
158
+ const signature = rasters.map(layer =>
159
+ `${L.Util.stamp(layer)}:${layer._rasterVersion || 0}:${layer.options.opacity}:${layer.options.zIndex}`).join('|');
160
+ if (!backend._roofRaster || backend._roofRaster.signature !== signature &&
161
+ (!rasters.some(layer => layer._loadingTiles) || now - backend._roofRaster.updatedAt >= 50)) {
162
+ const tiles = rasters.flatMap(layer => [...layer._rasterTiles.values()]
163
+ .filter(tile => tile.done && !tile.request.signal.aborted && tile.image)
164
+ .map(tile => ({ tile, layer })));
165
+ const zoom = tiles.length ? Math.max(...tiles.map(({ tile }) => tile.coords.z)) : map.getZoom();
217
166
  const bounds = new L.Bounds();
218
- for (const { coords, layer } of tiles) {
219
- const size = layer.getTileSize().multiplyBy(map.getZoomScale(zoom, coords.z));
167
+ for (const { tile: { coords }, layer } of tiles) {
168
+ const size = getRasterTileSize().multiplyBy(map.getZoomScale(zoom, coords.z));
220
169
  bounds.extend(new L.Point(coords.x, coords.y).scaleBy(size));
221
170
  bounds.extend(new L.Point(coords.x + 1, coords.y + 1).scaleBy(size));
222
171
  }
223
172
  const min = bounds.min || map.project(backend._sceneOrigin, zoom);
224
173
  const size = bounds.isValid() ? bounds.getSize() : new L.Point(1, 1);
225
174
  // ponytail: cap at 4096 px; virtual textures if wide views need native detail.
226
- const limit = 4096;
227
- const scale = Math.min(1, limit / Math.max(size.x, size.y));
228
- const width = Math.max(1, Math.ceil(size.x * scale));
229
- const height = Math.max(1, Math.ceil(size.y * scale));
175
+ const limit = 4096;
176
+ const scale = Math.min(1, limit / Math.max(size.x, size.y));
177
+ const width = Math.max(1, Math.ceil(size.x * scale));
178
+ const height = Math.max(1, Math.ceil(size.y * scale));
230
179
  const origin = map.project(backend._sceneOrigin, zoom);
231
180
  const pixels = map.options.crs.scale(zoom) / (40075016.68557849 * Math.cos(backend._sceneOrigin.lat * Math.PI / 180));
232
181
  const matrix = new DOMMatrix();
@@ -234,7 +183,7 @@ export function render(backend) {
234
183
  matrix.m41 = (origin.x - min.x) / size.x; matrix.m43 = (origin.y - min.y) / size.y;
235
184
  const texture = backend._roofRaster?.texture;
236
185
  if (texture && (texture.width !== width || texture.height !== height)) {
237
- backend._destroyTexture(texture.texture);
186
+ destroyTexture(backend, texture.texture);
238
187
  texture.texture = renderer.device.createTexture({
239
188
  size: [width, height],
240
189
  format: 'rgba8unorm',
@@ -244,7 +193,7 @@ export function render(backend) {
244
193
  texture.height = height;
245
194
  }
246
195
  backend._roofRaster = {
247
- signature, selection, matrix: Array.from(matrix.toFloat64Array()),
196
+ signature, updatedAt: now, matrix: Array.from(matrix.toFloat64Array()),
248
197
  texture: texture || {
249
198
  device: renderer.device,
250
199
  texture: renderer.device.createTexture({
@@ -263,7 +212,8 @@ export function render(backend) {
263
212
  // Compose the atlas on the GPU: re-uploading a large canvas stalls Firefox for hundreds of ms.
264
213
  const device = renderer.device;
265
214
  if (!renderer.roofBlit) {
266
- const module = device.createShaderModule({ code: `
215
+ const module = device.createShaderModule({
216
+ code: `
267
217
  @group(0) @binding(0) var source: texture_2d<f32>;
268
218
  @group(0) @binding(1) var sourceSampler: sampler;
269
219
  @group(0) @binding(2) var<uniform> opacity: f32;
@@ -276,7 +226,8 @@ export function render(backend) {
276
226
  let color = textureSample(source, sourceSampler, input.uv);
277
227
  return vec4f(color.rgb, color.a * opacity);
278
228
  }
279
- ` });
229
+ `
230
+ });
280
231
  renderer.roofBlit = {
281
232
  pipeline: device.createRenderPipeline({
282
233
  layout: 'auto',
@@ -297,14 +248,6 @@ export function render(backend) {
297
248
  sampler: device.createSampler({ magFilter: 'linear', minFilter: 'linear' }),
298
249
  };
299
250
  }
300
- // Raster tiles keep their GPU copy; terrain meshes already own one for the same image.
301
- const roofTiles = backend._roofTiles ||= new Map();
302
- for (const [el, source] of roofTiles) {
303
- if (!tiles.some(tile => tile.el === el) || map._terrain3D?._rasterTiles.has(el)) {
304
- source.texture.destroy();
305
- roofTiles.delete(el);
306
- }
307
- }
308
251
  const opacities = new Float32Array(Math.max(1, tiles.length) * 64);
309
252
  const opacityBuffer = device.createBuffer({
310
253
  size: opacities.byteLength,
@@ -320,27 +263,18 @@ export function render(backend) {
320
263
  }],
321
264
  });
322
265
  atlasPass.setPipeline(renderer.roofBlit.pipeline);
323
- tiles.sort((a, b) => (a.layer.options.zIndex || 0) - (b.layer.options.zIndex || 0) || a.coords.z - b.coords.z);
324
- for (const [i, { coords, el, layer }] of tiles.entries()) {
325
- let source = map._terrain3D?._rasterTiles.get(el)?.texture || roofTiles.get(el);
326
- if (!source) {
327
- source = {
328
- texture: device.createTexture({
329
- size: [el.naturalWidth, el.naturalHeight],
330
- format: 'rgba8unorm',
331
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
332
- }),
333
- image: el, uploaded: null,
334
- };
335
- roofTiles.set(el, source);
336
- }
266
+ tiles.sort((a, b) => (a.layer.options.zIndex || 0) - (b.layer.options.zIndex || 0) ||
267
+ a.tile.coords.z - b.tile.coords.z);
268
+ for (const [i, { tile, layer }] of tiles.entries()) {
269
+ const { coords, image } = tile;
270
+ const source = tile.texture;
337
271
  if (source.uploaded !== source.image) {
338
- device.queue.copyExternalImageToTexture({ source: el }, { texture: source.texture },
272
+ device.queue.copyExternalImageToTexture({ source: image }, { texture: source.texture },
339
273
  [source.texture.width, source.texture.height]);
340
274
  source.uploaded = source.image;
341
275
  }
342
276
  opacities[i * 64] = layer.options.opacity;
343
- const tileSize = layer.getTileSize().multiplyBy(map.getZoomScale(zoom, coords.z));
277
+ const tileSize = getRasterTileSize().multiplyBy(map.getZoomScale(zoom, coords.z));
344
278
  const offset = new L.Point(coords.x, coords.y).scaleBy(tileSize).subtract(min);
345
279
  const x = offset.x * width / size.x, y = offset.y * height / size.y;
346
280
  atlasPass.setViewport(x, y, Math.min(tileSize.x * width / size.x, width - x),
@@ -361,36 +295,48 @@ export function render(backend) {
361
295
  opacityBuffer.destroy();
362
296
  }
363
297
  } else if (backend._roofRaster) {
364
- backend._destroyTexture(backend._roofRaster.texture.texture);
298
+ destroyTexture(backend, backend._roofRaster.texture.texture);
365
299
  backend._roofRaster = null;
366
- for (const source of backend._roofTiles?.values() || []) source.texture.destroy();
367
- backend._roofTiles = null;
368
300
  }
369
301
  // Visible meshes: opaque first, transparent surfaces back-to-front.
370
302
  const meshes = [];
371
- traverse(backend.scene, mesh => { if (!mesh.visible) return true; if (mesh.geometry && mesh._visibleInFrame) meshes.push(mesh); });
372
- meshes.sort((a, b) => Number(a.program.transparent) - Number(b.program.transparent) ||
373
- (a.program.transparent
374
- ? (a.renderOrder || 0) - (b.renderOrder || 0) ||
375
- b._sortDepth - a._sortDepth || a.id - b.id
376
- : a.id - b.id)
377
- );
303
+ traverse(backend.scene, mesh => {
304
+ if (!mesh.visible) return true;
305
+ if (!mesh.geometry || !mesh._visibleInFrame) return;
306
+ if (mesh.program.uniforms.roofTexture && !rasters.length) mesh._roofRevealed = true;
307
+ if (mesh.program.uniforms.roofTexture && !mesh._roofRevealed && rasters.length) {
308
+ if (mesh._roofCoverageSignature !== backend._roofRaster?.signature) {
309
+ mesh._roofCoverageSignature = backend._roofRaster?.signature;
310
+ mesh._roofCovered = roofCoverage(mesh, backend, rasters);
311
+ }
312
+ if (!mesh._roofCovered) { mesh._appearance = 0; return; }
313
+ mesh._roofRevealed = true;
314
+ }
315
+ if (mesh.fadeDuration) {
316
+ mesh.fadeStart ??= mesh.tile?.loadedAt ?? now;
317
+ const progress = Math.min(1, (now - mesh.fadeStart) / mesh.fadeDuration);
318
+ mesh._appearance = progress * progress * (3 - 2 * progress);
319
+ appearing ||= progress < 1;
320
+ }
321
+ meshes.push(mesh);
322
+ });
323
+ sortMeshes(meshes);
378
324
  const encoder = renderer.device.createCommandEncoder();
379
- const pendingRasterTiles = [];
380
325
  // One uniform upload per frame: per-mesh writeBuffer calls dominate Firefox's GPU process.
381
326
  // Slot 0 holds the camera; 256-byte mesh slots follow (double-sided meshes use two).
382
327
  const shadowMeshes = [];
383
328
  if (sunlight?.altitude >= 3) {
384
329
  for (const layer of backend._layers) {
385
- if (layer instanceof L.Layer.types.terrain) continue;
330
+ if (layer._type === 'terrain') continue;
386
331
  traverse(layer.root, mesh => {
387
332
  if (!mesh.visible) return true;
388
- if (mesh.geometry && !mesh.tile && !mesh.program.nightLight && mesh.program.depthTest !== false) shadowMeshes.push(mesh);
333
+ if (mesh.geometry && !mesh.tile && mesh._appearance !== 0 &&
334
+ !mesh.program.nightLight && mesh.program.depthTest !== false) shadowMeshes.push(mesh);
389
335
  });
390
336
  }
391
337
  }
392
338
  if (!renderer.uniformBuffer || renderer.uniformBuffer.size < (meshes.length * 2 + shadowMeshes.length + 1) * 256) {
393
- if (renderer.uniformBuffer) backend._destroyTexture(renderer.uniformBuffer);
339
+ if (renderer.uniformBuffer) destroyTexture(backend, renderer.uniformBuffer);
394
340
  renderer.uniformBuffer = renderer.device.createBuffer({
395
341
  size: Math.max(64, meshes.length * 4 + shadowMeshes.length * 2) * 256,
396
342
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
@@ -408,9 +354,9 @@ export function render(backend) {
408
354
  frameData[55] = night * night * (3 - 2 * night);
409
355
  frameData.set(sunlight?.tint || [1, 1, 1], 56);
410
356
  frameData[59] = 0;
411
- if (night > 0) backend._updatePointLights();
357
+ if (night > 0) updatePointLights(backend);
412
358
  renderer.uniformSlot = 1;
413
- backend._renderSunlight(encoder, shadowMeshes, sunlight);
359
+ renderSunlight(backend, encoder, shadowMeshes, sunlight);
414
360
  const pass = encoder.beginRenderPass({
415
361
  colorAttachments: [{
416
362
  view: renderer.context.getCurrentTexture().createView(),
@@ -428,7 +374,6 @@ export function render(backend) {
428
374
  pass.setViewport(0, 0, renderer.canvas.width, renderer.canvas.height, 0, 1);
429
375
  pass.setBindGroup(1, renderer.sunlight.bindGroup);
430
376
  for (const mesh of meshes) {
431
- if (mesh.tile && mesh.tile.style.visibility !== 'hidden') pendingRasterTiles.push(mesh.tile);
432
377
  const world = mesh.worldMatrix;
433
378
  if (mesh.texture) {
434
379
  mesh.program.uniforms.baseTexture.value = mesh.texture;
@@ -444,24 +389,18 @@ export function render(backend) {
444
389
  }
445
390
  const frontFace = determinant < 0 ? 'cw' : 'ccw';
446
391
  const program = mesh.program;
447
- if (program.transparent && program._layerMaterial.doubleSided) {
448
- backend._drawGeometry(mesh, pass, 'front', frontFace);
449
- backend._drawGeometry(mesh, pass, 'back', frontFace);
392
+ if (program.transparent && program._layerMaterial.doubleSided && !mesh._nativeSource) {
393
+ drawGeometry(backend, mesh, pass, 'front', frontFace);
394
+ drawGeometry(backend, mesh, pass, 'back', frontFace);
450
395
  } else {
451
- backend._drawGeometry(mesh, pass, program.cullMode, frontFace);
396
+ drawGeometry(backend, mesh, pass, program.cullMode, frontFace);
452
397
  }
453
398
  }
454
399
  pass.end();
455
400
  renderer.device.queue.writeBuffer(renderer.uniformBuffer, 0, renderer.uniformData, 0, renderer.uniformSlot * 64);
456
401
  renderer.device.queue.submit([encoder.finish()]);
457
- if (pendingRasterTiles.length) {
458
- renderer.device.queue.onSubmittedWorkDone().then(() => {
459
- for (const tile of pendingRasterTiles) {
460
- if (tile.isConnected && tile._terrainVisibility !== undefined) tile.style.visibility = 'hidden';
461
- }
462
- }, error => {
463
- for (const layer of backend._layers || []) layer.fire('error', { error });
464
- });
402
+ for (const layer of backend._layers) {
403
+ if (layer._wantedRasterTiles) appearing = pruneRasterTiles(layer) || appearing;
465
404
  }
466
- if (map._animatingZoom) backend.update();
405
+ if (map._animatingZoom || appearing) update(backend);
467
406
  }
@@ -0,0 +1,170 @@
1
+ import { computeBounds } from './computeBounds.js';
2
+ import { updateCamera } from './updateCamera.js';
3
+ import { resizeSunlight } from './resizeSunlight.js';
4
+
5
+ /** One shared directional depth map. Off-screen but loaded geometry can cast shadows. */
6
+
7
+ export function renderSunlight(backend, encoder, meshes, sunlight) {
8
+ const renderer = backend.renderer, device = renderer.device, sun = renderer.sunlight;
9
+ if (!meshes.length || !sunlight || sunlight.altitude < 3) {
10
+ if (!sun.enabled) return;
11
+ const values = new Float32Array(20);
12
+ values.set([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
13
+ device.queue.writeBuffer(sun.buffer, 0, values);
14
+ sun.enabled = false;
15
+ sun.cache = null;
16
+ return;
17
+ }
18
+ const cache = sun.cache;
19
+ const unchanged = sun.enabled && cache?.meshes.size === meshes.length &&
20
+ sunlight.direction.every((value, i) => value === cache.direction[i]) &&
21
+ meshes.every(mesh => {
22
+ const previous = cache.meshes.get(mesh), range = mesh.geometry.drawRange;
23
+ return previous && previous.world === mesh._worldMatrixVersion && previous.geometry === mesh.geometry &&
24
+ previous.start === range.start && previous.count === range.count &&
25
+ previous.appearance === (mesh._appearance ?? 1) &&
26
+ Object.values(mesh.geometry.attributes).every(attribute => !attribute.needsUpdate);
27
+ });
28
+ if (unchanged) return;
29
+ const values = new Float32Array(20);
30
+ sun.enabled = true;
31
+ resizeSunlight(backend, Math.min(2048, device.limits.maxTextureDimension2D));
32
+ const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
33
+ for (const mesh of meshes) {
34
+ if (!mesh.geometry.bounds || mesh.geometry.attributes.position.needsUpdate) computeBounds(mesh.geometry);
35
+ const bounds = mesh.geometry.bounds, matrix = mesh.worldMatrix;
36
+ let cached = mesh._shadowBounds;
37
+ if (!cached || cached.version !== mesh._worldMatrixVersion || cached.bounds !== bounds) {
38
+ cached = mesh._shadowBounds = { version: mesh._worldMatrixVersion, bounds,
39
+ min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] };
40
+ for (let i = 0; i < 8; i++) {
41
+ const x = i & 1 ? bounds.max[0] : bounds.min[0], y = i & 2 ? bounds.max[1] : bounds.min[1];
42
+ const z = i & 4 ? bounds.max[2] : bounds.min[2];
43
+ const w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
44
+ for (let axis = 0; axis < 3; axis++) {
45
+ const value = (matrix[axis] * x + matrix[axis + 4] * y + matrix[axis + 8] * z + matrix[axis + 12]) / w;
46
+ cached.min[axis] = Math.min(cached.min[axis], value);
47
+ cached.max[axis] = Math.max(cached.max[axis], value);
48
+ }
49
+ }
50
+ }
51
+ for (let axis = 0; axis < 3; axis++) {
52
+ min[axis] = Math.min(min[axis], cached.min[axis]);
53
+ max[axis] = Math.max(max[axis], cached.max[axis]);
54
+ }
55
+ }
56
+ // Include ground receivers below/around the loaded buildings and trees.
57
+ min[1] = Math.min(0, min[1]);
58
+ const radius = Math.max(100, Math.hypot(...min.map((v, i) => max[i] - v)));
59
+ const center = min.map((v, i) => (v + max[i]) / 2);
60
+ const lightCamera = {
61
+ position: center.map((v, i) => v + sunlight.direction[i] * radius * 2),
62
+ target: center, up: [0, 0, -1], fov: 45, aspect: 1, near: 1, far: radius * 5,
63
+ viewMatrix: [], projectionMatrix: [], projectionViewMatrix: [],
64
+ };
65
+ updateCamera(lightCamera);
66
+ const view = new DOMMatrix(lightCamera.viewMatrix);
67
+ const low = [Infinity, Infinity, Infinity], high = [-Infinity, -Infinity, -Infinity];
68
+ for (let i = 0; i < 8; i++) {
69
+ const point = new DOMPoint(...min.map((v, axis) => (i & (1 << axis)) ? max[axis] : v), 1).matrixTransform(view);
70
+ [point.x, point.y, point.z].forEach((value, axis) => {
71
+ low[axis] = Math.min(low[axis], value - 20);
72
+ high[axis] = Math.max(high[axis], value + 20);
73
+ });
74
+ }
75
+ const span = low.map((v, i) => high[i] - v);
76
+ const projection = new DOMMatrix([
77
+ 2 / span[0], 0, 0, 0, 0, 2 / span[1], 0, 0, 0, 0, -1 / span[2], 0,
78
+ -(high[0] + low[0]) / span[0], -(high[1] + low[1]) / span[1], high[2] / span[2], 1,
79
+ ]);
80
+ values.set(projection.multiply(view).toFloat32Array());
81
+ values[16] = 1;
82
+ device.queue.writeBuffer(sun.buffer, 0, values);
83
+ if (!sun.pipeline) {
84
+ sun.meshLayout = device.createBindGroupLayout({
85
+ entries: [
86
+ { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: 'uniform', hasDynamicOffset: true } },
87
+ ]
88
+ });
89
+ // Do not bind the sampled depth texture while it is a render attachment.
90
+ sun.depthLayout = device.createBindGroupLayout({
91
+ entries: [
92
+ { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
93
+ ]
94
+ });
95
+ sun.depthBindGroup = device.createBindGroup({
96
+ layout: sun.depthLayout, entries: [{ binding: 0, resource: { buffer: sun.buffer } }],
97
+ });
98
+ const shader = device.createShaderModule({
99
+ code: `
100
+ struct Mesh { world: mat4x4<f32>, padding: array<vec4<f32>, 4>, highlight: vec4<f32> };
101
+ @group(0) @binding(0) var<uniform> mesh: Mesh;
102
+ @group(1) @binding(0) var<uniform> matrix: mat4x4<f32>;
103
+ @vertex fn main(@location(0) position: vec3<f32>) -> @builtin(position) vec4<f32> {
104
+ return matrix * mesh.world * vec4<f32>(position, 1.0);
105
+ }
106
+ @fragment fn fragmentMain(@builtin(position) position: vec4<f32>) {
107
+ let noise = fract(52.9829189 * fract(dot(floor(position.xy), vec2<f32>(0.06711056, 0.00583715))));
108
+ if (mesh.highlight.w < 1.0 && noise >= mesh.highlight.w) { discard; }
109
+ }
110
+ ` });
111
+ sun.pipeline = device.createRenderPipeline({
112
+ layout: device.createPipelineLayout({ bindGroupLayouts: [sun.meshLayout, sun.depthLayout] }),
113
+ vertex: {
114
+ module: shader, entryPoint: 'main', buffers: [
115
+ { arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] },
116
+ ]
117
+ },
118
+ fragment: { module: shader, entryPoint: 'fragmentMain', targets: [] },
119
+ primitive: { topology: 'triangle-list', cullMode: 'none' },
120
+ depthStencil: {
121
+ format: 'depth32float', depthWriteEnabled: true, depthCompare: 'less',
122
+ depthBias: 2, depthBiasSlopeScale: 2
123
+ },
124
+ });
125
+ }
126
+ const pass = encoder.beginRenderPass({
127
+ colorAttachments: [],
128
+ depthStencilAttachment: {
129
+ view: sun.texture.createView(), depthClearValue: 1,
130
+ depthLoadOp: 'clear', depthStoreOp: 'store'
131
+ },
132
+ });
133
+ pass.setPipeline(sun.pipeline);
134
+ pass.setBindGroup(1, sun.depthBindGroup);
135
+ for (const mesh of meshes) {
136
+ const offset = renderer.uniformSlot++ * 256;
137
+ renderer.uniformData.set(mesh.worldMatrix, offset / 4);
138
+ renderer.uniformData[offset / 4 + 35] = mesh._appearance ?? 1;
139
+ if (mesh._shadowBuffer !== renderer.uniformBuffer) {
140
+ mesh._shadowBuffer = renderer.uniformBuffer;
141
+ mesh._shadowBindGroup = device.createBindGroup({
142
+ layout: sun.meshLayout, entries: [
143
+ { binding: 0, resource: { buffer: renderer.uniformBuffer, size: 144 } },
144
+ ]
145
+ });
146
+ }
147
+ for (const attribute of Object.values(mesh.geometry.attributes)) {
148
+ if (attribute.needsUpdate) {
149
+ device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
150
+ attribute.needsUpdate = false;
151
+ }
152
+ }
153
+ pass.setBindGroup(0, mesh._shadowBindGroup, [offset]);
154
+ pass.setVertexBuffer(0, mesh.geometry.attributes.position.buffer);
155
+ const index = mesh.geometry.attributes.index, range = mesh.geometry.drawRange;
156
+ if (index) {
157
+ pass.setIndexBuffer(index.buffer, index.indexFormat);
158
+ pass.drawIndexed(range.count, 1, range.start, 0, 0);
159
+ } else pass.draw(range.count, 1, range.start, 0);
160
+ }
161
+ pass.end();
162
+ sun.cache = {
163
+ direction: [...sunlight.direction],
164
+ meshes: new Map(meshes.map(mesh => [mesh, {
165
+ world: mesh._worldMatrixVersion, geometry: mesh.geometry,
166
+ start: mesh.geometry.drawRange.start, count: mesh.geometry.drawRange.count,
167
+ appearance: mesh._appearance ?? 1,
168
+ }])),
169
+ };
170
+ }
@@ -0,0 +1,2 @@
1
+ /** Rendering owner per map; entries are removed on the last layer removal. */
2
+ export const renderers = new WeakMap();
@@ -0,0 +1,15 @@
1
+ import { bindSunlight } from './bindSunlight.js';
2
+ import { destroyTexture } from './destroyTexture.js';
3
+
4
+
5
+ export function resizeSunlight(backend, size) {
6
+ const device = backend.renderer.device, sun = backend.renderer.sunlight;
7
+ if (sun.size === size) return;
8
+ if (sun.texture) destroyTexture(backend, sun.texture);
9
+ sun.size = size;
10
+ sun.texture = device.createTexture({
11
+ size: [size, size], format: 'depth32float',
12
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
13
+ });
14
+ bindSunlight(backend);
15
+ }