You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

542 lines
11 KiB
JavaScript

import {
CullFaceNone, CullFaceBack, CullFaceFront, DoubleSide, BackSide,
NormalBlending, NoBlending, CustomBlending, AddEquation,
AdditiveBlending, SubtractiveBlending, MultiplyBlending, SubtractEquation, ReverseSubtractEquation,
ZeroFactor, OneFactor, SrcColorFactor, SrcAlphaFactor, SrcAlphaSaturateFactor, DstColorFactor, DstAlphaFactor,
OneMinusSrcColorFactor, OneMinusSrcAlphaFactor, OneMinusDstColorFactor, OneMinusDstAlphaFactor,
NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth
} from 'three';
let initialized = false, equationToGL, factorToGL;
class WebGLState {
constructor( backend ) {
this.backend = backend;
this.gl = this.backend.gl;
this.enabled = {};
this.currentFlipSided = null;
this.currentCullFace = null;
this.currentProgram = null;
this.currentBlendingEnabled = false;
this.currentBlending = null;
this.currentBlendSrc = null;
this.currentBlendDst = null;
this.currentBlendSrcAlpha = null;
this.currentBlendDstAlpha = null;
this.currentPremultipledAlpha = null;
this.currentPolygonOffsetFactor = null;
this.currentPolygonOffsetUnits = null;
this.currentColorMask = null;
this.currentDepthFunc = null;
this.currentDepthMask = null;
this.currentStencilFunc = null;
this.currentStencilRef = null;
this.currentStencilFuncMask = null;
this.currentStencilFail = null;
this.currentStencilZFail = null;
this.currentStencilZPass = null;
this.currentStencilMask = null;
if ( initialized === false ) {
this._init( this.gl );
initialized = true;
}
}
_init( gl ) {
// Store only WebGL constants here.
equationToGL = {
[ AddEquation ]: gl.FUNC_ADD,
[ SubtractEquation ]: gl.FUNC_SUBTRACT,
[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
};
factorToGL = {
[ ZeroFactor ]: gl.ZERO,
[ OneFactor ]: gl.ONE,
[ SrcColorFactor ]: gl.SRC_COLOR,
[ SrcAlphaFactor ]: gl.SRC_ALPHA,
[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
[ DstColorFactor ]: gl.DST_COLOR,
[ DstAlphaFactor ]: gl.DST_ALPHA,
[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA
};
}
enable( id ) {
const { enabled } = this;
if ( enabled[ id ] !== true ) {
this.gl.enable( id );
enabled[ id ] = true;
}
}
disable( id ) {
const { enabled } = this;
if ( enabled[ id ] !== false ) {
this.gl.disable( id );
enabled[ id ] = false;
}
}
setFlipSided( flipSided ) {
if ( this.currentFlipSided !== flipSided ) {
const { gl } = this;
if ( flipSided ) {
gl.frontFace( gl.CW );
} else {
gl.frontFace( gl.CCW );
}
this.currentFlipSided = flipSided;
}
}
setCullFace( cullFace ) {
const { gl } = this;
if ( cullFace !== CullFaceNone ) {
this.enable( gl.CULL_FACE );
if ( cullFace !== this.currentCullFace ) {
if ( cullFace === CullFaceBack ) {
gl.cullFace( gl.BACK );
} else if ( cullFace === CullFaceFront ) {
gl.cullFace( gl.FRONT );
} else {
gl.cullFace( gl.FRONT_AND_BACK );
}
}
} else {
this.disable( gl.CULL_FACE );
}
this.currentCullFace = cullFace;
}
setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
const { gl } = this;
if ( blending === NoBlending ) {
if ( this.currentBlendingEnabled === true ) {
this.disable( gl.BLEND );
this.currentBlendingEnabled = false;
}
return;
}
if ( this.currentBlendingEnabled === false ) {
this.enable( gl.BLEND );
this.currentBlendingEnabled = true;
}
if ( blending !== CustomBlending ) {
if ( blending !== this.currentBlending || premultipliedAlpha !== this.currentPremultipledAlpha ) {
if ( this.currentBlendEquation !== AddEquation || this.currentBlendEquationAlpha !== AddEquation ) {
gl.blendEquation( gl.FUNC_ADD );
this.currentBlendEquation = AddEquation;
this.currentBlendEquationAlpha = AddEquation;
}
if ( premultipliedAlpha ) {
switch ( blending ) {
case NormalBlending:
gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
break;
case AdditiveBlending:
gl.blendFunc( gl.ONE, gl.ONE );
break;
case SubtractiveBlending:
gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
break;
case MultiplyBlending:
gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
break;
default:
console.error( 'THREE.WebGLState: Invalid blending: ', blending );
break;
}
} else {
switch ( blending ) {
case NormalBlending:
gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
break;
case AdditiveBlending:
gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
break;
case SubtractiveBlending:
gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
break;
case MultiplyBlending:
gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
break;
default:
console.error( 'THREE.WebGLState: Invalid blending: ', blending );
break;
}
}
this.currentBlendSrc = null;
this.currentBlendDst = null;
this.currentBlendSrcAlpha = null;
this.currentBlendDstAlpha = null;
this.currentBlending = blending;
this.currentPremultipledAlpha = premultipliedAlpha;
}
return;
}
// custom blending
blendEquationAlpha = blendEquationAlpha || blendEquation;
blendSrcAlpha = blendSrcAlpha || blendSrc;
blendDstAlpha = blendDstAlpha || blendDst;
if ( blendEquation !== this.currentBlendEquation || blendEquationAlpha !== this.currentBlendEquationAlpha ) {
gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
this.currentBlendEquation = blendEquation;
this.currentBlendEquationAlpha = blendEquationAlpha;
}
if ( blendSrc !== this.currentBlendSrc || blendDst !== this.currentBlendDst || blendSrcAlpha !== this.currentBlendSrcAlpha || blendDstAlpha !== this.currentBlendDstAlpha ) {
gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
this.currentBlendSrc = blendSrc;
this.currentBlendDst = blendDst;
this.currentBlendSrcAlpha = blendSrcAlpha;
this.currentBlendDstAlpha = blendDstAlpha;
}
this.currentBlending = blending;
this.currentPremultipledAlpha = false;
}
setColorMask( colorMask ) {
if ( this.currentColorMask !== colorMask ) {
this.gl.colorMask( colorMask, colorMask, colorMask, colorMask );
this.currentColorMask = colorMask;
}
}
setDepthTest( depthTest ) {
const { gl } = this;
if ( depthTest ) {
this.enable( gl.DEPTH_TEST );
} else {
this.disable( gl.DEPTH_TEST );
}
}
setDepthMask( depthMask ) {
if ( this.currentDepthMask !== depthMask ) {
this.gl.depthMask( depthMask );
this.currentDepthMask = depthMask;
}
}
setDepthFunc( depthFunc ) {
if ( this.currentDepthFunc !== depthFunc ) {
const { gl } = this;
switch ( depthFunc ) {
case NeverDepth:
gl.depthFunc( gl.NEVER );
break;
case AlwaysDepth:
gl.depthFunc( gl.ALWAYS );
break;
case LessDepth:
gl.depthFunc( gl.LESS );
break;
case LessEqualDepth:
gl.depthFunc( gl.LEQUAL );
break;
case EqualDepth:
gl.depthFunc( gl.EQUAL );
break;
case GreaterEqualDepth:
gl.depthFunc( gl.GEQUAL );
break;
case GreaterDepth:
gl.depthFunc( gl.GREATER );
break;
case NotEqualDepth:
gl.depthFunc( gl.NOTEQUAL );
break;
default:
gl.depthFunc( gl.LEQUAL );
}
this.currentDepthFunc = depthFunc;
}
}
setStencilTest( stencilTest ) {
const { gl } = this;
if ( stencilTest ) {
this.enable( gl.STENCIL_TEST );
} else {
this.disable( gl.STENCIL_TEST );
}
}
setStencilMask( stencilMask ) {
if ( this.currentStencilMask !== stencilMask ) {
this.gl.stencilMask( stencilMask );
this.currentStencilMask = stencilMask;
}
}
setStencilFunc( stencilFunc, stencilRef, stencilMask ) {
if ( this.currentStencilFunc !== stencilFunc ||
this.currentStencilRef !== stencilRef ||
this.currentStencilFuncMask !== stencilMask ) {
this.gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
this.currentStencilFunc = stencilFunc;
this.currentStencilRef = stencilRef;
this.currentStencilFuncMask = stencilMask;
}
}
setStencilOp( stencilFail, stencilZFail, stencilZPass ) {
if ( this.currentStencilFail !== stencilFail ||
this.currentStencilZFail !== stencilZFail ||
this.currentStencilZPass !== stencilZPass ) {
this.gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
this.currentStencilFail = stencilFail;
this.currentStencilZFail = stencilZFail;
this.currentStencilZPass = stencilZPass;
}
}
setMaterial( material, frontFaceCW ) {
const { gl } = this;
material.side === DoubleSide
? this.disable( gl.CULL_FACE )
: this.enable( gl.CULL_FACE );
let flipSided = ( material.side === BackSide );
if ( frontFaceCW ) flipSided = ! flipSided;
this.setFlipSided( flipSided );
( material.blending === NormalBlending && material.transparent === false )
? this.setBlending( NoBlending )
: this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
this.setDepthFunc( material.depthFunc );
this.setDepthTest( material.depthTest );
this.setDepthMask( material.depthWrite );
this.setColorMask( material.colorWrite );
const stencilWrite = material.stencilWrite;
this.setStencilTest( stencilWrite );
if ( stencilWrite ) {
this.setStencilMask( material.stencilWriteMask );
this.setStencilFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
this.setStencilOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
}
this.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
material.alphaToCoverage === true
? this.enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
: this.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
}
setPolygonOffset( polygonOffset, factor, units ) {
const { gl } = this;
if ( polygonOffset ) {
this.enable( gl.POLYGON_OFFSET_FILL );
if ( this.currentPolygonOffsetFactor !== factor || this.currentPolygonOffsetUnits !== units ) {
gl.polygonOffset( factor, units );
this.currentPolygonOffsetFactor = factor;
this.currentPolygonOffsetUnits = units;
}
} else {
this.disable( gl.POLYGON_OFFSET_FILL );
}
}
useProgram( program ) {
if ( this.currentProgram !== program ) {
this.gl.useProgram( program );
this.currentProgram = program;
return true;
}
return false;
}
}
export default WebGLState;