#ifndef HEIGHT_MAP_H
#define HEIGHT_MAP_H

#include <vector>
using namespace std;

#include "./math/Mathematics.h"
#include "./openGLsupport/VBOmanager.h"
#include "./geometry/ModelObject.h"
#include "./texture/TGA.h"

using namespace ANALYTICAL_GEOMETRY;
using namespace GEOMETRY;

/*
Layout of indices:

 0 1 2 ... [sizeX+1]
 3 4 5
 6 7 8
 .
 .
 .
 [sizeY+1]
*/

/*
Polygon layout:

 [0/1]	[2/3]	[4/5]

 [6/7]	[8/9]	[10/11]

 ...	...		...

*/


/*
	v0----------v1
	|  \		|
	|    \	p1	|
	|	p0 \	|
	|		 \	|
	v3-----------v4

	v: vertex index
	p: polygon index
*/

///Creates HeightMap mesh from given 2D array.
/**
*	Loads 2D array of values and create height map mesh (consist of vertices, normals, tex. coords and faces ).
*	HeightMapImporter is primary destinated to generate terrain from height textures.
*/
class HeightMapImporter
{
private:
	vector<float> vertices;
	vector<float> normals;
	vector<float> tCoords;
	vector<int> faces;

	unsigned int size[2];

	void initFaces(void);
	void initVertices(void);

	float scale[3];
public:
	HeightMapImporter( float scaleX, float scaleY, float scaleZ ); /**<scales axisX, axisY and axisZ used for vertices*/

	void init( unsigned int sizeX, unsigned int sizeY );

	template< typename T> void loadVerticesHeight( T* ptr, int offset=1 );	/**<loads vertices from array*/
	template< typename T> void loadNormals( T* ptr );	/**<loads normals from array*/
	template< typename T> void loadTCoords( T* ptr );	/**<loads texture coords from array*/

	void setVertex( unsigned int indexX, unsigned int indexY, float height );	/**<sets vertex height on position [indexX, indexY] */
	void setNormal( unsigned int indexX, unsigned int indexY, float normal[3] ); /**<sets normal on position [indexX, indexY] */
	void setTCoord( unsigned int indexX, unsigned int indexY, float tCoord[2] ); /**<sets tex. coords on position [indexX, indexY] */

	void generateNormals( void );	/**<calculates normals from stored vertices arraz*/
	void generateTCoords( void );	/**<calculates tex. coords from given stored vertices arraz*/

	template< typename T> void autoLoad( unsigned int sizeX, unsigned int sizeY, T* ptr, int offset ); /**<loads vertices from array and generate automatic normals and tex. coords*/

	vector<float> &verticesRef(void);	/**<returns reference to vertices array which is allocated in object*/
	vector<float> &normalsRef(void);	/**<returns reference to normals array which is allocated in object*/
	vector<float>	&tCoordsRef(void);	/**<returns reference to tex. coord array which is allocated in object*/
	vector<int>	 &facesRef(void);		/**<returns reference to faces array which is allocated in object */
};

template< typename T> void HeightMapImporter::autoLoad( unsigned int sizeX, unsigned int sizeY, T* ptr, int offset )
{
	this->init( sizeX, sizeY );

	this->loadVerticesHeight( ptr, offset );
	this->generateNormals();
	this->generateTCoords();
}
template< typename T> void HeightMapImporter::loadVerticesHeight( T* ptr, int offset )
{
	for ( int i=0; i< this->size[0] * this->size[1] ; ++i)
	{
		this->vertices[ i * 3 + 2 ] = ptr[ i*offset ] * this->scale[2];
	}
}
template< typename T> void HeightMapImporter::loadNormals( T* ptr )
{
	for ( int i=0; i< this->size[0] * this->size[1] ; ++i)
	{
		this->vertices[ i * 3 + 0 ] = ptr[ i * 3 + 0 ];
		this->vertices[ i * 3 + 1 ] = ptr[ i * 3 + 1 ];
		this->vertices[ i * 3 + 2 ] = ptr[ i * 3 + 2 ];
	}
}
template< typename T> void HeightMapImporter::loadTCoords( T* ptr )
{
	for ( int i=0; i< this->size[0] * this->size[1] ; ++i)
	{
		this->vertices[ i * 2 + 0 ] = ptr[ i * 2 + 0 ];
		this->vertices[ i * 2 + 1 ] = ptr[ i * 2 + 1 ];
	}
}

//--------------------
void uploadHeightMapGeometry( HeightMapImporter heightMapImporter, VBOmanager& vbo_manager, const string &vbo_name, vector<MeshObject> &dst_meshes);

#endif