/* global THREE */

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.BloomPass = function ( strength, kernelSize, sigma, resolution ) {

    strength = ( typeof strength !== "undefined" ) ? strength : 1;
    kernelSize = ( typeof kernelSize !== "undefined" ) ? kernelSize : 25;
    sigma = ( typeof sigma !== "undefined" ) ? sigma : 4.0;
    resolution = ( typeof resolution !== "undefined" ) ? resolution : 256;

    // render targets

    var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat };

    this.renderTargetX = new THREE.WebGLRenderTarget( resolution, resolution, pars );
    this.renderTargetY = new THREE.WebGLRenderTarget( resolution, resolution, pars );

    // copy material

    if ( typeof THREE.CopyShader === "undefined" ) {
        console.error( "THREE.BloomPass relies on THREE.CopyShader" );
    }

    var copyShader = THREE.CopyShader;

    this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );

    this.copyUniforms[ "opacity" ].value = strength;

    this.materialCopy = new THREE.ShaderMaterial( {

        uniforms: this.copyUniforms,
        vertexShader: copyShader.vertexShader,
        fragmentShader: copyShader.fragmentShader,
        blending: THREE.AdditiveBlending,
        transparent: true

    } );

    // convolution material

    if ( typeof THREE.ConvolutionShader === "undefined" ) {
        console.error( "THREE.BloomPass relies on THREE.ConvolutionShader" );
    }

    var convolutionShader = THREE.ConvolutionShader;

    this.convolutionUniforms = THREE.UniformsUtils.clone( convolutionShader.uniforms );

    this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurx;
    this.convolutionUniforms[ "cKernel" ].value = THREE.ConvolutionShader.buildKernel( sigma );

    this.materialConvolution = new THREE.ShaderMaterial( {

        uniforms: this.convolutionUniforms,
        vertexShader:  convolutionShader.vertexShader,
        fragmentShader: convolutionShader.fragmentShader,
        defines: {
            "KERNEL_SIZE_FLOAT": kernelSize.toFixed( 1 ),
            "KERNEL_SIZE_INT": kernelSize.toFixed( 0 )
        }

    } );

    this.enabled = true;
    this.needsSwap = false;
    this.clear = false;

};

THREE.BloomPass.prototype = {

    render( renderer, writeBuffer, readBuffer, delta, maskActive ) {

        if ( maskActive ) {
            renderer.context.disable( renderer.context.STENCIL_TEST );
        }

        // Render quad with blured scene into texture (convolution pass 1)

        THREE.EffectComposer.quad.material = this.materialConvolution;

        this.convolutionUniforms[ "tDiffuse" ].value = readBuffer;
        this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurX;

        renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetX, true );


        // Render quad with blured scene into texture (convolution pass 2)

        this.convolutionUniforms[ "tDiffuse" ].value = this.renderTargetX;
        this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurY;

        renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetY, true );

        // Render original scene with superimposed blur to texture

        THREE.EffectComposer.quad.material = this.materialCopy;

        this.copyUniforms[ "tDiffuse" ].value = this.renderTargetY;

        if ( maskActive ) {
            renderer.context.enable( renderer.context.STENCIL_TEST );
        }

        renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer, this.clear );

    }

};

THREE.BloomPass.blurX = new THREE.Vector2( 0.001953125, 0.0 );
THREE.BloomPass.blurY = new THREE.Vector2( 0.0, 0.001953125 );
