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

import {
	LinearFilter,
	NearestFilter,
	RGBAFormat,
	RGBFormat,
	ShaderMaterial,
	Texture,
	UniformsUtils,
	WebGLRenderTarget
} from "../../../build/three.module.js";
import { Pass } from "../postprocessing/Pass.js";
import { SMAAEdgesShader } from "../shaders/SMAAShader.js";
import { SMAAWeightsShader } from "../shaders/SMAAShader.js";
import { SMAABlendShader } from "../shaders/SMAAShader.js";

var SMAAPass = function ( width, height ) {

	Pass.call( this );

	// render targets

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

	this.weightsRT = new WebGLRenderTarget( width, height, {
		depthBuffer: false,
		stencilBuffer: false,
		generateMipmaps: false,
		minFilter: LinearFilter,
		format: 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 Texture();
	this.areaTexture.name = "SMAAPass.area";
	this.areaTexture.image = areaTextureImage;
	this.areaTexture.format = RGBFormat;
	this.areaTexture.minFilter = 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 Texture();
	this.searchTexture.name = "SMAAPass.search";
	this.searchTexture.image = searchTextureImage;
	this.searchTexture.magFilter = NearestFilter;
	this.searchTexture.minFilter = NearestFilter;
	this.searchTexture.generateMipmaps = false;
	this.searchTexture.flipY = false;

	// materials - pass 1

	if ( SMAAEdgesShader === undefined ) {

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

	}

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

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

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

	// materials - pass 2

	this.uniformsWeights = UniformsUtils.clone( 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 ShaderMaterial( {
		defines: Object.assign( {}, SMAAWeightsShader.defines ),
		uniforms: this.uniformsWeights,
		vertexShader: SMAAWeightsShader.vertexShader,
		fragmentShader: SMAAWeightsShader.fragmentShader
	} );

	// materials - pass 3

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

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

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

	this.needsSwap = false;

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

};

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

	constructor: 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=';

	}

} );

export { SMAAPass };
