maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
70 lines (55 loc) • 3.55 kB
text/typescript
import {StencilMode} from '../stencil_mode.ts';
import {DepthMode} from '../depth_mode.ts';
import {CullFaceMode} from '../cull_face_mode.ts';
import {
backgroundUniformValues,
backgroundPatternUniformValues
} from '../program/background_program.ts';
import {coveringTiles} from '../../geo/projection/covering_tiles.ts';
import type {FrameRenderContext} from '../../render/frame_render_context.ts';
import type {OverscaledTileID} from '../../tile/tile_id.ts';
import type {Painter} from '../../render/painter.ts';
import type {TileManager} from '../../tile/tile_manager.ts';
import type {BackgroundStyleLayer} from '../../style/style_layer/background_style_layer.ts';
export function drawBackground(painter: Painter, tileManager: TileManager, layer: BackgroundStyleLayer, coords: OverscaledTileID[], frameRenderContext: FrameRenderContext): void {
const color = layer.paint.get('background-color');
const opacity = layer.paint.get('background-opacity');
if (opacity === 0) return;
const context = painter.context;
const gl = context.gl;
const projection = painter.style.projection;
const transform = frameRenderContext.transform;
const tileSize = transform.tileSize;
const image = layer.paint.get('background-pattern');
if (painter.isPatternMissing(image)) return;
const pass = (!image && color.a === 1 && opacity === 1 && frameRenderContext.opaquePassEnabledForLayer()) ? 'opaque' : 'translucent';
if (frameRenderContext.currentPass !== pass) return;
const stencilMode = StencilMode.disabled;
const depthMode = frameRenderContext.getDepthModeForSublayer(0, pass === 'opaque' ? DepthMode.ReadWrite : DepthMode.ReadOnly);
const colorMode = frameRenderContext.colorModeForRenderPass();
const program = frameRenderContext.useProgram(image ? 'backgroundPattern' : 'background');
const tileIDs = coords ? coords : coveringTiles(transform, {tileSize, terrain: frameRenderContext.terrain});
if (image) {
context.activeTexture.set(gl.TEXTURE0);
painter.patternAtlas.bind(painter.context);
}
const crossfade = layer.getCrossfadeParameters();
for (const tileID of tileIDs) {
const projectionData = frameRenderContext.getProjectionDataForTile(tileID);
const uniformValues = image ?
backgroundPatternUniformValues(opacity, painter, image, {tileID, tileSize}, crossfade) :
backgroundUniformValues(opacity, color);
const terrainData = frameRenderContext.getTerrainDataForTile(tileID);
// For globe rendering, background uses tile meshes *without* borders and no stencil clipping.
// This works assuming the tileIDs list contains only tiles of the same zoom level.
// This seems to always be the case for background layers, but I'm leaving this comment
// here in case this assumption is false in the future.
// In case background starts having tiny holes at tile boundaries, switch to meshes with borders
// and also enable stencil clipping. Make sure to render a proper tile clipping mask into stencil
// first though, as that doesn't seem to happen for background layers as of writing this.
const mesh = projection.getMeshFromTileID(context, tileID.canonical, false, true, 'raster');
program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.backCCW,
uniformValues, terrainData, projectionData, layer.id,
mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
}
}