#include <GLUT/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

static float fRotation = -45.0; // globale Variable
GLUquadricObj *quadratic;	// Ein Zeiger auf ein Quadrics element
GLuint pfennig_hinten_textur, pfennig_vorn_textur;
GLuint displayList;

void myInitOpenGL();
void cb_reshape (int w, int h);
GLuint LoadTextureRAW( const char * filename, int wrap );

void
Animate (int value)
{
	/** An dieser STelle werden Berechnungen durchgeführt, die zu einer
	* Animation der Szene erforderlich sind. Dieser Prozess läuft im
	* Hintergrund und wird hier alle 30ms aufgerufen.
	*/
	fRotation -= 5;  // Rotationswinkel ändern
	if (fRotation <= 0.0)
		fRotation += 360.0;
	
	// RenderScene aufrufen
	glutPostRedisplay();
	
	// Timer wieder registrieren - Animate wird so wieder aufgerufen
	glutTimerFunc(30, Animate, value);
}

void
renderDisk (double radius, int steps)
{
	int i;
	int maxi = steps;
	double step = (2*M_PI) / maxi;
	glBegin (GL_TRIANGLE_FAN);
	glTexCoord2d (0.5,0.5);
	glVertex3f (0, 0, 0);
	for (i = 0; i < maxi; ++i) {
		double c_phi = cos (i*step);
		double s_phi = sin (i*step);
		glTexCoord2d (0.5+c_phi/6, 0.5+s_phi/6);
		glVertex3f (radius * c_phi, radius * s_phi, 0);
	}
	glTexCoord2d (0.5+cos (2*M_PI)/6, 0.5+sin(2*M_PI)/6);
	glVertex3f (radius * cos (2*M_PI), radius * sin (2*M_PI), 0);
	glEnd ();
}

/*
	Texturen?
 */
void
RenderScene (void)
{
	//glRotatef(fRotation, 0., 0.1, 0.);

	int i=0;
	for (i=0; i<10; i++) {
		glTranslatef(-0.1, 0., 0.1);
		glRotatef(fRotation, 0., 0.1, 0.);
		glCallList(displayList);
	}
	
	glutSwapBuffers();
	glFlush();
}

int
main (int argc, char ** argv)
{
	glutInit (&argc, argv);
	
	glutInitWindowPosition(0, 0);
	glutInitWindowSize(600, 600);
	glutInitDisplayString("rgb double depth");
	glutCreateWindow ("Freie Aufgabe Stefan Pfetzing");
	
	glutDisplayFunc (RenderScene);
	glutIdleFunc (RenderScene);
	glutReshapeFunc (cb_reshape);
	myInitOpenGL();
	// Timer Callback registrieren. Wird nach 50ms aufgerufen.
	glutTimerFunc(30, Animate, 0);
	
	glutMainLoop();
    return 0;
}

void
myInitOpenGL() {
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity(); // ID Matrix laden
	
	
	// Texturen laden
	/*	if (!LoadGLTextures()){
	}*/
	
	glEnable (GL_TEXTURE_2D);
	glEnable (GL_DEPTH_TEST);
	glEnable (GL_LIGHTING);
	
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	glAlphaFunc(GL_EQUAL, 1.0f);
	
	// Farbe des ambienten Lichts
	float Ambient_Farbe[] = {1.0f, 1.0f, 1.0f, 1.0f};
	float Ambient_Staerke[] = {0.8f, 0.8f, 0.8f, 1.0f};
	
	float Licht0_Position[] = {0.0f, 50.0f, 100.0f, 0.0f};
	
	// Ambientes Licht definieren
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Ambient_Farbe);
	glMaterialfv(GL_FRONT, GL_AMBIENT, Ambient_Staerke);
	
	// Lichtquelle 0 aktivieren und definieren
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_POSITION, Licht0_Position);
	
	quadratic = gluNewQuadric();	// Zeiger auf quadratics-Objekte
	gluQuadricNormals(quadratic, GLU_SMOOTH); // Create Smooth Normals
	gluQuadricTexture(quadratic, GL_TRUE); // Create Texture Coords
	
	pfennig_vorn_textur   = LoadTextureRAW("../../pfennig_vorn.rgb", 0);
	pfennig_hinten_textur = LoadTextureRAW("../../pfennig_hinten.rgb", 0);

	double size = 0.3;
	double thickness = 0.05;

	displayList = glGenLists (1);
	glNewList (displayList, GL_COMPILE);
	
	glPushMatrix();
	glTranslatef(0, 0, thickness);
	glBindTexture( GL_TEXTURE_2D, pfennig_hinten_textur );
	glColor4f(1., 1., 1., 1.); //Weiss
	
	renderDisk (size, 64);
	
	glBindTexture( GL_TEXTURE_2D, 0); // textur freigeben...
	glColor4f(0.2, 0.2, 0.2, 1.); //GRUEN
	glPopMatrix();
	gluCylinder(quadratic, size, size, thickness, 64, 64);
	glBindTexture( GL_TEXTURE_2D, pfennig_vorn_textur );
	glColor4f(1., 1., 1., 1.); //Weiss
	
	renderDisk (size, 64);
	
	glEndList ();
	   
	
}


// load a 256x256 RGB .RAW file as a texture
GLuint LoadTextureRAW( const char * filename, int wrap )
{
    GLuint texture;
    int width, height;
    char * data;
    FILE * file;
	
    // open texture data
    file = fopen( filename, "rb" );
    if ( file == NULL )
	{
		printf("\nMindestens eine Textur konnte nicht geladen werden!\n");
		exit(0);
	}
	
    // allocate buffer
    width = 256;
    height = 256;
    data = malloc( width * height * 3 );
	
    // read texture data
	fseek( file, 512, SEEK_SET);
    fread( data, width * height * 3, 1, file );
    fclose( file );
	
    // allocate a texture name
    glGenTextures( 1, &texture );
	
    // select our current texture
    glBindTexture( GL_TEXTURE_2D, texture );
	
    // select modulate to mix texture with color for shading
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
	
    // when texture area is small, bilinear filter the closest mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                     GL_LINEAR_MIPMAP_NEAREST );
    // when texture area is large, bilinear filter the first mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	
    // if wrap is true, the texture wraps over at the edges (repeat)
    //       ... false, the texture ends at the edges (clamp)
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                     wrap ? GL_REPEAT : GL_CLAMP );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                     wrap ? GL_REPEAT : GL_CLAMP );
	
    // build our texture mipmaps
    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
                       GL_RGB, GL_UNSIGNED_BYTE, data );
	
    // free buffer
    free( data );
	
    return texture;
}

void cb_reshape (int w, int h)
{
	
	if (h <= 1)
		h = 1;
	
	glViewport (0, 0, w, h);
	
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluPerspective (60.f, (float) w / (float) h, 0.3f, 5.f);
	glTranslatef(1.1, 0, 1);
	
	glMatrixMode (GL_MODELVIEW);
	gluLookAt (3., 0., 0., 0., 0., 0., 0., 1., 0.);
	
	glutPostRedisplay ();
}

