maplibre-gl 2.1.8 → 2.2.0-pre.2

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 (121) hide show
  1. package/build/generate-style-spec.ts +2 -0
  2. package/dist/maplibre-gl-csp-worker.js +1 -1
  3. package/dist/maplibre-gl-csp-worker.js.map +1 -1
  4. package/dist/maplibre-gl-csp.js +1 -1
  5. package/dist/maplibre-gl-csp.js.map +1 -1
  6. package/dist/maplibre-gl-dev.js +1517 -290
  7. package/dist/maplibre-gl.css +1 -1
  8. package/dist/maplibre-gl.d.ts +3476 -3112
  9. package/dist/maplibre-gl.js +4 -4
  10. package/dist/maplibre-gl.js.map +1 -1
  11. package/dist/package.json +1 -1
  12. package/package.json +15 -15
  13. package/src/css/maplibre-gl.css +20 -0
  14. package/src/css/svg/maplibregl-ctrl-terrain.svg +7 -0
  15. package/src/data/bucket/fill_extrusion_attributes.ts +4 -0
  16. package/src/data/bucket/fill_extrusion_bucket.ts +28 -4
  17. package/src/data/dem_data.test.ts +14 -1
  18. package/src/data/dem_data.ts +13 -0
  19. package/src/geo/transform.test.ts +56 -1
  20. package/src/geo/transform.ts +199 -47
  21. package/src/index.ts +2 -0
  22. package/src/render/draw_background.ts +6 -6
  23. package/src/render/draw_circle.ts +6 -2
  24. package/src/render/draw_collision_debug.ts +5 -1
  25. package/src/render/draw_debug.ts +5 -5
  26. package/src/render/draw_fill.ts +5 -2
  27. package/src/render/draw_fill_extrusion.ts +3 -2
  28. package/src/render/draw_heatmap.ts +2 -3
  29. package/src/render/draw_hillshade.ts +8 -7
  30. package/src/render/draw_line.ts +7 -5
  31. package/src/render/draw_raster.ts +8 -6
  32. package/src/render/draw_symbol.test.ts +34 -10
  33. package/src/render/draw_symbol.ts +23 -12
  34. package/src/render/draw_terrain.ts +123 -0
  35. package/src/render/painter.ts +52 -14
  36. package/src/render/program/hillshade_program.ts +7 -2
  37. package/src/render/program/line_program.ts +24 -10
  38. package/src/render/program/program_uniforms.ts +5 -1
  39. package/src/render/program/terrain_program.ts +83 -0
  40. package/src/render/program.ts +29 -5
  41. package/src/render/render_to_texture.test.ts +41 -0
  42. package/src/render/render_to_texture.ts +154 -0
  43. package/src/render/terrain.test.ts +53 -0
  44. package/src/render/terrain.ts +369 -0
  45. package/src/render/vertex_array_object.ts +21 -4
  46. package/src/shaders/_prelude.vertex.glsl +76 -0
  47. package/src/shaders/_prelude.vertex.glsl.g.ts +1 -1
  48. package/src/shaders/circle.fragment.glsl +2 -1
  49. package/src/shaders/circle.fragment.glsl.g.ts +1 -1
  50. package/src/shaders/circle.vertex.glsl +6 -2
  51. package/src/shaders/circle.vertex.glsl.g.ts +1 -1
  52. package/src/shaders/collision_box.vertex.glsl +1 -1
  53. package/src/shaders/collision_box.vertex.glsl.g.ts +1 -1
  54. package/src/shaders/debug.vertex.glsl +1 -1
  55. package/src/shaders/debug.vertex.glsl.g.ts +1 -1
  56. package/src/shaders/fill_extrusion.vertex.glsl +16 -2
  57. package/src/shaders/fill_extrusion.vertex.glsl.g.ts +1 -1
  58. package/src/shaders/fill_extrusion_pattern.vertex.glsl +15 -2
  59. package/src/shaders/fill_extrusion_pattern.vertex.glsl.g.ts +1 -1
  60. package/src/shaders/line.vertex.glsl +7 -3
  61. package/src/shaders/line.vertex.glsl.g.ts +1 -1
  62. package/src/shaders/line_gradient.vertex.glsl +7 -3
  63. package/src/shaders/line_gradient.vertex.glsl.g.ts +1 -1
  64. package/src/shaders/line_pattern.vertex.glsl +7 -3
  65. package/src/shaders/line_pattern.vertex.glsl.g.ts +1 -1
  66. package/src/shaders/line_sdf.vertex.glsl +7 -4
  67. package/src/shaders/line_sdf.vertex.glsl.g.ts +1 -1
  68. package/src/shaders/shaders.ts +11 -1
  69. package/src/shaders/symbol_icon.vertex.glsl +8 -8
  70. package/src/shaders/symbol_icon.vertex.glsl.g.ts +1 -1
  71. package/src/shaders/symbol_sdf.vertex.glsl +8 -5
  72. package/src/shaders/symbol_sdf.vertex.glsl.g.ts +1 -1
  73. package/src/shaders/symbol_text_and_icon.vertex.glsl +8 -5
  74. package/src/shaders/symbol_text_and_icon.vertex.glsl.g.ts +1 -1
  75. package/src/shaders/terrain.fragment.glsl +7 -0
  76. package/src/shaders/terrain.fragment.glsl.g.ts +2 -0
  77. package/src/shaders/terrain.vertex.glsl +12 -0
  78. package/src/shaders/terrain.vertex.glsl.g.ts +2 -0
  79. package/src/shaders/terrain_coords.fragment.glsl +11 -0
  80. package/src/shaders/terrain_coords.fragment.glsl.g.ts +2 -0
  81. package/src/shaders/terrain_depth.fragment.glsl +15 -0
  82. package/src/shaders/terrain_depth.fragment.glsl.g.ts +2 -0
  83. package/src/source/canvas_source.test.ts +1 -1
  84. package/src/source/geojson_source.test.ts +25 -0
  85. package/src/source/geojson_source.ts +1 -8
  86. package/src/source/geojson_worker_source.test.ts +19 -23
  87. package/src/source/geojson_worker_source.ts +19 -70
  88. package/src/source/raster_dem_tile_source.ts +4 -3
  89. package/src/source/raster_dem_tile_worker_source.ts +0 -1
  90. package/src/source/source_cache.test.ts +83 -0
  91. package/src/source/source_cache.ts +72 -11
  92. package/src/source/terrain_source_cache.test.ts +89 -0
  93. package/src/source/terrain_source_cache.ts +201 -0
  94. package/src/source/tile.ts +15 -0
  95. package/src/source/tile_id.ts +9 -0
  96. package/src/style/pauseable_placement.ts +3 -1
  97. package/src/style/style.test.ts +16 -0
  98. package/src/style/style.ts +57 -3
  99. package/src/style/validate_style.ts +2 -0
  100. package/src/style-spec/CHANGELOG.md +6 -0
  101. package/src/style-spec/error/validation_error.ts +1 -1
  102. package/src/style-spec/package.json +2 -2
  103. package/src/style-spec/reference/v8.json +42 -0
  104. package/src/style-spec/types.g.ts +7 -0
  105. package/src/style-spec/validate/validate.ts +2 -0
  106. package/src/style-spec/validate/validate_terrain.test.ts +46 -0
  107. package/src/style-spec/validate/validate_terrain.ts +41 -0
  108. package/src/style-spec/validate_style.min.ts +2 -0
  109. package/src/style-spec/validate_style.ts +1 -0
  110. package/src/symbol/collision_index.ts +28 -12
  111. package/src/symbol/placement.ts +24 -9
  112. package/src/symbol/projection.ts +42 -27
  113. package/src/ui/camera.ts +2 -0
  114. package/src/ui/control/terrain_control.ts +77 -0
  115. package/src/ui/default_locale.ts +3 -2
  116. package/src/ui/events.ts +18 -3
  117. package/src/ui/handler_manager.ts +33 -3
  118. package/src/ui/map.ts +36 -6
  119. package/src/ui/marker.test.ts +21 -0
  120. package/src/ui/marker.ts +14 -0
  121. package/src/util/primitives.ts +14 -11
