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} 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'; export function drawFillExtrusion(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLayer, coords: Array) { const opacity = layer.paint.get('fill-extrusion-opacity'); if (opacity === 0) { return; } 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); } 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); // 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()); } } } function drawExtrusionTiles( painter: Painter, source: SourceCache, layer: FillExtrusionStyleLayer, coords: OverscaledTileID[], depthMode: DepthMode, stencilMode: Readonly, colorMode: Readonly) { 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); 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); } updatePatternPositionsInProgram(programConfiguration, fillPropertyName, constantPattern, tile, layer); const matrix = painter.translatePosMatrix( coord.posMatrix, 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(matrix, painter, shouldUseVerticalGradient, opacity, coord, crossfade, tile) : fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity); program.draw(context, context.gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments, layer.paint, painter.transform.zoom, programConfiguration, painter.style.map.terrain && bucket.centroidVertexBuffer); } }