// @flow import IndexBuffer from './index_buffer'; import VertexBuffer from './vertex_buffer'; import Framebuffer from './framebuffer'; import DepthMode from './depth_mode'; import StencilMode from './stencil_mode'; import ColorMode from './color_mode'; import CullFaceMode from './cull_face_mode'; import {deepEqual} from '../util/util'; import {ClearColor, ClearDepth, ClearStencil, ColorMask, DepthMask, StencilMask, StencilFunc, StencilOp, StencilTest, DepthRange, DepthTest, DepthFunc, Blend, BlendFunc, BlendColor, BlendEquation, CullFace, CullFaceSide, FrontFace, Program, ActiveTextureUnit, Viewport, BindFramebuffer, BindRenderbuffer, BindTexture, BindVertexBuffer, BindElementBuffer, BindVertexArrayOES, PixelStoreUnpack, PixelStoreUnpackPremultiplyAlpha, PixelStoreUnpackFlipY} from './value'; import type {TriangleIndexArray, LineIndexArray, LineStripIndexArray} from '../data/index_array_type'; import type { StructArray, StructArrayMember } from '../util/struct_array'; import type Color from '../style-spec/util/color'; type ClearArgs = { color?: Color, depth?: number, stencil?: number }; class Context { gl: WebGLRenderingContext; extVertexArrayObject: any; currentNumAttributes: ?number; maxTextureSize: number; clearColor: ClearColor; clearDepth: ClearDepth; clearStencil: ClearStencil; colorMask: ColorMask; depthMask: DepthMask; stencilMask: StencilMask; stencilFunc: StencilFunc; stencilOp: StencilOp; stencilTest: StencilTest; depthRange: DepthRange; depthTest: DepthTest; depthFunc: DepthFunc; blend: Blend; blendFunc: BlendFunc; blendColor: BlendColor; blendEquation: BlendEquation; cullFace: CullFace; cullFaceSide: CullFaceSide; frontFace: FrontFace; program: Program; activeTexture: ActiveTextureUnit; viewport: Viewport; bindFramebuffer: BindFramebuffer; bindRenderbuffer: BindRenderbuffer; bindTexture: BindTexture; bindVertexBuffer: BindVertexBuffer; bindElementBuffer: BindElementBuffer; bindVertexArrayOES: BindVertexArrayOES; pixelStoreUnpack: PixelStoreUnpack; pixelStoreUnpackPremultiplyAlpha: PixelStoreUnpackPremultiplyAlpha; pixelStoreUnpackFlipY: PixelStoreUnpackFlipY; extTextureFilterAnisotropic: any; extTextureFilterAnisotropicMax: any; extTextureHalfFloat: any; extRenderToTextureHalfFloat: any; extTimerQuery: any; constructor(gl: WebGLRenderingContext) { this.gl = gl; this.extVertexArrayObject = this.gl.getExtension('OES_vertex_array_object'); this.clearColor = new ClearColor(this); this.clearDepth = new ClearDepth(this); this.clearStencil = new ClearStencil(this); this.colorMask = new ColorMask(this); this.depthMask = new DepthMask(this); this.stencilMask = new StencilMask(this); this.stencilFunc = new StencilFunc(this); this.stencilOp = new StencilOp(this); this.stencilTest = new StencilTest(this); this.depthRange = new DepthRange(this); this.depthTest = new DepthTest(this); this.depthFunc = new DepthFunc(this); this.blend = new Blend(this); this.blendFunc = new BlendFunc(this); this.blendColor = new BlendColor(this); this.blendEquation = new BlendEquation(this); this.cullFace = new CullFace(this); this.cullFaceSide = new CullFaceSide(this); this.frontFace = new FrontFace(this); this.program = new Program(this); this.activeTexture = new ActiveTextureUnit(this); this.viewport = new Viewport(this); this.bindFramebuffer = new BindFramebuffer(this); this.bindRenderbuffer = new BindRenderbuffer(this); this.bindTexture = new BindTexture(this); this.bindVertexBuffer = new BindVertexBuffer(this); this.bindElementBuffer = new BindElementBuffer(this); this.bindVertexArrayOES = this.extVertexArrayObject && new BindVertexArrayOES(this); this.pixelStoreUnpack = new PixelStoreUnpack(this); this.pixelStoreUnpackPremultiplyAlpha = new PixelStoreUnpackPremultiplyAlpha(this); this.pixelStoreUnpackFlipY = new PixelStoreUnpackFlipY(this); this.extTextureFilterAnisotropic = ( gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') ); if (this.extTextureFilterAnisotropic) { this.extTextureFilterAnisotropicMax = gl.getParameter(this.extTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT); } this.extTextureHalfFloat = gl.getExtension('OES_texture_half_float'); if (this.extTextureHalfFloat) { gl.getExtension('OES_texture_half_float_linear'); this.extRenderToTextureHalfFloat = gl.getExtension('EXT_color_buffer_half_float'); } this.extTimerQuery = gl.getExtension('EXT_disjoint_timer_query'); this.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); } setDefault() { this.unbindVAO(); this.clearColor.setDefault(); this.clearDepth.setDefault(); this.clearStencil.setDefault(); this.colorMask.setDefault(); this.depthMask.setDefault(); this.stencilMask.setDefault(); this.stencilFunc.setDefault(); this.stencilOp.setDefault(); this.stencilTest.setDefault(); this.depthRange.setDefault(); this.depthTest.setDefault(); this.depthFunc.setDefault(); this.blend.setDefault(); this.blendFunc.setDefault(); this.blendColor.setDefault(); this.blendEquation.setDefault(); this.cullFace.setDefault(); this.cullFaceSide.setDefault(); this.frontFace.setDefault(); this.program.setDefault(); this.activeTexture.setDefault(); this.bindFramebuffer.setDefault(); this.pixelStoreUnpack.setDefault(); this.pixelStoreUnpackPremultiplyAlpha.setDefault(); this.pixelStoreUnpackFlipY.setDefault(); } setDirty() { this.clearColor.dirty = true; this.clearDepth.dirty = true; this.clearStencil.dirty = true; this.colorMask.dirty = true; this.depthMask.dirty = true; this.stencilMask.dirty = true; this.stencilFunc.dirty = true; this.stencilOp.dirty = true; this.stencilTest.dirty = true; this.depthRange.dirty = true; this.depthTest.dirty = true; this.depthFunc.dirty = true; this.blend.dirty = true; this.blendFunc.dirty = true; this.blendColor.dirty = true; this.blendEquation.dirty = true; this.cullFace.dirty = true; this.cullFaceSide.dirty = true; this.frontFace.dirty = true; this.program.dirty = true; this.activeTexture.dirty = true; this.viewport.dirty = true; this.bindFramebuffer.dirty = true; this.bindRenderbuffer.dirty = true; this.bindTexture.dirty = true; this.bindVertexBuffer.dirty = true; this.bindElementBuffer.dirty = true; if (this.extVertexArrayObject) { this.bindVertexArrayOES.dirty = true; } this.pixelStoreUnpack.dirty = true; this.pixelStoreUnpackPremultiplyAlpha.dirty = true; this.pixelStoreUnpackFlipY.dirty = true; } createIndexBuffer(array: TriangleIndexArray | LineIndexArray | LineStripIndexArray, dynamicDraw?: boolean) { return new IndexBuffer(this, array, dynamicDraw); } createVertexBuffer(array: StructArray, attributes: $ReadOnlyArray, dynamicDraw?: boolean) { return new VertexBuffer(this, array, attributes, dynamicDraw); } createRenderbuffer(storageFormat: number, width: number, height: number) { const gl = this.gl; const rbo = gl.createRenderbuffer(); this.bindRenderbuffer.set(rbo); gl.renderbufferStorage(gl.RENDERBUFFER, storageFormat, width, height); this.bindRenderbuffer.set(null); return rbo; } createFramebuffer(width: number, height: number, hasDepth: boolean) { return new Framebuffer(this, width, height, hasDepth); } clear({color, depth}: ClearArgs) { const gl = this.gl; let mask = 0; if (color) { mask |= gl.COLOR_BUFFER_BIT; this.clearColor.set(color); this.colorMask.set([true, true, true, true]); } if (typeof depth !== 'undefined') { mask |= gl.DEPTH_BUFFER_BIT; // Workaround for platforms where clearDepth doesn't seem to work // without reseting the depthRange. See https://github.com/mapbox/mapbox-gl-js/issues/3437 this.depthRange.set([0, 1]); this.clearDepth.set(depth); this.depthMask.set(true); } // See note in Painter#clearStencil: implement this the easy way once GPU bug/workaround is fixed upstream // if (typeof stencil !== 'undefined') { // mask |= gl.STENCIL_BUFFER_BIT; // this.clearStencil.set(stencil); // this.stencilMask.set(0xFF); // } gl.clear(mask); } setCullFace(cullFaceMode: $ReadOnly) { if (cullFaceMode.enable === false) { this.cullFace.set(false); } else { this.cullFace.set(true); this.cullFaceSide.set(cullFaceMode.mode); this.frontFace.set(cullFaceMode.frontFace); } } setDepthMode(depthMode: $ReadOnly) { if (depthMode.func === this.gl.ALWAYS && !depthMode.mask) { this.depthTest.set(false); } else { this.depthTest.set(true); this.depthFunc.set(depthMode.func); this.depthMask.set(depthMode.mask); this.depthRange.set(depthMode.range); } } setStencilMode(stencilMode: $ReadOnly) { if (stencilMode.test.func === this.gl.ALWAYS && !stencilMode.mask) { this.stencilTest.set(false); } else { this.stencilTest.set(true); this.stencilMask.set(stencilMode.mask); this.stencilOp.set([stencilMode.fail, stencilMode.depthFail, stencilMode.pass]); this.stencilFunc.set({ func: stencilMode.test.func, ref: stencilMode.ref, mask: stencilMode.test.mask }); } } setColorMode(colorMode: $ReadOnly) { if (deepEqual(colorMode.blendFunction, ColorMode.Replace)) { this.blend.set(false); } else { this.blend.set(true); this.blendFunc.set(colorMode.blendFunction); this.blendColor.set(colorMode.blendColor); } this.colorMask.set(colorMode.mask); } unbindVAO() { // Unbinding the VAO prevents other things (custom layers, new buffer creation) from // unintentionally changing the state of the last VAO used. if (this.extVertexArrayObject) { this.bindVertexArrayOES.set(null); } } } export default Context;