UNPKG

maplibre-gl

Version:

BSD licensed community fork of mapbox-gl, a WebGL interactive maps library

519 lines (476 loc) 13.7 kB
import Color from '../style-spec/util/color'; import type Context from './context'; import type { BlendFuncType, BlendEquationType, ColorMaskType, DepthRangeType, DepthMaskType, StencilFuncType, StencilOpType, DepthFuncType, TextureUnitType, ViewportType, CullFaceModeType, FrontFaceType, } from './types'; export interface IValue<T> { current: T; default: T; dirty: boolean; get(): T; setDefault(): void; set(value: T): void; } class BaseValue<T> implements IValue<T> { gl: WebGLRenderingContext; current: T; default: T; dirty: boolean; constructor(context: Context) { this.gl = context.gl; this.default = this.getDefault(); this.current = this.default; this.dirty = false; } get(): T { return this.current; } set(value: T) { // eslint-disable-line // overridden in child classes; } getDefault(): T { return this.default; // overriden in child classes } setDefault() { this.set(this.default); } } export class ClearColor extends BaseValue<Color> { getDefault(): Color { return Color.transparent; } set(v: Color) { const c = this.current; if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty) return; this.gl.clearColor(v.r, v.g, v.b, v.a); this.current = v; this.dirty = false; } } export class ClearDepth extends BaseValue<number> { getDefault(): number { return 1; } set(v: number) { if (v === this.current && !this.dirty) return; this.gl.clearDepth(v); this.current = v; this.dirty = false; } } export class ClearStencil extends BaseValue<number> { getDefault(): number { return 0; } set(v: number) { if (v === this.current && !this.dirty) return; this.gl.clearStencil(v); this.current = v; this.dirty = false; } } export class ColorMask extends BaseValue<ColorMaskType> { getDefault(): ColorMaskType { return [true, true, true, true]; } set(v: ColorMaskType) { const c = this.current; if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return; this.gl.colorMask(v[0], v[1], v[2], v[3]); this.current = v; this.dirty = false; } } export class DepthMask extends BaseValue<DepthMaskType> { getDefault(): DepthMaskType { return true; } set(v: DepthMaskType): void { if (v === this.current && !this.dirty) return; this.gl.depthMask(v); this.current = v; this.dirty = false; } } export class StencilMask extends BaseValue<number> { getDefault(): number { return 0xFF; } set(v: number): void { if (v === this.current && !this.dirty) return; this.gl.stencilMask(v); this.current = v; this.dirty = false; } } export class StencilFunc extends BaseValue<StencilFuncType> { getDefault(): StencilFuncType { return { func: this.gl.ALWAYS, ref: 0, mask: 0xFF }; } set(v: StencilFuncType): void { const c = this.current; if (v.func === c.func && v.ref === c.ref && v.mask === c.mask && !this.dirty) return; this.gl.stencilFunc(v.func, v.ref, v.mask); this.current = v; this.dirty = false; } } export class StencilOp extends BaseValue<StencilOpType> { getDefault(): StencilOpType { const gl = this.gl; return [gl.KEEP, gl.KEEP, gl.KEEP]; } set(v: StencilOpType) { const c = this.current; if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && !this.dirty) return; this.gl.stencilOp(v[0], v[1], v[2]); this.current = v; this.dirty = false; } } export class StencilTest extends BaseValue<boolean> { getDefault(): boolean { return false; } set(v: boolean) { if (v === this.current && !this.dirty) return; const gl = this.gl; if (v) { gl.enable(gl.STENCIL_TEST); } else { gl.disable(gl.STENCIL_TEST); } this.current = v; this.dirty = false; } } export class DepthRange extends BaseValue<DepthRangeType> { getDefault(): DepthRangeType { return [0, 1]; } set(v: DepthRangeType) { const c = this.current; if (v[0] === c[0] && v[1] === c[1] && !this.dirty) return; this.gl.depthRange(v[0], v[1]); this.current = v; this.dirty = false; } } export class DepthTest extends BaseValue<boolean> { getDefault(): boolean { return false; } set(v: boolean) { if (v === this.current && !this.dirty) return; const gl = this.gl; if (v) { gl.enable(gl.DEPTH_TEST); } else { gl.disable(gl.DEPTH_TEST); } this.current = v; this.dirty = false; } } export class DepthFunc extends BaseValue<DepthFuncType> { getDefault(): DepthFuncType { return this.gl.LESS; } set(v: DepthFuncType) { if (v === this.current && !this.dirty) return; this.gl.depthFunc(v); this.current = v; this.dirty = false; } } export class Blend extends BaseValue<boolean> { getDefault(): boolean { return false; } set(v: boolean) { if (v === this.current && !this.dirty) return; const gl = this.gl; if (v) { gl.enable(gl.BLEND); } else { gl.disable(gl.BLEND); } this.current = v; this.dirty = false; } } export class BlendFunc extends BaseValue<BlendFuncType> { getDefault(): BlendFuncType { const gl = this.gl; return [gl.ONE, gl.ZERO]; } set(v: BlendFuncType) { const c = this.current; if (v[0] === c[0] && v[1] === c[1] && !this.dirty) return; this.gl.blendFunc(v[0], v[1]); this.current = v; this.dirty = false; } } export class BlendColor extends BaseValue<Color> { getDefault(): Color { return Color.transparent; } set(v: Color) { const c = this.current; if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty) return; this.gl.blendColor(v.r, v.g, v.b, v.a); this.current = v; this.dirty = false; } } export class BlendEquation extends BaseValue<BlendEquationType> { getDefault(): BlendEquationType { return this.gl.FUNC_ADD; } set(v: BlendEquationType) { if (v === this.current && !this.dirty) return; this.gl.blendEquation(v); this.current = v; this.dirty = false; } } export class CullFace extends BaseValue<boolean> { getDefault(): boolean { return false; } set(v: boolean) { if (v === this.current && !this.dirty) return; const gl = this.gl; if (v) { gl.enable(gl.CULL_FACE); } else { gl.disable(gl.CULL_FACE); } this.current = v; this.dirty = false; } } export class CullFaceSide extends BaseValue<CullFaceModeType> { getDefault(): CullFaceModeType { return this.gl.BACK; } set(v: CullFaceModeType) { if (v === this.current && !this.dirty) return; this.gl.cullFace(v); this.current = v; this.dirty = false; } } export class FrontFace extends BaseValue<FrontFaceType> { getDefault(): FrontFaceType { return this.gl.CCW; } set(v: FrontFaceType) { if (v === this.current && !this.dirty) return; this.gl.frontFace(v); this.current = v; this.dirty = false; } } export class ProgramValue extends BaseValue<WebGLProgram> { getDefault(): WebGLProgram { return null; } set(v?: WebGLProgram | null) { if (v === this.current && !this.dirty) return; this.gl.useProgram(v); this.current = v; this.dirty = false; } } export class ActiveTextureUnit extends BaseValue<TextureUnitType> { getDefault(): TextureUnitType { return this.gl.TEXTURE0; } set(v: TextureUnitType) { if (v === this.current && !this.dirty) return; this.gl.activeTexture(v); this.current = v; this.dirty = false; } } export class Viewport extends BaseValue<ViewportType> { getDefault(): ViewportType { const gl = this.gl; return [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]; } set(v: ViewportType) { const c = this.current; if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return; this.gl.viewport(v[0], v[1], v[2], v[3]); this.current = v; this.dirty = false; } } export class BindFramebuffer extends BaseValue<WebGLFramebuffer> { getDefault(): WebGLFramebuffer { return null; } set(v?: WebGLFramebuffer | null) { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, v); this.current = v; this.dirty = false; } } export class BindRenderbuffer extends BaseValue<WebGLRenderbuffer> { getDefault(): WebGLRenderbuffer { return null; } set(v?: WebGLRenderbuffer | null) { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.bindRenderbuffer(gl.RENDERBUFFER, v); this.current = v; this.dirty = false; } } export class BindTexture extends BaseValue<WebGLTexture> { getDefault(): WebGLTexture { return null; } set(v?: WebGLTexture | null) { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.bindTexture(gl.TEXTURE_2D, v); this.current = v; this.dirty = false; } } export class BindVertexBuffer extends BaseValue<WebGLBuffer> { getDefault(): WebGLBuffer { return null; } set(v?: WebGLBuffer | null) { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.bindBuffer(gl.ARRAY_BUFFER, v); this.current = v; this.dirty = false; } } export class BindElementBuffer extends BaseValue<WebGLBuffer> { getDefault(): WebGLBuffer { return null; } set(v?: WebGLBuffer | null) { // Always rebind const gl = this.gl; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, v); this.current = v; this.dirty = false; } } export class BindVertexArrayOES extends BaseValue<any> { vao: any; constructor(context: Context) { super(context); this.vao = context.extVertexArrayObject; } getDefault(): any { return null; } set(v: any) { if (!this.vao || v === this.current && !this.dirty) return; this.vao.bindVertexArrayOES(v); this.current = v; this.dirty = false; } } export class PixelStoreUnpack extends BaseValue<number> { getDefault(): number { return 4; } set(v: number) { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.pixelStorei(gl.UNPACK_ALIGNMENT, v); this.current = v; this.dirty = false; } } export class PixelStoreUnpackPremultiplyAlpha extends BaseValue<boolean> { getDefault(): boolean { return false; } set(v: boolean): void { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, ((v as any))); this.current = v; this.dirty = false; } } export class PixelStoreUnpackFlipY extends BaseValue<boolean> { getDefault(): boolean { return false; } set(v: boolean): void { if (v === this.current && !this.dirty) return; const gl = this.gl; gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, ((v as any))); this.current = v; this.dirty = false; } } class FramebufferAttachment<T> extends BaseValue<T> { parent: WebGLFramebuffer; context: Context; constructor(context: Context, parent: WebGLFramebuffer) { super(context); this.context = context; this.parent = parent; } getDefault() { return null; } } export class ColorAttachment extends FramebufferAttachment<WebGLTexture> { setDirty() { this.dirty = true; } set(v?: WebGLTexture | null): void { if (v === this.current && !this.dirty) return; this.context.bindFramebuffer.set(this.parent); // note: it's possible to attach a renderbuffer to the color // attachment point, but thus far MBGL only uses textures for color const gl = this.gl; gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, v, 0); this.current = v; this.dirty = false; } } export class DepthAttachment extends FramebufferAttachment<WebGLRenderbuffer> { set(v?: WebGLRenderbuffer | null): void { if (v === this.current && !this.dirty) return; this.context.bindFramebuffer.set(this.parent); // note: it's possible to attach a texture to the depth attachment // point, but thus far MBGL only uses renderbuffers for depth const gl = this.gl; gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, v); this.current = v; this.dirty = false; } }