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

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

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

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

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

/*--------------------------------------------------------------------
Variables globales*/

	int TotalMeshes = 0;

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

extern "C"
{

/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
	MESH
*/

	/*====================================================================
	Crea una malla vacia*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshNull()
	{
		ISceneNode* mesh = SceneManager->addEmptySceneNode();
		return (void*)mesh;
	}

	/*====================================================================
	Crea una malla con forma de cubo*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshCube()
	{
		const unsigned short u[36] = {0,2,1,0,3,2,1,5,4,1,2,5,4,6,7,4,5,6,7,3,0,7,6,3,9,5,2,9,8,5,0,11,10,0,10,7};

		SMeshBuffer* buffer = new SMeshBuffer();

		buffer->Indices.set_used(36);

		for(unsigned int i=0; i<36; ++i)
			buffer->Indices[i] = u[i];

		SColor clr(255,255,255,255);

		buffer->Vertices.reallocate(12);

		buffer->Vertices.set_used(0);
		buffer->Vertices.push_back(S3DVertex(0,0,0,-1,-1,-1,clr,0,1));
		buffer->Vertices.push_back(S3DVertex(1,0,0, 1,-1,-1,clr,1,1));
		buffer->Vertices.push_back(S3DVertex(1,1,0, 1, 1,-1,clr,1,0));
		buffer->Vertices.push_back(S3DVertex(0,1,0,-1, 1,-1,clr,0,0));
		buffer->Vertices.push_back(S3DVertex(1,0,1, 1,-1, 1,clr,0,1));
		buffer->Vertices.push_back(S3DVertex(1,1,1, 1, 1, 1,clr,0,0));
		buffer->Vertices.push_back(S3DVertex(0,1,1,-1, 1, 1,clr,1,0));
		buffer->Vertices.push_back(S3DVertex(0,0,1,-1,-1, 1,clr,1,1));
		buffer->Vertices.push_back(S3DVertex(0,1,1,-1, 1, 1,clr,0,1));
		buffer->Vertices.push_back(S3DVertex(0,1,0,-1, 1,-1,clr,1,1));
		buffer->Vertices.push_back(S3DVertex(1,0,1, 1,-1, 1,clr,1,0));
		buffer->Vertices.push_back(S3DVertex(1,0,0, 1,-1,-1,clr,0,0));

		buffer->BoundingBox.reset(0,0,0); 

		for(unsigned int i=0; i<12; ++i)
		{
			buffer->Vertices[i].Pos -= core::vector3df(0.5f, 0.5f, 0.5f);
			buffer->Vertices[i].Pos *= 1.0f;
			buffer->BoundingBox.addInternalPoint(buffer->Vertices[i].Pos);
		}

		SMesh* mesh = new SMesh();
		mesh->addMeshBuffer(buffer);
		buffer->drop();

		mesh->recalculateBoundingBox();
		
		SAnimatedMesh* anmesh = new SAnimatedMesh(mesh);

		for (unsigned int i = 0; i<anmesh->getMeshBufferCount();++i)
			anmesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		IAnimatedMeshSceneNode* meshf = SceneManager->addAnimatedMeshSceneNode(anmesh); 
		meshf->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
		meshf->setMaterialFlag(EMF_ANISOTROPIC_FILTER,true);

		TotalMeshes = TotalMeshes+1;

		return (void*)meshf;
	}

	/*====================================================================
	Crea una malla con forma de esfera*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshSphere(int polycount)
	{
		float radius = 1;
		unsigned int polyCountX = polycount;
		unsigned int polyCountY = polycount;

		SMeshBuffer* buffer = new SMeshBuffer();

		if (polyCountX < 2)
			polyCountX = 2;
		if (polyCountY < 2)
			polyCountY = 2;
		if (polyCountX * polyCountY > 32767)
		{
			if (polyCountX > polyCountY)
				polyCountX = 32767/polyCountY-1;
			else
				polyCountY = 32767/(polyCountX+1);
		}

		unsigned int polyCountXPitch = polyCountX+1;
		buffer->Vertices.set_used((polyCountXPitch * polyCountY) + 2);
		buffer->Indices.set_used((polyCountX * polyCountY) * 6);

		const video::SColor clr(100, 255,255,255);

		unsigned int i=0;
		unsigned int level = 0;

		for (unsigned int p1 = 0; p1 < polyCountY-1; ++p1)
		{
			for (u32 p2 = 0; p2 < polyCountX - 1; ++p2)
			{
				const u32 curr = level + p2;
				buffer->Indices[i] = curr + polyCountXPitch;
				buffer->Indices[++i] = curr;
				buffer->Indices[++i] = curr + 1;
				buffer->Indices[++i] = curr + polyCountXPitch;
				buffer->Indices[++i] = curr+1;
				buffer->Indices[++i] = curr + 1 + polyCountXPitch;
				++i;
			}

			buffer->Indices[i] = level + polyCountX - 1 + polyCountXPitch;
			buffer->Indices[++i] = level + polyCountX - 1;
			buffer->Indices[++i] = level + polyCountX;
			++i;

			buffer->Indices[i] = level + polyCountX - 1 + polyCountXPitch;
			buffer->Indices[++i] = level + polyCountX;
			buffer->Indices[++i] = level + polyCountX + polyCountXPitch;
			++i;
			level += polyCountXPitch;
		}

		const unsigned int polyCountSq = polyCountXPitch * polyCountY; // top point
		const unsigned int polyCountSq1 = polyCountSq + 1; // bottom point
		const unsigned int polyCountSqM1 = (polyCountY - 1) * polyCountXPitch; // last row's first vertex

		for (unsigned int p2 = 0; p2 < polyCountX - 1; ++p2)
		{
			buffer->Indices[i] = polyCountSq;
			buffer->Indices[++i] = p2 + 1;
			buffer->Indices[++i] = p2;
			++i;

			buffer->Indices[i] = polyCountSqM1 + p2;
			buffer->Indices[++i] = polyCountSqM1 + p2 + 1;
			buffer->Indices[++i] = polyCountSq1;
			++i;
		}

		buffer->Indices[i] = polyCountSq;
		buffer->Indices[++i] = polyCountX;
		buffer->Indices[++i] = polyCountX-1;
		++i;

		buffer->Indices[i] = polyCountSqM1 + polyCountX - 1;
		buffer->Indices[++i] = polyCountSqM1;
		buffer->Indices[++i] = polyCountSq1;

		const double AngleX = 2 * core::PI / polyCountX;
		const double AngleY = core::PI / polyCountY;

		i = 0;
		double axz;
		double ay = 0;

		for(unsigned int y = 0; y < polyCountY; ++y)
		{
			ay += AngleY;
			const f64 sinay = sin(ay);
			axz = 0;

			for (unsigned int xz = 0;xz < polyCountX; ++xz)
			{
				const vector3df pos(static_cast<f32>(radius * cos(axz) * sinay),
							static_cast<f32>(radius * cos(ay)),
							static_cast<f32>(radius * sin(axz) * sinay));

				vector3df normal(pos);
				normal.normalize();

				float tu = 0.5f;
				if (y==0)
				{
					if (normal.Y != -1.0f && normal.Y != 1.0f)
						tu = static_cast<f32>(acos(clamp(normal.X/sinay, -1.0, 1.0)) * 0.5 *RECIPROCAL_PI64);
					if (normal.Z < 0.0f)
						tu=1-tu;
				}
				else
					tu = buffer->Vertices[i-polyCountXPitch].TCoords.X;
				buffer->Vertices[i] = S3DVertex(pos.X, pos.Y, pos.Z,
							normal.X, normal.Y, normal.Z,
							clr, tu,
							static_cast<f32>(ay*RECIPROCAL_PI64));
				++i;
				axz += AngleX;
			}

			buffer->Vertices[i] = S3DVertex(buffer->Vertices[i-polyCountX]);
			buffer->Vertices[i].TCoords.X = 1.0f;
			++i;
		}

		buffer->Vertices[i] = S3DVertex(0.0f,radius,0.0f,0.0f,1.0f,0.0f,clr,0.5f,0.0f);

		++i;
		buffer->Vertices[i] = S3DVertex(0.0f,-radius,0.0f,0.0f,-1.0f,0.0f,clr,0.5f,1.0f);

		buffer->BoundingBox.reset(buffer->Vertices[i].Pos);
		buffer->BoundingBox.addInternalPoint(buffer->Vertices[i-1].Pos);
		buffer->BoundingBox.addInternalPoint(radius,0.0f,0.0f);
		buffer->BoundingBox.addInternalPoint(-radius,0.0f,0.0f);
		buffer->BoundingBox.addInternalPoint(0.0f,0.0f,radius);
		buffer->BoundingBox.addInternalPoint(0.0f,0.0f,-radius);

		SMesh* mesh = new SMesh();
		mesh->addMeshBuffer(buffer);
		buffer->drop();

		mesh->recalculateBoundingBox();

		SAnimatedMesh* anmesh = new SAnimatedMesh(mesh);

		for (unsigned int i = 0; i<anmesh->getMeshBufferCount();++i)
			anmesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		IAnimatedMeshSceneNode* meshf = SceneManager->addAnimatedMeshSceneNode(anmesh);
		meshf->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
		meshf->setMaterialFlag(EMF_ANISOTROPIC_FILTER,true);

		TotalMeshes = TotalMeshes+1;

		return (void*)meshf;
	}

	/*====================================================================
	Crea una malla con forma de cilindro*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshCylinder(unsigned int tesselation)
	{
		float radius = 1;
		float length = 1;
		const SColor& color = SColor(0xffffffff);
		float oblique = 0;
		bool closeTop = true;

		SMeshBuffer* buffer = new SMeshBuffer();

		const float recTesselation = reciprocal((float)tesselation);
		const float recTesselationHalf = recTesselation * 0.5f;
		const float angleStep = (PI * 2.f ) * recTesselation;
		const float angleStepHalf = angleStep*0.5f;

		unsigned int i;
		S3DVertex v;
		v.Color = color;
		buffer->Vertices.reallocate(tesselation*4+(closeTop?2:1));
		buffer->Indices.reallocate((tesselation*2)*(closeTop?12:9));
		float tcx = 0.f;
		for ( i = 0; i != tesselation; ++i )
		{
			const float angle = angleStep * i;
			v.Pos.X = radius * cosf(angle);
			v.Pos.Y = 0.f;
			v.Pos.Z = radius * sinf(angle);
			v.Normal = v.Pos;
			v.Normal.normalize();
			v.TCoords.X = tcx;
			v.TCoords.Y = 0.0f;
			buffer->Vertices.push_back(v);

			v.Pos.X += oblique;
			v.Pos.Y = length;
			v.Normal = v.Pos;
			v.Normal.normalize();
			v.TCoords.Y = 1.0f;
			buffer->Vertices.push_back(v);

			v.Pos.X = radius * cosf(angle+angleStepHalf);
			v.Pos.Y = 0.f;
			v.Pos.Z = radius * sinf(angle+angleStepHalf);
			v.Normal = v.Pos;
			v.Normal.normalize();
			v.TCoords.X = tcx+recTesselationHalf;
			v.TCoords.Y = 0.0f;
			buffer->Vertices.push_back(v);

			v.Pos.X += oblique;
			v.Pos.Y = length;
			v.Normal = v.Pos;
			v.Normal.normalize();
			v.TCoords.Y = 1.0f;
			buffer->Vertices.push_back(v);
			tcx += recTesselation;
		}

		const unsigned int nonWrappedSize = ( tesselation* 4 )-2;
		for(i = 0;i != nonWrappedSize;i += 2)
		{
			buffer->Indices.push_back(i+2);
			buffer->Indices.push_back(i+0);
			buffer->Indices.push_back(i+1);

			buffer->Indices.push_back(i+2);
			buffer->Indices.push_back(i+1);
			buffer->Indices.push_back(i+3);
		}

		buffer->Indices.push_back(0);
		buffer->Indices.push_back(i+0);
		buffer->Indices.push_back(i+1);

		buffer->Indices.push_back(0);
		buffer->Indices.push_back(i+1);
		buffer->Indices.push_back(1);

		v.Pos.X = 0.0f;
		v.Pos.Y = 0.0f;
		v.Pos.Z = 0.0f;
		v.Normal.X = 0.0f;
		v.Normal.Y = -1.0f;
		v.Normal.Z = 0.0f;
		v.TCoords.X = 1.0f;
		v.TCoords.Y = 1.0f;
		buffer->Vertices.push_back(v);

		unsigned int index = buffer->Vertices.size()-1;

		for ( i = 0; i != nonWrappedSize; i += 2 )
		{
			buffer->Indices.push_back(index);
			buffer->Indices.push_back(i+0);
			buffer->Indices.push_back(i+2);
		}

		buffer->Indices.push_back(index);
		buffer->Indices.push_back(i+0);
		buffer->Indices.push_back(0);

		if (closeTop)
		{
			v.Pos.X = oblique;
			v.Pos.Y = length;
			v.Pos.Z = 0.f;
			v.Normal.X = 0.f;
			v.Normal.Y = 1.f;
			v.Normal.Z = 0.f;
			v.TCoords.X = 0.f;
			v.TCoords.Y = 0.f;
			buffer->Vertices.push_back(v);

			index = buffer->Vertices.size()-1;

			for(i = 0;i != nonWrappedSize;i += 2)
			{
				buffer->Indices.push_back(i+1);
				buffer->Indices.push_back(index);
				buffer->Indices.push_back(i+3);
			}

			buffer->Indices.push_back ( i + 1 );
			buffer->Indices.push_back ( index );
			buffer->Indices.push_back ( 1 );
		}

		buffer->recalculateBoundingBox();
		SMesh* mesh = new SMesh();
		mesh->addMeshBuffer(buffer);
		mesh->recalculateBoundingBox();
		buffer->drop();

		SAnimatedMesh* anmesh = new SAnimatedMesh(mesh);

		for (unsigned int i = 0; i<anmesh->getMeshBufferCount();++i)
			anmesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		IAnimatedMeshSceneNode* meshf = SceneManager->addAnimatedMeshSceneNode(anmesh);
		meshf->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
		meshf->setMaterialFlag(EMF_ANISOTROPIC_FILTER,true);

		TotalMeshes = TotalMeshes+1;

		return (void*)meshf;
	}

	/*====================================================================
	Crea una malla con forma de cono*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshCone(unsigned int tesselation)
	{
		float radius = 1;
		float length = 1;
		const SColor& colorTop = SColor(0xffffffff);
		const SColor& colorBottom = SColor(0xffffffff);
		float oblique = 0;

		SMeshBuffer* buffer = new SMeshBuffer();

		const float angleStep = (PI * 2.f ) / tesselation;
		const float angleStepHalf = angleStep*0.5;

		S3DVertex v;
		unsigned int i;
		float tcx = 0.f;
		v.Color = colorTop;

		for(i = 0;i != tesselation;++i)
		{
			float angle = angleStep * f32(i);

			v.Pos.X = radius * cosf(angle);
			v.Pos.Y = 0.f;
			v.Pos.Z = radius * sinf(angle);
			v.Normal = v.Pos;
			v.Normal.normalize();
			v.TCoords.X = tcx;
			v.TCoords.Y = 0.0f;
			buffer->Vertices.push_back(v);

			angle += angleStepHalf;
			v.Pos.X = radius * cosf(angle);
			v.Pos.Y = 0.0;
			v.Pos.Z = radius * sinf(angle);
			v.Normal = v.Pos;
			v.Normal.normalize();
			v.TCoords.Y = 0.0;
			buffer->Vertices.push_back(v);
		}

		const unsigned int nonWrappedSize = buffer->Vertices.size()-1;

		v.Pos.X = oblique;
		v.Pos.Y = length;
		v.Pos.Z = 0.0;
		v.Normal.X = 0.0;
		v.Normal.Y = 1.0;
		v.Normal.Z = 0.0;
		v.TCoords.X = 0.0;
		v.TCoords.Y = 0.0;
		buffer->Vertices.push_back(v);

		unsigned int index = buffer->Vertices.size()-1;

		for(i = 0;i != nonWrappedSize;i += 1)
		{
			buffer->Indices.push_back(i+0);
			buffer->Indices.push_back(index);
			buffer->Indices.push_back(i+1);
		}

		buffer->Indices.push_back(i+0);
		buffer->Indices.push_back(index);
		buffer->Indices.push_back(0);

		v.Color = colorBottom;
		v.Pos.X = 0.0;
		v.Pos.Y = 0.0;
		v.Pos.Z = 0.0;
		v.Normal.X = 0.;
		v.Normal.Y = -1.0;
		v.Normal.Z = 0.0;
		v.TCoords.X = 1.0;
		v.TCoords.Y = 1.0;
		buffer->Vertices.push_back(v);

		index = buffer->Vertices.size() - 1;

		for(i = 0; i != nonWrappedSize; i += 1)
		{
			buffer->Indices.push_back(index);
			buffer->Indices.push_back(i+0);
			buffer->Indices.push_back(i+1);
		}

		buffer->Indices.push_back(index);
		buffer->Indices.push_back(i+0);
		buffer->Indices.push_back(0);

		buffer->recalculateBoundingBox();
		SMesh* mesh = new SMesh();
		mesh->addMeshBuffer(buffer);
		buffer->drop();

		mesh->recalculateBoundingBox();

		SAnimatedMesh* anmesh = new SAnimatedMesh(mesh);

		for (unsigned int i = 0; i<anmesh->getMeshBufferCount();++i)
			anmesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		IAnimatedMeshSceneNode* meshf = SceneManager->addAnimatedMeshSceneNode(anmesh);
		meshf->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
		meshf->setMaterialFlag(EMF_ANISOTROPIC_FILTER,true);

		TotalMeshes = TotalMeshes+1;

		return (void*)meshf;
	}

	/*====================================================================
	Crea una malla plana*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshPlane(float size,unsigned int tileCount)
	{
		IAnimatedMesh* mesh = SceneManager->addHillPlaneMesh("myHill",
			dimension2d<f32>(size,size),
			dimension2d<u32>(tileCount,tileCount),0,0,
			dimension2d<f32>(0,0),
			dimension2d<f32>(5.0f,5.0f));

		for (unsigned int i = 0; i<mesh->getMeshBufferCount();++i)
			mesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		IAnimatedMeshSceneNode* nmesh = SceneManager->addAnimatedMeshSceneNode(mesh);
			nmesh->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
			nmesh->setMaterialFlag(EMF_ANISOTROPIC_FILTER,true);

		TotalMeshes = TotalMeshes+1;

		return (void*)nmesh;
	}

	/*================================================================
	Carga el archivo de sonido*/

	DLL_EXPORT void* DLL_APIENTRY CreateMeshWater(float Height,float Speed,float Length)
	{
		IAnimatedMesh* mesh = SceneManager->addHillPlaneMesh("myHill",
			dimension2d<f32>(1.0f,1.0f),
			dimension2d<u32>(64,64),0,0,
			dimension2d<f32>(0,0),
			dimension2d<f32>(1.0f,1.0f));

		for (unsigned int i = 0; i<mesh->getMeshBufferCount();++i)
			mesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		ISceneNode* water = SceneManager->addWaterSurfaceSceneNode(mesh->getMesh(0),Height,Speed,Length);
		return (void*)water;
	}

	/*====================================================================
	Carga una malla desde un archivo*/

	DLL_EXPORT void* DLL_APIENTRY LoadMesh(const char* FileName,int ToTangents)
	{
		IAnimatedMesh* mesh = SceneManager->getMesh(FileName);

		for (unsigned int i = 0; i<mesh->getMeshBufferCount();++i)
			mesh->getMeshBuffer(i)->setHardwareMappingHint(EHM_DYNAMIC);

		if(ToTangents)
			((ISkinnedMesh*)mesh)->convertMeshToTangents();
		
		IAnimatedMeshSceneNode* node = SceneManager->addAnimatedMeshSceneNode(mesh);

		node->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
		node->setMaterialFlag(EMF_ANISOTROPIC_FILTER,true);

		node->setLoopMode(false);

		for(unsigned int i = 0;i<node->getMaterialCount();++i)
			node->getMaterial(i).SpecularColor.set(255,255,255,255);

		TotalMeshes = TotalMeshes+1;

		return (void*)node;
	}

	
	



	/*====================================================================
	Dibuja el contorno de la malla a base de lineas*/

	DLL_EXPORT void DLL_APIENTRY OutlineMesh(IAnimatedMeshSceneNode* mesh,float Width,unsigned int R,unsigned int G,unsigned int B)
	{
		SMaterial tmat[MATERIAL_MAX_TEXTURES],lmat;

		lmat.DiffuseColor = SColor(255,R,G,B);
		lmat.SpecularColor = SColor(255,R,G,B);
		lmat.AmbientColor = SColor(255,R,G,B);
		lmat.EmissiveColor = SColor(255,R,G,B);
		lmat.BackfaceCulling = false;
		lmat.FrontfaceCulling = true;
		lmat.Lighting = true;
		lmat.Thickness = Width;
		lmat.Wireframe = true;
		
		for(unsigned int i = 0;i<mesh->getMaterialCount();i++)
		{
			tmat[i] = mesh->getMaterial(i);
			mesh->getMaterial(i) = lmat;
		}

		mesh->render();

		for(unsigned int j = 0;j<mesh->getMaterialCount();j++)
			mesh->getMaterial(j) = tmat[j];
	}

	/*====================================================================
	Hace que la malla proyecte y reciba sombra*/

	DLL_EXPORT void DLL_APIENTRY MeshCastShadow(IAnimatedMeshSceneNode* Mesh)
	{
		Mesh->addShadowVolumeSceneNode(0,-1,true,10000);
	}

	/*====================================================================
	CAmbia de tamaņo la malla*/

	DLL_EXPORT void DLL_APIENTRY ScaleMesh(IAnimatedMeshSceneNode* mesh,float SX,float SY,float SZ)
	{
		mesh->setScale(vector3df(SX,SY,SZ));
		mesh->setMaterialFlag(EMF_NORMALIZE_NORMALS,true);
	}

	/*====================================================================
	DEVUELVE LA POSICION ACTUAL DE LA ANIMACION*/

	DLL_EXPORT int DLL_APIENTRY CurrentFrame(IAnimatedMeshSceneNode* mesh)
	{
		return (int)mesh->getFrameNr();
	}

	/*====================================================================
	DEVUELVE LA POSICION INICIAL DE LA ANIMACION*/

	DLL_EXPORT int DLL_APIENTRY StartFrame(IAnimatedMeshSceneNode* mesh)
	{
		return mesh->getStartFrame();
	}

	/*====================================================================
	DEVUELVE LA POSICION FINAL DE LA ANIMACION*/

	DLL_EXPORT int DLL_APIENTRY EndFrame(IAnimatedMeshSceneNode* mesh)
	{
		return mesh->getEndFrame();
	}

	/*====================================================================
	Anima la malla*/

	DLL_EXPORT void DLL_APIENTRY AnimateMesh(IAnimatedMeshSceneNode* mesh,bool looped,float speed,int begin,int end,float time)
	{
		mesh->setLoopMode(looped);
		mesh->setAnimationSpeed(speed);
		mesh->setFrameLoop(begin,end);
		//mesh->setTransitionTime(time);
	}

	/*====================================================================
	Devuelve TRUE si la malla colisiona con otra malla*/

	DLL_EXPORT bool DLL_APIENTRY MeshesCollide(IAnimatedMeshSceneNode* mesh1,IAnimatedMeshSceneNode* mesh2)
	{ 
		return mesh1->getTransformedBoundingBox().intersectsWithBox(mesh2->getTransformedBoundingBox());
	}

	/*====================================================================
	Devuelve el numero total de vertices que tiene la malla*/

	DLL_EXPORT unsigned int DLL_APIENTRY VertexCount(IAnimatedMeshSceneNode* mesh)
	{
		return mesh->getMesh()->getMeshBuffer(0)->getVertexCount();
	}

/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
	CHILD
*/

	/*====================================================================
	Encuentra una union especifica dentro de la malla*/

	DLL_EXPORT void* DLL_APIENTRY FindChild(IAnimatedMeshSceneNode* Mesh,const char* JointName)
	{
		IBoneSceneNode* Joint = Mesh->getJointNode(JointName);
		return (void*)Joint;
	}

	/*====================================================================
	Devuelve el numero total de uniones que tiene la malla*/

	DLL_EXPORT unsigned int DLL_APIENTRY CountChildren(IAnimatedMeshSceneNode* Mesh)
	{
		return Mesh->getJointCount();
	}

	/*====================================================================
	Devuelve el nombre de una union especifica de la malla*/

	DLL_EXPORT const char* DLL_APIENTRY ChildName(IBoneSceneNode* Joint)
	{
		return Joint->getBoneName();
	}

	/*====================================================================
	Devuelve el numero donde esta situada una union especifica de la malla*/

	DLL_EXPORT unsigned int DLL_APIENTRY ChildIndex(IBoneSceneNode* Joint)
	{
		return Joint->getBoneIndex();
	}

	/*====================================================================
	Devuelve el nombre de una union especifica de la malla*/

	DLL_EXPORT void DLL_APIENTRY ChildMode(IAnimatedMeshSceneNode* Mesh,E_JOINT_UPDATE_ON_RENDER mode)
	{
		Mesh->setJointMode(mode);
	}


	/* ----------------------------------------------------------------------------
load a BSP file creating a mesh object for it and returning it for the caller
to manage  --- added by nespa
*/
DLL_EXPORT void* DLL_APIENTRY LoadMeshBSP( char *cptrFile )
{
    
	IAnimatedMesh* mesh = SceneManager->getMesh( cptrFile );

	return (void *)mesh;
}




/* ----------------------------------------------------------------------------
add the supplied BSPmesh object to the scene as an octtree node --- added by nespa
*/
DLL_EXPORT void* DLL_APIENTRY CreateNodeBSPfromMeshBSP( void *vptrMesh )
{
    // add the mesh to the scene as an octtree
	ISceneNode* node=SceneManager->addOctTreeSceneNode((IAnimatedMesh*)vptrMesh);
	TotalMeshes = TotalMeshes+1;
    return (void *)node;
}



/* ----------------------------------------------------------------------------
add a collision animator to a BSP node --- added by nespa
*/


DLL_EXPORT void DLL_APIENTRY StaticCollisionsBSP(IAnimatedMesh* meshBSP, ISceneNode* nodeBSP ,IAnimatedMeshSceneNode* entity,
											float radiusx, float radiusy, float radiusz,
                                            float gravityx, float gravityy, float gravityz,
											float offsetx, float offsety, float offsetz )

	{
		ITriangleSelector* selector = SceneManager->createOctTreeTriangleSelector(
            meshBSP->getMesh(0), nodeBSP, 128);
		nodeBSP->setTriangleSelector(selector);

		scene::ISceneNodeAnimator* anim = SceneManager->createCollisionResponseAnimator(
		selector, entity, core::vector3df(radiusx,radiusy,radiusz),
		core::vector3df(gravityx,gravityy,gravityz),
		core::vector3df(offsetx,offsety,offsetz));
		entity->addAnimator(anim);
		anim->drop();
		
	}
	
}

	