UNPKG

s2maps-gpu

Version:

S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.

131 lines (130 loc) 4.41 kB
import Workflow, { Feature } from './workflow.js'; import frag1 from '../shaders/shade1.fragment.glsl'; import vert1 from '../shaders/shade1.vertex.glsl'; import frag2 from '../shaders/shade2.fragment.glsl'; import vert2 from '../shaders/shade2.vertex.glsl'; /** Shape Feature is a standalone shade render storage unit that can be drawn to the GPU */ export class ShadeFeature extends Feature { layerGuide; workflow; source; featureCode; tile; type = 'shade'; maskLayer = true; /** * @param layerGuide - layer guide for this feature * @param workflow - the shade workflow * @param source - the input mask source * @param featureCode - the encoded feature code that tells the GPU how to compute it's properties * @param tile - the tile that the feature is drawn on */ constructor(layerGuide, workflow, source, featureCode, tile) { super(workflow, tile, layerGuide, featureCode); this.layerGuide = layerGuide; this.workflow = workflow; this.source = source; this.featureCode = featureCode; this.tile = tile; } /** Draw this feature to the GPU */ draw() { super.draw(); this.workflow.draw(this); } /** * Duplicate this feature * @param tile - the tile that the feature is drawn on * @returns the duplicated feature */ duplicate(tile) { const { layerGuide, workflow, source, featureCode } = this; return new ShadeFeature(layerGuide, workflow, source, featureCode, tile); } } /** Shade Workflow */ export default class ShadeWorkflow extends Workflow { label = 'shade'; /** @param context - The WebGL(1|2) context */ constructor(context) { // get gl from context const { type, devicePixelRatio } = context; // inject Program super(context); // build shaders if (type === 1) this.buildShaders(vert1, frag1, { aPos: 0 }); else this.buildShaders(vert2, frag2); // activate so we can setup devicePixelRatio this.use(); // set pixel ratio this.setDevicePixelRatio(devicePixelRatio); } /** * Build a layer definition for this workflow given the user input layer * @param layerBase - the common layer attributes * @param layer - the user defined layer attributes * @returns a built layer definition that's ready to describe how to render a feature */ buildLayerDefinition(layerBase, layer) { let { color } = layer; color = color ?? 'rgb(0.6, 0.6, 0.6)'; return { ...layerBase, type: 'shade', color, }; } /** * given a set of layerIndexes that use Masks and the tile of interest, build a mask feature * @param layerDefinition - layer definition * @param tile - the tile that needs a mask */ buildMaskFeature(layerDefinition, tile) { const { mask, zoom } = tile; const { minzoom, maxzoom } = layerDefinition; // not in the zoom range, ignore if (zoom < minzoom || zoom > maxzoom) return; // set the layer guide const layerGuide = { ...layerDefinition, sourceName: 'mask', layerCode: [], interactive: false, opaque: false, }; tile.addFeatures([new ShadeFeature(layerGuide, this, mask, [0], tile)]); } /** Use this workflow as the current shaders for the GPU */ use() { super.use(); // grab context & prep const { context } = this; context.enableCullFace(); context.enableDepthTest(); context.disableStencilTest(); context.shadeBlend(); context.lessDepth(); } /** Set the layer code uniforms for this workflow */ setLayerCode() { // noop } /** * Draw a shade feature * @param feature - the feature */ draw(feature) { const { gl, context } = this; const { source, layerGuide: { layerIndex, visible }, } = feature; const { count, offset, vao } = source; if (!visible) return; // bind vao & draw context.setDepthRange(layerIndex); gl.bindVertexArray(vao); gl.drawElements(gl.TRIANGLE_STRIP, count, gl.UNSIGNED_INT, offset * 4); } }