s2maps-gpu
Version:
S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.
132 lines (131 loc) • 4.66 kB
JavaScript
import { colorFunc } from './vectorWorker.js';
import parseFeature from 's2/style/parseFeature.js';
/** Worker for processing raster data */
export default class RasterWorker {
gpuType;
/** @param gpuType - the GPU context of the map renderer (WebGL(1|2) | WebGPU) */
constructor(gpuType) {
this.gpuType = gpuType;
}
/**
* Setup an RGBA style layer for the appropriate layer type
* @param layerDefinition - input sensor/raster/hillshade layer
* @returns the pre-processed worker layer
*/
setupLayer(layerDefinition) {
const { type, name, layerIndex, source, layer, minzoom, maxzoom, opacity } = layerDefinition;
// build feature code design
// opacity->saturation->contrast
const design = [[opacity]];
if (type === 'raster') {
const { saturation, contrast } = layerDefinition;
design.push([saturation], [contrast]);
}
else if (type === 'hillshade') {
const { shadowColor, accentColor, highlightColor, azimuth, altitude, lch } = layerDefinition;
design.push([shadowColor, colorFunc(lch)], [accentColor, colorFunc(lch)], [highlightColor, colorFunc(lch)], [azimuth], [altitude]);
}
return {
type,
name,
layerIndex,
source,
layer,
minzoom,
maxzoom,
getCode: this.buildCode(design),
};
}
/**
* Build code in relation to the design of the raster layer
* @param design - the design to modify
* @returns the build function
*/
buildCode(design) {
const { gpuType } = this;
const featureFunctions = [];
for (const [input, cb] of design) {
featureFunctions.push(parseFeature(input, cb));
}
return (zoom) => {
// prep codes
const code = [];
const properties = {};
const webgl1Code = featureFunctions
.map((func) => func(code, properties, zoom))
.flat();
return gpuType === 1 ? webgl1Code : code;
};
}
/**
* Build the raster tile
* @param mapID - the map id to ship the data back to
* @param sourceName - the source name the data to belongs to
* @param layers - the layers to process
* @param tile - the tile request
* @param data - the tile raster data
* @param size - the tile size
*/
async buildTile(mapID, sourceName, layers, tile, data, size) {
// prep variables
const { zoom, id, time } = tile;
// prebuild feature code if webgl1
const rasterFeatures = [];
const sensorFeatures = [];
const HillshadeFeatures = [];
for (const { type, getCode, layerIndex } of layers) {
const guide = type === 'raster' ? rasterFeatures : type === 'sensor' ? sensorFeatures : HillshadeFeatures;
guide.push({
code: getCode(zoom),
layerIndex,
});
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=1335594 - saved for posterity
const image = await createImageBitmap(new Blob([data]), { premultiplyAlpha: 'none' });
// ship the raster data.
if (rasterFeatures.length > 0) {
const rasterData = {
mapID,
type: 'raster',
tileID: id,
size,
sourceName,
featureGuides: rasterFeatures,
image,
};
postMessage(rasterData, [image]);
}
if (sensorFeatures.length > 0 && time !== undefined) {
const sensorData = {
mapID,
type: 'sensor',
tileID: id,
size,
sourceName,
featureGuides: sensorFeatures,
image,
time,
};
postMessage(sensorData, [image]);
}
if (HillshadeFeatures.length > 0) {
const hillshadeData = {
mapID,
type: 'hillshade',
tileID: id,
size: image.width,
sourceName,
featureGuides: HillshadeFeatures,
image,
};
postMessage(hillshadeData, [image]);
}
}
/**
* TODO: flush images
* @param _mapID - the map id to ship the data back to
* @param _tile - the tile request
* @param _sourceName - the source name the data to belongs to
*/
async flush(_mapID, _tile, _sourceName) { }
}