//********************************************************************
// This source file is part of Ninfa3D Engine
// 
// Copyright (C) 2008-2009 Viz_fuerte.
// All rights reserved.
// 
// LIMITED WARRANTY
// This software is provided "as-is", without any express or implied warranty.
// In no event shall the author be held liable for any damages arising from the use of this software.
// This is a contract. By accepting the Ninfa3D Engine (the SOFTWARE), 
// you (either an individual or a single entity, the LICENSEE) accept the terms and conditions of this licensing agreement.
// 
// If the LICENSEE does not accept the terms and conditions, then LICENSEE must not accept the SOFTWARE.
// If at a later time the LICENSEE decides not to continue licensing the SOFTWARE under these terms and 
// conditions, then the LICENSEE must delete permanently all files constituting the SOFTWARE.
//
// File: Camera.cpp
//********************************************************************

/*--------------------------------------------------------------------
Includos*/

	#include "..\..\Header Files\Ninfa3D.h"

/*--------------------------------------------------------------------
Variables externas*/

	extern IrrlichtDevice* device;
	extern IVideoDriver* driver;
	extern ISceneManager* SceneManager;
	extern IGUIInOutFader* fader;

/*--------------------------------------------------------------------
Declaracion global de funciones*/

extern "C"
{

	/*================================================================
	CREA UNA CAMARA NORMAL*/

	DLL_EXPORT void* DLL_APIENTRY CreateCamera()
	{
		ICameraSceneNode* camera = SceneManager->addCameraSceneNode(0);
		camera->bindTargetAndRotation(true);
		return (void*)camera;
	}

	/*================================================================
	CREA UNA CAMARA DE TIPO ISOMETRICO*/

	DLL_EXPORT void* DLL_APIENTRY CreateCameraIsometric(float Width,float Height,float Near,float Far)
	{
		ICameraSceneNode* camera = SceneManager->addCameraSceneNodeFPS(0);

		matrix4 identity;
		identity.makeIdentity(); 

		matrix4 orthoMatrix;
		orthoMatrix.buildProjectionMatrixOrthoLH(Width,Height,Near,Far);
		camera->setProjectionMatrix(orthoMatrix,true);

		// update the matrices in the driver
		driver->setTransform(ETS_PROJECTION,orthoMatrix);
		driver->setTransform(ETS_VIEW,identity);
		driver->setTransform(ETS_WORLD,identity); 

		return (void*)camera;
	}

	/*================================================================
	CREA UNA CAMARA TIPO FPS*/

	DLL_EXPORT void* DLL_APIENTRY CreateCameraFPS(float rots,float movs)
	{
		SKeyMap keyMap[8];

		keyMap[0].Action = EKA_MOVE_FORWARD;
		keyMap[0].KeyCode = KEY_UP;
		keyMap[1].Action = EKA_MOVE_FORWARD;
		keyMap[1].KeyCode = KEY_KEY_W;

		keyMap[2].Action = EKA_MOVE_BACKWARD;
		keyMap[2].KeyCode = KEY_DOWN;
		keyMap[3].Action = EKA_MOVE_BACKWARD;
		keyMap[3].KeyCode = KEY_KEY_S;

		keyMap[4].Action = EKA_STRAFE_LEFT;
		keyMap[4].KeyCode = KEY_LEFT;
		keyMap[5].Action = EKA_STRAFE_LEFT;
		keyMap[5].KeyCode = KEY_KEY_A;

		keyMap[6].Action = EKA_STRAFE_RIGHT;
		keyMap[6].KeyCode = KEY_RIGHT;
		keyMap[7].Action = EKA_STRAFE_RIGHT;
		keyMap[7].KeyCode = KEY_KEY_D;

		ICameraSceneNode* camera = SceneManager->addCameraSceneNodeFPS(0,rots,movs,-1,keyMap,8);
		return (void*)camera;
	}

	/*================================================================
	CREA UNA CAMARA TIPO MAYA*/

	DLL_EXPORT void* DLL_APIENTRY CreateCameraMaya(float rots,float zoos,float tras)
	{
		ICameraSceneNode* camera = SceneManager->addCameraSceneNodeMaya(0,rots,zoos,tras);
		camera->bindTargetAndRotation(true);

		if(camera)
			device->getLogger()->log("The camera has been created.",ELL_INFORMATION);

		return (void*)camera;
	}

	/*================================================================
	CAMBIA EL RANGO DE LA CAMARA*/

	DLL_EXPORT void DLL_APIENTRY CameraRange(ICameraSceneNode* camera,float n,float f)
	{
		if(camera)
		{
			camera->setNearValue(n);
			camera->setFarValue(f);
		}
		else
			device->getLogger()->log("The camera does not exist.",ELL_ERROR);
	}

	/*================================================================
	APUNTA LA CAMARA A UNAS COORDENADAS 3D*/

	DLL_EXPORT void DLL_APIENTRY CameraTarget(ICameraSceneNode* camera,float tx,float ty,float tz)
	{
		if(camera)
			camera->setTarget(vector3df(tx,ty,tz));
		else
			device->getLogger()->log("The camera does not exist.",ELL_ERROR);
	}

	/*================================================================
	CAMBIA EL TAMAŅO DE VISION DE LA CAMARA*/

	DLL_EXPORT void DLL_APIENTRY CameraViewPort(int wight,int height)
	{
		driver->setViewPort(rect<s32>(-wight,-height,wight,height));
	}
	
	DLL_EXPORT void DLL_APIENTRY CameraAspectRatio(ICameraSceneNode* camera,float aspect)
	{
		if(camera)
			camera->setAspectRatio(aspect);
		else
			device->getLogger()->log("The camera does not exist.",ELL_ERROR);
	}

	DLL_EXPORT void DLL_APIENTRY CameraFOV(ICameraSceneNode* camera,float fovy)
	{
		if(camera)
			camera->setFOV(fovy);
		else
			device->getLogger()->log("The camera does not exist.",ELL_ERROR);
	}

	DLL_EXPORT void DLL_APIENTRY ActiveCamera(ICameraSceneNode* camera)
	{
		if(camera)
			SceneManager->setActiveCamera(camera);
		else
			device->getLogger()->log("The camera does not exist.",ELL_ERROR);
	}

	DLL_EXPORT void* DLL_APIENTRY CameraPick(int x,int y)
	{
		return (void*)SceneManager->getSceneCollisionManager()->getSceneNodeFromScreenCoordinatesBB(position2d<s32>(x,y));
	}

/*
	DLL_EXPORT float DLL_APIENTRY PickedX()
	{
		ICameraSceneNode* camera = SceneManager->getActiveCamera();
		line3d<f32> line;
		line.start = camera->getPosition();
		line.end = line.start+(camera->getTarget()-line.start).normalize()*1000.0f;

		vector3df intersection;
		triangle3df tri;

		IAnimatedMeshSceneNode* mesh = SceneManager->getSceneCollisionManager()->getSceneNodeFromRayBB(line);

		SceneManager->getSceneCollisionManager()->getCollisionPoint(line,mesh->getTriangleSelector(),intersection,tri);
		return intersection.X;
	}

	DLL_EXPORT float DLL_APIENTRY PickedY()
	{
		ICameraSceneNode* camera = SceneManager->getActiveCamera();
		line3d<f32> line;
		line.start = camera->getPosition();
		line.end = line.start+(camera->getTarget()-line.start).normalize()*1000.0f;

		vector3df intersection;
		triangle3df tri;

		IAnimatedMeshSceneNode* mesh = SceneManager->getSceneCollisionManager()->getSceneNodeFromRayBB(line);

		SceneManager->getSceneCollisionManager()->getCollisionPoint(line,mesh->getTriangleSelector(),intersection,tri);
		return intersection.Y;
	}

	DLL_EXPORT float DLL_APIENTRY PickedZ()
	{
		ICameraSceneNode* camera = SceneManager->getActiveCamera();
		line3d<f32> line;
		line.start = camera->getPosition();
		line.end = line.start+(camera->getTarget()-line.start).normalize()*1000.0f;

		vector3df intersection;
		triangle3df tri;

		IAnimatedMeshSceneNode* mesh = SceneManager->getSceneCollisionManager()->getSceneNodeFromRayBB(line);

		SceneManager->getSceneCollisionManager()->getCollisionPoint(line,mesh->getTriangleSelector(),intersection,tri);
		return intersection.Z;
	}
*/
	DLL_EXPORT float DLL_APIENTRY TargetX(ICameraSceneNode* camera)
	{
		vector3df vect = camera->getTarget();
		return vect.X;
	}

	DLL_EXPORT float DLL_APIENTRY TargetY(ICameraSceneNode* camera)
	{
		vector3df vect = camera->getTarget();
		return vect.Y;
	}

	DLL_EXPORT float DLL_APIENTRY TargetZ(ICameraSceneNode* camera)
	{
		vector3df vect = camera->getTarget();
		return vect.Z;
	}

	DLL_EXPORT int DLL_APIENTRY ViewPortWidth()
	{
		return driver->getViewPort().getWidth();
	}

	DLL_EXPORT int DLL_APIENTRY ViewPortHeight()
	{
		return driver->getViewPort().getHeight();
	}

	/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
	FADER
	*/

	/*====================================================================
	Activa y establece el modo de niebla*/

	DLL_EXPORT void DLL_APIENTRY FadeIn(unsigned int Time)
	{
		fader->fadeIn(Time);
	}

	/*====================================================================
	Activa y establece el modo de niebla*/

	DLL_EXPORT void DLL_APIENTRY FadeOut(unsigned int Time)
	{
		fader->fadeOut(Time);
	}

	/*====================================================================
	Activa y establece el modo de niebla*/

	DLL_EXPORT void DLL_APIENTRY FaderColor(unsigned int R,unsigned int G,unsigned int B)
	{
		fader->setColor(SColor(0,R,G,B));
	}

	/*====================================================================
	Activa y establece el modo de niebla*/

	DLL_EXPORT bool DLL_APIENTRY FaderIsReady()
	{
		return fader->isReady();
	}

}