@navaramap/three 0.0.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 (350) hide show
  1. package/LICENSE +8 -0
  2. package/dist/assets/atmosphere/README.md +1 -0
  3. package/dist/assets/atmosphere/higher_order_scattering.bin +0 -0
  4. package/dist/assets/atmosphere/higher_order_scattering.exr +0 -0
  5. package/dist/assets/atmosphere/irradiance.bin +0 -0
  6. package/dist/assets/atmosphere/irradiance.exr +0 -0
  7. package/dist/assets/atmosphere/scattering.bin +0 -0
  8. package/dist/assets/atmosphere/scattering.exr +0 -0
  9. package/dist/assets/atmosphere/single_mie_scattering.bin +0 -0
  10. package/dist/assets/atmosphere/single_mie_scattering.exr +0 -0
  11. package/dist/assets/atmosphere/stars.bin +0 -0
  12. package/dist/assets/atmosphere/transmittance.bin +0 -0
  13. package/dist/assets/atmosphere/transmittance.exr +0 -0
  14. package/dist/assets/cloud/README.md +1 -0
  15. package/dist/assets/cloud/local_weather.png +0 -0
  16. package/dist/assets/cloud/shape.bin +1 -0
  17. package/dist/assets/cloud/shape_detail.bin +1 -0
  18. package/dist/assets/cloud/turbulence.png +0 -0
  19. package/dist/assets/fontWorker-CEJEfRpb.js +2 -0
  20. package/dist/assets/fontWorker-CEJEfRpb.js.map +1 -0
  21. package/dist/assets/index-BUB-ijMO.js +12 -0
  22. package/dist/assets/index-BUB-ijMO.js.map +1 -0
  23. package/dist/assets/navara_wasm_font_worker_bg-665OLxjy.wasm +0 -0
  24. package/dist/assets/navara_wasm_worker_bg-BXhKC5bE.wasm +0 -0
  25. package/dist/assets/noise/README.md +1 -0
  26. package/dist/assets/noise/stbn.bin +0 -0
  27. package/dist/assets/water/README.md +3 -0
  28. package/dist/assets/water/waternormals.jpg +0 -0
  29. package/dist/index.d.ts +10114 -0
  30. package/dist/index.js +34481 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/index.umd.cjs +6345 -0
  33. package/dist/index.umd.cjs.map +1 -0
  34. package/package.json +95 -0
  35. package/src/Color.ts +111 -0
  36. package/src/ShadowMapViewers.ts +49 -0
  37. package/src/atmosphere.test.ts +76 -0
  38. package/src/atmosphere.ts +364 -0
  39. package/src/bufferView.ts +90 -0
  40. package/src/camera.ts +182 -0
  41. package/src/concurrency.ts +15 -0
  42. package/src/constants/assets.ts +30 -0
  43. package/src/constants/decoder.ts +7 -0
  44. package/src/constants/index.ts +2 -0
  45. package/src/core/BaseDesc.ts +142 -0
  46. package/src/core/BaseHandle.ts +126 -0
  47. package/src/core/DescRegistry.ts +88 -0
  48. package/src/core/EffectDesc.ts +343 -0
  49. package/src/core/EffectDescRegistry.ts +31 -0
  50. package/src/core/InstancedMeshDesc.ts +413 -0
  51. package/src/core/LightDesc.ts +216 -0
  52. package/src/core/LightDescRegistry.ts +32 -0
  53. package/src/core/MeshDesc.ts +457 -0
  54. package/src/core/MeshDescRegistry.ts +32 -0
  55. package/src/core/MeshDescWithSelectiveEffect.ts +129 -0
  56. package/src/core/Registries.ts +59 -0
  57. package/src/core/SelectiveEffectRegistry.ts +90 -0
  58. package/src/core/ViewContext.ts +235 -0
  59. package/src/core/errors.ts +16 -0
  60. package/src/core/index.ts +50 -0
  61. package/src/device.ts +414 -0
  62. package/src/effects/CustomEffectPass.ts +28 -0
  63. package/src/effects/copy.ts +10 -0
  64. package/src/effects/effect.ts +87 -0
  65. package/src/effects/index.ts +4 -0
  66. package/src/effects/render.ts +10 -0
  67. package/src/evaluations/FeatureEvaluator.ts +529 -0
  68. package/src/evaluations/index.ts +1 -0
  69. package/src/event/HillshadeContext.test.ts +232 -0
  70. package/src/event/HillshadeContext.ts +299 -0
  71. package/src/event/context.ts +279 -0
  72. package/src/event/feature.ts +357 -0
  73. package/src/event/featureEvent.ts +81 -0
  74. package/src/event/features/billboard.ts +30 -0
  75. package/src/event/features/model.ts +192 -0
  76. package/src/event/features/modelGpuBytes.test.ts +69 -0
  77. package/src/event/features/modelGpuBytes.ts +87 -0
  78. package/src/event/features/point.ts +25 -0
  79. package/src/event/features/polygon.ts +23 -0
  80. package/src/event/features/polygonOutline.ts +19 -0
  81. package/src/event/features/polyline.ts +19 -0
  82. package/src/event/features/text.ts +71 -0
  83. package/src/event/hillshade.test.ts +842 -0
  84. package/src/event/hillshade.ts +588 -0
  85. package/src/event/index.ts +700 -0
  86. package/src/event/loaders.ts +53 -0
  87. package/src/event/tile.ts +19 -0
  88. package/src/event/worker.ts +999 -0
  89. package/src/event/workerTaskSettlement.test.ts +243 -0
  90. package/src/event/workerTaskSettlement.ts +128 -0
  91. package/src/inMemoryBufferStore.test.ts +60 -0
  92. package/src/inMemoryBufferStore.ts +67 -0
  93. package/src/index.iife.ts +11 -0
  94. package/src/index.ts +2556 -0
  95. package/src/input.ts +144 -0
  96. package/src/layer.ts +183 -0
  97. package/src/layers/effect/FinalCopyEffectDesc.ts +29 -0
  98. package/src/layers/effect/MRTPassEffectDesc.ts +105 -0
  99. package/src/layers/effect/README.md +9 -0
  100. package/src/layers/effect/SelectiveEffectDesc.ts +113 -0
  101. package/src/layers/effect/SkyEnvMapEffectDesc.ts +58 -0
  102. package/src/layers/effect/TransparentPassEffectDesc.ts +62 -0
  103. package/src/layers/effect/index.ts +5 -0
  104. package/src/layers/index.ts +1 -0
  105. package/src/layersManager.ts +63 -0
  106. package/src/light.ts +15 -0
  107. package/src/loaders/AbortableImageLoader.ts +203 -0
  108. package/src/loaders/AbortableTextureLoader.ts +74 -0
  109. package/src/loaders/index.ts +5 -0
  110. package/src/material/enhancer/DESIGN.md +300 -0
  111. package/src/material/enhancer/MaterialEnhancer.ts +112 -0
  112. package/src/material/enhancer/ShaderReplacer.test.ts +114 -0
  113. package/src/material/enhancer/ShaderReplacer.ts +97 -0
  114. package/src/material/enhancer/batchTexture.ts +8 -0
  115. package/src/material/enhancer/index.ts +46 -0
  116. package/src/material/enhancer/instancedSprite/index.ts +7 -0
  117. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.test.ts +214 -0
  118. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.ts +134 -0
  119. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/markers.ts +21 -0
  120. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/material.ts +32 -0
  121. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.test.ts +277 -0
  122. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.ts +151 -0
  123. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.test.ts +114 -0
  124. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.ts +49 -0
  125. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.test.ts +82 -0
  126. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.ts +80 -0
  127. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/types.ts +146 -0
  128. package/src/material/enhancer/instancedSprite/instancedSpriteMaterialEnhancer.ts +105 -0
  129. package/src/material/enhancer/model/index.ts +25 -0
  130. package/src/material/enhancer/model/modelBaseEnhancer/index.test.ts +74 -0
  131. package/src/material/enhancer/model/modelBaseEnhancer/index.ts +110 -0
  132. package/src/material/enhancer/model/modelBaseEnhancer/markers.ts +27 -0
  133. package/src/material/enhancer/model/modelBaseEnhancer/material.test.ts +66 -0
  134. package/src/material/enhancer/model/modelBaseEnhancer/material.ts +44 -0
  135. package/src/material/enhancer/model/modelBaseEnhancer/mutates.test.ts +84 -0
  136. package/src/material/enhancer/model/modelBaseEnhancer/mutates.ts +47 -0
  137. package/src/material/enhancer/model/modelBaseEnhancer/shader.test.ts +24 -0
  138. package/src/material/enhancer/model/modelBaseEnhancer/shader.ts +162 -0
  139. package/src/material/enhancer/model/modelBaseEnhancer/state.test.ts +103 -0
  140. package/src/material/enhancer/model/modelBaseEnhancer/state.ts +52 -0
  141. package/src/material/enhancer/model/modelBaseEnhancer/types.ts +89 -0
  142. package/src/material/enhancer/model/modelMaterialEnhancer.ts +91 -0
  143. package/src/material/enhancer/model/modelWaterEnhancer/index.test.ts +71 -0
  144. package/src/material/enhancer/model/modelWaterEnhancer/index.ts +175 -0
  145. package/src/material/enhancer/model/modelWaterEnhancer/material.test.ts +48 -0
  146. package/src/material/enhancer/model/modelWaterEnhancer/material.ts +25 -0
  147. package/src/material/enhancer/model/modelWaterEnhancer/mutates.test.ts +89 -0
  148. package/src/material/enhancer/model/modelWaterEnhancer/mutates.ts +89 -0
  149. package/src/material/enhancer/model/modelWaterEnhancer/shader.test.ts +34 -0
  150. package/src/material/enhancer/model/modelWaterEnhancer/shader.ts +111 -0
  151. package/src/material/enhancer/model/modelWaterEnhancer/state.test.ts +105 -0
  152. package/src/material/enhancer/model/modelWaterEnhancer/state.ts +59 -0
  153. package/src/material/enhancer/model/modelWaterEnhancer/types.ts +141 -0
  154. package/src/material/enhancer/model/pntsEnhancer/index.test.ts +96 -0
  155. package/src/material/enhancer/model/pntsEnhancer/index.ts +82 -0
  156. package/src/material/enhancer/model/pntsEnhancer/markers.ts +6 -0
  157. package/src/material/enhancer/model/pntsEnhancer/material.test.ts +37 -0
  158. package/src/material/enhancer/model/pntsEnhancer/material.ts +21 -0
  159. package/src/material/enhancer/model/pntsEnhancer/mutates.test.ts +80 -0
  160. package/src/material/enhancer/model/pntsEnhancer/mutates.ts +29 -0
  161. package/src/material/enhancer/model/pntsEnhancer/shader.test.ts +32 -0
  162. package/src/material/enhancer/model/pntsEnhancer/shader.ts +56 -0
  163. package/src/material/enhancer/model/pntsEnhancer/state.test.ts +87 -0
  164. package/src/material/enhancer/model/pntsEnhancer/state.ts +29 -0
  165. package/src/material/enhancer/model/pntsEnhancer/types.ts +38 -0
  166. package/src/material/enhancer/polygon/index.ts +22 -0
  167. package/src/material/enhancer/polygon/polygonBaseEnhancer/index.test.ts +101 -0
  168. package/src/material/enhancer/polygon/polygonBaseEnhancer/index.ts +130 -0
  169. package/src/material/enhancer/polygon/polygonBaseEnhancer/markers.ts +23 -0
  170. package/src/material/enhancer/polygon/polygonBaseEnhancer/material.test.ts +19 -0
  171. package/src/material/enhancer/polygon/polygonBaseEnhancer/material.ts +38 -0
  172. package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.test.ts +75 -0
  173. package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.ts +122 -0
  174. package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.test.ts +25 -0
  175. package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +249 -0
  176. package/src/material/enhancer/polygon/polygonBaseEnhancer/state.test.ts +102 -0
  177. package/src/material/enhancer/polygon/polygonBaseEnhancer/state.ts +92 -0
  178. package/src/material/enhancer/polygon/polygonBaseEnhancer/types.ts +150 -0
  179. package/src/material/enhancer/polygon/polygonMaterialEnhancer.ts +97 -0
  180. package/src/material/enhancer/polygon/polygonWaterEnhancer/index.test.ts +72 -0
  181. package/src/material/enhancer/polygon/polygonWaterEnhancer/index.ts +164 -0
  182. package/src/material/enhancer/polygon/polygonWaterEnhancer/material.test.ts +48 -0
  183. package/src/material/enhancer/polygon/polygonWaterEnhancer/material.ts +35 -0
  184. package/src/material/enhancer/polygon/polygonWaterEnhancer/mutates.ts +61 -0
  185. package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.test.ts +34 -0
  186. package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.ts +96 -0
  187. package/src/material/enhancer/polygon/polygonWaterEnhancer/state.test.ts +98 -0
  188. package/src/material/enhancer/polygon/polygonWaterEnhancer/state.ts +57 -0
  189. package/src/material/enhancer/polygon/polygonWaterEnhancer/types.ts +115 -0
  190. package/src/material/enhancer/polyline/index.ts +7 -0
  191. package/src/material/enhancer/polyline/polylineBaseEnhancer/index.test.ts +157 -0
  192. package/src/material/enhancer/polyline/polylineBaseEnhancer/index.ts +154 -0
  193. package/src/material/enhancer/polyline/polylineBaseEnhancer/markers.ts +19 -0
  194. package/src/material/enhancer/polyline/polylineBaseEnhancer/material.test.ts +42 -0
  195. package/src/material/enhancer/polyline/polylineBaseEnhancer/material.ts +38 -0
  196. package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.test.ts +120 -0
  197. package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.ts +169 -0
  198. package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.test.ts +67 -0
  199. package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.ts +75 -0
  200. package/src/material/enhancer/polyline/polylineBaseEnhancer/state.test.ts +55 -0
  201. package/src/material/enhancer/polyline/polylineBaseEnhancer/state.ts +91 -0
  202. package/src/material/enhancer/polyline/polylineBaseEnhancer/types.ts +170 -0
  203. package/src/material/enhancer/polyline/polylineMaterialEnhancer.ts +102 -0
  204. package/src/material/enhancer/sdfText/index.ts +7 -0
  205. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/index.ts +125 -0
  206. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/markers.ts +19 -0
  207. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.test.ts +35 -0
  208. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.ts +32 -0
  209. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.test.ts +381 -0
  210. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.ts +232 -0
  211. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/shader.ts +36 -0
  212. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.test.ts +118 -0
  213. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.ts +107 -0
  214. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +184 -0
  215. package/src/material/enhancer/sdfText/sdfTextMaterialEnhancer.ts +100 -0
  216. package/src/material/enhancer/shadowMap/index.ts +7 -0
  217. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/index.ts +97 -0
  218. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/markers.ts +10 -0
  219. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/material.ts +31 -0
  220. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/mutates.ts +8 -0
  221. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.test.ts +17 -0
  222. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.ts +53 -0
  223. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/state.ts +17 -0
  224. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/types.ts +26 -0
  225. package/src/material/enhancer/test-utils/shaderCompatibility.ts +124 -0
  226. package/src/material/enhancer/tileComposite/compose.test.ts +95 -0
  227. package/src/material/enhancer/tileComposite/compose.ts +112 -0
  228. package/src/material/enhancer/tileComposite/index.ts +23 -0
  229. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/index.ts +11 -0
  230. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.ts +132 -0
  231. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/shader.ts +245 -0
  232. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/types.ts +43 -0
  233. package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/index.ts +29 -0
  234. package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/mutates.ts +68 -0
  235. package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/shader.ts +24 -0
  236. package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/index.ts +29 -0
  237. package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/mutates.ts +34 -0
  238. package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/shader.ts +36 -0
  239. package/src/material/enhancer/tileComposite/tileWaterEnhancer/index.ts +23 -0
  240. package/src/material/enhancer/tileComposite/tileWaterEnhancer/mutates.ts +23 -0
  241. package/src/material/enhancer/tileComposite/tileWaterEnhancer/shader.ts +8 -0
  242. package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/index.ts +23 -0
  243. package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/mutates.ts +34 -0
  244. package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/shader.ts +13 -0
  245. package/src/material/enhancer/tileComposite/types.ts +58 -0
  246. package/src/material/index.ts +3 -0
  247. package/src/material/macro/index.ts +1 -0
  248. package/src/material/macro/tileShader.test.ts +136 -0
  249. package/src/material/macro/tileShader.ts +287 -0
  250. package/src/material/overrideMaterialsForMRT.ts +439 -0
  251. package/src/material/selectiveEffectMaterialSetup.test.ts +52 -0
  252. package/src/material/selectiveEffectMaterialSetup.ts +53 -0
  253. package/src/material/types/index.ts +1 -0
  254. package/src/material/types/uniform.ts +1 -0
  255. package/src/mesh/DrapedMesh.ts +101 -0
  256. package/src/mesh/batchTexture.test.ts +646 -0
  257. package/src/mesh/batchTexture.ts +437 -0
  258. package/src/mesh/batchedFeature.ts +186 -0
  259. package/src/mesh/batchedSdfText.ts +484 -0
  260. package/src/mesh/featureMesh.ts +43 -0
  261. package/src/mesh/index.ts +16 -0
  262. package/src/mesh/instanced.ts +117 -0
  263. package/src/mesh/model.ts +483 -0
  264. package/src/mesh/pickableMesh.ts +55 -0
  265. package/src/mesh/pickableMeshWrapper.ts +529 -0
  266. package/src/mesh/polygon.ts +699 -0
  267. package/src/mesh/polygonOutline.ts +393 -0
  268. package/src/mesh/polyline.ts +523 -0
  269. package/src/mesh/releaseGeometryArrays.ts +57 -0
  270. package/src/mesh/rtcRteHelper.ts +211 -0
  271. package/src/mesh/sdfText.test.ts +200 -0
  272. package/src/mesh/sdfText.ts +1019 -0
  273. package/src/mesh/sprite/billboardAtlas.test.ts +177 -0
  274. package/src/mesh/sprite/billboardAtlas.ts +210 -0
  275. package/src/mesh/sprite/billboardAtlasImageLoader.ts +29 -0
  276. package/src/mesh/sprite/index.ts +1 -0
  277. package/src/mesh/sprite/instancedSprite.ts +694 -0
  278. package/src/mesh/tile.test.ts +393 -0
  279. package/src/mesh/tile.ts +1790 -0
  280. package/src/object3DEvent.ts +6 -0
  281. package/src/orchestrators/RenderPassOrchestrator.ts +147 -0
  282. package/src/orchestrators/index.ts +1 -0
  283. package/src/passes/AllDepthCopyPass.ts +165 -0
  284. package/src/passes/CustomRenderPass.ts +279 -0
  285. package/src/passes/NormalCopyPass.ts +125 -0
  286. package/src/passes/RenderTargetCopyPass.ts +91 -0
  287. package/src/passes/SkyEnvMapPass.ts +58 -0
  288. package/src/passes/index.ts +5 -0
  289. package/src/pick/pickHelper.ts +273 -0
  290. package/src/pick/pickTerrain.ts +254 -0
  291. package/src/plugins/AttributionPlugin/AttributionPlugin.test.ts +210 -0
  292. package/src/plugins/AttributionPlugin/attribution.test.ts +225 -0
  293. package/src/plugins/AttributionPlugin/attribution.ts +355 -0
  294. package/src/plugins/AttributionPlugin/attributionStyles.ts +163 -0
  295. package/src/plugins/AttributionPlugin/index.ts +702 -0
  296. package/src/plugins/index.ts +1 -0
  297. package/src/quality.ts +1 -0
  298. package/src/renderOrder.ts +3 -0
  299. package/src/scene.test.ts +164 -0
  300. package/src/scene.ts +127 -0
  301. package/src/shaders/index.ts +1 -0
  302. package/src/solar.test.ts +81 -0
  303. package/src/solar.ts +101 -0
  304. package/src/source.ts +80 -0
  305. package/src/stats.ts +102 -0
  306. package/src/tasks/computeVertexNormalsAsync.ts +15 -0
  307. package/src/tasks/constructPolygonBatchedFeature.ts +34 -0
  308. package/src/tasks/constructPolylineBatchedFeature.ts +27 -0
  309. package/src/tasks/constructQuantizedMeshTerrainMesh.ts +24 -0
  310. package/src/tasks/constructTerrainMesh.ts +25 -0
  311. package/src/tasks/getImageDataFromBlob.ts +13 -0
  312. package/src/tasks/getImageDataFromImageBitmap.ts +12 -0
  313. package/src/tasks/parseMvtTile.ts +22 -0
  314. package/src/tasks/queueTask.ts +19 -0
  315. package/src/tasks/toCreasedNormalsAsync.ts +18 -0
  316. package/src/tasks/upsampleQuantizedMeshTerrainMesh.ts +44 -0
  317. package/src/tasks/upsampleTerrainMesh.ts +39 -0
  318. package/src/texture.ts +19 -0
  319. package/src/textures.ts +13 -0
  320. package/src/tileTexture/CompositeShader.snapshot.test.ts +59 -0
  321. package/src/tileTexture/CompositeShader.test.ts +168 -0
  322. package/src/tileTexture/CompositeShader.ts +53 -0
  323. package/src/tileTexture/SlotPlanner.test.ts +105 -0
  324. package/src/tileTexture/SlotPlanner.ts +102 -0
  325. package/src/tileTexture/TileTextureCache.test.ts +227 -0
  326. package/src/tileTexture/TileTextureCache.ts +192 -0
  327. package/src/tileTexture/TileTextureCompositor.test.ts +260 -0
  328. package/src/tileTexture/TileTextureCompositor.ts +421 -0
  329. package/src/tileTexture/__snapshots__/CompositeShader.snapshot.test.ts.snap +2649 -0
  330. package/src/tileTexture/index.ts +8 -0
  331. package/src/tileTexture/types.ts +150 -0
  332. package/src/type/index.ts +261 -0
  333. package/src/uniforms.ts +20 -0
  334. package/src/utils/arraysEqual.ts +9 -0
  335. package/src/utils/blendModes.ts +80 -0
  336. package/src/utils/geometry.ts +53 -0
  337. package/src/utils/hillshadeNormalMapGenerator.ts +193 -0
  338. package/src/utils/index.ts +8 -0
  339. package/src/utils/object.test.ts +14 -0
  340. package/src/utils/object.ts +7 -0
  341. package/src/utils/replacer.test.ts +42 -0
  342. package/src/utils/replacer.ts +89 -0
  343. package/src/utils/screen.ts +29 -0
  344. package/src/utils/textureFragmentIndex.test.ts +224 -0
  345. package/src/utils/textureFragmentIndex.ts +97 -0
  346. package/src/utils/worker.ts +3 -0
  347. package/src/vite-env.d.ts +2 -0
  348. package/src/worker/index.ts +13 -0
  349. package/src/worker/tasks/computeVertexNormals.ts +15 -0
  350. package/src/worker/tasks/toCreasedNormals.ts +22 -0
