UNPKG

s2maps-gpu

Version:

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

127 lines (126 loc) 4.35 kB
import { Color } from 'style/color/index.js'; import parseFeature from 's2/style/parseFeature.js'; /** * Color function to convert a color to either RBG or LCH * @param lch - flag to use lch if true * @returns a color parsing function */ export const colorFunc = (lch) => { return (i) => { const color = new Color(i); return lch ? color.getLCH() : color.getRGB(); }; }; /** * Clamp tool to ensure the number is between -1 and 1 * @param i - input number * @returns clamped number */ export const clamp = (i) => Math.max(-1, Math.min(1, i)); /** * # Vector Worker * * Base class for all vector workers. * Ensurses that all vector workers can reuse things like prepping and shipping interactive features, * flusing, id-generation, etc. */ export default class VectorWorker { idGen; gpuType; interactiveMap = new Map(); /** * @param idGen - id generator to ensure features don't overlap * @param gpuType - the GPU context of the map renderer (WebGL(1|2) | WebGPU) */ constructor(idGen, gpuType) { this.idGen = idGen; this.gpuType = gpuType; } /** * Add an interactive feature * @param id - feature id * @param properties - feature properties * @param workerLayer - worker layer to pull the interactive-properties from */ _addInteractiveFeature(id, properties, workerLayer) { const { cursor, name, source, layer } = workerLayer; this.interactiveMap.set(id, { __id: id, __cursor: cursor, __name: name, __source: source, __layer: layer, ...properties, }); } /** * Flush a tile-request to the render thread * @param mapID - id of the map to ship the data back to * @param tile - tile request * @param sourceName - name of the source the data belongs to * @param _wait - wait function. Not needed at this flush level. */ async flush(mapID, tile, sourceName, _wait) { await this.postInteractive(mapID, sourceName, tile.id); } /** * Build code for a vector layer * @param design - the design to modify * @returns the build function */ buildCode(design) { const featureFunctions = []; for (const [input, cb] of design) { featureFunctions.push(parseFeature(input, cb)); } return (zoom, properties) => { // prep codes const webgl2Code = []; const webgl1Code = featureFunctions.flatMap((func) => func(webgl2Code, properties, zoom)); return [webgl1Code, webgl2Code]; }; } /** * Post an interactive feature set to the render thread * @param mapID - id of the map to ship the data back to * @param sourceName - name of the source the data belongs to * @param tileID - tile id the features belong to */ postInteractive(mapID, sourceName, tileID) { if (this.interactiveMap.size === 0) return; const interactiveGuide = []; const interactiveData = []; const textEncoder = new TextEncoder(); let offset = 0; for (const [id, properties] of this.interactiveMap) { const uint8Array = textEncoder.encode(JSON.stringify(properties)); const length = uint8Array.length; interactiveGuide.push(id, offset, offset + length); for (const byte of uint8Array) interactiveData.push(byte); offset += length; } this.interactiveMap.clear(); // Upon building the batches, convert to buffers and ship. const interactiveGuideBuffer = new Uint32Array(interactiveGuide).buffer; const interactiveDataBuffer = new Uint8ClampedArray(interactiveData).buffer; // ship the vector data. postMessage({ mapID, type: 'interactive', sourceName, tileID, interactiveGuideBuffer, interactiveDataBuffer, }, [interactiveGuideBuffer, interactiveDataBuffer]); } } /** * A convenience function to convert an ID to an RGBA encoded color * @param id - the id to convert * @returns an RGBA encoded color */ export function idToRGB(id) { return [id & 255, (id >> 8) & 255, (id >> 16) & 255, 0]; }