@@ -58,6 +58,7 @@ function drawExtrusionTiles(painter, source, layer, coords, depthMode, stencilMo
58
58
  const bucket: FillExtrusionBucket = (tile.getBucket(layer) as any);
59
59
  if (!bucket) continue;
60
60
 
61
+ const terrainData = painter.style.terrain && painter.style.terrain.getTerrainData(coord);
61
62
  const programConfiguration = bucket.programConfigurations.get(layer.id);
62
63
  const program = painter.useProgram(image ? 'fillExtrusionPattern' : 'fillExtrusion', programConfiguration);
63
64
 
@@ -86,8 +87,8 @@ function drawExtrusionTiles(painter, source, layer, coords, depthMode, stencilMo
86
87
  fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity);
87
88
 
88
89
  program.draw(context, context.gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.backCCW,
89
- uniformValues, layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer,
90
+ uniformValues, terrainData, layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer,
90
91
  bucket.segments, layer.paint, painter.transform.zoom,
91
- programConfiguration);
92
+ programConfiguration, painter.style.terrain && bucket.centroidVertexBuffer);
92
93
  }
93
94
  }
@@ -53,8 +53,7 @@ function drawHeatmap(painter: Painter, sourceCache: SourceCache, layer: HeatmapS
53
53
  const {zoom} = painter.transform;
54
54
 
55
55
  program.draw(context, gl.TRIANGLES, DepthMode.disabled, stencilMode, colorMode, CullFaceMode.disabled,
56
- heatmapUniformValues(coord.posMatrix,
57
- tile, zoom, layer.paint.get('heatmap-intensity')),
56
+ heatmapUniformValues(coord.posMatrix, tile, zoom, layer.paint.get('heatmap-intensity')), null,
58
57
  layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer,
59
58
  bucket.segments, layer.paint, painter.transform.zoom,
60
59
  programConfiguration);
@@ -125,7 +124,7 @@ function renderTextureToMap(painter, layer) {
125
124
 
126
125
  painter.useProgram('heatmapTexture').draw(context, gl.TRIANGLES,
127
126
  DepthMode.disabled, StencilMode.disabled, painter.colorModeForRenderPass(), CullFaceMode.disabled,
128
- heatmapTextureUniformValues(painter, layer, 0, 1),
127
+ heatmapTextureUniformValues(painter, layer, 0, 1), null,
129
128
  layer.id, painter.viewportBuffer, painter.quadTriangleIndexBuffer,
130
129
  painter.viewportSegments, layer.paint, painter.transform.zoom);
131
130
  }
@@ -27,32 +27,33 @@ function drawHillshade(painter: Painter, sourceCache: SourceCache, layer: Hillsh
27
27
 
28
28
  for (const coord of coords) {
29
29
  const tile = sourceCache.getTile(coord);
30
- if (tile.needsHillshadePrepare && painter.renderPass === 'offscreen') {
30
+ if (typeof tile.needsHillshadePrepare !== 'undefined' && tile.needsHillshadePrepare && painter.renderPass === 'offscreen') {
31
31
  prepareHillshade(painter, tile, layer, depthMode, StencilMode.disabled, colorMode);
32
32
  } else if (painter.renderPass === 'translucent') {
33
- renderHillshade(painter, tile, layer, depthMode, stencilModes[coord.overscaledZ], colorMode);
33
+ renderHillshade(painter, coord, tile, layer, depthMode, stencilModes[coord.overscaledZ], colorMode);
34
34
  }
35
35
  }
36
36
 
37
37
  context.viewport.set([0, 0, painter.width, painter.height]);
38
38
  }
39
39
 
40
- function renderHillshade(painter, tile, layer, depthMode, stencilMode, colorMode) {
40
+ function renderHillshade(painter, coord, tile, layer, depthMode, stencilMode, colorMode) {
41
41
  const context = painter.context;
42
42
  const gl = context.gl;
43
43
  const fbo = tile.fbo;
44
44
  if (!fbo) return;
45
45
 
46
46
  const program = painter.useProgram('hillshade');
47
+ const terrainData = painter.style.terrain && painter.style.terrain.getTerrainData(coord);
47
48
 
48
49
  context.activeTexture.set(gl.TEXTURE0);
49
50
  gl.bindTexture(gl.TEXTURE_2D, fbo.colorAttachment.get());
50
51
 
51
- const uniformValues = hillshadeUniformValues(painter, tile, layer);
52
-
52
+ const terrainCoord = terrainData ? coord : null;
53
53
  program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.disabled,
54
- uniformValues, layer.id, painter.rasterBoundsBuffer,
54
+ hillshadeUniformValues(painter, tile, layer, terrainCoord), terrainData, layer.id, painter.rasterBoundsBuffer,
55
55
  painter.quadTriangleIndexBuffer, painter.rasterBoundsSegments);
56
+
56
57
  }
57
58
 
58
59
  // hillshade rendering is done in two steps. the prepare step first calculates the slope of the terrain in the x and y
@@ -97,7 +98,7 @@ function prepareHillshade(painter, tile, layer, depthMode, stencilMode, colorMod
97
98
  painter.useProgram('hillshadePrepare').draw(context, gl.TRIANGLES,
98
99
  depthMode, stencilMode, colorMode, CullFaceMode.disabled,
99
100
  hillshadeUniformPrepareValues(tile.tileID, dem),
100
- layer.id, painter.rasterBoundsBuffer,
101
+ null, layer.id, painter.rasterBoundsBuffer,
101
102
  painter.quadTriangleIndexBuffer, painter.rasterBoundsSegments);
102
103
 
103
104
  tile.needsHillshadePrepare = false;
@@ -56,6 +56,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
56
56
  const prevProgram = painter.context.program.get();
57
57
  const program = painter.useProgram(programId, programConfiguration);
58
58
  const programChanged = firstTile || program.program !== prevProgram;
59
+ const terrainData = painter.style.terrain && painter.style.terrain.getTerrainData(coord);
59
60
 
60
61
  const constantPattern = patternProperty.constantOr(null);
61
62
  if (constantPattern && tile.imageAtlas) {
@@ -65,10 +66,11 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
65
66
  if (posTo && posFrom) programConfiguration.setConstantPatternPositions(posTo, posFrom);
66
67
  }
67
68
 
68
- const uniformValues = image ? linePatternUniformValues(painter, tile, layer, crossfade) :
69
- dasharray ? lineSDFUniformValues(painter, tile, layer, dasharray, crossfade) :
70
- gradient ? lineGradientUniformValues(painter, tile, layer, bucket.lineClipsArray.length) :
71
- lineUniformValues(painter, tile, layer);
69
+ const terrainCoord = terrainData ? coord : null;
70
+ const uniformValues = image ? linePatternUniformValues(painter, tile, layer, crossfade, terrainCoord) :
71
+ dasharray ? lineSDFUniformValues(painter, tile, layer, dasharray, crossfade, terrainCoord) :
72
+ gradient ? lineGradientUniformValues(painter, tile, layer, bucket.lineClipsArray.length, terrainCoord) :
73
+ lineUniformValues(painter, tile, layer, terrainCoord);
72
74
 
73
75
  if (image) {
74
76
  context.activeTexture.set(gl.TEXTURE0);
@@ -113,7 +115,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
113
115
  }
114
116
 
115
117
  program.draw(context, gl.TRIANGLES, depthMode,
116
- painter.stencilModeForClipping(coord), colorMode, CullFaceMode.disabled, uniformValues,
118
+ painter.stencilModeForClipping(coord), colorMode, CullFaceMode.disabled, uniformValues, terrainData,
117
119
  layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments,
118
120
  layer.paint, painter.transform.zoom, programConfiguration, bucket.layoutVertexBuffer2);
119
121
 
@@ -39,12 +39,11 @@ function drawRaster(painter: Painter, sourceCache: SourceCache, layer: RasterSty
39
39
  layer.paint.get('raster-opacity') === 1 ? DepthMode.ReadWrite : DepthMode.ReadOnly, gl.LESS);
40
40
 
41
41
  const tile = sourceCache.getTile(coord);
42
- const posMatrix = painter.transform.calculatePosMatrix(coord.toUnwrapped(), align);
43
42
 
44
43
  tile.registerFadeDuration(layer.paint.get('raster-fade-duration'));
45
44
 
46
45
  const parentTile = sourceCache.findLoadedParent(coord, 0),
47
- fade = getFadeValues(tile, parentTile, sourceCache, layer, painter.transform);
46
+ fade = getFadeValues(tile, parentTile, sourceCache, layer, painter.transform, painter.style.terrain);
48
47
 
49
48
  let parentScaleBy, parentTL;
50
49
 
@@ -64,24 +63,27 @@ function drawRaster(painter: Painter, sourceCache: SourceCache, layer: RasterSty
64
63
  tile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST);
65
64
  }
66
65
 
66
+ const terrainData = painter.style.terrain && painter.style.terrain.getTerrainData(coord);
67
+ const terrainCoord = terrainData ? coord : null;
68
+ const posMatrix = terrainCoord ? terrainCoord.posMatrix : painter.transform.calculatePosMatrix(coord.toUnwrapped(), align);
67
69
  const uniformValues = rasterUniformValues(posMatrix, parentTL || [0, 0], parentScaleBy || 1, fade, layer);
68
70
 
69
71
  if (source instanceof ImageSource) {
70
72
  program.draw(context, gl.TRIANGLES, depthMode, StencilMode.disabled, colorMode, CullFaceMode.disabled,
71
- uniformValues, layer.id, source.boundsBuffer,
73
+ uniformValues, terrainData, layer.id, source.boundsBuffer,
72
74
  painter.quadTriangleIndexBuffer, source.boundsSegments);
73
75
  } else {
74
76
  program.draw(context, gl.TRIANGLES, depthMode, stencilModes[coord.overscaledZ], colorMode, CullFaceMode.disabled,
75
- uniformValues, layer.id, painter.rasterBoundsBuffer,
77
+ uniformValues, terrainData, layer.id, painter.rasterBoundsBuffer,
76
78
  painter.quadTriangleIndexBuffer, painter.rasterBoundsSegments);
77
79
  }
78
80
  }
79
81
  }
