// Author : Chris Tolley
// Date   : 5/18/2004
// HeightBasedTexture.cpp contains the class definition for a texture that
// is generated based on a height map

#include <vector>
#include <windows.h>
#include <gl/gl.h>
#include <math.h>

using namespace std;

#include "HeightBasedTexture.h"
#include "logger.h"

// Constructor.  numPixels is multipled by itself and then 3
// to get the actual size of the texture.  The texture is
// numPixels x numPixels.  numPixels must be a power of 2
HeightBasedTexture::HeightBasedTexture( int numPixels ) : 
									m_iNumPixels( numPixels * numPixels ),
						m_iRows( numPixels ), m_iCols( numPixels )
{
	// Make room for the height data
	m_tData.resize( m_iNumPixels * 3 );
}// End HeightBasedTexture::Constructor


// Destructor
HeightBasedTexture::~HeightBasedTexture()
{}


// Sets up the texture based on the data from the height map
void HeightBasedTexture::initializeTexture( vector< colorSet > colors,
											HeightData& hData )
{
	// Get the number of colums and rows from the height map
	int hCols = hData.getColumns();
	int hRows = hData.getRows();

	unsigned char height = 0;
	int rowIndex = 0;
	int colIndex = 0;

	// For each column of this texture
	for( int z = 0; z < m_iCols; ++z )
	{
		colIndex = ( z * hCols ) / m_iCols;
		// For each row of this texture
		for( int x = 0; x < m_iRows; ++x )
		{
			// Calculate the corresponding row value in the height map
			rowIndex = ( x * hRows ) / m_iRows;

			// Get the height value at rowIndex,colIndex
			height = hData.at( rowIndex, colIndex );

			// Now loop through each color set and calculate this pixels
			// red, green, and blue values
			unsigned char newRed = 0;
			unsigned char newGreen = 0;
			unsigned char newBlue = 0;

			// For each color set
			vector< colorSet >::iterator color = colors.begin();
			for( color; color != colors.end(); ++color )
			{
				// Get the pixel values from the current color
				unsigned char r, g, b;
				color->text_.getTitledPixel( x, z, r, g, b );

				// Calculate the presence of this color at this height
				float presence = 
					calcPresence( color->height_, height, colors.size() );

				// Add the rgb values times the presence to the new color values
				newRed   += r * presence;
				newGreen += g * presence;
				newBlue	 += b * presence;
			}// End for color

			// Set the RGB values for this pixel to the calculated values
			setPixel( x, z, newRed, newGreen, newBlue );

			// Set the rgb values for this pixel to the height at that point
//			setPixel( x, z, height, height, height );
		}// End for x
	}// End for z

	int temp = height;
	temp = rowIndex;
	temp = colIndex;

//	logger::open( "height.xml" );
/*	// Calculate the size of the height map
	int hSize = hData.getColumns() * hData.getRows();

	// For each pixel in the texture we are generating
	int size = m_tData.size();
	unsigned int index;
	for( int n = 0; n < size; n += 3 )
	{
		// Calculate the index of the height value for this pixel
		index = ( n * hSize );// / m_iNumPixels;
		index = index / m_iNumPixels;

		// Get the height value for this pixel
		int height = hData[index];

		// Now loop through each color set and calculate this pixels
		// red, green, and blue values
		unsigned char newRed = 0;
		unsigned char newGreen = 0;
		unsigned char newBlue = 0;

		newRed = height;
		newGreen = height;
		newBlue = height;

		// For each color set
/*		vector< colorSet >::iterator color = colors.begin();
		for( color; color != colors.end(); ++color )
		{
			// Calculate the color's presence at height height
			float presence = 
				calcPresence( height, color->height_, colors.size() );

			newRed   += float( color->red_   ) * presence;
			newGreen += float( color->green_ ) * presence;
			newBlue  += float( color->blue_  ) * presence;
		}// End for color
*/		// Now add the new color values to the texture data
/*		m_tData[n]     = newRed;
		m_tData[n + 1] = newGreen;
		m_tData[n + 2] = newBlue;
	}// End for n
*/
	// Lastly we register this texture with OpenGL
	// Enable Texturing
	glEnable( GL_TEXTURE_2D );

	// Set up this texture object with OpenGL
	glGenTextures( 1, &id_ );
	glBindTexture(GL_TEXTURE_2D, id_);

		// Set up the filter variables.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

     // generate the texture image
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, sqrt( m_iNumPixels ),
				 sqrt( m_iNumPixels ), 0, GL_RGB, GL_UNSIGNED_BYTE, m_tData.begin() );

	// Disable texturing
	glDisable( GL_TEXTURE_2D );
}// End HeightBasedTexture::initializeTexture



// Points r,g,b to the RGB values of the (x,z)th pixel
void HeightBasedTexture::getPixel( int x, int z, unsigned char& r, 
								  unsigned char& g, unsigned char& b )
{
	int index = ( z * ( m_iCols * 3 ) ) + ( x * 3 );
	r = m_tData[index];
	g = m_tData[index + 1];
	b = m_tData[index + 2];
}// End HeightBasedTexture::getPixel


// Sets the (x,z)th pixel color values to r,g,b
void HeightBasedTexture::setPixel( int x, int z, unsigned char r, 
								  unsigned char g, unsigned char b )
{
	int index = ( z * ( m_iCols * 3 ) ) + ( x * 3 );
	m_tData[index]     = r;
	m_tData[index + 1] = g;
	m_tData[index + 2] = b;
}// End HeightBasedTexture::setPixel


// Selects this texture as the current texture for OpenGL to use
void HeightBasedTexture::select()
{
	glBindTexture(GL_TEXTURE_2D, id_);
}// End HeightBasedTexture::select


// Deselects this texture so OpenGL no longer uses it.
void HeightBasedTexture::deselect()
{
	glBindTexture( GL_TEXTURE_2D, 0 );
}// End HeightBasedTexture::deselect


// Calculates h2's presence relative to h1.  numColors is the number
// of color sets there are
float HeightBasedTexture::calcPresence( float h1, float h2, 
										int numColors ) const
{
	float percent = 256 / numColors;
	;
	// Calculate the presence percentage
	float presence;
	presence = ( percent - abs( h1 - h2 )) / percent;

	// Make sure that the presence value in within range
	if( presence < 0.0f )
		presence = 0.0f;
	else
	{
		if( presence > 1.0f )
			presence = 1.0f;
	}// End else

	return presence;
}// End HeightBasedTexture::calcPresence