@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,707 @@
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
+ // Line rendering style
7
+
8
+ import type {LineStyleRuntime, GeometryFeature, GeometryDraw, RawGeometryDraw, GeometryContext, GeometryMeshVariant, LineFeatureStyle, GeometryBuildMesh, GeometryTile, GeometryTileData, GeometryExtrusion, GeometryOutlineDraw} from '../geometry-style-types';
9
+ import type {GeometryLine, GeometryPolygon, PolylineVertexIndices} from '../../builders/geometry-types';
10
+ import type {PropertyCache} from '../property-types';
11
+ import type UniformBuffer from '../../gl/uniform_buffer';
12
+
13
+ import log from '../../utils/log';
14
+ import {Style} from '../style';
15
+ import StyleParser from '../style_parser';
16
+ import gl from '../../gl/constants'; // web workers don't have access to GL context, so import all GL constants
17
+ import Texture from '../../gl/texture';
18
+ import VertexLayout from '../../gl/vertex_layout';
19
+ import {buildPolylines} from '../../builders/polylines';
20
+ import renderDashArray from './dasharray';
21
+ import Geo from '../../utils/geo';
22
+
23
+ import WorkerBroker from '../../utils/worker_broker';
24
+ import hashString from '../../utils/hash';
25
+
26
+ import polygons_vs from '../polygons/polygons_vertex.glsl';
27
+ import polygons_fs from '../polygons/polygons_fragment.glsl';
28
+ import {buildLinesWGSL} from './lines_wgsl';
29
+ import {GLOBE_PROJECTION_GLSL, TERRAIN_DRAPING_GLSL} from '../../scene/projection_shaders';
30
+ import {getProjectedRoadUnit} from '../../procedures/mesh-projector';
31
+
32
+ export const Lines: LineStyleRuntime = Object.create(Style);
33
+
34
+ const DASH_SCALE = 20; // adjustment factor for UV scale to for line dash patterns w/fractional pixel width
35
+
36
+ Object.assign(Lines, {
37
+ name: 'lines',
38
+ built_in: true,
39
+ vertex_shader_src: polygons_vs.replace('#pragma tangram: projection', GLOBE_PROJECTION_GLSL + TERRAIN_DRAPING_GLSL),
40
+ fragment_shader_src: polygons_fs,
41
+ selection: true, // enable feature selection
42
+
43
+ getWGSLShaderSource(this: LineStyleRuntime, selection = false) {
44
+ return buildLinesWGSL({ animated: this.animated === true, lighting: this.portable_lighting_mode,
45
+ lightCount: this.portable_light_count, cpuProjection: Boolean(this.cpu_projection), terrain: Boolean(this.terrain), selection });
46
+ },
47
+
48
+ setGL(this: LineStyleRuntime, gl_context: WebGLRenderingContext | null, uniform_blocks: Record<string, UniformBuffer> = {}, options = {}) {
49
+ if (Object.prototype.hasOwnProperty.call(this, 'line_uniform_buffer') &&
50
+ this.line_uniform_buffer) {
51
+ this.line_uniform_buffer.destroy();
52
+ this.line_uniform_buffer = null;
53
+ }
54
+ Style.setGL.call(this, gl_context, uniform_blocks, options);
55
+ if (this.shader_language === 'wgsl') {
56
+ if (typeof this.uniform_block_factory !== 'function') {
57
+ throw new Error('portable line styles require a uniform block factory');
58
+ }
59
+ this.line_uniform_buffer = this.uniform_block_factory({
60
+ id: `${this.name}-line-style`,
61
+ name: 'TangramLine',
62
+ binding: 5,
63
+ snapshotPerMesh: true,
64
+ uniforms: {
65
+ u_has_line_texture: 'bool',
66
+ u_texture_ratio: 'float',
67
+ u_v_scale_adjust: 'float',
68
+ u_has_dash: 'float',
69
+ u_dash_background_color: 'vec4'
70
+ }
71
+ });
72
+ this.uniform_blocks = Object.assign({}, this.uniform_blocks, {
73
+ TangramLine: this.line_uniform_buffer
74
+ });
75
+ }
76
+ },
77
+
78
+ destroy(this: LineStyleRuntime) {
79
+ Style.destroy.call(this);
80
+ if (Object.prototype.hasOwnProperty.call(this, 'line_uniform_buffer') &&
81
+ this.line_uniform_buffer) {
82
+ this.line_uniform_buffer.destroy();
83
+ this.line_uniform_buffer = null;
84
+ }
85
+ },
86
+
87
+ init(this: LineStyleRuntime) {
88
+ Style.init.apply(this, arguments as unknown as Parameters<typeof Style.init>);
89
+ this.defines.TANGRAM_CPU_PROJECTED = Boolean(this.cpu_projection);
90
+ const attributes = this.shaders?.attributes;
91
+ const hasAttributes = attributes && typeof attributes === 'object' ? Object.keys(attributes).length > 0 : Boolean(attributes);
92
+ const positionBlocks = this.shaders?.blocks?.position;
93
+ const hasPositionBlocks = Array.isArray(positionBlocks) ? positionBlocks.length > 0 : Boolean(positionBlocks);
94
+ if (this.cpu_projection && (hasAttributes || hasPositionBlocks)) {
95
+ throw new Error('CPU projected lines do not support custom vertex shader blocks');
96
+ }
97
+ this.defines.TANGRAM_PROJECTED_TRAFFIC = Boolean(this.cpu_projection && this.animated);
98
+ if (this.cpu_projection && this.animated) this.texcoords = true;
99
+
100
+ // Tell the shader we want a order in vertex attributes, and to extrude lines
101
+ this.defines.TANGRAM_EXTRUDE_LINES = true;
102
+ this.defines.TANGRAM_TEXTURE_COORDS = true; // texcoords attribute is set to static when not needed
103
+
104
+ // Additional single-allocated object used for holding outline style as it is processed
105
+ // Separate from this.feature_style so that outline properties do not overwrite calculated
106
+ // inline properties (outline call is made *within* the inline call)
107
+ // The scratch object is populated by the base parser before geometry is built.
108
+ this.outline_feature_style = {} as LineFeatureStyle;
109
+ this.inline_feature_style = this.feature_style; // save reference to main computed style object
110
+
111
+ this.dash_textures = {}; // cache previously rendered line dash pattern textures
112
+ },
113
+
114
+ // Calculate width or offset at zoom given in `context`
115
+ calcDistance (this: LineStyleRuntime, prop: PropertyCache | null | undefined, context: GeometryContext) {
116
+ return (StyleParser.evalCachedDistanceProperty(prop, context) as number) || 0;
117
+ },
118
+
119
+ // Calculate width or offset at next zoom (used for zoom-based interpolation in shader)
120
+ calcDistanceNextZoom (this: LineStyleRuntime, prop: PropertyCache | null | undefined, context: GeometryContext) {
121
+ context.zoom++;
122
+ let val = this.calcDistance(prop, context);
123
+ context.zoom--;
124
+ return val;
125
+ },
126
+
127
+ // Calculate width at current and next zoom, and scaling factor between
128
+ calcWidth (this: LineStyleRuntime, draw: GeometryDraw, style: LineFeatureStyle, context: GeometryContext) {
129
+ style.projected_pixel_scale = this.cpu_projection && draw.projected_pixel_width ?
130
+ 1 / (context.units_per_meter_overzoom * context.meters_per_pixel) : 0;
131
+ // line width in meters
132
+ let width = this.calcDistance(draw.width, context);
133
+ if (width < 0) {
134
+ return; // skip lines with negative width
135
+ }
136
+
137
+ let next_width;
138
+ if (draw.next_width && !this.cpu_projection) {
139
+ next_width = this.calcDistanceNextZoom(draw.next_width, context);
140
+ }
141
+ else {
142
+ next_width = width / 2; // when width is static, width at next zoom is just half as many tile units
143
+ }
144
+
145
+ if ((width === 0 && next_width === 0) || next_width < 0) {
146
+ return false; // skip lines that don't interpolate to a positive value at next zoom
147
+ }
148
+
149
+ // these values are saved for later calculating the outline width, which needs to add the base line's width
150
+ style.width_unscaled = width;
151
+ style.next_width_unscaled = next_width;
152
+
153
+ // calculate relative change in line width between zooms
154
+ // interpolate from the line width at the zoom mid-point, towards/away from the previous/next integer zoom
155
+ // Projected scenes have an explicit style zoom independent of data/camera zoom.
156
+ // Bake that zoom's width; geographic shaders alone interpolate toward next zoom.
157
+ if (draw.next_width && !this.cpu_projection) {
158
+ next_width *= 2; // NB: a given width is twice as big in screen space at the next zoom
159
+ let mid_width = (width + next_width) * 0.5;
160
+ style.width = mid_width * context.units_per_meter_overzoom; // width at zoom mid-point
161
+ style.width_scale = 1 - (next_width / mid_width);
162
+ }
163
+ else {
164
+ style.width = width * context.units_per_meter_overzoom;
165
+ style.width_scale = 0;
166
+ }
167
+
168
+ // optional adjustment to texcoord width based on scale
169
+ if (draw.texcoords) {
170
+ // when drawing an outline, use the inline's texture scale
171
+ // (e.g. keeps dashed outline pattern locked to inline pattern)
172
+ if (draw.inline_texcoord_width) {
173
+ style.texcoord_width = draw.inline_texcoord_width;
174
+ }
175
+ // when drawing an inline, calculate UVs based on line width
176
+ else {
177
+ // UVs can't calc for zero-width, use next zoom width in that case
178
+ style.texcoord_width = (style.width_unscaled || style.next_width_unscaled) * context.units_per_meter_overzoom / context.tile.overzoom2; // shorten calcs
179
+ }
180
+ }
181
+
182
+ return true;
183
+ },
184
+
185
+ // Calculate offset at current and next zoom, and scaling factor between
186
+ calcOffset (this: LineStyleRuntime, draw: GeometryDraw, style: LineFeatureStyle, context: GeometryContext) {
187
+ // Pre-calculated offset passed
188
+ // This happens when a line passes pre-computed offset values to its outline
189
+ if (draw.offset_precalc) {
190
+ style.offset = draw.offset_precalc;
191
+ // Inline parsing supplies both precalculated offset fields to the outline.
192
+ style.offset_scale = draw.offset_scale_precalc!;
193
+ }
194
+ // Offset to calculate
195
+ else if (draw.offset) {
196
+ let offset = this.calcDistance(draw.offset, context);
197
+
198
+ if (draw.next_offset && !this.cpu_projection) {
199
+ let next_offset = this.calcDistanceNextZoom(draw.next_offset, context) * 2;
200
+
201
+ if (Math.abs(offset) >= Math.abs(next_offset)) {
202
+ style.offset = offset * context.units_per_meter_overzoom;
203
+ if (offset !== 0) {
204
+ style.offset_scale = 1 - (next_offset / offset);
205
+ }
206
+ else {
207
+ style.offset_scale = 0;
208
+ }
209
+ }
210
+ else {
211
+ style.offset = next_offset * context.units_per_meter_overzoom;
212
+ if (next_offset !== 0) {
213
+ style.offset_scale = (1 - (offset / next_offset)) * -1;
214
+ }
215
+ else {
216
+ style.offset_scale = 0;
217
+ }
218
+ }
219
+ }
220
+ else {
221
+ style.offset = offset * context.units_per_meter_overzoom;
222
+ style.offset_scale = 0;
223
+ }
224
+ }
225
+ // No offset
226
+ else {
227
+ style.offset = 0;
228
+ style.offset_scale = 0;
229
+ }
230
+ },
231
+
232
+ _parseFeature (this: LineStyleRuntime, feature: GeometryFeature, draw: GeometryDraw, context: GeometryContext) {
233
+ var style = this.feature_style;
234
+
235
+ // calculate line width at current and next zoom
236
+ if (this.calcWidth(draw, style, context) === false) {
237
+ return; // missing or zero width
238
+ }
239
+
240
+ // calculate line offset at current and next zoom
241
+ this.calcOffset(draw, style, context);
242
+
243
+ style.color = this.parseColor(draw.color, context);
244
+ if (!style.color) {
245
+ return;
246
+ }
247
+
248
+ style.alpha = StyleParser.evalCachedProperty(draw.alpha, context) as number | undefined; // optional alpha override
249
+
250
+ style.variant = draw.variant; // pre-calculated mesh variant
251
+
252
+ // height defaults to feature height, but extrude style can dynamically adjust height by returning a number or array (instead of a boolean)
253
+ style.z = (StyleParser.evalCachedDistanceProperty(draw.z, context) as number) || StyleParser.defaults.z;
254
+ style.height = feature.properties.height || StyleParser.defaults.height;
255
+ style.extrude = StyleParser.evalProperty(draw.extrude, context) as GeometryExtrusion;
256
+ if (style.extrude) {
257
+ if (typeof style.extrude === 'number') {
258
+ style.height = style.extrude;
259
+ }
260
+ else if (Array.isArray(style.extrude)) {
261
+ style.height = style.extrude[1];
262
+ }
263
+ }
264
+
265
+ // Raise line height if extruded
266
+ if (style.extrude && style.height) {
267
+ style.z += style.height;
268
+ }
269
+
270
+ style.z *= Geo.height_scale; // provide sub-meter precision of height values
271
+
272
+ style.cap = draw.cap;
273
+ style.join = draw.join;
274
+
275
+ style.miter_limit = draw.miter_limit;
276
+ style.tile_edges = draw.tile_edges; // usually activated for debugging, or rare visualization needs
277
+
278
+ // Construct an outline style
279
+ // Reusable outline style object, marked as already wrapped in cache objects (preprocessed = true)
280
+ style.outline = style.outline || {
281
+ width: {}, next_width: {},
282
+ preprocessed: true
283
+ } as GeometryOutlineDraw;
284
+
285
+ if (draw.outline && draw.outline.visible !== false && draw.outline.color && draw.outline.width) {
286
+ // outline width in meters
287
+ // NB: multiply by 2 because outline is applied on both sides of line
288
+ let outline_width = this.calcDistance(draw.outline.width, context) * 2;
289
+ let outline_next_width = this.calcDistanceNextZoom(draw.outline.next_width, context) * 2;
290
+
291
+ if ((outline_width === 0 && outline_next_width === 0) || outline_width < 0 || outline_next_width < 0) {
292
+ // skip lines that don't interpolate between zero or greater width
293
+ style.outline.width.value = null;
294
+ style.outline.next_width.value = null;
295
+ style.outline.color = null;
296
+ style.outline.inline_texcoord_width = null;
297
+ style.outline.texcoords = false;
298
+ }
299
+ else {
300
+ // Maintain consistent outline width around the line fill
301
+ style.outline.width.value = outline_width + style.width_unscaled;
302
+ style.outline.next_width.value = outline_next_width + style.next_width_unscaled;
303
+ style.outline.inline_texcoord_width = style.texcoord_width;
304
+
305
+ // Offset is directly copied from fill to outline, no need to re-calculate it
306
+ style.outline.offset_precalc = style.offset;
307
+ style.outline.offset_scale_precalc = style.offset_scale;
308
+ style.outline.projected_pixel_width = draw.projected_pixel_width;
309
+
310
+ style.outline.color = draw.outline.color;
311
+ style.outline.alpha = draw.outline.alpha;
312
+ style.outline.interactive = draw.outline.interactive;
313
+ style.outline.cap = draw.outline.cap;
314
+ style.outline.join = draw.outline.join;
315
+ style.outline.miter_limit = draw.outline.miter_limit;
316
+ style.outline.texcoords = draw.outline.texcoords;
317
+ style.outline.extrude = draw.outline.extrude;
318
+ style.outline.z = draw.outline.z;
319
+ style.outline.style = draw.outline.style;
320
+ style.outline.variant = draw.outline.variant;
321
+
322
+ // Explicitly defined outline order, or inherited from inner line
323
+ if (draw.outline.order) {
324
+ style.outline.order = this.parseOrder(draw.outline.order, context);
325
+ }
326
+ else {
327
+ style.outline.order = style.order;
328
+ }
329
+
330
+ // Don't let outline be above inner line
331
+ if (style.outline.order > style.order) {
332
+ style.outline.order = style.order;
333
+ }
334
+
335
+ // Outlines are always at half-layer intervals to avoid conflicting with inner lines
336
+ style.outline.order -= 0.5;
337
+ }
338
+ }
339
+ else {
340
+ style.outline.width.value = null;
341
+ style.outline.next_width.value = null;
342
+ style.outline.color = null;
343
+ style.outline.inline_texcoord_width = null;
344
+ }
345
+
346
+ return style;
347
+ },
348
+
349
+ _preprocess (this: LineStyleRuntime, draw: RawGeometryDraw) {
350
+ if (this.cpu_projection && !draw.preprocessed) draw.projected_pixel_width = getProjectedRoadUnit(draw.width) === 'px';
351
+ draw.color = StyleParser.createColorPropertyCache(draw.color);
352
+ draw.alpha = StyleParser.createPropertyCache(draw.alpha);
353
+ draw.width = StyleParser.createPropertyCache(draw.width, StyleParser.parseUnits);
354
+ if (draw.width && (draw.width as PropertyCache).type !== StyleParser.CACHE_TYPE.STATIC) {
355
+ draw.next_width = StyleParser.createPropertyCache(draw.width, StyleParser.parseUnits);
356
+ }
357
+ draw.offset = draw.offset && StyleParser.createPropertyCache(draw.offset, StyleParser.parseUnits);
358
+ if (draw.offset && (draw.offset as PropertyCache).type !== StyleParser.CACHE_TYPE.STATIC) {
359
+ draw.next_offset = StyleParser.createPropertyCache(draw.offset, StyleParser.parseUnits);
360
+ }
361
+ draw.z = StyleParser.createPropertyCache(draw.z, StyleParser.parseUnits);
362
+
363
+ draw.dash = (draw.dash !== undefined ? draw.dash : this.dash);
364
+ draw.dash_key = draw.dash && this.dashTextureKey(draw.dash);
365
+ draw.dash_background_color = (draw.dash_background_color !== undefined ? draw.dash_background_color : this.dash_background_color);
366
+ draw.dash_background_color = draw.dash_background_color && StyleParser.parseColor(draw.dash_background_color);
367
+ draw.texture_merged = draw.dash_key || ((draw.texture !== undefined ? draw.texture : this.texture));
368
+ draw.texcoords = ((this.texcoords || draw.texture_merged) ? 1 : 0);
369
+ this.computeVariant(draw);
370
+
371
+ if (draw.outline) {
372
+ draw.outline.is_outline = true; // mark as outline (so mesh variant can be adjusted for render order, etc.)
373
+ draw.outline.style = draw.outline.style || this.name;
374
+ draw.outline.color = StyleParser.createColorPropertyCache(draw.outline.color);
375
+ draw.outline.alpha = StyleParser.createPropertyCache(draw.outline.alpha);
376
+ draw.outline.width = StyleParser.createPropertyCache(draw.outline.width, StyleParser.parseUnits);
377
+ draw.outline.next_width = StyleParser.createPropertyCache(draw.outline.width, StyleParser.parseUnits); // width re-computed for next zoom
378
+
379
+ draw.outline.interactive = (draw.outline.interactive != null) ? draw.outline.interactive : draw.interactive;
380
+ draw.outline.cap = draw.outline.cap || draw.cap;
381
+ draw.outline.join = draw.outline.join || draw.join;
382
+ draw.outline.miter_limit = (draw.outline.miter_limit != null) ? draw.outline.miter_limit : draw.miter_limit;
383
+
384
+ // always apply inline values for offset and extrusion/height to outline
385
+ draw.outline.offset = draw.offset;
386
+ draw.outline.extrude = draw.extrude;
387
+ draw.outline.z = draw.z;
388
+
389
+ // outline inherits dash pattern, but NOT explicit texture
390
+ let outline_style = this.styles[draw.outline.style];
391
+ if (outline_style) {
392
+ draw.outline.dash = (draw.outline.dash !== undefined ? draw.outline.dash : outline_style.dash);
393
+ draw.outline.texture = (draw.outline.texture !== undefined ? draw.outline.texture : outline_style.texture);
394
+
395
+ if (draw.outline.dash != null) { // dash was defined by outline draw or style
396
+ draw.outline.dash_key = draw.outline.dash && this.dashTextureKey(draw.outline.dash);
397
+ draw.outline.texture_merged = draw.outline.dash_key;
398
+ }
399
+ else if (draw.outline.dash === null) { // dash explicitly disabled by outline draw or style
400
+ draw.outline.dash_key = null;
401
+ draw.outline.texture_merged = draw.outline.texture;
402
+ }
403
+ else if (draw.outline.texture != null) { // texture was defined by outline draw or style
404
+ draw.outline.dash_key = null; // outline explicitly turning off dash
405
+ draw.outline.texture_merged = draw.outline.texture;
406
+ }
407
+ else { // no dash or texture defined for outline, inherit parent dash
408
+ draw.outline.dash = draw.dash;
409
+ draw.outline.dash_key = draw.outline.dash && this.dashTextureKey(draw.outline.dash);
410
+ draw.outline.texture_merged = draw.outline.dash_key;
411
+ }
412
+ draw.outline.dash_background_color = (draw.outline.dash_background_color !== undefined ? draw.outline.dash_background_color : outline_style.dash_background_color);
413
+ draw.outline.dash_background_color = (draw.outline.dash_background_color !== undefined ? draw.outline.dash_background_color : draw.dash_background_color);
414
+ draw.outline.dash_background_color = draw.outline.dash_background_color && StyleParser.parseColor(draw.outline.dash_background_color);
415
+ draw.outline.texcoords = ((outline_style.texcoords || draw.outline.texture_merged) ? 1 : 0);
416
+
417
+ // outline inherits draw blend order from parent inline, unless explicitly turned off with null
418
+ if (draw.outline.blend_order === undefined && draw.blend_order != null) {
419
+ draw.outline.blend_order = draw.blend_order;
420
+ }
421
+
422
+ outline_style.computeVariant(draw.outline);
423
+ }
424
+ else {
425
+ log({ level: 'warn', once: true }, `Layer group '${draw.layers.join(', ')}': ` +
426
+ `line 'outline' specifies non-existent draw style '${draw.outline.style}' (or maybe the style is ` +
427
+ 'defined but is missing a \'base\' or has another error), skipping outlines for features matching this layer group');
428
+ draw.outline = null;
429
+ }
430
+ }
431
+ // Preprocessing replaces authored values with the cache wrappers consumed above.
432
+ return draw as GeometryDraw;
433
+ },
434
+
435
+ // Unique string key for a dash pattern (used as texture name)
436
+ dashTextureKey (this: LineStyleRuntime, dash: number[]) {
437
+ return '__dash_' + JSON.stringify(dash);
438
+ },
439
+
440
+ // Return or render a dash pattern texture
441
+ getDashTexture (this: LineStyleRuntime, dash: number[]) {
442
+ let dash_key = this.dashTextureKey(dash);
443
+
444
+ if (this.dash_textures[dash_key] == null) {
445
+ this.dash_textures[dash_key] = true;
446
+ // Render line pattern
447
+ const dash_texture = renderDashArray(dash, { scale: DASH_SCALE });
448
+ Texture.create(this.resource_context, dash_key, {
449
+ data: dash_texture.pixels,
450
+ height: dash_texture.length,
451
+ width: 1,
452
+ filtering: 'nearest'
453
+ });
454
+ }
455
+ },
456
+
457
+ // Override
458
+ async endData (this: LineStyleRuntime, tile: GeometryTile) {
459
+ const tile_data: GeometryTileData | null = await Style.endData.call(this, tile);
460
+ if (tile_data) {
461
+ tile_data.uniforms.u_has_line_texture = false;
462
+ tile_data.uniforms.u_texture = Texture.default;
463
+ tile_data.uniforms.u_texture_ratio = 1;
464
+ tile_data.uniforms.u_v_scale_adjust = Geo.tile_scale;
465
+ tile_data.uniforms.u_has_dash = 0;
466
+ tile_data.uniforms.u_dash_background_color = [0, 0, 0, 0];
467
+
468
+ let pending = [];
469
+ for (let m in tile_data.meshes) {
470
+ let variant = tile_data.meshes[m].variant;
471
+ if (variant.texture) {
472
+ let uniforms = tile_data.meshes[m].uniforms = tile_data.meshes[m].uniforms || {};
473
+ uniforms.u_has_line_texture = true;
474
+ uniforms.u_texture = variant.texture;
475
+ uniforms.u_texture_ratio = 1;
476
+
477
+ if (variant.dash) {
478
+ uniforms.u_v_scale_adjust = Geo.tile_scale * DASH_SCALE;
479
+ uniforms.u_has_dash = (variant.dash_background_color != null ? 1 : 0);
480
+ uniforms.u_dash_background_color = variant.dash_background_color || [0, 0, 0, 0];
481
+ }
482
+
483
+ if (variant.dash_key && this.dash_textures[variant.dash_key] == null) {
484
+ this.dash_textures[variant.dash_key] = true;
485
+ try {
486
+ await (WorkerBroker as {postMessage(target: string, ...payloads: unknown[]): Promise<unknown>}).postMessage(this.main_thread_target+'.getDashTexture', variant.dash);
487
+ }
488
+ catch (e) {
489
+ log('trace', `${this.name}: line dash texture create failed because style no longer on main thread`);
490
+ }
491
+ }
492
+
493
+ if (Texture.textures[variant.texture] == null) {
494
+ pending.push(
495
+ Texture.syncTexturesToWorker([variant.texture]).then(textures => {
496
+ // The enclosing branch supplies a named, immutable mesh texture.
497
+ let texture = textures[variant.texture as string];
498
+ if (texture) {
499
+ uniforms.u_texture_ratio = texture.height / texture.width;
500
+ }
501
+ })
502
+ );
503
+ }
504
+ else {
505
+ let texture = Texture.textures[variant.texture];
506
+ uniforms.u_texture_ratio = texture.height / texture.width;
507
+ }
508
+ }
509
+ }
510
+ await Promise.all(pending);
511
+ }
512
+ return tile_data;
513
+ },
514
+
515
+ // Calculate and store mesh variant (unique by draw group but not feature)
516
+ computeVariant (this: LineStyleRuntime, draw: GeometryDraw | RawGeometryDraw) {
517
+ // Factors that determine a unique mesh rendering variant
518
+ // The first concatenation converts this numeric flag to the string hash input.
519
+ let key = (draw.offset ? 1 : 0) as string | number; // whether feature has a line offset
520
+ key += '/' + draw.texcoords; // whether feature has texture UVs
521
+ key += '/' + (draw.interactive ? 1 : 0); // whether feature has interactivity
522
+ key += '/' + ((draw.extrude || draw.z) ? 1 : 0); // whether feature has a z coordinate
523
+ key += '/' + draw.is_outline; // whether this is an outline of a line feature
524
+
525
+ if (draw.dash_key) { // whether feature has a line dash pattern
526
+ key += draw.dash_key;
527
+ if (draw.dash_background_color) {
528
+ key += draw.dash_background_color as unknown as string;
529
+ }
530
+ }
531
+
532
+ if (draw.texture_merged) { // whether feature has a line texture
533
+ key += draw.texture_merged;
534
+ }
535
+
536
+ const blend_order = this.getBlendOrderForDraw(draw);
537
+ key += '/' + blend_order;
538
+
539
+ // Create unique key
540
+ key = hashString(key as string);
541
+ draw.variant = key;
542
+
543
+ if (this.variants[key] == null) {
544
+ this.variants[key] = {
545
+ key,
546
+ blend_order,
547
+ mesh_order: (draw.is_outline ? 0 : 1), // outlines should be drawn first, so inline is on top
548
+ selection: (draw.interactive ? 1 : 0),
549
+ offset: (draw.offset ? 1 : 0),
550
+ z_or_offset: ((draw.offset || draw.extrude || draw.z) ? 1 : 0),
551
+ texcoords: draw.texcoords,
552
+ texture: draw.texture_merged,
553
+ dash: draw.dash,
554
+ dash_key: draw.dash_key,
555
+ dash_background_color: draw.dash_background_color as GeometryMeshVariant['dash_background_color']
556
+ };
557
+ }
558
+ },
559
+
560
+ // Override
561
+ // Create or return desired vertex layout permutation based on flags
562
+ vertexLayoutForMeshVariant (this: LineStyleRuntime, variant: GeometryMeshVariant) {
563
+ if (this.vertex_layouts[variant.key] == null) {
564
+ const portable = this.shader_language === 'wgsl';
565
+ // Attributes for this mesh variant
566
+ // WebGL can provide optional fields as constant vertex attributes. WebGPU
567
+ // requires every shader-declared input to be backed by a vertex buffer, so
568
+ // portable layouts write explicit zero values for unused line fields.
569
+ const attribs = [
570
+ { name: 'a_position', size: 4, type: gl.SHORT, normalized: false },
571
+ { name: 'a_extrude', size: 2, type: gl.SHORT, normalized: false },
572
+ { name: 'a_offset', size: 2, type: gl.SHORT, normalized: false, static: ((portable || variant.offset) ? null : [0, 0]) },
573
+ { name: 'a_z_and_offset_scale', size: 2, type: gl.SHORT, normalized: false, static: ((portable || variant.z_or_offset) ? null : [0, 0]) },
574
+ {
575
+ name: 'a_texcoord',
576
+ size: 2,
577
+ type: this.shader_language === 'wgsl' ? gl.FLOAT : gl.UNSIGNED_SHORT,
578
+ normalized: this.shader_language !== 'wgsl',
579
+ static: ((portable || variant.texcoords) ? null : [0, 0])
580
+ },
581
+ { name: 'a_color', size: 4, type: gl.UNSIGNED_BYTE, normalized: true },
582
+ { name: 'a_selection_color', size: 4, type: gl.UNSIGNED_BYTE, normalized: true, static: (variant.selection || this.shader_language === 'wgsl' ? null : [0, 0, 0, 0]) }
583
+ ];
584
+
585
+ this.addCustomAttributesToAttributeList(attribs);
586
+ if (this.cpu_projection) {
587
+ attribs.push({name: 'a_projected_position', size: 3, type: gl.FLOAT, normalized: false});
588
+ attribs.push({name: 'a_projected_stroke', size: 4, type: gl.FLOAT, normalized: false});
589
+ attribs.push({name: 'a_projected_normals', size: 4, type: gl.FLOAT, normalized: false});
590
+ attribs.push({name: 'a_projected_widths', size: 2, type: gl.FLOAT, normalized: false});
591
+ }
592
+ this.vertex_layouts[variant.key] = new VertexLayout(attribs);
593
+ }
594
+ return this.vertex_layouts[variant.key];
595
+ },
596
+
597
+ // Override
598
+ meshVariantTypeForDraw (this: LineStyleRuntime, draw: Pick<GeometryDraw, 'variant'>) {
599
+ return this.variants[draw.variant]; // return pre-calculated mesh variant
600
+ },
601
+
602
+ /**
603
+ * A "template" that sets constant attibutes for each vertex, which is then modified per vertex or per feature.
604
+ * A plain JS array matching the order of the vertex layout.
605
+ */
606
+ makeVertexTemplate(this: LineStyleRuntime, style: LineFeatureStyle, mesh: GeometryBuildMesh) {
607
+ let i = 0;
608
+ const portable = this.shader_language === 'wgsl';
609
+
610
+ // a_position.xy - vertex position
611
+ // a_position.z - line width scaling factor
612
+ // a_position.w - layer order
613
+ this.vertex_template[i++] = 0;
614
+ this.vertex_template[i++] = 0;
615
+ this.vertex_template[i++] = style.width_scale * 1024;
616
+ this.vertex_template[i++] = this.scaleOrder(style.order);
617
+
618
+ // a_extrude.xy - extrusion vector (vertex extrusion away from center of line)
619
+ this.vertex_template[i++] = 0;
620
+ this.vertex_template[i++] = 0;
621
+
622
+ // a_offset.xy - normal vector
623
+ // offset can be static or dynamic depending on style
624
+ if (portable || mesh.variant.offset) {
625
+ this.vertex_template[i++] = 0;
626
+ this.vertex_template[i++] = 0;
627
+ }
628
+
629
+ // a_z_and_offset_scale.xy
630
+ if (portable || mesh.variant.z_or_offset) {
631
+ this.vertex_template[i++] = style.z || 0; // feature z position
632
+ this.vertex_template[i++] = style.offset_scale * 1024; // line offset scaling factor
633
+ }
634
+
635
+ // a_texcoord.uv - texture coordinates
636
+ if (portable || mesh.variant.texcoords) {
637
+ this.vertex_template[i++] = 0;
638
+ this.vertex_template[i++] = 0;
639
+ }
640
+
641
+ // a_color.rgba - feature color
642
+ this.vertex_template[i++] = style.color[0] * 255;
643
+ this.vertex_template[i++] = style.color[1] * 255;
644
+ this.vertex_template[i++] = style.color[2] * 255;
645
+ this.vertex_template[i++] = (style.alpha != null ? style.alpha : style.color[3]) * 255;
646
+
647
+ // a_selection_color.rgba - selection color
648
+ if (mesh.variant.selection || this.shader_language === 'wgsl') {
649
+ this.vertex_template[i++] = style.selection_color[0] * 255;
650
+ this.vertex_template[i++] = style.selection_color[1] * 255;
651
+ this.vertex_template[i++] = style.selection_color[2] * 255;
652
+ this.vertex_template[i++] = style.selection_color[3] * 255;
653
+ }
654
+
655
+ this.addCustomAttributesToVertexTemplate(style, i);
656
+ if (this.cpu_projection) {
657
+ const index = mesh.vertex_data.vertex_layout.index.a_projected_position;
658
+ this.vertex_template[index] = this.vertex_template[index + 1] = this.vertex_template[index + 2] = 0;
659
+ const stroke = mesh.vertex_data.vertex_layout.index.a_projected_stroke;
660
+ this.vertex_template[stroke] = this.vertex_template[stroke + 1] = this.vertex_template[stroke + 2] = 0;
661
+ this.vertex_template[stroke + 3] = style.projected_pixel_scale ?? 0;
662
+ }
663
+ return this.vertex_template;
664
+ },
665
+
666
+ buildLines(this: LineStyleRuntime, lines: GeometryLine[], style: LineFeatureStyle, context: GeometryContext, options?: {closed_polygon?: boolean; remove_tile_edges?: boolean}) {
667
+ // Outline (build first so that blended geometry without a depth test is drawn first/under the inner line)
668
+ this.feature_style = this.outline_feature_style; // swap in outline-specific style holder
669
+ if (style.outline && style.outline.color != null && style.outline.width.value != null) {
670
+ var outline_style = this.styles[style.outline.style];
671
+ if (outline_style) {
672
+ outline_style.addFeature(context.feature, style.outline, context);
673
+ }
674
+ }
675
+
676
+ // Main line
677
+ this.feature_style = this.inline_feature_style; // restore calculated style for inline
678
+ let mesh = this.getTileMesh(context.tile, this.meshVariantTypeForDraw(style));
679
+ let vertex_data = mesh.vertex_data;
680
+ let vertex_layout = vertex_data.vertex_layout;
681
+ let vertex_template = this.makeVertexTemplate(style, mesh);
682
+ const vertex_layout_index = this.shader_language === 'wgsl' && !mesh.variant.texcoords ?
683
+ Object.assign({}, vertex_layout.index, { a_texcoord: null }) :
684
+ vertex_layout.index;
685
+ return buildPolylines(
686
+ lines,
687
+ style,
688
+ vertex_data,
689
+ vertex_template,
690
+ // Extrusion is packed; a constant zero offset has no component index.
691
+ vertex_layout_index as unknown as PolylineVertexIndices,
692
+ (options && options.closed_polygon), // closed_polygon
693
+ (!style.tile_edges && options && options.remove_tile_edges), // remove_tile_edges
694
+ (Geo.tile_scale * context.tile.pad_scale * 2) // tile_edge_tolerance
695
+ );
696
+ },
697
+
698
+ buildPolygons(this: LineStyleRuntime, polygons: GeometryPolygon[], style: LineFeatureStyle, context: GeometryContext) {
699
+ // Render polygons as individual lines
700
+ let geom_count = 0;
701
+ for (let p=0; p < polygons.length; p++) {
702
+ geom_count += this.buildLines(polygons[p], style, context, { closed_polygon: true, remove_tile_edges: true });
703
+ }
704
+ return geom_count;
705
+ }
706
+
707
+ } satisfies Partial<LineStyleRuntime>);