
// Mesh.cpp
// This file contains all of the code related to the mesh side of the application and the code for the GUI
//

#include "empty.h"
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <stdio.h>
#include <GL/freeglut.h> // Changed to FreeGLUT
#include "vec.h"


//GUI
#include "cegui/include/CEGUI.h"
#include "cegui/include/RendererModules/OpenGL/CEGUIOpenGL.h"
#include "cegui/include/RendererModules/OpenGL/CEGUIOpenGLRenderer.h"

//Model Loader
#include "glm/glm.h"
#include "glm2/glm.h"

#define DOWN 1
#define UP 0

//Global Variables
static int spinx = 0;
static int spiny = 0;
static int spinl = 0;
static int beginx, beginy, beginv;
GLMmodel* dmodel = NULL;
static int xRot=0;
static int yRot=0;
static int wFrame=0;
static int pLoad=0;
static int mouserbstate = UP;
static int mouselbstate = UP;
int mousex;
int mousey;
float mouseZoom = -5.0;
static int winH = 600;
static int winW = 600;
int prevx=0,prevy=0;
int window_id;
bool keep_running = true;
GLfloat inc = 0.001;

typedef struct{
	GLdouble x;
	GLdouble y;
	GLdouble z;
}CVector3;

void MovePoint(GLfloat x, GLfloat y, GLfloat amount); // moves a point on the model when given the mouse x & y coordinates by amount 
CVector3 GetOGLPos(int x, int y); // converts between coordinate systems
void MouseWheel(int, int, int, int); // Mousewheel Zoom
void display_mesh(void);
void subdivide(GLfloat *v1, GLfloat *v2, GLfloat *v3, long depth);
int getZ(int x, int y);

using namespace glm; //Required for some maths functions

void
output(GLfloat x, GLfloat y, char *format,...)
{
  va_list args;
  char buffer[200], *p;

  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);
  glPushMatrix();
  glTranslatef(x, y, 0);
  for (p = buffer; *p; p++)
    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();
}

// Rotates the model when the right mouse button is held down
void
movemodel(int button, int state, int x, int y)
{
  if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
    beginx = x;
	beginy = y;
	mouserbstate = DOWN;
  }else
	  mouserbstate = UP;
  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
	  //CVector3 position = GetOGLPos(x, y);
	  //MovePoint(position.x, position.y, 1);
	  mousex = x;
	  mousey = y;
	  mouselbstate = DOWN;
  }else
	  mouselbstate = UP;

	// CEGUI
	if (state == 0){     // State 0 = Button Pressed
		switch (button){
			case 0:     // glut's left mouse button
				CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton);
				break;
			case 1:     // glut's middle mouse button
				CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
				break;
			case 2:     // glut's right mouse button
				CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton);
				break;
			case 3:     // glut's mouse wheel up
				CEGUI::System::getSingleton().injectMouseWheelChange(2.0);
				break;
			case 4:     // glut's mouse wheen down
				CEGUI::System::getSingleton().injectMouseWheelChange(-2.0);
				break;
			}
		}
	else if (state == 1){    // State 1 = Button Released
		switch (button) {
			case 0:     // glut's left mouse button
				CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton);
				break;
			case 1:     // glut's middle mouse button
				CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::MiddleButton);
				break;
			case 2:     // glut's right mouse button
				CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton);
				break;
			}
	}

}

//Needed to get the movement of the mouse
void
motion(int x, int y)
{
	// CEGUI
	CEGUI::System::getSingleton().injectMousePosition(x,y);

	if(mouserbstate == DOWN){
	  spinx = (spinx + (x - beginx)) % 360;
	  spiny = (spiny + (y - beginy)) % 360;
	  beginx = x;
	  beginy = y;
	  glutPostRedisplay();
	}
	if(mouselbstate == DOWN && prevx!=x && prevy!=y){
		CVector3 position = GetOGLPos(x, y);


		/*GLfloat tx = position.x-0.05;
		GLfloat ty = position.y-0.05;
		GLfloat inc = 0;
		for(int i=0; i < 10; i++){
			for (int j=0; j < 10; j++){
			MovePoint(tx,ty,inc);
			tx += 0.1;

			if (j <= 5){
				inc -= 0.003;
			} else {
				inc += 0.005;
			}

			}
			ty += 0.1;
		}*/

		MovePoint(position.x, position.y, 0.05);

		mousex = x;
		mousey = y;
		glutPostRedisplay();
	}
	prevx = x;
	prevy = y;
}

