@allmaps/render
Version:
Render functions for WebGL and image buffers
1,123 lines (1,122 loc) • 34.4 kB
JavaScript
import { throttle } from "lodash-es";
import { wrap } from "comlink";
import { mergeOptions, squaredDistance, hexToFractionalRgb, maxOfNumberOrUndefined } from "@allmaps/stdlib";
import { supportedDistortionMeasures } from "@allmaps/transform";
import { red, darkblue, green, yellow, black } from "@allmaps/tailwind";
import { BaseRenderer } from "./BaseRenderer.js";
import { createWebGL2WarpedMapFactory } from "../maps/WebGL2WarpedMap.js";
import { CacheableWorkerImageDataTile } from "../tilecache/CacheableWorkerImageDataTile.js";
import { WarpedMapEvent, WarpedMapEventType } from "../shared/events.js";
import { multiplyHomogeneousTransform, homogeneousTransformToMatrix4, invertHomogeneousTransform } from "../shared/homogeneous-transform.js";
import { createShader, createProgram } from "../shared/webgl2.js";
import { Viewport } from "../viewport/Viewport.js";
import vertex_shader_default from "../shaders/map/vertex-shader.glsl.js";
import fragment_shader_default from "../shaders/map/fragment-shader.glsl.js";
import vertex_shader_default$1 from "../shaders/lines/vertex-shader.glsl.js";
import fragment_shader_default$1 from "../shaders/lines/fragment-shader.glsl.js";
import vertex_shader_default$2 from "../shaders/points/vertex-shader.glsl.js";
import fragment_shader_default$2 from "../shaders/points/fragment-shader.glsl.js";
import WorkerWrapper from "../workers/fetch-and-get-image-data.js";
const THROTTLE_PREPARE_RENDER_WAIT_MS = 200;
const THROTTLE_PREPARE_RENDER_OPTIONS = {
leading: true,
trailing: true
};
const THROTTLE_CHANGED_WAIT_MS = 50;
const THROTTLE_CHANGED_OPTIONS = {
leading: true,
trailing: true
};
const defaultWebgl2RendererOptions = {
debugMaps: false,
renderMaps: true,
renderLines: true,
renderPoints: true
};
const DEFAULT_OPACITY = 1;
const DEFAULT_SATURATION = 1;
const DEFAULT_REMOVE_COLOR_THRESHOLD = 0;
const DEFAULT_REMOVE_COLOR_HARDNESS = 0.7;
const SIGNIFICANT_VIEWPORT_EPSILON = 100 * Number.EPSILON;
const SIGNIFICANT_VIEWPORT_DISTANCE = 5;
const ANIMATION_DURATION = 750;
class WebGL2Renderer extends BaseRenderer {
#worker;
gl;
partialWebgl2RendererOptions;
mapProgram;
linesProgram;
pointsProgram;
previousSignificantViewport;
opacity = DEFAULT_OPACITY;
saturation = DEFAULT_SATURATION;
renderOptions = {};
lastAnimationFrameRequestId;
animating = false;
transformaterTransitionStart;
animationProgress = 0;
disableRender = false;
throttledPrepareRenderInternal;
throttledChanged;
/**
* Creates an instance of WebGL2Renderer.
*
* @constructor
* @param gl - WebGL 2 rendering context
* @param options - options
*/
constructor(gl, options) {
const mapVertexShader = createShader(
gl,
gl.VERTEX_SHADER,
vertex_shader_default
);
const mapFragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragment_shader_default
);
const linesVertexShader = createShader(
gl,
gl.VERTEX_SHADER,
vertex_shader_default$1
);
const linesFragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragment_shader_default$1
);
const pointsVertexShader = createShader(
gl,
gl.VERTEX_SHADER,
vertex_shader_default$2
);
const pointsFragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragment_shader_default$2
);
const mapProgram = createProgram(gl, mapVertexShader, mapFragmentShader);
const linesProgram = createProgram(
gl,
linesVertexShader,
linesFragmentShader
);
const pointsProgram = createProgram(
gl,
pointsVertexShader,
pointsFragmentShader
);
const worker = new WorkerWrapper();
const wrappedWorker = wrap(worker);
super(
CacheableWorkerImageDataTile.createFactory(wrappedWorker),
createWebGL2WarpedMapFactory(gl, mapProgram, linesProgram, pointsProgram),
options
);
this.#worker = worker;
this.gl = gl;
this.partialWebgl2RendererOptions = mergeOptions(
defaultWebgl2RendererOptions,
options
);
this.mapProgram = mapProgram;
this.linesProgram = linesProgram;
this.pointsProgram = pointsProgram;
gl.deleteShader(mapVertexShader);
gl.deleteShader(mapFragmentShader);
gl.deleteShader(mapVertexShader);
gl.deleteShader(mapFragmentShader);
gl.deleteShader(mapVertexShader);
gl.deleteShader(mapFragmentShader);
gl.disable(gl.DEPTH_TEST);
this.addEventListeners();
this.throttledPrepareRenderInternal = throttle(
this.prepareRenderInternal.bind(this),
THROTTLE_PREPARE_RENDER_WAIT_MS,
THROTTLE_PREPARE_RENDER_OPTIONS
);
this.throttledChanged = throttle(
this.changed.bind(this),
THROTTLE_CHANGED_WAIT_MS,
THROTTLE_CHANGED_OPTIONS
);
}
initializeWebGL(gl) {
const mapVertexShader = createShader(
gl,
gl.VERTEX_SHADER,
vertex_shader_default
);
const mapFragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragment_shader_default
);
const linesVertexShader = createShader(
gl,
gl.VERTEX_SHADER,
vertex_shader_default$1
);
const linesFragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragment_shader_default$1
);
const pointsVertexShader = createShader(
gl,
gl.VERTEX_SHADER,
vertex_shader_default$2
);
const pointsFragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragment_shader_default$2
);
const mapProgram = createProgram(gl, mapVertexShader, mapFragmentShader);
const linesProgram = createProgram(
gl,
linesVertexShader,
linesFragmentShader
);
const pointsProgram = createProgram(
gl,
pointsVertexShader,
pointsFragmentShader
);
this.gl = gl;
this.mapProgram = mapProgram;
this.linesProgram = linesProgram;
this.pointsProgram = pointsProgram;
gl.disable(gl.DEPTH_TEST);
for (const webgl2WarpedMap of this.warpedMapList.getWarpedMaps()) {
webgl2WarpedMap.initializeWebGL(mapProgram, linesProgram, pointsProgram);
}
}
/**
* Get the opacity of the renderer
*
* @returns
*/
getOpacity() {
return this.opacity;
}
/**
* Set the opacity of the renderer
*
* @param opacity - opacity to set
*/
setOpacity(opacity) {
this.opacity = opacity;
}
/**
* Reset the opacity of the renderer
*/
resetOpacity() {
this.opacity = DEFAULT_OPACITY;
}
/**
* Get the opacity of a map
*
* @param mapId - ID of the map
* @returns
*/
getMapOpacity(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
return webgl2WarpedMap.opacity;
}
}
/**
* Set the opacity of a map
*
* @param mapId - ID of the map
* @param opacity - opacity to set
*/
setMapOpacity(mapId, opacity) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.opacity = Math.min(Math.max(opacity, 0), 1);
}
}
/**
* Rreset the opacity of a map
*
* @param mapId - ID of the map
*/
resetMapOpacity(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.opacity = DEFAULT_OPACITY;
}
}
/**
* Get the remove color options of the renderer
*
* @returns
*/
getRemoveColorOptions() {
return this.renderOptions.removeColorOptions;
}
/**
* Set the remove color options of the renderer
*
* @param removeColorOptions
*/
setRemoveColorOptions(removeColorOptions) {
this.renderOptions.removeColorOptions = removeColorOptions;
}
/**
* Reset the remove color options of the renderer
*/
resetRemoveColorOptions() {
this.renderOptions.removeColorOptions = void 0;
}
/**
* Get the remove color options of a map
*
* @param mapId - ID of the map
* @returns
*/
getMapRemoveColorOptions(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
return webgl2WarpedMap.renderOptions.removeColorOptions;
}
}
/**
* Set the WebGL2 Renderer options
*
* @param partialWebgl2RendererOptions - Options
*/
setOptions(partialWebgl2RendererOptions) {
this.partialWebgl2RendererOptions = mergeOptions(
this.partialWebgl2RendererOptions,
partialWebgl2RendererOptions
);
super.setOptions(partialWebgl2RendererOptions);
}
/**
* Set the remove color options of a map
*
* @param mapId - ID of the map
* @param removeColorOptions - the 'remove color options' to set
*/
setMapRemoveColorOptions(mapId, removeColorOptions) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.renderOptions.removeColorOptions = removeColorOptions;
}
}
/**
* Reset the remove color options of a map
*
* @param mapId - ID of the map
*/
resetMapRemoveColorOptions(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.renderOptions.removeColorOptions = void 0;
}
}
/**
* Get the colorize options of the renderer
*
* @returns
*/
getColorizeOptions() {
return this.renderOptions.colorizeOptions;
}
/**
* Set the colorize options of the renderer
*
* @param colorizeOptions - the colorize options to set
*/
setColorizeOptions(colorizeOptions) {
this.renderOptions.colorizeOptions = colorizeOptions;
}
/**
* Reset the colorize options of the renderer
*/
resetColorizeOptions() {
this.renderOptions.colorizeOptions = void 0;
}
/**
* Get the colorize options of a map
*
* @param mapId - ID of the map
* @returns Colorize options
*/
getMapColorizeOptions(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
return webgl2WarpedMap.renderOptions.colorizeOptions;
}
}
/**
* Set the colorize options of a map
*
* @param mapId - ID of the map
* @param colorizeOptions - the colorize options to set
*/
setMapColorizeOptions(mapId, colorizeOptions) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.renderOptions.colorizeOptions = colorizeOptions;
}
}
/**
* Reset the colorize options of a map
*
* @param mapId - ID of the map
*/
resetMapColorizeOptions(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.renderOptions.colorizeOptions = void 0;
}
}
/**
* Get the grid options of the renderer
*
* @returns
*/
getGridOptions() {
return this.renderOptions.gridOptions;
}
/**
* Set the grid options of the renderer
*
* @param gridOptions - the grid options to set
*/
setGridOptions(gridOptions) {
this.renderOptions.gridOptions = gridOptions;
}
/**
* Reset the grid options of the renderer
*/
resetGridOptions() {
this.renderOptions.gridOptions = void 0;
}
/**
* Get the grid options of a map
*
* @param mapId - ID of the map
* @returns
*/
getMapGridOptions(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
return webgl2WarpedMap.renderOptions.gridOptions;
}
}
/**
* Set the grid options of a map
*
* @param mapId - ID of the map
* @param gridOptions - the grid options to set
*/
setMapGridOptions(mapId, gridOptions) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.renderOptions.gridOptions = gridOptions;
}
}
/**
* Reset the grid options of a map
*
* @param mapId - ID of the map
*/
resetMapGridOptions(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.renderOptions.gridOptions = void 0;
}
}
/**
* Get the saturation of the renderer
*
* @returns
*/
getSaturation() {
return this.saturation;
}
/**
* Set the saturation of the renderer
*
* 0 - grayscale, 1 - original colors
*
* @param saturation - the satuation to set
*/
setSaturation(saturation) {
this.saturation = saturation;
}
/**
* Reset the satuation of the renderer
*/
resetSaturation() {
this.saturation = DEFAULT_SATURATION;
}
/**
* Get the saturation of a map
*
* @param mapId - ID of the map
* @returns
*/
getMapSaturation(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
return webgl2WarpedMap.saturation;
}
}
/**
* Set the saturation of a map
*
* 0 - grayscale, 1 - original colors
*
* @param mapId - ID of the map
* @param saturation - the saturation to set
*/
setMapSaturation(mapId, saturation) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.saturation = saturation;
}
}
/**
* Reset the saturation of a map
*
* @param mapId - ID of the map
*/
resetMapSaturation(mapId) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
webgl2WarpedMap.saturation = DEFAULT_SATURATION;
}
}
/**
* Render the map for a given viewport.
*
* If no viewport is specified the current viewport is rerendered.
* If no current viewport is known, a viewport is deduced based on the WarpedMapList and canvas width and hight.
*
* @param viewport - the current viewport
*/
render(viewport) {
if (this.disableRender) {
return;
}
this.viewport = viewport || this.viewport || Viewport.fromSizeAndMaps(
[this.gl.canvas.width, this.gl.canvas.width],
this.warpedMapList
);
this.loadMissingImageInfosInViewport();
if (this.someImageInfosInViewport()) {
this.throttledPrepareRenderInternal();
}
this.renderInternal();
}
clear() {
this.warpedMapList.clear();
this.mapsInViewport = /* @__PURE__ */ new Set();
this.mapsWithRequestedTilesForViewport = /* @__PURE__ */ new Set();
this.gl.clear(this.gl.DEPTH_BUFFER_BIT | this.gl.COLOR_BUFFER_BIT);
this.tileCache.clear();
}
cancelThrottledFunctions() {
this.throttledPrepareRenderInternal.cancel();
this.throttledChanged.cancel();
}
destroy() {
this.cancelThrottledFunctions();
for (const webgl2WarpedMap of this.warpedMapList.getWarpedMaps()) {
this.removeEventListenersFromWebGL2WarpedMap(webgl2WarpedMap);
}
this.removeEventListeners();
super.destroy();
this.gl.deleteProgram(this.mapProgram);
this.gl.deleteProgram(this.linesProgram);
this.gl.deleteProgram(this.pointsProgram);
this.#worker.terminate();
}
updateMapsForViewport(tiles) {
const { mapsEnteringViewport, mapsLeavingViewport } = super.updateMapsForViewport(tiles);
this.updateVertexBuffers(mapsEnteringViewport);
return { mapsEnteringViewport, mapsLeavingViewport };
}
resetPrevious(mapIds) {
const webgl2WarpedMaps = this.warpedMapList.getWarpedMaps({ mapIds });
for (const webgl2WarpedMap of webgl2WarpedMaps) {
webgl2WarpedMap.resetPrevious();
}
}
updateVertexBuffers(mapIds) {
if (!this.viewport) {
return;
}
const webgl2WarpedMaps = this.warpedMapList.getWarpedMaps({ mapIds });
for (const webgl2WarpedMap of webgl2WarpedMaps) {
webgl2WarpedMap.updateVertexBuffers(
this.viewport.projectedGeoToClipHomogeneousTransform,
this.partialWebgl2RendererOptions
);
}
}
prepareRenderInternal() {
this.assureProjection();
this.requestFetchableTiles();
}
shouldRequestFetchableTiles() {
if (!this.viewport) {
return false;
}
if (this.animating) {
return false;
}
if (!this.previousSignificantViewport) {
this.previousSignificantViewport = this.viewport;
return true;
} else {
const rectangleSquaredDistances = [];
for (let i = 0; i < 4; i++) {
rectangleSquaredDistances.push(
squaredDistance(
this.previousSignificantViewport.projectedGeoRectangle[i],
this.viewport.projectedGeoRectangle[i]
) / Math.pow(this.viewport.projectedGeoPerViewportScale, 2)
);
}
const maxSquaredDistance = Math.max(...rectangleSquaredDistances);
if (maxSquaredDistance < SIGNIFICANT_VIEWPORT_EPSILON) {
return true;
}
if (maxSquaredDistance > Math.pow(SIGNIFICANT_VIEWPORT_DISTANCE, 2)) {
this.previousSignificantViewport = this.viewport;
return true;
} else {
return false;
}
}
}
shouldAnticipateInteraction() {
return true;
}
renderInternal() {
if (!this.viewport) {
return;
}
const gl = this.gl;
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
if (this.partialWebgl2RendererOptions.renderMaps) {
this.renderMapsInternal();
}
if (this.partialWebgl2RendererOptions.renderLines) {
this.renderLinesInternal();
}
if (this.partialWebgl2RendererOptions.renderPoints) {
this.renderPointsInternal();
}
}
renderMapsInternal() {
if (!this.viewport) {
return;
}
this.setMapProgramUniforms();
for (const mapId of this.mapsWithRequestedTilesForViewport) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (!webgl2WarpedMap) {
continue;
}
this.setMapProgramRenderOptionsUniforms(
this.renderOptions,
webgl2WarpedMap.renderOptions
);
this.setMapProgramMapUniforms(webgl2WarpedMap);
const count = webgl2WarpedMap.resourceTrianglePoints.length;
const primitiveType = this.gl.TRIANGLES;
const offset = 0;
this.gl.bindVertexArray(webgl2WarpedMap.mapVao);
this.gl.drawArrays(primitiveType, offset, count);
}
}
renderLinesInternal() {
this.setLinesProgramUniforms();
for (const mapId of this.mapsInViewport) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (!webgl2WarpedMap) {
continue;
}
this.setLinesProgramMapUniforms(webgl2WarpedMap);
const count = webgl2WarpedMap.lineLayers.reduce(
(accumulator, lineLayer) => accumulator + lineLayer.projectedGeoLines.length,
0
) * 6;
const primitiveType = this.gl.TRIANGLES;
const offset = 0;
this.gl.bindVertexArray(webgl2WarpedMap.linesVao);
this.gl.drawArrays(primitiveType, offset, count);
}
}
renderPointsInternal() {
this.setPointsProgramUniforms();
for (const mapId of this.mapsInViewport) {
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (!webgl2WarpedMap) {
continue;
}
this.setPointsProgramMapUniforms(webgl2WarpedMap);
const count = webgl2WarpedMap.pointLayers.reduce(
(accumulator, pointLayer) => accumulator + pointLayer.projectedGeoPoints.length,
0
);
const primitiveType = this.gl.POINTS;
const offset = 0;
this.gl.bindVertexArray(webgl2WarpedMap.pointsVao);
this.gl.drawArrays(primitiveType, offset, count);
}
}
setMapProgramUniforms() {
const program = this.mapProgram;
const gl = this.gl;
gl.useProgram(program);
const debugLocation = gl.getUniformLocation(program, "u_debug");
gl.uniform1f(
debugLocation,
this.partialWebgl2RendererOptions.debugMaps ? 1 : 0
);
const animationProgressLocation = gl.getUniformLocation(
program,
"u_animationProgress"
);
gl.uniform1f(animationProgressLocation, this.animationProgress);
const colorDistortion00 = gl.getUniformLocation(
program,
"u_colorDistortion00"
);
gl.uniform4f(colorDistortion00, ...hexToFractionalRgb(red), 1);
const colorDistortion01 = gl.getUniformLocation(
program,
"u_colorDistortion01"
);
gl.uniform4f(colorDistortion01, ...hexToFractionalRgb(darkblue), 1);
const colorDistortion1 = gl.getUniformLocation(
program,
"u_colorDistortion1"
);
gl.uniform4f(colorDistortion1, ...hexToFractionalRgb(green), 1);
const colorDistortion2 = gl.getUniformLocation(
program,
"u_colorDistortion2"
);
gl.uniform4f(colorDistortion2, ...hexToFractionalRgb(yellow), 1);
const colorDistortion3 = gl.getUniformLocation(
program,
"u_colorDistortion3"
);
gl.uniform4f(colorDistortion3, ...hexToFractionalRgb(red), 1);
const colorGrid = gl.getUniformLocation(program, "u_colorGrid");
gl.uniform4f(colorGrid, ...hexToFractionalRgb(black), 1);
}
setMapProgramRenderOptionsUniforms(layerRenderOptions, mapRenderOptions) {
const gl = this.gl;
const program = this.mapProgram;
gl.useProgram(program);
const renderOptions = {
removeColorOptions: {
color: mapRenderOptions.removeColorOptions?.color || layerRenderOptions.removeColorOptions?.color,
hardness: maxOfNumberOrUndefined(
mapRenderOptions.removeColorOptions?.hardness,
layerRenderOptions.removeColorOptions?.hardness
),
threshold: maxOfNumberOrUndefined(
mapRenderOptions.removeColorOptions?.threshold,
layerRenderOptions.removeColorOptions?.threshold
)
},
colorizeOptions: {
...layerRenderOptions.colorizeOptions,
...mapRenderOptions.colorizeOptions
},
gridOptions: {
...layerRenderOptions.gridOptions,
...mapRenderOptions.gridOptions
}
};
const removeColorOptionsColor = renderOptions.removeColorOptions?.color;
const removeColorLocation = gl.getUniformLocation(program, "u_removeColor");
gl.uniform1f(removeColorLocation, removeColorOptionsColor ? 1 : 0);
if (removeColorOptionsColor) {
const removeColorOptionsColorLocation = gl.getUniformLocation(
program,
"u_removeColorOptionsColor"
);
gl.uniform3fv(removeColorOptionsColorLocation, removeColorOptionsColor);
const removeColorOptionsThresholdLocation = gl.getUniformLocation(
program,
"u_removeColorOptionsThreshold"
);
gl.uniform1f(
removeColorOptionsThresholdLocation,
renderOptions.removeColorOptions?.threshold || DEFAULT_REMOVE_COLOR_THRESHOLD
);
const removeColorOptionsHardnessLocation = gl.getUniformLocation(
program,
"u_removeColorOptionsHardness"
);
gl.uniform1f(
removeColorOptionsHardnessLocation,
renderOptions.removeColorOptions?.hardness || DEFAULT_REMOVE_COLOR_HARDNESS
);
}
const colorizeOptionsColor = renderOptions.colorizeOptions?.color;
const colorizeLocation = gl.getUniformLocation(program, "u_colorize");
gl.uniform1f(colorizeLocation, colorizeOptionsColor ? 1 : 0);
if (colorizeOptionsColor) {
const colorizeOptionsColorLocation = gl.getUniformLocation(
program,
"u_colorizeOptionsColor"
);
gl.uniform3fv(colorizeOptionsColorLocation, colorizeOptionsColor);
}
const gridOptionsGrid = renderOptions.gridOptions?.enabled;
const gridLocation = gl.getUniformLocation(program, "u_grid");
gl.uniform1f(gridLocation, gridOptionsGrid ? 1 : 0);
}
setMapProgramMapUniforms(webgl2WarpedMap) {
if (!this.viewport) {
return;
}
const gl = this.gl;
const program = this.mapProgram;
gl.useProgram(program);
const renderHomogeneousTransform = multiplyHomogeneousTransform(
this.viewport.projectedGeoToClipHomogeneousTransform,
webgl2WarpedMap.invertedRenderHomogeneousTransform
);
const renderHomogeneousTransformLocation = gl.getUniformLocation(
program,
"u_renderHomogeneousTransform"
);
gl.uniformMatrix4fv(
renderHomogeneousTransformLocation,
false,
homogeneousTransformToMatrix4(renderHomogeneousTransform)
);
const opacityLocation = gl.getUniformLocation(program, "u_opacity");
gl.uniform1f(opacityLocation, this.opacity * webgl2WarpedMap.opacity);
const saturationLocation = gl.getUniformLocation(program, "u_saturation");
gl.uniform1f(
saturationLocation,
this.saturation * webgl2WarpedMap.saturation
);
const distortionLocation = gl.getUniformLocation(program, "u_distortion");
gl.uniform1f(distortionLocation, webgl2WarpedMap.distortionMeasure ? 1 : 0);
const distortionOptionsDistortionMeasureLocation = gl.getUniformLocation(
program,
"u_distortionOptionsdistortionMeasure"
);
gl.uniform1i(
distortionOptionsDistortionMeasureLocation,
webgl2WarpedMap.distortionMeasure ? supportedDistortionMeasures.indexOf(webgl2WarpedMap.distortionMeasure) : 0
);
const scaleFactorForViewportLocation = gl.getUniformLocation(
program,
"u_scaleFactorForViewport"
);
const scaleFactorForViewport = webgl2WarpedMap.tileZoomLevelForViewport ? webgl2WarpedMap.tileZoomLevelForViewport.scaleFactor : 1;
gl.uniform1i(scaleFactorForViewportLocation, scaleFactorForViewport);
const cachedTilesTextureArrayLocation = gl.getUniformLocation(
program,
"u_cachedTilesTextureArray"
);
gl.uniform1i(cachedTilesTextureArrayLocation, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D_ARRAY, webgl2WarpedMap.cachedTilesTextureArray);
const cachedTilesResourceOriginPointsAndDimensionsLocation = gl.getUniformLocation(
program,
"u_cachedTilesResourceOriginPointsAndDimensionsTexture"
);
gl.uniform1i(cachedTilesResourceOriginPointsAndDimensionsLocation, 1);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(
gl.TEXTURE_2D,
webgl2WarpedMap.cachedTilesResourceOriginPointsAndDimensionsTexture
);
const cachedTileScaleFactorsTextureLocation = gl.getUniformLocation(
program,
"u_cachedTilesScaleFactorsTexture"
);
gl.uniform1i(cachedTileScaleFactorsTextureLocation, 2);
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(
gl.TEXTURE_2D,
webgl2WarpedMap.cachedTilesScaleFactorsTexture
);
}
setLinesProgramUniforms() {
if (!this.viewport) {
return;
}
const gl = this.gl;
const program = this.linesProgram;
gl.useProgram(program);
const viewportToClipHomogeneousTransformLocation = gl.getUniformLocation(
program,
"u_viewportToClipHomogeneousTransform"
);
gl.uniformMatrix4fv(
viewportToClipHomogeneousTransformLocation,
false,
homogeneousTransformToMatrix4(
this.viewport.viewportToClipHomogeneousTransform
)
);
const clipToViewportHomogeneousTransformLocation = gl.getUniformLocation(
program,
"u_clipToViewportHomogeneousTransform"
);
gl.uniformMatrix4fv(
clipToViewportHomogeneousTransformLocation,
false,
homogeneousTransformToMatrix4(
invertHomogeneousTransform(
this.viewport.viewportToClipHomogeneousTransform
)
)
);
const animationProgressLocation = gl.getUniformLocation(
program,
"u_animationProgress"
);
gl.uniform1f(animationProgressLocation, this.animationProgress);
}
setLinesProgramMapUniforms(webgl2WarpedMap) {
if (!this.viewport) {
return;
}
const gl = this.gl;
const program = this.linesProgram;
gl.useProgram(program);
const renderHomogeneousTransform = multiplyHomogeneousTransform(
this.viewport.projectedGeoToClipHomogeneousTransform,
webgl2WarpedMap.invertedRenderHomogeneousTransform
);
const renderHomogeneousTransformLocation = gl.getUniformLocation(
program,
"u_renderHomogeneousTransform"
);
gl.uniformMatrix4fv(
renderHomogeneousTransformLocation,
false,
homogeneousTransformToMatrix4(renderHomogeneousTransform)
);
}
setPointsProgramUniforms() {
if (!this.viewport) {
return;
}
const gl = this.gl;
const program = this.pointsProgram;
gl.useProgram(program);
const animationProgressLocation = gl.getUniformLocation(
program,
"u_animationProgress"
);
gl.uniform1f(animationProgressLocation, this.animationProgress);
}
setPointsProgramMapUniforms(webgl2WarpedMap) {
if (!this.viewport) {
return;
}
const gl = this.gl;
const program = this.pointsProgram;
gl.useProgram(program);
const renderHomogeneousTransform = multiplyHomogeneousTransform(
this.viewport.projectedGeoToClipHomogeneousTransform,
webgl2WarpedMap.invertedRenderHomogeneousTransform
);
const renderHomogeneousTransformLocation = gl.getUniformLocation(
program,
"u_renderHomogeneousTransform"
);
gl.uniformMatrix4fv(
renderHomogeneousTransformLocation,
false,
homogeneousTransformToMatrix4(renderHomogeneousTransform)
);
}
startTransformerTransition(mapIds) {
this.updateVertexBuffers(mapIds);
if (this.lastAnimationFrameRequestId !== void 0) {
cancelAnimationFrame(this.lastAnimationFrameRequestId);
}
this.animating = true;
this.transformaterTransitionStart = void 0;
this.lastAnimationFrameRequestId = requestAnimationFrame(
((now) => this.transformerTransitionFrame(now, mapIds)).bind(this)
);
}
transformerTransitionFrame(now, mapIds) {
if (!this.transformaterTransitionStart) {
this.transformaterTransitionStart = now;
}
if (now - this.transformaterTransitionStart < ANIMATION_DURATION) {
this.animationProgress = (now - this.transformaterTransitionStart) / ANIMATION_DURATION;
this.changed();
this.renderInternal();
this.lastAnimationFrameRequestId = requestAnimationFrame(
((now2) => this.transformerTransitionFrame(now2, mapIds)).bind(
this
)
);
} else {
this.finishTransformerTransition(mapIds);
}
}
finishTransformerTransition(mapIds) {
this.resetPrevious(mapIds);
this.updateVertexBuffers(mapIds);
this.animating = false;
this.animationProgress = 0;
this.transformaterTransitionStart = void 0;
this.changed();
}
changed() {
this.dispatchEvent(new WarpedMapEvent(WarpedMapEventType.CHANGED));
}
imageInfoLoaded(event) {
if (event instanceof WarpedMapEvent) {
this.dispatchEvent(new WarpedMapEvent(WarpedMapEventType.IMAGEINFOLOADED));
}
}
clearMap(mapId) {
const webGL2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webGL2WarpedMap) {
webGL2WarpedMap.clearTextures();
}
}
mapTileLoaded(event) {
if (event instanceof WarpedMapEvent) {
const { mapId, tileUrl } = event.data;
const tile = this.tileCache.getCacheableTile(tileUrl);
if (!tile) {
return;
}
if (!tile.isCachedTile()) {
return;
}
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (!webgl2WarpedMap) {
return;
}
webgl2WarpedMap.addCachedTileAndUpdateTextures(tile);
}
}
mapTileRemoved(event) {
if (event instanceof WarpedMapEvent) {
const { mapId, tileUrl } = event.data;
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (!webgl2WarpedMap) {
return;
}
webgl2WarpedMap.removeCachedTileAndUpdateTextures(tileUrl);
}
}
warpedMapAdded(event) {
if (event instanceof WarpedMapEvent) {
const mapId = event.data;
const webgl2WarpedMap = this.warpedMapList.getWarpedMap(mapId);
if (webgl2WarpedMap) {
this.addEventListenersToWebGL2WarpedMap(webgl2WarpedMap);
}
}
}
preChange(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
for (const webgl2WarpedMap of this.warpedMapList.getWarpedMaps({
mapIds
})) {
if (this.animating) {
webgl2WarpedMap.mixPreviousAndNew(1 - this.animationProgress);
}
}
}
}
optionsChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.finishTransformerTransition(mapIds);
}
this.changed();
}
gcpsChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.finishTransformerTransition(mapIds);
}
this.changed();
}
resourceMaskChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.finishTransformerTransition(mapIds);
}
this.changed();
}
transformationChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.startTransformerTransition(mapIds);
}
}
distortionChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.startTransformerTransition(mapIds);
}
}
internalProjectionChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.startTransformerTransition(mapIds);
}
}
projectionChanged(event) {
if (event instanceof WarpedMapEvent) {
const mapIds = event.data;
this.finishTransformerTransition(mapIds);
}
this.changed();
}
addEventListenersToWebGL2WarpedMap(webgl2WarpedMap) {
webgl2WarpedMap.addEventListener(
WarpedMapEventType.TEXTURESUPDATED,
this.throttledChanged.bind(this)
);
}
removeEventListenersFromWebGL2WarpedMap(webgl2WarpedMap) {
webgl2WarpedMap.removeEventListener(
WarpedMapEventType.TEXTURESUPDATED,
this.throttledChanged.bind(this)
);
}
contextLost() {
this.disableRender = true;
this.cancelThrottledFunctions();
for (const webgl2WarpedMap of this.warpedMapList.getWarpedMaps()) {
webgl2WarpedMap.cancelThrottledFunctions();
}
this.tileCache.clear();
}
contextRestored() {
this.initializeWebGL(this.gl);
this.disableRender = false;
}
}
export {
WebGL2Renderer
};
//# sourceMappingURL=WebGL2Renderer.js.map