@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,683 @@
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
+ import Geo from '../utils/geo';
7
+ import {TileID} from '../tile/tile_id';
8
+ import {createGlobePreloadCoordinates} from '../tile/globe_tile_preload';
9
+ import TangramTileTraversalAdapter from '../tile/tile_traversal_adapter';
10
+ import type {TangramTraversalState} from '../tile/tile_traversal_adapter';
11
+ import ExternalCamera from './external_camera';
12
+ import type Camera from './camera_base';
13
+ import type {CameraView, CameraConfiguration, MatrixSet, Program, UniformBuffer} from './camera_base';
14
+ import type HostFrame from './host_frame';
15
+ import type {NormalizedRenderView} from './host_frame';
16
+ import ProjectedTileLOD from './projected_tile_lod';
17
+ import type {HostCamera, HostProjection, HostTileResourceOptions} from '../types';
18
+ import type {Bounds, Meters, Tile} from '../utils/geo';
19
+ import type {TileCoordinate} from '../tile/tile_id';
20
+ import type {VisibilityLODAdapter, GlobeVisibilityLODAdapter, VisibilityViewState} from './visibility_adapter';
21
+ import type {SubscriptionMethods} from '../utils/subscribe';
22
+ import {
23
+ WebMercatorGlobeVisibilityAdapter,
24
+ WebMercatorVisibilityAdapter
25
+ } from './visibility_adapter';
26
+ import Utils from '../utils/utils';
27
+ import subscribeMixin from '../utils/subscribe';
28
+ import log from '../utils/log';
29
+
30
+ export const VIEW_PAN_SNAP_TIME = 0.5;
31
+
32
+
33
+ /** Optional camera construction policy, supplied only by the classic entry. */
34
+ export type CameraFactory = (name: string, view: CameraView, config: CameraConfiguration) => Camera;
35
+
36
+ /** Options owned by the renderer view rather than a specific host library. */
37
+ export interface ViewOptions {
38
+ cameraFactory?: CameraFactory;
39
+ cameraMode?: 'external' | 'scene';
40
+ externalCamera?: boolean;
41
+ visibilityAdapter?: VisibilityLODAdapter;
42
+ globeVisibilityAdapter?: GlobeVisibilityLODAdapter;
43
+ continuousZoom?: boolean;
44
+ wrapView?: boolean;
45
+ }
46
+
47
+ interface ViewTile {
48
+ visible: boolean;
49
+ loading: boolean;
50
+ style_z: number;
51
+ preserve_tiles_within_zoom?: number;
52
+ coords: TileCoordinate;
53
+ key: string;
54
+ isProxy(): boolean;
55
+ setupProgram(matrices: MatrixSet & {model: Float64Array; model32: Float32Array}, program: ViewProgram, buffer?: UniformBuffer): void;
56
+ }
57
+
58
+ interface ViewProgram extends Program {
59
+ uniform(type: string, name: string, value: number | boolean | number[] | Float32Array | Float64Array): void;
60
+ bindUniformBlocks(): void;
61
+ }
62
+
63
+ /** Scene services used by View; no dependency on the scene implementation. */
64
+ export interface ViewScene {
65
+ config: {cameras?: Record<string, CameraConfiguration & {active?: boolean}>} | null;
66
+ uniform_buffers?: Record<string, UniformBuffer>;
67
+ tile_manager: {
68
+ updateTilesForView(): void;
69
+ removeTiles(predicate: (tile: ViewTile) => boolean): void;
70
+ /** Report tiles pinned by the current bounded globe preload policy. */
71
+ isTilePreloaded?(key: string): boolean;
72
+ /** Install shared worker/cache limits before refreshing visibility. */
73
+ setResourceLimits?(options: Readonly<HostTileResourceOptions> | undefined): void;
74
+ } | null;
75
+ updateConfig(options: {rebuild: boolean; normalize: boolean}): unknown;
76
+ requestRedraw(): void;
77
+ }
78
+
79
+ type ViewCenter = {lng: number; lat: number; meters?: Meters; tile?: Tile};
80
+
81
+ export default class View {
82
+ declare subscribe: SubscriptionMethods['subscribe'];
83
+ declare unsubscribe: SubscriptionMethods['unsubscribe'];
84
+ declare unsubscribeAll: SubscriptionMethods['unsubscribeAll'];
85
+ declare trigger: SubscriptionMethods['trigger'];
86
+ declare hasSubscribersFor: SubscriptionMethods['hasSubscribersFor'];
87
+ readonly scene: ViewScene;
88
+ /** Scene teardown retires its tile owner; view operations require the live manager. */
89
+ private get activeTileManager(): NonNullable<ViewScene['tile_manager']> {
90
+ if (!this.scene.tile_manager) throw new Error('View scene tile manager has been destroyed');
91
+ return this.scene.tile_manager;
92
+ }
93
+ readonly visibility_adapter: VisibilityLODAdapter;
94
+ readonly globe_visibility_adapter: GlobeVisibilityLODAdapter;
95
+ /** Shared traversal/bounds contract, independent of host viewport classes. */
96
+ readonly traversal_adapter: TangramTileTraversalAdapter;
97
+ private readonly cameraFactory?: CameraFactory;
98
+ private hostFrame: HostFrame | null = null;
99
+ private readonly projectedTileLOD = new ProjectedTileLOD();
100
+ private dataTileZoom?: number;
101
+ private visibilityKey = '';
102
+ private applyingFrame = false;
103
+ camera?: Camera;
104
+ zoom: number | null;
105
+ /** Integer style zoom retained for source display filters and worker geometry. */
106
+ tile_zoom: number | undefined;
107
+ center: ViewCenter | null;
108
+ bounds: Bounds | null;
109
+ meters_per_pixel: number | null;
110
+ size: {css: {width?: number; height?: number}; device: {width?: number; height?: number}; meters: Partial<Meters>};
111
+ aspect: number | null;
112
+ buffer: number;
113
+ projection: HostProjection;
114
+ camera_mode: 'external' | 'scene';
115
+ external_camera: boolean;
116
+ continuous_zoom: boolean;
117
+ wrap: boolean;
118
+ preserve_tiles_within_zoom: number;
119
+ panning: boolean;
120
+ panning_stop_at: number;
121
+ pan_snap_timer: number;
122
+ zoom_direction: number;
123
+ user_input_at: number;
124
+ user_input_timeout: number;
125
+ user_input_active: boolean;
126
+ matrices: MatrixSet & {model: Float64Array; model32: Float32Array; model_view: Float64Array; normal: Float64Array} = createViewMatrices();
127
+
128
+
129
+ constructor (scene: ViewScene, options: ViewOptions = {}) {
130
+ subscribeMixin(this);
131
+
132
+ this.scene = scene;
133
+ this.cameraFactory = options.cameraFactory;
134
+ this.visibility_adapter = options.visibilityAdapter || new WebMercatorVisibilityAdapter();
135
+ this.globe_visibility_adapter = options.globeVisibilityAdapter || new WebMercatorGlobeVisibilityAdapter();
136
+ this.traversal_adapter = new TangramTileTraversalAdapter(this.visibility_adapter, this.globe_visibility_adapter);
137
+
138
+ this.zoom = null;
139
+ this.center = null;
140
+ this.bounds = null;
141
+ this.meters_per_pixel = null;
142
+
143
+ this.panning = false;
144
+ this.panning_stop_at = 0;
145
+ this.pan_snap_timer = 0;
146
+ this.zoom_direction = 0;
147
+
148
+ this.user_input_at = 0;
149
+ this.user_input_timeout = 50;
150
+ this.user_input_active = false;
151
+
152
+ // Size of viewport in CSS pixels, device pixels, and mercator meters
153
+ this.size = {
154
+ css: {},
155
+ device: {},
156
+ meters: {}
157
+ };
158
+ this.aspect = null;
159
+
160
+ this.buffer = 0;
161
+ this.projection = { type: 'web-mercator' };
162
+ // Host-driven renderers own camera projection. `externalCamera` remains
163
+ // as a compatibility alias while callers migrate to the explicit mode.
164
+ this.camera_mode = options.cameraMode || (options.externalCamera === true || !options.cameraFactory ? 'external' : 'scene');
165
+ this.external_camera = this.camera_mode === 'external';
166
+ this.continuous_zoom = (typeof options.continuousZoom === 'boolean') ? options.continuousZoom : true;
167
+ this.wrap = (options.wrapView === false) ? false : true;
168
+ this.preserve_tiles_within_zoom = 1;
169
+
170
+ this.reset();
171
+ }
172
+
173
+ /** Installs every host field before making one visibility update. */
174
+ applyHostFrame(frame: HostFrame, resize: () => void, setCamera: () => void): void {
175
+ const eyeStates = frame.tileLOD ? frame.renderViews.map(eye => {
176
+ const state = this.getHostEyeState(frame, eye, Math.floor(frame.geographicAnchor.zoom));
177
+ const projection = eye.projection ?? frame.projection;
178
+ const bounds = getProjectionBounds(projection, this.visibility_adapter.calculateBounds(state).bounds);
179
+ return {eye, state: {...state, bounds}, camera: eye.camera, viewport: eye.viewport, projection, bounds};
180
+ }) : [];
181
+ const dataTileZoom = this.projectedTileLOD.select(frame, eyeStates, zoom => {
182
+ let count = 0;
183
+ for (const {eye, projection} of eyeStates) {
184
+ if (projection.type === 'globe') {
185
+ if (!this.globe_visibility_adapter.countTileCoordinates) {
186
+ throw new Error('Automatic tile LOD requires a globe visibility candidate counter');
187
+ }
188
+ count += this.globe_visibility_adapter.countTileCoordinates({
189
+ tile_zoom: zoom, buffer: frame.tileBuffer, visibleBounds: projection.visibleBounds,
190
+ cameraPosition: eye.camera.position, maxElevation: projection.maxElevation
191
+ });
192
+ }
193
+ else {
194
+ if (!this.visibility_adapter.countTileCoordinates) {
195
+ throw new Error('Automatic tile LOD requires a planar visibility candidate counter');
196
+ }
197
+ const state = this.getHostEyeState(frame, eye, zoom);
198
+ const bounds = getProjectionBounds(projection, this.visibility_adapter.calculateBounds(state).bounds);
199
+ count += this.visibility_adapter.countTileCoordinates({...state, bounds});
200
+ }
201
+ }
202
+ return count;
203
+ });
204
+ const key = JSON.stringify({
205
+ anchor: frame.geographicAnchor, projection: frame.projection, buffer: frame.tileBuffer, tileZoom: dataTileZoom,
206
+ tileLOD: frame.tileLOD, tileResources: frame.tileResources, globePreloadZoom: frame.globePreloadZoom,
207
+ views: frame.renderViews.map(view => ({
208
+ viewport: view.viewport, anchor: view.geographicAnchor, projection: view.projection,
209
+ camera: {view: Array.from(view.camera.view), projection: Array.from(view.camera.projection), position: view.camera.position}
210
+ }))
211
+ });
212
+ const changed = key !== this.visibilityKey;
213
+ this.hostFrame = frame;
214
+ this.dataTileZoom = dataTileZoom;
215
+ this.applyingFrame = true;
216
+ try {
217
+ this.activeTileManager.setResourceLimits?.(frame.tileResources);
218
+ this.buffer = frame.tileBuffer;
219
+ this.setProjection(frame.projection);
220
+ resize();
221
+ this.setView({lng: frame.geographicAnchor.longitude, lat: frame.geographicAnchor.latitude, zoom: frame.geographicAnchor.zoom});
222
+ setCamera();
223
+ }
224
+ finally {
225
+ this.applyingFrame = false;
226
+ }
227
+ this.visibilityKey = key;
228
+ if (changed) {
229
+ this.updateBounds();
230
+ }
231
+ }
232
+
233
+ private invalidateBounds(previousTileZoom = this.tile_zoom): void {
234
+ if (!this.applyingFrame) {
235
+ this.updateBounds(previousTileZoom);
236
+ }
237
+ }
238
+
239
+ private getVisibilityState(): VisibilityViewState | null {
240
+ if (!this.center || this.zoom === null || this.size.css.width === undefined || this.size.css.height === undefined) {
241
+ return null;
242
+ }
243
+ return {
244
+ center: this.center, zoom: this.zoom,
245
+ tile_zoom: this.dataTileZoom ?? this.tile_zoom ?? this.baseZoom(this.zoom),
246
+ size: {css: {width: this.size.css.width, height: this.size.css.height}},
247
+ bounds: this.bounds, buffer: this.buffer, wrap: this.wrap
248
+ };
249
+ }
250
+
251
+ /** Derives an eye's geographic state without mutating the installed logical frame. */
252
+ private getHostEyeState(frame: HostFrame, eye: NormalizedRenderView, tileZoom: number): VisibilityViewState {
253
+ const anchor = eye.geographicAnchor ?? frame.geographicAnchor;
254
+ const projection = eye.projection ?? frame.projection;
255
+ return {
256
+ center: {lng: anchor.longitude, lat: anchor.latitude}, zoom: anchor.zoom, tile_zoom: tileZoom,
257
+ size: {css: eye.viewport}, bounds: null, buffer: frame.tileBuffer, wrap: this.wrap,
258
+ camera: projection.type === 'web-mercator' ? eye.camera : undefined
259
+ };
260
+ }
261
+
262
+ private getReadyState() {
263
+ if (!this.center?.meters || this.zoom === null || this.meters_per_pixel === null || this.aspect === null ||
264
+ this.size.css.width === undefined || this.size.css.height === undefined ||
265
+ this.size.meters.x === undefined || this.size.meters.y === undefined) {
266
+ throw new Error('View camera state is not ready');
267
+ }
268
+ return {
269
+ centerMeters: this.center.meters, zoom: this.zoom, metersPerPixel: this.meters_per_pixel,
270
+ aspect: this.aspect, width: this.size.css.width, height: this.size.css.height,
271
+ sizeMeters: {x: this.size.meters.x, y: this.size.meters.y}
272
+ };
273
+ }
274
+
275
+ private getCameraView(): CameraView {
276
+ const view = this;
277
+ return {
278
+ scene: this.scene,
279
+ setView: state => this.setView(state),
280
+ get projection() { return view.projection; },
281
+ get size() {
282
+ const state = view.getReadyState();
283
+ return {css: {width: state.width, height: state.height}, meters: state.sizeMeters};
284
+ },
285
+ get aspect() { return view.getReadyState().aspect; },
286
+ get zoom() { return view.getReadyState().zoom; },
287
+ get meters_per_pixel() { return view.getReadyState().metersPerPixel; },
288
+ get center() { return {meters: view.getReadyState().centerMeters}; }
289
+ };
290
+ }
291
+
292
+ // Reset state before scene config is updated
293
+ reset () {
294
+ this.createCamera();
295
+ }
296
+
297
+ // Create camera
298
+ createCamera () {
299
+ if (this.external_camera) {
300
+ this.camera = new ExternalCamera('external', this.getCameraView(), { type: 'external' });
301
+ return;
302
+ }
303
+ let active_camera = this.getActiveCamera();
304
+ if (active_camera && this.cameraFactory && this.scene.config?.cameras) {
305
+ this.camera = this.cameraFactory(active_camera, this.getCameraView(), this.scene.config.cameras[active_camera]);
306
+ this.camera.updateView();
307
+ }
308
+ }
309
+
310
+ // Supply camera matrices from an embedding renderer
311
+ setCameraMatrices (matrices: HostCamera) {
312
+ if (!this.camera || !(this.camera instanceof ExternalCamera)) {
313
+ throw new Error('View must use cameraMode \'external\' to accept camera matrices');
314
+ }
315
+ if (this.camera.setMatrices(matrices)) {
316
+ this.invalidateBounds();
317
+ }
318
+ }
319
+
320
+ // Get active camera - for public API
321
+ getActiveCamera () {
322
+ if (this.scene.config && this.scene.config.cameras) {
323
+ for (let name in this.scene.config.cameras) {
324
+ if (this.scene.config.cameras[name].active) {
325
+ return name;
326
+ }
327
+ }
328
+
329
+ // If no camera set as active, use first one
330
+ let keys = Object.keys(this.scene.config.cameras);
331
+ return keys[0];
332
+ }
333
+ }
334
+
335
+ // Set active camera and recompile - for public API
336
+ setActiveCamera (name: string) {
337
+ let prev = this.getActiveCamera();
338
+ if (prev === name) {
339
+ return name;
340
+ }
341
+
342
+ if (this.scene.config?.cameras?.[name]) {
343
+ this.scene.config.cameras[name].active = true;
344
+
345
+ // Clear previously active camera
346
+ if (prev && this.scene.config.cameras[prev]) {
347
+ delete this.scene.config.cameras[prev].active;
348
+ }
349
+ }
350
+
351
+ this.scene.updateConfig({ rebuild: false, normalize: false });
352
+ return this.getActiveCamera();
353
+ }
354
+
355
+ // Update method called once per frame
356
+ update (time = Date.now()) {
357
+ if (this.camera != null && this.ready()) {
358
+ this.camera.update();
359
+ }
360
+ this.pan_snap_timer = (time - this.panning_stop_at) / 1000;
361
+ this.user_input_active = ((time - this.user_input_at) < this.user_input_timeout);
362
+ }
363
+
364
+ // Set logical pixel size of viewport
365
+ setViewportSize (width: number, height: number) {
366
+ this.size.css = { width, height };
367
+ this.size.device = {
368
+ width: Math.round(width * (Utils.device_pixel_ratio ?? 1)),
369
+ height: Math.round(height * (Utils.device_pixel_ratio ?? 1))
370
+ };
371
+ this.aspect = width / height;
372
+ this.invalidateBounds();
373
+ }
374
+
375
+ // Set the host projection and its geographic visibility metadata.
376
+ setProjection (projection: HostProjection = { type: 'web-mercator' }) {
377
+ if (projectionsEqual(this.projection, projection)) {
378
+ return false;
379
+ }
380
+ this.projection = projection;
381
+ this.invalidateBounds();
382
+ return true;
383
+ }
384
+
385
+ // Set the map view, can be passed an object with lat/lng and/or zoom
386
+ setView ({ lng, lat, zoom }: {lng?: number; lat?: number; zoom?: number} = {}) {
387
+ var changed = false;
388
+
389
+ // Set center
390
+ if (typeof lng === 'number' && typeof lat === 'number') {
391
+ if (!this.center || lng !== this.center.lng || lat !== this.center.lat) {
392
+ changed = true;
393
+ this.center = { lng, lat };
394
+ }
395
+ }
396
+
397
+ // Set zoom
398
+ if (typeof zoom === 'number' && zoom !== this.zoom) {
399
+ changed = true;
400
+ this.setZoom(zoom);
401
+ }
402
+
403
+ if (changed) {
404
+ this.invalidateBounds();
405
+ }
406
+ return changed;
407
+ }
408
+
409
+ setZoom (zoom: number) {
410
+ let last_tile_zoom = this.tile_zoom;
411
+ let tile_zoom = this.baseZoom(zoom);
412
+ if (!this.continuous_zoom) {
413
+ zoom = tile_zoom;
414
+ }
415
+
416
+ if (tile_zoom !== last_tile_zoom) {
417
+ this.zoom_direction = typeof last_tile_zoom === 'number' && tile_zoom > last_tile_zoom ? 1 : -1;
418
+ }
419
+
420
+ this.zoom = zoom;
421
+ this.tile_zoom = tile_zoom;
422
+
423
+ this.invalidateBounds(last_tile_zoom);
424
+ this.scene.requestRedraw();
425
+ }
426
+
427
+ // Choose the base zoom level to use for a given fractional zoom
428
+ baseZoom (zoom: number) {
429
+ return Math.floor(zoom);
430
+ }
431
+
432
+ setPanning (panning: boolean) {
433
+ this.panning = panning;
434
+ if (!this.panning) {
435
+ this.panning_stop_at = (+new Date());
436
+ }
437
+ }
438
+
439
+ markUserInput () {
440
+ this.user_input_at = (+new Date());
441
+ }
442
+
443
+ ready () {
444
+ // TODO: better concept of 'readiness' state?
445
+ if (typeof this.size.css.width !== 'number' ||
446
+ typeof this.size.css.height !== 'number' ||
447
+ this.center == null ||
448
+ typeof this.zoom !== 'number') {
449
+ return false;
450
+ }
451
+ return true;
452
+ }
453
+
454
+ // Calculate viewport bounds based on current center and zoom
455
+ updateBounds (previousTileZoom = this.tile_zoom) {
456
+ const state = this.getVisibilityState();
457
+ if (!state || !this.center) {
458
+ return;
459
+ }
460
+
461
+ const viewBounds = this.visibility_adapter.calculateBounds(state);
462
+ this.tile_zoom = this.dataTileZoom === undefined ? viewBounds.tileZoom : this.baseZoom(state.zoom);
463
+ if (typeof previousTileZoom === 'number' && this.tile_zoom !== previousTileZoom) {
464
+ this.zoom_direction = this.tile_zoom > previousTileZoom ? 1 : -1;
465
+ }
466
+ this.meters_per_pixel = viewBounds.metersPerPixel;
467
+ this.size.meters = viewBounds.sizeMeters;
468
+ this.center.meters = viewBounds.centerMeters;
469
+ this.center.tile = this.dataTileZoom === undefined ? viewBounds.centerTile :
470
+ Geo.tileForMeters([viewBounds.centerMeters.x, viewBounds.centerMeters.y], this.dataTileZoom);
471
+ this.bounds = viewBounds.bounds;
472
+
473
+ this.activeTileManager.updateTilesForView();
474
+
475
+ this.trigger('move');
476
+ this.scene.requestRedraw(); // TODO automate via move event?
477
+ }
478
+
479
+ findVisibleTileCoordinates (): TileCoordinate[] {
480
+ return this.traversal_adapter.getTileIndices({viewState: this.getTileTraversalState()});
481
+ }
482
+
483
+ /** Snapshot the logical/eye traversal inputs without exposing a View or Scene to a tileset. */
484
+ getTileTraversalState(): TangramTraversalState {
485
+ if (!this.bounds) {
486
+ return {eyes: []};
487
+ }
488
+
489
+
490
+ const state = this.getVisibilityState();
491
+ if (!state) {
492
+ return {eyes: []};
493
+ }
494
+ const hostFrame = this.hostFrame;
495
+ const views = hostFrame?.renderViews;
496
+ if (!views) {
497
+ return {eyes: [{view: state, projection: this.projection, position: this.camera?.position_meters}]};
498
+ }
499
+ return {union: true, eyes: views.map(eye => ({
500
+ view: this.getHostEyeState(hostFrame, eye,
501
+ this.dataTileZoom ?? this.baseZoom((eye.geographicAnchor ?? hostFrame.geographicAnchor).zoom)),
502
+ projection: eye.projection ?? this.projection, position: eye.camera.position,
503
+ calculateBounds: true, dataZoom: this.dataTileZoom
504
+ }))};
505
+ }
506
+
507
+ /** Global coarse coordinates at no finer a data level than the current view. */
508
+ findPreloadedTileCoordinates(): TileCoordinate[] {
509
+ const zoom = this.hostFrame?.globePreloadZoom;
510
+ if (this.projection.type !== 'globe' || zoom === undefined || !this.center?.tile) return [];
511
+ return createGlobePreloadCoordinates(Math.min(zoom, this.center.tile.z));
512
+ }
513
+
514
+ // Remove tiles too far outside of view
515
+ pruneTilesForView () {
516
+ // A projected footprint is a finite source region, not the geographic camera's rectangle.
517
+ // Keep its loaded tiles warm across projection switches; configured cache budgets still apply.
518
+ if (this.projection.type === 'projected') return;
519
+ // TODO: will this function ever be called when view isn't ready?
520
+ if (!this.ready() || !this.center?.meters || this.meters_per_pixel === null ||
521
+ this.size.meters.x === undefined || this.size.meters.y === undefined || this.tile_zoom === undefined) {
522
+ return;
523
+ }
524
+ const centerMeters = this.center.meters;
525
+ const sizeMeters = {x: this.size.meters.x, y: this.size.meters.y};
526
+ const metersPerPixel = this.meters_per_pixel;
527
+ const tileZoom = this.tile_zoom;
528
+
529
+ this.activeTileManager.removeTiles(tile => {
530
+ // Ignore visible tiles
531
+ if (tile.visible || tile.isProxy() || this.activeTileManager.isTilePreloaded?.(tile.key)) {
532
+ return false;
533
+ }
534
+
535
+ // Remove tiles outside given zoom that are still loading
536
+ if (tile.loading && tile.style_z !== this.tile_zoom) {
537
+ return true;
538
+ }
539
+
540
+ // Discard if too far from current zoom
541
+ const zdiff = Math.abs(tile.style_z - tileZoom);
542
+ const preserve_tiles_within_zoom = (tile.preserve_tiles_within_zoom != null ?
543
+ tile.preserve_tiles_within_zoom : this.preserve_tiles_within_zoom); // optionally tile source specific
544
+ if (zdiff > preserve_tiles_within_zoom) {
545
+ return true;
546
+ }
547
+
548
+ if (this.projection.type === 'globe') {
549
+ return true;
550
+ }
551
+
552
+ // Discard tiles outside an area surrounding the viewport, handling tiles at different zooms
553
+ // Get min and max tiles for the viewport, at the scale of the tile currently being evaluated
554
+ const view_buffer = metersPerPixel * Geo.tile_size; // buffer area to keep tiles surrounding viewport
555
+ const view_tile_min = TileID.coordAtZoom(
556
+ Geo.tileForMeters(
557
+ [
558
+ centerMeters.x - sizeMeters.x/2 - view_buffer,
559
+ centerMeters.y + sizeMeters.y/2 + view_buffer
560
+ ],
561
+ tileZoom),
562
+ tile.coords.z);
563
+ const view_tile_max = TileID.coordAtZoom(
564
+ Geo.tileForMeters(
565
+ [
566
+ centerMeters.x + sizeMeters.x/2 + view_buffer,
567
+ centerMeters.y - sizeMeters.y/2 - view_buffer
568
+ ],
569
+ tileZoom),
570
+ tile.coords.z);
571
+
572
+ if (tile.coords.x < view_tile_min.x || tile.coords.x > view_tile_max.x ||
573
+ tile.coords.y < view_tile_min.y || tile.coords.y > view_tile_max.y) {
574
+ log('trace', `View: remove tile ${tile.key} (as ${tile.coords.key}) ` +
575
+ `for being too far out of visible area (${view_tile_min.key}, ${view_tile_max.key})`);
576
+ return true;
577
+ }
578
+ return false;
579
+ });
580
+ }
581
+
582
+ // Allocate model-view matrices
583
+ // 64-bit versions are for CPU calcuations
584
+ // 32-bit versions are downsampled and sent to GPU
585
+ createMatrices () {
586
+
587
+ this.matrices = createViewMatrices();
588
+ }
589
+
590
+ // Calculate and set model/view and normal matrices for a tile
591
+ setupTile (tile: ViewTile, program: ViewProgram, clipBounds?: readonly number[]) {
592
+ const uniform_buffer = this.scene.uniform_buffers && this.scene.uniform_buffers.TangramTile;
593
+
594
+ // Tile-specific state
595
+ // TODO: calc these once per tile (currently being needlessly re-calculated per-tile-per-style)
596
+ tile.setupProgram(this.matrices, program, uniform_buffer);
597
+ const bounds = clipBounds ? Array.from(clipBounds) : [0, 0, 0, 0];
598
+ if (uniform_buffer) uniform_buffer.setUniforms({u_tile_clip_bounds: bounds});
599
+ else program.uniform('4fv', 'u_tile_clip_bounds', bounds);
600
+
601
+ // Model-view and normal matrices
602
+ this.camera?.setupMatrices(this.matrices, program, uniform_buffer);
603
+ if (uniform_buffer) {
604
+ program.bindUniformBlocks();
605
+ }
606
+ }
607
+
608
+ // Set general uniforms that must be updated once per program
609
+ setupProgram (program: ViewProgram, uniform_buffers: Record<string, UniformBuffer> = {}) {
610
+ const {centerMeters, zoom, metersPerPixel} = this.getReadyState();
611
+ const width = this.size.device.width ?? 0;
612
+ const height = this.size.device.height ?? 0;
613
+ if (uniform_buffers.TangramView) {
614
+ uniform_buffers.TangramView.setUniforms({
615
+ u_resolution: [width, height],
616
+ u_map_position: [centerMeters.x, centerMeters.y, zoom],
617
+ u_meters_per_pixel: metersPerPixel,
618
+ u_device_pixel_ratio: Utils.device_pixel_ratio ?? 1,
619
+ u_view_pan_snap_timer: this.pan_snap_timer,
620
+ u_view_panning: this.panning,
621
+ u_projection_mode: this.projection.type === 'globe' ? 1 : this.projection.type === 'projected' ? 2 : 0
622
+ });
623
+ }
624
+ else {
625
+ program.uniform('2fv', 'u_resolution', [width, height]);
626
+ program.uniform('3fv', 'u_map_position', [centerMeters.x, centerMeters.y, zoom]);
627
+ program.uniform('1f', 'u_meters_per_pixel', metersPerPixel);
628
+ program.uniform('1f', 'u_device_pixel_ratio', Utils.device_pixel_ratio ?? 1);
629
+ program.uniform('1f', 'u_view_pan_snap_timer', this.pan_snap_timer);
630
+ program.uniform('1i', 'u_view_panning', this.panning);
631
+ program.uniform('1i', 'u_projection_mode', this.projection.type === 'globe' ? 1 : this.projection.type === 'projected' ? 2 : 0);
632
+ }
633
+
634
+ this.camera?.setupProgram(program, uniform_buffers.TangramCamera);
635
+ }
636
+
637
+ // View requires some animation, such as after panning stops
638
+ isAnimating () {
639
+ return (this.pan_snap_timer <= VIEW_PAN_SNAP_TIME);
640
+ }
641
+
642
+ }
643
+
644
+ /** Projects explicit geographic footprints, unwrapping globe samples across the antimeridian. */
645
+ function getProjectionBounds(projection: HostProjection, fallback: Bounds): Bounds | null {
646
+ if (projection.visibleBounds === undefined) return fallback;
647
+ if (projection.visibleBounds === null) return null;
648
+ const [west, south, east, north] = projection.visibleBounds;
649
+ const clampLatitude = (latitude: number) => projection.type === 'globe'
650
+ ? Math.max(-85.05112878, Math.min(85.05112878, latitude)) : latitude;
651
+ const southwest = Geo.latLngToMeters([west, clampLatitude(south)]);
652
+ const northeast = Geo.latLngToMeters([projection.type === 'globe' && east < west ? east + 360 : east, clampLatitude(north)]);
653
+ if (![...southwest, ...northeast].every(Number.isFinite)) {
654
+ throw new Error('HostFrame visibleBounds must project to finite meters');
655
+ }
656
+ return {sw: {x: southwest[0], y: southwest[1]}, ne: {x: northeast[0], y: northeast[1]}};
657
+ }
658
+
659
+ function projectionsEqual(previous: HostProjection, next: HostProjection): boolean {
660
+ if (previous === next) {
661
+ return true;
662
+ }
663
+ if (!previous || !next || previous.type !== next.type) {
664
+ return false;
665
+ }
666
+ const previousBounds = previous.visibleBounds;
667
+ const nextBounds = next.visibleBounds;
668
+ const heightMatches = previous.type !== 'globe' || next.type !== 'globe' ||
669
+ previous.maxElevation === next.maxElevation;
670
+ return heightMatches && (previousBounds === nextBounds || (
671
+ Array.isArray(previousBounds) && Array.isArray(nextBounds) &&
672
+ previousBounds.length === nextBounds.length &&
673
+ previousBounds.every((value, index) => value === nextBounds[index])));
674
+ }
675
+
676
+ /** Allocates the CPU and GPU matrix views used for one tile's transforms. */
677
+ function createViewMatrices() {
678
+ return {
679
+ model: new Float64Array(16), model32: new Float32Array(16),
680
+ model_view: new Float64Array(16), model_view32: new Float32Array(16),
681
+ normal: new Float64Array(9), normal32: new Float32Array(9), inverse_normal32: new Float32Array(9)
682
+ };
683
+ }