/*-----------------------------------------
Programmed by Fabre Cédric
(Copland/simson) 02/10/2006
Thanks to the Irrlicht team
for this good 3D engine !
This code has not been tested under Linux.
If you find any errors or corrections,
in advance thanks you for any feedbacks.
-------------------------------------------
Contact : simson2004@wanadoo.fr
-----------------------------------------*/

#include <irrlicht.h>
#include "CEffects.h"

using namespace irr;

CQuadSceneNode::CQuadSceneNode(scene::ISceneNode* parent,scene::ISceneManager* mgr,s32 id): scene::ISceneNode(parent, mgr, id)
{
	Material.DiffuseColor = video::SColor(0,0,0,0);
	Material.EmissiveColor = video::SColor(0,0,0,0);
	Material.SpecularColor = video::SColor(0,0,0,0);
	Material.ZBuffer = false;
	Material.Wireframe = false;
	Material.PointCloud = false;
	Material.Lighting = false;
	Material.BackfaceCulling = false;
	Material.FogEnable = false;
	Material.GouraudShading = false;
	Material.NormalizeNormals = true;
	Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;

	irr::video::E_DRIVER_TYPE dr = mgr->getVideoDriver()->getDriverType();

	if (dr != video::EDT_OPENGL)
	{
		video::SColor Color = video::SColor(4,40,40,40);
		VertexQuad[0]=video::S3DVertex(-1,1,0,0,0,0,Color,0,0);
		VertexQuad[1]=video::S3DVertex(1,1,0,0,0,0,Color,1,0);
		VertexQuad[2]=video::S3DVertex(-1,-1,0,0,0,0,Color,0,1);
		VertexQuad[3]=video::S3DVertex(1,-1,0,0,0,0,Color,1,1);
	}
	else
	{
		video::SColor Color = video::SColor(4,34,34,34);
		VertexQuad[0]=video::S3DVertex(-1,1,0,0,0,0,Color,0,0);
		VertexQuad[1]=video::S3DVertex(1,1,0,0,0,0,Color,1,0);
		VertexQuad[2]=video::S3DVertex(-1,-1,0,0,0,0,Color,0,-1);
		VertexQuad[3]=video::S3DVertex(1,-1,0,0,0,0,Color,1,-1);
	}

	Box.reset(VertexQuad[0].Pos);

	for (s32 i=1; i<4; ++i)
	{
		Box.addInternalPoint(VertexQuad[i].Pos);
	}
}

/* 1.2
void CQuadSceneNode::OnPreRender()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);
	ISceneNode::OnPreRender();
}
*/
void CQuadSceneNode::OnAnimate(u32 timeMs)
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);
	ISceneNode::OnAnimate(timeMs);
}

/*
void CQuadSceneNode::OnRegisterSceneNode()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);
	ISceneNode::OnRegisterSceneNode();
}
*/


void CQuadSceneNode::render()
{
	u16 indices[] = {	0,1,2, 3,2,1	};
	video::IVideoDriver* driver = SceneManager->getVideoDriver();

	driver->setMaterial(Material);
	driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
	driver->drawIndexedTriangleList(&VertexQuad[0], 4, &indices[0], 2);
}

const core::aabbox3d<f32>& CQuadSceneNode::getBoundingBox() const
{
	return Box;
}

//s32 CQuadSceneNode::getMaterialCount()
u32 CQuadSceneNode::getMaterialCount()
{
	return 1;
}

video::SMaterial& CQuadSceneNode::getMaterial(u32 i)
{
	return Material;
}


//Déclaration de RTexGlow;
video::ITexture* RTexGlow=0;
video::ITexture* RTexDream=0;
video::ITexture* RTexNV=0;

//Déclaration d'un CQuadSceneNode (Node personnalisé pour créer un Quad)
CQuadSceneNode* Quad[11];

//Méthode de création du Glow
void CreateGlow(scene::ICameraSceneNode* CamGlow,scene::ISceneManager* smgr,video::IVideoDriver* driver,s32 GlowSize=64)
{
	//On vérifi que la carte vidéo soit cappable d'utiliser le Render To Texture
	if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
	{
		//Ici on creer notre Render Texture
		RTexGlow=driver->createRenderTargetTexture(core::dimension2d<s32>(GlowSize,GlowSize));

		s32 width=0,height=0;
		f32 SizeY=0.75f;
		core::dimension2d<s32>(width,height) = driver->getScreenSize();

		if(height>0)
		{
			SizeY=(f32)(width/height);
		}

		f32 ScaleX = CamGlow->getAspectRatio() * SizeY;

		//Ici on va créer plusieurs quad pour simuler un effet de Blur
		for (int nbquad=0;nbquad<=3;nbquad++)
		{
			Quad[nbquad] = new CQuadSceneNode(smgr->getRootSceneNode(), smgr, 0);
			Quad[nbquad]->setParent(CamGlow);
			Quad[nbquad]->setPosition(irr::core::vector3df(-0.003f+(nbquad/300),-0.001f+(nbquad/300),1.09f));
			Quad[nbquad]->setScale(irr::core::vector3df(ScaleX+((float)nbquad/300),SizeY+((float)nbquad/300),1));
			Quad[nbquad]->setMaterialTexture(0,RTexGlow);
			Quad[nbquad]->drop();
		}
	}
}