//Converts co-ordinates
CVector3 GetOGLPos(int x, int y)
{
	GLint viewport[4];
	GLdouble modelview[16];
	GLdouble projection[16];
	GLfloat winX, winY, winZ;
	CVector3 pos;

	glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
	glGetDoublev( GL_PROJECTION_MATRIX, projection );
	glGetIntegerv( GL_VIEWPORT, viewport );

	winX = (float)x;
	winY = (float)viewport[3] - (float)y;
	glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );

	gluUnProject( winX, winY, winZ, modelview, projection, viewport, &pos.x, &pos.y, &pos.z);

	return pos;
}

//MouseWheel Zoom Functionality
void MouseWheel(int button, int dir, int x, int y)
{
	// Zoom In / Out
    if (dir > 0) {
		mouseZoom += 0.05;
    } else {
		mouseZoom -= 0.05;
    }
	// Redraw
	glutPostRedisplay();
}

//Gets the position of the mouse when no buttons are pressed down
void
pmotion(int x, int y)
{
	// CEGUI
	CEGUI::System::getSingleton().injectMousePosition(x,y);

	mousex = x;
	mousey = y;
	glutPostRedisplay();
}

//Function called by the timer function updates the position of the light and redraws the screen
void
animate(int value){
  spinl = (spinl + (value + beginv)) % 360;	//move light
  beginv = value;
  glutPostRedisplay();	//redraw
  glutTimerFunc(100, animate, 1);	//Timer calls are volitile so we re-register the callback to give us repeating function callback
}


//Initilization
void
myinit(void)
{
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  glDepthFunc(GL_LESS);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_POLYGON_SMOOTH);
  glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);

}


//NOT USED
void calcTexCords(GLfloat v1, GLfloat v2, GLfloat v3){
	GLfloat dimensions[3];
    GLfloat x, y, scalefactor;
    GLuint i;

	glmDimensions(dmodel, dimensions);
    scalefactor = 2.0 / 
        glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2]));
	
    x = dmodel->vertices[3 * 1 + 0] * scalefactor;
    y = dmodel->vertices[3 * 1 + 2] * scalefactor;
    v1 = (x + 1.0) / 2.0;
    v2 = (y + 1.0) / 2.0;
	v3 = (x + 1.0) / 2.0;
}

//performs model subdivision
void subdivide(GLfloat *v1, GLfloat *v2, GLfloat *v3, long depth)
{
   GLfloat v12[3], v23[3], v31[3];
   GLint i;

   if (depth == 0) {
	   glBegin(GL_TRIANGLES);
        glNormal3fv(v1); glVertex3fv(v1);   
		glNormal3fv(v2); glVertex3fv(v2);  
		glNormal3fv(v3); glVertex3fv(v3); 
		glEnd();
      return;
   }
   for (i = 0; i < 3; i++) {
      v12[i] = (v1[i]+v2[i])/2;
      v23[i] = (v2[i]+v3[i])/2;
      v31[i] = (v3[i]+v1[i])/2;
   }
   normalize(v12);
   normalize(v23);
   normalize(v31);
   subdivide(v1, v12, v31, depth-1);
   subdivide(v2, v23, v12, depth-1);
   subdivide(v3, v31, v23, depth-1);
   subdivide(v12, v23, v31, depth-1);
}


//draws the model on screen
void DrawOBJ(){
	// Load the model only if it hasn't been loaded before
	// If it's been loaded then pmodel1 should be a pointer to the model geometry data...otherwise it's null
	if (!dmodel)
	{
		// this is the call that actualy reads the OBJ and creates the model object
		dmodel = glmReadOBJ("bin/face2.obj");
		if (!dmodel) exit(0);
		// This will rescale the object to fit into the unity matrix
		// Depending on your project you might want to keep the original size and positions you had in 3DS Max or GMAX so you may have to comment this.
		glmUnitize(dmodel);
		// These 2 functions calculate triangle and vertex normals from the geometry data.
		// To be honest I had some problem with very complex models that didn't look to good because of how vertex normals were calculated
		// So if you can export these directly from you modeling tool do it and comment these line
		// 3DS Max can calculate these for you and GLM is perfectly capable of loading them
		glmFacetNormals(dmodel);
		glmVertexNormals(dmodel, 90.0);
		//glmLinearTexture(model);
		//GLfloat* twidth = &model->textures->width;
		//GLfloat* theight = &model->textures->height;
		//glmLoadTexture("textura_paralelipied.tga", false, false, false, false, twidth, theight);
	}

	// This is the call that will actually draw the model
	// Don't forget to tell it if you want textures or not :))
	/*glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glBindTexture(GL_TEXTURE_2D, dmodel->textures->id);
	for(int i = 0; i < dmodel->numtriangles; i++){
		subdivide(&dmodel->vertices[3 * dmodel->triangles[i].vindices[0]], &dmodel->vertices[3 * dmodel->triangles[i].vindices[1]], &dmodel->vertices[3 * dmodel->triangles[i].vindices[2]], 1);
	}*/
	if(pLoad==0)
		glmDraw(dmodel, GLM_SMOOTH | GLM_TEXTURE ); 
	else
		glmDraw(dmodel, GLM_SMOOTH | GLM_TEXTURE | GLM_MATERIAL | GLM_POINTS ); 

}

