/*global define*/ define([ '../Core/BoundingRectangle', '../Core/Cartesian2', '../Core/Cartesian4', '../Core/Color', '../Core/defaultValue', '../Core/defined', '../Core/destroyObject', '../Core/Math', '../Core/Matrix4', '../Core/PixelFormat', '../Core/Transforms', '../Renderer/ClearCommand', '../Renderer/PassState', '../Renderer/PixelDatatype', '../Renderer/RenderbufferFormat', '../Shaders/PostProcessFilters/AdditiveBlend', '../Shaders/PostProcessFilters/BrightPass', '../Shaders/PostProcessFilters/GaussianBlur1D', '../Shaders/PostProcessFilters/PassThrough' ], function( BoundingRectangle, Cartesian2, Cartesian4, Color, defaultValue, defined, destroyObject, CesiumMath, Matrix4, PixelFormat, Transforms, ClearCommand, PassState, PixelDatatype, RenderbufferFormat, AdditiveBlend, BrightPass, GaussianBlur1D, PassThrough) { "use strict"; var SunPostProcess = function() { this._fbo = undefined; this._downSampleFBO1 = undefined; this._downSampleFBO2 = undefined; this._clearFBO1Command = undefined; this._clearFBO2Command = undefined; this._downSampleCommand = undefined; this._brightPassCommand = undefined; this._blurXCommand = undefined; this._blurYCommand = undefined; this._blendCommand = undefined; this._fullScreenCommand = undefined; this._downSamplePassState = new PassState(); this._downSamplePassState.scissorTest = { enable : true, rectangle : new BoundingRectangle() }; this._upSamplePassState = new PassState(); this._upSamplePassState.scissorTest = { enabled : true, rectangle : new BoundingRectangle() }; this._uCenter = new Cartesian2(); this._uRadius = undefined; this._blurStep = new Cartesian2(); }; SunPostProcess.prototype.clear = function(context, color) { var clear = this._clearFBO1Command; Color.clone(defaultValue(color, Color.BLACK), clear.color); clear.execute(context); clear = this._clearFBO2Command; Color.clone(defaultValue(color, Color.BLACK), clear.color); clear.execute(context); }; SunPostProcess.prototype.execute = function(context, framebuffer) { this._downSampleCommand.execute(context, this._downSamplePassState); this._brightPassCommand.execute(context, this._downSamplePassState); this._blurXCommand.execute(context, this._downSamplePassState); this._blurYCommand.execute(context, this._downSamplePassState); this._fullScreenCommand.framebuffer = framebuffer; this._blendCommand.framebuffer = framebuffer; this._fullScreenCommand.execute(context); this._blendCommand.execute(context, this._upSamplePassState); }; var viewportBoundingRectangle = new BoundingRectangle(); var downSampleViewportBoundingRectangle = new BoundingRectangle(); var sunPositionECScratch = new Cartesian4(); var sunPositionWCScratch = new Cartesian2(); var sizeScratch = new Cartesian2(); var postProcessMatrix4Scratch= new Matrix4(); SunPostProcess.prototype.update = function(context) { var width = context.drawingBufferWidth; var height = context.drawingBufferHeight; var that = this; if (!defined(this._downSampleCommand)) { this._clearFBO1Command = new ClearCommand({ color : new Color() }); this._clearFBO2Command = new ClearCommand({ color : new Color() }); var rs; var uniformMap = {}; this._downSampleCommand = context.createViewportQuadCommand(PassThrough, { renderState : rs, uniformMap : uniformMap, owner : this }); uniformMap = { u_avgLuminance : function() { // A guess at the average luminance across the entire scene return 0.5; }, u_threshold : function() { return 0.25; }, u_offset : function() { return 0.1; } }; this._brightPassCommand = context.createViewportQuadCommand(BrightPass, { renderState : rs, uniformMap : uniformMap, owner : this }); var delta = 1.0; var sigma = 2.0; uniformMap = { delta : function() { return delta; }, sigma : function() { return sigma; }, direction : function() { return 0.0; } }; this._blurXCommand = context.createViewportQuadCommand(GaussianBlur1D, { renderState : rs, uniformMap : uniformMap, owner : this }); uniformMap = { delta : function() { return delta; }, sigma : function() { return sigma; }, direction : function() { return 1.0; } }; this._blurYCommand = context.createViewportQuadCommand(GaussianBlur1D, { renderState : rs, uniformMap : uniformMap, owner : this }); uniformMap = { u_center : function() { return that._uCenter; }, u_radius : function() { return that._uRadius; } }; this._blendCommand = context.createViewportQuadCommand(AdditiveBlend, { renderState : rs, uniformMap : uniformMap, owner : this }); uniformMap = {}; this._fullScreenCommand = context.createViewportQuadCommand(PassThrough, { renderState : rs, uniformMap : uniformMap, owner : this }); } var downSampleWidth = Math.pow(2.0, Math.ceil(Math.log(width) / Math.log(2)) - 2.0); var downSampleHeight = Math.pow(2.0, Math.ceil(Math.log(height) / Math.log(2)) - 2.0); var downSampleSize = Math.max(downSampleWidth, downSampleHeight); var viewport = viewportBoundingRectangle; viewport.width = width; viewport.height = height; var downSampleViewport = downSampleViewportBoundingRectangle; downSampleViewport.width = downSampleSize; downSampleViewport.height = downSampleSize; var fbo = this._fbo; var colorTexture = (defined(fbo) && fbo.getColorTexture(0)) || undefined; if (!defined(colorTexture) || colorTexture.width !== width || colorTexture.height !== height) { fbo = fbo && fbo.destroy(); this._downSampleFBO1 = this._downSampleFBO1 && this._downSampleFBO1.destroy(); this._downSampleFBO2 = this._downSampleFBO2 && this._downSampleFBO2.destroy(); this._blurStep.x = this._blurStep.y = 1.0 / downSampleSize; var colorTextures = [context.createTexture2D({ width : width, height : height })]; if (context.depthTexture) { fbo = this._fbo = context.createFramebuffer({ colorTextures :colorTextures, depthTexture : context.createTexture2D({ width : width, height : height, pixelFormat : PixelFormat.DEPTH_COMPONENT, pixelDatatype : PixelDatatype.UNSIGNED_SHORT }) }); } else { fbo = this._fbo = context.createFramebuffer({ colorTextures : colorTextures, depthRenderbuffer : context.createRenderbuffer({ format : RenderbufferFormat.DEPTH_COMPONENT16 }) }); } this._downSampleFBO1 = context.createFramebuffer({ colorTextures : [context.createTexture2D({ width : downSampleSize, height : downSampleSize })] }); this._downSampleFBO2 = context.createFramebuffer({ colorTextures : [context.createTexture2D({ width : downSampleSize, height : downSampleSize })] }); this._clearFBO1Command.framebuffer = this._downSampleFBO1; this._clearFBO2Command.framebuffer = this._downSampleFBO2; this._downSampleCommand.framebuffer = this._downSampleFBO1; this._brightPassCommand.framebuffer = this._downSampleFBO2; this._blurXCommand.framebuffer = this._downSampleFBO1; this._blurYCommand.framebuffer = this._downSampleFBO2; var downSampleRenderState = context.createRenderState({ viewport : downSampleViewport }); var upSampleRenderState = context.createRenderState(); this._downSampleCommand.uniformMap.u_texture = function() { return fbo.getColorTexture(0); }; this._downSampleCommand.renderState = downSampleRenderState; this._brightPassCommand.uniformMap.u_texture = function() { return that._downSampleFBO1.getColorTexture(0); }; this._brightPassCommand.renderState = downSampleRenderState; this._blurXCommand.uniformMap.u_texture = function() { return that._downSampleFBO2.getColorTexture(0); }; this._blurXCommand.uniformMap.u_step = function() { return that._blurStep; }; this._blurXCommand.renderState = downSampleRenderState; this._blurYCommand.uniformMap.u_texture = function() { return that._downSampleFBO1.getColorTexture(0); }; this._blurYCommand.uniformMap.u_step = function() { return that._blurStep; }; this._blurYCommand.renderState = downSampleRenderState; this._blendCommand.uniformMap.u_texture0 = function() { return fbo.getColorTexture(0); }; this._blendCommand.uniformMap.u_texture1 = function() { return that._downSampleFBO2.getColorTexture(0); }; this._blendCommand.renderState = upSampleRenderState; this._fullScreenCommand.uniformMap.u_texture = function() { return fbo.getColorTexture(0); }; this._fullScreenCommand.renderState = upSampleRenderState; } var us = context.uniformState; var sunPosition = us.sunPositionWC; var viewMatrix = us.view; var viewProjectionMatrix = us.viewProjection; var projectionMatrix = us.projection; // create up sampled render state var viewportTransformation = Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, postProcessMatrix4Scratch); var sunPositionEC = Matrix4.multiplyByPoint(viewMatrix, sunPosition, sunPositionECScratch); var sunPositionWC = Transforms.pointToGLWindowCoordinates(viewProjectionMatrix, viewportTransformation, sunPosition, sunPositionWCScratch); sunPositionEC.x += CesiumMath.SOLAR_RADIUS; var limbWC = Transforms.pointToGLWindowCoordinates(projectionMatrix, viewportTransformation, sunPositionEC, sunPositionEC); var sunSize = Cartesian2.magnitude(Cartesian2.subtract(limbWC, sunPositionWC, limbWC)) * 30.0 * 2.0; var size = sizeScratch; size.x = sunSize; size.y = sunSize; var scissorRectangle = this._upSamplePassState.scissorTest.rectangle; scissorRectangle.x = Math.max(sunPositionWC.x - size.x * 0.5, 0.0); scissorRectangle.y = Math.max(sunPositionWC.y - size.y * 0.5, 0.0); scissorRectangle.width = Math.min(size.x, width); scissorRectangle.height = Math.min(size.y, height); this._uCenter = Cartesian2.clone(sunPositionWC, this._uCenter); this._uRadius = Math.max(size.x, size.y) * 0.5; // create down sampled render state viewportTransformation = Matrix4.computeViewportTransformation(downSampleViewport, 0.0, 1.0, postProcessMatrix4Scratch); sunPositionWC = Transforms.pointToGLWindowCoordinates(viewProjectionMatrix, viewportTransformation, sunPosition, sunPositionWCScratch); size.x *= downSampleWidth / width; size.y *= downSampleHeight / height; scissorRectangle = this._downSamplePassState.scissorTest.rectangle; scissorRectangle.x = Math.max(sunPositionWC.x - size.x * 0.5, 0.0); scissorRectangle.y = Math.max(sunPositionWC.y - size.y * 0.5, 0.0); scissorRectangle.width = Math.min(size.x, width); scissorRectangle.height = Math.min(size.y, height); this._downSamplePassState.context = context; this._upSamplePassState.context = context; return this._fbo; }; SunPostProcess.prototype.isDestroyed = function() { return false; }; SunPostProcess.prototype.destroy = function() { this._fbo = this._fbo && this._fbo.destroy(); this._downSampleFBO1 = this._downSampleFBO1 && this._downSampleFBO1.destroy(); this._downSampleFBO2 = this._downSampleFBO2 && this._downSampleFBO2.destroy(); this._downSampleCommand = this._downSampleCommand && this._downSampleCommand.shaderProgram && this._downSampleCommand.shaderProgram.destroy(); this._brightPassCommand = this._brightPassCommand && this._brightPassCommand.shaderProgram && this._brightPassCommand.shaderProgram.destroy(); this._blurXCommand = this._blurXCommand && this._blurXCommand.shaderProgram && this._blurXCommand.shaderProgram.destroy(); this._blurYCommand = this._blurYCommand && this._blurYCommand.shaderProgram && this._blurYCommand.shaderProgram.destroy(); this._blendCommand = this._blendCommand && this._blendCommand.shaderProgram && this._blendCommand.shaderProgram.destroy(); this._fullScreenCommand = this._fullScreenCommand && this._fullScreenCommand.shaderProgram && this._fullScreenCommand.shaderProgram.destroy(); return destroyObject(this); }; return SunPostProcess; });