UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

230 lines (227 loc) 9.13 kB
import { BitPacking } from '../../core/math/bit-packing.js'; import { BLENDEQUATION_ADD, BLENDMODE_ONE, BLENDMODE_ZERO, BLENDMODE_SRC_ALPHA, BLENDMODE_ONE_MINUS_SRC_ALPHA } from './constants.js'; // masks (to only keep relevant bits) const opMask = 0b111; const factorMask = 0b1111; // shifts values to where individual parts are stored const colorOpShift = 0; // 00 - 02 (3bits) const colorSrcFactorShift = 3; // 03 - 06 (4bits) const colorDstFactorShift = 7; // 07 - 10 (4bits) const alphaOpShift = 11; // 11 - 13 (3bits) const alphaSrcFactorShift = 14; // 14 - 17 (4bits) const alphaDstFactorShift = 18; // 18 - 21 (4bits) const redWriteShift = 22; // 22 (1 bit) const greenWriteShift = 23; // 23 (1 bit) const blueWriteShift = 24; // 24 (1 bit) const alphaWriteShift = 25; // 25 (1 bit) const blendShift = 26; // 26 (1 bit) // combined values access const allWriteMasks = 0b1111; const allWriteShift = redWriteShift; /** * BlendState is a descriptor that defines how output of fragment shader is written and blended * into render target. A blend state can be set on a material using {@link Material#blendState}, * or in some cases on the graphics device using {@link GraphicsDevice#setBlendState}. * * For the best performance, do not modify blend state after it has been created, but create * multiple blend states and assign them to the material or graphics device as needed. * * @category Graphics */ class BlendState { /** * Create a new BlendState instance. * * All factor parameters can take the following values: * * - {@link BLENDMODE_ZERO} * - {@link BLENDMODE_ONE} * - {@link BLENDMODE_SRC_COLOR} * - {@link BLENDMODE_ONE_MINUS_SRC_COLOR} * - {@link BLENDMODE_DST_COLOR} * - {@link BLENDMODE_ONE_MINUS_DST_COLOR} * - {@link BLENDMODE_SRC_ALPHA} * - {@link BLENDMODE_SRC_ALPHA_SATURATE} * - {@link BLENDMODE_ONE_MINUS_SRC_ALPHA} * - {@link BLENDMODE_DST_ALPHA} * - {@link BLENDMODE_ONE_MINUS_DST_ALPHA} * - {@link BLENDMODE_CONSTANT} * - {@link BLENDMODE_ONE_MINUS_CONSTANT} * * All op parameters can take the following values: * * - {@link BLENDEQUATION_ADD} * - {@link BLENDEQUATION_SUBTRACT} * - {@link BLENDEQUATION_REVERSE_SUBTRACT} * - {@link BLENDEQUATION_MIN} * - {@link BLENDEQUATION_MAX} * * @param {boolean} [blend] - Enables or disables blending. Defaults to false. * @param {number} [colorOp] - Configures color blending operation. Defaults to * {@link BLENDEQUATION_ADD}. * @param {number} [colorSrcFactor] - Configures source color blending factor. Defaults to * {@link BLENDMODE_ONE}. * @param {number} [colorDstFactor] - Configures destination color blending factor. Defaults to * {@link BLENDMODE_ZERO}. * @param {number} [alphaOp] - Configures alpha blending operation. Defaults to * {@link BLENDEQUATION_ADD}. * @param {number} [alphaSrcFactor] - Configures source alpha blending factor. Defaults to * {@link BLENDMODE_ONE}. * @param {number} [alphaDstFactor] - Configures destination alpha blending factor. Defaults to * {@link BLENDMODE_ZERO}. * @param {boolean} [redWrite] - True to enable writing of the red channel and false otherwise. * Defaults to true. * @param {boolean} [greenWrite] - True to enable writing of the green channel and false * otherwise. Defaults to true. * @param {boolean} [blueWrite] - True to enable writing of the blue channel and false otherwise. * Defaults to true. * @param {boolean} [alphaWrite] - True to enable writing of the alpha channel and false * otherwise. Defaults to true. */ constructor(blend = false, colorOp = BLENDEQUATION_ADD, colorSrcFactor = BLENDMODE_ONE, colorDstFactor = BLENDMODE_ZERO, alphaOp, alphaSrcFactor, alphaDstFactor, redWrite = true, greenWrite = true, blueWrite = true, alphaWrite = true){ /** * Bit field representing the blend state for render target 0. * * @private */ this.target0 = 0; this.setColorBlend(colorOp, colorSrcFactor, colorDstFactor); this.setAlphaBlend(alphaOp ?? colorOp, alphaSrcFactor ?? colorSrcFactor, alphaDstFactor ?? colorDstFactor); this.setColorWrite(redWrite, greenWrite, blueWrite, alphaWrite); this.blend = blend; } /** * Sets whether blending is enabled. * * @type {boolean} */ set blend(value) { this.target0 = BitPacking.set(this.target0, value ? 1 : 0, blendShift); } /** * Gets whether blending is enabled. * * @type {boolean} */ get blend() { return BitPacking.all(this.target0, blendShift); } setColorBlend(op, srcFactor, dstFactor) { this.target0 = BitPacking.set(this.target0, op, colorOpShift, opMask); this.target0 = BitPacking.set(this.target0, srcFactor, colorSrcFactorShift, factorMask); this.target0 = BitPacking.set(this.target0, dstFactor, colorDstFactorShift, factorMask); } setAlphaBlend(op, srcFactor, dstFactor) { this.target0 = BitPacking.set(this.target0, op, alphaOpShift, opMask); this.target0 = BitPacking.set(this.target0, srcFactor, alphaSrcFactorShift, factorMask); this.target0 = BitPacking.set(this.target0, dstFactor, alphaDstFactorShift, factorMask); } setColorWrite(redWrite, greenWrite, blueWrite, alphaWrite) { this.redWrite = redWrite; this.greenWrite = greenWrite; this.blueWrite = blueWrite; this.alphaWrite = alphaWrite; } get colorOp() { return BitPacking.get(this.target0, colorOpShift, opMask); } get colorSrcFactor() { return BitPacking.get(this.target0, colorSrcFactorShift, factorMask); } get colorDstFactor() { return BitPacking.get(this.target0, colorDstFactorShift, factorMask); } get alphaOp() { return BitPacking.get(this.target0, alphaOpShift, opMask); } get alphaSrcFactor() { return BitPacking.get(this.target0, alphaSrcFactorShift, factorMask); } get alphaDstFactor() { return BitPacking.get(this.target0, alphaDstFactorShift, factorMask); } set redWrite(value) { this.target0 = BitPacking.set(this.target0, value ? 1 : 0, redWriteShift); } get redWrite() { return BitPacking.all(this.target0, redWriteShift); } set greenWrite(value) { this.target0 = BitPacking.set(this.target0, value ? 1 : 0, greenWriteShift); } get greenWrite() { return BitPacking.all(this.target0, greenWriteShift); } set blueWrite(value) { this.target0 = BitPacking.set(this.target0, value ? 1 : 0, blueWriteShift); } get blueWrite() { return BitPacking.all(this.target0, blueWriteShift); } set alphaWrite(value) { this.target0 = BitPacking.set(this.target0, value ? 1 : 0, alphaWriteShift); } get alphaWrite() { return BitPacking.all(this.target0, alphaWriteShift); } get allWrite() { // return a number with all 4 bits, for fast compare return BitPacking.get(this.target0, allWriteShift, allWriteMasks); } /** * Copies the contents of a source blend state to this blend state. * * @param {BlendState} rhs - A blend state to copy from. * @returns {BlendState} Self for chaining. */ copy(rhs) { this.target0 = rhs.target0; return this; } /** * Returns an identical copy of the specified blend state. * * @returns {this} The result of the cloning. */ clone() { const clone = new this.constructor(); return clone.copy(this); } get key() { return this.target0; } /** * Reports whether two BlendStates are equal. * * @param {BlendState} rhs - The blend state to compare to. * @returns {boolean} True if the blend states are equal and false otherwise. */ equals(rhs) { return this.target0 === rhs.target0; } static{ /** * A blend state that has blending disabled and writes to all color channels. * * @type {BlendState} * @readonly */ this.NOBLEND = Object.freeze(new BlendState()); } static{ /** * A blend state that does not write to color channels. * * @type {BlendState} * @readonly */ this.NOWRITE = Object.freeze(new BlendState(undefined, undefined, undefined, undefined, undefined, undefined, undefined, false, false, false, false)); } static{ /** * A blend state that does simple translucency using alpha channel. * * @type {BlendState} * @readonly */ this.ALPHABLEND = Object.freeze(new BlendState(true, BLENDEQUATION_ADD, BLENDMODE_SRC_ALPHA, BLENDMODE_ONE_MINUS_SRC_ALPHA)); } static{ /** * A blend state that does simple additive blending. * * @type {BlendState} * @readonly */ this.ADDBLEND = Object.freeze(new BlendState(true, BLENDEQUATION_ADD, BLENDMODE_ONE, BLENDMODE_ONE)); } } export { BlendState };