123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- import BoundingRectangle from '../Core/BoundingRectangle.js';
- import Color from '../Core/Color.js';
- import defaultValue from '../Core/defaultValue.js';
- import defined from '../Core/defined.js';
- import DeveloperError from '../Core/DeveloperError.js';
- import WebGLConstants from '../Core/WebGLConstants.js';
- import WindingOrder from '../Core/WindingOrder.js';
- import ContextLimits from './ContextLimits.js';
- import freezeRenderState from './freezeRenderState.js';
- function validateBlendEquation(blendEquation) {
- return ((blendEquation === WebGLConstants.FUNC_ADD) ||
- (blendEquation === WebGLConstants.FUNC_SUBTRACT) ||
- (blendEquation === WebGLConstants.FUNC_REVERSE_SUBTRACT) ||
- (blendEquation === WebGLConstants.MIN) ||
- (blendEquation === WebGLConstants.MAX));
- }
- function validateBlendFunction(blendFunction) {
- return ((blendFunction === WebGLConstants.ZERO) ||
- (blendFunction === WebGLConstants.ONE) ||
- (blendFunction === WebGLConstants.SRC_COLOR) ||
- (blendFunction === WebGLConstants.ONE_MINUS_SRC_COLOR) ||
- (blendFunction === WebGLConstants.DST_COLOR) ||
- (blendFunction === WebGLConstants.ONE_MINUS_DST_COLOR) ||
- (blendFunction === WebGLConstants.SRC_ALPHA) ||
- (blendFunction === WebGLConstants.ONE_MINUS_SRC_ALPHA) ||
- (blendFunction === WebGLConstants.DST_ALPHA) ||
- (blendFunction === WebGLConstants.ONE_MINUS_DST_ALPHA) ||
- (blendFunction === WebGLConstants.CONSTANT_COLOR) ||
- (blendFunction === WebGLConstants.ONE_MINUS_CONSTANT_COLOR) ||
- (blendFunction === WebGLConstants.CONSTANT_ALPHA) ||
- (blendFunction === WebGLConstants.ONE_MINUS_CONSTANT_ALPHA) ||
- (blendFunction === WebGLConstants.SRC_ALPHA_SATURATE));
- }
- function validateCullFace(cullFace) {
- return ((cullFace === WebGLConstants.FRONT) ||
- (cullFace === WebGLConstants.BACK) ||
- (cullFace === WebGLConstants.FRONT_AND_BACK));
- }
- function validateDepthFunction(depthFunction) {
- return ((depthFunction === WebGLConstants.NEVER) ||
- (depthFunction === WebGLConstants.LESS) ||
- (depthFunction === WebGLConstants.EQUAL) ||
- (depthFunction === WebGLConstants.LEQUAL) ||
- (depthFunction === WebGLConstants.GREATER) ||
- (depthFunction === WebGLConstants.NOTEQUAL) ||
- (depthFunction === WebGLConstants.GEQUAL) ||
- (depthFunction === WebGLConstants.ALWAYS));
- }
- function validateStencilFunction(stencilFunction) {
- return ((stencilFunction === WebGLConstants.NEVER) ||
- (stencilFunction === WebGLConstants.LESS) ||
- (stencilFunction === WebGLConstants.EQUAL) ||
- (stencilFunction === WebGLConstants.LEQUAL) ||
- (stencilFunction === WebGLConstants.GREATER) ||
- (stencilFunction === WebGLConstants.NOTEQUAL) ||
- (stencilFunction === WebGLConstants.GEQUAL) ||
- (stencilFunction === WebGLConstants.ALWAYS));
- }
- function validateStencilOperation(stencilOperation) {
- return ((stencilOperation === WebGLConstants.ZERO) ||
- (stencilOperation === WebGLConstants.KEEP) ||
- (stencilOperation === WebGLConstants.REPLACE) ||
- (stencilOperation === WebGLConstants.INCR) ||
- (stencilOperation === WebGLConstants.DECR) ||
- (stencilOperation === WebGLConstants.INVERT) ||
- (stencilOperation === WebGLConstants.INCR_WRAP) ||
- (stencilOperation === WebGLConstants.DECR_WRAP));
- }
- /**
- * @private
- */
- function RenderState(renderState) {
- var rs = defaultValue(renderState, defaultValue.EMPTY_OBJECT);
- var cull = defaultValue(rs.cull, defaultValue.EMPTY_OBJECT);
- var polygonOffset = defaultValue(rs.polygonOffset, defaultValue.EMPTY_OBJECT);
- var scissorTest = defaultValue(rs.scissorTest, defaultValue.EMPTY_OBJECT);
- var scissorTestRectangle = defaultValue(scissorTest.rectangle, defaultValue.EMPTY_OBJECT);
- var depthRange = defaultValue(rs.depthRange, defaultValue.EMPTY_OBJECT);
- var depthTest = defaultValue(rs.depthTest, defaultValue.EMPTY_OBJECT);
- var colorMask = defaultValue(rs.colorMask, defaultValue.EMPTY_OBJECT);
- var blending = defaultValue(rs.blending, defaultValue.EMPTY_OBJECT);
- var blendingColor = defaultValue(blending.color, defaultValue.EMPTY_OBJECT);
- var stencilTest = defaultValue(rs.stencilTest, defaultValue.EMPTY_OBJECT);
- var stencilTestFrontOperation = defaultValue(stencilTest.frontOperation, defaultValue.EMPTY_OBJECT);
- var stencilTestBackOperation = defaultValue(stencilTest.backOperation, defaultValue.EMPTY_OBJECT);
- var sampleCoverage = defaultValue(rs.sampleCoverage, defaultValue.EMPTY_OBJECT);
- var viewport = rs.viewport;
- this.frontFace = defaultValue(rs.frontFace, WindingOrder.COUNTER_CLOCKWISE);
- this.cull = {
- enabled : defaultValue(cull.enabled, false),
- face : defaultValue(cull.face, WebGLConstants.BACK)
- };
- this.lineWidth = defaultValue(rs.lineWidth, 1.0);
- this.polygonOffset = {
- enabled : defaultValue(polygonOffset.enabled, false),
- factor : defaultValue(polygonOffset.factor, 0),
- units : defaultValue(polygonOffset.units, 0)
- };
- this.scissorTest = {
- enabled : defaultValue(scissorTest.enabled, false),
- rectangle : BoundingRectangle.clone(scissorTestRectangle)
- };
- this.depthRange = {
- near : defaultValue(depthRange.near, 0),
- far : defaultValue(depthRange.far, 1)
- };
- this.depthTest = {
- enabled : defaultValue(depthTest.enabled, false),
- func : defaultValue(depthTest.func, WebGLConstants.LESS) // func, because function is a JavaScript keyword
- };
- this.colorMask = {
- red : defaultValue(colorMask.red, true),
- green : defaultValue(colorMask.green, true),
- blue : defaultValue(colorMask.blue, true),
- alpha : defaultValue(colorMask.alpha, true)
- };
- this.depthMask = defaultValue(rs.depthMask, true);
- this.stencilMask = defaultValue(rs.stencilMask, ~0);
- this.blending = {
- enabled : defaultValue(blending.enabled, false),
- color : new Color(
- defaultValue(blendingColor.red, 0.0),
- defaultValue(blendingColor.green, 0.0),
- defaultValue(blendingColor.blue, 0.0),
- defaultValue(blendingColor.alpha, 0.0)
- ),
- equationRgb : defaultValue(blending.equationRgb, WebGLConstants.FUNC_ADD),
- equationAlpha : defaultValue(blending.equationAlpha, WebGLConstants.FUNC_ADD),
- functionSourceRgb : defaultValue(blending.functionSourceRgb, WebGLConstants.ONE),
- functionSourceAlpha : defaultValue(blending.functionSourceAlpha, WebGLConstants.ONE),
- functionDestinationRgb : defaultValue(blending.functionDestinationRgb, WebGLConstants.ZERO),
- functionDestinationAlpha : defaultValue(blending.functionDestinationAlpha, WebGLConstants.ZERO)
- };
- this.stencilTest = {
- enabled : defaultValue(stencilTest.enabled, false),
- frontFunction : defaultValue(stencilTest.frontFunction, WebGLConstants.ALWAYS),
- backFunction : defaultValue(stencilTest.backFunction, WebGLConstants.ALWAYS),
- reference : defaultValue(stencilTest.reference, 0),
- mask : defaultValue(stencilTest.mask, ~0),
- frontOperation : {
- fail : defaultValue(stencilTestFrontOperation.fail, WebGLConstants.KEEP),
- zFail : defaultValue(stencilTestFrontOperation.zFail, WebGLConstants.KEEP),
- zPass : defaultValue(stencilTestFrontOperation.zPass, WebGLConstants.KEEP)
- },
- backOperation : {
- fail : defaultValue(stencilTestBackOperation.fail, WebGLConstants.KEEP),
- zFail : defaultValue(stencilTestBackOperation.zFail, WebGLConstants.KEEP),
- zPass : defaultValue(stencilTestBackOperation.zPass, WebGLConstants.KEEP)
- }
- };
- this.sampleCoverage = {
- enabled : defaultValue(sampleCoverage.enabled, false),
- value : defaultValue(sampleCoverage.value, 1.0),
- invert : defaultValue(sampleCoverage.invert, false)
- };
- this.viewport = (defined(viewport)) ? new BoundingRectangle(viewport.x, viewport.y, viewport.width, viewport.height) : undefined;
- //>>includeStart('debug', pragmas.debug);
- if ((this.lineWidth < ContextLimits.minimumAliasedLineWidth) ||
- (this.lineWidth > ContextLimits.maximumAliasedLineWidth)) {
- throw new DeveloperError('renderState.lineWidth is out of range. Check minimumAliasedLineWidth and maximumAliasedLineWidth.');
- }
- if (!WindingOrder.validate(this.frontFace)) {
- throw new DeveloperError('Invalid renderState.frontFace.');
- }
- if (!validateCullFace(this.cull.face)) {
- throw new DeveloperError('Invalid renderState.cull.face.');
- }
- if ((this.scissorTest.rectangle.width < 0) ||
- (this.scissorTest.rectangle.height < 0)) {
- throw new DeveloperError('renderState.scissorTest.rectangle.width and renderState.scissorTest.rectangle.height must be greater than or equal to zero.');
- }
- if (this.depthRange.near > this.depthRange.far) {
- // WebGL specific - not an error in GL ES
- throw new DeveloperError('renderState.depthRange.near can not be greater than renderState.depthRange.far.');
- }
- if (this.depthRange.near < 0) {
- // Would be clamped by GL
- throw new DeveloperError('renderState.depthRange.near must be greater than or equal to zero.');
- }
- if (this.depthRange.far > 1) {
- // Would be clamped by GL
- throw new DeveloperError('renderState.depthRange.far must be less than or equal to one.');
- }
- if (!validateDepthFunction(this.depthTest.func)) {
- throw new DeveloperError('Invalid renderState.depthTest.func.');
- }
- if ((this.blending.color.red < 0.0) || (this.blending.color.red > 1.0) ||
- (this.blending.color.green < 0.0) || (this.blending.color.green > 1.0) ||
- (this.blending.color.blue < 0.0) || (this.blending.color.blue > 1.0) ||
- (this.blending.color.alpha < 0.0) || (this.blending.color.alpha > 1.0)) {
- // Would be clamped by GL
- throw new DeveloperError('renderState.blending.color components must be greater than or equal to zero and less than or equal to one.');
- }
- if (!validateBlendEquation(this.blending.equationRgb)) {
- throw new DeveloperError('Invalid renderState.blending.equationRgb.');
- }
- if (!validateBlendEquation(this.blending.equationAlpha)) {
- throw new DeveloperError('Invalid renderState.blending.equationAlpha.');
- }
- if (!validateBlendFunction(this.blending.functionSourceRgb)) {
- throw new DeveloperError('Invalid renderState.blending.functionSourceRgb.');
- }
- if (!validateBlendFunction(this.blending.functionSourceAlpha)) {
- throw new DeveloperError('Invalid renderState.blending.functionSourceAlpha.');
- }
- if (!validateBlendFunction(this.blending.functionDestinationRgb)) {
- throw new DeveloperError('Invalid renderState.blending.functionDestinationRgb.');
- }
- if (!validateBlendFunction(this.blending.functionDestinationAlpha)) {
- throw new DeveloperError('Invalid renderState.blending.functionDestinationAlpha.');
- }
- if (!validateStencilFunction(this.stencilTest.frontFunction)) {
- throw new DeveloperError('Invalid renderState.stencilTest.frontFunction.');
- }
- if (!validateStencilFunction(this.stencilTest.backFunction)) {
- throw new DeveloperError('Invalid renderState.stencilTest.backFunction.');
- }
- if (!validateStencilOperation(this.stencilTest.frontOperation.fail)) {
- throw new DeveloperError('Invalid renderState.stencilTest.frontOperation.fail.');
- }
- if (!validateStencilOperation(this.stencilTest.frontOperation.zFail)) {
- throw new DeveloperError('Invalid renderState.stencilTest.frontOperation.zFail.');
- }
- if (!validateStencilOperation(this.stencilTest.frontOperation.zPass)) {
- throw new DeveloperError('Invalid renderState.stencilTest.frontOperation.zPass.');
- }
- if (!validateStencilOperation(this.stencilTest.backOperation.fail)) {
- throw new DeveloperError('Invalid renderState.stencilTest.backOperation.fail.');
- }
- if (!validateStencilOperation(this.stencilTest.backOperation.zFail)) {
- throw new DeveloperError('Invalid renderState.stencilTest.backOperation.zFail.');
- }
- if (!validateStencilOperation(this.stencilTest.backOperation.zPass)) {
- throw new DeveloperError('Invalid renderState.stencilTest.backOperation.zPass.');
- }
- if (defined(this.viewport)) {
- if (this.viewport.width < 0) {
- throw new DeveloperError('renderState.viewport.width must be greater than or equal to zero.');
- }
- if (this.viewport.height < 0) {
- throw new DeveloperError('renderState.viewport.height must be greater than or equal to zero.');
- }
- if (this.viewport.width > ContextLimits.maximumViewportWidth) {
- throw new DeveloperError('renderState.viewport.width must be less than or equal to the maximum viewport width (' + ContextLimits.maximumViewportWidth.toString() + '). Check maximumViewportWidth.');
- }
- if (this.viewport.height > ContextLimits.maximumViewportHeight) {
- throw new DeveloperError('renderState.viewport.height must be less than or equal to the maximum viewport height (' + ContextLimits.maximumViewportHeight.toString() + '). Check maximumViewportHeight.');
- }
- }
- //>>includeEnd('debug');
- this.id = 0;
- this._applyFunctions = [];
- }
- var nextRenderStateId = 0;
- var renderStateCache = {};
- /**
- * Validates and then finds or creates an immutable render state, which defines the pipeline
- * state for a {@link DrawCommand} or {@link ClearCommand}. All inputs states are optional. Omitted states
- * use the defaults shown in the example below.
- *
- * @param {Object} [renderState] The states defining the render state as shown in the example below.
- *
- * @exception {RuntimeError} renderState.lineWidth is out of range.
- * @exception {DeveloperError} Invalid renderState.frontFace.
- * @exception {DeveloperError} Invalid renderState.cull.face.
- * @exception {DeveloperError} scissorTest.rectangle.width and scissorTest.rectangle.height must be greater than or equal to zero.
- * @exception {DeveloperError} renderState.depthRange.near can't be greater than renderState.depthRange.far.
- * @exception {DeveloperError} renderState.depthRange.near must be greater than or equal to zero.
- * @exception {DeveloperError} renderState.depthRange.far must be less than or equal to zero.
- * @exception {DeveloperError} Invalid renderState.depthTest.func.
- * @exception {DeveloperError} renderState.blending.color components must be greater than or equal to zero and less than or equal to one
- * @exception {DeveloperError} Invalid renderState.blending.equationRgb.
- * @exception {DeveloperError} Invalid renderState.blending.equationAlpha.
- * @exception {DeveloperError} Invalid renderState.blending.functionSourceRgb.
- * @exception {DeveloperError} Invalid renderState.blending.functionSourceAlpha.
- * @exception {DeveloperError} Invalid renderState.blending.functionDestinationRgb.
- * @exception {DeveloperError} Invalid renderState.blending.functionDestinationAlpha.
- * @exception {DeveloperError} Invalid renderState.stencilTest.frontFunction.
- * @exception {DeveloperError} Invalid renderState.stencilTest.backFunction.
- * @exception {DeveloperError} Invalid renderState.stencilTest.frontOperation.fail.
- * @exception {DeveloperError} Invalid renderState.stencilTest.frontOperation.zFail.
- * @exception {DeveloperError} Invalid renderState.stencilTest.frontOperation.zPass.
- * @exception {DeveloperError} Invalid renderState.stencilTest.backOperation.fail.
- * @exception {DeveloperError} Invalid renderState.stencilTest.backOperation.zFail.
- * @exception {DeveloperError} Invalid renderState.stencilTest.backOperation.zPass.
- * @exception {DeveloperError} renderState.viewport.width must be greater than or equal to zero.
- * @exception {DeveloperError} renderState.viewport.width must be less than or equal to the maximum viewport width.
- * @exception {DeveloperError} renderState.viewport.height must be greater than or equal to zero.
- * @exception {DeveloperError} renderState.viewport.height must be less than or equal to the maximum viewport height.
- *
- *
- * @example
- * var defaults = {
- * frontFace : WindingOrder.COUNTER_CLOCKWISE,
- * cull : {
- * enabled : false,
- * face : CullFace.BACK
- * },
- * lineWidth : 1,
- * polygonOffset : {
- * enabled : false,
- * factor : 0,
- * units : 0
- * },
- * scissorTest : {
- * enabled : false,
- * rectangle : {
- * x : 0,
- * y : 0,
- * width : 0,
- * height : 0
- * }
- * },
- * depthRange : {
- * near : 0,
- * far : 1
- * },
- * depthTest : {
- * enabled : false,
- * func : DepthFunction.LESS
- * },
- * colorMask : {
- * red : true,
- * green : true,
- * blue : true,
- * alpha : true
- * },
- * depthMask : true,
- * stencilMask : ~0,
- * blending : {
- * enabled : false,
- * color : {
- * red : 0.0,
- * green : 0.0,
- * blue : 0.0,
- * alpha : 0.0
- * },
- * equationRgb : BlendEquation.ADD,
- * equationAlpha : BlendEquation.ADD,
- * functionSourceRgb : BlendFunction.ONE,
- * functionSourceAlpha : BlendFunction.ONE,
- * functionDestinationRgb : BlendFunction.ZERO,
- * functionDestinationAlpha : BlendFunction.ZERO
- * },
- * stencilTest : {
- * enabled : false,
- * frontFunction : StencilFunction.ALWAYS,
- * backFunction : StencilFunction.ALWAYS,
- * reference : 0,
- * mask : ~0,
- * frontOperation : {
- * fail : StencilOperation.KEEP,
- * zFail : StencilOperation.KEEP,
- * zPass : StencilOperation.KEEP
- * },
- * backOperation : {
- * fail : StencilOperation.KEEP,
- * zFail : StencilOperation.KEEP,
- * zPass : StencilOperation.KEEP
- * }
- * },
- * sampleCoverage : {
- * enabled : false,
- * value : 1.0,
- * invert : false
- * }
- * };
- *
- * var rs = RenderState.fromCache(defaults);
- *
- * @see DrawCommand
- * @see ClearCommand
- *
- * @private
- */
- RenderState.fromCache = function(renderState) {
- var partialKey = JSON.stringify(renderState);
- var cachedState = renderStateCache[partialKey];
- if (defined(cachedState)) {
- ++cachedState.referenceCount;
- return cachedState.state;
- }
- // Cache miss. Fully define render state and try again.
- var states = new RenderState(renderState);
- var fullKey = JSON.stringify(states);
- cachedState = renderStateCache[fullKey];
- if (!defined(cachedState)) {
- states.id = nextRenderStateId++;
- //>>includeStart('debug', pragmas.debug);
- states = freezeRenderState(states);
- //>>includeEnd('debug');
- cachedState = {
- referenceCount : 0,
- state : states
- };
- // Cache full render state. Multiple partially defined render states may map to this.
- renderStateCache[fullKey] = cachedState;
- }
- ++cachedState.referenceCount;
- // Cache partial render state so we can skip validation on a cache hit for a partially defined render state
- renderStateCache[partialKey] = {
- referenceCount : 1,
- state : cachedState.state
- };
- return cachedState.state;
- };
- /**
- * @private
- */
- RenderState.removeFromCache = function(renderState) {
- var states = new RenderState(renderState);
- var fullKey = JSON.stringify(states);
- var fullCachedState = renderStateCache[fullKey];
- // decrement partial key reference count
- var partialKey = JSON.stringify(renderState);
- var cachedState = renderStateCache[partialKey];
- if (defined(cachedState)) {
- --cachedState.referenceCount;
- if (cachedState.referenceCount === 0) {
- // remove partial key
- delete renderStateCache[partialKey];
- // decrement full key reference count
- if (defined(fullCachedState)) {
- --fullCachedState.referenceCount;
- }
- }
- }
- // remove full key if reference count is zero
- if (defined(fullCachedState) && (fullCachedState.referenceCount === 0)) {
- delete renderStateCache[fullKey];
- }
- };
- /**
- * This function is for testing purposes only.
- * @private
- */
- RenderState.getCache = function() {
- return renderStateCache;
- };
- /**
- * This function is for testing purposes only.
- * @private
- */
- RenderState.clearCache = function() {
- renderStateCache = {};
- };
- function enableOrDisable(gl, glEnum, enable) {
- if (enable) {
- gl.enable(glEnum);
- } else {
- gl.disable(glEnum);
- }
- }
- function applyFrontFace(gl, renderState) {
- gl.frontFace(renderState.frontFace);
- }
- function applyCull(gl, renderState) {
- var cull = renderState.cull;
- var enabled = cull.enabled;
- enableOrDisable(gl, gl.CULL_FACE, enabled);
- if (enabled) {
- gl.cullFace(cull.face);
- }
- }
- function applyLineWidth(gl, renderState) {
- gl.lineWidth(renderState.lineWidth);
- }
- function applyPolygonOffset(gl, renderState) {
- var polygonOffset = renderState.polygonOffset;
- var enabled = polygonOffset.enabled;
- enableOrDisable(gl, gl.POLYGON_OFFSET_FILL, enabled);
- if (enabled) {
- gl.polygonOffset(polygonOffset.factor, polygonOffset.units);
- }
- }
- function applyScissorTest(gl, renderState, passState) {
- var scissorTest = renderState.scissorTest;
- var enabled = (defined(passState.scissorTest)) ? passState.scissorTest.enabled : scissorTest.enabled;
- enableOrDisable(gl, gl.SCISSOR_TEST, enabled);
- if (enabled) {
- var rectangle = (defined(passState.scissorTest)) ? passState.scissorTest.rectangle : scissorTest.rectangle;
- gl.scissor(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
- }
- }
- function applyDepthRange(gl, renderState) {
- var depthRange = renderState.depthRange;
- gl.depthRange(depthRange.near, depthRange.far);
- }
- function applyDepthTest(gl, renderState) {
- var depthTest = renderState.depthTest;
- var enabled = depthTest.enabled;
- enableOrDisable(gl, gl.DEPTH_TEST, enabled);
- if (enabled) {
- gl.depthFunc(depthTest.func);
- }
- }
- function applyColorMask(gl, renderState) {
- var colorMask = renderState.colorMask;
- gl.colorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha);
- }
- function applyDepthMask(gl, renderState) {
- gl.depthMask(renderState.depthMask);
- }
- function applyStencilMask(gl, renderState) {
- gl.stencilMask(renderState.stencilMask);
- }
- function applyBlendingColor(gl, color) {
- gl.blendColor(color.red, color.green, color.blue, color.alpha);
- }
- function applyBlending(gl, renderState, passState) {
- var blending = renderState.blending;
- var enabled = (defined(passState.blendingEnabled)) ? passState.blendingEnabled : blending.enabled;
- enableOrDisable(gl, gl.BLEND, enabled);
- if (enabled) {
- applyBlendingColor(gl, blending.color);
- gl.blendEquationSeparate(blending.equationRgb, blending.equationAlpha);
- gl.blendFuncSeparate(blending.functionSourceRgb, blending.functionDestinationRgb, blending.functionSourceAlpha, blending.functionDestinationAlpha);
- }
- }
- function applyStencilTest(gl, renderState) {
- var stencilTest = renderState.stencilTest;
- var enabled = stencilTest.enabled;
- enableOrDisable(gl, gl.STENCIL_TEST, enabled);
- if (enabled) {
- var frontFunction = stencilTest.frontFunction;
- var backFunction = stencilTest.backFunction;
- var reference = stencilTest.reference;
- var mask = stencilTest.mask;
- // Section 6.8 of the WebGL spec requires the reference and masks to be the same for
- // front- and back-face tests. This call prevents invalid operation errors when calling
- // stencilFuncSeparate on Firefox. Perhaps they should delay validation to avoid requiring this.
- gl.stencilFunc(frontFunction, reference, mask);
- gl.stencilFuncSeparate(gl.BACK, backFunction, reference, mask);
- gl.stencilFuncSeparate(gl.FRONT, frontFunction, reference, mask);
- var frontOperation = stencilTest.frontOperation;
- var frontOperationFail = frontOperation.fail;
- var frontOperationZFail = frontOperation.zFail;
- var frontOperationZPass = frontOperation.zPass;
- gl.stencilOpSeparate(gl.FRONT, frontOperationFail, frontOperationZFail, frontOperationZPass);
- var backOperation = stencilTest.backOperation;
- var backOperationFail = backOperation.fail;
- var backOperationZFail = backOperation.zFail;
- var backOperationZPass = backOperation.zPass;
- gl.stencilOpSeparate(gl.BACK, backOperationFail, backOperationZFail, backOperationZPass);
- }
- }
- function applySampleCoverage(gl, renderState) {
- var sampleCoverage = renderState.sampleCoverage;
- var enabled = sampleCoverage.enabled;
- enableOrDisable(gl, gl.SAMPLE_COVERAGE, enabled);
- if (enabled) {
- gl.sampleCoverage(sampleCoverage.value, sampleCoverage.invert);
- }
- }
- var scratchViewport = new BoundingRectangle();
- function applyViewport(gl, renderState, passState) {
- var viewport = defaultValue(renderState.viewport, passState.viewport);
- if (!defined(viewport)) {
- viewport = scratchViewport;
- viewport.width = passState.context.drawingBufferWidth;
- viewport.height = passState.context.drawingBufferHeight;
- }
- passState.context.uniformState.viewport = viewport;
- gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
- }
- RenderState.apply = function(gl, renderState, passState) {
- applyFrontFace(gl, renderState);
- applyCull(gl, renderState);
- applyLineWidth(gl, renderState);
- applyPolygonOffset(gl, renderState);
- applyDepthRange(gl, renderState);
- applyDepthTest(gl, renderState);
- applyColorMask(gl, renderState);
- applyDepthMask(gl, renderState);
- applyStencilMask(gl, renderState);
- applyStencilTest(gl, renderState);
- applySampleCoverage(gl, renderState);
- applyScissorTest(gl, renderState, passState);
- applyBlending(gl, renderState, passState);
- applyViewport(gl, renderState, passState);
- };
- function createFuncs(previousState, nextState) {
- var funcs = [];
- if (previousState.frontFace !== nextState.frontFace) {
- funcs.push(applyFrontFace);
- }
- if ((previousState.cull.enabled !== nextState.cull.enabled) || (previousState.cull.face !== nextState.cull.face)) {
- funcs.push(applyCull);
- }
- if (previousState.lineWidth !== nextState.lineWidth) {
- funcs.push(applyLineWidth);
- }
- if ((previousState.polygonOffset.enabled !== nextState.polygonOffset.enabled) ||
- (previousState.polygonOffset.factor !== nextState.polygonOffset.factor) ||
- (previousState.polygonOffset.units !== nextState.polygonOffset.units)) {
- funcs.push(applyPolygonOffset);
- }
- if ((previousState.depthRange.near !== nextState.depthRange.near) || (previousState.depthRange.far !== nextState.depthRange.far)) {
- funcs.push(applyDepthRange);
- }
- if ((previousState.depthTest.enabled !== nextState.depthTest.enabled) || (previousState.depthTest.func !== nextState.depthTest.func)) {
- funcs.push(applyDepthTest);
- }
- if ((previousState.colorMask.red !== nextState.colorMask.red) ||
- (previousState.colorMask.green !== nextState.colorMask.green) ||
- (previousState.colorMask.blue !== nextState.colorMask.blue) ||
- (previousState.colorMask.alpha !== nextState.colorMask.alpha)) {
- funcs.push(applyColorMask);
- }
- if (previousState.depthMask !== nextState.depthMask) {
- funcs.push(applyDepthMask);
- }
- if (previousState.stencilMask !== nextState.stencilMask) {
- funcs.push(applyStencilMask);
- }
- if ((previousState.stencilTest.enabled !== nextState.stencilTest.enabled) ||
- (previousState.stencilTest.frontFunction !== nextState.stencilTest.frontFunction) ||
- (previousState.stencilTest.backFunction !== nextState.stencilTest.backFunction) ||
- (previousState.stencilTest.reference !== nextState.stencilTest.reference) ||
- (previousState.stencilTest.mask !== nextState.stencilTest.mask) ||
- (previousState.stencilTest.frontOperation.fail !== nextState.stencilTest.frontOperation.fail) ||
- (previousState.stencilTest.frontOperation.zFail !== nextState.stencilTest.frontOperation.zFail) ||
- (previousState.stencilTest.backOperation.fail !== nextState.stencilTest.backOperation.fail) ||
- (previousState.stencilTest.backOperation.zFail !== nextState.stencilTest.backOperation.zFail) ||
- (previousState.stencilTest.backOperation.zPass !== nextState.stencilTest.backOperation.zPass)) {
- funcs.push(applyStencilTest);
- }
- if ((previousState.sampleCoverage.enabled !== nextState.sampleCoverage.enabled) ||
- (previousState.sampleCoverage.value !== nextState.sampleCoverage.value) ||
- (previousState.sampleCoverage.invert !== nextState.sampleCoverage.invert)) {
- funcs.push(applySampleCoverage);
- }
- return funcs;
- }
- RenderState.partialApply = function(gl, previousRenderState, renderState, previousPassState, passState, clear) {
- if (previousRenderState !== renderState) {
- // When a new render state is applied, instead of making WebGL calls for all the states or first
- // comparing the states one-by-one with the previous state (basically a linear search), we take
- // advantage of RenderState's immutability, and store a dynamically populated sparse data structure
- // containing functions that make the minimum number of WebGL calls when transitioning from one state
- // to the other. In practice, this works well since state-to-state transitions generally only require a
- // few WebGL calls, especially if commands are stored by state.
- var funcs = renderState._applyFunctions[previousRenderState.id];
- if (!defined(funcs)) {
- funcs = createFuncs(previousRenderState, renderState);
- renderState._applyFunctions[previousRenderState.id] = funcs;
- }
- var len = funcs.length;
- for (var i = 0; i < len; ++i) {
- funcs[i](gl, renderState);
- }
- }
- var previousScissorTest = (defined(previousPassState.scissorTest)) ? previousPassState.scissorTest : previousRenderState.scissorTest;
- var scissorTest = (defined(passState.scissorTest)) ? passState.scissorTest : renderState.scissorTest;
- // Our scissor rectangle can get out of sync with the GL scissor rectangle on clears.
- // Seems to be a problem only on ANGLE. See https://github.com/AnalyticalGraphicsInc/cesium/issues/2994
- if ((previousScissorTest !== scissorTest) || clear) {
- applyScissorTest(gl, renderState, passState);
- }
- var previousBlendingEnabled = (defined(previousPassState.blendingEnabled)) ? previousPassState.blendingEnabled : previousRenderState.blending.enabled;
- var blendingEnabled = (defined(passState.blendingEnabled)) ? passState.blendingEnabled : renderState.blending.enabled;
- if ((previousBlendingEnabled !== blendingEnabled) ||
- (blendingEnabled && (previousRenderState.blending !== renderState.blending))) {
- applyBlending(gl, renderState, passState);
- }
- if (previousRenderState !== renderState || previousPassState !== passState || previousPassState.context !== passState.context) {
- applyViewport(gl, renderState, passState);
- }
- };
- RenderState.getState = function(renderState) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(renderState)) {
- throw new DeveloperError('renderState is required.');
- }
- //>>includeEnd('debug');
- return {
- frontFace : renderState.frontFace,
- cull : {
- enabled : renderState.cull.enabled,
- face : renderState.cull.face
- },
- lineWidth : renderState.lineWidth,
- polygonOffset : {
- enabled : renderState.polygonOffset.enabled,
- factor : renderState.polygonOffset.factor,
- units : renderState.polygonOffset.units
- },
- scissorTest : {
- enabled : renderState.scissorTest.enabled,
- rectangle : BoundingRectangle.clone(renderState.scissorTest.rectangle)
- },
- depthRange : {
- near : renderState.depthRange.near,
- far : renderState.depthRange.far
- },
- depthTest : {
- enabled : renderState.depthTest.enabled,
- func : renderState.depthTest.func
- },
- colorMask : {
- red : renderState.colorMask.red,
- green : renderState.colorMask.green,
- blue : renderState.colorMask.blue,
- alpha : renderState.colorMask.alpha
- },
- depthMask : renderState.depthMask,
- stencilMask : renderState.stencilMask,
- blending : {
- enabled : renderState.blending.enabled,
- color : Color.clone(renderState.blending.color),
- equationRgb : renderState.blending.equationRgb,
- equationAlpha : renderState.blending.equationAlpha,
- functionSourceRgb : renderState.blending.functionSourceRgb,
- functionSourceAlpha : renderState.blending.functionSourceAlpha,
- functionDestinationRgb : renderState.blending.functionDestinationRgb,
- functionDestinationAlpha : renderState.blending.functionDestinationAlpha
- },
- stencilTest : {
- enabled : renderState.stencilTest.enabled,
- frontFunction : renderState.stencilTest.frontFunction,
- backFunction : renderState.stencilTest.backFunction,
- reference : renderState.stencilTest.reference,
- mask : renderState.stencilTest.mask,
- frontOperation : {
- fail : renderState.stencilTest.frontOperation.fail,
- zFail : renderState.stencilTest.frontOperation.zFail,
- zPass : renderState.stencilTest.frontOperation.zPass
- },
- backOperation : {
- fail : renderState.stencilTest.backOperation.fail,
- zFail : renderState.stencilTest.backOperation.zFail,
- zPass : renderState.stencilTest.backOperation.zPass
- }
- },
- sampleCoverage : {
- enabled : renderState.sampleCoverage.enabled,
- value : renderState.sampleCoverage.value,
- invert : renderState.sampleCoverage.invert
- },
- viewport : defined(renderState.viewport) ? BoundingRectangle.clone(renderState.viewport) : undefined
- };
- };
- export default RenderState;
|