#include "plane.h"

#define PI 3.1415926535897932384626433832795


//bumpmapping idea from:  www.UltimateGameProgramming.com   dot3bumpNet
//see also for further informations

//provide also a simple version; because this really needs a good gfx card!


	// Multitexture functions.
PFNGLACTIVETEXTUREARBPROC   glActiveTextureARB   = NULL;
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;

// main plane
Vector3 Square[4] =
{
   Vector3(-30.0, -.01, -30.0),
   Vector3(30.0, -.01, -30.0),
   Vector3(30.0, -.01, 30.0),
   Vector3(-30.0, -.01, 30.0)
};

//higher ground
Vector3 Square2[4] =
{
   Vector3(-2.0, 1.99, -2.0),
   Vector3(2.0, 1.99, -2.0),
   Vector3(2.0, 1.99, 2.0),
   Vector3(-2.0, 1.99, 2.0)
};


//ramp
Vector3 Square3[4] =
{
	Vector3 (-10.0,0.0,-10.0),
	Vector3 (5.0,5.0,-10.0),
	Vector3 (5.0,5.0,-18.0),
	Vector3 (-10.0,0.0,-18.0)
};
//ramp closing  consists of 2 triangles and a square4
Vector3 Square4[4] =
{
	Vector3 (5.0,0.0,-10.0),
	Vector3 (5.0,0.0,-18.0),
	Vector3 (5.0,5.0,-18.0),
	Vector3 (5.0,5.0,-10.0)
};
Vector3 Triangle1[3] =
{
	Vector3 (-10.0,0.0,-10.0),
	Vector3 (5.0,0.0,-10.0),
	Vector3 (5.0,5.0,-10.0)
};
Vector3 Triangle2[3] =
{
	Vector3 (-10.0,0.0,-18.0),
	Vector3 (5.0,0.0,-18.0),
	Vector3 (5.0,5.0,-18.0)
};


// List of texture coordinates for our object.
Vector2 texCoords[4] =
{
   Vector2(0.0f, 0.0f),
   Vector2(1.0f, 0.0f),
   Vector2(1.0f, 1.0f),
   Vector2(0.0f, 1.0f)
};




plane::plane(void)
{
	nickX=0.f;
	nickZ=0.f;

	
}

