s2maps-gpu
Version:
S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.
124 lines (123 loc) • 4.36 kB
JavaScript
import { Color } from 'style/color/index.js';
import Workflow from './workflow.js';
// WEBGL1
import frag1 from '../shaders/wallpaper1.fragment.glsl';
import vert1 from '../shaders/wallpaper1.vertex.glsl';
// WEBGL2
import frag2 from '../shaders/wallpaper2.fragment.glsl';
import vert2 from '../shaders/wallpaper2.vertex.glsl';
/** Wallpaper Workflow renders a user styled wallpaper to the GPU */
export default class WallpaperWorkflow extends Workflow {
label = 'wallpaper';
scheme;
tileSize = 512;
scale = { x: 0, y: 0 };
/** @param context - WebGL(1|2) context */
constructor(context) {
// get gl from context
const { type } = context;
// inject Workflow
super(context);
// install shaders
if (type === 1)
this.buildShaders(vert1, frag1);
else
this.buildShaders(vert2, frag2);
// setup scheme
this.scheme = {
background: new Color('#000'),
fade1: new Color('#000'),
fade2: new Color('#000'),
halo: new Color('#000'),
};
}
/**
* Update the scale relative to the projector's position (zoom, aspect, multiplier)
* @param projector - Projector
*/
#updateScale(projector) {
const { gl, uniforms } = this;
const { uScale } = uniforms;
const { min, pow } = Math;
const { dirty, zoom, aspect, multiplier } = projector;
if (!dirty)
return;
const radius = this.tileSize * min(pow(2, zoom), 32_768);
const mult2 = multiplier / 2;
const x = (this.scale.x = radius / (aspect.x / mult2));
const y = (this.scale.y = radius / (aspect.y / mult2));
gl.uniform2fv(uScale, [x, y]);
}
/**
* Update the wallpaper style
* @param style - input user defined style
*/
updateStyle(style) {
const { scheme } = this;
const { background, fade1, fade2, halo } = style.wallpaper ?? {};
// inject wallpaper into scheme
if (background !== undefined)
scheme.background = new Color(background);
if (fade1 !== undefined)
scheme.fade1 = new Color(fade1);
if (fade2 !== undefined)
scheme.fade2 = new Color(fade2);
if (halo !== undefined)
scheme.halo = new Color(halo);
// inject uniforms
this.use();
this.#updateUniforms();
}
/**
* Update uniforms for the current colorblind mode
* @param cbAdjust - colorblind mode
*/
#updateUniforms(cbAdjust) {
const { gl, uniforms, scheme } = this;
const { uBackground, uFade1, uFade2, uHalo } = uniforms;
// inject uniforms
gl.uniform4fv(uBackground, scheme.background.getRGB(true, cbAdjust));
gl.uniform4fv(uFade1, scheme.fade1.getRGB(true, cbAdjust));
gl.uniform4fv(uFade2, scheme.fade2.getRGB(true, cbAdjust));
gl.uniform4fv(uHalo, scheme.halo.getRGB(true, cbAdjust));
}
/** Flush the uniforms to the GPU */
flush() {
if (this.updateColorBlindMode !== null) {
if (this.updateColorBlindMode === 0)
this.#updateUniforms();
else if (this.updateColorBlindMode === 1)
this.#updateUniforms('protanopia');
else if (this.updateColorBlindMode === 2)
this.#updateUniforms('deuteranopia');
else if (this.updateColorBlindMode === 3)
this.#updateUniforms('tritanopia');
this.updateColorBlindMode = null;
}
}
/** Use this workflow as the current shaders for the GPU */
use() {
super.use();
const { context } = this;
// ignore z-fighting and only pass where stencil is 0
context.defaultBlend();
context.disableCullFace();
context.disableDepthTest();
context.enableStencilTest();
context.stencilFuncEqual(0);
}
/**
* Draw the wallpaper
* @param projector - Projector
*/
draw(projector) {
// setup variables
const { context } = this;
// let the context know the current workflow
context.setWorkflow(this);
// update scale if necessary
this.#updateScale(projector);
// draw the wallpaper
context.drawQuad();
}
}