#pragma once
#ifdef USE_TEMPORAL

#include <unordered_map>
//#include <glm/gtc/matrix_transform.hpp>

#include "OglShader.h"
#include "OglTex.h"
#include "OglFrameBuffer.h"

static bool finish = true;
const int WAVELEVELS = 5;
const float leaveProb = 0.9f;

#define uint unsigned int
#define uchar unsigned char

struct CamData {
	glm::mat4 invMatrix;
	glm::mat4 noTranslMatrix;
	glm::mat4 matrix;
	glm::vec3 pos;
	glm::vec3 posPrev;
	glm::vec2 zClip;
	GLfloat zClipRatio;

	float rotx, roty, dirrotx, dirroty;
};

struct LightData {
	glm::vec3 pos, color;
	glm::mat4 MVP, MVPprev, invMVP;
	bool shadow;
	LightData(glm::vec3 pos, glm::vec3 color, glm::mat4 MVP,
		glm::mat4 MVPprev, glm::mat4 invMVP) :
		pos(pos), color(color), MVP(MVP),
		MVPprev(MVPprev), invMVP(invMVP) {}
};

class OglRenderer {
public:
	void init(uint wi,uint he, string shaderDir);
	void updateBuffers(uint wi, uint he);
	void createRandomTexture();

	void buildShader( string strProg, string strVertex, string strFragment );
	void buildShaderG(string strProg, string strVertex, string strGeometry, string strFragment);
	void buildShaderC(string strProg, string strCompute);
	void enableBuffer( OglFrameBuffer *buffer, bool clear = true );

	//rendering passes
	void GBufferP( OglFrameBuffer *buffer, uint wi, uint he );
	void GBufferAA( OglFrameBuffer *buffer,  uint wi, uint he );
	void GBufferAAG(OglFrameBuffer *buffer, CamData camData, uint wi, uint he);
	void Ambient( OglFrameBuffer *buffer, glm::vec3 ambient, uint wi, uint he );
	void AmbDir( OglFrameBuffer *buffer, glm::vec3 ambient, LightData lDirData, CamData camData, uint wi, uint he, bool geom = false );
	void Quad( OglFrameBuffer *buffer, uint wi, uint he );
	void QuadSrc(OglFrameBuffer *buffer, uint wi, uint he, OglTex *src);
	void QuadA(OglFrameBuffer *buffer, uint wi, uint he, OglTex *src);
	void varBlur(OglFrameBuffer *buffer, uint wi, uint he, OglTex *src);
	void QuadAA( OglFrameBuffer *buffer, uint wi, uint he, bool geom = false );
	void TempAA(OglFrameBuffer *buffer, uint wi, uint he, OglTex *src, OglTex *prevSrc, glm::vec2 res);

	void WaveletBlur(OglFrameBuffer *buffer, uint wi, uint he, OglTex *src, OglTex *srcNormalDepth, glm::vec2 res, float iter);

	void EVSMGauss( OglFrameBuffer *buffer, uint wi, uint he );
	void EVSMGaussV( OglFrameBuffer *buffer, uint wi, uint he );

	//void Blur( OglFrameBuffer *buffer, OglTex *whatTex, uint wi, uint he );

	//void render( OglCam *cam, vector<BVH*> bufferisms, glm::vec3 ambient, OglLightDir *dirLight, bool AA, bool geom, frameinfo frinf, double time, double lastTime );
private:
	OglFrameBuffer GBuffer[2], GBuffer0[2], AABuffer[2], AATemp, DirLBuffer, DirLRangeBuffer[2], AOBuffer;
	OglFrameBuffer waveletBuffer[WAVELEVELS], varBuffer;

	OglShaderProg *activeShader;
	unordered_map<string, OglVertexShader> shVertex;
	unordered_map<string, OglFragmentShader> shFragment;
	unordered_map<string, OglGeometryShader> shGeometry;
	unordered_map<string, OglComputeShader> shCompute;
	unordered_map<string, OglShaderProg> shProg;

	OglTexTarget texColor[2], texNormal[2], texVelocity[2], texAATemp, texAO;
	OglTexTarget texColor2, texNormal2, texVelocity2;
	OglTexTarget texAA[2]; uint texNum, AAp;
	OglTexTarget texDirLRange[2];
	OglTex randomTex;

	char imgNow;
	bool first;
	OglTexImage imgTex, imgVar[2];
	OglTexTarget waveletTex[WAVELEVELS], texVar;

	glm::vec3 lastWiggle;
	uint wim, hem;
	uint wp;
	GLfloat rx[4], ry[4];
	uint cnt, gbId;
};

#endif