bool plane::initialie(Vector3 light_pos)
{

	stabilize_nick = 0; // see damping for use
	

	//setup system  / your pc should support multitextures or else it won't be visible

	 // load extensions 
   char *extension = (char*)glGetString( GL_EXTENSIONS);

   // Check for multitexture support.
   if(strstr(extension, "GL_ARB_multitexture") == NULL)
      return false;

   // Check for texture env combine support.
   if(strstr(extension, "GL_EXT_texture_env_combine") == NULL)
      return false;

   // Grab multitexture functions.
   glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
   glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB");

   // Error checking.
   if(!glActiveTextureARB || !glMultiTexCoord2fARB) return false;


   // Load base texture.
   if(!Terrain.LoadTGA("pics/rock_texture.tga")) return false;
   glGenTextures(1, &Terrain.ID);
   glBindTexture(GL_TEXTURE_2D, Terrain.ID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

   int type = Terrain.type == 3 ? GL_RGB : GL_RGBA;
   gluBuild2DMipmaps(GL_TEXTURE_2D, Terrain.type, Terrain.imageWidth, Terrain.imageHeight,
                     type, GL_UNSIGNED_BYTE, Terrain.image);

   // Load normal map.
   if(!BumpMap.LoadTGA("pics/rock_normal.tga")) return false;
   glGenTextures(1, &BumpMap.ID);
   glBindTexture(GL_TEXTURE_2D, BumpMap.ID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

   type = BumpMap.type == 3 ? GL_RGB : GL_RGBA;
   gluBuild2DMipmaps(GL_TEXTURE_2D, BumpMap.type, BumpMap.imageWidth, BumpMap.imageHeight,
                     type, GL_UNSIGNED_BYTE, BumpMap.image);


   //create a mapping from texture coord. space to object space
   tangentMatrix = Matrix4(  1.0, 0.0, 0.0, 0.0,
							 0.0, 0.0, 1.0, 0.0,
							 0.0, 1.0, 0.0, 0.0,
							 0.0, 0.0, 0.0, 1.0);

   lightPos = light_pos;
   



   	plane_list = glGenLists(1);
	glNewList (plane_list,GL_COMPILE);


		glPushAttrib(GL_TEXTURE_BIT);


	   glActiveTextureARB(GL_TEXTURE0_ARB);
	   glBindTexture (GL_TEXTURE_2D, BumpMap.ID);
	   glEnable(GL_TEXTURE_2D);

	   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
	   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_EXT); 
	   glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
	   glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
	   glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); 
	   glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);

	  
	   glActiveTextureARB(GL_TEXTURE1_ARB);
	   glBindTexture(GL_TEXTURE_2D, Terrain.ID);
	   glEnable(GL_TEXTURE_2D);

	   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
	   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
	   glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
	   glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
	   glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
	   glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);

	   // main plane
	   glBegin(GL_QUADS);

		  for(int i = 0; i < 4; i++)
			 {
				
				Vector3 lightVector = lightPos - Square[i];
				lightVector.normalize();

				lightVector = tangentMatrix * (lightVector);

				lightVector *= 0.5f;
				lightVector += 0.5f;

				glColor3f(lightVector.x, lightVector.y, lightVector.z);

				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texCoords[i].x, texCoords[i].y);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texCoords[i].y, texCoords[i].y);
	      
				glNormal3f(0.0f, 1.0f, 0.0f);
				glVertex3f(Square[i].x, Square[i].y, Square[i].z);

			 }

			//higher ground
		   for(int i = 0; i < 4; i++)
			 {
				Vector3 lightVector = lightPos - Square2[i];
				lightVector.normalize();

				lightVector = tangentMatrix * (lightVector);

				lightVector *= 0.5f;
				lightVector += 0.5f;

				glColor3f(lightVector.x, lightVector.y, lightVector.z);

				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texCoords[i].x, texCoords[i].y);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texCoords[i].y, texCoords[i].y);
	      
				glNormal3f(0.0f, 1.0f, 0.0f);
				glVertex3f(Square2[i].x, Square2[i].y, Square2[i].z);

			 }

		    //ramp
		    for(int i = 0; i < 4; i++)
			 {
				Vector3 lightVector = lightPos - Square3[i];
				lightVector.normalize();

				lightVector = tangentMatrix * (lightVector);

				lightVector *= 0.5f;
				lightVector += 0.5f;

				glColor3f(lightVector.x, lightVector.y, lightVector.z);

				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texCoords[i].x, texCoords[i].y);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texCoords[i].y, texCoords[i].y);
	      
				glNormal3f(0.0f, 1.0f, 0.0f);
				glVertex3f(Square3[i].x, Square3[i].y, Square3[i].z);

			 }
			 //ramp closing
		    for(int i = 0; i < 4; i++)
			 {
				Vector3 lightVector = lightPos - Square4[i];
				lightVector.normalize();

				lightVector = tangentMatrix * (lightVector);

				lightVector *= 0.5f;
				lightVector += 0.5f;

				glColor3f(lightVector.x, lightVector.y, lightVector.z);

				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texCoords[i].x, texCoords[i].y);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texCoords[i].y, texCoords[i].y);
	      
				glNormal3f(1.0f, 0.0f, 0.0f);
				glVertex3f(Square4[i].x, Square4[i].y, Square4[i].z);

			 }

	   glEnd();

	   glBegin(GL_TRIANGLES);
			 //ramp closing
		    for(int i = 0; i < 3; i++)
			 {
				Vector3 lightVector = lightPos - Triangle1[i];
				lightVector.normalize();

				lightVector = tangentMatrix * (lightVector);

				lightVector *= 0.5f;
				lightVector += 0.5f;

				glColor3f(lightVector.x, lightVector.y, lightVector.z);

				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texCoords[i].x, texCoords[i].y);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texCoords[i].y, texCoords[i].y);
	      
				glNormal3f(0.0f, 0.0f, -1.0f);
				glVertex3f(Triangle1[i].x, Triangle1[i].y, Triangle1[i].z);

			 }
			 for(int i = 0; i < 3; i++)
			 {
				Vector3 lightVector = lightPos - Triangle2[i];
				lightVector.normalize();

				lightVector = tangentMatrix * (lightVector);

				lightVector *= 0.5f;
				lightVector += 0.5f;

				glColor3f(lightVector.x, lightVector.y, lightVector.z);

				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texCoords[i].x, texCoords[i].y);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texCoords[i].y, texCoords[i].y);
	      
				glNormal3f(0.0f, 0.0f, 1.0f);
				glVertex3f(Triangle2[i].x, Triangle2[i].y, Triangle2[i].z);

			 }


	   glEnd();

	   glPopAttrib();



	glEndList();




	//simple version
	simple_plane_list = glGenLists(1);
	glNewList (simple_plane_list,GL_COMPILE);


		//glPushAttrib(GL_TEXTURE_BIT);
		//glPushAttrib(GL_ALL_ATTRIB_BITS);

		//glEnable(GL_TEXTURE_2D);

		//glBindTexture(GL_TEXTURE_2D, Terrain.ID);
		glColor3f(0.2,.1,1);
		float mat_color[4] = { .3f, .1f, 1.0f, 1.0f };
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_color);


	  
	   // main plane
	   glBegin(GL_QUADS);
		  for(int i = 0; i < 4; i++)
			 {
			
	      
				glNormal3f(0.0f, 1.0f, 0.0f);
				glVertex3f(Square[i].x, Square[i].y, Square[i].z);

			 }
		
			//higher ground
		   for(int i = 0; i < 4; i++)
			 {

	      
				glNormal3f(0.0f, 1.0f, 0.0f);
				glVertex3f(Square2[i].x, Square2[i].y, Square2[i].z);

			 }

		    //ramp
		    for(int i = 0; i < 4; i++)
			 {
			
	      
				glNormal3f(0.0f, 1.0f, 0.0f);
				glVertex3f(Square3[i].x, Square3[i].y, Square3[i].z);

			 }

			 //ramp closing
		    for(int i = 0; i < 4; i++)
			 {
				
				glNormal3f(1.0f, 0.0f, 0.0f);
				glVertex3f(Square4[i].x, Square4[i].y, Square4[i].z);

			 }
			

	   glEnd();

	   glBegin(GL_TRIANGLES);
			 //ramp closing
		    for(int i = 0; i < 3; i++)
			 {
				
				glNormal3f(0.0f, 0.0f, -1.0f);
				glVertex3f(Triangle1[i].x, Triangle1[i].y, Triangle1[i].z);

			 }
			 for(int i = 0; i < 3; i++)
			 {
				
				glNormal3f(0.0f, 0.0f, 1.0f);
				glVertex3f(Triangle2[i].x, Triangle2[i].y, Triangle2[i].z);

			 }


	   glEnd();


	   glColor3f(.8,.8,.8);


	   //glDisable(GL_TEXTURE_2D);
	   //glPopAttrib();



	glEndList();

   
	gfx_prop=true;

   return true;

}

