UNPKG

@itwin/core-frontend

Version:
342 lines • 12.4 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module WebGL */ import { GL } from "./GL"; import { System } from "./System"; /** @internal */ export class RenderStateFlags { cull = false; depthTest = false; blend = false; stencilTest = false; depthMask = true; colorWrite = true; constructor(src) { if (src) { this.copyFrom(src); } } copyFrom(src) { this.cull = src.cull; this.depthTest = src.depthTest; this.blend = src.blend; this.stencilTest = src.stencilTest; this.depthMask = src.depthMask; this.colorWrite = src.colorWrite; } clone(result) { if (!result) { return new RenderStateFlags(this); } else { result.copyFrom(this); return result; } } equals(rhs) { return this.cull === rhs.cull && this.depthTest === rhs.depthTest && this.blend === rhs.blend && this.stencilTest === rhs.stencilTest && this.depthMask === rhs.depthMask && this.colorWrite === rhs.colorWrite; } apply(previousFlags) { RenderStateFlags.enableOrDisable(this.cull, GL.Capability.CullFace, previousFlags.cull); RenderStateFlags.enableOrDisable(this.depthTest, GL.Capability.DepthTest, previousFlags.depthTest); RenderStateFlags.enableOrDisable(this.blend, GL.Capability.Blend, previousFlags.blend); RenderStateFlags.enableOrDisable(this.stencilTest, GL.Capability.StencilTest, previousFlags.stencilTest); if (previousFlags.depthMask !== this.depthMask) { System.instance.context.depthMask(this.depthMask); } if (previousFlags.colorWrite !== this.colorWrite) { System.instance.context.colorMask(this.colorWrite, this.colorWrite, this.colorWrite, this.colorWrite); } } static enableOrDisable(currentFlag, value, previousFlag) { if (currentFlag !== previousFlag) { const gl = System.instance.context; if (currentFlag) { gl.enable(value); } else { gl.disable(value); } } } } /** @internal */ export class RenderStateBlend { color = [0.0, 0.0, 0.0, 0.0]; equationRgb = GL.BlendEquation.Default; equationAlpha = GL.BlendEquation.Default; functionSourceRgb = GL.BlendFactor.DefaultSrc; functionSourceAlpha = GL.BlendFactor.DefaultSrc; functionDestRgb = GL.BlendFactor.DefaultDst; functionDestAlpha = GL.BlendFactor.DefaultDst; constructor(src) { if (src) { this.copyFrom(src); } } apply(previousBlend) { const gl = System.instance.context; if (previousBlend === undefined || !this.equalColors(previousBlend)) { gl.blendColor(this.color[0], this.color[1], this.color[2], this.color[3]); } if (previousBlend === undefined || previousBlend.equationRgb !== this.equationRgb || previousBlend.equationAlpha !== this.equationAlpha) { gl.blendEquationSeparate(this.equationRgb, this.equationAlpha); } if (previousBlend === undefined || previousBlend.functionSourceRgb !== this.functionSourceRgb || previousBlend.functionSourceAlpha !== this.functionSourceAlpha || previousBlend.functionDestRgb !== this.functionDestRgb || previousBlend.functionDestAlpha !== this.functionDestAlpha) { gl.blendFuncSeparate(this.functionSourceRgb, this.functionDestRgb, this.functionSourceAlpha, this.functionDestAlpha); } } copyFrom(src) { this.setColor(src.color); this.equationRgb = src.equationRgb; this.equationAlpha = src.equationAlpha; this.functionSourceRgb = src.functionSourceRgb; this.functionSourceAlpha = src.functionSourceAlpha; this.functionDestRgb = src.functionDestRgb; this.functionDestAlpha = src.functionDestAlpha; } clone(result) { if (!result) { return new RenderStateBlend(this); } else { result.copyFrom(this); return result; } } equals(rhs) { return this.equalColors(rhs) && this.equationRgb === rhs.equationRgb && this.equationAlpha === rhs.equationAlpha && this.functionSourceRgb === rhs.functionSourceRgb && this.functionSourceAlpha === rhs.functionSourceAlpha && this.functionDestRgb === rhs.functionDestRgb && this.functionDestAlpha === rhs.functionDestAlpha; } equalColors(rhs) { return this.color[0] === rhs.color[0] && this.color[1] === rhs.color[1] && this.color[2] === rhs.color[2] && this.color[3] === rhs.color[3]; } setColor(color) { this.color[0] = color[0]; this.color[1] = color[1]; this.color[2] = color[2]; this.color[3] = color[3]; } setBlendFunc(src, dst) { this.setBlendFuncSeparate(src, src, dst, dst); } setBlendFuncSeparate(srcRgb, srcAlpha, dstRgb, dstAlpha) { this.functionSourceRgb = srcRgb; this.functionSourceAlpha = srcAlpha; this.functionDestRgb = dstRgb; this.functionDestAlpha = dstAlpha; } } /** @internal */ export class RenderStateStencilOperation { fail = GL.StencilOperation.Default; zFail = GL.StencilOperation.Default; zPass = GL.StencilOperation.Default; constructor(src) { if (src) { this.copyFrom(src); } } copyFrom(src) { this.fail = src.fail; this.zFail = src.zFail; this.zPass = src.zPass; } clone(result) { if (!result) { return new RenderStateStencilOperation(this); } else { result.copyFrom(this); return result; } } equals(rhs) { return this.fail === rhs.fail && this.zFail === rhs.zFail && this.zPass === rhs.zPass; } } /** @internal */ export class RenderStateStencilFunction { function = GL.StencilFunction.Default; ref = 0; mask = 0xFFFFFFFF; constructor(src) { if (src) { this.copyFrom(src); } } copyFrom(src) { this.function = src.function; this.ref = src.ref; this.mask = src.mask; } clone(result) { if (!result) { return new RenderStateStencilFunction(this); } else { result.copyFrom(this); return result; } } equals(rhs) { return this.function === rhs.function && this.ref === rhs.ref && this.mask === rhs.mask; } } /** @internal */ export class RenderStateStencil { frontFunction = new RenderStateStencilFunction(); backFunction = new RenderStateStencilFunction(); frontOperation = new RenderStateStencilOperation(); backOperation = new RenderStateStencilOperation(); constructor(src) { if (src) { this.copyFrom(src); } } apply(previousStencil) { const gl = System.instance.context; if (previousStencil === undefined || !previousStencil.frontFunction.equals(this.frontFunction)) { gl.stencilFuncSeparate(GL.CullFace.Front, this.frontFunction.function, this.frontFunction.ref, this.frontFunction.mask); } if (previousStencil === undefined || !previousStencil.backFunction.equals(this.backFunction)) { gl.stencilFuncSeparate(GL.CullFace.Back, this.backFunction.function, this.backFunction.ref, this.backFunction.mask); } if (previousStencil === undefined || !previousStencil.frontOperation.equals(this.frontOperation)) { gl.stencilOpSeparate(GL.CullFace.Front, this.frontOperation.fail, this.frontOperation.zFail, this.frontOperation.zPass); } if (previousStencil === undefined || !previousStencil.backOperation.equals(this.backOperation)) { gl.stencilOpSeparate(GL.CullFace.Back, this.backOperation.fail, this.backOperation.zFail, this.backOperation.zPass); } } copyFrom(src) { this.frontFunction.copyFrom(src.frontFunction); this.backFunction.copyFrom(src.backFunction); this.frontOperation.copyFrom(src.frontOperation); this.backOperation.copyFrom(src.backOperation); } clone(result) { if (!result) { return new RenderStateStencil(this); } else { result.copyFrom(this); return result; } } equals(rhs) { return this.frontFunction.equals(rhs.frontFunction) && this.backFunction.equals(rhs.backFunction) && this.frontOperation.equals(rhs.frontOperation) && this.backOperation.equals(rhs.backOperation); } } /** Encapsulates the state of an OpenGL context. * to modify the context for a rendering operation, do *not* directly call * functions like glDepthMask(), glBlendFunc(), etc - otherwise such calls may adversely * affect subsequent rendering operations. * Instead, set up a RenderState as desired and invoke System.instance.applyRenderState() * The context tracks the most-recently applied RenderState, allowing it to minimize * the number of GL state changes actually invoked, improving performance. * @internal */ export class RenderState { flags = new RenderStateFlags(); blend = new RenderStateBlend(); stencil = new RenderStateStencil(); frontFace = GL.FrontFace.Default; cullFace = GL.CullFace.Default; depthFunc = GL.DepthFunc.Default; stencilMask = 0xFFFFFFFF; constructor(src) { if (src) { this.copyFrom(src); } } static defaults = new RenderState(); copyFrom(src) { this.flags.copyFrom(src.flags); this.blend.copyFrom(src.blend); this.stencil.copyFrom(src.stencil); this.frontFace = src.frontFace; this.cullFace = src.cullFace; this.depthFunc = src.depthFunc; this.stencilMask = src.stencilMask; } clone(result) { if (!result) { return new RenderState(this); } else { result.copyFrom(this); return result; } } set clockwiseFrontFace(clockwise) { this.frontFace = clockwise ? GL.FrontFace.Clockwise : GL.FrontFace.CounterClockwise; } equals(rhs) { return this.flags.equals(rhs.flags) && this.blend.equals(rhs.blend) && this.stencil.equals(rhs.stencil) && this.frontFace === rhs.frontFace && this.cullFace === rhs.cullFace && this.depthFunc === rhs.depthFunc && this.stencilMask === rhs.stencilMask; } apply(prevState) { this.flags.apply(prevState.flags); if (this.flags.blend) { if (prevState.flags.blend) this.blend.apply(prevState.blend); else this.blend.apply(); } if (this.flags.cull) { if (!prevState.flags.cull || prevState.cullFace !== this.cullFace) { System.instance.context.cullFace(this.cullFace); } } if (this.flags.depthTest) { if (!prevState.flags.depthTest || prevState.depthFunc !== this.depthFunc) { System.instance.context.depthFunc(this.depthFunc); } } if (this.flags.stencilTest) { if (prevState.flags.stencilTest) this.stencil.apply(prevState.stencil); else this.stencil.apply(); } if (this.frontFace !== prevState.frontFace) { System.instance.context.frontFace(this.frontFace); } if (this.stencilMask !== prevState.stencilMask) { System.instance.context.stencilMask(this.stencilMask); } } } Object.freeze(RenderState.defaults); //# sourceMappingURL=RenderState.js.map