@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,285 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type VertexLayout from './vertex_layout';
6
+
7
+ type VertexAttribute = VertexLayout['dynamic_attribs'][number];
8
+
9
+ /** Packed triangle data after projection-aware refinement. */
10
+ export type GlobeMeshData = {
11
+ /** Interleaved vertices, with the original vertices retained at their original indices. */
12
+ vertices: Uint8Array;
13
+ /** Triangle indices, promoted to 32 bits when necessary. */
14
+ indices: Uint16Array | Uint32Array;
15
+ };
16
+
17
+ /** Limits for globe refinement in Tangram tile-local coordinates. */
18
+ export type GlobeMeshOptions = {
19
+ /** Actual source tile zoom, not the style zoom. */
20
+ tileZoom: number;
21
+ /** Tile-local units per tile edge. */
22
+ tileScale?: number;
23
+ /** Maximum Mercator angular edge span; conservatively bounds spherical span. */
24
+ maxAngularSpan?: number;
25
+ /** Maximum additional vertices; additional triangles are limited to twice this budget. */
26
+ maxAdditionalVertices?: number;
27
+ /** Optional expanded tile-space position for packed ribbons; never changes the preserved attributes. */
28
+ getPosition?: (vertex: DataView) => [number, number];
29
+ /** Optional packed height for topology checks on elevated surfaces; curvature still uses XY. */
30
+ getElevation?: (vertex: DataView) => number;
31
+ /** Optional additional edge decision; callers must use the same criterion across adjacent meshes. */
32
+ shouldSplitEdge?: (first: DataView, second: DataView) => boolean;
33
+ /** Fan partial-edge refinements around an interior vertex instead of introducing a long diagonal. */
34
+ splitRemainderInterior?: boolean;
35
+ /** Choose the shorter green-refinement diagonal; useful for floating terrain ribbons and thin MVT faces. */
36
+ splitRemainderShortest?: boolean;
37
+ };
38
+
39
+ const INTERPOLATED_ATTRIBUTES = new Set([
40
+ 'a_position', 'a_normal', 'a_color', 'a_texcoord', 'a_extrude', 'a_offset',
41
+ 'a_z_and_offset_scale', 'a_projected_position', 'a_projected_normal', 'a_projected_stroke', 'a_projected_normals', 'a_projected_widths'
42
+ ]);
43
+
44
+ /**
45
+ * Split long triangle edges before spherical projection. Shared indexed edges share
46
+ * midpoints; independent tile edges use the same quantized midpoint rule. Selection
47
+ * IDs and layer order remain flat. Unknown varying attributes are rejected rather
48
+ * than guessing their interpolation semantics. Camera state is deliberately absent.
49
+ */
50
+ export function refineGlobeMesh(
51
+ vertices: Uint8Array,
52
+ indices: Uint16Array | Uint32Array | false,
53
+ layout: {stride: number; dynamic_attribs: VertexAttribute[]},
54
+ options: GlobeMeshOptions
55
+ ): GlobeMeshData {
56
+ const tileScale = options.tileScale ?? 4096;
57
+ const angularSpan = options.maxAngularSpan ?? 4;
58
+ const budget = options.maxAdditionalVertices ?? 262144;
59
+ if (!Number.isInteger(options.tileZoom) || options.tileZoom < 0 || options.tileZoom > 30 ||
60
+ !Number.isFinite(tileScale) || tileScale <= 0 ||
61
+ !Number.isFinite(angularSpan) || angularSpan <= 0 || angularSpan > 180 ||
62
+ !Number.isInteger(budget) || budget < 0) {
63
+ throw new RangeError('Globe mesh: invalid refinement limits');
64
+ }
65
+ const maximumEdge = tileScale * 2 ** options.tileZoom * angularSpan / 360;
66
+ if (maximumEdge < 2) {
67
+ throw new RangeError('Globe mesh: refinement exceeds packed position precision');
68
+ }
69
+ const position = layout.dynamic_attribs.find(attribute => attribute.name === 'a_position');
70
+ if (!position || position.size < 2 || position.offset === undefined ||
71
+ layout.stride <= 0 || vertices.byteLength % layout.stride !== 0) {
72
+ throw new Error('Globe mesh: an aligned position layout is required');
73
+ }
74
+ const originalCount = vertices.byteLength / layout.stride;
75
+ const triangleIndices = indices || Uint32Array.from({length: originalCount}, (_, index) => index);
76
+ if (triangleIndices.length % 3 !== 0 || triangleIndices.some(index => index >= originalCount)) {
77
+ throw new Error('Globe mesh: invalid triangle indices');
78
+ }
79
+ const records: Uint8Array[] = [];
80
+ const positions: [number, number][] = [];
81
+ for (let index = 0; index < originalCount; index++) {
82
+ const record = vertices.subarray(index * layout.stride, (index + 1) * layout.stride);
83
+ records.push(record);
84
+ const view = new DataView(record.buffer, record.byteOffset, record.byteLength);
85
+ const point: [number, number] = options.getPosition ? options.getPosition(view) :
86
+ [readComponent(view, position, 0), readComponent(view, position, 1)];
87
+ if (!point.every(Number.isFinite)) {
88
+ throw new Error('Globe mesh: nonfinite position');
89
+ }
90
+ positions.push(point);
91
+ }
92
+ const midpoints = new Map<string, number>();
93
+ const output: number[] = [];
94
+ const pending: number[][] = [];
95
+ const maximumTriangles = triangleIndices.length / 3 + budget * 2;
96
+ // A LIFO worklist must start in reverse to preserve source triangle/feature draw order.
97
+ for (let index = triangleIndices.length - 3; index >= 0; index -= 3) {
98
+ pending.push([triangleIndices[index], triangleIndices[index + 1], triangleIndices[index + 2]]);
99
+ }
100
+ const isLong = (first: number, second: number): boolean => {
101
+ const distance = Math.hypot(positions[first][0] - positions[second][0], positions[first][1] - positions[second][1]);
102
+ return distance > maximumEdge || (distance >= 2 && Boolean(options.shouldSplitEdge?.(
103
+ new DataView(records[first].buffer, records[first].byteOffset, layout.stride),
104
+ new DataView(records[second].buffer, records[second].byteOffset, layout.stride))));
105
+ };
106
+ const getMidpoint = (first: number, second: number): number => {
107
+ const key = `${Math.min(first, second)}:${Math.max(first, second)}`;
108
+ const cached = midpoints.get(key);
109
+ if (cached !== undefined) {
110
+ return cached;
111
+ }
112
+ if (records.length >= originalCount + budget) {
113
+ throw new RangeError('Globe mesh: refinement vertex budget exceeded');
114
+ }
115
+ const record = interpolatePackedVertex(records[first], records[second], layout, 0.5);
116
+ const outputView = new DataView(record.buffer);
117
+ const midpoint = records.length;
118
+ records.push(record);
119
+ positions.push(options.getPosition ? options.getPosition(outputView) :
120
+ [readComponent(outputView, position, 0), readComponent(outputView, position, 1)]);
121
+ midpoints.set(key, midpoint);
122
+ return midpoint;
123
+ };
124
+ while (pending.length) {
125
+ const triangle = pending.pop()!;
126
+ const [first, second, third] = triangle;
127
+ const split = [isLong(first, second), isLong(second, third), isLong(third, first)];
128
+ const count = split.filter(Boolean).length;
129
+ if (count === 0) {
130
+ output.push(first, second, third);
131
+ }
132
+ else if (count === 3) {
133
+ const firstMidpoint = getMidpoint(first, second);
134
+ const secondMidpoint = getMidpoint(second, third);
135
+ const thirdMidpoint = getMidpoint(third, first);
136
+ pending.push([first, firstMidpoint, thirdMidpoint], [firstMidpoint, second, secondMidpoint],
137
+ [thirdMidpoint, secondMidpoint, third], [firstMidpoint, secondMidpoint, thirdMidpoint]);
138
+ }
139
+ else {
140
+ // Rotate the triangle to place the single split (or unsplit) edge first.
141
+ const edge = split.findIndex(value => value === (count === 1));
142
+ const start = triangle[edge];
143
+ const end = triangle[(edge + 1) % 3];
144
+ const opposite = triangle[(edge + 2) % 3];
145
+ if (options.splitRemainderInterior) {
146
+ // Repeated green triangulation can alternate long diagonals
147
+ // without converging. A centroid fan contracts interior edges
148
+ // and leaves every shared boundary midpoint unchanged.
149
+ const boundary = [start];
150
+ if (split[edge]) boundary.push(getMidpoint(start, end));
151
+ boundary.push(end);
152
+ if (split[(edge + 1) % 3]) boundary.push(getMidpoint(end, opposite));
153
+ boundary.push(opposite);
154
+ if (split[(edge + 2) % 3]) boundary.push(getMidpoint(opposite, start));
155
+ if (records.length >= originalCount + budget) {
156
+ throw new RangeError('Globe mesh: refinement vertex budget exceeded');
157
+ }
158
+ const record = interpolatePackedVertex(
159
+ interpolatePackedVertex(records[start], records[end], layout, 0.5),
160
+ records[opposite], layout, 1 / 3);
161
+ const view = new DataView(record.buffer);
162
+ const point: [number, number] = options.getPosition ? options.getPosition(view) :
163
+ [readComponent(view, position, 0), readComponent(view, position, 1)];
164
+ const cross = (first: number[], second: number[], third: number[]): number =>
165
+ (second[0] - first[0]) * (third[1] - first[1]) - (second[1] - first[1]) * (third[0] - first[0]);
166
+ const topologyPosition = (index: number): [number, number, number] => [
167
+ ...positions[index], options.getElevation?.(new DataView(records[index].buffer,
168
+ records[index].byteOffset, layout.stride)) ?? 0];
169
+ const corners = [start, end, opposite].map(topologyPosition);
170
+ const axes = selectTrianglePlane(corners);
171
+ const flatten = (position: readonly [number, number, number]): [number, number] =>
172
+ [position[axes[0]], position[axes[1]]];
173
+ const centerPoint = flatten([...point, options.getElevation?.(view) ?? 0]);
174
+ const orientation = cross(flatten(corners[0]), flatten(corners[1]), flatten(corners[2]));
175
+ if (boundary.some((corner, boundaryEdge) =>
176
+ cross(flatten(topologyPosition(corner)), flatten(topologyPosition(boundary[(boundaryEdge + 1) % boundary.length])), centerPoint) * orientation <= 0)) {
177
+ throw new RangeError('Globe mesh: refinement exceeds packed position precision');
178
+ }
179
+ const center = records.length;
180
+ records.push(record);
181
+ positions.push(point);
182
+ for (let boundaryEdge = 0; boundaryEdge < boundary.length; boundaryEdge++) {
183
+ pending.push([boundary[boundaryEdge], boundary[(boundaryEdge + 1) % boundary.length], center]);
184
+ }
185
+ }
186
+ else if (count === 1) {
187
+ const midpoint = getMidpoint(start, end);
188
+ pending.push([start, midpoint, opposite], [midpoint, end, opposite]);
189
+ }
190
+ else {
191
+ const endMidpoint = getMidpoint(end, opposite);
192
+ const startMidpoint = getMidpoint(opposite, start);
193
+ const distance = (first: number, second: number) => Math.hypot(positions[first][0] - positions[second][0], positions[first][1] - positions[second][1]);
194
+ pending.push([opposite, startMidpoint, endMidpoint]);
195
+ if (options.splitRemainderShortest && distance(start, endMidpoint) < distance(end, startMidpoint)) {
196
+ pending.push([start, end, endMidpoint], [start, endMidpoint, startMidpoint]);
197
+ } else {
198
+ pending.push([start, end, startMidpoint], [end, endMidpoint, startMidpoint]);
199
+ }
200
+ }
201
+ }
202
+ if (pending.length + output.length / 3 > maximumTriangles) {
203
+ throw new RangeError('Globe mesh: refinement triangle budget exceeded');
204
+ }
205
+ }
206
+ if (records.length === originalCount) {
207
+ return {vertices, indices: triangleIndices};
208
+ }
209
+ const refinedVertices = new Uint8Array(records.length * layout.stride);
210
+ records.forEach((record, index) => refinedVertices.set(record, index * layout.stride));
211
+ return {
212
+ vertices: refinedVertices,
213
+ indices: records.length <= 65536 ? new Uint16Array(output) : new Uint32Array(output)
214
+ };
215
+ }
216
+
217
+ /** Choose the dominant source-space plane so vertical walls retain the same packed-precision checks as roofs. */
218
+ export function selectTrianglePlane(points: readonly (readonly [number, number, number])[]): readonly [0 | 1 | 2, 0 | 1 | 2] {
219
+ const planes = [[0, 1], [0, 2], [1, 2]] as const;
220
+ let selected: typeof planes[number] = planes[0];
221
+ let maximumArea = 0;
222
+ for (const plane of planes) {
223
+ const [first, second] = plane;
224
+ const area = Math.abs((points[1][first] - points[0][first]) * (points[2][second] - points[0][second]) -
225
+ (points[1][second] - points[0][second]) * (points[2][first] - points[0][first]));
226
+ if (area > maximumArea) {maximumArea = area; selected = plane;}
227
+ }
228
+ return selected;
229
+ }
230
+
231
+ /** Preserve Tangram's packed interpolation and flat IDs at refinement or clipping intersections. */
232
+ export function interpolatePackedVertex(first: Uint8Array, second: Uint8Array,
233
+ layout: {stride: number; dynamic_attribs: VertexAttribute[]}, fraction: number): Uint8Array {
234
+ const record = first.slice();
235
+ const firstView = new DataView(first.buffer, first.byteOffset, layout.stride);
236
+ const secondView = new DataView(second.buffer, second.byteOffset, layout.stride);
237
+ const outputView = new DataView(record.buffer);
238
+ for (const attribute of layout.dynamic_attribs) {
239
+ for (let component = 0; component < attribute.size; component++) {
240
+ const firstValue = readComponent(firstView, attribute, component);
241
+ const secondValue = readComponent(secondView, attribute, component);
242
+ const flat = attribute.name === 'a_selection_color' || (attribute.name === 'a_position' && component === 3);
243
+ if (flat || !INTERPOLATED_ATTRIBUTES.has(attribute.name)) {
244
+ if (firstValue !== secondValue) throw new Error(`Globe mesh: varying flat attribute ${attribute.name} is unsupported`);
245
+ }
246
+ else {
247
+ // Keep the exact existing midpoint arithmetic, including integer rounding.
248
+ writeComponent(outputView, attribute, component, fraction === 0.5 ?
249
+ (firstValue + secondValue) / 2 : firstValue * (1 - fraction) + secondValue * fraction);
250
+ }
251
+ }
252
+ }
253
+ return record;
254
+ }
255
+
256
+ /** Read a component without assuming the interleaved buffer starts at byte zero. */
257
+ function readComponent(view: DataView, attribute: VertexAttribute, component: number): number {
258
+ const offset = attribute.offset ?? 0;
259
+ switch (attribute.type) {
260
+ case 0x1400: return view.getInt8(offset + component);
261
+ case 0x1401: return view.getUint8(offset + component);
262
+ case 0x1402: return view.getInt16(offset + component * 2, true);
263
+ case 0x1403: return view.getUint16(offset + component * 2, true);
264
+ case 0x1404: return view.getInt32(offset + component * 4, true);
265
+ case 0x1405: return view.getUint32(offset + component * 4, true);
266
+ case 0x1406: return view.getFloat32(offset + component * 4, true);
267
+ default: throw new Error(`Globe mesh: unsupported attribute type ${attribute.type}`);
268
+ }
269
+ }
270
+
271
+ /** Interpolate in the attribute's packed domain, rounding integer coordinates consistently. */
272
+ function writeComponent(view: DataView, attribute: VertexAttribute, component: number, value: number): void {
273
+ const offset = attribute.offset ?? 0;
274
+ const integer = Math.round(value);
275
+ switch (attribute.type) {
276
+ case 0x1400: view.setInt8(offset + component, integer); break;
277
+ case 0x1401: view.setUint8(offset + component, integer); break;
278
+ case 0x1402: view.setInt16(offset + component * 2, integer, true); break;
279
+ case 0x1403: view.setUint16(offset + component * 2, integer, true); break;
280
+ case 0x1404: view.setInt32(offset + component * 4, integer, true); break;
281
+ case 0x1405: view.setUint32(offset + component * 4, integer, true); break;
282
+ case 0x1406: view.setFloat32(offset + component * 4, value, true); break;
283
+ default: throw new Error(`Globe mesh: unsupported attribute type ${attribute.type}`);
284
+ }
285
+ }
package/src/gl/glsl.ts ADDED
@@ -0,0 +1,257 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ type UniformValue = number | string | boolean | number[] | string[] | number[][];
7
+ type ParsedUniform = {
8
+ type: string;
9
+ method: string;
10
+ name: string;
11
+ value: UniformValue;
12
+ path: (string | number)[];
13
+ };
14
+
15
+ interface GLSLNamespace {
16
+ parseUniforms(uniforms?: Record<string, unknown>): ParsedUniform[];
17
+ defineVariable(name: string, value: unknown): string | undefined;
18
+ defineUniform(name: string, value: unknown): string | undefined;
19
+ expandVec3(value: UniformValue, z?: number): number[] | undefined;
20
+ expandVec4(value: UniformValue, w?: number): number[] | undefined;
21
+ }
22
+
23
+ const GLSL = {} as GLSLNamespace;
24
+ export default GLSL;
25
+
26
+ /**
27
+ Parse uniforms from a JS object, infers types and returns an array of objects with the
28
+ necessary information to set uniform values on a GL program. Each object in the returned
29
+ array has the form:
30
+ { type, method, name, value }
31
+
32
+ type: the GL uniform type, such as 'vec3', 'float', etc.
33
+ method: the GL uniform setter method to use, such as '1f', '3fv', etc.
34
+ name: the fully qualified name of the GL uniform location, e.g. 'array[0].field', etc.
35
+ value: the value to be passed to the GL uniform setter for that type, e.g. [1, 2, 3] for a vec3
36
+
37
+ Textures have special behavior: uniforms with string values are treated as textures, and
38
+ the string is used as a unique texture 'key' to be interpreted by the caller (which is responsible
39
+ for actually setting the uniforms). For example, this could be used as a key into a dictionary of
40
+ known texture names, or it could simply be used as a URL to dynamically load the texture from.
41
+ */
42
+ GLSL.parseUniforms = function (uniforms: Record<string, unknown> = {}): ParsedUniform[] {
43
+ const parsed: ParsedUniform[] = [];
44
+
45
+ for (const [name, uniform] of Object.entries(uniforms)) {
46
+ // Single float
47
+ if (typeof uniform === 'number') {
48
+ parsed.push({
49
+ type: 'float',
50
+ method: '1f',
51
+ name,
52
+ value: uniform,
53
+ path: [name]
54
+ });
55
+ }
56
+ // Array: vector, array of floats, array of textures
57
+ else if (Array.isArray(uniform)) {
58
+ // Numeric values
59
+ if (typeof uniform[0] === 'number') {
60
+ // float vectors (vec2, vec3, vec4)
61
+ if (uniform.length >= 2 && uniform.length <= 4) {
62
+ parsed.push({
63
+ type: 'vec' + uniform.length,
64
+ method: uniform.length + 'fv',
65
+ name,
66
+ value: uniform,
67
+ path: [name]
68
+ });
69
+ }
70
+ // float array
71
+ else if (uniform.length > 4) {
72
+ parsed.push({
73
+ type: 'float[]',
74
+ method: '1fv',
75
+ name: name + '[0]',
76
+ value: uniform,
77
+ path: [name]
78
+ });
79
+ }
80
+ // TODO: assume matrix for (typeof == Float32Array && length == 16)?
81
+ }
82
+ // Array of textures
83
+ else if (typeof uniform[0] === 'string') {
84
+ for (let u = 0; u < uniform.length; u++) {
85
+ parsed.push({
86
+ type: 'sampler2D',
87
+ method: '1i',
88
+ name: name + '[' + u + ']',
89
+ value: uniform[u],
90
+ path: [name, u]
91
+ });
92
+ }
93
+ }
94
+ // Array of arrays - but only arrays of vectors are allowed in this case
95
+ else if (Array.isArray(uniform[0]) && typeof uniform[0][0] === 'number') {
96
+ // float vectors (vec2, vec3, vec4)
97
+ if (uniform[0].length >= 2 && uniform[0].length <= 4) {
98
+ // Set each vector in the array
99
+ for (let u = 0; u < uniform.length; u++) {
100
+ parsed.push({
101
+ type: 'vec' + uniform[0].length,
102
+ method: uniform[0].length + 'fv',
103
+ name: name + '[' + u + ']',
104
+ value: uniform[u],
105
+ path: [name, u]
106
+ });
107
+ }
108
+ }
109
+ }
110
+ // TODO: else warning
111
+ }
112
+ // Boolean
113
+ else if (typeof uniform === 'boolean') {
114
+ parsed.push({
115
+ type: 'bool',
116
+ method: '1i',
117
+ name,
118
+ value: uniform,
119
+ path: [name]
120
+ });
121
+ }
122
+ // Texture
123
+ else if (typeof uniform === 'string') {
124
+ parsed.push({
125
+ type: 'sampler2D',
126
+ method: '1i',
127
+ name,
128
+ value: uniform,
129
+ path: [name]
130
+ });
131
+ }
132
+ }
133
+
134
+ return parsed;
135
+ };
136
+
137
+ /**
138
+ Generate a GLSL variable definition from a JS object
139
+ */
140
+ GLSL.defineVariable = function (name: string, value: unknown): string | undefined {
141
+ let type: string | undefined;
142
+ let array: number | undefined;
143
+
144
+ // Single float
145
+ if (typeof value === 'number') {
146
+ type = 'float';
147
+ }
148
+ // Multiple floats - vector or array
149
+ else if (Array.isArray(value)) {
150
+ // Numeric values
151
+ if (typeof value[0] === 'number') {
152
+ // float vectors (vec2, vec3, vec4)
153
+ if (value.length >= 2 && value.length <= 4) {
154
+ type = 'vec' + value.length;
155
+ }
156
+ // float array
157
+ else { //if (value.length > 4) {
158
+ type = 'float';
159
+ array = value.length;
160
+ }
161
+ // TODO: assume matrix for (typeof == Float32Array && length == 16)?
162
+ }
163
+ // Array of textures
164
+ else if (typeof value[0] === 'string') {
165
+ type = 'sampler2D';
166
+ array = value.length;
167
+ }
168
+ // Array of arrays - but only arrays of vectors are allowed in this case
169
+ else if (Array.isArray(value[0]) && typeof value[0][0] === 'number') {
170
+ // float vectors (vec2, vec3, vec4)
171
+ if (value[0].length >= 2 && value[0].length <= 4) {
172
+ type = 'vec' + value[0].length;
173
+ array = value.length;
174
+ }
175
+ }
176
+ }
177
+ // Boolean
178
+ else if (typeof value === 'boolean') {
179
+ type = 'bool';
180
+ }
181
+ // Texture
182
+ else if (typeof value === 'string') {
183
+ type = 'sampler2D';
184
+ }
185
+ else {
186
+ return; // no valid type found
187
+ }
188
+
189
+ // Construct variable definition
190
+ var variable = '';
191
+ variable += `${type} ${name}`;
192
+ if (array) {
193
+ variable += `[${array}]`;
194
+ }
195
+ variable += ';\n';
196
+
197
+ return variable;
198
+ };
199
+
200
+ /**
201
+ Generate a GLSL uniform definition from a JS object
202
+ */
203
+ GLSL.defineUniform = function (name: string, value: unknown): string | undefined {
204
+ var def = GLSL.defineVariable(name, value);
205
+ if (!def) {
206
+ return;
207
+ }
208
+ return 'uniform ' + def;
209
+ };
210
+
211
+ /**
212
+ Expand a single value or 2-element array into a 3-element array, with the last ( z )
213
+ coordinate defaulting to 1 (with option to specify). Also runs parseFloat to try to maintain
214
+ data integrity. Returns null if input couldn't be parsed.
215
+ */
216
+ GLSL.expandVec3 = function (v: UniformValue, z = 1): number[] | undefined {
217
+ let x: number[];
218
+ if (Array.isArray(v)) {
219
+ if (v.length === 2) {
220
+ x = [...v, z].map(parseFloat as any);
221
+ }
222
+ else {
223
+ return v as number[];
224
+ }
225
+ }
226
+ else {
227
+ x = [v, v, v].map(parseFloat as any);
228
+ }
229
+
230
+ if (x && x.every(n => typeof n === 'number' && !isNaN(n))) {
231
+ return x;
232
+ }
233
+ };
234
+
235
+ /**
236
+ Expand a single value or 3-element array into a 4-element array, with the last (e.g. w or a)
237
+ coordinate defaulting to 1 (with option to specify). Also runs parseFloat to try to maintain
238
+ data integrity. Returns null if input couldn't be parsed.
239
+ */
240
+ GLSL.expandVec4 = function (v: UniformValue, w = 1): number[] | undefined {
241
+ let x: number[];
242
+ if (Array.isArray(v)) {
243
+ if (v.length === 3) {
244
+ x = [...v, w].map(parseFloat as any);
245
+ }
246
+ else {
247
+ return v as number[];
248
+ }
249
+ }
250
+ else {
251
+ x = [v, v, v, w].map(parseFloat as any);
252
+ }
253
+
254
+ if (x && x.every(n => typeof n === 'number' && !isNaN(n))) {
255
+ return x;
256
+ }
257
+ };
@@ -0,0 +1,56 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {Buffer, RenderPass, RenderPipelineParameters} from '@luma.gl/core';
6
+ import type {GlobeMeshOptions} from './globe_mesh';
7
+ import type {VertexArrayBinding, VertexArrayContext} from './vao';
8
+ import type {VertexAttribute, VertexAttributeProgram, VertexAttributeContext} from './vertex-types';
9
+ import type VBOMesh from './vbo_mesh';
10
+ import type {TangramDrawableProgram, TangramMeshBufferOptions, TangramMeshDrawOptions, TangramMeshDrawDescriptor} from '../gpu/tangram_gpu_backend';
11
+
12
+ /** Original packed vertex/index bytes retained only when CPU updates or refinement need them. */
13
+ export type MeshVertexData = Uint8Array | Int8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array;
14
+ /** Missing element data means the mesh uses a non-indexed draw. */
15
+ export type MeshElementData = Uint16Array | Uint32Array | false | null | undefined;
16
+ /** The classic mesh path uses raw GL; the portable path needs no GL context. */
17
+ export type MeshContext = Pick<WebGLRenderingContext, 'STATIC_DRAW' | 'ELEMENT_ARRAY_BUFFER' | 'ARRAY_BUFFER' |
18
+ 'createBuffer' | 'bindBuffer' | 'bufferData' | 'drawElements' | 'drawArrays' | 'deleteBuffer'> & VertexArrayContext & VertexAttributeContext;
19
+ /** Layout capabilities shared by device meshes and their classic attribute bindings. */
20
+ export interface MeshVertexLayout {
21
+ stride: number;
22
+ /** Packed attribute offsets, absent only for minimal non-annotation layouts. */
23
+ offset?: Record<string, number>;
24
+ dynamic_attribs?: VertexAttribute[];
25
+ getBufferLayout(): TangramMeshDrawDescriptor['bufferLayout'];
26
+ getStaticAttributes(): {attribute: string; value: number[]}[];
27
+ enableDynamicAttributes?(context: VertexAttributeContext, program: VertexAttributeProgram): void;
28
+ enableStaticAttributes?(context: VertexAttributeContext, program: VertexAttributeProgram): void;
29
+ }
30
+ /** Legacy program operations added to the device submission contract. */
31
+ export interface MeshProgram extends TangramDrawableProgram, VertexAttributeProgram {
32
+ use(options?: {bindUniformBlocks: boolean}): void;
33
+ }
34
+ /** Caller-supplied allocation and owned texture/fade/refinement state. */
35
+ export interface MeshOptions {
36
+ id?: string | number;
37
+ bufferFactory?: (options: TangramMeshBufferOptions) => Buffer;
38
+ draw_mode?: number;
39
+ data_usage?: number;
40
+ uniforms?: Record<string, unknown>;
41
+ textures?: string[];
42
+ retain?: boolean;
43
+ fade_in_time?: number;
44
+ globeRefinement?: GlobeMeshOptions;
45
+ globeRefinementError?: string;
46
+ }
47
+ /** Per-draw host state; camera projection controls lazy geometry refinement only. */
48
+ export interface MeshRenderOptions {
49
+ projection?: string;
50
+ program?: MeshProgram;
51
+ meshRenderer?: {drawMesh(options: Omit<TangramMeshDrawOptions, 'mesh'> & {mesh: VBOMesh}): boolean | null};
52
+ renderPass?: RenderPass;
53
+ renderState?: RenderPipelineParameters;
54
+ }
55
+ /** Classic bindings are opaque to device renderers and keyed by program identity. */
56
+ export type MeshVertexArrays = Record<string | number, VertexArrayBinding>;