[c]***********************************************************************************/
//Inlcude Dateien
#include <stdlib.h>
#include <glut.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdio.h>
#include <GLAUX.h>
#include <windows.h>
#define USE_MATH_DEFINES
#include <math.h>
/**********************************************************************************/
// Namespace definieren
using namespace std;
/**********************************************************************************/
// Variablen Deklarieren
// struct fuer die Koordinaten
struct vertice
{
	float x,y,z;
};
// struct fuer die Eckpunkte
struct face
{
	int a,b,c;
};
// vector listen festlegen
vector<face> faces;
vector<vertice> vertices;
// Rotation fuer die Kamera
float xpos = 0, ypos = 0, zpos = 0, xrot = 0, yrot = 0, angle=0.0;
float lastx, lasty;
// Array fue die Tasten, insgesamt koennen 255 Tasten benutzt werden  
bool* keyStates = new bool[256]; 
// Textur
GLuint texture;
bool textur1 =  true;
bool textur2 =  false;
// Variablen fuer die Objekte
GLint objModel;
GLint objModel2;
// Definieren des Lichtes
//Licht1
GLfloat Light0Ambient[]=		{ 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat Light0Diffuse[]=		{ 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat Light0Specular[] =		{ 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat Light0Position[]=		{ 0.0f, -10.0f, 2.0f,0.0f };
//Licht2
GLfloat Light1Ambient[]=		{ 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat Light1Diffuse[]=		{ 0.0f, 0.0f, 1.0f, 1.0f };
GLfloat Light1Specular[] =		{ 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat Light1Position[]=		{ -20.0f, 10.0f, 2.0f,0.0f };
//Licht3
GLfloat Light2Ambient[]=		{ 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat Light2Diffuse[]=		{ 1.0f, 0.0f, 0.0f, 1.0f };
GLfloat Light2Specular[] =		{ 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat Light2Position[]=		{ 20.0f, 12.0f, 2.0f, 0.0f };
/***************************************************************************************/
// Funktion fuer das Berechnen der Normalen
vertice normalize(vertice a,vertice b, vertice c)
{
		vertice q;
		vertice w;
		vertice n1;
		vertice n2;
		float laenge;
		q.x = a.x - b.x;
		q.y = a.y - b.y;
		q.z = a.z - b.z;
		w.x = a.x - c.x;
		w.y = a.y - c.y;
		w.z = a.z - c.z;
		// Kreuzprodukt berechnen
		n1.x = ( q.y * w.z ) - ( q.z * w.y);
		n1.y = ( q.z * w.x ) - ( q.x * w.z);
		n1.z = ( q.x * w.y ) - ( q.y * w.x);
		// Skalarprodukt berechnen
		laenge = sqrt( ( n1.x * n1.x ) + ( n1.y * n1.y ) + ( n1.z * n1.z ) );
		// Kreuzprodukt durch die Laenge Teilen
		n2.x = n1.x / laenge;
		n2.y = n1.y / laenge;
		n2.z = n1.z / laenge;
		// gebe n2 zurueck
		return n2;
}
// Funktion fuer das Laden der Textur
GLuint LoadTexture( const char * filename, int width, int height )
{
 
   unsigned char * data;
	FILE * file;
	// Der folgende Code liest die Raw/Bmp datei
	// file oeffnen
	file = fopen( filename, "rb" ); 
	// wenn die Datei leer ist, soll die Textur auch leer sein
	if ( file == NULL ) 
	{
	   return 0; 
	}
	// festlegen des Speichers fuer die Textur
	data = (unsigned char *)malloc( width * height * 3 ); 
	// In der Datei lesen
	fread( data, width * height * 3, 1, file ); 
	// Datei wieder schliessen
	fclose( file ); 
	// Generiere Textur
	glGenTextures( 1, &texture ); 
	// Textur binden
	glBindTexture( GL_TEXTURE_2D, texture ); 
	// Enviroment Textur Parameter
	// The parameter GL_MODULATE will blend the texture with 
	// whatever is underneath, setting it to GL_DECAL
	// will tell the texture to replace whatever is on the object.
   glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); 
	// festlegen welche Textur wann benutzt wird. MIN filter = welche qualitaet gezeigt
	// wird wenn man nah dran ist , MAG Filter = welche qualitaet gezeigt
	// wird wenn das Objekt weiter weg ist.
	// Das erste ist das schlechteste und das letzte das beste von der Qualität
	// GL_NEAREST
	// GL_LINEAR
	// GL_LINEAR_MIPMAP_NEAREST
	// GL_LINEAR_MIPMAP_LINEAR
	// Mip Map Filter festlegen fuer das Enviroment
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	// Parameter um Textur zu wiederholen. 
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
	// Generiere Textur
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
	// gebe Textur Frei
	free( data ); 
	// return the texture data
	return texture; 
}
// aufraeumen sonst wird opengl sehr langsam und der Speicher zu voll
void FreeTexture( GLuint texture )
{
	// Textur Löschen reicht aus
  glDeleteTextures( 1, &texture ); 
}
	
		
void ausgtest()
{
	vector<vertice> normals;
	vector<vertice> facenormals;
	vector <vertice> unnormals;
	vector <int> anz_fl;
	vertice temp;
		temp.x=0;
		temp.y=0;
		temp.z=0;
	int first,second,third;
	for(unsigned int i = 0; i< vertices.size(); i++)
	{
		unnormals.push_back( temp );
		normals.push_back( temp );
		anz_fl.push_back (0) ;
	}
	for(unsigned int i = 0; i< faces.size(); i++)
	{
		facenormals.push_back(temp);
	}
	vertice fnorm;
	fnorm.x=0;
	fnorm.y=0;
	fnorm.z=0;
	
	vertice norm;
	norm.x=0;
	norm.y=0;
	norm.z=0;
	float laenge = 0.0;
	
	for(unsigned int i = 0; i< faces.size();i++)
	{
		anz_fl[faces.a]++;
		anz_fl[faces[i].b]++;
		anz_fl[faces[i].c]++;
		fnorm = normalize(vertices[faces[i].a],vertices[faces[i].b],vertices[faces[i].c]);
		facenormals[i].x = fnorm.x;
		facenormals[i].y = fnorm.y;
		facenormals[i].z = fnorm.z;
	}
		for(unsigned int j = 0; j< faces.size(); j++)
		{
			first = faces[j].a;
			second = faces[j].b;
			third = faces[j].c;
			unnormals[first].x += facenormals[j].x;
			unnormals[first].y += facenormals[j].y;
			unnormals[first].z += facenormals[j].z;
			
			unnormals[second].x += facenormals[j].x;
			unnormals[second].y += facenormals[j].y;
			unnormals[second].z += facenormals[j].z;
			unnormals[third].x += facenormals[j].x;
			unnormals[third].y += facenormals[j].y;
			unnormals[third].z += facenormals[j].z;
		}
	for(unsigned int i = 0; i< vertices.size();i++)
	{
		norm.x = unnormals[i].x / anz_fl[i];
		norm.y = unnormals[i].y / anz_fl[i];
		norm.z = unnormals[i].z / anz_fl[i];
		laenge = sqrt( ( norm.x * norm.x ) + ( norm.y * norm.y ) + ( norm.z * norm.z ) );
		normals[i].x = norm.x / laenge;
		normals[i].y = norm.y / laenge;
		normals[i].z = norm.z / laenge;
		glNormal3f( normals[i].x, normals[i].y, normals[i].z );
	}
// Normalen und Textur Koordinaten festlegen
	for(unsigned int k=0;k<faces.size();k++)
	{
		glNormal3f(normals[faces[k].a].x, normals[faces[k].a].y, normals[faces[k].a].z );
		glTexCoord2f(0.0f, 0.0f);
		glVertex3f( vertices[faces[k].a].x, vertices[faces[k].a].y, vertices[faces[k].a].z );
		
		glNormal3f(normals[faces[k].b].x, normals[faces[k].b].y, normals[faces[k].b].z );
		glTexCoord2f(1.0f, 0.0f);
		glVertex3f( vertices[faces[k].b].x, vertices[faces[k].b].y, vertices[faces[k].b].z );
		
		glNormal3f(normals[faces[k].c].x, normals[faces[k].c].y, normals[faces[k].c].z );
		glTexCoord2f(0.0f, 1.0f); 
		glVertex3f( vertices[faces[k].c].x, vertices[faces[k].c].y, vertices[faces[k].c].z );
	}
	
}
// Funktion fuer das Laden von Obj Dateien
void loadFile( char* filename )
{
	// Leere faces und vertices
	faces.clear();
	vertices.clear();
	
	// Lade datei
	ifstream file( filename );
	
	// falls keine Datei vorhanden beende 
	if (!file)
	{
		cout << "Keine Obj Datei vorhanden! Bitte beenden (esc) und Textur Datei \n in den Ordner einfügen.";
		system( "PAUSE" );
	}
	// festlegen der variable line
	string line; 
	
	// while schleife fuer das auslesen jeder Zeile
	while ( getline( file, line) )
	{
		// variablen deklarieren
		int a,b,c;
		vertice v;
		face f;
		
		// if Abfragen fuer jede Zeile
		if ( sscanf( line.c_str(), "v %f %f %f", &(v.x), &(v.y), &(v.z) ) )
		{
			vertices.push_back( v );
			
		}
		if (sscanf( line.c_str(), "f %i %i %i", &a, &b, &c ) )
		{	
			a--; b--; c--;
			f.a = a;
			f.b = b;
			f.c = c;
			
			faces.push_back( f );
		}
	}
	// fuer die Berechnung der Normalen der Datei
	//ausgabe();
	ausgtest();
	return;
}
void init( void ) 
{
	// aktiviere Textur Mapping 
	glEnable(GL_TEXTURE_2D); 
	// Hintergrundfarbe auf schwarz setzen
	glClearColor( 0.0, 0.0, 0.0, 0.0 );
	// Render Model festlegen
	glShadeModel( GL_SMOOTH );
   glEnable(GL_AUTO_NORMAL);
   glEnable(GL_NORMALIZE);
	   
   // Schreibe die Liste fuer das erste objekt
	   objModel = glGenLists(2);
		glNewList( objModel, GL_COMPILE );
		glBegin( GL_TRIANGLES );
			loadFile( "cow-nonormals.obj");
		glEnd();
	   glEndList();
  
	// schreibe die liste fuer das zweite objekt
		objModel2 = glGenLists(2);
			glNewList( objModel2, GL_COMPILE );
			glBegin( GL_TRIANGLES );
				glBindTexture(GL_TEXTURE_2D, texture);
				loadFile( "affe2.obj");
			glEnd();
		glEndList();
	
	
	
	// Licht 1 mit parametern
	glLightfv(GL_LIGHT0, GL_AMBIENT, Light0Ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, Light0Diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, Light0Specular);
	
	// Licht 2
	glLightfv(GL_LIGHT1, GL_AMBIENT, Light1Ambient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, Light1Diffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, Light1Specular);
	
	// Licht 3
	glLightfv(GL_LIGHT2, GL_AMBIENT, Light2Ambient);
	glLightfv(GL_LIGHT2, GL_DIFFUSE, Light2Diffuse);
	glLightfv(GL_LIGHT2, GL_SPECULAR, Light2Specular);
	
	
	
	// aktiviere das Licht berechnung
	glEnable( GL_LIGHTING );
	// aktiviere das Licht
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHT2);
	// aktiviere Materialfarbe
	glEnable( GL_COLOR_MATERIAL );
	glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
	
	glEnable(GL_DEPTH_TEST);
}
// Funktion fuer die Kamera
void camera (void) 
{
	 //rotiere die Kamera um die x-Achse (links, Rechts)
	glRotatef(xrot,1.0,0.0,0.0); 
	//rotiere die Kamera um die y-Achse (oben, unten)
	glRotatef(yrot,0.0,1.0,0.0);  
	//bringe die Kamera auf die Position
	glTranslated(-xpos,-ypos,-zpos); 
}
// Funktion fuer das Rendern der Objekte
void display(void)
{
	//leeren des Farbbuffers und des tiefen buffers 
   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   // Tiefentest aktivieren
   glEnable(GL_DEPTH_TEST);
	
	// Matrix leeren
   glLoadIdentity( ); 
   
   // Kamera aktivieren
   camera();
   // Kamera Positionen
	glLightfv(GL_LIGHT0, GL_POSITION,Light0Position);
	glLightfv(GL_LIGHT1, GL_POSITION,Light1Position);
	glLightfv(GL_LIGHT2, GL_POSITION,Light2Position);
 
	// Liste mit dem Objekt 1 aufrufen
	glCallList( objModel );
   
	glTranslatef(7,0,0);
	// abfrage fuer die Textur aktivierung
	  if(textur2 == true)
	  {
		glEnable(GL_TEXTURE_2D);
	  }
	  else
	  {
		   glDisable(GL_TEXTURE_2D);
	  }
	// Liste mit dem Objekt 2 aufrufen
	   glCallList( objModel2 );
	 	
	  if(textur1 == true)
	  {
			glEnable(GL_TEXTURE_2D);
	  }
	  
	  else
	  {
			glDisable(GL_TEXTURE_2D);
	  }
	  // Glut Buffer einschalten
   glutSwapBuffers( ); 
}
void reshape( int w, int h )
{
	// setzt den viewport auf die groeße des fensters
   glViewport( 0, 0, (GLsizei) w, (GLsizei) h );
   // Projektionsmatrix aufrufen
   glMatrixMode( GL_PROJECTION );
   glLoadIdentity( );
	// Set the Field of view angle (in degrees), the aspect ratio of our window,
   //and the new and far planes  
   gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
   // zurueck zur modelview matrix
   glMatrixMode( GL_MODELVIEW );
}
void keyboard( unsigned char key, int x, int y )
{
	// Status der Taste auf gedrueckt stellen
	keyStates[key] = true; 
	// Q kameraauge nach oben
	if (key=='q' || key=='Q')
	{
		xrot += 1;
		if (xrot >360) xrot -= 360;
	}
	// Kameraauge nach unten
	if (key=='e' || key=='E')
	{
		xrot -= 1;
		if (xrot < -360) xrot += 360;
	}
	// W = vorwaerts
	if (key=='w' || key=='W')
	{
		float xrotrad, yrotrad;
		yrotrad = (yrot / 180 * 3.141592654f);
		xrotrad = (xrot / 180 * 3.141592654f);
		xpos += float(sin(yrotrad)) ;
		zpos -= float(cos(yrotrad)) ;
		ypos -= float(sin(xrotrad)) ;
	}
	// s = rueckwaerts
	if (key=='s' || key=='S')
	{
		float xrotrad, yrotrad;
		yrotrad = (yrot / 180 * 3.141592654f);
		xrotrad = (xrot / 180 * 3.141592654f);
		xpos -= float(sin(yrotrad));
		zpos += float(cos(yrotrad)) ;
		ypos += float(sin(xrotrad));
	}
	// d = nach links
	if (key=='d' || key=='D')
	{
		float yrotrad;
		yrotrad = (yrot / 180 * 3.141592654f);
		xpos += float(cos(yrotrad)) * 0.2;
		zpos += float(sin(yrotrad)) * 0.2;
	}
	// a = nach rechts
	if (key=='a' || key=='A')
	{
		float yrotrad;
		yrotrad = (yrot / 180 * 3.141592654f);
		xpos -= float(cos(yrotrad)) * 0.2;
		zpos -= float(sin(yrotrad)) * 0.2;
	}
	// Licht 1 an
	if( key=='1' )
	{
		glEnable( GL_LIGHT0 );
		glutPostRedisplay();
	}
	
	//Licht 1 aus
	if( key=='2' )
	{
		glDisable( GL_LIGHT0 );
		glutPostRedisplay();
	}
	// Licht 2 an
	if( key=='3' )
	{
		glEnable( GL_LIGHT1 );
		glutPostRedisplay();
	}
	
	// Licht 2 aus
	if( key=='4' )
	{
		glDisable( GL_LIGHT1 );
		glutPostRedisplay();
	}
	// Licht 3 an
	if( key=='5' )
	{
		glEnable( GL_LIGHT2 );
		glutPostRedisplay();
	}
	//Licht 3 aus
	if( key=='6' )
	{
		glDisable( GL_LIGHT2 );
		glutPostRedisplay();
	}
	// esc = beenden 
	if (key==27)
	{
		glutLeaveGameMode();
		exit(0);
	}
}
// Funktion fuer das loslassen der Taste
void keyRelease( unsigned char key, int x, int y )
{
	keyStates[key] = false; // Set the state of the current key to not pressed
}
// Funktion fuer eine Textausgabe
void textausgabe()
{
	cout<<"W/S --> Vor/Zurueck  "<<endl;
	cout<<"A/D --> drehen  "<<endl;
	cout<<"R/F --> Textur Objekt 1 an/aus  "<<endl;
	cout<<"C/V --> Textur Objekt 2 an/aus  "<<endl;
	cout<<"T/G --> Licht 1 an/aus  "<<endl;
	cout<<"Z/H --> Licht 2 an/aus  "<<endl;
	cout<<"U/J --> Licht 3 an/aus  "<<endl;
	cout<<"esc --> Beenden  "<<endl;
}
// Funktion fuer das Bewegen der Maus
void mouseMovement(int x, int y) 
{
	// check the difference between the current x and the last x position
	int diffx=x-lastx; 
	// check the difference between the current y and the last y position
	int diffy=y-lasty; 
	// set lastx to the current x position
	lastx=x;
	// set lasty to the current y position
	lasty=y; 
	// set the xrot to xrot with the addition of the difference in the y position
	xrot += (float) diffy; 
	// set the xrot to yrot with the addition of the difference in the x position
	yrot += (float) diffx;	
}
// Main
int main( int argc, char** argv )
{
	// OpenGL initialisiern
	   glutInit( &argc, argv );
	   // Fenstermodus setzen
	   glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB |  GLUT_DEPTH  );
/*
	   // Einstellungen fuer den Vollbild Modus
	   glutGameModeString( "1024×768:32@75" ); 
		// Enter den Fullscreen Modus
		glutEnterGameMode(); 
*/
	   // Fenstergroesse festlegen
	   glutInitWindowSize( 500, 500 ); 
	   // Fensterposition festlegen
	   glutInitWindowPosition( 100, 100 );
	   // erstelle das Fenster
	   glutCreateWindow( argv[0] );
	   // Funktion init() aufrufen
	   init( );
	   // OpenGL Display Funktion, fuer das rendern
	   glutDisplayFunc( display ); 
	   glutIdleFunc( display );
	   // Funktion fuer das Rendern
	   glutReshapeFunc( reshape );
	   // Funktion fuer die Maus bewegung
	   glutPassiveMotionFunc(mouseMovement); 
	 
	   // Funktion fuer die Tasten, und das loslassen
	   glutKeyboardFunc( keyboard );
	   glutKeyboardUpFunc( keyRelease );
	   // Funktion fuer die Textausgabe
	   textausgabe();
		// Textur laden
	   texture = LoadTexture( "terr.bmp" , 256, 256);
	   // Hauptschleife aufrufen damit OpenGL nicht beendet wird
	   glutMainLoop( );
	   // löschen der Textur
	   FreeTexture( texture );
	   return 0;
}[/c]