/**************************************************************
* Driven pendulum by Johannes Lampel                          *
* see http://johannes.lampel.net/projects/pendel/ for details *
**************************************************************/


/*********************************************
* Object Orientated Example Using Base Class *
* Author: Andreas Oberdorfer            2004 *
*********************************************/

#include "Example.h"											// Header File For Derived Application Class

#include <gl\gl.h>												// Header File For The OpenGL32 Library
#include <gl\glu.h>												// Header File For The GLu32 Library
#include <gl\glaux.h>											// Header File For The GLaux Library


#pragma comment(lib, "opengl32.lib")							// Search For OpenGL32.lib While Linking
#pragma comment(lib, "glu32.lib")								// Search For GLu32.lib While Linking
#pragma comment(lib, "glaux.lib")								// Search For GLaux.lib While Linking

GLfloat LightAmbient[]=		{ 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]=		{ 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]=	{ 0.0f, 1.0f, 1.0f, -0.0f };
//GLfloat Att[]=	{ 1.0f, 1.0f, 1.0f };

int sign(double f){
	return f>0?1:f<0?-1:0;
}

// Create The Derived GL_Example Class And Return A Pointer To The GL_Application Base Class
GL_Application * GL_Application::Create(const char * class_name)
{
	GL_Example * example = new GL_Example(class_name);
	return reinterpret_cast<GL_Application *>(example);
}


// Class Constructor
GL_Example::GL_Example(const char * class_name) : GL_Application(class_name)
{
	m_Angle = 0.0f;												// Set Starting Angle To Zero

	m_lPoincareEntries = 20;
	m_lEPhasenRaumEntries = 10000;

	m_fq = 2;
	m_fg = 1.105;
	m_fwd = 2.0/3.0;
	m_fTheta = 0;
	m_fThetap = 0;
	m_fPoincareLevel = 0;
}

bool GL_Example::Initialize()									// Any GL Init Code & User Initialiazation Goes Here
{
	// Start Of User Initialization
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);						// Black Background
	glClearDepth(1.0f);											// Depth Buffer Setup
	glDepthFunc(GL_LEQUAL);										// The Type Of Depth Testing (Less Or Equal)
	glEnable(GL_DEPTH_TEST);									// Enable Depth Testing
	glShadeModel(GL_SMOOTH);									// Select Smooth Shading
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			// Set Perspective Calculations To Most Accurate

	glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);		// Setup The Ambient Light
	glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);		// Setup The Diffuse Light
	glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);	// Position The Light
	//glLightfv(GL_LIGHT1, GL_CONSTANT_ATTENUATION,Att);
	//glLightfv(GL_LIGHT1, GL_LINEAR_ATTENUATION,Att);
	//glLightfv(GL_LIGHT1, GL_QUADRATIC_ATTENUATION,Att);
	glEnable(GL_LIGHT1);								// Enable Light One

	glPointSize(3);

	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE,GL_DST_ALPHA);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_BLEND);

	BuildFont();

	ResizeDraw(true);											// Enable Redraw During Window Resize

	/*int i;
	float dt = 1.0/80.0;
	for(i=0; i < 10000; i++){
		m_fThetap -= dt *( 1.0/m_fq * m_fThetap + sin(m_fTheta) - m_fg * cos(m_fwd * g_HPTime.getTime_d() - 10000.0/80.0+(float)i/80.0 ) ) ;
		m_fTheta += m_fThetap * dt;

		// zu phasenraum + anregung hinzufügen
		m_LVEPhasenRaum.push_back(Vector(m_fTheta,m_fThetap,m_fg * cos(m_fwd * g_HPTime.getTime_d() - 10000.0/80.0+(float)i/80.0)));
	}*/

	return true;												// Return true (Initialization Successful)
}

void GL_Example::Deinitialize()									// Any User DeInitialization Goes Here
{
	KillFont();
}