//Méthode de rendu du Glow
void RenderGlow(scene::ISceneManager* smgr,video::IVideoDriver* driver,s32 gA=0,s32 gR=0,s32 gG=0,s32 gB=0)
{
	//On test si le Render Texture existe bien
	if (RTexGlow)
	{
		for (int i=0;i<=10;i++)
		{
			if (Quad[i] != NULL)
			{
				if (i==0 || i >=4){Quad[i]->setVisible(false);}else{Quad[i]->setVisible(true);}
			}
		}

		//On affiche notre scene
		driver->setRenderTarget(RTexGlow, true, true, video::SColor(gA,gR,gG,gB));
		smgr->drawAll();
		driver->setRenderTarget(0);

		//On affiche nos quads
		Quad[0]->setVisible(true);

		for (int i=0;i<=10;i++)
		{
			if (Quad[i] != NULL){Quad[i]->updateAbsolutePosition();}
		}
	}
}


//Méthode de création de l'effet Dream Filter
void CreateDreamFilter(scene::ICameraSceneNode* CamDream,scene::ISceneManager* smgr,video::IVideoDriver* driver,f32 EffectSize=1.0f,s32 DreamSize=64)
{
	//On vérifi que la carte vidéo soit cappable d'utiliser le Render To Texture
	if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
	{
		//Ici on creer notre Render Texture
		RTexDream=driver->createRenderTargetTexture(core::dimension2d<s32>(DreamSize,DreamSize));

		s32 width=0,height=0;
		f32 SizeY=0.75f;
		core::dimension2d<s32>(width,height) = driver->getScreenSize();

		if(height>0)
		{
			SizeY=(f32)(width/height);
		}

		f32 ScaleX = CamDream->getAspectRatio() * SizeY;

		//Alors ici on va en créer plusieurs pour simuler un effet de Blur
		for (int nbquad=4;nbquad<=7;nbquad++)
		{
			Quad[nbquad] = new CQuadSceneNode(smgr->getRootSceneNode(), smgr, 0);
			Quad[nbquad]->setParent(CamDream);
			Quad[nbquad]->setPosition(irr::core::vector3df(-0.001f,-0.001f,1.09f));
			Quad[nbquad]->setScale(irr::core::vector3df((ScaleX+((float)nbquad/20)*EffectSize),(SizeY+((float)nbquad/20)*EffectSize),1));
			Quad[nbquad]->setMaterialTexture(0,RTexDream);
			Quad[nbquad]->drop();
		}
	}
}

//Méthode de rendu du DreamFilter
void RenderDreamFilter(scene::ISceneManager* smgr,video::IVideoDriver* driver,s32 dA=0,s32 dR=0,s32 dG=0,s32 dB=0)
{
	//On test si le Render Texture existe bien
	if (RTexDream)
	{
		for (int i=0;i<=10;i++)
		{
			if (Quad[i] != NULL){Quad[i]->setVisible(false);}
		}

		Quad[5]->setVisible(true);
		Quad[6]->setVisible(true);
		Quad[7]->setVisible(true);

		//On affiche notre scene
		driver->setRenderTarget(RTexDream, true, true, video::SColor(dA,dR,dG,dB));
		smgr->drawAll();
		driver->setRenderTarget(0);

		Quad[4]->setVisible(true);

		for (int i=0;i<=10;i++)
		{
			if (Quad[i] != NULL){Quad[i]->updateAbsolutePosition();}
		}
	}
}

