/**
* \file wave_z_compute_byHand.cpp
* \author basile.graf@epfl.ch
*
* !!!! Wave-evaluation function in this file is not automaticaly updated by MATLAB code generation !!!!!
*/


struct seaDatas
{
	float *z;
	float *R;
	float *G;
	float *B;
	int N;
	float L;
};


#include <math.h>

#include "Sea.h"


#define pi 3.14159265358979
#define LUTLEN 64
#define LUTLENF 64.0f


float sinLUT[LUTLEN]; ///< Look Up Table for sine function (used for wave drawing)
float cosLUT[LUTLEN]; ///< Look Up Table for cosine function (used for wave drawing)

seaDatas seaDat;
seaDatas *sd = &seaDat;




/// fill sine and cosine look up tables
void fillWaveLuts()
{
	int k;
	for (k=0; k<LUTLEN; k++)
	{
		sinLUT[k] = sin(((float)k)*(2.0f*pi)/(LUTLENF-1.0f));
		cosLUT[k] = cos(((float)k)*(2.0f*pi)/(LUTLENF-1.0f));
	}
}


/// Cosine approximation using LUT
/**
* \param xarg
* return result
*/
__inline float Wcos(float xarg)
{
	float x;
	x = xarg/(2*pi);
	if (x<0) x=-x;
	x = x - (float (int (x)));
	x *= LUTLENF;
	return cosLUT[int(x)];
}


/// Sine approximation using LUT
/**
* \param xarg
* return result
*/
__inline float Wsin(float xarg)
{
	return Wcos(xarg-pi/2.0f);
}


/// Initialize and allocate memory for sea data
/**
* Don't forget to call free_wave_variables() 
*/
void wave_init()//graphicDatas *gd)
{
	long k;
	int N;

	sd->N = 64;
	sd->L = 150.0;//100

	N = sd->N;

	sd->z = new float [N*N];
	sd->R = new float [N*N];
	sd->G = new float [N*N];
	sd->B = new float [N*N];

	for (k=0; k<N*N; k++) sd->z[k]=0.0f;

	//Fill LUTs:
	fillWaveLuts();
}

/// Compute sea-mesh
/**
* Fill the sea-mesh containig wave heigth on a \f$ N \times N \f$ mesh 
* representing a sea square of \f$ L \times L \f$ meters using LUT functions (faster)
* \param *d : pointer to the datas data-structure
*/
void wave_z_compute(datas *d)//, graphicDatas *gd)
{
	float x,y, a,b;
	long i, j, iN, k;
	long N;
	float L;

	N=sd->N;
	L=sd->L;
	
	x = (float)d->x;
	y = (float)d->y;

	for (i=0; i<N; i++)
	{
		iN=i*N;
		a = x - (L/2.0f)+i*(L/((float)N-1.0f));
		for (j=0; j<N; j++)
		{
			b = y - (L/2.0f)+j*(L/((float)N-1.0f));
			k = iN+j;

			//sd->z[k] = d->Wave_amp0*sin(2.0*pi*(a*cos(d->Wave_angle0)/d->Lambda0+b*sin(d->Wave_angle0)/d->Lambda0+d->V_wave0/d->Lambda0*d->t))+d->Wave_amp1*sin(2.0*pi*(a*cos(d->Wave_angle1)/d->Lambda1+b*sin(d->Wave_angle1)/d->Lambda1+d->V_wave1/d->Lambda1*d->t))+d->Wave_amp2*sin(2.0*pi*(a*cos(d->Wave_angle2)/d->Lambda2+b*sin(d->Wave_angle2)/d->Lambda2+d->V_wave2/d->Lambda2*d->t)); 
			sd->z[k] = d->Wave_amp0*Wsin(2.0*pi*(a*Wcos(d->Wave_angle0)/d->Lambda0+b*Wsin(d->Wave_angle0)/d->Lambda0+d->V_wave0/d->Lambda0*d->t))+d->Wave_amp1*Wsin(2.0*pi*(a*Wcos(d->Wave_angle1)/d->Lambda1+b*Wsin(d->Wave_angle1)/d->Lambda1+d->V_wave1/d->Lambda1*d->t))+d->Wave_amp2*Wsin(2.0*pi*(a*Wcos(d->Wave_angle2)/d->Lambda2+b*Wsin(d->Wave_angle2)/d->Lambda2+d->V_wave2/d->Lambda2*d->t)); 
			//sd->z[k] = 0.0f;
		}
	}

}


/// Free sea data memory
/**
* Free memory allocated by wave_init().
*/
void free_wave_variables()//graphicDatas *gd)
{

	delete [] sd->z;
	delete [] sd->R;
	delete [] sd->G;
	delete [] sd->B;
}


/// Draws the sea
/**
* Once initialization with wave_init() is done, and after each call of wave_z_compute(), 
* this function can be called to actually draw the sea. The code of this function contains OpenGL code.
*/
void Draw_sea()//graphicDatas *gd)
{
	float x,y, a,b, dl;
	long i, j, iN, k;
	long N;
	float L;

	N=sd->N;
	L=sd->L;


	dl = L/((float)N-1);

	glEnable(GL_BLEND) ;
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ; 
	
	glBegin(GL_QUADS);
	for (i=0; i<(N-1); i++)
	{
		iN=i*N;
		a = 0.0 - (L/2.0f)+i*(L/((float)N-1.0f));//a = x - (L/2.0f)+i*(L/((float)N-1.0f));
		for (j=0; j<(N-1); j++)
		{
			b = 0.0 - (L/2.0f)+j*(L/((float)N-1.0f));//b = y - (L/2.0f)+j*(L/((float)N-1.0f));
			k = iN+j;
			glNormal3f(0.0,0.0,1.0);
			glColor4f(0.0f,0.1f*(sd->z[k]+2.0f),0.5f*(sd->z[k]+2.0f),0.7f);
				glVertex3f(a,    b ,   sd->z[k]);	
			glColor4f(0.0f,0.1f*(sd->z[k+N]+2.0f),0.5f*(sd->z[k+N]+2.0f),0.7f);
				glVertex3f(a+dl, b ,   sd->z[k+N]);	
			glColor4f(0.0f,0.1f*(sd->z[k+N+1]+2.0f),0.5f*(sd->z[k+N+1]+2.0f),0.7f);
				glVertex3f(a+dl, b+dl, sd->z[k+N+1]);
			glColor4f(0.0f,0.1f*(sd->z[k+1]+2.0f),0.5f*(sd->z[k+1]+2.0f),0.7f);
				glVertex3f(a,    b+dl, sd->z[k+1]);
		}
	}
	glEnd();
}