void GL_Example::Update(DWORD milliseconds)						// Perform Motion Updates
{
	double dts = g_HPTime.getElapsed_d();
	if(dts < 1.0/40.0){
		Sleep(1000.f/40.f - dts*1000);
	}
	if (m_Keys.IsPressed(VK_ESCAPE) == true)					// Is ESC Being Pressed?
	{
		TerminateApplication();									// Terminate The Program
	}

	if (m_Keys.IsPressed(VK_F1) == true)						// Is F1 Being Pressed?
	{
		ToggleFullscreen();										// Toggle Fullscreen Mode
	}
	if(m_Keys.IsPressed(VK_SPACE) == true){
		while(m_fTheta > 1 * M_PI){
			m_fTheta -= 2*M_PI;
			list<Vector>::iterator iter;
			for(iter = m_LVEPhasenRaum.begin(); iter != m_LVEPhasenRaum.end(); iter++){
				(*iter).x -= 2*M_PI;
			}
			for(iter = m_LVPoincare.begin(); iter != m_LVPoincare.end(); iter++){
				(*iter).x -= 2*M_PI;
			}
		}
		while(m_fTheta < -1 * M_PI){
			m_fTheta += 2*M_PI;
			list<Vector>::iterator iter;
			for(iter = m_LVEPhasenRaum.begin(); iter != m_LVEPhasenRaum.end(); iter++){
				(*iter).x += 2*M_PI;
			}
			for(iter = m_LVPoincare.begin(); iter != m_LVPoincare.end(); iter++){
				(*iter).x += 2*M_PI;
			}
		}
	}
	if(m_Keys.isHit('D') == true){
		m_fwd += 0.005;
	}
	if(m_Keys.isHit('C') == true){
		m_fwd -= 0.005;
	}
	if(m_Keys.isHit('A') == true){
		m_fq += 0.005;
	}
	if(m_Keys.isHit('Y') == true){
		m_fq -= 0.005;
	}
	if(m_Keys.isHit('S') == true){
		m_fg += 0.005;
	}
	if(m_Keys.isHit('X') == true){
		m_fg -= 0.005;
	}

	if(m_Keys.isHit('G') == true){
		int iExp=log(m_lEPhasenRaumEntries)/log(10);
		m_lEPhasenRaumEntries += pow(10,iExp);
		if(m_lEPhasenRaumEntries < 0 || m_lEPhasenRaumEntries > 1000000000)
			m_lEPhasenRaumEntries = 1000000000;
	}
	if(m_Keys.isHit('B') == true){
		int iExp=log(m_lEPhasenRaumEntries*0.9)/log(10);
		m_lEPhasenRaumEntries -= pow(10,iExp);
		if(m_lEPhasenRaumEntries < 10)
			m_lEPhasenRaumEntries = 10;
	}

	if(m_Keys.isHit('H') == true){
		int iExp=log(m_lPoincareEntries)/log(10);
		m_lPoincareEntries += pow(10,iExp);
		if(m_lPoincareEntries < 0 || m_lPoincareEntries > 1000000000)
			m_lPoincareEntries = 1000000000;
	}
	if(m_Keys.isHit('N') == true){
		int iExp=log(m_lPoincareEntries*0.9)/log(10);
		m_lPoincareEntries -= pow(10,iExp);
		if(m_lPoincareEntries < 1)
			m_lPoincareEntries = 1;
	}

	if(m_Keys.isHit('F') == true){
		m_fPoincareLevel += 0.1;
		m_LVPoincare.clear();
	}
	if(m_Keys.isHit('V') == true){
		m_fPoincareLevel -= 0.1;
		m_LVPoincare.clear();
	}

	if(m_Keys.isHit('R') == true){
		int i,iMax = 10000,iIt;
		double dt,
			dTime = g_HPTime.getTime_d();

		dt = 2*M_PI/m_fwd / (double)iMax * 10.0;
		iIt = (double)iMax *m_fwd* dt / 2*M_PI;
		dt = 2*M_PI/m_fwd / (double)iMax * iIt;

		for(i=0; i < iMax; i++){
			m_fThetap -= dt *( 1.0/m_fq * m_fThetap + sin(m_fTheta) - m_fg * cos(m_fwd * (dTime - (double)iMax*dt+(double)i*dt )) ) ;
			m_fTheta += m_fThetap * dt;

			// zu phasenraum + anregung hinzufügen
			m_LVEPhasenRaum.push_back(Vector(m_fTheta,m_fThetap,m_fg * cos(m_fwd * (dTime - (double)iMax*dt+(double)i*dt ) )));

			// gucken ob wir n poincareebenenpunkt hinzufügen müssen
			if(sign(m_fg * cos(m_fwd * (dTime- (double)iMax*dt+(double)i*dt) ) - m_fPoincareLevel) > sign(m_fg * cos(m_fwd * (dTime- (double)iMax*dt+(double)i*dt + m_dt) ) - m_fPoincareLevel)){
				m_LVPoincare.push_back(Vector(m_fTheta,m_fThetap,m_fg * cos(m_fwd * (dTime- (double)iMax*dt+(double)i*dt) ) ));
			}
		}
	}

	m_Angle += (float)(milliseconds) / 30.0f;					// Update m_angle Based On The Clock

	m_dt = g_HPTime.getElapsed_d();
	g_HPTime.markTick();

	m_fThetap -= m_dt *( 1.0/m_fq * m_fThetap + sin(m_fTheta) - m_fg * cos(m_fwd * g_HPTime.getTime_d() ) ) ;
	m_fTheta += m_fThetap * m_dt;

	// zu phasenraum + anregung hinzufügen
	m_LVEPhasenRaum.push_back(Vector(m_fTheta,m_fThetap,m_fg * cos(m_fwd * g_HPTime.getTime_d() )));

	// gucken ob wir n poincareebenenpunkt hinzufügen müssen
	if(sign(m_fg * cos(m_fwd * g_HPTime.getTime_d() ) - m_fPoincareLevel) > sign(m_fg * cos(m_fwd * (g_HPTime.getTime_d() + m_dt) ) - m_fPoincareLevel)){
		m_LVPoincare.push_back(Vector(m_fTheta,m_fThetap,m_fg * cos(m_fwd * g_HPTime.getTime_d() )));
	}

	// listen uU kürzen
	while(m_LVEPhasenRaum.size() > m_lEPhasenRaumEntries){
		m_LVEPhasenRaum.erase(m_LVEPhasenRaum.begin());
	}
	while(m_LVPoincare.size() > m_lPoincareEntries){
		m_LVPoincare.erase(m_LVPoincare.begin());
	}

	// tell key class that frame is over
	m_Keys.frame();
}

