@tangram.gl/tangram-renderer 0.0.0-stage → 0.0.1

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 (321) hide show
  1. package/README.md +60 -2
  2. package/dist/core.js +36923 -0
  3. package/dist/core.js.map +6 -0
  4. package/dist/index.js +32 -0
  5. package/dist/loaders-gl-worker.js +82 -0
  6. package/dist/loaders-gl-worker.js.map +6 -0
  7. package/dist/map-logic.js +2 -0
  8. package/dist/map-logic.js.map +6 -0
  9. package/dist/projected-basemaps-worker.js +3 -0
  10. package/dist/projected-basemaps-worker.js.map +6 -0
  11. package/dist/shader-modules.js +141 -0
  12. package/dist/shader-modules.js.map +6 -0
  13. package/dist/style-schema.js +126 -0
  14. package/dist/style-schema.js.map +6 -0
  15. package/dist/tangram-style.schema.json +882 -0
  16. package/dist/tangram.debug.mjs +37139 -0
  17. package/dist/tangram.debug.mjs.map +6 -0
  18. package/dist/tangram.min.mjs +4950 -0
  19. package/dist/types/builders/earcut.d.ts +15 -0
  20. package/dist/types/core.d.ts +29 -0
  21. package/dist/types/gl/constants.d.ts +2 -0
  22. package/dist/types/gl/globe_mesh.d.ts +48 -0
  23. package/dist/types/gl/glsl.d.ts +17 -0
  24. package/dist/types/gl/vertex-constants.d.ts +4 -0
  25. package/dist/types/gl/vertex-types.d.ts +34 -0
  26. package/dist/types/gl/vertex_data.d.ts +32 -0
  27. package/dist/types/gl/vertex_elements.d.ts +8 -0
  28. package/dist/types/gl/vertex_layout.d.ts +32 -0
  29. package/dist/types/glsl.d.ts +14 -0
  30. package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
  31. package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
  32. package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
  33. package/dist/types/index.d.ts +155 -0
  34. package/dist/types/lights/light-definitions.d.ts +121 -0
  35. package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
  36. package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
  37. package/dist/types/map-logic/globe-terrain.d.ts +54 -0
  38. package/dist/types/map-logic/index.d.ts +33 -0
  39. package/dist/types/map-logic/label-identity.d.ts +22 -0
  40. package/dist/types/map-logic/label-placement.d.ts +32 -0
  41. package/dist/types/map-logic/screen-bounds.d.ts +15 -0
  42. package/dist/types/map-logic/terrain-data.d.ts +55 -0
  43. package/dist/types/map-logic/terrain-error.d.ts +51 -0
  44. package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
  45. package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
  46. package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
  47. package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
  48. package/dist/types/map-logic/terrain-query.d.ts +33 -0
  49. package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
  50. package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
  51. package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
  52. package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
  53. package/dist/types/map-logic/tile-residency.d.ts +17 -0
  54. package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
  55. package/dist/types/procedures/js-yaml.d.ts +15 -0
  56. package/dist/types/procedures/mesh-projector.d.ts +107 -0
  57. package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
  58. package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
  59. package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
  60. package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
  61. package/dist/types/procedures/terrain-draping.d.ts +165 -0
  62. package/dist/types/procedures/terrain-globe.d.ts +6 -0
  63. package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
  64. package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
  65. package/dist/types/procedures/web-mercator-math.d.ts +4 -0
  66. package/dist/types/scene/globals.d.ts +11 -0
  67. package/dist/types/scene/ground_footprint.d.ts +16 -0
  68. package/dist/types/scene/host_frame.d.ts +54 -0
  69. package/dist/types/scene/projection_math.d.ts +52 -0
  70. package/dist/types/scene/scene-resource-types.d.ts +177 -0
  71. package/dist/types/scene/scene_bundle.d.ts +69 -0
  72. package/dist/types/scene/visibility_adapter.d.ts +106 -0
  73. package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
  74. package/dist/types/selection/terrain_surface.d.ts +149 -0
  75. package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
  76. package/dist/types/shader-modules/height-decode.d.ts +13 -0
  77. package/dist/types/shader-modules/hillshade.d.ts +13 -0
  78. package/dist/types/shader-modules/index.d.ts +6 -0
  79. package/dist/types/shader-modules/planar.d.ts +12 -0
  80. package/dist/types/shader-modules/sphere-map.d.ts +13 -0
  81. package/dist/types/shader-modules/triplanar.d.ts +15 -0
  82. package/dist/types/sources/decoded_tile_store.d.ts +95 -0
  83. package/dist/types/sources/tile_source_metadata.d.ts +32 -0
  84. package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
  85. package/dist/types/tile/tile_id.d.ts +37 -0
  86. package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
  87. package/dist/types/types.d.ts +293 -0
  88. package/dist/types/utils/geo.d.ts +57 -0
  89. package/dist/types/utils/hash.d.ts +1 -0
  90. package/dist/types/utils/log.d.ts +27 -0
  91. package/dist/types/utils/props.d.ts +6 -0
  92. package/dist/types/utils/subscribe.d.ts +10 -0
  93. package/dist/types/utils/thread.d.ts +6 -0
  94. package/dist/types/utils/urls.d.ts +26 -0
  95. package/dist/types/utils/utils.d.ts +26 -0
  96. package/dist/types/utils/version.d.ts +2 -0
  97. package/dist/types/utils/worker-types.d.ts +68 -0
  98. package/dist/types/utils/worker_broker.d.ts +3 -0
  99. package/package.json +103 -3
  100. package/src/builders/common.ts +41 -0
  101. package/src/builders/earcut.d.ts +15 -0
  102. package/src/builders/geometry-types.ts +60 -0
  103. package/src/builders/points.ts +115 -0
  104. package/src/builders/polygons.ts +225 -0
  105. package/src/builders/polylines.ts +682 -0
  106. package/src/builders/wireframe.ts +31 -0
  107. package/src/core.d.ts +29 -0
  108. package/src/core.ts +33 -0
  109. package/src/experimental/loaders-gl-worker.ts +19 -0
  110. package/src/experimental/projected-basemaps-worker.ts +13 -0
  111. package/src/experimental/projected-mesh-cache.ts +137 -0
  112. package/src/experimental/projected-mesh-domain.ts +110 -0
  113. package/src/experimental/projected-mesh-refinement.ts +193 -0
  114. package/src/experimental/projected-mesh.ts +399 -0
  115. package/src/experimental/projected-normal.ts +26 -0
  116. package/src/experimental/projected-symbol-mesh.ts +74 -0
  117. package/src/gl/constants.ts +18 -0
  118. package/src/gl/context.ts +103 -0
  119. package/src/gl/extensions.ts +30 -0
  120. package/src/gl/globe_mesh.ts +285 -0
  121. package/src/gl/glsl.ts +257 -0
  122. package/src/gl/mesh-types.ts +56 -0
  123. package/src/gl/render_state.ts +111 -0
  124. package/src/gl/shader_program.ts +1310 -0
  125. package/src/gl/texture.ts +814 -0
  126. package/src/gl/uniform_buffer.ts +340 -0
  127. package/src/gl/vao.ts +154 -0
  128. package/src/gl/vbo_mesh.ts +349 -0
  129. package/src/gl/vertex-constants.ts +19 -0
  130. package/src/gl/vertex-types.ts +35 -0
  131. package/src/gl/vertex_data.ts +126 -0
  132. package/src/gl/vertex_elements.ts +54 -0
  133. package/src/gl/vertex_layout.ts +241 -0
  134. package/src/glsl.d.ts +14 -0
  135. package/src/gpu/luma_device_renderer.ts +579 -0
  136. package/src/gpu/pixel_readback.ts +51 -0
  137. package/src/gpu/resource_lifecycle.ts +32 -0
  138. package/src/gpu/tangram_gpu_backend.ts +195 -0
  139. package/src/index.d.ts +155 -0
  140. package/src/index.ts +105 -0
  141. package/src/labels/collision-types.ts +94 -0
  142. package/src/labels/collision.ts +273 -0
  143. package/src/labels/collision_grid.ts +61 -0
  144. package/src/labels/intersect.ts +30 -0
  145. package/src/labels/label-types.ts +91 -0
  146. package/src/labels/label.ts +207 -0
  147. package/src/labels/label_line.ts +801 -0
  148. package/src/labels/label_point.ts +131 -0
  149. package/src/labels/main-pass-types.ts +73 -0
  150. package/src/labels/main_pass.ts +221 -0
  151. package/src/labels/point_anchor.ts +100 -0
  152. package/src/labels/point_placement.ts +150 -0
  153. package/src/labels/projected-pass.ts +259 -0
  154. package/src/labels/repeat_group.ts +72 -0
  155. package/src/lights/ambient_light.glsl +18 -0
  156. package/src/lights/directional_light.glsl +39 -0
  157. package/src/lights/geographic-lights.ts +21 -0
  158. package/src/lights/light-definitions.ts +285 -0
  159. package/src/lights/light.ts +590 -0
  160. package/src/lights/lighting-uniforms.ts +80 -0
  161. package/src/lights/lighting-wgsl.ts +116 -0
  162. package/src/lights/material.glsl +237 -0
  163. package/src/lights/material.ts +145 -0
  164. package/src/lights/native-falloff.ts +37 -0
  165. package/src/lights/point_light.glsl +96 -0
  166. package/src/lights/spot_light.glsl +111 -0
  167. package/src/map-logic/draped-terrain-bounds.ts +71 -0
  168. package/src/map-logic/globe-terrain-preparation.ts +217 -0
  169. package/src/map-logic/globe-terrain.ts +296 -0
  170. package/src/map-logic/index.ts +37 -0
  171. package/src/map-logic/label-identity.ts +36 -0
  172. package/src/map-logic/label-placement.ts +117 -0
  173. package/src/map-logic/screen-bounds.ts +34 -0
  174. package/src/map-logic/terrain-data.ts +107 -0
  175. package/src/map-logic/terrain-error.ts +134 -0
  176. package/src/map-logic/terrain-ground-topology.ts +164 -0
  177. package/src/map-logic/terrain-height-field.ts +254 -0
  178. package/src/map-logic/terrain-navigation.ts +50 -0
  179. package/src/map-logic/terrain-neighborhood.ts +43 -0
  180. package/src/map-logic/terrain-query.ts +51 -0
  181. package/src/map-logic/terrain-resource-budget.ts +124 -0
  182. package/src/map-logic/terrain-transition-topology.ts +164 -0
  183. package/src/map-logic/tile-build-queue.ts +110 -0
  184. package/src/map-logic/tile-cache-policy.ts +89 -0
  185. package/src/map-logic/tile-residency.ts +50 -0
  186. package/src/map-logic/triangle-query-index.ts +265 -0
  187. package/src/procedures/js-yaml.d.ts +15 -0
  188. package/src/procedures/mesh-projector.ts +191 -0
  189. package/src/procedures/mlt-loaders.ts +55 -0
  190. package/src/procedures/mvt-dependencies.d.ts +20 -0
  191. package/src/procedures/mvt-legacy.ts +150 -0
  192. package/src/procedures/mvt-loaders.ts +53 -0
  193. package/src/procedures/mvt-parser.ts +48 -0
  194. package/src/procedures/mvt-properties.ts +36 -0
  195. package/src/procedures/mvt-tile-provider.ts +72 -0
  196. package/src/procedures/pmtiles-loader.ts +75 -0
  197. package/src/procedures/projected-coordinate-transform.ts +79 -0
  198. package/src/procedures/projection-batch-executor.ts +140 -0
  199. package/src/procedures/scene-yaml-legacy.ts +16 -0
  200. package/src/procedures/scene-yaml-loaders.ts +10 -0
  201. package/src/procedures/terrain-draping.ts +713 -0
  202. package/src/procedures/terrain-globe.ts +32 -0
  203. package/src/procedures/terrain-styled-topology.ts +184 -0
  204. package/src/procedures/web-mercator-legacy.ts +24 -0
  205. package/src/procedures/web-mercator-math.ts +50 -0
  206. package/src/scene/camera.ts +298 -0
  207. package/src/scene/camera_base.ts +116 -0
  208. package/src/scene/classic_scene.ts +20 -0
  209. package/src/scene/external_camera.ts +101 -0
  210. package/src/scene/globals.ts +120 -0
  211. package/src/scene/ground_footprint.ts +139 -0
  212. package/src/scene/host_frame.ts +326 -0
  213. package/src/scene/projected_tile_lod.ts +125 -0
  214. package/src/scene/projection_math.ts +142 -0
  215. package/src/scene/projection_shaders.ts +183 -0
  216. package/src/scene/renderer.ts +516 -0
  217. package/src/scene/scene-resource-types.ts +174 -0
  218. package/src/scene/scene.ts +2378 -0
  219. package/src/scene/scene_bundle.ts +304 -0
  220. package/src/scene/scene_debug.ts +129 -0
  221. package/src/scene/scene_loader.ts +402 -0
  222. package/src/scene/scene_worker.ts +528 -0
  223. package/src/scene/view.ts +683 -0
  224. package/src/scene/visibility_adapter.ts +319 -0
  225. package/src/scene/worker_url.ts +15 -0
  226. package/src/selection/draped-terrain-surface.ts +377 -0
  227. package/src/selection/selection-types.ts +79 -0
  228. package/src/selection/selection.ts +542 -0
  229. package/src/selection/selection_fragment.glsl +18 -0
  230. package/src/selection/selection_globals.glsl +9 -0
  231. package/src/selection/selection_pixels.ts +59 -0
  232. package/src/selection/selection_vertex.glsl +15 -0
  233. package/src/selection/terrain_surface.ts +298 -0
  234. package/src/shader-modules/globe-horizon.ts +52 -0
  235. package/src/shader-modules/height-decode.ts +41 -0
  236. package/src/shader-modules/hillshade.ts +70 -0
  237. package/src/shader-modules/index.ts +10 -0
  238. package/src/shader-modules/planar.ts +24 -0
  239. package/src/shader-modules/sphere-map.ts +38 -0
  240. package/src/shader-modules/triplanar.ts +45 -0
  241. package/src/sources/aligned_tile_source.ts +122 -0
  242. package/src/sources/data_source.ts +655 -0
  243. package/src/sources/decoded_tile_store.ts +245 -0
  244. package/src/sources/geojson.ts +300 -0
  245. package/src/sources/mvt.ts +247 -0
  246. package/src/sources/raster.ts +341 -0
  247. package/src/sources/shared_tile_source_adapter.ts +117 -0
  248. package/src/sources/sources.ts +10 -0
  249. package/src/sources/tile_source_adapter.ts +84 -0
  250. package/src/sources/tile_source_metadata.ts +65 -0
  251. package/src/sources/tile_source_state.ts +112 -0
  252. package/src/sources/topojson.ts +90 -0
  253. package/src/styles/feature_annotations.ts +16 -0
  254. package/src/styles/filter.ts +190 -0
  255. package/src/styles/geometry-style-types.ts +209 -0
  256. package/src/styles/globe_visibility_wgsl.ts +22 -0
  257. package/src/styles/layer-types.ts +45 -0
  258. package/src/styles/layer.ts +586 -0
  259. package/src/styles/lines/dasharray.ts +49 -0
  260. package/src/styles/lines/lines.ts +707 -0
  261. package/src/styles/lines/lines_wgsl.ts +224 -0
  262. package/src/styles/points/point-runtime-types.ts +125 -0
  263. package/src/styles/points/points.ts +1079 -0
  264. package/src/styles/points/points_fragment.glsl +126 -0
  265. package/src/styles/points/points_vertex.glsl +230 -0
  266. package/src/styles/points/points_wgsl.ts +189 -0
  267. package/src/styles/polygons/polygons.ts +268 -0
  268. package/src/styles/polygons/polygons_fragment.glsl +173 -0
  269. package/src/styles/polygons/polygons_vertex.glsl +213 -0
  270. package/src/styles/polygons/polygons_wgsl.ts +127 -0
  271. package/src/styles/property-types.ts +125 -0
  272. package/src/styles/raster/raster.ts +33 -0
  273. package/src/styles/raster/raster_globals.glsl +46 -0
  274. package/src/styles/style-mixing-types.ts +101 -0
  275. package/src/styles/style-runtime-types.ts +220 -0
  276. package/src/styles/style-schema.ts +133 -0
  277. package/src/styles/style.ts +1033 -0
  278. package/src/styles/style_globals.glsl +69 -0
  279. package/src/styles/style_manager.ts +464 -0
  280. package/src/styles/style_parser.ts +620 -0
  281. package/src/styles/text/font_manager.ts +180 -0
  282. package/src/styles/text/fontfaceobserver.d.ts +10 -0
  283. package/src/styles/text/text-types.ts +220 -0
  284. package/src/styles/text/text.ts +378 -0
  285. package/src/styles/text/text_canvas.ts +773 -0
  286. package/src/styles/text/text_labels.ts +436 -0
  287. package/src/styles/text/text_segments.ts +142 -0
  288. package/src/styles/text/text_settings.ts +228 -0
  289. package/src/styles/text/text_wgsl.ts +159 -0
  290. package/src/styles/text/text_wrap.ts +194 -0
  291. package/src/tile/globe_tile_preload.ts +40 -0
  292. package/src/tile/tangram_tileset_2d.ts +108 -0
  293. package/src/tile/tile-build-types.ts +155 -0
  294. package/src/tile/tile.ts +807 -0
  295. package/src/tile/tile_id.ts +172 -0
  296. package/src/tile/tile_manager.ts +889 -0
  297. package/src/tile/tile_pyramid.ts +119 -0
  298. package/src/tile/tile_resource_cache.ts +91 -0
  299. package/src/tile/tile_traversal_adapter.ts +132 -0
  300. package/src/types.ts +332 -0
  301. package/src/utils/debounce.ts +17 -0
  302. package/src/utils/debug_settings.ts +43 -0
  303. package/src/utils/errors.ts +12 -0
  304. package/src/utils/functions.ts +95 -0
  305. package/src/utils/geo.ts +364 -0
  306. package/src/utils/hash.ts +14 -0
  307. package/src/utils/log.ts +108 -0
  308. package/src/utils/media_capture.ts +193 -0
  309. package/src/utils/merge.ts +44 -0
  310. package/src/utils/obb.ts +134 -0
  311. package/src/utils/props.ts +43 -0
  312. package/src/utils/slice.ts +14 -0
  313. package/src/utils/subscribe.ts +58 -0
  314. package/src/utils/task.ts +154 -0
  315. package/src/utils/thread.ts +26 -0
  316. package/src/utils/urls.ts +223 -0
  317. package/src/utils/utils.ts +310 -0
  318. package/src/utils/vector.ts +197 -0
  319. package/src/utils/version.ts +8 -0
  320. package/src/utils/worker-types.ts +79 -0
  321. package/src/utils/worker_broker.ts +523 -0
