//********************************************************************
// 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: Body.cpp
//********************************************************************

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

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

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

	extern ISceneManager* SceneManager;
	extern NewtonWorld* nWorld;
	extern IVideoDriver* driver;

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

extern "C"
{

	void _cdecl NewtonCollisionDebug(void* userData, int vertexCount, const float* FaceArray, int id);

	/*====================================================================
	Crea un cuerpo vacio*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyNull()
	{
		CBodySceneNode* body = new CBodySceneNode(0,SceneManager,-1);
		body->addBodyNull();
		return (void*)body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cubo*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyCube(float dx,float dy,float dz,float Mass)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyCube(dx,dy,dz,Mass);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de esfera*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodySphere(float rx,float ry,float rz,float Mass)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodySphere(rx,ry,rz,Mass);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cono*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyCone(float radius,float height,float mass,bool Offset)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyCone(radius,height,mass,Offset);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyCylinder(float radius,float height,float mass,bool Offset)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyCylinder(radius,height,mass,Offset);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyCapsule(float radius,float height,float mass,bool Offset)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyCapsule(radius,height,mass,Offset);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyHull(IAnimatedMeshSceneNode* mesh,float mass)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyHull(mesh,mass);
		return (void*)Body;
	} 

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyTree(IAnimatedMeshSceneNode* mesh,float mass)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyTree(mesh,mass);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo  BSP Tree* ---- added by nespa*/
	
	DLL_EXPORT void* DLL_APIENTRY CreateBodyTreeBSP(IAnimatedMesh* mesh,ISceneNode* node)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyTreeBSP(mesh,node);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyTerrain(ITerrainSceneNode* mesh,int LOD)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyTerrain(mesh,LOD);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateBodyWater(float SX,float SY,float SZ,float FluidDensity,float LinearViscosity,float AngulaViscosity)
	{
		CBodySceneNode* Body = new CBodySceneNode(0,SceneManager,-1);
		Body->addBodyWater(SX,SY,SZ,FluidDensity,LinearViscosity,AngulaViscosity);
		return (void*)Body;
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void DLL_APIENTRY BodyFreezeState(CBodySceneNode* body,int State)
	{
		NewtonBodySetFreezeState(body->getBody(),State);
	}

	/*====================================================================
	Assign a material to body ----- added by nespa*/

	DLL_EXPORT void DLL_APIENTRY BodyMaterial(CBodySceneNode* body,int MatID)
	{
		NewtonBodySetMaterialGroupID(body->getBody(),MatID);
	}

	/*====================================================================
	Cambia la masa del cuerpo.*/

	DLL_EXPORT void DLL_APIENTRY BodyMass(CBodySceneNode* body,float NewMass)
	{
		float OldMass,Ixx,Iyy,Izz; 
		NewtonBodyGetMassMatrix(body->getBody(),&OldMass,&Ixx,&Iyy,&Izz); 
		NewtonBodySetMassMatrix(body->getBody(),NewMass,Ixx,Iyy,Izz); 
	}

	/*====================================================================
	Cambia la masa del cuerpo.*/

	DLL_EXPORT void DLL_APIENTRY BodyCenterOfMass(CBodySceneNode* body,float X,float Y,float Z)
	{
		dVector origin(X,Y,Z);
		NewtonBodySetCentreOfMass(body->getBody(),&origin[0]);
	}

	/*====================================================================
	Cambia el centro de inercia del cuerpo.*/

	DLL_EXPORT void DLL_APIENTRY BodyMomentOfInertia(CBodySceneNode* body,float NewIxx,float NewIyy,float NewIzz)
	{
		float OldMass,OldIxx,OldIyy,OldIzz; 
		NewtonBodyGetMassMatrix(body->getBody(),&OldMass,&OldIxx,&OldIyy,&OldIzz); 
		NewtonBodySetMassMatrix(body->getBody(),OldMass,NewIxx,NewIyy,NewIzz); 
	}

	/*====================================================================
	Aplica velocidad lineal al cuerpo.*/

	DLL_EXPORT void DLL_APIENTRY BodyAutoSleep(CBodySceneNode* body,int State)
	{
		NewtonBodySetAutoSleep(body->getBody(),State);
	}

	/*====================================================================
	Aplica velocidad lineal al cuerpo.*/

	DLL_EXPORT void DLL_APIENTRY LinearVelocity(CBodySceneNode* body,float vx,float vy,float vz)
	{
		float velocity[] = {vx,vy,vz};
		NewtonBodySetVelocity(body->getBody(),&velocity[0]);
	}

	/*====================================================================
	Aplica velocidad angular al cuerpo.*/

	DLL_EXPORT void DLL_APIENTRY AngularVelocity(CBodySceneNode* body,float ox,float oy,float oz)
	{
		float omega[] = {ox,oy,oz};
		NewtonBodySetOmega(body->getBody(),&omega[0]);
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void DLL_APIENTRY LinearDamping(CBodySceneNode* body,float linearDamp)
	{
		NewtonBodySetLinearDamping(body->getBody(),linearDamp);
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void DLL_APIENTRY AngularDamping(CBodySceneNode* body,float ax,float ay,float az)
	{
		float anDam[] = { ax,ay,az };
		NewtonBodySetAngularDamping(body->getBody(),anDam);
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT void DLL_APIENTRY AddImpulse(CBodySceneNode* body,float vx,float vy,float vz,float px,float py,float pz)
	{
		float ve[] = {vx,vy,vz};
		float po[] = {px,py,pz};
		NewtonBodyAddImpulse(body->getBody(),ve,po);
	}

	/*====================================================================
	Crea un cuerpo con forma de cilindro*/

	DLL_EXPORT bool DLL_APIENTRY BodiesCollide(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		return b1->BodiesCollide(b2->getBody());
	}

	DLL_EXPORT float DLL_APIENTRY BodyCollX(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		vector3df result = b1->getColl(b2->getBody(),0);
		return result.X;
	}

	DLL_EXPORT float DLL_APIENTRY BodyCollY(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		vector3df result = b1->getColl(b2->getBody(),0);
		return result.Y;
	}

	DLL_EXPORT float DLL_APIENTRY BodyCollZ(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		vector3df result = b1->getColl(b2->getBody(),0);
		return result.Z;
	}

	DLL_EXPORT float DLL_APIENTRY BodyCollNX(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		vector3df result = b1->getColl(b2->getBody(),1);
		return result.X;
	}

	DLL_EXPORT float DLL_APIENTRY BodyCollNY(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		vector3df result = b1->getColl(b2->getBody(),1);
		return result.Y;
	}

	DLL_EXPORT float DLL_APIENTRY BodyCollNZ(CBodySceneNode* b1,CBodySceneNode* b2)
	{
		vector3df result = b1->getColl(b2->getBody(),1);
		return result.Z;
	}

	
	DLL_EXPORT void DLL_APIENTRY DrawBody(CBodySceneNode* b1)
	{
		matrix4 mat;
		SMaterial material;
		material.setTexture(1,0);
		material.setFlag(EMF_LIGHTING, false);
		driver->setTransform(ETS_WORLD, mat);
		driver->setMaterial(material);
		dMatrix t1;
		NewtonBodyGetMatrix(b1->getBody(), &t1[0][0]);
		NewtonCollisionForEachPolygonDo(NewtonBodyGetCollision(b1->getBody()),&t1[0][0],NewtonCollisionDebug,NULL);
	}

	void _cdecl NewtonCollisionDebug(void* userData, int vertexCount, const float* FaceArray, int id)
	{
	   vector3df p0(FaceArray[0], FaceArray[1], FaceArray[2]);
	   const SColor c0(0,0,255,0);
	   for(int i = 2; i < vertexCount; i ++)
	   {
		  vector3df p1(FaceArray[(i-1) * 3 + 0], FaceArray[(i-1) * 3 + 1], FaceArray[(i-1) * 3 + 2]);
		  vector3df p2(FaceArray[i * 3 + 0], FaceArray[i * 3 + 1], FaceArray[i * 3 + 2]);
		  triangle3df t;
		  t.set(p1, p2, p0);
		  driver->draw3DTriangle(t, c0);
		}
	}

}