void GL_Example::Draw()											// Perform All Scene Drawing
{
	int i = 0;
	char szTemp[250];
	static float fN[3] = {1,1,1};
	static float fNa[3] = {.5,.5,.5};
	float fMax,fMax1;
	float x,y,z,x1,y1,z1;
	list<Vector>::iterator iter,itero;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// Clear Screen And Depth Buffer

	// draw text info
	//glEnable(GL_LIGHTING);
	glLoadIdentity();											// Reset The Modelview Matrix
	glTranslatef(-8.0f, 15.0f, -40.0f);
	glColor4f(1,1,1,1);

	sprintf(szTemp,"q (A/Y)          : %.3lf\ng (S/X)          : %.3lf\nomega (D/C)  : %.3lf\n\nPoincaré Offset (F/V) : %.2lf\n\nTheta            : %.2lf\nTheta'           : %.2lf",m_fq,m_fg,m_fwd,m_fPoincareLevel,m_fTheta,m_fThetap);
	glPrint(false,szTemp);
	glTranslatef(.0f, -6.0f, 0.0f);
	glPrint(false,"10 Umläufe der Anregung (R)");
	glTranslatef(.0f, -1.0f, 0.0f);
	glPrint(false,"Aktuelle Position auf Bildmitte (LEERTASTE)");

	glLoadIdentity();											// Reset The Modelview Matrix
	glTranslatef(11.0f, 15.0f, -40.0f);

	glColor4f(1,0,0,1);
	glPrint(false,"Theta");
	glTranslatef(.0f, -1.0f, 0.0f);
	glColor4f(0,1,0,1);
	glPrint(false,"Theta'");
	glTranslatef(.0f, -1.0f, 0.0f);
	glColor4f(0,0,1,1);
	glPrint(false,"Anregung");

	glLoadIdentity();											// Reset The Modelview Matrix
	glTranslatef(-20.0f, -15.0f, -40.0f);

	glColor4f(1,1,1,1);
	sprintf(szTemp,"Max. gespeicherte Frames (G/B)               %li (%li)",m_lEPhasenRaumEntries,m_LVEPhasenRaum.size());
	glPrint(false,szTemp);
	glTranslatef(0,-1,0);
	sprintf(szTemp,"Max. gespeicherte Poincarépunkte (H/N)   %li(%li)",m_lPoincareEntries,m_LVPoincare.size());
	glPrint(false,szTemp);

	//glDisable(GL_LIGHTING);

	// display pendel and force
	glLoadIdentity();
	glTranslatef(2.0f, 0.0f, -6.0f);							// Translate 6 Units Into The Screen

	glRotatef(m_fTheta * 180 / M_PI,0,0,1);

	glColor3f(1,1,1);
	glBegin(GL_LINE_STRIP);
	glVertex3f(0,0,0);
	glVertex3f(0,-1,0);
	glEnd();

	glBegin(GL_LINE_STRIP);
	glVertex3f(0,-1,0);
	glColor3f(1-fabs(cos(m_fwd * g_HPTime.getTime_d() )),1-fabs(cos(m_fwd * g_HPTime.getTime_d() )),1);
	glVertex3f(m_fg * cos(m_fwd * g_HPTime.getTime_d() ),-1,0);
	glEnd();

	// let's have some light
	glEnable(GL_LIGHTING);

	glDisable(GL_BLEND);
	glTranslatef(0,-1,0);
	glRotatef(45,1,0,1);
	glScalef(.1,.1,.1);
	glBegin(GL_QUADS);
		float f[3] = {.5,.5,.5};
		//float fh[3] = {1,1,1};

		glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,f);
		glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,f);

		glColor4f(.5,.5,.5,1);
		glNormal3f( 0.0f, 1.0f, 0.0f);
		glVertex3f(+1,+1,-1);					// Top Right Of The Quad (Top)
		glVertex3f(-1,+1,-1);					// Top Left Of The Quad (Top)
		glVertex3f(-1,+1,+1);					// Bottom Left Of The Quad (Top)
		glVertex3f(+1,+1,+1);					// Bottom Right Of The Quad (Top)z
		
		glNormal3f( 0.0f, -1.0f,1.0f);
		glVertex3f(+1,-1,+1);					// Top Right Of The Quad (Bottom)
		glVertex3f(-1,-1,+1);					// Top Left Of The Quad (Bottom)
		glVertex3f(-1,-1,-1);					// Bottom Left Of The Quad (Bottom)
		glVertex3f(+1,-1,-1);					// Bottom Right Of The Quad (Bottom)
		
		glNormal3f( 0.0f, 0.0f, 1.0f);
		glVertex3f(+1,+1,+1);					// Top Right Of The Quad (Front)
		glVertex3f(-1,+1,+1);					// Top Left Of The Quad (Front)
		glVertex3f(-1,-1,+1);					// Bottom Left Of The Quad (Front)
		glVertex3f(+1,-1,+1);					// Bottom Right Of The Quad (Front)
		
		glNormal3f( 0.0f,0.0f, -1.0f);
		glVertex3f(+1,-1,-1);					// Top Right Of The Quad (Back)
		glVertex3f(-1,-1,-1);					// Top Left Of The Quad (Back)
		glVertex3f(-1,+1,-1);					// Bottom Left Of The Quad (Back)
		glVertex3f(+1,+1,-1);					// Bottom Right Of The Quad (Back)
		
		glNormal3f( -1.0f, 0.0f, 0.0f);
		glVertex3f(-1,+1,+1);					// Top Right Of The Quad (Left)
		glVertex3f(-1,+1,-1);					// Top Left Of The Quad (Left)
		glVertex3f(-1,-1,-1);					// Bottom Left Of The Quad (Left)
		glVertex3f(-1,-1,+1);					// Bottom Right Of The Quad (Left)
		
		glNormal3f(1.0f, 0.0f, 0.0f);
		glVertex3f(+1,+1,-1);					// Top Right Of The Quad (Right)
		glVertex3f(+1,+1,+1);					// Top Left Of The Quad (Right)
		glVertex3f(+1,-1,+1);					// Bottom Left Of The Quad (Right)
		glVertex3f(+1,-1,-1);					// Bottom Right Of The Quad (Right)
	glEnd();											// Done Drawing
	glDisable(GL_LIGHTING);
	glEnable(GL_BLEND);

	// draw poincare surface
	glLoadIdentity();											// Reset The Modelview Matrix

	glTranslatef(-9.0f, 6.0f, -24.0f);							// Translate 6 Units Into The Screen
	glOrtho(-1,1,-1,1,-100,100);

	// draw poincaré points
	glColor4f(1,0,0,1);
	for(iter = m_LVPoincare.begin(); iter != m_LVPoincare.end(); iter++){
		x = (*iter).x;
		while(x<-M_PI)
			x+=2.0*M_PI;
		while(x>M_PI)
			x-=2.0*M_PI;
		/*glBegin(GL_LINES);
		glVertex3f(x, (*iter).y, (*iter).z-0.2);
		glVertex3f(x, (*iter).y, (*iter).z+0.2);
		glEnd();*/
		glBegin(GL_POINTS);
		glVertex3f(x, (*iter).y, m_fPoincareLevel-.2);
		glEnd();
	}

	glBegin(GL_LINES);

	i=0;
	fMax = m_LVEPhasenRaum.size();
	fMax1 = fMax / 10.f;
	fMax1 = fMax1<200?fMax1:200;
	fMax -= fMax1;
	itero = iter = m_LVEPhasenRaum.begin();
	iter++;
	for(; iter != m_LVEPhasenRaum.end(); iter++,itero++){
		x = (*iter).x;
		y = (*iter).y;
		x1= (*itero).x;
		y1= (*itero).y;

		while(x<-M_PI){
			x+=2.0*M_PI;
			x1+=2.0*M_PI;
		}
		while(x>M_PI){
			x-=2.0*M_PI;
			x1-=2.0*M_PI;
		}

		if(i < fMax)
			glColor4f( float(i) / fMax, float(i) / fMax,1,0);
		else
			glColor4f( 1, 1.f-float(i-fMax) / fMax1, 1.f-float(i-fMax) / fMax1,0);

		glVertex3f(x1, y1, m_fPoincareLevel-.1-float(i)/100000.f);
		glVertex3f(x, y, m_fPoincareLevel-.1-float(i)/100000.f);
		i++;
	}
	glEnd();
	// draw a red cross for the current position
	if(m_LVEPhasenRaum.size() > 3){
		iter = m_LVEPhasenRaum.end();
		iter --;

		x = (*iter).x;
		while(x<-M_PI){
			x+=2.0*M_PI;
		}
		while(x>M_PI){
			x-=2.0*M_PI;
		}

		glPushMatrix();
		glTranslatef(x, (*iter).y, m_fPoincareLevel-.1);
		glScalef(.3,.3,.3);

		glColor4f(1,0,0,1);
		glBegin(GL_LINES);
		glVertex3f(-1,0,0);
		glVertex3f(1,0,0);

		glVertex3f(0,-1,0);
		glVertex3f(0,1,0);

		glEnd();
		glPopMatrix();
	}


	glBegin(GL_QUADS);
	glColor4f(.5,.5,.5,0);
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,fN);
	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,fNa);

	glVertex3f(-M_PI,-3,m_fPoincareLevel);
	glVertex3f(M_PI,-3,m_fPoincareLevel);
	glVertex3f(M_PI,3,m_fPoincareLevel);
	glVertex3f(-M_PI,3,m_fPoincareLevel);
	glEnd();

	// display phasenraum + force
	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -16.0f);
	glRotatef(30,1,0,0);
	glRotatef(m_Angle,0,1,0);
	glRotatef(-90,1,0,0);

	glBegin(GL_LINES);
	glColor3f(1,0,0);
	glVertex3f(0,0,0);
	glVertex3f(1,0,0);

	glColor3f(0,1,0);
	glVertex3f(0,0,0);
	glVertex3f(0,1,0);

	glColor3f(0,0,1);
	glVertex3f(0,0,0);
	glVertex3f(0,0,1);
	glEnd();

	glBegin(GL_LINE_STRIP);

	i=0;
	fMax = m_LVEPhasenRaum.size();
	fMax1 = fMax / 10.f;
	fMax1 = fMax1<200?fMax1:200;
	fMax -= fMax1;
	for(iter = m_LVEPhasenRaum.begin(); iter != m_LVEPhasenRaum.end(); iter++){
		if(i < fMax)
			glColor4f( float(i) / fMax, float(i) / fMax,1,0);
		else
			glColor4f( 1, 1.f-float(i-fMax) / fMax1, 1.f-float(i-fMax) / fMax1,0);
		glVertex3f((*iter).x, (*iter).y, (*iter).z);
		i++;
	}
	glEnd();

	// draw a red cross for the current position
	if(m_LVEPhasenRaum.size() > 3){
		iter = m_LVEPhasenRaum.end();
		iter --;

		glPushMatrix();
		glTranslatef((*iter).x, (*iter).y, (*iter).z);
		glScalef(.3,.3,.3);

		glColor4f(1,0,0,1);
		glBegin(GL_LINES);
		glVertex3f(-1,0,0);
		glVertex3f(1,0,0);

		glVertex3f(0,-1,0);
		glVertex3f(0,1,0);

		glVertex3f(0,0,-1);
		glVertex3f(0,0,1);
		glEnd();
		glPopMatrix();
	}


	// draw poincaré points
	glBegin(GL_LINES);
	glColor4f(1,0,0,1);
	for(iter = m_LVPoincare.begin(); iter != m_LVPoincare.end(); iter++){
		glVertex3f((*iter).x, (*iter).y, (*iter).z-0.2);
		glVertex3f((*iter).x, (*iter).y, (*iter).z+0.2);
	}
	glEnd();

	// draw poincare surface inside phasenraum+force
	glBegin(GL_QUADS);
	glColor4f(.5,.5,.5,0);
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,fN);
	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,fNa);

	glVertex3f(-M_PI,-3,m_fPoincareLevel);
	glVertex3f(M_PI,-3,m_fPoincareLevel);
	glVertex3f(M_PI,3,m_fPoincareLevel);
	glVertex3f(-M_PI,3,m_fPoincareLevel);
	glEnd();
}

