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
542 lines
11 KiB
JavaScript
2 years ago
|
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;
|