/*
								+----------------------------------+
								|                                  |
								|     ***  MyVertex class  ***     |
								|                                  |
								|   Copyright © -tHE SWINe- 2007   |
								|                                  |
								|            MyVertex.h            |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __MY_VERTEX_INCLUDED
#define __MY_VERTEX_INCLUDED

/**
 *	@file dev/MyVertex.h
 *	@date 2007
 *	@author -tHE SWINe-
 *	@brief MyVertex class
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

/*
 *								=== TMyVertex ===
 */

/*
 *	struct TMyVertex
 *		- my custom vertex class
 */
struct TMyVertex {
	Vector3f v_position; // position

	typedef enum {
		n_Texcoord_Num = 4
	};

	Vector3f v_normal;
	Vector4f v_color;
	Vector4f p_texture_coord[n_Texcoord_Num];
	// some more coordinates to make it more curly

	typedef TMyVertex TIntermediate;
	// we will need structure to store intermediate results in.
	// later on, we'll see why is that

	/*
	 *	inline TMyVertex()
	 *		- default constructor, do nothing
	 */
	inline TMyVertex() {};

	/*
	 *	inline TMyVertex(float f_x)
	 *		- constructor with position x parameter
	 *		  (initializes position to [f_x, 0, 0], all other parameters to zero,
	 *		  texcoord's w components are set to 1)
	 */
	inline TMyVertex(float f_x)
		:v_position(f_x, 0, 0), v_normal(0, 0, 0), v_color(0, 0, 0, 0)
	{
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] = Vector4f(0, 0, 0, 1);
	}

	/*
	 *	inline TMyVertex(float f_x, float f_y, float f_z)
	 *		- constructor with 3-space position parameter
	 *		  (initializes position to [f_x, f_y, f_z], all other parameters to zero,
	 *		  texcoord's w components are set to 1)
	 */
	inline TMyVertex(float f_x, float f_y, float f_z)
		:v_position(f_x, f_y, f_z), v_normal(0, 0, 0), v_color(0, 0, 0, 0)
	{
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] = Vector4f(0, 0, 0, 1);
	}

	/*
	 *	inline TMyVertex(const Vector3f &r_v_vector)
	 *		- constructor with 3-space position parameter
	 *		  (initializes position to r_v_vector, all other parameters to zero,
	 *		  texcoord's w components are set to 1)
	 */
	inline TMyVertex(const Vector3f &r_v_vector)
		:v_position(r_v_vector), v_normal(0, 0, 0), v_color(0, 0, 0, 0)
	{
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] = Vector4f(0, 0, 0, 1);
	}

	/*
	 *	inline TMyVertex(const TMyVertex &r_t_vertex)
	 *		- copy-constructor
	 */
	inline TMyVertex(const TMyVertex &r_t_vertex)
		:v_position(r_t_vertex.v_position), v_normal(r_t_vertex.v_normal),
		v_color(r_t_vertex.v_color)
	{
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] = r_t_vertex.p_texture_coord[i];
	}

	/*
	 *	inline operator Vector3f() const
	 *		- conversion to Vector3f should return vertex position
	 */
	inline operator Vector3f() const
	{
		return v_position;
	}

	/*
	 *	inline TMyVertex operator =(const Vector3f &r_v_position)
	 *		- assigning Vector3f should write to vertex position
	 */
	inline TMyVertex operator =(const Vector3f &r_v_position)
	{
		v_position = r_v_position;
		return *this;
	}

	/*
	 *	inline TMyVertex operator =(const TMyVertex &r_t_vertex)
	 *		- we need to specify such an assignment as well to avoid converting
	 *		  TMyVertex to Vector3f when assigning to another TMyVertex
	 */
	inline TMyVertex operator =(const TMyVertex &r_t_vertex)
	{
		v_position = r_t_vertex.v_position;
		v_normal = r_t_vertex.v_normal;
		v_color = r_t_vertex.v_color;
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] = r_t_vertex.p_texture_coord[i];
		return *this;
	}

	/*
	 *	inline bool operator ==(const TMyVertex &r_t_vertex)
	 *		- we might need means to compare two vertices
	 *		- constant f_epsilon is used as maximal coordinate distance tolerance
	 */
	inline bool operator ==(const TMyVertex &r_t_vertex)
	{
		if((v_position - r_t_vertex.v_position).f_Length() >= f_epsilon ||
		   (v_normal - r_t_vertex.v_normal).f_Length() >= f_epsilon ||
		   (v_color - r_t_vertex.v_color).f_Length() >= f_epsilon)
			return false;
		for(int i = 0; i < n_Texcoord_Num; ++ i) {
			if((p_texture_coord[i] - r_t_vertex.p_texture_coord[i]).f_Length() >= f_epsilon)
				return false;
		}
		return true;
	}

	/*
	 *	TVertex operator *(float f_scalar) const
	 *		- return vertex, scaled by f_scalar
	 */
	TMyVertex operator *(float f_scalar) const
	{
		TMyVertex t_tmp;

		t_tmp.v_position = v_position * f_scalar;
		t_tmp.v_normal = v_normal * f_scalar;
		t_tmp.v_color = v_color * f_scalar;
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			t_tmp.p_texture_coord[i] = p_texture_coord[i] * f_scalar;
		// scale vertex

		return t_tmp;
	}

	/*
	 *	TMyVertex operator +(const TMyVertex &r_vertex) const
	 *		- return vertex with sum of coordinates of both original vertices
	 */
	TMyVertex operator +(const TMyVertex &r_vertex) const
	{
		TMyVertex t_tmp;

		t_tmp.v_position = v_position + r_vertex.v_position;
		t_tmp.v_normal = v_normal + r_vertex.v_normal;
		t_tmp.v_color = v_color + r_vertex.v_color;
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			t_tmp.p_texture_coord[i] = p_texture_coord[i] + r_vertex.p_texture_coord[i];
		// add vertex

		return t_tmp;
	}

	/*
	 *	TVertex operator *=(float f_scalar)
	 *		- return vertex, scaled by f_scalar
	 */
	TMyVertex operator *=(float f_scalar)
	{
		v_position *= f_scalar;
		v_normal *= f_scalar;
		v_color *= f_scalar;
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] *= f_scalar;
		// scale vertex

		return *this;
	}

	/*
	 *	TMyVertex operator +=(const TMyVertex &r_vertex)
	 *		- return vertex with sum of coordinates of both original vertices
	 */
	TMyVertex operator +=(const TMyVertex &r_vertex)
	{
		v_position += r_vertex.v_position;
		v_normal += r_vertex.v_normal;
		v_color += r_vertex.v_color;
		for(int i = 0; i < n_Texcoord_Num; ++ i)
			p_texture_coord[i] += r_vertex.p_texture_coord[i];
		// add vertex

		return *this;
	}
};

/*
 *								=== ~TMyVertex ===
 */

#endif // __MY_VERTEX_INCLUDED