//Gets the z coordinate from the model given the nearest x and y  coordinate
int getZ(int x, int y){
	int smallx=0, smally=0,nx=0,ny=0,px=1000,py=1000;
  int z;
  for(int i = 0; i<dmodel->numvertices; i++){
	  if((dmodel->vertices[i*3]-x)<smallx){
		  smallx = (dmodel->vertices[i*3]-x);
		  nx = dmodel->vertices[i*3];
	  }
	  if((dmodel->vertices[i*3+1]-y)<smally){
		  smally = (dmodel->vertices[i*3]-y);
		  ny = dmodel->vertices[i*3+1];
	  }
	  if(smallx < 0)
		 smallx = smallx *-1;
	  if(smally < 0)
		 smally = smally *-1;

	  if(smallx < px && smally < py){
		z = dmodel->vertices[i*3+2];
		px = smallx;
		py = smally;
	  }
  }
  return z;
}

//moves a point on the model
void MovePoint(GLfloat x, GLfloat y, GLfloat amount){
  GLfloat smallx=0, smally=0,nx=0,ny=0,px=1,py=1;
  int z=5;
  for(int i = 1; i<dmodel->numvertices; i++){
	  smally = (dmodel->vertices[i*3+1]+y);
	  smallx = (dmodel->vertices[i*3]+x);
	  if(dmodel->vertices[i*3]>x && dmodel->vertices[i*3]<x+0.01){
		if(dmodel->vertices[i*3+1]>y && dmodel->vertices[i*3+1]<y+0.01){
			dmodel->vertices[i*3+2] += amount;
		}
	  }
	}
  for(int i = 1; i<dmodel->numvertices; i++){
	  smally = (dmodel->vertices[i*3+1]+y);
	  smallx = (dmodel->vertices[i*3]+x);
	  if(dmodel->vertices[i*3]>x+0.01 && dmodel->vertices[i*3]<x+0.025){
		if(dmodel->vertices[i*3+1]>y+0.01 && dmodel->vertices[i*3+1]<y+0.025){
			dmodel->vertices[i*3+2] += (amount/10)*9;
		}
	  }
	}
  for(int i = 1; i<dmodel->numvertices; i++){
	  smally = (dmodel->vertices[i*3+1]+y);
	  smallx = (dmodel->vertices[i*3]+x);
	  if(dmodel->vertices[i*3]>x+0.025 && dmodel->vertices[i*3]<x+0.05){
		if(dmodel->vertices[i*3+1]>y+0.025 && dmodel->vertices[i*3+1]<y+0.05){
			dmodel->vertices[i*3+2] += (amount/10)*7;
		}
	  }
	}
  for(int i = 1; i<dmodel->numvertices; i++){
	  smally = (dmodel->vertices[i*3+1]+y);
	  smallx = (dmodel->vertices[i*3]+x);
	  if(dmodel->vertices[i*3]>x+0.05 && dmodel->vertices[i*3]<x+0.075){
		if(dmodel->vertices[i*3+1]>y+0.05 && dmodel->vertices[i*3+1]<y+0.075){
			dmodel->vertices[i*3+2] += (amount/10)*5;
		}
	  }
	}
  for(int i = 1; i<dmodel->numvertices; i++){
	  smally = (dmodel->vertices[i*3+1]+y);
	  smallx = (dmodel->vertices[i*3]+x);
	  if(dmodel->vertices[i*3]>x+0.075 && dmodel->vertices[i*3]<x+0.1){
		if(dmodel->vertices[i*3+1]>y+0.075 && dmodel->vertices[i*3+1]<y+0.1){
			dmodel->vertices[i*3+2] += (amount/10)*2;
		}
	  }
	}
	/*dmodel->vertices[z] += amount;
	printf("z=%f\n",dmodel->vertices[z]);
	printf("closest match is %d\n",z);
	printf("\t Vertex x=%f y=%f z=%f\n",dmodel->vertices[z-2],dmodel->vertices[z-1],dmodel->vertices[z]);
	printf("mouse x=%f y=%f",x,y);*/
}


