// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#ifndef __S_3D_VERTEX_H_INCLUDED__
#define __S_3D_VERTEX_H_INCLUDED__

#include "vector3d.h"
#include "vector2d.h"
#include "SColor.h"

namespace irr
{
namespace video
{

//! Enumeration for all vertex types there are.
enum E_VERTEX_TYPE
{
	//! Standard vertex type used by the Irrlicht engine, video::S3DVertex.
	EVT_STANDARD = 0,

	//! Vertex with two texture coordinates, video::S3DVertex2TCoords. Usually used
	//! for geometry with lightmaps or other special materials.
	EVT_2TCOORDS,

	//! Vertex with a tangent and binormal vector, video::S3DVertexTangents. Usually
	//! used for tangent space normal mapping.
	EVT_TANGENTS
};

//! standard vertex used by the Irrlicht engine.
struct S3DVertex
{
	//! default constructor
	S3DVertex() {};

	//! constructor
	S3DVertex(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv)
		: Pos(x,y,z), Normal(nx,ny,nz), Color(c), TCoords(tu,tv) {}

	//! constructor
	S3DVertex(const core::vector3df& pos, const core::vector3df& normal,
		SColor color, const core::vector2d<f32>& tcoords)
		: Pos(pos), Normal(normal), Color(color), TCoords(tcoords) {}

	//! Position
	core::vector3df Pos;
	
	//! Normal vector
	core::vector3df Normal;

	//! Color
	SColor Color;

	//! Texture coordinates
	core::vector2d<f32> TCoords;

	bool operator == (const S3DVertex& other) const
	{
		return (Pos == other.Pos && Normal == other.Normal &&
			Color == other.Color && TCoords == other.TCoords);
	}

	bool operator != (const S3DVertex& other) const
	{
		return (Pos != other.Pos || Normal != other.Normal ||
			Color != other.Color || TCoords != other.TCoords);
	}

	// < operator is implemented so that vertices can be used as map keys
	bool operator < (const S3DVertex& other) const
	{
		if (Pos.X < other.Pos.X) return true;
		if (Pos.X > other.Pos.X) return false;
		if (Pos.Y < other.Pos.Y) return true;
		if (Pos.Y > other.Pos.Y) return false;
		if (Pos.Z < other.Pos.Z) return true;
		if (Pos.Z > other.Pos.Z) return false;

		if (Normal.X < other.Normal.X) return true;
		if (Normal.X > other.Normal.X) return false;
		if (Normal.Y < other.Normal.Y) return true;
		if (Normal.Y > other.Normal.Y) return false;
		if (Normal.Z < other.Normal.Z) return true;
		if (Normal.Z > other.Normal.Z) return false;

		if (TCoords.X < other.TCoords.X) return true;
		if (TCoords.X > other.TCoords.X) return false;
		if (TCoords.Y < other.TCoords.Y) return true;
		if (TCoords.Y > other.TCoords.Y) return false;

		return false;
	}


	E_VERTEX_TYPE getType() const
	{
		return EVT_STANDARD;
	}
};


//! Vertex with two texture coordinates.
/** Usually used for geometry with lightmaps
or other special materials.
*/
struct S3DVertex2TCoords
{
	//! default constructor
	S3DVertex2TCoords() {};

	//! constructor with two different texture coords
	S3DVertex2TCoords(f32 x, f32 y, f32 z, SColor c, f32 tu, f32 tv, f32 tu2, f32 tv2)
		: Pos(x,y,z), Color(c), TCoords(tu,tv), TCoords2(tu2,tv2) {}

	//! constructor with two different texture coords
	S3DVertex2TCoords(const core::vector3df& pos, SColor color,
		const core::vector2d<f32>& tcoords, const core::vector2d<f32>& tcoords2)
		: Pos(pos), Color(color), TCoords(tcoords), TCoords2(tcoords2) {}

	//! constructor 
	S3DVertex2TCoords(const core::vector3df& pos, const core::vector3df& normal, const SColor& color,
		const core::vector2d<f32>& tcoords, const core::vector2d<f32>& tcoords2)
		: Pos(pos), Normal(normal), Color(color), TCoords(tcoords), TCoords2(tcoords2) {}

	//! constructor with the same texture coords and normal
	S3DVertex2TCoords(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv)
		: Pos(x,y,z), Normal(nx,ny,nz), Color(c), TCoords(tu,tv), TCoords2(tu,tv) {}

	//! constructor with the same texture coords and normal
	S3DVertex2TCoords(const core::vector3df& pos, const core::vector3df& normal,
		SColor color, const core::vector2d<f32>& tcoords)
		: Pos(pos), Normal(normal), Color(color), TCoords(tcoords), TCoords2(tcoords) {}

	//! constructor from S3DVertex
	S3DVertex2TCoords(S3DVertex& o)
		: Pos(o.Pos), Normal(o.Normal), Color(o.Color), TCoords(o.TCoords) {}

	//! Position
	core::vector3df Pos;

	//! Normal
	core::vector3df Normal;

	//! Color
	SColor Color;

	//! First set of texture coordinates
	core::vector2d<f32> TCoords;

	//! Second set of texture coordinates
	core::vector2d<f32> TCoords2;

	//! Equality operator
	bool operator == (const S3DVertex2TCoords& other) const
	{
		return (Pos == other.Pos && Normal == other.Normal &&
			Color == other.Color && TCoords == other.TCoords &&
			TCoords2 == other.TCoords2);
	}

	//! Inequality operator
	bool operator != (const S3DVertex2TCoords& other) const
	{
		return (Pos != other.Pos || Normal != other.Normal ||
			Color != other.Color || TCoords != other.TCoords ||
			TCoords2 != other.TCoords2);
	}

	E_VERTEX_TYPE getType() const
	{
		return EVT_2TCOORDS;
	}
};


//! Vertex with a tangent and binormal vector.
/**  Usually used for tangent space normal mapping.
*/
struct S3DVertexTangents
{
	//! default constructor
	S3DVertexTangents() { };

	//! constructor
	S3DVertexTangents(f32 x, f32 y, f32 z)
	: Pos(x,y,z) { }

	//! constructor
	S3DVertexTangents(const core::vector3df& pos,
		const core::vector2df& tcoords,	SColor c)
		: Pos(pos), Color(c), TCoords(tcoords) { }
		
	//! constructor
	S3DVertexTangents(const core::vector3df& pos, const core::vector3df& normal,
		const core::vector2df& tcoords,	SColor c)
		: Pos(pos), Normal(normal), Color(c), TCoords(tcoords) { }

	//! Position
	core::vector3df Pos;

	//! Normal vector
	core::vector3df Normal;

	//! Color
	SColor Color;

	//! Texture coordinates
	core::vector2d<f32> TCoords;

	//! Tangent vector along the x-axis of the texture
	core::vector3df Tangent;

	//! Binormal vector (tangent x normal)
	core::vector3df Binormal;

	bool operator == (const S3DVertexTangents& other) const
	{
		return (Pos == other.Pos && Normal == other.Normal &&
			Color == other.Color && TCoords == other.TCoords &&
			Tangent == other.Tangent && Binormal == other.Binormal);
	}

	bool operator != (const S3DVertexTangents& other) const
	{
		return (Pos != other.Pos || Normal != other.Normal ||
			Color != other.Color || TCoords != other.TCoords ||
			Tangent != other.Tangent || Binormal != other.Binormal);
	}

	E_VERTEX_TYPE getType() const
	{
		return EVT_TANGENTS;
	}
};



} // end namespace video
} // end namespace irr

#endif