80
82
 
81
- function getFadeValues(tile, parentTile, sourceCache, layer, transform) {
83
+ function getFadeValues(tile, parentTile, sourceCache, layer, transform, terrain) {
82
84
  const fadeDuration = layer.paint.get('raster-fade-duration');
83
85
 
84
- if (fadeDuration > 0) {
86
+ if (!terrain && fadeDuration > 0) {
85
87
  const now = browser.now();
86
88
  const sinceTile = (now - tile.timeAdded) / fadeDuration;
87
89
  const sinceParent = parentTile ? (now - parentTile.timeAdded) / fadeDuration : -1;
@@ -10,9 +10,13 @@ import drawSymbol from './draw_symbol';
10
10
  import * as symbolProjection from '../symbol/projection';
11
11
  import type ZoomHistory from '../style/zoom_history';
12
12
  import type Map from '../ui/map';
13
- import type Transform from '../geo/transform';
13
+ import Transform from '../geo/transform';
14
14
  import type EvaluationParameters from '../style/evaluation_parameters';
15
15
  import type {SymbolLayerSpecification} from '../style-spec/types.g';
16
+ import Style from '../style/style';
17
+ import TerrainSourceCache from '../source/terrain_source_cache';
18
+ import {Evented} from '../util/evented';
19
+ import {RequestManager} from '../util/request_manager';
16
20
 
17
21
  jest.mock('./painter');
18
22
  jest.mock('./program');
@@ -21,6 +25,22 @@ jest.mock('../source/tile');
21
25
  jest.mock('../data/bucket/symbol_bucket');
22
26
  jest.mock('../symbol/projection');
23
27
 
28
+ class StubMap extends Evented {
29
+ transform: Transform;
30
+ painter: Painter;
31
+ _requestManager: RequestManager;
32
+
33
+ constructor() {
34
+ super();
35
+ this.transform = new Transform();
36
+ this._requestManager = {
37
+ transformRequest: (url) => {
38
+ return {url};
39
+ }
40
+ } as any as RequestManager;
41
+ }
42
+ }
43
+
24
44
  describe('drawSymbol', () => {
25
45
  test('should not do anything', () => {
26
46
  const mockPainter = new Painter(null, null);
@@ -37,12 +57,13 @@ describe('drawSymbol', () => {
37
57
  painterMock.context = {
38
58
  gl: {},
39
59
  activeTexture: {
40
- set: () => {}
60
+ set: () => { }
41
61
  }
42
62
  } as any;
43
63
  painterMock.renderPass = 'translucent';
44
64
  painterMock.transform = {pitch: 0, labelPlaneMatrix: mat4.create()} as any as Transform;
45
65
  painterMock.options = {} as any;
66
+ painterMock.style = {terrainSourceCache: {getTerrain: () => null}} as any as Style;
46
67
 
47
68
  const layerSpec = {
48
69
  id: 'mock-layer',
@@ -58,12 +79,12 @@ describe('drawSymbol', () => {
58
79
 
59
80
  const tileId = new OverscaledTileID(1, 0, 1, 0, 0);
60
81
  tileId.posMatrix = mat4.create();
61
- const programMock = new Program(null, null, null, null, null, null);
82
+ const programMock = new Program(null, null, null, null, null, null, null);
62
83
  (painterMock.useProgram as jest.Mock).mockReturnValue(programMock);
63
84
  const bucketMock = new SymbolBucket(null);
64
85
  bucketMock.icon = {
65
86
  programConfigurations: {
66
- get: () => {}
87
+ get: () => { }
67
88
  },
68
89
  segments: {
69
90
  get: () => [1]
@@ -76,7 +97,7 @@ describe('drawSymbol', () => {
76
97
  const tile = new Tile(tileId, 256);
77
98
  tile.tileID = tileId;
78
99
  tile.imageAtlasTexture = {
79
- bind: () => {}
100
+ bind: () => { }
80
101
  } as any;
81
102
  (tile.getBucket as jest.Mock).mockReturnValue(bucketMock);
82
103
  const sourceCacheMock = new SourceCache(null, null, null);
@@ -94,7 +115,7 @@ describe('drawSymbol', () => {
94
115
  painterMock.context = {
95
116
  gl: {},
96
117
  activeTexture: {
97
- set: () => {}
118
+ set: () => { }
98
119
  }
99
120
  } as any;
100
121
  painterMock.renderPass = 'translucent';
@@ -119,12 +140,12 @@ describe('drawSymbol', () => {
119
140
 
120
141
  const tileId = new OverscaledTileID(1, 0, 1, 0, 0);
121
142
  tileId.posMatrix = mat4.create();
122
- const programMock = new Program(null, null, null, null, null, null);
143
+ const programMock = new Program(null, null, null, null, null, null, null);
123
144
  (painterMock.useProgram as jest.Mock).mockReturnValue(programMock);
124
145
  const bucketMock = new SymbolBucket(null);
125
146
  bucketMock.icon = {
126
147
  programConfigurations: {
127
- get: () => {}
148
+ get: () => { }
128
149
  },
129
150
  segments: {
130
151
  get: () => [1]
@@ -137,16 +158,19 @@ describe('drawSymbol', () => {
137
158
  const tile = new Tile(tileId, 256);
138
159
  tile.tileID = tileId;
139
160
  tile.imageAtlasTexture = {
140
- bind: () => {}
161
+ bind: () => { }
141
162
  } as any;
142
163
  (tile.getBucket as jest.Mock).mockReturnValue(bucketMock);
143
164
  const sourceCacheMock = new SourceCache(null, null, null);
144
165
  (sourceCacheMock.getTile as jest.Mock).mockReturnValue(tile);
145
166
  sourceCacheMock.map = {showCollisionBoxes: false} as any as Map;
167
+ painterMock.style = {
168
+ terrainSourceCache: new TerrainSourceCache(new Style(new StubMap() as any as Map))
169
+ } as any as Style;
146
170
 
147
171
  const spy = jest.spyOn(symbolProjection, 'updateLineLabels');
148
172
  drawSymbol(painterMock, sourceCacheMock, layer, [tileId], null);
149
173
 
150
- expect(spy.mock.calls[0][8]).toBeFalsy(); // rotateToLine === false
174
+ expect(spy.mock.calls[0][9]).toBeFalsy(); // rotateToLine === false
151
175
  });
152
176
  });
@@ -9,7 +9,7 @@ import {mat4} from 'gl-matrix';
9
9
  import StencilMode from '../gl/stencil_mode';
10
10
  import DepthMode from '../gl/depth_mode';
11
11
  import CullFaceMode from '../gl/cull_face_mode';
12
- import SymbolBucket, {addDynamicAttributes, SymbolBuffers} from '../data/bucket/symbol_bucket';
12
+ import {addDynamicAttributes} from '../data/bucket/symbol_bucket';
13
13
 
14
14
  import {getAnchorAlignment, WritingMode} from '../symbol/shaping';
15
15
  import ONE_EM from '../symbol/one_em';
@@ -31,6 +31,9 @@ import type {OverscaledTileID} from '../source/tile_id';
31
31
  import type {UniformValues} from './uniform_binding';
32
32
  import type {SymbolSDFUniformsType} from '../render/program/symbol_program';
33
33
  import type {CrossTileID, VariableOffset} from '../symbol/placement';
34
+ import type SymbolBucket from '../data/bucket/symbol_bucket';
35
+ import type {SymbolBuffers} from '../data/bucket/symbol_bucket';
36
+ import type {TerrainData} from '../render/terrain';
34
37
  import type {SymbolLayerSpecification} from '../style-spec/types.g';
35
38
  import type Transform from '../geo/transform';
36
39
  import type ColorMode from '../gl/color_mode';
@@ -39,6 +42,7 @@ import type Program from './program';
39
42
  type SymbolTileRenderState = {
40
43
  segments: SegmentVector;
41
44
  sortKey: number;
45
+ terrainData: TerrainData;
42
46
  state: {
43
47
  program: Program<any>;
44
48
  buffers: SymbolBuffers;
@@ -145,8 +149,9 @@ function updateVariableAnchors(coords: Array<OverscaledTileID>,
145
149
 
146
150
  if (size) {
147
151
  const tileScale = Math.pow(2, tr.zoom - tile.tileID.overscaledZ);
152
+ const getElevation = painter.style.terrain ? (x: number, y: number) => painter.style.terrain.getElevation(coord, x, y) : null;
148
153
  updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets,
149
- tr, labelPlaneMatrix, coord.posMatrix, tileScale, size, updateTextFitIcon);
154
+ tr, labelPlaneMatrix, coord.posMatrix, tileScale, size, updateTextFitIcon, getElevation);
150
155
  }
151
156
  }
152
157
  }
@@ -161,7 +166,8 @@ function updateVariableAnchorsForBucket(
161
166
  posMatrix: mat4,
162
167
  tileScale: number,
163
168
  size: EvaluatedZoomSize,
164
- updateTextFitIcon: boolean) {
169
+ updateTextFitIcon: boolean,
170
+ getElevation: (x: number, y: number) => number) {
165
171
  const placedSymbols = bucket.text.placedSymbolArray;
166
172
  const dynamicTextLayoutVertexArray = bucket.text.dynamicLayoutVertexArray;
167
173
  const dynamicIconLayoutVertexArray = bucket.icon.dynamicLayoutVertexArray;
@@ -179,7 +185,7 @@ function updateVariableAnchorsForBucket(
179
185
  symbolProjection.hideGlyphs(symbol.numGlyphs, dynamicTextLayoutVertexArray);
180
186
  } else {
181
187
  const tileAnchor = new Point(symbol.anchorX, symbol.anchorY);
182
- const projectedAnchor = symbolProjection.project(tileAnchor, pitchWithMap ? posMatrix : labelPlaneMatrix);
188
+ const projectedAnchor = symbolProjection.project(tileAnchor, pitchWithMap ? posMatrix : labelPlaneMatrix, getElevation);
183
189
  const perspectiveRatio = symbolProjection.getPerspectiveRatio(transform.cameraToCenterDistance, projectedAnchor.signedDistanceFromCamera);
184
190
  let renderTextSize = evaluateSizeForFeature(bucket.textSizeData, size, symbol) * perspectiveRatio / ONE_EM;
185
191
  if (pitchWithMap) {
@@ -196,7 +202,7 @@ function updateVariableAnchorsForBucket(
196
202
  // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent
197
203
  // tile-unit based shift to the anchor before projecting to the label plane.
198
204
  const shiftedAnchor = pitchWithMap ?
199
- symbolProjection.project(tileAnchor.add(shift), labelPlaneMatrix).point :
205
+ symbolProjection.project(tileAnchor.add(shift), labelPlaneMatrix, getElevation).point :
200
206
  projectedAnchor.point.add(rotateWithMap ?
201
207
  shift.rotate(-transform.angle) :
202
208
  shift);
@@ -295,6 +301,7 @@ function drawLayerSymbols(
295
301
 
296
302
  const program = painter.useProgram(getSymbolProgramName(isSDF, isText, bucket), programConfiguration);
297
303
  const size = evaluateSizeForZoom(sizeData, tr.zoom);
304
+ const terrainData = painter.style.terrain && painter.style.terrain.getTerrainData(coord);
298
305
 
299
306
  let texSize: [number, number];
300
307
  let texSizeIcon: [number, number] = [0, 0];
@@ -331,8 +338,9 @@ function drawLayerSymbols(
331
338
  bucket.hasIconData();
332
339
 
333
340
  if (alongLine) {
341
+ const getElevation = painter.style.terrain ? (x: number, y: number) => painter.style.terrain.getElevation(coord, x, y) : null;
334
342
  const rotateToLine = layer.layout.get('text-rotation-alignment') === 'map';
335
- symbolProjection.updateLineLabels(bucket, coord.posMatrix, painter, isText, labelPlaneMatrix, glCoordMatrix, pitchWithMap, keepUpright, rotateToLine);
343
+ symbolProjection.updateLineLabels(bucket, coord.posMatrix, painter, isText, labelPlaneMatrix, glCoordMatrix, pitchWithMap, keepUpright, rotateToLine, getElevation);
336
344
  }
337
345
 
338
346
  const matrix = painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor),
@@ -377,14 +385,16 @@ function drawLayerSymbols(
377
385
  tileRenderState.push({
378
386
  segments: new SegmentVector([segment]),
379
387
  sortKey: segment.sortKey,
380
- state
388
+ state,
389
+ terrainData
381
390
  });
382
391
  }
383
392
  } else {
384
393
  tileRenderState.push({
385
394
  segments: buffers.segments,
386
395
  sortKey: 0,
387
- state
396
+ state,
397
+ terrainData
388
398
  });
389
399
  }
390
400
  }
@@ -409,11 +419,11 @@ function drawLayerSymbols(
409
419
  const uniformValues = state.uniformValues;
410
420
  if (state.hasHalo) {
411
421
  uniformValues['u_is_halo'] = 1;
412
- drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, uniformValues);
422
+ drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, uniformValues, segmentState.terrainData);
413
423
  }
414
424
  uniformValues['u_is_halo'] = 0;
415
425
  }
416
- drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, state.uniformValues);
426
+ drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, state.uniformValues, segmentState.terrainData);
417
427
  }
418
428
  }
419
429
 
@@ -426,11 +436,12 @@ function drawSymbolElements(
426
436
  depthMode: Readonly<DepthMode>,
427
437
  stencilMode: StencilMode,
428
438
  colorMode: Readonly<ColorMode>,
429
- uniformValues: UniformValues<SymbolSDFUniformsType | SymbolIconUniformsType>) {
439
+ uniformValues: UniformValues<SymbolSDFUniformsType | SymbolIconUniformsType>,
440
+ terrainData: TerrainData) {
430
441
  const context = painter.context;
431
442
  const gl = context.gl;
432
443
  program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.disabled,
433
- uniformValues, layer.id, buffers.layoutVertexBuffer,
444
+ uniformValues, terrainData, layer.id, buffers.layoutVertexBuffer,
434
445
  buffers.indexBuffer, segments, layer.paint,
435
446
  painter.transform.zoom, buffers.programConfigurations.get(layer.id),
436
447
  buffers.dynamicLayoutVertexBuffer, buffers.opacityVertexBuffer);
@@ -0,0 +1,123 @@
1
+ import StencilMode from '../gl/stencil_mode';
2
+ import DepthMode from '../gl/depth_mode';
3
+ import {terrainUniformValues, terrainDepthUniformValues, terrainCoordsUniformValues} from './program/terrain_program';
4
+ import type Painter from './painter';
5
+ import type Tile from '../source/tile';
6
+ import CullFaceMode from '../gl/cull_face_mode';
7
+ import Texture from './texture';
8
+ import Color from '../style-spec/util/color';
9
+ import ColorMode from '../gl/color_mode';
10
+ import Terrain from './terrain';
11
+
12
+ /**
13
+ * Redraw the Depth Framebuffer
14
+ * @param {Painter} painter - the painter
15
+ * @param {Terrain} terrain - the terrain
16
+ */
17
+ function drawDepth(painter: Painter, terrain: Terrain) {
18
+ const context = painter.context;
19
+ const gl = context.gl;
20
+ const colorMode = ColorMode.unblended;
21
+ const depthMode = new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, [0, 1]);
22
+ const mesh = terrain.getTerrainMesh();
23
+ const tiles = terrain.sourceCache.getRenderableTiles();
24
+ const program = painter.useProgram('terrainDepth');
25
+ context.bindFramebuffer.set(terrain.getFramebuffer('depth').framebuffer);
26
+ context.viewport.set([0, 0, painter.width / devicePixelRatio, painter.height / devicePixelRatio]);
27
+ context.clear({color: Color.transparent, depth: 1});
28
+ for (const tile of tiles) {
29
+ const terrainData = terrain.getTerrainData(tile.tileID);
30
+ const posMatrix = painter.transform.calculatePosMatrix(tile.tileID.toUnwrapped());
31
+ const uniformValues = terrainDepthUniformValues(posMatrix);
32
+ program.draw(context, gl.TRIANGLES, depthMode, StencilMode.disabled, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, 'terrain', mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
33
+ }
34
+ context.bindFramebuffer.set(null);
35
+ context.viewport.set([0, 0, painter.width, painter.height]);
36
+ }
37
+
38
+ /**
39
+ * Redraw the Coords Framebuffers
40
+ * @param {Painter} painter - the painter
41
+ * @param {Terrain} terrain - the terrain
42
+ */
43
+ function drawCoords(painter: Painter, terrain: Terrain) {
44
+ const context = painter.context;
45
+ const gl = context.gl;
46
+ const colorMode = ColorMode.unblended;
47
+ const depthMode = new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, [0, 1]);
48
+ const mesh = terrain.getTerrainMesh();
49
+ const coords = terrain.getCoordsTexture();
50
+ const tiles = terrain.sourceCache.getRenderableTiles();
51
+
52
+ // draw tile-coords into framebuffer
53
+ const program = painter.useProgram('terrainCoords');
54
+ context.bindFramebuffer.set(terrain.getFramebuffer('coords').framebuffer);
55
+ context.viewport.set([0, 0, painter.width / devicePixelRatio, painter.height / devicePixelRatio]);
56
+ context.clear({color: Color.transparent, depth: 1});
57
+ terrain.coordsIndex = [];
58
+ for (const tile of tiles) {
59
+ const terrainData = terrain.getTerrainData(tile.tileID);
60
+ context.activeTexture.set(gl.TEXTURE0);
61
+ gl.bindTexture(gl.TEXTURE_2D, coords.texture);
62
+ const posMatrix = painter.transform.calculatePosMatrix(tile.tileID.toUnwrapped());
63
+ const uniformValues = terrainCoordsUniformValues(posMatrix, 255 - terrain.coordsIndex.length);
64
+ program.draw(context, gl.TRIANGLES, depthMode, StencilMode.disabled, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, 'terrain', mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
65
+ terrain.coordsIndex.push(tile.tileID.key);
66
+ }
67
+
68
+ context.bindFramebuffer.set(null);
69
+ context.viewport.set([0, 0, painter.width, painter.height]);
70
+ }
71
+
72
+ /**
73
+ * Render, e.g. drape, a render-to-texture tile onto the 3d mesh on screen.
74
+ * @param {Painter} painter - the painter
75
+ * @param {Terrain} terrain - the source cache
76
+ * @param {Tile} tile - the tile
77
+ */
78
+ function drawTerrain(painter: Painter, terrain: Terrain, tile: Tile) {
79
+ const context = painter.context;
80
+ const gl = context.gl;
81
+ const colorMode = painter.colorModeForRenderPass();
82
+ const depthMode = new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, painter.depthRangeFor3D);
83
+ const program = painter.useProgram('terrain');
84
+ const mesh = terrain.getTerrainMesh();
85
+ const terrainData = terrain.getTerrainData(tile.tileID);
86
+
87
+ context.bindFramebuffer.set(null);
88
+ context.viewport.set([0, 0, painter.width, painter.height]);
89
+ context.activeTexture.set(gl.TEXTURE0);
90
+ gl.bindTexture(gl.TEXTURE_2D, terrain.getRTTFramebuffer().colorAttachment.get());
91
+ const posMatrix = painter.transform.calculatePosMatrix(tile.tileID.toUnwrapped());
92
+ const uniformValues = terrainUniformValues(posMatrix);
93
+ program.draw(context, gl.TRIANGLES, depthMode, StencilMode.disabled, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, 'terrain', mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
94
+ }
95
+
96
+ /**
97
+ * prepare the render-to-texture tile.
98
+ * E.g. creates the necessary textures and attach them to the render-to-texture-framebuffer.
99
+ * @param {Painter} painter - the painter
100
+ * @param {Terrain} terrain - the terrain
101
+ * @param {Tile} tile - the tile
102
+ * @param {number} stack number of a layer-groop. see painter.ts
103
+ */
104
+ function prepareTerrain(painter: Painter, terrain: Terrain, tile: Tile, stack: number) {
105
+ const context = painter.context;
106
+ const size = tile.tileSize * terrain.qualityFactor;
107
+ if (!tile.textures[stack]) {
108
+ tile.textures[stack] = painter.getTileTexture(size) || new Texture(context, {width: size, height: size, data: null}, context.gl.RGBA);
109
+ tile.textures[stack].bind(context.gl.LINEAR, context.gl.CLAMP_TO_EDGE);
110
+ if (stack === 0) terrain.sourceCache.renderHistory.push(tile.tileID.key);
111
+ }
112
+ const fb = terrain.getRTTFramebuffer();
113
+ fb.colorAttachment.set(tile.textures[stack].texture);
114
+ context.bindFramebuffer.set(fb.framebuffer);
115
+ context.viewport.set([0, 0, size, size]);
116
+ }
117
+
118
+ export {
119
+ prepareTerrain,
120
+ drawTerrain,
121
+ drawDepth,
122
+ drawCoords
123
+ };