#include "Vertex.h"

Vertex::Vertex()
{
	_x = 0.0f;
	_y = 0.0f;
	_z = 0.0f;
	_w = 0.0f;
	_contributeCount = 0;	
	_normal = Vector3D(0, 0, 0);
	_r = 0;
	_g = 0;
	_b = 0;
	_uvIndex = -1;
	_zOriginal = 0;
	_uOverZ = 0;
	_vOverZ = 0;
	_zRecip = 0;
}

Vertex::Vertex(const float x, const float y, const float z)
{
	_x = x;
	_y = y;
	_z = z;
	_w = 1.0f;
	_contributeCount = 0;	
	_normal = Vector3D(0, 0, 0);
	_r = 0;
	_g = 0;
	_b = 0;
	_uvIndex = -1;
	_zOriginal = 0;
	_uOverZ = 0;
	_vOverZ = 0;
	_zRecip = 0;
}

Vertex::Vertex(const float x, const float y, const float z, const float w)
{
	_x = x;
	_y = y;
	_z = z;
	_w = w;
	_contributeCount = 0;	
	_normal = Vector3D(0, 0, 0);
	_r = 0;
	_g = 0;
	_b = 0;
	_uvIndex = -1;
	_zOriginal = 0;
	_uOverZ = 0;
	_vOverZ = 0;
	_zRecip = 0;
}

Vertex::Vertex(const Vertex & other)
{
	Copy(other);
}

float Vertex::GetX() const
{
	return _x;
}

void Vertex::SetX(const float x)
{
	_x = x;
}

float Vertex::GetY() const
{
	return _y;
}

void Vertex::SetY(const float y)
{
	_y = y;
}

float Vertex::GetZ() const
{
	return _z;
}

void Vertex::SetZ(const float z)
{
	_z = z;
}

float Vertex::GetW() const
{
	return _w;
}

void Vertex::SetW(const float w)
{
	_w = w;
}

const int Vertex::GetContributeCount() const
{
	return _contributeCount;
}

void Vertex::IncrementContributeCount()
{
	_contributeCount++;
}

void Vertex::ResetContributeCount()
{
	_contributeCount = 0;
}

const Vector3D& Vertex::GetNormal() const
{
	return _normal;
}

void Vertex::SetNormal(float x, float y, float z)
{
	_normal.SetX(x);
	_normal.SetY(y);
	_normal.SetZ(z);
}

void Vertex::SetNormal(const Vector3D& normal)
{
	SetNormal(normal.GetX(), normal.GetY(), normal.GetZ());
}

void Vertex::NormalizeNormal()
{
	_normal.Normalize();
}

void Vertex::ResetNormal(bool resetCount)
{
	SetNormal(0, 0, 0);
	if (resetCount)
	{
		ResetContributeCount();
	}
}

const COLORREF Vertex::GetColor() const
{
	return RGB(_r, _g, _b);
}

int Vertex::GetR() const
{
	return _r;
}

void Vertex::SetR(const int r)
{
	_r = r;
}

int Vertex::GetG() const
{
	return _g;
}

void Vertex::SetG(const int g)
{
	_g = g;
}

int Vertex::GetB() const
{
	return _b;
}

void Vertex::SetB(const int b)
{
	_b = b;
}

void Vertex::SetColor(int r, int g, int b)
{
	_r = r;
	_g = g;
	_b = b;
}

void Vertex::SetColor(const COLORREF colorIn)
{
	SetColor((int)GetRValue(colorIn), (int)GetGValue(colorIn), (int)GetBValue(colorIn));
}

int Vertex::GetUVIndex() const
{
	return _uvIndex;
}

void Vertex::SetUVIndex(const int index)
{
	_uvIndex = index;
}

float Vertex::GetZOriginal() const
{
	return _zOriginal;
}

float Vertex::GetUOverZ() const
{
	return _uOverZ;
}

void Vertex::SetUOverZ(const float value)
{
	_uOverZ = value / _zOriginal;
}

float Vertex::GetVOverZ() const
{
	return _vOverZ;
}

void Vertex::SetVOverZ(const float value)
{
	_vOverZ = value / _zOriginal;
}

float Vertex::GetZRecip() const
{
	return _zRecip;
}

void Vertex::UVCorrect(float u, float v)
{
	_zOriginal = _w;
	_zRecip = 1 / _zOriginal;
	SetUOverZ(u);
	SetVOverZ(v);
}

int Vertex::GetXInt(bool forceRoundUp) const
{
	if (forceRoundUp)
	{
		return (int)ceil(GetX());
	}
	else
	{
		return (int)floor(GetX());
	}
;}

int Vertex::GetYInt(bool forceRoundUp) const
{
	if (forceRoundUp)
	{
		return (int)ceil(GetY());
	}
	else
	{
		return (int)floor(GetY());
	}
}

int Vertex::GetZInt(bool forceRoundUp) const
{
	if (forceRoundUp)
	{
		return (int)ceil(GetZ());
	}
	else
	{
		return (int)floor(GetZ());
	}
}

int Vertex::GetWInt(bool forceRoundUp) const
{
	if (forceRoundUp)
	{
		return (int)ceil(GetW());
	}
	else
	{
		return (int)floor(GetW());
	}
}

void Vertex::Dehomogenize()
{	
	_x = _x / _w;
	_y = _y / _w;
	_z = _z / _w;
	_w = _w / _w;
}

Vertex& Vertex::operator=(const Vertex& rhs)
{
	// Only do the assignment if we are not assigning
	// to ourselves
	if (this != &rhs)
	{
		Copy(rhs);
	}
	return *this;
}

const Vector3D Vertex::operator-(const Vertex& rhs) const
{		
	return Vector3D(rhs.GetX() - _x, rhs.GetY() - _y, rhs.GetZ() - _z);
}

// The const at the end of the declaraion for '==" indicates that this operation does not change
// any of the member variables in this class.

bool Vertex::operator==(const Vertex& rhs) const
{
	return (_x == rhs.GetX() && _y == rhs.GetY() && _z == rhs.GetZ() && _w == rhs.GetW());
}

// You can see three different uses of 'const' here:
//
// The first const indicates that the method changes the return value, but it is not moved in memory
// The second const indicates that the parameter is passed by reference, but it is not modified
// The third const indicates that the operator does not change any of the memory variables in the class.

const Vertex Vertex::operator+(const Vertex& rhs) const
{
	return Vertex(_x + rhs.GetX(), _y + rhs.GetY(), _z + rhs.GetZ(), _w + rhs.GetW());
}

void Vertex::Copy(const Vertex& other)
{
	_x = other.GetX();
	_y = other.GetY();
	_z = other.GetZ();
	_w = other.GetW();

	_contributeCount = other.GetContributeCount();
	_normal = other.GetNormal();
	
	_r = other.GetR();
	_g = other.GetG();
	_b = other.GetB();

	_uvIndex = other.GetUVIndex();

	_zOriginal = other.GetZOriginal();
	_uOverZ = other.GetUOverZ();
	_vOverZ = other.GetVOverZ();
	_zRecip = other.GetZRecip();
}
