UNPKG

maplibre-gl

Version:

BSD licensed community fork of mapbox-gl, a WebGL interactive maps library

105 lines (89 loc) 5.14 kB
import {DepthMode} from '../gl/depth_mode'; import {StencilMode} from '../gl/stencil_mode'; import {ColorMode} from '../gl/color_mode'; import {CullFaceMode} from '../gl/cull_face_mode'; import { fillExtrusionUniformValues, fillExtrusionPatternUniformValues, } from './program/fill_extrusion_program'; import type {Painter, RenderOptions} from './painter'; import type {SourceCache} from '../source/source_cache'; import type {FillExtrusionStyleLayer} from '../style/style_layer/fill_extrusion_style_layer'; import type {FillExtrusionBucket} from '../data/bucket/fill_extrusion_bucket'; import type {OverscaledTileID} from '../source/tile_id'; import {updatePatternPositionsInProgram} from './update_pattern_positions_in_program'; import {translatePosition} from '../util/util'; export function drawFillExtrusion(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLayer, coords: Array<OverscaledTileID>, renderOptions: RenderOptions) { const opacity = layer.paint.get('fill-extrusion-opacity'); if (opacity === 0) { return; } const {isRenderingToTexture} = renderOptions; if (painter.renderPass === 'translucent') { const depthMode = new DepthMode(painter.context.gl.LEQUAL, DepthMode.ReadWrite, painter.depthRangeFor3D); if (opacity === 1 && !layer.paint.get('fill-extrusion-pattern').constantOr(1 as any)) { const colorMode = painter.colorModeForRenderPass(); drawExtrusionTiles(painter, source, layer, coords, depthMode, StencilMode.disabled, colorMode, isRenderingToTexture); } else { // Draw transparent buildings in two passes so that only the closest surface is drawn. // First draw all the extrusions into only the depth buffer. No colors are drawn. drawExtrusionTiles(painter, source, layer, coords, depthMode, StencilMode.disabled, ColorMode.disabled, isRenderingToTexture); // Then draw all the extrusions a second type, only coloring fragments if they have the // same depth value as the closest fragment in the previous pass. Use the stencil buffer // to prevent the second draw in cases where we have coincident polygons. drawExtrusionTiles(painter, source, layer, coords, depthMode, painter.stencilModeFor3D(), painter.colorModeForRenderPass(), isRenderingToTexture); } } } function drawExtrusionTiles( painter: Painter, source: SourceCache, layer: FillExtrusionStyleLayer, coords: OverscaledTileID[], depthMode: DepthMode, stencilMode: Readonly<StencilMode>, colorMode: Readonly<ColorMode>, isRenderingToTexture: boolean) { const context = painter.context; const gl = context.gl; const fillPropertyName = 'fill-extrusion-pattern'; const patternProperty = layer.paint.get(fillPropertyName); const image = patternProperty.constantOr(1 as any); const crossfade = layer.getCrossfadeParameters(); const opacity = layer.paint.get('fill-extrusion-opacity'); const constantPattern = patternProperty.constantOr(null); const transform = painter.transform; for (const coord of coords) { const tile = source.getTile(coord); const bucket: FillExtrusionBucket = (tile.getBucket(layer) as any); if (!bucket) continue; const terrainData = painter.style.map.terrain && painter.style.map.terrain.getTerrainData(coord); const programConfiguration = bucket.programConfigurations.get(layer.id); const program = painter.useProgram(image ? 'fillExtrusionPattern' : 'fillExtrusion', programConfiguration); if (image) { painter.context.activeTexture.set(gl.TEXTURE0); tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE); programConfiguration.updatePaintBuffers(crossfade); } const projectionData = transform.getProjectionData({overscaledTileID: coord, applyGlobeMatrix: !isRenderingToTexture, applyTerrainMatrix: true}); updatePatternPositionsInProgram(programConfiguration, fillPropertyName, constantPattern, tile, layer); const translate = translatePosition( transform, tile, layer.paint.get('fill-extrusion-translate'), layer.paint.get('fill-extrusion-translate-anchor') ); const shouldUseVerticalGradient = layer.paint.get('fill-extrusion-vertical-gradient'); const uniformValues = image ? fillExtrusionPatternUniformValues(painter, shouldUseVerticalGradient, opacity, translate, coord, crossfade, tile) : fillExtrusionUniformValues(painter, shouldUseVerticalGradient, opacity, translate); program.draw(context, context.gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, projectionData, layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments, layer.paint, painter.transform.zoom, programConfiguration, painter.style.map.terrain && bucket.centroidVertexBuffer); } }