@tangram.gl/tangram-renderer 0.0.0-stage → 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 (321) hide show
  1. package/README.md +59 -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,259 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Matrix4} from '@math.gl/core';
6
+ import type HostFrame from '../scene/host_frame';
7
+ import type {LabelMesh, LabelTile, MeshLabel} from './main-pass-types';
8
+ import {getGeographicProjectionProcedure, PROJECTION_CONSTANTS, projectGeographicPosition} from '../scene/projection_math';
9
+ import {resolveLabelPlacement} from '../map-logic/label-placement';
10
+ import type {ScreenLabelCandidate} from '../map-logic/label-placement';
11
+ import {areGeographicLabelCopies} from '../map-logic/label-identity';
12
+ import type {GeographicLabelAnchor} from '../map-logic/label-identity';
13
+ import {unionScreenBounds as unionBounds} from '../map-logic/screen-bounds';
14
+ import type {ScreenBounds} from '../map-logic/screen-bounds';
15
+ import type {TerrainSurfaceCollection} from '../selection/terrain_surface';
16
+
17
+ /** Settled surfaces retain only one eye signature and a bounded set of exact anchor results. */
18
+ const terrainVisibility = new WeakMap<TerrainSurfaceCollection, {eyes: string; results: Map<string, boolean>}>();
19
+
20
+ type Bounds = ScreenBounds;
21
+ /** One worker identity may have multiple atlas/outline mesh ranges. */
22
+ interface Candidate extends ScreenLabelCandidate, GeographicLabelAnchor {
23
+ id: string;
24
+ label: MeshLabel;
25
+ tile: LabelTile;
26
+ parts: {mesh: LabelMesh; label: MeshLabel}[];
27
+ boxes: Map<string, Bounds>;
28
+ anchor: [number, number];
29
+ height: number;
30
+ }
31
+ /** Immutable domain eligibility must survive later hide/show writes. */
32
+ const eligible = new WeakMap<LabelMesh, Map<MeshLabel, boolean>>();
33
+
34
+ /**
35
+ * Lay out projected billboard candidates in CSS pixels before either eye draws.
36
+ * One shared mask is collision-free in every eye, avoiding GPU buffer mutations
37
+ * between queued stereo draws. Worker snapshots and source geometry stay immutable.
38
+ * @returns Whether masks changed or pending label meshes were activated.
39
+ */
40
+ export function layoutProjectedAnnotations(tiles: readonly LabelTile[], frame: HostFrame,
41
+ {clockwiseRotation = false, terrainExaggeration = 1, terrainTransitionDuration = 0, terrainTime = performance.now(), terrainSurface}: {
42
+ clockwiseRotation?: boolean;
43
+ /** Same visual relief multiplier used by the terrain vertex shaders. */
44
+ terrainExaggeration?: number;
45
+ /** Per-mesh transition duration in milliseconds, matching the renderer. */
46
+ terrainTransitionDuration?: number;
47
+ /** Shared monotonic frame time, so both eyes and color agree during morphing. */
48
+ terrainTime?: number;
49
+ /** Exact ground generation about to draw; missing triangles never certify occlusion. */
50
+ terrainSurface?: TerrainSurfaceCollection;
51
+ } = {}): boolean {
52
+ let terrainCache = terrainSurface && terrainVisibility.get(terrainSurface);
53
+ const eyeSignature = frame.renderViews.map(view => `${view.id}/${view.camera.position.join(',')}/${Array.from(view.camera.view).join(',')}/${Array.from(view.camera.projection).join(',')}`).join(';');
54
+ if (terrainSurface && terrainCache?.eyes !== eyeSignature) {
55
+ terrainCache = {eyes: eyeSignature, results: new Map()}; terrainVisibility.set(terrainSurface, terrainCache);
56
+ }
57
+ const cameras = frame.renderViews.map(eye => {
58
+ const matrix = frame.projection.type === 'globe' ? new Matrix4(Array.from(eye.camera.projection)) :
59
+ new Matrix4(Array.from(eye.camera.projection)).multiplyRight(Array.from(eye.camera.view));
60
+ return {eye, matrix, inverse: terrainSurface ? invertFrameMatrix(matrix) : undefined};
61
+ });
62
+ const candidates = new Map<string, Candidate>();
63
+ for (const tile of tiles) {
64
+ const meshes = {...tile.meshes, ...tile.pending_label_meshes};
65
+ for (const [style, parts] of Object.entries(meshes)) {
66
+ // A resident proxy may no longer draw this style once its child labels are ready.
67
+ if (tile.isProxy() && tile.shouldProxyForStyle?.(style) === false) continue;
68
+ for (const mesh of parts) {
69
+ if (!mesh.valid || !mesh.labels || !mesh.vertex_data || !mesh.vertex_layout.offset || mesh.vertex_layout.offset.a_shape === undefined ||
70
+ (mesh.vertex_layout.offset.a_projected_position === undefined && mesh.vertex_layout.offset.a_position === undefined)) continue;
71
+ for (const label of Object.values(mesh.labels)) {
72
+ const id = String(label.container.label.id);
73
+ let candidate = candidates.get(id);
74
+ if (!candidate) {
75
+ const position = label.container.label.position;
76
+ const unitsPerMeter = 4096 * 2 ** tile.coords.z / (2 * Math.PI * 6378137);
77
+ const first = label.ranges[0]?.[0];
78
+ const data = new DataView(mesh.vertex_data.buffer, mesh.vertex_data.byteOffset, mesh.vertex_data.byteLength);
79
+ const height = label.container.label.layout.projected_height ?? (first === undefined ||
80
+ mesh.vertex_layout.offset.a_position === undefined ? 0 : (mesh.vertex_layout.offset.a_terrain === undefined ? data.getInt16(first + mesh.vertex_layout.offset.a_position + 4, true) : data.getFloat32(first + mesh.vertex_layout.offset.a_position + 8, true)));
81
+ const layout = label.container.label.layout;
82
+ candidate = {id, label, tile, parts: [], boxes: new Map(), height,
83
+ linkedId: String(label.container.linked), collide: layout.projected_collide,
84
+ identity: layout.projected_identity, repeatGroup: layout.repeat_group, repeatDistance: layout.repeat_distance,
85
+ sourceTileIdentity: tile, sourceZoom: tile.coords.z, anchor: [
86
+ tile.min.x + position[0] / unitsPerMeter, tile.min.y + position[1] / unitsPerMeter]};
87
+ candidates.set(id, candidate);
88
+ }
89
+ candidate.parts.push({mesh, label});
90
+ for (const {eye, matrix, inverse} of cameras) {
91
+ const box = getScreenBounds(mesh, label, tile, frame, eye.camera.position, matrix,
92
+ eye.viewport.width, eye.viewport.height, clockwiseRotation, terrainExaggeration, terrainTransitionDuration, terrainTime, terrainSurface, terrainCache?.results, inverse, eye.id);
93
+ if (box) candidate.boxes.set(eye.id, unionBounds(candidate.boxes.get(eye.id), box));
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ const sorted = [...candidates.values()].sort((left, right) =>
100
+ left.label.container.label.layout.priority - right.label.container.label.layout.priority ||
101
+ left.tile.build_id - right.tile.build_id || Number(left.id) - Number(right.id));
102
+ const visibility = resolveLabelPlacement(sorted, {
103
+ viewports: new Map(frame.renderViews.map(eye => [eye.id, eye.viewport])),
104
+ isDuplicate: (candidate, previous) => areGeographicLabelCopies(candidate, previous, {
105
+ worldWidth: 2 * Math.PI * PROJECTION_CONSTANTS.mercatorRadius,
106
+ wrapHorizontal: frame.projection.type === 'globe'
107
+ })
108
+ });
109
+ const uploads = new Set<LabelMesh>();
110
+ for (const candidate of sorted) for (const {mesh, label} of candidate.parts) {
111
+ if (!mesh.vertex_data || !mesh.vertex_layout.offset) continue;
112
+ const view = new DataView(mesh.vertex_data.buffer, mesh.vertex_data.byteOffset, mesh.vertex_data.byteLength);
113
+ for (const [start, count] of label.ranges) for (let index = 0; index < count; index++) {
114
+ const offset = start + index * mesh.vertex_layout.stride + mesh.vertex_layout.offset.a_shape + 6;
115
+ const shown = visibility.get(candidate) && eligible.get(mesh)?.get(label) ? 1 : 0;
116
+ if (view.getInt16(offset, true) !== shown) {
117
+ view.setInt16(offset, shown, true);
118
+ uploads.add(mesh);
119
+ }
120
+ }
121
+ }
122
+ uploads.forEach(mesh => mesh.upload());
123
+ const pending = tiles.some(tile => tile.pending_label_meshes !== null);
124
+ tiles.forEach(tile => tile.swapPendingLabels());
125
+ return uploads.size > 0 || pending;
126
+ }
127
+
128
+ /** Reconstruct the shader's rotated pixel quad from retained packed geometry, including atlas ranges. */
129
+ function getScreenBounds(mesh: LabelMesh, label: MeshLabel, tile: LabelTile, frame: HostFrame,
130
+ eye: readonly number[], matrix: Matrix4, width: number, height: number,
131
+ clockwiseRotation: boolean, terrainExaggeration: number, transitionDuration: number, terrainTime: number,
132
+ terrainSurface?: TerrainSurfaceCollection, terrainCache?: Map<string, boolean>, inverse?: Matrix4, eyeId?: string): Bounds | null {
133
+ let eligibility = eligible.get(mesh);
134
+ if (!eligibility) eligible.set(mesh, eligibility = new Map());
135
+ if (!mesh.vertex_data || !mesh.vertex_layout.offset) return null;
136
+ const data = new DataView(mesh.vertex_data.buffer, mesh.vertex_data.byteOffset, mesh.vertex_data.byteLength);
137
+ const {stride, offset} = mesh.vertex_layout;
138
+ const first = label.ranges[0]?.[0];
139
+ if (first === undefined) return null;
140
+ if (!eligibility.has(label)) eligibility.set(label, data.getInt16(first + offset.a_shape + 6, true) !== 0);
141
+ if (!eligibility.get(label)) return null;
142
+ let bounds: Bounds | undefined;
143
+ /** A billboard has constant clip depth; probe its rectangle, not only its geographic anchor. */
144
+ let clipDepth: number | undefined;
145
+ let anchorScreen: [number, number] | undefined;
146
+ for (const [start, count] of label.ranges) for (let index = 0; index < count; index++) {
147
+ const base = start + index * stride;
148
+ let anchor: [number, number, number];
149
+ if (offset.a_projected_position !== undefined) {
150
+ anchor = [data.getFloat32(base + offset.a_projected_position, true),
151
+ data.getFloat32(base + offset.a_projected_position + 4, true),
152
+ data.getFloat32(base + offset.a_projected_position + 8, true)];
153
+ } else {
154
+ const scale = 2 * Math.PI * PROJECTION_CONSTANTS.mercatorRadius / (4096 * 2 ** tile.coords.z);
155
+ anchor = offset.a_terrain === undefined ? [tile.min.x + data.getInt16(base + offset.a_position, true) * scale,
156
+ tile.min.y + data.getInt16(base + offset.a_position + 2, true) * scale,
157
+ data.getInt16(base + offset.a_position + 4, true)] : [
158
+ tile.min.x + data.getFloat32(base + offset.a_position, true) * scale,
159
+ tile.min.y + data.getFloat32(base + offset.a_position + 4, true) * scale,
160
+ data.getFloat32(base + offset.a_position + 8, true)];
161
+ if (offset.a_terrain !== undefined) {
162
+ if (data.getFloat32(base + offset.a_terrain + 12, true) < 0.5) return null;
163
+ mesh.terrainVisibleAt ??= terrainTime;
164
+ const duration = mesh.variant?.terrainTransitionDuration ?? transitionDuration;
165
+ const blend = duration ? Math.max(0, Math.min(1, (terrainTime - mesh.terrainVisibleAt) / duration)) : 1;
166
+ const current = data.getFloat32(base + offset.a_terrain, true);
167
+ const previous = data.getFloat32(base + offset.a_terrain_previous, true);
168
+ anchor[2] += (previous + (current - previous) * blend) * terrainExaggeration;
169
+ }
170
+ if (frame.projection.type === 'globe') {
171
+ anchor = projectGeographicPosition(getGeographicProjectionProcedure('web-mercator').unproject(anchor), 'globe');
172
+ if (isGlobeOccluded(anchor, eye)) return null;
173
+ }
174
+ }
175
+ const position = matrix.transform([...anchor, 1]);
176
+ if (position[3] <= 0 || position[2] < -position[3] || position[2] > position[3]) return null;
177
+ const depth = position[2] / position[3];
178
+ // Curved labels may have different anchors/depths. Unknown shared depth
179
+ // keeps them collision-eligible rather than pretending this is a quad.
180
+ clipDepth = clipDepth === undefined ? depth : clipDepth === depth ? depth : NaN;
181
+ anchorScreen = [(position[0] / position[3] + 1) * width / 2, (1 - position[1] / position[3]) * height / 2];
182
+ const shape = base + offset.a_shape;
183
+ // Retain the existing GLSL clockwise and WGSL counter-clockwise sprite conventions.
184
+ const angle = data.getInt16(shape + 4, true) / 4096 * (clockwiseRotation ? -1 : 1);
185
+ let point: [number, number] = [data.getInt16(shape, true) / 256, data.getInt16(shape + 2, true) / 256];
186
+ const displacement: [number, number] = offset.a_offset === undefined ? [0, 0] :
187
+ [data.getInt16(base + offset.a_offset, true), -data.getInt16(base + offset.a_offset + 2, true)];
188
+ if (offset.a_offsets !== undefined && data.getUint16(base + offset.a_offsets, true) !== 0) {
189
+ const zoom = Math.max(0, Math.min(1, frame.geographicAnchor.zoom - tile.style_z));
190
+ const preAngle = mixCurve(Array.from({length: 4}, (_, index) =>
191
+ data.getInt8(base + offset.a_pre_angles + index) * Math.PI / 128), zoom);
192
+ const curveAngle = mixCurve(Array.from({length: 4}, (_, index) =>
193
+ data.getInt16(base + offset.a_angles + index * 2, true) * Math.PI / 16384), zoom);
194
+ point = rotate(point, preAngle * (clockwiseRotation ? -1 : 1));
195
+ point[0] += mixCurve(Array.from({length: 4}, (_, index) => data.getUint16(base + offset.a_offsets + index * 2, true) / 64), zoom);
196
+ point = rotate(point, curveAngle * (clockwiseRotation ? -1 : 1));
197
+ const rotatedOffset = rotate(displacement, angle);
198
+ point = [point[0] + rotatedOffset[0], point[1] + rotatedOffset[1]];
199
+ } else point = rotate([point[0] + displacement[0], point[1] + displacement[1]], angle);
200
+ const screenX = (position[0] / position[3] + 1) * width / 2 + point[0];
201
+ const screenY = (1 - position[1] / position[3]) * height / 2 - point[1];
202
+ bounds = unionBounds(bounds, [screenX, screenY, screenX, screenY]);
203
+ }
204
+ if (!bounds) return null;
205
+ if (terrainSurface && terrainCache && inverse && anchorScreen && typeof clipDepth === 'number' && Number.isFinite(clipDepth)) {
206
+ const depth = clipDepth;
207
+ const probes = [[bounds[0], bounds[1]], [bounds[0], bounds[3]], [bounds[2], bounds[1]], [bounds[2], bounds[3]],
208
+ [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2]];
209
+ const isBlocked = (x: number, y: number): boolean => {
210
+ const key = `${eyeId}/${width},${height}/${x},${y},${depth}`;
211
+ const cached = terrainCache.get(key);
212
+ if (cached !== undefined) return cached;
213
+ const horizontal = x / width * 2 - 1, vertical = 1 - y / height * 2;
214
+ const near = inverse.transform([horizontal, vertical, -1, 1]), target = inverse.transform([horizontal, vertical, depth, 1]);
215
+ const start: [number, number, number] = [near[0] / near[3], near[1] / near[3], near[2] / near[3]];
216
+ const end: [number, number, number] = [target[0] / target[3], target[1] / target[3], target[2] / target[3]];
217
+ const inset = terrainSurface.projection === 'globe' ? 0.25 * PROJECTION_CONSTANTS.globeRadius / PROJECTION_CONSTANTS.earthRadius : 0.25;
218
+ const hidden = [...start, ...end].every(Number.isFinite) && terrainSurface.intersectSegment(start, end, {startInset: inset, endInset: inset}) !== null;
219
+ if (terrainCache.size >= 10000) terrainCache.clear();
220
+ terrainCache.set(key, hidden); return hidden;
221
+ };
222
+ // This refinement may restore an anchor-hidden label, never hide one
223
+ // whose original anchor test was clear (including offset billboards).
224
+ const blocked = isBlocked(...anchorScreen) && probes.every(([x, y]) => isBlocked(x, y));
225
+ if (blocked) return null;
226
+ }
227
+ const buffer = label.container.label.layout.buffer ?? [0, 0];
228
+ bounds = [bounds[0] - buffer[0] - 1, bounds[1] - buffer[1] - 1,
229
+ bounds[2] + buffer[0] + 1, bounds[3] + buffer[1] + 1];
230
+ return bounds[2] < 0 || bounds[0] > width || bounds[3] < 0 || bounds[1] > height ? null : bounds;
231
+ }
232
+
233
+ /** Singular host matrices leave terrain visibility unknown rather than hiding annotations. */
234
+ function invertFrameMatrix(matrix: Matrix4): Matrix4 | undefined {
235
+ try {return new Matrix4(matrix).invert();}
236
+ catch {return undefined;}
237
+ }
238
+
239
+ /** Mirror the production shader's finite eye-to-anchor sphere segment and f32 tolerance. */
240
+ function isGlobeOccluded(position: readonly number[], eye: readonly number[]): boolean {
241
+ const radius = PROJECTION_CONSTANTS.globeRadius;
242
+ if (Math.hypot(...eye) <= radius) return false;
243
+ const segment = position.map((value, index) => value - eye[index]);
244
+ const squaredLength = segment.reduce((sum, value) => sum + value * value, 0);
245
+ if (squaredLength === 0) return false;
246
+ const amount = Math.max(0, Math.min(1, -eye.reduce((sum, value, index) => sum + value * segment[index], 0) / squaredLength));
247
+ const closest = eye.map((value, index) => value * (1 - amount) + position[index] * amount);
248
+ return closest.reduce((sum, value) => sum + value * value, 0) / radius ** 2 < 1 - 1e-6;
249
+ }
250
+ /** Apply the same clockwise GLSL or counterclockwise WGSL billboard convention. */
251
+ function rotate(point: readonly [number, number], angle: number): [number, number] {
252
+ return [point[0] * Math.cos(angle) - point[1] * Math.sin(angle), point[0] * Math.sin(angle) + point[1] * Math.cos(angle)];
253
+ }
254
+ /** Preserve the shader's 0/.33/.66/.99 piecewise interpolation, including its last interval. */
255
+ function mixCurve(values: readonly number[], zoom: number): number {
256
+ const mix = (left: number, right: number, amount: number) => left * (1 - amount) + right * amount;
257
+ return zoom < 0.33 ? mix(values[0], values[1], 3 * zoom) : mix(values[1],
258
+ mix(values[2], values[3], 3 * (Math.max(zoom, 0.66) - 0.66)), 3 * (Math.max(0.33, Math.min(0.66, zoom)) - 0.33));
259
+ }
@@ -0,0 +1,72 @@
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
+ type Position = [number, number];
7
+ type RepeatObject = {position?: Position};
8
+ type RepeatLayout = {repeat_distance?: number; repeat_group?: string; repeat_scale: number};
9
+ export default class RepeatGroup {
10
+ static groups: Record<string, Record<string, RepeatGroup>> = {};
11
+ key: string;
12
+ repeat_dist: number;
13
+ repeat_dist_sq: number;
14
+ positions: Position[];
15
+
16
+ constructor (key: string, repeat_dist: number) {
17
+ this.key = key;
18
+ this.repeat_dist = repeat_dist;
19
+ this.repeat_dist_sq = this.repeat_dist * this.repeat_dist;
20
+ this.positions = [];
21
+ }
22
+
23
+ // Check an object to see if it's a repeat in this group
24
+ check (obj: RepeatObject): boolean | undefined {
25
+ // Check distance from new object to objects already in group
26
+ const p1 = obj.position!;
27
+ for (let i=0; i < this.positions.length; i++) {
28
+ let p2 = this.positions[i];
29
+ let dx = p1[0] - p2[0];
30
+ let dy = p1[1] - p2[1];
31
+ let dist_sq = dx * dx + dy * dy;
32
+
33
+ // Found an existing object within allowed distance
34
+ if (dist_sq < this.repeat_dist_sq) {
35
+ return true;
36
+ }
37
+ }
38
+ }
39
+
40
+ // Add object to this group
41
+ add (obj: RepeatObject): void {
42
+ // only store object's position, to save space / prevent unnecessary references
43
+ if (obj && obj.position) {
44
+ this.positions.push(obj.position);
45
+ }
46
+ }
47
+
48
+ // Static methods are used to manage repeat groups, within and across tiles
49
+
50
+ // Reset all groups for this tile
51
+ static clear (tile: string): void {
52
+ this.groups[tile] = {};
53
+ }
54
+
55
+ // Check an object to see if it's a repeat within its designated group
56
+ static check (obj: RepeatObject, layout: RepeatLayout, tile: string): boolean | undefined {
57
+ if (layout.repeat_distance && layout.repeat_group && this.groups[tile][layout.repeat_group]) {
58
+ return this.groups[tile][layout.repeat_group].check(obj);
59
+ }
60
+ }
61
+
62
+ // Add an object to its designated group
63
+ static add (obj: RepeatObject, layout: RepeatLayout, tile: string): void {
64
+ if (layout.repeat_distance && layout.repeat_group) {
65
+ if (this.groups[tile][layout.repeat_group] == null) {
66
+ this.groups[tile][layout.repeat_group] = new RepeatGroup(layout.repeat_group, layout.repeat_distance * layout.repeat_scale);
67
+ }
68
+ this.groups[tile][layout.repeat_group].add(obj);
69
+ }
70
+ }
71
+
72
+ }
@@ -0,0 +1,18 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+
5
+ /*
6
+
7
+ Expected globals:
8
+ light_accumulator_*
9
+
10
+ */
11
+
12
+ struct AmbientLight {
13
+ vec3 ambient;
14
+ };
15
+
16
+ void calculateLight(in AmbientLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
17
+ light_accumulator_ambient.rgb += _light.ambient;
18
+ }
@@ -0,0 +1,39 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+
5
+ /*
6
+
7
+ Expected globals:
8
+ material
9
+ light_accumulator_*
10
+
11
+ */
12
+
13
+ struct DirectionalLight {
14
+ vec3 ambient;
15
+ vec3 diffuse;
16
+ vec3 specular;
17
+ vec3 direction;
18
+ };
19
+
20
+ void calculateLight(in DirectionalLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
21
+
22
+ light_accumulator_ambient.rgb += _light.ambient;
23
+
24
+ float nDotVP = clamp(dot(_normal, -_light.direction), 0.0, 1.0);
25
+
26
+ #ifdef TANGRAM_MATERIAL_DIFFUSE
27
+ light_accumulator_diffuse.rgb += _light.diffuse * nDotVP;
28
+ #endif
29
+
30
+ #ifdef TANGRAM_MATERIAL_SPECULAR
31
+ float pf = 0.0;
32
+ if (nDotVP > 0.0) {
33
+ vec3 reflectVector = reflect(_light.direction, _normal);
34
+ float eyeDotR = max(dot(normalize(_eyeToPoint), reflectVector), 0.0);
35
+ pf = pow(eyeDotR, material.shininess);
36
+ }
37
+ light_accumulator_specular.rgb += _light.specular * pf;
38
+ #endif
39
+ }
@@ -0,0 +1,21 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /** Geographic longitude/latitude in degrees and altitude in meters. */
6
+ type GeographicPosition = readonly [number, number, number];
7
+
8
+ import {getGeographicProjectionProcedure} from '../scene/projection_math';
9
+
10
+ /** Project a lamp into Tangram's geometry space, choosing the nearest planar world copy. */
11
+ export function projectGeographicLight(position: GeographicPosition, globe: boolean, anchorLongitude?: number): [number, number, number] {
12
+ if (!position.every(Number.isFinite) || Math.abs(position[1]) > 90) {
13
+ throw new Error('Geographic lights require finite longitude/latitude/altitude and latitude within +/-90 degrees');
14
+ }
15
+ return getGeographicProjectionProcedure(globe ? 'globe' : 'web-mercator').project(position, anchorLongitude);
16
+ }
17
+
18
+ /** Rotate a geographic spotlight's east/north/up direction into globe common space. */
19
+ export function projectGeographicDirection(position: GeographicPosition, direction: readonly [number, number, number], globe: boolean): [number, number, number] {
20
+ return getGeographicProjectionProcedure(globe ? 'globe' : 'web-mercator').projectVector(position, direction);
21
+ }