/**
 * @author mpk / http://polko.me/
 */

THREE.SMAAPass = function ( width, height ) {

	THREE.Pass.call( this );

	// render targets

	this.edgesRT = new THREE.WebGLRenderTarget( width, height, {
		depthBuffer: false,
		stencilBuffer: false,
		generateMipmaps: false,
		minFilter: THREE.LinearFilter,
		format: THREE.RGBFormat
	} );
	this.edgesRT.texture.name = "SMAAPass.edges";

	this.weightsRT = new THREE.WebGLRenderTarget( width, height, {
		depthBuffer: false,
		stencilBuffer: false,
		generateMipmaps: false,
		minFilter: THREE.LinearFilter,
		format: THREE.RGBAFormat
	} );
	this.weightsRT.texture.name = "SMAAPass.weights";

	// textures
	var scope = this;

	var areaTextureImage = new Image();
	areaTextureImage.src = this.getAreaTexture();
	areaTextureImage.onload = function () {

		// assigning data to HTMLImageElement.src is asynchronous (see #15162)
		scope.areaTexture.needsUpdate = true;

	};

	this.areaTexture = new THREE.Texture();
	this.areaTexture.name = "SMAAPass.area";
	this.areaTexture.image = areaTextureImage;
	this.areaTexture.format = THREE.RGBFormat;
	this.areaTexture.minFilter = THREE.LinearFilter;
	this.areaTexture.generateMipmaps = false;
	this.areaTexture.flipY = false;

	var searchTextureImage = new Image();
	searchTextureImage.src = this.getSearchTexture();
	searchTextureImage.onload = function () {

		// assigning data to HTMLImageElement.src is asynchronous (see #15162)
		scope.searchTexture.needsUpdate = true;

	};

	this.searchTexture = new THREE.Texture();
	this.searchTexture.name = "SMAAPass.search";
	this.searchTexture.image = searchTextureImage;
	this.searchTexture.magFilter = THREE.NearestFilter;
	this.searchTexture.minFilter = THREE.NearestFilter;
	this.searchTexture.generateMipmaps = false;
	this.searchTexture.flipY = false;

	// materials - pass 1

	if ( THREE.SMAAEdgesShader === undefined ) {

		console.error( "THREE.SMAAPass relies on THREE.SMAAShader" );

	}

	this.uniformsEdges = THREE.UniformsUtils.clone( THREE.SMAAEdgesShader.uniforms );

	this.uniformsEdges[ "resolution" ].value.set( 1 / width, 1 / height );

	this.materialEdges = new THREE.ShaderMaterial( {
		defines: Object.assign( {}, THREE.SMAAEdgesShader.defines ),
		uniforms: this.uniformsEdges,
		vertexShader: THREE.SMAAEdgesShader.vertexShader,
		fragmentShader: THREE.SMAAEdgesShader.fragmentShader
	} );

	// materials - pass 2

	this.uniformsWeights = THREE.UniformsUtils.clone( THREE.SMAAWeightsShader.uniforms );

	this.uniformsWeights[ "resolution" ].value.set( 1 / width, 1 / height );
	this.uniformsWeights[ "tDiffuse" ].value = this.edgesRT.texture;
	this.uniformsWeights[ "tArea" ].value = this.areaTexture;
	this.uniformsWeights[ "tSearch" ].value = this.searchTexture;

	this.materialWeights = new THREE.ShaderMaterial( {
		defines: Object.assign( {}, THREE.SMAAWeightsShader.defines ),
		uniforms: this.uniformsWeights,
		vertexShader: THREE.SMAAWeightsShader.vertexShader,
		fragmentShader: THREE.SMAAWeightsShader.fragmentShader
	} );

	// materials - pass 3

	this.uniformsBlend = THREE.UniformsUtils.clone( THREE.SMAABlendShader.uniforms );

	this.uniformsBlend[ "resolution" ].value.set( 1 / width, 1 / height );
	this.uniformsBlend[ "tDiffuse" ].value = this.weightsRT.texture;

	this.materialBlend = new THREE.ShaderMaterial( {
		uniforms: this.uniformsBlend,
		vertexShader: THREE.SMAABlendShader.vertexShader,
		fragmentShader: THREE.SMAABlendShader.fragmentShader
	} );

	this.needsSwap = false;

	this.fsQuad = new THREE.Pass.FullScreenQuad( null );

};

THREE.SMAAPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {

	constructor: THREE.SMAAPass,

	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {

		// pass 1

		this.uniformsEdges[ "tDiffuse" ].value = readBuffer.texture;

		this.fsQuad.material = this.materialEdges;

		renderer.setRenderTarget( this.edgesRT );
		if ( this.clear ) renderer.clear();
		this.fsQuad.render( renderer );

		// pass 2

		this.fsQuad.material = this.materialWeights;

		renderer.setRenderTarget( this.weightsRT );
		if ( this.clear ) renderer.clear();
		this.fsQuad.render( renderer );

		// pass 3

		this.uniformsBlend[ "tColor" ].value = readBuffer.texture;

		this.fsQuad.material = this.materialBlend;

		if ( this.renderToScreen ) {

			renderer.setRenderTarget( null );
			this.fsQuad.render( renderer );

		} else {

			renderer.setRenderTarget( writeBuffer );
			if ( this.clear ) renderer.clear();
			this.fsQuad.render( renderer );

		}

	},

	setSize: function ( width, height ) {

		this.edgesRT.setSize( width, height );
		this.weightsRT.setSize( width, height );

		this.materialEdges.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );
		this.materialWeights.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );
		this.materialBlend.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );

	},

	getAreaTexture: function () {

		return 'data:image/png;base64,[encoded data, 44272 characters]';

	},

	getSearchTexture: function () {

		return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAAhCAAAAABIXyLAAAAAOElEQVRIx2NgGAWjYBSMglEwEICREYRgFBZBqDCSLA2MGPUIVQETE9iNUAqLR5gIeoQKRgwXjwAAGn4AtaFeYLEAAAAASUVORK5CYII=';

	}

} );