@@ -0,0 +1,111 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ /*
7
+
8
+ Expected globals:
9
+ material
10
+ light_accumulator_*
11
+
12
+ */
13
+
14
+ struct SpotLight {
15
+ vec3 ambient;
16
+ vec3 diffuse;
17
+ vec3 specular;
18
+ vec4 position;
19
+ float useLumaAttenuation;
20
+ vec3 attenuationCoefficients;
21
+
22
+ float attenuationExponent;
23
+ float innerRadius;
24
+ float outerRadius;
25
+
26
+ vec3 direction;
27
+ float spotCosCutoff;
28
+ float spotExponent;
29
+ vec2 lumaConeCos;
30
+ };
31
+
32
+ void calculateLight(in SpotLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
33
+
34
+ float dist = length(_light.position.xyz - _eyeToPoint);
35
+
36
+ // Compute vector from surface to light position
37
+ vec3 VP = (_light.position.xyz - _eyeToPoint) / dist;
38
+
39
+ // normal . light direction
40
+ float nDotVP = clamp(dot(_normal, VP), 0.0, 1.0);
41
+
42
+ // Attenuation defaults
43
+ float attenuation = 1.0;
44
+ if (_light.attenuationExponent != 0.0) {
45
+ float Rin = _light.innerRadius >= 0.0 ? _light.innerRadius : 1.0;
46
+ float e = _light.attenuationExponent;
47
+ if (_light.outerRadius >= 0.0) {
48
+ float Rdiff = _light.outerRadius-Rin;
49
+ float d = clamp(max(0.0,dist-Rin)/Rdiff, 0.0, 1.0);
50
+ attenuation = 1.0-(pow(d,e));
51
+ } else {
52
+ // If no outer is provide behaves like:
53
+ // https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
54
+ float d = max(0.0,dist-Rin)/Rin+1.0;
55
+ attenuation = clamp(1.0/(pow(d,e)), 0.0, 1.0);
56
+ }
57
+ } else {
58
+ float Rin = max(_light.innerRadius, 0.0);
59
+ if (_light.innerRadius >= 0.0) {
60
+ if (_light.outerRadius >= 0.0) {
61
+ float Rdiff = _light.outerRadius-Rin;
62
+ float d = clamp(max(0.0,dist-Rin)/Rdiff, 0.0, 1.0);
63
+ attenuation = 1.0-d*d;
64
+ } else {
65
+ // If no outer is provide behaves like:
66
+ // https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
67
+ float d = max(0.0,dist-Rin)/Rin+1.0;
68
+ attenuation = clamp(1.0/d, 0.0, 1.0);
69
+ }
70
+ } else {
71
+ if (_light.outerRadius >= 0.0) {
72
+ float d = clamp(dist/_light.outerRadius, 0.0, 1.0);
73
+ attenuation = 1.0-d*d;
74
+ } else {
75
+ attenuation = 1.0;
76
+ }
77
+ }
78
+ }
79
+
80
+ // spotlight attenuation factor
81
+ float spotAttenuation = 0.0;
82
+
83
+ // See if point on surface is inside cone of illumination
84
+ float spotDot = clamp(dot(-VP, _light.direction), 0.0, 1.0);
85
+
86
+ if (spotDot >= _light.spotCosCutoff) {
87
+ spotAttenuation = pow(spotDot, _light.spotExponent);
88
+ }
89
+ if (_light.useLumaAttenuation > 0.5) {
90
+ // Match luma.gl's minimum cone factor, including its small outside-cone contribution.
91
+ attenuation /= tangramNativeDistanceDenominator(_light.attenuationCoefficients, dist);
92
+ spotAttenuation = tangramNativeConeFactor(_light.lumaConeCos, spotDot) * pow(spotDot, _light.spotExponent);
93
+ }
94
+
95
+ light_accumulator_ambient.rgb += _light.ambient * attenuation * spotAttenuation;
96
+
97
+ #ifdef TANGRAM_MATERIAL_DIFFUSE
98
+ light_accumulator_diffuse.rgb += _light.diffuse * nDotVP * attenuation * spotAttenuation;
99
+ #endif
100
+
101
+ #ifdef TANGRAM_MATERIAL_SPECULAR
102
+ // Power factor for shiny speculars
103
+ float pf = 0.0;
104
+ if (nDotVP > 0.0) {
105
+ vec3 reflectVector = reflect(-VP, _normal);
106
+ float eyeDotR = max(dot(-normalize(_eyeToPoint), reflectVector), 0.0);
107
+ pf = pow(eyeDotR, material.shininess);
108
+ }
109
+ light_accumulator_specular.rgb += _light.specular * pf * attenuation * spotAttenuation;
110
+ #endif
111
+ }
@@ -0,0 +1,71 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {getGeographicProjectionProcedure, PROJECTION_CONSTANTS} from '../scene/projection_math';
6
+
7
+ /** Immutable worker query channels; no scene, GPU, provider or query-index ownership. */
8
+ interface DrapedTerrainBoundsInput {
9
+ /** Absolute Mercator XYZ, with authored offsets in meters. */
10
+ positions: Float64Array;
11
+ /** Current/previous physical DEM heights, interleaved per vertex. */
12
+ heights: Float32Array;
13
+ /** Optional current/previous affine globe bases and relief vectors, twelve channels per vertex. */
14
+ globeBasis?: Float32Array;
15
+ /** Actual rendered triangle indices. */
16
+ indices: Uint16Array | Uint32Array;
17
+ /** Optional trusted worker summary of these exact immutable channels. */
18
+ boundsSummary?: DrapedTerrainBoundsSummary;
19
+ }
20
+
21
+ /** Independent channel extrema enclose every convex rendered triangle throughout its height morph. */
22
+ export interface DrapedTerrainBoundsSummary {
23
+ /** Radius-one globe directions of indexed vertices, not geographic rectangle corners. */
24
+ directions: {minimum: [number, number, number]; maximum: [number, number, number]};
25
+ /** Authored meter offsets, independent of relief exaggeration. */
26
+ offsets: readonly [number, number];
27
+ /** Physical current/previous DEM endpoints, conservatively enclosing all morph fractions. */
28
+ heights: readonly [number, number];
29
+ /** Affine globe channels enclose canonical face cuts without projecting them back onto the sphere. */
30
+ globe?: {
31
+ /** Zero-relief common-space endpoint extrema. */
32
+ base: {minimum: number[]; maximum: number[]};
33
+ /** Common-space displacement per unit exaggeration. */
34
+ relief: {minimum: number[]; maximum: number[]};
35
+ };
36
+ }
37
+
38
+ /** Compatibility owners without worker summaries pay one indexed scan, never one scan per eye/frame. */
39
+ const boundsSummaries = new WeakMap<DrapedTerrainBoundsInput, DrapedTerrainBoundsSummary>();
40
+
41
+ /** Compute bounds from the actual indexed vertices so long globe chords and unwrapped tiles remain enclosed. */
42
+ export function summarizeDrapedTerrainBounds(mesh: DrapedTerrainBoundsInput): DrapedTerrainBoundsSummary {
43
+ const cached = mesh.boundsSummary ?? boundsSummaries.get(mesh);
44
+ if (cached) return cached;
45
+ const directions: DrapedTerrainBoundsSummary['directions'] = {minimum: [Infinity, Infinity, Infinity], maximum: [-Infinity, -Infinity, -Infinity]};
46
+ const offsets: [number, number] = [Infinity, -Infinity], heights: [number, number] = [Infinity, -Infinity];
47
+ const globeBounds = mesh.globeBasis ? {base: {minimum: [Infinity, Infinity, Infinity], maximum: [-Infinity, -Infinity, -Infinity]},
48
+ relief: {minimum: [Infinity, Infinity, Infinity], maximum: [-Infinity, -Infinity, -Infinity]}} : undefined;
49
+ if (mesh.globeBasis && mesh.globeBasis.length !== mesh.positions.length * 4) throw new Error('Invalid terrain globe basis channels');
50
+ const mercator = getGeographicProjectionProcedure('web-mercator'), globe = getGeographicProjectionProcedure('globe');
51
+ for (const vertex of mesh.indices) {
52
+ if (vertex * 3 + 2 >= mesh.positions.length) throw new Error('Invalid terrain bounds index');
53
+ const position = [mesh.positions[vertex * 3], mesh.positions[vertex * 3 + 1], mesh.positions[vertex * 3 + 2]] as const;
54
+ const current = mesh.heights[vertex * 2], previous = mesh.heights[vertex * 2 + 1];
55
+ if (![...position, current, previous].every(Number.isFinite)) throw new Error('Invalid terrain bounds channels');
56
+ const direction = globe.project(mercator.unproject([position[0], position[1], 0]));
57
+ for (const axis of [0, 1, 2]) {
58
+ directions.minimum[axis] = Math.min(directions.minimum[axis], direction[axis] / PROJECTION_CONSTANTS.globeRadius);
59
+ directions.maximum[axis] = Math.max(directions.maximum[axis], direction[axis] / PROJECTION_CONSTANTS.globeRadius);
60
+ if (mesh.globeBasis && globeBounds) for (const endpoint of [0, 6]) {
61
+ const base = mesh.globeBasis[vertex * 12 + endpoint + axis], relief = mesh.globeBasis[vertex * 12 + endpoint + 3 + axis];
62
+ if (!Number.isFinite(base) || !Number.isFinite(relief)) throw new Error('Invalid terrain globe basis channels');
63
+ globeBounds.base.minimum[axis] = Math.min(globeBounds.base.minimum[axis], base); globeBounds.base.maximum[axis] = Math.max(globeBounds.base.maximum[axis], base);
64
+ globeBounds.relief.minimum[axis] = Math.min(globeBounds.relief.minimum[axis], relief); globeBounds.relief.maximum[axis] = Math.max(globeBounds.relief.maximum[axis], relief);
65
+ }
66
+ }
67
+ offsets[0] = Math.min(offsets[0], position[2]); offsets[1] = Math.max(offsets[1], position[2]);
68
+ heights[0] = Math.min(heights[0], current, previous); heights[1] = Math.max(heights[1], current, previous);
69
+ }
70
+ const summary = {directions, offsets, heights, ...(globeBounds ? {globe: globeBounds} : {})}; boundsSummaries.set(mesh, summary); return summary;
71
+ }
@@ -0,0 +1,217 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {prepareGlobeTerrainMeshSteps, type GlobeTerrainMeshTemplate} from './globe-terrain';
6
+ import type {TerrainHeightGrid} from './terrain-data';
7
+ import type {TerrainResourceBudget, TerrainResourceLease} from './terrain-resource-budget';
8
+
9
+ /** Complete, immutable neighborhood generation; only library-produced handles can resolve templates. */
10
+ export interface GlobeTerrainPreparationSnapshot {
11
+ /** Ordered immutable source identities; applications must not mutate their samples. */
12
+ readonly grids: readonly TerrainHeightGrid[];
13
+ /** Uniform curved-cell resolution for all stitched tiles. */
14
+ readonly resolution: number;
15
+ /** Owned prepared typed arrays, excluding source, display/query buffers and GPU allocations. */
16
+ readonly byteLength: number;
17
+ }
18
+
19
+ /** One source and the touching immutable neighbors that determined its topology and lighting. */
20
+ interface PreparedTile {
21
+ grid: TerrainHeightGrid;
22
+ neighbors: readonly TerrainHeightGrid[];
23
+ template: GlobeTerrainMeshTemplate;
24
+ }
25
+
26
+ /** Snapshot internals cannot be forged or modified through an exported handle. */
27
+ const snapshots = new WeakMap<GlobeTerrainPreparationSnapshot, readonly PreparedTile[]>();
28
+
29
+ /** Validate library ownership, including empty snapshots whose templates cannot be looked up. */
30
+ export function assertGlobeTerrainPreparationSnapshot(snapshot: GlobeTerrainPreparationSnapshot): void {
31
+ if (!snapshots.has(snapshot)) throw new Error('Prepared globe terrain requires a completed snapshot');
32
+ }
33
+
34
+ /** Resolve only a source identity belonging to a completed preparation generation. */
35
+ export function getPreparedGlobeTerrainTemplate(snapshot: GlobeTerrainPreparationSnapshot, grid: TerrainHeightGrid): GlobeTerrainMeshTemplate {
36
+ assertGlobeTerrainPreparationSnapshot(snapshot);
37
+ const tile = snapshots.get(snapshot)?.find(candidate => candidate.grid === grid);
38
+ if (!tile) throw new Error('Prepared globe terrain requires a completed snapshot and matching source identity');
39
+ return tile.template;
40
+ }
41
+
42
+ /** Detached cooperative-work diagnostics, not a frame-time or whole-process memory measurement. */
43
+ export interface GlobeTerrainPreparationStatistics {
44
+ /** Tiles still awaiting preparation in the latest request. */
45
+ pending: number;
46
+ /** Unique current and staged template storage; shared templates count once. */
47
+ retainedBytes: number;
48
+ /** Maximum retained template bytes permitted by this owner. */
49
+ byteLimit: number;
50
+ /** Fully published generations. */
51
+ committed: number;
52
+ /** Requests replaced before completion. */
53
+ cancelled: number;
54
+ /** New templates admitted by the latest generation. */
55
+ prepared: number;
56
+ /** Templates reused by the latest generation. */
57
+ reused: number;
58
+ /** Cooperative CPU slices in the latest generation. */
59
+ slices: number;
60
+ /** Last slice's elapsed time; an indivisible step may exceed its target. */
61
+ lastSliceMs: number;
62
+ /** Largest observed slice in the latest generation. */
63
+ maxSliceMs: number;
64
+ /** CPU slice elapsed sum, excluding time yielded back to the host. */
65
+ workMs: number;
66
+ /** Largest current-plus-candidate typed-template requirement observed before allocation. */
67
+ requiredPeakBytes: number;
68
+ /** Last preparation/admission failure; retry is explicit. */
69
+ error?: string;
70
+ }
71
+
72
+ /** Same-datum touching footprints, including antimeridian edges and corners. */
73
+ function getNeighbors(grid: TerrainHeightGrid, grids: readonly TerrainHeightGrid[]): TerrainHeightGrid[] {
74
+ const circumference = 2 * Math.PI * 6378137;
75
+ return grids.filter(candidate => candidate !== grid && [-circumference, 0, circumference].some(shift =>
76
+ candidate.bounds[0] + shift <= grid.bounds[2] && candidate.bounds[2] + shift >= grid.bounds[0] && candidate.bounds[1] <= grid.bounds[3] && candidate.bounds[3] >= grid.bounds[1]));
77
+ }
78
+
79
+ /** Ordered identity comparison; no expensive sample scan or source mutation is performed. */
80
+ function sameGrids(first: readonly TerrainHeightGrid[], second: readonly TerrainHeightGrid[]): boolean {
81
+ return first.length === second.length && first.every((grid, index) => grid === second[index]);
82
+ }
83
+
84
+ /** Latest-request-wins preparation driven by the host, with atomic stitched snapshots and bounded retention. */
85
+ export class GlobeTerrainPreparation {
86
+ private current?: GlobeTerrainPreparationSnapshot;
87
+ private target?: {grids: readonly TerrainHeightGrid[]; resolution: number};
88
+ private iterator?: Generator<void, void, void>;
89
+ private staged: PreparedTile[] = [];
90
+ private disposed = false;
91
+ private readonly statistics: GlobeTerrainPreparationStatistics;
92
+ /** Leases cover this owner's current/staged templates, not external snapshots or scratch. */
93
+ private readonly leases = new Map<GlobeTerrainMeshTemplate, TerrainResourceLease>();
94
+ /** Optional shared admission with sources, display preparation and renderer owners. */
95
+ private readonly resourceBudget?: TerrainResourceBudget;
96
+
97
+ /** Retention includes the currently displayed and partially prepared generations, but not transient scratch arrays. */
98
+ constructor(maxRetainedBytes = 96 * 1024 * 1024, options: {
99
+ /** Shared registered-allocation budget; independent local limits still apply. */
100
+ resourceBudget?: TerrainResourceBudget;
101
+ } = {}) {
102
+ if (!Number.isSafeInteger(maxRetainedBytes) || maxRetainedBytes < 0) throw new Error('Prepared terrain byte limit must be a non-negative integer');
103
+ this.resourceBudget = options.resourceBudget;
104
+ this.statistics = {pending: 0, retainedBytes: 0, byteLimit: maxRetainedBytes, committed: 0, cancelled: 0, prepared: 0, reused: 0, slices: 0, lastSliceMs: 0, maxSliceMs: 0, workMs: 0, requiredPeakBytes: 0};
105
+ }
106
+
107
+ /** Replace obsolete staged work; unchanged requests and failed generations do not restart automatically. */
108
+ request(grids: readonly TerrainHeightGrid[], resolution = 64): boolean {
109
+ if (this.disposed) throw new Error('Globe terrain preparation is disposed');
110
+ if (!Number.isSafeInteger(resolution) || resolution < 2 || resolution > 256) throw new Error('Globe terrain resolution must be an integer in [2, 256]');
111
+ if (grids.some(grid => grid.verticalDatum !== grids[0].verticalDatum)) throw new Error('Globe terrain grids require one compatible vertical datum');
112
+ if (new Set(grids.map(grid => grid.bounds.join(','))).size !== grids.length) throw new Error('Globe terrain grids must have distinct footprints');
113
+ if (this.target?.resolution === resolution && sameGrids(this.target.grids, grids)) return false;
114
+ this.cancel();
115
+ this.target = {grids: Object.freeze([...grids]), resolution};
116
+ Object.assign(this.statistics, {pending: grids.length, prepared: 0, reused: 0, slices: 0, lastSliceMs: 0, maxSliceMs: 0, workMs: 0, requiredPeakBytes: 0, error: undefined});
117
+ this.iterator = this.prepare(this.target.grids, resolution);
118
+ return true;
119
+ }
120
+
121
+ /** Run at least one bounded step, then yield after the elapsed target; true means a complete generation was committed. */
122
+ advance(budgetMs = 4, now: () => number = () => performance.now()): boolean {
123
+ if (!Number.isFinite(budgetMs) || budgetMs <= 0) throw new Error('Preparation slice target must be positive');
124
+ if (!this.iterator) return false;
125
+ const started = now();
126
+ let committed = false;
127
+ try {
128
+ do {
129
+ const result = this.iterator.next();
130
+ if (result.done) {this.iterator = undefined; committed = true; break;}
131
+ } while (now() - started < budgetMs);
132
+ } catch (error) {
133
+ this.iterator?.return(); this.iterator = undefined; this.staged = []; this.statistics.pending = 0;
134
+ this.releaseUnusedLeases();
135
+ this.statistics.error = error instanceof Error ? error.message : String(error);
136
+ }
137
+ const elapsed = Math.max(0, now() - started);
138
+ this.statistics.slices++; this.statistics.lastSliceMs = elapsed; this.statistics.maxSliceMs = Math.max(this.statistics.maxSliceMs, elapsed); this.statistics.workMs += elapsed;
139
+ return committed;
140
+ }
141
+
142
+ /** Retry a failed immutable request without resetting the displayed snapshot. */
143
+ retry(): boolean {
144
+ if (!this.statistics.error || !this.target || this.disposed) return false;
145
+ const {grids, resolution} = this.target; this.target = undefined;
146
+ return this.request(grids, resolution);
147
+ }
148
+
149
+ /** Completed snapshot only; partial generations are never exposed for rendering or picking. */
150
+ getSnapshot(): GlobeTerrainPreparationSnapshot | undefined {return this.current;}
151
+
152
+ /** Detached diagnostic snapshot, including unique current/staged template backing storage. */
153
+ getStatistics(): GlobeTerrainPreparationStatistics {
154
+ return {...this.statistics, retainedBytes: this.getRetainedBytes(this.staged)};
155
+ }
156
+
157
+ /** True until the latest generation commits, fails or is cancelled by teardown. */
158
+ isPending(): boolean {return Boolean(this.iterator);}
159
+
160
+ /** Cancel pending work and release its reservations without discarding the displayed snapshot. */
161
+ cancel(): boolean {
162
+ const pending = Boolean(this.iterator);
163
+ if (pending) this.statistics.cancelled++;
164
+ this.iterator?.return(); this.iterator = undefined; this.staged = []; this.target = undefined; this.statistics.pending = 0;
165
+ this.releaseUnusedLeases();
166
+ return pending;
167
+ }
168
+
169
+ /** Release references to current, staged and source data; safe to repeat. */
170
+ destroy(): void {
171
+ this.cancel(); this.current = undefined; this.releaseUnusedLeases();
172
+ this.statistics.pending = 0; this.disposed = true;
173
+ }
174
+
175
+ /** Count shared template handles once across visible and candidate generations. */
176
+ private getRetainedBytes(staged: readonly PreparedTile[]): number {
177
+ const templates = new Set([...(this.current ? snapshots.get(this.current) ?? [] : []), ...staged].map(tile => tile.template));
178
+ return [...templates].reduce((sum, template) => sum + template.byteLength, 0);
179
+ }
180
+
181
+ /** Release only templates no longer retained by this owner; external snapshot ownership is separate. */
182
+ private releaseUnusedLeases(): void {
183
+ const retained = new Set([...(this.current ? snapshots.get(this.current) ?? [] : []), ...this.staged].map(tile => tile.template));
184
+ for (const [template, lease] of this.leases) if (!retained.has(template)) {lease.release(); this.leases.delete(template);}
185
+ }
186
+
187
+ /** Preserve unaffected immutable neighborhoods; commit every stitched tile together only after admission succeeds. */
188
+ private *prepare(grids: readonly TerrainHeightGrid[], resolution: number): Generator<void, void, void> {
189
+ const previous = new Map((this.current ? snapshots.get(this.current) ?? [] : []).map(tile => [tile.grid, tile]));
190
+ for (const grid of grids) {
191
+ const neighbors = getNeighbors(grid, grids), retained = previous.get(grid);
192
+ const reuse = retained && this.current?.resolution === resolution && retained.neighbors.length === neighbors.length && retained.neighbors.every((neighbor, index) => neighbor === neighbors[index]);
193
+ let reservation: TerrainResourceLease | undefined;
194
+ let template: GlobeTerrainMeshTemplate;
195
+ try {
196
+ template = reuse ? retained.template : yield* prepareGlobeTerrainMeshSteps(grid, {resolution, neighbors,
197
+ onAllocate: (bytes, allocation) => {
198
+ const required = this.getRetainedBytes(this.staged) + bytes;
199
+ this.statistics.requiredPeakBytes = Math.max(this.statistics.requiredPeakBytes, required);
200
+ if (required > this.statistics.byteLimit) throw new Error('Prepared globe terrain retained-byte limit exceeded; current terrain retained');
201
+ if (this.resourceBudget) {
202
+ reservation = this.resourceBudget.reserveShared(allocation, 'retained', bytes) ?? undefined;
203
+ if (!reservation) throw new Error('Prepared globe terrain shared resource budget exceeded; current terrain retained');
204
+ }
205
+ }});
206
+ if (reservation) {this.leases.set(template, reservation); reservation = undefined;}
207
+ } finally {reservation?.release();}
208
+ const candidate = {grid, neighbors, template};
209
+ if (this.getRetainedBytes([...this.staged, candidate]) > this.statistics.byteLimit) throw new Error('Prepared globe terrain retained-byte limit exceeded; current terrain retained');
210
+ this.staged.push(candidate); this.statistics.pending--;
211
+ if (reuse) this.statistics.reused++; else this.statistics.prepared++;
212
+ yield;
213
+ }
214
+ const snapshot = Object.freeze({grids, resolution, byteLength: this.staged.reduce((sum, tile) => sum + tile.template.byteLength, 0)});
215
+ snapshots.set(snapshot, this.staged); this.current = snapshot; this.staged = []; this.statistics.committed++; this.releaseUnusedLeases();
216
+ }
217
+ }