//Méthode de création de l'effet NightVision
void CreateNightVision(scene::ICameraSceneNode* CamNightVision,scene::ISceneManager* smgr,video::IVideoDriver* driver,irr::c8* NoiseFile,s32 NightVisionSize=64)
{
		irr::video::E_DRIVER_TYPE dr = smgr->getVideoDriver()->getDriverType();
		irr::video::ITexture* NoiseTexture = driver->getTexture(NoiseFile);

		//Ici on creer notre Render Texture
		RTexNV=driver->createRenderTargetTexture(core::dimension2d<s32>(NightVisionSize,NightVisionSize));

		s32 width=0,height=0;
		f32 SizeY=0.75f;
		core::dimension2d<s32>(width,height) = driver->getScreenSize();

		if(height>0)
		{
			SizeY=(f32)(width/height);
		}

		f32 ScaleX = CamNightVision->getAspectRatio() * SizeY;

		for (int nbquad=8;nbquad<=10;nbquad++)
		{
			Quad[nbquad]= new CQuadSceneNode(smgr->getRootSceneNode(), smgr, 0);
			Quad[nbquad]->setParent(CamNightVision);
			Quad[nbquad]->setPosition(irr::core::vector3df(-0.001f,0.001f,1.09f));
			Quad[nbquad]->setScale(irr::core::vector3df(ScaleX,SizeY,1));

			for (u32 i =0;i<=Quad[nbquad]->getMaterialCount()-1;i++)
			{
				if(nbquad!=10)
				{
					//On test si on est en directx ou autre pour gérer les coloris
					if (dr !=  video::EDT_OPENGL)
					{
						Quad[nbquad]->getMaterial(i).MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA;
						Quad[nbquad]->getMaterial(i).DiffuseColor = video::SColor(10,20,150,20);
						Quad[nbquad]->getMaterial(i).EmissiveColor = video::SColor(10,20,150,20);
						Quad[nbquad]->getMaterial(i).AmbientColor = video::SColor(10,20,150,20);
						Quad[nbquad]->getMaterial(i).SpecularColor = video::SColor(10,20,150,20);
						Quad[nbquad]->getMaterial(i).Lighting=true;
					}
					else
					{
						Quad[nbquad]->getMaterial(i).MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA;
						Quad[nbquad]->getMaterial(i).DiffuseColor = video::SColor(10,10,120,10);
						Quad[nbquad]->getMaterial(i).EmissiveColor = video::SColor(10,10,120,10);
						Quad[nbquad]->getMaterial(i).AmbientColor = video::SColor(10,10,120,10);
						Quad[nbquad]->getMaterial(i).SpecularColor = video::SColor(10,10,120,10);
						Quad[nbquad]->getMaterial(i).Lighting=true;
					}
				}
			}

			if (nbquad!=10)
			{
				Quad[nbquad]->setMaterialTexture(0,RTexNV);
			}
			else
			{
				core::vector3df vec = Quad[nbquad]->getPosition();
				vec.Z = 1.05f;
				scene::ISceneNodeAnimator* noiseAnim = smgr->createFlyCircleAnimator(vec,0.03f,0.7f);
				Quad[nbquad]->setScale(irr::core::vector3df(ScaleX+0.05f,SizeY+0.05f,1));
				Quad[nbquad]->addAnimator(noiseAnim);
				Quad[nbquad]->setMaterialTexture(0,NoiseTexture);
			}

			Quad[nbquad]->drop();
		}
}

//Méthode de rendu de l'effet NightVision
void RenderNightVision(scene::ISceneManager* smgr,video::IVideoDriver* driver)
{
	//On test si le Render Texture existe bien
	if (RTexNV)
	{
		for (int i=0;i<=10;i++)
		{
			if (Quad[i] != NULL)
			{
				if (i<=8){Quad[i]->setVisible(false);}else{Quad[i]->setVisible(true);}
			}
		}

		//On affiche notre scene
		driver->setRenderTarget(RTexNV, true, true, video::SColor(0,0,0,0));
		smgr->drawAll();
		driver->setRenderTarget(0);

		Quad[8]->setVisible(true);

		for (int i=0;i<=10;i++)
		{
			if (Quad[i] != NULL){Quad[i]->updateAbsolutePosition();}
		}
	}
}

//Méthode si l'on ne veut plus rien afficher
void RenderNothing()
{
	for (int i =0;i<=10;i++)
	{
		if (Quad[i]!= NULL){Quad[i]->setVisible(false);}
	}
}

//Méthode de suppression du Glow
void DeleteGlow()
{
	if (RTexGlow){RTexGlow->drop();}
	for (int i=0;i<=3;i++)
	{
		if (Quad[i] != NULL){Quad[i]->remove();}
	}
}

//Méthode de suppression du DreamFilter
void DeleteDream()
{
	if (RTexDream){RTexDream->drop();}
	for (int i=4;i<=7;i++)
	{
		if (Quad[i] != NULL){Quad[i]->remove();}
	}
}

//Méthode de suppression du Night Vision
void DeleteNightVision()
{
	if (RTexNV){RTexNV->drop();}
	for (int i=8;i<=10;i++)
	{
		if (Quad[i] != NULL){Quad[i]->remove();}
	}
}

//Méthode de suppression
void DeleteEffects()
{
	//On test si notre Render Texture existe bien et on supprime
	if (RTexGlow){RTexGlow->drop();}
	if (RTexDream){RTexDream->drop();}
	if (RTexNV){RTexNV->drop();}

	for (int i=0;i<=10;i++)
	{
		if (Quad[i] != NULL){Quad[i]->remove();}
	}
}

