/** * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ import { GLRenderingContext } from './compat'; export type WebGLState = { currentProgramId: number currentMaterialId: number currentRenderItemId: number /** * specifies which WebGL capability to enable * - `gl.BLEND`: blending of the computed fragment color values * - `gl.CULL_FACE`: culling of polygons * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer * - `gl.DITHER`: dithering of color components before they get written to the color buffer * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer */ enable: (cap: number) => void /** * specifies which WebGL capability to disable * - `gl.BLEND`: blending of the computed fragment color values * - `gl.CULL_FACE`: culling of polygons * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer * - `gl.DITHER`: dithering of color components before they get written to the color buffer * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer */ disable: (cap: number) => void /** specifies whether polygons are front- or back-facing by setting a winding orientation */ frontFace: (mode: number) => void /** specifies whether or not front- and/or back-facing polygons can be culled */ cullFace: (mode: number) => void /** sets whether writing into the depth buffer is enabled or disabled */ depthMask: (flag: boolean) => void /** sets which color components to enable or to disable */ colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => void /** specifies the color values used when clearing color buffers, used when calling `gl.clear`, clamped to [0, 1] */ clearColor: (red: number, green: number, blue: number, alpha: number) => void /** defines which function is used for blending pixel arithmetic */ blendFunc: (src: number, dst: number) => void /** defines which function is used for blending pixel arithmetic for RGB and alpha components separately */ blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void /** set both the RGB blend equation and alpha blend equation to a single equation, determines how a new pixel is combined with an existing */ blendEquation: (mode: number) => void /** set the RGB blend equation and alpha blend equation separately, determines how a new pixel is combined with an existing */ blendEquationSeparate: (modeRGB: number, modeAlpha: number) => void } export function createState(gl: GLRenderingContext): WebGLState { const enabledCapabilities: { [k: number]: boolean } = {} let currentFrontFace = gl.getParameter(gl.FRONT_FACE) let currentCullFace = gl.getParameter(gl.CULL_FACE_MODE) let currentDepthMask = gl.getParameter(gl.DEPTH_WRITEMASK) let currentColorMask = gl.getParameter(gl.COLOR_WRITEMASK) let currentClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE) let currentBlendSrcRGB = gl.getParameter(gl.BLEND_SRC_RGB) let currentBlendDstRGB = gl.getParameter(gl.BLEND_DST_RGB) let currentBlendSrcAlpha = gl.getParameter(gl.BLEND_SRC_ALPHA) let currentBlendDstAlpha = gl.getParameter(gl.BLEND_DST_ALPHA) let currentBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB) let currentBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA) return { currentProgramId: -1, currentMaterialId: -1, currentRenderItemId: -1, enable: (cap: number) => { if (enabledCapabilities[cap] !== true ) { gl.enable(cap) enabledCapabilities[cap] = true } }, disable: (cap: number) => { if (enabledCapabilities[cap] !== false) { gl.disable(cap) enabledCapabilities[cap] = false } }, frontFace: (mode: number) => { if (mode !== currentFrontFace) { gl.frontFace(mode) currentFrontFace = mode } }, cullFace: (mode: number) => { if (mode !== currentCullFace) { gl.cullFace(mode) currentCullFace = mode } }, depthMask: (flag: boolean) => { if (flag !== currentDepthMask) { gl.depthMask(flag) currentDepthMask = flag } }, colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => { if (red !== currentColorMask[0] || green !== currentColorMask[1] || blue !== currentColorMask[2] || alpha !== currentColorMask[3]) { gl.colorMask(red, green, blue, alpha) currentColorMask[0] = red currentColorMask[1] = green currentColorMask[2] = blue currentColorMask[3] = alpha } }, clearColor: (red: number, green: number, blue: number, alpha: number) => { if (red !== currentClearColor[0] || green !== currentClearColor[1] || blue !== currentClearColor[2] || alpha !== currentClearColor[3]) { gl.clearColor(red, green, blue, alpha) currentClearColor[0] = red currentClearColor[1] = green currentClearColor[2] = blue currentClearColor[3] = alpha } }, blendFunc: (src: number, dst: number) => { if (src !== currentBlendSrcRGB || dst !== currentBlendDstRGB || src !== currentBlendSrcAlpha || dst !== currentBlendDstAlpha) { gl.blendFunc(src, dst) currentBlendSrcRGB = src currentBlendDstRGB = dst currentBlendSrcAlpha = src currentBlendDstAlpha = dst } }, blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => { if (srcRGB !== currentBlendSrcRGB || dstRGB !== currentBlendDstRGB || srcAlpha !== currentBlendSrcAlpha || dstAlpha !== currentBlendDstAlpha) { gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) currentBlendSrcRGB = srcRGB currentBlendDstRGB = dstRGB currentBlendSrcAlpha = srcAlpha currentBlendDstAlpha = dstAlpha } }, blendEquation: (mode: number) => { if (mode !== currentBlendEqRGB || mode !== currentBlendEqAlpha) { gl.blendEquation(mode) currentBlendEqRGB = mode currentBlendEqAlpha = mode } }, blendEquationSeparate: (modeRGB: number, modeAlpha: number) => { if (modeRGB !== currentBlendEqRGB || modeAlpha !== currentBlendEqAlpha) { gl.blendEquationSeparate(modeRGB, modeAlpha) currentBlendEqRGB = modeRGB currentBlendEqAlpha = modeAlpha } } } }