UNPKG

maplibre-gl

Version:

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

128 lines (106 loc) 5.41 kB
import {StencilMode} from '../stencil_mode'; import {DepthMode} from '../depth_mode'; import {CullFaceMode} from '../cull_face_mode'; import {type Program} from '../program'; import {circleUniformValues} from '../program/circle_program'; import {SegmentVector} from '../../data/segment'; import {type OverscaledTileID} from '../../tile/tile_id'; import type {Painter, RenderOptions} from '../../render/painter'; import type {TileManager} from '../../tile/tile_manager'; import type {CircleStyleLayer} from '../../style/style_layer/circle_style_layer'; import type {CircleBucket} from '../../data/bucket/circle_bucket'; import type {ProgramConfiguration} from '../../data/program_configuration'; import type {VertexBuffer} from '../vertex_buffer'; import type {IndexBuffer} from '../index_buffer'; import type {UniformValues} from '../uniform_binding'; import type {CircleUniformsType} from '../program/circle_program'; import type {TerrainData} from '../../render/terrain'; import {translatePosition} from '../../util/util'; import type {ProjectionData} from '../../geo/projection/projection_data'; type TileRenderState = { programConfiguration: ProgramConfiguration; program: Program<any>; layoutVertexBuffer: VertexBuffer; indexBuffer: IndexBuffer; uniformValues: UniformValues<CircleUniformsType>; terrainData: TerrainData; projectionData: ProjectionData; }; type SegmentsTileRenderState = { segments: SegmentVector; sortKey: number; state: TileRenderState; }; export function drawCircles(painter: Painter, tileManager: TileManager, layer: CircleStyleLayer, coords: OverscaledTileID[], renderOptions: RenderOptions) { if (painter.renderPass !== 'translucent') return; const {isRenderingToTexture} = renderOptions; const opacity = layer.paint.get('circle-opacity'); const strokeWidth = layer.paint.get('circle-stroke-width'); const strokeOpacity = layer.paint.get('circle-stroke-opacity'); const sortFeaturesByKey = !layer.layout.get('circle-sort-key').isConstant(); if (opacity.constantOr(1) === 0 && (strokeWidth.constantOr(1) === 0 || strokeOpacity.constantOr(1) === 0)) { return; } const context = painter.context; const gl = context.gl; const transform = painter.transform; const depthMode = painter.getDepthModeForSublayer(0, DepthMode.ReadOnly); // Turn off stencil testing to allow circles to be drawn across boundaries, // so that large circles are not clipped to tiles const stencilMode = StencilMode.disabled; const colorMode = painter.colorModeForRenderPass(); const segmentsRenderStates: SegmentsTileRenderState[] = []; // Note: due to how the shader is written, this value only has effect when globe rendering is enabled and `circle-pitch-alignment` is set to 'map'. const radiusCorrectionFactor = transform.getCircleRadiusCorrection(); for (const coord of coords) { const tile = tileManager.getTile(coord); const bucket: CircleBucket<any> = (tile.getBucket(layer) as any); if (!bucket) continue; const styleTranslate = layer.paint.get('circle-translate'); const styleTranslateAnchor = layer.paint.get('circle-translate-anchor'); const translateForUniforms = translatePosition(transform, tile, styleTranslate, styleTranslateAnchor); const programConfiguration = bucket.programConfigurations.get(layer.id); const program = painter.useProgram('circle', programConfiguration); const layoutVertexBuffer = bucket.layoutVertexBuffer; const indexBuffer = bucket.indexBuffer; const terrainData = painter.style.map.terrain?.getTerrainData(coord); const uniformValues = circleUniformValues(painter, tile, layer, translateForUniforms, radiusCorrectionFactor); const projectionData = transform.getProjectionData({overscaledTileID: coord, applyGlobeMatrix: !isRenderingToTexture, applyTerrainMatrix: true}); const state: TileRenderState = { programConfiguration, program, layoutVertexBuffer, indexBuffer, uniformValues, terrainData, projectionData }; if (sortFeaturesByKey) { const oldSegments = bucket.segments.get(); for (const segment of oldSegments) { segmentsRenderStates.push({ segments: new SegmentVector([segment]), sortKey: (segment.sortKey as any as number), state }); } } else { segmentsRenderStates.push({ segments: bucket.segments, sortKey: 0, state }); } } if (sortFeaturesByKey) { segmentsRenderStates.sort((a, b) => a.sortKey - b.sortKey); } for (const segmentsState of segmentsRenderStates) { const {programConfiguration, program, layoutVertexBuffer, indexBuffer, uniformValues, terrainData, projectionData} = segmentsState.state; const segments = segmentsState.segments; program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, projectionData, layer.id, layoutVertexBuffer, indexBuffer, segments, layer.paint, painter.transform.zoom, programConfiguration); } }