//*****************************************************************************************
// Disclaimer, Authorship and License
/*
	This code has been written to serve as a learning tool for the course MAE 574, 
	Virtual Reality Applications and Research, Spring 2009.
	
	Large parts of the code has been adapted from the examples given in the OpenGL 
	Programming Guide by Woo et. al and also from Computer Graphics Using OpenGL by FS Hill
	Some parts of the code has also been adapted from various resources available through 
	out the internet.I thank all those whose code and resources I have used to write these 
	examples. You may use this code for any non-commerical purpose. Feel free to include 
	and use parts of this code for your own application, but remember that this code is not
	entirely bug free, use it at your own risk..If you plan on using the code for your any 
	academic purpose please drop me an email. I would like to attach a link to your course 
	from my home page.

	The Author of this code is Govindarajan Srimathveeravalli, Dept. of Mech and Aero Eng. ,
	University at Buffalo.
*/
//******************************************************************************************
// This code demonstrates the reading and adding multi textures in OpenGL from TGA files.
// Try the following
// 1. Notice how lighting is disabled for the textured background, yet there seems to be
//    an illumination effect. Would enabling the spotlight for the background make any 
//    difference?

#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <string>
#include <stdlib.h>
#include <glut.h>
#include <Glext.h>
#include <math.h>

#include "CTgaImg.h"

float xVal = 10.;
float yVal = 0.;
float zVal = 0.;

// create a checkerboard image.
CTgaImg *img1 = new CTgaImg;
CTgaImg *img2 = new CTgaImg;

PFNGLMULTITEXCOORD2FARBPROC	 glMultiTexCoord2fARB  = NULL;
PFNGLACTIVETEXTUREARBPROC	 glActiveTextureARB	   = NULL;

GLuint texName1;
GLuint texName2;

bool light = true;

// White spotlight :- the spot light points downwards from the emissive white sphere source.
GLfloat white_light_diff[] = { 1., 1., 1., 1. };
GLfloat white_light_amb[] = { .2, .2, .2, 1. };
GLfloat spot_spec[] = { 0.6, 0.6, 0.6, 1. };
GLfloat spot_posn[] = { 0., 0., 100., 1. }; 
GLfloat spot_direcn[] = { 0., 0., -1. };
float spot_cutoff = 2.;
float spot_expo = 0.0;

// Silvery material for the object
GLfloat mat_ambient[] = { 0.19, 0., 0., 1. };
GLfloat mat_diffuse[] = { 1., 0., 0., 1. };
GLfloat mat_specular[] = { 0.51, 0., 0., 1. };

void reshape( int w, int h )
{
	glViewport( 0, 0, (GLsizei)w, (GLsizei)h );
	
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	glFrustum( -.4, .4, -.3, .3, 1., 1300. );
	
	glMatrixMode( GL_MODELVIEW );
	
	glutPostRedisplay();
}

void draw( )
{
	// Prelims
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glLoadIdentity();
 
	gluLookAt( 0., 0., 150., 0., 0., 0., 0., 1., 0. );
	
	glEnable( GL_LIGHTING );
	glDisable( GL_TEXTURE_2D );
	glPushMatrix();
		glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
		glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
		glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
		glTranslatef( 0., 0., 20. );
		glutSolidSphere( 10, 20, 20 );
	glPopMatrix();

	// -------------------------------------------------
	// Light mapping (courtesy Apron Tutorials )
	glDisable( GL_LIGHTING );
	glPushAttrib( GL_TEXTURE_BIT );
	glActiveTextureARB(GL_TEXTURE0_ARB);
	glEnable( GL_TEXTURE_2D );
	glBindTexture(GL_TEXTURE_2D, texName1);

	glActiveTextureARB(GL_TEXTURE1_ARB);
	glEnable( GL_TEXTURE_2D );
	glBindTexture(GL_TEXTURE_2D, texName2);

	glBegin(GL_QUADS);
		// top left vertex
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0., 0.);
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0., 0.);
		glVertex3f( -50, -50, 0. );
		// bottom left vertex
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 0.0f);
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 0.0f);
		glVertex3f( 50, -50, 0. );
		// bottom right vertex
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 1.0f);
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 1.0f);
		glVertex3f( 50, 50, 0. );
		// top right vertex
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 1.0f);
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 1.0f);
		glVertex3f( -50, 50, 0. );
	glEnd();
	glPopAttrib( );
	glDisable( GL_TEXTURE_2D );

	glutSwapBuffers();
}

void init( )
{
	glClearColor( .46, .53, .6, 0. );

	//// Second light is a white spotlight
	glLightfv( GL_LIGHT0, GL_DIFFUSE, white_light_diff );
	glLightfv( GL_LIGHT0, GL_SPECULAR, spot_spec);
	glLightfv( GL_LIGHT0, GL_POSITION, spot_posn );
	glLightfv( GL_LIGHT0, GL_SPOT_DIRECTION, spot_direcn );
	glLightfv( GL_LIGHT0, GL_SPOT_CUTOFF, &spot_cutoff );
	glLightfv( GL_LIGHT0, GL_SPOT_EXPONENT, &spot_expo );

	glEnable( GL_LIGHTING );
	glEnable( GL_LIGHT0 );

	// Read in info from the TGA image now
	std::cout << img1->loadTGAImg("wall.tga") << "\n";
	std::cout << img2->loadTGAImg("light.tga") << "\n";

	glActiveTextureARB	 = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
	glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB");
	
	glGenTextures(1, &texName1);
	glBindTexture(GL_TEXTURE_2D, texName1);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img1->getImgWidth(), img1->getImgHeight(), 
                0, GL_RGB, GL_UNSIGNED_BYTE , img1->getImgPixelData() );
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


	glGenTextures(1, &texName2);
	glBindTexture(GL_TEXTURE_2D, texName2);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img2->getImgWidth(), img2->getImgHeight(), 
                0, GL_RGB, GL_UNSIGNED_BYTE , img2->getImgPixelData() );
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


	// Enable depth testing
	glEnable( GL_DEPTH_TEST );
	// Set up a shading model
	glShadeModel( GL_SMOOTH );
	glEnable( GL_CULL_FACE );
	glEnable( GL_AUTO_NORMAL );
	glEnable( GL_NORMALIZE );
	glFrontFace( GL_CCW );
	glCullFace( GL_BACK );
}

int main(int argc, char* argv[])
{
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
	glutInitWindowPosition( 50, 50 );
	glutInitWindowSize( 640, 480 );
	glutCreateWindow( "Texture - image from file" );

	init();

	glutDisplayFunc( draw );
	glutReshapeFunc( reshape );
	

	glutMainLoop();

	return 0;
}