/*  Lighting has been removed and this function is run once per frame to do rendering
 */
void
display_mesh(void)
{
  GLfloat position[] =
  {0.0, 0.0, 1.5, 1.0};

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glTranslatef(0.0, 0.0, mouseZoom); /* MOUSEWHEEL */

  glPushMatrix();
  glRotated((GLdouble) spinl, 0.0, 1.0, 0.0);
  glRotated(0.0, 1.0, 0.0, 0.0);

  glTranslated(0.0, 0.0, 1.5);
  glPopMatrix();
  if(wFrame==1)
	  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
  glRotated((GLdouble) spinx, 0.0, 1.0, 0.0);
  glRotated((GLdouble) spiny, 1.0, 0.0, 0.0);
  glColor3f(1.0, 1.0, 1.0);
  DrawOBJ();
	  
  if(wFrame==1)
	  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  glPopMatrix();
  glPushAttrib(GL_ENABLE_BIT);
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_LIGHTING);
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  gluOrtho2D(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT));
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  glPointSize(1.0);
  glColor3f(1.0, 1.0, 0.0);
  glBegin(GL_POINTS);
  glVertex3f(mousex,(winH-mousey), getZ(mousex,(winH-mousey)));
  for (int a = 0; a < 360; a += 360 / 60)
  {
    double heading = a * 3.1415926535897932384626433832795 / 180;
    glVertex3f((cos(heading) * 15) + mousex, (sin(heading) * 15) + (winH-mousey), getZ(mousex,(winH-mousey)));
  }
  glEnd();
  glPopMatrix();
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glPopAttrib();
  glDisable(GL_LIGHTING);
}

//called when the window is resized
void
myReshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(40.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0);
  glMatrixMode(GL_MODELVIEW);
  winH = h;
  winW = w;
  mousex = 0;
  mousey = 0;
}

void
tmotion(int x, int y)
{
  printf("Tablet motion x = %d, y = %d\n", x, y);
}

void
tbutton(int b, int s, int x, int y)
{
  printf("b = %d, s = %d, x = %d, y = %d\n", b, s, x, y);
}

void
smotion(int x, int y, int z)
{
  fprintf(stderr, "Spaceball motion %d %d %d\n", x, y, z);
}

void
rmotion(int x, int y, int z)
{
  fprintf(stderr, "Spaceball rotate %d %d %d\n", x, y, z);
}

void
sbutton(int button, int state)
{
  fprintf(stderr, "Spaceball button %d is %s\n",
    button, state == GLUT_UP ? "up" : "down");
}

void
dials(int dial, int value)
{
  fprintf(stderr, "Dial %d is %d\n", dial, value);
  spinl = value % 360;
  glutPostRedisplay();
}

void
buttons(int button, int state)
{
  fprintf(stderr, "Button %d is %s\n", button,
    state == GLUT_UP ? "up" : "down");
}

void Keys(unsigned char key, int x_, int y_)
{
   switch (key)
   {
   case GLUT_KEY_RIGHT:
      xRot += 1;
      break;

   case GLUT_KEY_LEFT:
      xRot -= 1;
      break;

   case GLUT_KEY_UP:
      yRot += 1;
      break;

   case GLUT_KEY_DOWN:
      yRot -= 1;
      break;
   case 'p':
	   if(pLoad==0)
		   pLoad=1;
	   else
		   pLoad=0;
	   break;
   case 27:
	   exit(0);
	   break;
   }
   if(key == 'w'){
	   if(wFrame==0)
		   wFrame=1;
	   else
		   wFrame=0;
   }
   return;
}

// CEGUI: Register Slider Callback
bool CEGUIClass::handleSlider(const CEGUI::EventArgs& e){
	CEGUI::WindowManager * winMgr = CEGUI::WindowManager::getSingletonPtr();
	CEGUI::Slider * slider = static_cast<CEGUI::Slider*>(winMgr->getWindow("sliderOne"));
	printf("Slider position: %f\n",slider->getCurrentValue()/100);
}

// CEGUI: Slider Registering
void CEGUIClass::registerSlider(Window* w){
	CEGUI::WindowManager& winMgr = WindowManager::getSingleton();
	CEGUI::Window* window = winMgr.getWindow("sliderOne");
	window->subscribeEvent(Slider::EventValueChanged, Event::Subscriber(&CEGUIClass::handleSlider, this));
}