void GL_Example::BuildFont(void)								// Build Our Bitmap Font
{
	HFONT	font;										// Windows Font ID
	
	base = glGenLists(256);								// Storage For 256 Characters
	
	font = CreateFont(	-6,							// Height Of Font
		0,								// Width Of Font
		0,								// Angle Of Escapement
		0,								// Orientation Angle
		FW_NORMAL,						// Font Weight
		FALSE,							// Italic
		FALSE,							// Underline
		FALSE,							// Strikeout
		ANSI_CHARSET,					// Character Set Identifier
		OUT_TT_PRECIS,					// Output Precision
		CLIP_DEFAULT_PRECIS,			// Clipping Precision
		ANTIALIASED_QUALITY,			// Output Quality
		FF_DONTCARE|DEFAULT_PITCH,		// Family And Pitch
		//"Comic Sans MS");				// Font Name
		//"Times New Roman");				// Font Name
		"Tahoma");				// Font Name
	
	SelectObject(m_Window.m_hDC, font);							// Selects The Font We Created
	
	wglUseFontOutlines(	m_Window.m_hDC,							// Select The Current DC
		0,								// Starting Character
		255,							// Number Of Display Lists To Build
		base,							// Starting Display Lists
		.002,							// Deviation From The True Outlines
		.1,								// Font Thickness In The Z Direction
		WGL_FONT_POLYGONS,				// Use Polygons, Not Lines
		gmf);							// Address Of Buffer To Recieve Data
}

