maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
108 lines (88 loc) • 4.01 kB
text/typescript
import type {Context} from '../../webgl/context.ts';
import type {CanonicalTileID} from '../../tile/tile_id.ts';
import {type Mesh} from '../../render/mesh.ts';
import {SubdivisionGranularityExpression, SubdivisionGranularitySetting} from '../../render/subdivision_granularity_settings.ts';
import type {Projection, TileMeshUsage} from './projection.ts';
import {type PreparedShader, shaders} from '../../shaders/shaders.ts';
import {createTileMeshWithBuffers, type CreateTileMeshOptions} from '../../util/create_tile_mesh.ts';
import {type EvaluationParameters} from '../../style/evaluation_parameters.ts';
export const VerticalPerspectiveShaderDefine = '#define GLOBE';
export const VerticalPerspectiveShaderVariantKey = 'globe';
const granularitySettingsGlobe: SubdivisionGranularitySetting = new SubdivisionGranularitySetting({
fill: new SubdivisionGranularityExpression(128, 2),
line: new SubdivisionGranularityExpression(512, 0),
// Always keep at least some subdivision on raster tiles, etc,
// otherwise they will be visibly warped at high zooms (before mercator transition).
// This si not needed on fill, because fill geometry tends to already be
// highly tessellated and granular at high zooms.
tile: new SubdivisionGranularityExpression(128, 32),
// Stencil granularity must never be higher than fill granularity,
// otherwise we would get seams in the oceans at zoom levels where
// stencil has higher granularity than fill.
stencil: new SubdivisionGranularityExpression(128, 1),
circle: 3
});
export class VerticalPerspectiveProjection implements Projection {
private _tileMeshCache: {[_: string]: Mesh} = {};
get name(): 'vertical-perspective' {
return 'vertical-perspective';
}
get transitionState(): number {
return 1;
}
get useSubdivision(): boolean {
return true;
}
get shaderVariantName(): string {
return VerticalPerspectiveShaderVariantKey;
}
get shaderDefine(): string {
return VerticalPerspectiveShaderDefine;
}
get shaderPreludeCode(): PreparedShader {
return shaders.projectionGlobe;
}
get vertexShaderPreludeCode(): string {
return shaders.projectionMercator.vertexSource;
}
get subdivisionGranularity(): SubdivisionGranularitySetting {
return granularitySettingsGlobe;
}
get useGlobeControls(): boolean {
return true;
}
public destroy(): void {
// Do nothing.
}
private _getMeshKey(options: CreateTileMeshOptions): string {
return `${options.granularity.toString(36)}_${options.generateBorders ? 'b' : ''}${options.extendToNorthPole ? 'n' : ''}${options.extendToSouthPole ? 's' : ''}`;
}
public getMeshFromTileID(context: Context, canonical: CanonicalTileID, hasBorder: boolean, allowPoles: boolean, usage: TileMeshUsage): Mesh {
// Stencil granularity must match fill granularity
const granularityConfig = usage === 'stencil' ? granularitySettingsGlobe.stencil : granularitySettingsGlobe.tile;
const granularity = granularityConfig.getGranularityForZoomLevel(canonical.z);
const north = (canonical.y === 0) && allowPoles;
const south = (canonical.y === (1 << canonical.z) - 1) && allowPoles;
return this._getMesh(context, {
granularity,
generateBorders: hasBorder,
extendToNorthPole: north,
extendToSouthPole: south,
});
}
private _getMesh(context: Context, options: CreateTileMeshOptions): Mesh {
const key = this._getMeshKey(options);
if (key in this._tileMeshCache) {
return this._tileMeshCache[key];
}
const mesh = createTileMeshWithBuffers(context, options);
this._tileMeshCache[key] = mesh;
return mesh;
}
recalculate(_params: EvaluationParameters): void {
// Do nothing.
}
hasTransition(): boolean {
return false;
}
}