import Color from '../Core/Color.js'; import defined from '../Core/defined.js'; import defineProperties from '../Core/defineProperties.js'; import destroyObject from '../Core/destroyObject.js'; import PixelFormat from '../Core/PixelFormat.js'; import ClearCommand from '../Renderer/ClearCommand.js'; import Framebuffer from '../Renderer/Framebuffer.js'; import PixelDatatype from '../Renderer/PixelDatatype.js'; import RenderState from '../Renderer/RenderState.js'; import Sampler from '../Renderer/Sampler.js'; import ShaderSource from '../Renderer/ShaderSource.js'; import Texture from '../Renderer/Texture.js'; import TextureMagnificationFilter from '../Renderer/TextureMagnificationFilter.js'; import TextureMinificationFilter from '../Renderer/TextureMinificationFilter.js'; import TextureWrap from '../Renderer/TextureWrap.js'; import PassThrough from '../Shaders/PostProcessStages/PassThrough.js'; import BlendingState from './BlendingState.js'; import StencilConstants from './StencilConstants.js'; import StencilFunction from './StencilFunction.js'; import StencilOperation from './StencilOperation.js'; /** * @private */ function InvertClassification() { this.previousFramebuffer = undefined; this._previousFramebuffer = undefined; this._texture = undefined; this._classifiedTexture = undefined; this._depthStencilTexture = undefined; this._fbo = undefined; this._fboClassified = undefined; this._rsUnclassified = undefined; this._rsClassified = undefined; this._unclassifiedCommand = undefined; this._classifiedCommand = undefined; this._translucentCommand = undefined; this._clearColorCommand = new ClearCommand({ color : new Color(0.0, 0.0, 0.0, 0.0), owner : this }); this._clearCommand = new ClearCommand({ color : new Color(0.0, 0.0, 0.0, 0.0), depth : 1.0, stencil : 0 }); var that = this; this._uniformMap = { colorTexture : function() { return that._texture; }, depthTexture : function() { return that._depthStencilTexture; }, classifiedTexture : function() { return that._classifiedTexture; } }; } defineProperties(InvertClassification.prototype, { unclassifiedCommand : { get : function() { return this._unclassifiedCommand; } } }); InvertClassification.isTranslucencySupported = function(context) { return context.depthTexture && context.fragmentDepth; }; var rsUnclassified = { depthMask : false, stencilTest : { enabled : true, frontFunction : StencilFunction.EQUAL, frontOperation : { fail : StencilOperation.KEEP, zFail : StencilOperation.KEEP, zPass : StencilOperation.KEEP }, backFunction : StencilFunction.NEVER, reference : 0, mask : StencilConstants.CLASSIFICATION_MASK }, blending : BlendingState.ALPHA_BLEND }; var rsClassified = { depthMask : false, stencilTest : { enabled : true, frontFunction : StencilFunction.NOT_EQUAL, frontOperation : { fail : StencilOperation.KEEP, zFail : StencilOperation.KEEP, zPass : StencilOperation.KEEP }, backFunction : StencilFunction.NEVER, reference : 0, mask : StencilConstants.CLASSIFICATION_MASK }, blending : BlendingState.ALPHA_BLEND }; // Set the 3D Tiles bit when rendering back into the scene's framebuffer. This is only needed if // invert classification does not use the scene's depth-stencil texture, which is the case if the invert // classification color is translucent. var rsDefault = { depthMask : true, depthTest : { enabled : true }, stencilTest : StencilConstants.setCesium3DTileBit(), stencilMask : StencilConstants.CESIUM_3D_TILE_MASK, blending : BlendingState.ALPHA_BLEND }; var translucentFS = '#extension GL_EXT_frag_depth : enable\n'+ 'uniform sampler2D colorTexture;\n' + 'uniform sampler2D depthTexture;\n' + 'uniform sampler2D classifiedTexture;\n' + 'varying vec2 v_textureCoordinates;\n' + 'void main()\n' + '{\n' + ' vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' + ' if (color.a == 0.0)\n' + ' {\n' + ' discard;\n' + ' }\n' + ' bool isClassified = all(equal(texture2D(classifiedTexture, v_textureCoordinates), vec4(0.0)));\n' + '#ifdef UNCLASSIFIED\n' + ' vec4 highlightColor = czm_invertClassificationColor;\n' + ' if (isClassified)\n' + ' {\n' + ' discard;\n' + ' }\n' + '#else\n' + ' vec4 highlightColor = vec4(1.0);\n' + ' if (!isClassified)\n' + ' {\n' + ' discard;\n' + ' }\n' + '#endif\n' + ' gl_FragColor = color * highlightColor;\n' + ' gl_FragDepthEXT = texture2D(depthTexture, v_textureCoordinates).r;\n' + '}\n'; var opaqueFS = 'uniform sampler2D colorTexture;\n' + 'varying vec2 v_textureCoordinates;\n' + 'void main()\n' + '{\n' + ' vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' + ' if (color.a == 0.0)\n' + ' {\n' + ' discard;\n' + ' }\n' + '#ifdef UNCLASSIFIED\n' + ' gl_FragColor = color * czm_invertClassificationColor;\n' + '#else\n' + ' gl_FragColor = color;\n' + '#endif\n' + '}\n'; InvertClassification.prototype.update = function(context) { var texture = this._texture; var previousFramebufferChanged = !defined(texture) || this.previousFramebuffer !== this._previousFramebuffer; this._previousFramebuffer = this.previousFramebuffer; var width = context.drawingBufferWidth; var height = context.drawingBufferHeight; var textureChanged = !defined(texture) || texture.width !== width || texture.height !== height; if (textureChanged || previousFramebufferChanged) { this._texture = this._texture && this._texture.destroy(); this._classifiedTexture = this._classifiedTexture && this._classifiedTexture.destroy(); this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy(); this._texture = new Texture({ context : context, width : width, height : height, pixelFormat : PixelFormat.RGBA, pixelDatatype : PixelDatatype.UNSIGNED_BYTE, sampler : new Sampler({ wrapS : TextureWrap.CLAMP_TO_EDGE, wrapT : TextureWrap.CLAMP_TO_EDGE, minificationFilter : TextureMinificationFilter.LINEAR, magnificationFilter : TextureMagnificationFilter.LINEAR }) }); if (!defined(this._previousFramebuffer)) { this._classifiedTexture = new Texture({ context : context, width : width, height : height, pixelFormat : PixelFormat.RGBA, pixelDatatype : PixelDatatype.UNSIGNED_BYTE, sampler : new Sampler({ wrapS : TextureWrap.CLAMP_TO_EDGE, wrapT : TextureWrap.CLAMP_TO_EDGE, minificationFilter : TextureMinificationFilter.LINEAR, magnificationFilter : TextureMagnificationFilter.LINEAR }) }); this._depthStencilTexture = new Texture({ context : context, width : width, height : height, pixelFormat : PixelFormat.DEPTH_STENCIL, pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8 }); } } if (!defined(this._fbo) || textureChanged || previousFramebufferChanged) { this._fbo = this._fbo && this._fbo.destroy(); this._fboClassified = this._fboClassified && this._fboClassified.destroy(); var depthStencilTexture; var depthStencilRenderbuffer; if (defined(this._previousFramebuffer)) { depthStencilTexture = this._previousFramebuffer.depthStencilTexture; depthStencilRenderbuffer = this._previousFramebuffer.depthStencilRenderbuffer; } else { depthStencilTexture = this._depthStencilTexture; } this._fbo = new Framebuffer({ context : context, colorTextures : [this._texture], depthStencilTexture : depthStencilTexture, depthStencilRenderbuffer : depthStencilRenderbuffer, destroyAttachments : false }); if (!defined(this._previousFramebuffer)) { this._fboClassified = new Framebuffer({ context : context, colorTextures : [this._classifiedTexture], depthStencilTexture : depthStencilTexture, destroyAttachments : false }); } } if (!defined(this._rsUnclassified)) { this._rsUnclassified = RenderState.fromCache(rsUnclassified); this._rsClassified = RenderState.fromCache(rsClassified); this._rsDefault = RenderState.fromCache(rsDefault); } if (!defined(this._unclassifiedCommand) || previousFramebufferChanged) { if (defined(this._unclassifiedCommand)) { this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy(); this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy(); } var fs = defined(this._previousFramebuffer) ? opaqueFS : translucentFS; var unclassifiedFSSource = new ShaderSource({ defines : ['UNCLASSIFIED'], sources : [fs] }); var classifiedFSSource = new ShaderSource({ sources : [fs] }); this._unclassifiedCommand = context.createViewportQuadCommand(unclassifiedFSSource, { renderState : defined(this._previousFramebuffer) ? this._rsUnclassified : this._rsDefault, uniformMap : this._uniformMap, owner : this }); this._classifiedCommand = context.createViewportQuadCommand(classifiedFSSource, { renderState : defined(this._previousFramebuffer) ? this._rsClassified : this._rsDefault, uniformMap : this._uniformMap, owner : this }); if (defined(this._translucentCommand)) { this._translucentCommand.shaderProgram = this._translucentCommand.shaderProgram && this._translucentCommand.shaderProgram.destroy(); } if (!defined(this._previousFramebuffer)) { this._translucentCommand = context.createViewportQuadCommand(PassThrough, { renderState : this._rsUnclassified, uniformMap : this._uniformMap, owner : this }); } } }; InvertClassification.prototype.clear = function(context, passState) { var framebuffer = passState.framebuffer; if (defined(this._previousFramebuffer)) { passState.framebuffer = this._fbo; this._clearColorCommand.execute(context, passState); } else { passState.framebuffer = this._fbo; this._clearCommand.execute(context, passState); passState.framebuffer = this._fboClassified; this._clearCommand.execute(context, passState); } passState.framebuffer = framebuffer; }; InvertClassification.prototype.executeClassified = function(context, passState) { if (!defined(this._previousFramebuffer)) { var framebuffer = passState.framebuffer; passState.framebuffer = this._fboClassified; this._translucentCommand.execute(context, passState); passState.framebuffer = framebuffer; } this._classifiedCommand.execute(context, passState); }; InvertClassification.prototype.executeUnclassified = function(context, passState) { this._unclassifiedCommand.execute(context, passState); }; InvertClassification.prototype.isDestroyed = function() { return false; }; InvertClassification.prototype.destroy = function() { this._fbo = this._fbo && this._fbo.destroy(); this._texture = this._texture && this._texture.destroy(); this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy(); if (defined(this._unclassifiedCommand)) { this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy(); this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy(); } return destroyObject(this); }; export default InvertClassification;