/*  Main Loop
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 */
int
run_mesh(int argc, char **argv)
{
	Window* myRoot;

  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(winH, winW);
  window_id = glutCreateWindow(argv[0]);
  myinit();
  CEGUI::OpenGLRenderer& myRenderer = CEGUI::OpenGLRenderer::create();
  CEGUI::System::create( myRenderer );
  glutTimerFunc(100, animate, 1);	//NEW: Time function registration to move light automatcally
  glutMouseFunc(movemodel);
  glutMouseWheelFunc(MouseWheel); /* NEW: MOUSEWHEEL ZOOM */
  glutMotionFunc(motion);
  glutPassiveMotionFunc(pmotion);
  glutReshapeFunc(myReshape);
  glutDisplayFunc(display_mesh);
  glutTabletMotionFunc(tmotion);
  glutTabletButtonFunc(tbutton);
  glutSpaceballMotionFunc(smotion);
  glutSpaceballRotateFunc(rmotion);
  glutSpaceballButtonFunc(sbutton);
  glutDialsFunc(dials);
  glutButtonBoxFunc(buttons);
  glutKeyboardFunc(&Keys);
  printf("Here 1\n");
  CEGUI::DefaultResourceProvider* rp = static_cast<CEGUI::DefaultResourceProvider*>
    (CEGUI::System::getSingleton().getResourceProvider());
  printf("Here 2\n");

	rp->setResourceGroupDirectory("schemes", "bin/datafiles/schemes/");
	rp->setResourceGroupDirectory("imagesets", "bin/datafiles/imagesets/");
	rp->setResourceGroupDirectory("fonts", "bin/datafiles/fonts/");
	rp->setResourceGroupDirectory("layouts", "bin/datafiles/layouts/");
	rp->setResourceGroupDirectory("looknfeels", "bin/datafiles/looknfeel/");
	rp->setResourceGroupDirectory("lua_scripts", "bin/datafiles/lua_scripts/");

	printf("Here 3\n");

	// set the default resource groups to be used
	CEGUI::Imageset::setDefaultResourceGroup("imagesets");
	CEGUI::Font::setDefaultResourceGroup("fonts");
	CEGUI::Scheme::setDefaultResourceGroup("schemes");
	CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
	CEGUI::WindowManager::setDefaultResourceGroup("layouts");
	CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");

	printf("Here 4\n");

	// setup default group for validation schemas
	CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
	printf("Here 5\n");

	if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))
		parser->setProperty("SchemaDefaultResourceGroup", "schemas");
	printf("Here 6\n");

	// create (load) the TaharezLook scheme file
	// (this auto-loads the TaharezLook looknfeel and imageset files)
	try{
		CEGUI::SchemeManager::getSingleton().create( "TaharezLook.scheme" );
	} 
	catch( CEGUI::InvalidRequestException &e ) 
	{
		printf("CEGUI::InvalidRequestException occured: %s", e.getMessage().c_str() );
		getchar();
		return false;
	}

	printf("Here 7\n");

	// create (load) a font.
	// The first font loaded automatically becomes the default font, but note
	// that the scheme might have already loaded a font, so there may already
	// be a default set - if we want the "Commonweath-10" font to definitely
	// be the default, we should set the default explicitly afterwards.

	CEGUI::FontManager::getSingleton().create( "DejaVuSans-10.font" );
	printf("Here 8\n");

	CEGUI::System::getSingleton().setDefaultMouseCursor( "TaharezLook", "MouseArrow" );
	printf("Here 9\n");

    using namespace CEGUI;
	try{
		myRoot = WindowManager::getSingleton().loadWindowLayout( "main.layout" );
		System::getSingleton().setGUISheet( myRoot );
	} 
	catch( CEGUI::InvalidRequestException &e ) 
	{ 
		printf("CEGUI::InvalidRequestException occured: %s", e.getMessage().c_str() );  
		return false;
	}

	// CEGUI: Setup slider
	CEGUI::WindowManager * winMgr = CEGUI::WindowManager::getSingletonPtr();
	CEGUI::Slider * slider = static_cast<CEGUI::Slider*>(winMgr->getWindow("sliderOne"));
	slider->setCurrentValue(0.5);

	// CEGUI: Slider event handling
	CEGUIClass *cegObj = new CEGUIClass();
	cegObj->registerSlider(myRoot);

	// ****************************

	while(keep_running){
	glutMainLoopEvent();
	CEGUI::System::getSingleton().renderGUI();
	glutSwapBuffers();
	}

	glutDestroyWindow(window_id);
	return 0;             /* ANSI C requires main to return int. */
}