void plane::render(void)
{

	if (gfx_prop) glCallList(plane_list);
	else glCallList(simple_plane_list);
	   
}

void plane::damp()
{
	if (!(stabilize_nick <= 10))
	{
	nickX = nickX*0.99;
	nickZ = nickZ*0.99;
	} else stabilize_nick++;

}

void plane::nick_plane(float dx, float dz, Vector3 cam_dir)
{
	stabilize_nick = 0;

	float scale_vec = 0.08;

	float angle;
	if (cam_dir.x>0) angle = atanf (cam_dir.z/cam_dir.x);
	else if (cam_dir.x<0) angle = PI + atanf (cam_dir.z/cam_dir.x);
	else if (cam_dir.z>0) angle = PI / 2.f;
	else angle = - PI /2.f;

	//one could define a Matrix RotationY with (PI - angle) and than multiply with Vec3(dx,0,dz)
	//should be equalt to this:

	angle = PI/2.f -angle;
	
	Vector3 vec = Vector3(cosf(angle)*dx+sinf(angle)*dz,0.0, -sinf(angle)*dx+cosf(angle)*dz);
	vec.normalize();
	nickX += (vec.x*scale_vec);
	nickZ += (vec.z*scale_vec);

	//be sure the values don't get too high
	double max = 20.0;
	if (nickX >= max) nickX = max;
	else if (nickX <= -max) nickX = -max;

	if (nickZ >= max) nickZ = max;
	else if (nickZ <= -max) nickZ = -max;



	//printf("current nickX: %f,  nickZ: %f\n",nickX, nickZ);

}

void plane::toggle_gfx()
{
	if (gfx_prop) gfx_prop=false; else gfx_prop = true;
}

plane::~plane(void)
{
	
}