void GL_Example::KillFont(void)									// Delete The Font
{
	glDeleteLists(base, 256);								// Delete All 256 Characters
}

void GL_Example::glPrint(bool bMid,const char *text)					// Custom GL "Print" Routine
{
	glPushMatrix();
	float		length=0;								// Used To Find The Length Of The Text
	char szLine[256],*szReturn;
	const char *szPointer;
	
	if (!*text)									// If There's No Text
		return;											// Do Nothing
	
	length  = 0;
	for (unsigned int loop=0;loop<(strlen(text));loop++)	// Loop To Find Text Length
	{
		length+=gmf[text[loop]].gmfCellIncX;			// Increase Length By Each Characters Width
	}
	
	/*if(bMid)glTranslatef(-length/2,0.0f,0.0f);					// Center Our Text On The Screen
	*/

	szPointer = text;

	while(*szPointer){
		szReturn = strstr(szPointer,"\n");
		if(szReturn){
			strncpy(szLine,szPointer,szReturn-szPointer);
			szLine[szReturn-szPointer] = 0;
			szPointer = szReturn;
			szPointer ++;
		}
		else{
			strcpy(szLine,szPointer);
			szPointer = szPointer + strlen(szPointer);
		}
		length  = 0;
		for (unsigned int loop=0;loop<(strlen(szLine));loop++)	// Loop To Find Text Length
		{
			length+=gmf[szLine[loop]].gmfCellIncX;			// Increase Length By Each Characters Width
		}

		glPushAttrib(GL_LIST_BIT);							// Pushes The Display List Bits
		glListBase(base);									// Sets The Base Character to 0
		glCallLists(strlen(szLine), GL_UNSIGNED_BYTE, szLine);	// Draws The Display List Text
		glPopAttrib();										// Pops The Display List Bits

		glTranslatef(-length,-gmf['A'].gmfBlackBoxY*1.15,0.0f);
	}
	glPopMatrix();
}