@@ -0,0 +1,588 @@
1
+ import { generate_id_from_entity } from "@navaramap/core";
2
+ import type { EntityEvent, HillshadeBackfilledEvent } from "@navaramap/engine";
3
+
4
+ import type { TileMesh } from "../mesh/tile";
5
+ import { getTextureFragmentSlots } from "../utils/textureFragmentIndex";
6
+
7
+ import type { EventContext } from "./context";
8
+ import type { HillshadeContext } from "./HillshadeContext";
9
+
10
+ /**
11
+ * Resolve the entity ID that hillshade state is keyed by.
12
+ * For edge updates with target_entity_ind/gen, use the target.
13
+ * Otherwise fall back to the event's own entity.
14
+ */
15
+ export function resolveHillshadeEntityId(
16
+ event: HillshadeBackfilledEvent,
17
+ ): string {
18
+ if (
19
+ event.target_entity_ind !== undefined &&
20
+ event.target_entity_gen !== undefined
21
+ ) {
22
+ return `${event.target_entity_ind}_${event.target_entity_gen}`;
23
+ }
24
+ return generate_id_from_entity(event);
25
+ }
26
+
27
+ /**
28
+ * Create padded DEM data (CPU only, no GPU upload)
29
+ * @returns { data, paddedSize } or undefined if invalid
30
+ */
31
+ function createPaddedDemData(
32
+ originalBytes: Uint8Array,
33
+ ): { data: Uint8Array; paddedSize: number } | undefined {
34
+ if (originalBytes.length % 4 !== 0) {
35
+ return undefined;
36
+ }
37
+
38
+ const originalSize = Math.sqrt(originalBytes.length / 4);
39
+ if (!Number.isInteger(originalSize) || originalSize < 1) {
40
+ return undefined;
41
+ }
42
+
43
+ const paddedSize = originalSize + 2;
44
+ const paddedBytes = new Uint8Array(paddedSize * paddedSize * 4);
45
+
46
+ const rowBytes = originalSize * 4;
47
+ for (let y = 0; y < originalSize; y++) {
48
+ const srcRowStart = y * rowBytes;
49
+ const dstRowStart = (y + 1) * paddedSize * 4 + 4;
50
+ paddedBytes.set(
51
+ originalBytes.subarray(srcRowStart, srcRowStart + rowBytes),
52
+ dstRowStart,
53
+ );
54
+ }
55
+
56
+ replicateEdgesToPadding(paddedBytes, paddedSize);
57
+
58
+ return { data: paddedBytes, paddedSize };
59
+ }
60
+
61
+ /**
62
+ * Apply pending edges that arrived before texture creation.
63
+ * @returns Array of { direction, bytes } for each successfully applied edge
64
+ */
65
+ function applyPendingEdges(
66
+ demData: Uint8Array,
67
+ paddedSize: number,
68
+ hillshadeContext: HillshadeContext,
69
+ entityId: string,
70
+ ): { direction: number; bytes: Uint8Array }[] {
71
+ const applied: { direction: number; bytes: Uint8Array }[] = [];
72
+ const pending = hillshadeContext.pendingEdges.get(entityId);
73
+
74
+ if (!pending || pending.size === 0) {
75
+ return applied;
76
+ }
77
+
78
+ for (const [edgeDirection, edgeBytes] of pending) {
79
+ const edgeSize = edgeBytes.length / 4;
80
+ const expectedTexSize = edgeSize + 2;
81
+
82
+ if (paddedSize === expectedTexSize) {
83
+ updatePaddingEdge(demData, edgeBytes, paddedSize, edgeDirection);
84
+ applied.push({ direction: edgeDirection, bytes: edgeBytes });
85
+ }
86
+ }
87
+
88
+ hillshadeContext.pendingEdges.delete(entityId);
89
+
90
+ return applied;
91
+ }
92
+
93
+ /**
94
+ * Rebind textures to all meshes using this entity
95
+ */
96
+ function rebindTexturesForEntity(entityId: string, ctx: EventContext): void {
97
+ const { textureFragmentIndex, loadedTexs, textureOptions } = ctx;
98
+
99
+ // These are guaranteed to exist by validation in processHillshadeBackfilled
100
+ if (!textureFragmentIndex || !loadedTexs || !textureOptions) {
101
+ return;
102
+ }
103
+
104
+ const slots = getTextureFragmentSlots(textureFragmentIndex, entityId);
105
+ if (!slots) return;
106
+
107
+ // Deduplicate tileMeshes: same mesh may appear in multiple slots
108
+ const uniqueMeshes = new Set<TileMesh>();
109
+ for (const { tileMesh } of slots) {
110
+ uniqueMeshes.add(tileMesh);
111
+ }
112
+
113
+ for (const tileMesh of uniqueMeshes) {
114
+ tileMesh.rebindTextures(loadedTexs, textureOptions);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Process initial hillshade texture creation
120
+ */
121
+ function processInitialHillshadeTexture(
122
+ ctx: EventContext,
123
+ event: HillshadeBackfilledEvent,
124
+ entityId: string,
125
+ ): void {
126
+ const { loadedTexs, buf, tileHandler, hillshadeContext } = ctx;
127
+
128
+ // These are guaranteed to exist by validation in processHillshadeBackfilled
129
+ if (!loadedTexs || !buf || !tileHandler || !hillshadeContext) {
130
+ return;
131
+ }
132
+
133
+ // Validate original_handle exists
134
+ const originalHandle = event.original_handle;
135
+ if (originalHandle === undefined || originalHandle === null) {
136
+ return;
137
+ }
138
+
139
+ // Read data without removing - DataManager handles cleanup via reference counting
140
+ // When multiple consumers (terrain, hillshade) share the same URL, the data is shared.
141
+ // Reference count is decremented when each consumer entity is deleted.
142
+ // Only when ref count reaches 0 (last consumer removed) is the data actually deleted.
143
+ // buf.u8 returns a short-lived view into WASM memory; createPaddedDemData
144
+ // copies it synchronously below, so no further copy is needed.
145
+ const originalBytes = buf.u8(originalHandle);
146
+ if (!originalBytes) {
147
+ return;
148
+ }
149
+
150
+ // Create padded DEM data (CPU only, no GPU upload)
151
+ const padded = createPaddedDemData(originalBytes);
152
+ if (!padded) {
153
+ return;
154
+ }
155
+ const { data: demData, paddedSize } = padded;
156
+
157
+ // Get tile handle for calculations
158
+ const tileHandleBigInt =
159
+ typeof event.tile_handle === "bigint"
160
+ ? event.tile_handle
161
+ : BigInt(event.tile_handle);
162
+
163
+ // Get tile info for zoom level (validate before doing expensive work)
164
+ const tile = tileHandler.getTile(tileHandleBigInt);
165
+ if (!tile) {
166
+ return;
167
+ }
168
+
169
+ // Apply any pending edge updates that arrived before texture creation
170
+ const appliedEdges = applyPendingEdges(
171
+ demData,
172
+ paddedSize,
173
+ hillshadeContext,
174
+ entityId,
175
+ );
176
+
177
+ const metersPerTexel = tileHandler.calcMetersPerTexel(
178
+ tileHandleBigInt,
179
+ tile.coords.z,
180
+ paddedSize,
181
+ );
182
+
183
+ const hillshadeConfig = hillshadeContext.getHillshadeConfig(
184
+ tileHandler,
185
+ tileHandleBigInt,
186
+ );
187
+
188
+ const contentWidth = paddedSize - 2;
189
+ const contentHeight = paddedSize - 2;
190
+
191
+ // Sanity check: in normal flow, loadedTexs should not have this entity yet
192
+ if (loadedTexs.has(entityId)) {
193
+ console.warn(
194
+ `[Hillshade] Unexpected: loadedTexs already contains ${entityId}, cleaning up`,
195
+ );
196
+ hillshadeContext.clearRenderTarget(entityId);
197
+ loadedTexs.delete(entityId);
198
+ }
199
+
200
+ // Generate normal map (DEM is uploaded transiently and freed after render)
201
+ const normalMap = hillshadeContext.generateNormalMap(
202
+ entityId,
203
+ ctx.viewContext,
204
+ demData,
205
+ paddedSize,
206
+ metersPerTexel,
207
+ hillshadeConfig,
208
+ contentWidth,
209
+ contentHeight,
210
+ );
211
+
212
+ loadedTexs.set(entityId, normalMap);
213
+
214
+ // Store handle-only TempDem entry (no full padded DEM retained)
215
+ hillshadeContext.storeTempDem(
216
+ entityId,
217
+ originalHandle,
218
+ paddedSize,
219
+ metersPerTexel,
220
+ hillshadeConfig,
221
+ );
222
+
223
+ // Persist edge bytes so padded DEM can be reconstructed on subsequent edge arrivals
224
+ for (const { direction, bytes } of appliedEdges) {
225
+ hillshadeContext.storeEdgeData(entityId, direction, bytes);
226
+ }
227
+
228
+ // Mark the edges that were already applied from pending as received
229
+ for (const { direction } of appliedEdges) {
230
+ const allEdgesReceived = hillshadeContext.markEdgeReceived(
231
+ entityId,
232
+ direction,
233
+ );
234
+ if (allEdgesReceived) {
235
+ hillshadeContext.clearTempDem(entityId);
236
+ break;
237
+ }
238
+ }
239
+
240
+ // Rebind textures to update the meshes
241
+ rebindTexturesForEntity(entityId, ctx);
242
+ }
243
+
244
+ /**
245
+ * Process hillshade edge update
246
+ */
247
+ function processHillshadeEdgeUpdate(
248
+ ctx: EventContext,
249
+ event: HillshadeBackfilledEvent,
250
+ entityId: string,
251
+ ): void {
252
+ const { loadedTexs, buf, hillshadeContext } = ctx;
253
+
254
+ // These are guaranteed to exist by validation in processHillshadeBackfilled
255
+ if (!loadedTexs || !buf || !hillshadeContext) {
256
+ return;
257
+ }
258
+
259
+ // Validate edge_data_handle exists
260
+ const edgeDataHandle = event.edge_data_handle;
261
+ if (edgeDataHandle === undefined || edgeDataHandle === null) {
262
+ return;
263
+ }
264
+
265
+ // Read edge data and remove from BufferStore immediately to prevent leaks
266
+ const edgeBytes = buf.removeU8(edgeDataHandle);
267
+ if (!edgeBytes) {
268
+ return;
269
+ }
270
+
271
+ // Validate edge data: one edge (size pixels × 4 bytes RGBA)
272
+ if (edgeBytes.length % 4 !== 0) {
273
+ return;
274
+ }
275
+
276
+ const texture = loadedTexs.get(entityId);
277
+
278
+ if (!texture) {
279
+ // Texture doesn't exist yet - queue this edge update for later application
280
+ let pending = hillshadeContext.pendingEdges.get(entityId);
281
+ if (!pending) {
282
+ pending = new Map<number, Uint8Array>();
283
+ hillshadeContext.pendingEdges.set(entityId, pending);
284
+ }
285
+ // Copy and store edge data, replacing any previous update for this direction
286
+ pending.set(event.edge_direction, new Uint8Array(edgeBytes));
287
+ return;
288
+ }
289
+
290
+ // Texture exists (it's a normal map), check if we have the temporary DEM entry
291
+ const tempDemEntry = hillshadeContext.getTempDem(entityId);
292
+ if (!tempDemEntry) {
293
+ // No temp DEM - edge updates complete or timed out, ignore this late arrival
294
+ return;
295
+ }
296
+
297
+ const edgeSize = edgeBytes.length / 4;
298
+ const { originalHandle, paddedSize } = tempDemEntry;
299
+
300
+ // Texture should be padded (edgeSize + 2)
301
+ const expectedTexSize = edgeSize + 2;
302
+ if (paddedSize !== expectedTexSize) {
303
+ // Size mismatch - different zoom levels, discard this edge data
304
+ return;
305
+ }
306
+
307
+ // Store edge bytes for reconstruction on future edge arrivals
308
+ hillshadeContext.storeEdgeData(
309
+ entityId,
310
+ event.edge_direction,
311
+ new Uint8Array(edgeBytes),
312
+ );
313
+
314
+ // Mark this edge as received
315
+ const allEdgesReceived = hillshadeContext.markEdgeReceived(
316
+ entityId,
317
+ event.edge_direction,
318
+ );
319
+
320
+ // Re-read the original DEM from WASM buffer (reference-counted, still valid).
321
+ // The returned view is consumed synchronously by createPaddedDemData below.
322
+ const originalBytes = buf.u8(originalHandle);
323
+ if (originalBytes) {
324
+ // Rebuild the padded DEM transiently, apply all received edges, generate normal map
325
+ const padded = createPaddedDemData(originalBytes);
326
+ if (padded) {
327
+ for (const [dir, storedBytes] of tempDemEntry.receivedEdgeData) {
328
+ updatePaddingEdge(padded.data, storedBytes, padded.paddedSize, dir);
329
+ }
330
+
331
+ const contentWidth = padded.paddedSize - 2;
332
+ const contentHeight = padded.paddedSize - 2;
333
+ const updatedTexture = hillshadeContext.generateNormalMap(
334
+ entityId,
335
+ ctx.viewContext,
336
+ padded.data,
337
+ padded.paddedSize,
338
+ tempDemEntry.metersPerTexel,
339
+ tempDemEntry.hillshadeConfig,
340
+ contentWidth,
341
+ contentHeight,
342
+ );
343
+ loadedTexs.set(entityId, updatedTexture);
344
+ // padded.data is released here (no persistent reference kept)
345
+ }
346
+ }
347
+
348
+ // If all 4 edges received, cleanup the temporary entry
349
+ if (allEdgesReceived) {
350
+ hillshadeContext.clearTempDem(entityId);
351
+ }
352
+
353
+ // Rebind textures to update the meshes
354
+ rebindTexturesForEntity(entityId, ctx);
355
+ }
356
+
357
+ /**
358
+ * Handle a hillshade_canceled event.
359
+ *
360
+ * Two responsibilities, both scoped to "the canceled entity":
361
+ * 1. Pre-empt any pending `hillshade_backfilled` events in the EventManager
362
+ * stack whose effect would target this entity, so they never run. Matched
363
+ * via `resolveHillshadeEntityId` so an edge update X→Y (keyed by target Y)
364
+ * survives a cancel of source X — Y still wants that edge data.
365
+ * 2. Drop in-flight backfill state that earlier events created — queued
366
+ * neighbor edges and the in-progress DEM assembly entry.
367
+ *
368
+ * Does NOT dispose render targets or `loadedTexs` textures: those belong to
369
+ * the texture-fragment lifecycle and are released by
370
+ * `processTextureFragmentRemoved`. Disposing them here would race against
371
+ * other tiles that may still reference the texture.
372
+ *
373
+ * Idempotent: safe to call when no state exists for the entity.
374
+ */
375
+ export function processHillshadeCanceled(
376
+ ctx: EventContext,
377
+ event: EntityEvent | undefined,
378
+ ) {
379
+ if (!event) return;
380
+
381
+ const { hillshadeContext, eventManager } = ctx;
382
+ if (!hillshadeContext) return;
383
+
384
+ const entityId = generate_id_from_entity(event);
385
+
386
+ const backfillStack = eventManager.stacks
387
+ .hillshade_backfilled as HillshadeBackfilledEvent[];
388
+ if (backfillStack.length > 0) {
389
+ const kept: HillshadeBackfilledEvent[] = [];
390
+ for (const bf of backfillStack) {
391
+ if (resolveHillshadeEntityId(bf) === entityId) {
392
+ if (bf && "free" in bf && typeof bf.free === "function") {
393
+ bf.free();
394
+ }
395
+ } else {
396
+ kept.push(bf);
397
+ }
398
+ }
399
+ eventManager.stacks.hillshade_backfilled = kept;
400
+ }
401
+
402
+ hillshadeContext.pendingEdges.delete(entityId);
403
+ hillshadeContext.clearTempDem(entityId);
404
+ }
405
+
406
+ export function processHillshadeBackfilled(
407
+ ctx: EventContext,
408
+ event: HillshadeBackfilledEvent | undefined,
409
+ ) {
410
+ if (!event) return;
411
+
412
+ const {
413
+ loadedTexs,
414
+ buf,
415
+ textureFragmentIndex,
416
+ textureOptions,
417
+ tileHandler,
418
+ hillshadeContext,
419
+ } = ctx;
420
+
421
+ if (
422
+ !loadedTexs ||
423
+ !buf ||
424
+ !tileHandler ||
425
+ !hillshadeContext ||
426
+ !textureOptions ||
427
+ !textureFragmentIndex
428
+ ) {
429
+ return;
430
+ }
431
+
432
+ const entityId = resolveHillshadeEntityId(event);
433
+
434
+ // 1. Create texture if original data is provided
435
+ if (event.original_handle !== undefined && event.original_handle !== null) {
436
+ processInitialHillshadeTexture(ctx, event, entityId);
437
+ }
438
+
439
+ // 2. Update edges if edge data is provided
440
+ if (event.edge_data_handle !== undefined && event.edge_data_handle !== null) {
441
+ processHillshadeEdgeUpdate(ctx, event, entityId);
442
+ }
443
+ }
444
+
445
+ /**
446
+ * TODO: define this function in Rust and use it in web worker
447
+ * Update a padding edge of a padded texture from neighbor edge data
448
+ * @param textureData - The Uint8Array backing the DataTexture (paddedSize×paddedSize×4 bytes)
449
+ * @param edgeBytes - Buffer containing one edge from neighbor (contentSize pixels × 4 bytes RGBA)
450
+ * @param paddedSize - Padded texture size (e.g., 258 for 256×256 content)
451
+ * @param direction - Edge direction: 0=Left, 1=Right, 2=Top, 3=Bottom
452
+ * @internal Exported for testing only
453
+ */
454
+ export function updatePaddingEdge(
455
+ textureData: Uint8Array,
456
+ edgeBytes: Uint8Array,
457
+ paddedSize: number,
458
+ direction: number,
459
+ ): void {
460
+ const contentSize = paddedSize - 2;
461
+
462
+ switch (direction) {
463
+ case 0: // Left padding (x=0)
464
+ for (let y = 0; y < contentSize; y++) {
465
+ const srcIdx = y * 4;
466
+ const dstY = y + 1; // Content starts at y=1
467
+ const dstIdx = (dstY * paddedSize + 0) * 4;
468
+ textureData.set(edgeBytes.subarray(srcIdx, srcIdx + 4), dstIdx);
469
+ }
470
+ break;
471
+
472
+ case 1: // Right padding (x=paddedSize-1)
473
+ for (let y = 0; y < contentSize; y++) {
474
+ const srcIdx = y * 4;
475
+ const dstY = y + 1;
476
+ const dstX = paddedSize - 1;
477
+ const dstIdx = (dstY * paddedSize + dstX) * 4;
478
+ textureData.set(edgeBytes.subarray(srcIdx, srcIdx + 4), dstIdx);
479
+ }
480
+ break;
481
+
482
+ case 2: // Top padding (y=0)
483
+ for (let x = 0; x < contentSize; x++) {
484
+ const srcIdx = x * 4;
485
+ const dstX = x + 1; // Content starts at x=1
486
+ const dstIdx = (0 * paddedSize + dstX) * 4;
487
+ textureData.set(edgeBytes.subarray(srcIdx, srcIdx + 4), dstIdx);
488
+ }
489
+ break;
490
+
491
+ case 3: // Bottom padding (y=paddedSize-1)
492
+ for (let x = 0; x < contentSize; x++) {
493
+ const srcIdx = x * 4;
494
+ const dstX = x + 1;
495
+ const dstY = paddedSize - 1;
496
+ const dstIdx = (dstY * paddedSize + dstX) * 4;
497
+ textureData.set(edgeBytes.subarray(srcIdx, srcIdx + 4), dstIdx);
498
+ }
499
+ break;
500
+ }
501
+ }
502
+
503
+ /**
504
+ * TODO: define this function in Rust and use it in web worker
505
+ * Initialize padding by replicating content edges
506
+ * @param paddedBytes - Padded texture data (paddedSize×paddedSize×4 bytes)
507
+ * @param paddedSize - Padded texture size (e.g., 258)
508
+ * @internal Exported for testing only
509
+ */
510
+ export function replicateEdgesToPadding(
511
+ paddedBytes: Uint8Array,
512
+ paddedSize: number,
513
+ ): void {
514
+ const contentSize = paddedSize - 2;
515
+
516
+ // Top padding (y=0): copy from first content row (y=1)
517
+ for (let x = 1; x <= contentSize; x++) {
518
+ const srcIdx = (1 * paddedSize + x) * 4;
519
+ const dstIdx = (0 * paddedSize + x) * 4;
520
+ paddedBytes[dstIdx] = paddedBytes[srcIdx];
521
+ paddedBytes[dstIdx + 1] = paddedBytes[srcIdx + 1];
522
+ paddedBytes[dstIdx + 2] = paddedBytes[srcIdx + 2];
523
+ paddedBytes[dstIdx + 3] = paddedBytes[srcIdx + 3];
524
+ }
525
+
526
+ // Bottom padding (y=paddedSize-1): copy from last content row (y=contentSize)
527
+ for (let x = 1; x <= contentSize; x++) {
528
+ const srcIdx = (contentSize * paddedSize + x) * 4;
529
+ const dstIdx = ((paddedSize - 1) * paddedSize + x) * 4;
530
+ paddedBytes[dstIdx] = paddedBytes[srcIdx];
531
+ paddedBytes[dstIdx + 1] = paddedBytes[srcIdx + 1];
532
+ paddedBytes[dstIdx + 2] = paddedBytes[srcIdx + 2];
533
+ paddedBytes[dstIdx + 3] = paddedBytes[srcIdx + 3];
534
+ }
535
+
536
+ // Left padding (x=0): copy from first content column (x=1)
537
+ for (let y = 1; y <= contentSize; y++) {
538
+ const srcIdx = (y * paddedSize + 1) * 4;
539
+ const dstIdx = (y * paddedSize + 0) * 4;
540
+ paddedBytes[dstIdx] = paddedBytes[srcIdx];
541
+ paddedBytes[dstIdx + 1] = paddedBytes[srcIdx + 1];
542
+ paddedBytes[dstIdx + 2] = paddedBytes[srcIdx + 2];
543
+ paddedBytes[dstIdx + 3] = paddedBytes[srcIdx + 3];
544
+ }
545
+
546
+ // Right padding (x=paddedSize-1): copy from last content column (x=contentSize)
547
+ for (let y = 1; y <= contentSize; y++) {
548
+ const srcIdx = (y * paddedSize + contentSize) * 4;
549
+ const dstIdx = (y * paddedSize + (paddedSize - 1)) * 4;
550
+ paddedBytes[dstIdx] = paddedBytes[srcIdx];
551
+ paddedBytes[dstIdx + 1] = paddedBytes[srcIdx + 1];
552
+ paddedBytes[dstIdx + 2] = paddedBytes[srcIdx + 2];
553
+ paddedBytes[dstIdx + 3] = paddedBytes[srcIdx + 3];
554
+ }
555
+
556
+ // Corners: copy from adjacent content pixels
557
+ // Top-left (0, 0)
558
+ const tlSrcIdx = (1 * paddedSize + 1) * 4;
559
+ const tlDstIdx = 0;
560
+ paddedBytes[tlDstIdx] = paddedBytes[tlSrcIdx];
561
+ paddedBytes[tlDstIdx + 1] = paddedBytes[tlSrcIdx + 1];
562
+ paddedBytes[tlDstIdx + 2] = paddedBytes[tlSrcIdx + 2];
563
+ paddedBytes[tlDstIdx + 3] = paddedBytes[tlSrcIdx + 3];
564
+
565
+ // Top-right (paddedSize-1, 0)
566
+ const trSrcIdx = (1 * paddedSize + contentSize) * 4;
567
+ const trDstIdx = (paddedSize - 1) * 4;
568
+ paddedBytes[trDstIdx] = paddedBytes[trSrcIdx];
569
+ paddedBytes[trDstIdx + 1] = paddedBytes[trSrcIdx + 1];
570
+ paddedBytes[trDstIdx + 2] = paddedBytes[trSrcIdx + 2];
571
+ paddedBytes[trDstIdx + 3] = paddedBytes[trSrcIdx + 3];
572
+
573
+ // Bottom-left (0, paddedSize-1)
574
+ const blSrcIdx = (contentSize * paddedSize + 1) * 4;
575
+ const blDstIdx = (paddedSize - 1) * paddedSize * 4;
576
+ paddedBytes[blDstIdx] = paddedBytes[blSrcIdx];
577
+ paddedBytes[blDstIdx + 1] = paddedBytes[blSrcIdx + 1];
578
+ paddedBytes[blDstIdx + 2] = paddedBytes[blSrcIdx + 2];
579
+ paddedBytes[blDstIdx + 3] = paddedBytes[blSrcIdx + 3];
580
+
581
+ // Bottom-right (paddedSize-1, paddedSize-1)
582
+ const brSrcIdx = (contentSize * paddedSize + contentSize) * 4;
583
+ const brDstIdx = ((paddedSize - 1) * paddedSize + (paddedSize - 1)) * 4;
584
+ paddedBytes[brDstIdx] = paddedBytes[brSrcIdx];
585
+ paddedBytes[brDstIdx + 1] = paddedBytes[brSrcIdx + 1];
586
+ paddedBytes[brDstIdx + 2] = paddedBytes[brSrcIdx + 2];
587
+ paddedBytes[brDstIdx + 3] = paddedBytes[brSrcIdx + 3];
588
+ }