#include "input.h"

//actors
#include "particleSystem.h"

//************************************************************
//
//                      Static stuff!
//
//************************************************************


//define all static thingys

//global object info
map <string, actorID> Renderer::actorInfo;

GLuint Renderer::selectBuf[BUFSIZE];  //for picking

//active actors
string Renderer::backgroundTex="";
//Vector4f Renderer::backgroundColor=Vector4f(0.2,0.8,1,1);
Vector4f Renderer::backgroundColor=Vector4f(0.0,0.0,0.0,1);

vector <Actor*> Renderer::actorList;

map <string, GLuint> Renderer::textureList;
map <string, GLuint> Renderer::shaderList;

GLuint Renderer::frameBufferTexture=0;

bool Renderer::bRenderShadow=false;

int Renderer::screenX,
    Renderer::screenY,                //screen width
    Renderer::nearClip,
    Renderer::farClip;              //clipping planes

int Renderer::frames;
bool Renderer::bFullscreen=false;



double Renderer::currentTime,
       Renderer::deltaTime,
       Renderer::physicsTime;

float Renderer::lookSpeed,
      Renderer::moveSpeed;



float Renderer::fov=45;
Vector3f* Renderer::camLoc;
Vector3f* Renderer::camLook;

Vector3f Renderer::lightLoc(0,28,-20);                  //light Location
Vector3f Renderer::ambient(1,1,1);

Content*  Renderer::content;

bool Renderer::bUpdatePhysics=false;


//************************************************************
//
//RTTY actorInfo - Information about every Actor:
//                 Class Name, Type, Size
//
//************************************************************


void Renderer::fillGlobalLists(){
//actors
Actor *A;
A= new Actor;
createActorID(A);

ParticleSystem *P;
P= new ParticleSystem;
createActorID(P);
}


//************************************************************
//
//Constructor and Destructor
//
//************************************************************

Renderer::Renderer(){

    nearClip=1;
    farClip=1000;

    lookSpeed=0.005;
    moveSpeed=0.1;


    shadow_tx = 0; // the shadow texture
    shadow_fb = 0; // the framebuffer object to render to that texture
    shadow_sz = 256; // the shadow map size
}

Renderer::~Renderer(){

    glDeleteFramebuffersEXT(1, &frameBufferTexture);

}

//************************************************************
//
//  Windowing stuff and screen setup
//
//************************************************************

void Renderer::initWindow(int x, int y, char* windowName){

    screenX=x;
    screenY=y;
    Input::screenX=x;
    Input::screenY=y;
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
//    glutInitDisplayString("rgba double depth>=24 sample=8");

    if (bFullscreen)
      {
      // 1024x768, 32bit pixel depth, 60Hz refresh rate
      glutGameModeString( "1024x768:32@60" );
      // start fullscreen game mode
      glutEnterGameMode();
      }
    else
      {
      glutInitWindowSize(x,y);
      glutInitWindowPosition(Input::windowX,Input::windowY);
      glutCreateWindow(windowName);
      }
}

void Renderer::reDrawScreen(int w, int h){

	// Prevent a divide by zero, when window is too short
	// (you cant make a window of zero width).
	if(h == 0)
		h = 1;

	float ratio = 1.0* w / h;

	// Reset the coordinate system before modifying
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);

	// Set the correct perspective.
	gluPerspective(fov,ratio,nearClip,farClip);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(camLoc->x, camLoc->y,camLoc->z,
		      camLook->x,camLook->y,camLook->z,
			  0.0f,1.0f,0.0f);
    Input::screenX=w;
    Input::screenY=h;
}

//************************************************************
//
//  Setting up and calling all Actors' update function
//
//************************************************************

void Renderer::setup(){

//generate Class and Type Lists
fillGlobalLists();

//add content
content= new Content;  //add different type depending on your content!


//checking for extensions and shaders:
if (GLEE_ARB_point_sprite)
  std::cout << "supporting point sprites \n";
if (GLEE_ARB_vertex_shader && GLEE_ARB_fragment_shader)
  std::cout << "Ready for GLSL \n";
// and framebuffer  objects
 // verify FBOs are supported (otherwise we get FuBar'd Objects)
if (!glutExtensionSupported ("GL_EXT_framebuffer_object") ){
    cerr << "FBO extension unsupported" << endl;
    exit (1);
}


FreeImage_Initialise();

Input::setup();          //controller gets created here!

//TODO: this should be set up using an xml file
content->setup();               //everything gets set up here!


for (int i=0;i<actorList.size();i++)
  actorList[i]->setup();                                  //all actors get setup

//setup basic lighting
float lightPos[]={0.0,130.0,0.0,0.0};
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);

//background Color
glClearColor(backgroundColor.r,backgroundColor.g,backgroundColor.b,backgroundColor.a);


//-------------------------------------------------------
// framebuffer object

// create fbo and attach texture to ti
glGenFramebuffersEXT (1, &shadow_fb);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);

 // create the texture we'll use for the shadow map
glGenTextures (1, &frameBufferTexture);
glBindTexture (GL_TEXTURE_2D, frameBufferTexture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadow_sz, shadow_sz, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR,borderColor);
    // set up hardware shadow mapping
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);

// attach colorBuffer to a texture
//glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, shadow_sz, shadow_sz, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
//glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, frameBufferTexture, 0);

glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, frameBufferTexture, 0);
glDrawBuffer (GL_NONE);
glReadBuffer (GL_NONE);

// verify all is well and restore state
checkFBOStatus();
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
glBindTexture (GL_TEXTURE_2D, 0);

//-------------------------------------------------------
//end framebuffer object

//TODO: set up two (or more!) texture channels!

glutMainLoop();
}

void Renderer::checkFBOStatus(){

GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
    break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
    cerr << "FBO configuration unsupported" << endl;
    break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
    cerr << "FBO DrawBuffer incomplete" << endl;
    break;
default:
    cerr << "FBO programmer error" << endl;
    break;
}
}


void Renderer::update(){

for (int i=0;i<Renderer::actorList.size();i++)
  Renderer::actorList[i]->update(deltaTime);

Input::update(deltaTime);

if (bUpdatePhysics)
  physicsUpdate();

draw();
}


void Renderer::physicsUpdate(){

}

//************************************************************
//
//  Drawing to the screen - Actors, Buttons and RenderToTexture
//
//************************************************************

void Renderer::draw(){

	glClear( GL_COLOR_BUFFER_BIT |
			 GL_DEPTH_BUFFER_BIT );


	/*
	 *	Enable lighting and the z-buffer
	 */


    glClearDepth(1.0f);
    glDepthFunc(GL_LEQUAL);

    glEnable(GL_DEPTH_TEST);

//    glEnable(GL_MULTISAMPLE);   //just in case we force multisampling

    glMatrixMode(GL_PROJECTION);
	glLoadIdentity();


	/*
	 *	Draw Background texture
	 */

  if (Renderer::backgroundTex!=""){

    glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glOrtho(0,screenX,screenY,0,-1,1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();


    drawBackground();
    }

	/*
	 *	Draw 3D stuff
	 */

    // framebuffer start
    //------------------------------------------------------

    if (bRenderShadow)
      drawShadows();
    //---------------------------------------------------------


    glClear(GL_DEPTH_BUFFER_BIT);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	gluPerspective(fov,(screenY==0)?(1):((float)screenX/screenY),nearClip,farClip);
    glPushMatrix();

	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(camLoc->x, camLoc->y, camLoc->z,
    camLook->x, camLook->y, camLook->z,
    0.0f, 1.0f, 0.0f);

    if (bRenderShadow)
      applyShadows();

    draw3D();

    /*
	 *	Set Ortho viewing transformation
	 */

    glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glOrtho(0,screenX,screenY,0,-1,1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	/*
	 *	Draw all Buttons
	 */
    if (!Input::controller->bRunning)
      draw2D();

	/*
	 *	Draw all Debug Info
	 */

    glPushMatrix();
    Input::displayFPS();
    glPopMatrix();

	/*
	 *	Set perspective viewing transformation - in case we do picking afterwards!!!
	 */

  	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

    glutSwapBuffers();
    frames++;
    deltaTime=glutGet(GLUT_ELAPSED_TIME)-currentTime;
    currentTime=glutGet(GLUT_ELAPSED_TIME);
    glDisable(GL_MULTISAMPLE);
}

void Renderer::drawShadows(){

    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);
    //glClearColor(0,0,0,1);
    glClear(GL_DEPTH_BUFFER_BIT);

	glPushAttrib(GL_VIEWPORT_BIT);
    glShadeModel(GL_FLAT);
    glViewport (0, 0, shadow_sz, shadow_sz);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(20.0f, 1.0f, 10.0f, 280.0f);             //this sets the framing of the light!

    glGetFloatv(GL_PROJECTION_MATRIX, lightProjectionMatrix);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt( lightLoc.x, lightLoc.y, lightLoc.z,
    1.0f, 1.0f, 1.0f,
    0.0f, 1.0f, 0.0f);

    //save both matrices
    glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix);
	glPolygonOffset(4.1f, 8.0f);

	//only draw back faces into shadow map
	//for some reason, just using polygon offset doesnt work
	//glCullFace(GL_FRONT);
	//glEnable(GL_CULL_FACE);
    glColorMask(0, 0, 0, 0);// disable the color drawing
	glEnable(GL_POLYGON_OFFSET_FILL);

    for (int i=Renderer::actorList.size()-1;i>=0;i--)
      if (!Renderer::actorList[i]->bHidden)// && !Renderer::actorList[i]->bShadow)
        Renderer::actorList[i]->draw();

	glDisable(GL_POLYGON_OFFSET_FILL);
	//glDisable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);

    glColorMask(1,1,1,1);
    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
    glPopAttrib (); // restore the viewport

 //   lightLoc.z-=0.01;
}

void Renderer::applyShadows(){

    glActiveTexture(GL_TEXTURE1);

//one way...
	glEnable(GL_TEXTURE_2D);

	float x[] = { 1.0f, 0.0f, 0.0f, 0.0f };
    float y[] = { 0.0f, 1.0f, 0.0f, 0.0f };
    float z[] = { 0.0f, 0.0f, 1.0f, 0.0f };
    float w[] = { 0.0f, 0.0f, 0.0f, 1.0f };

	const GLfloat bias[] = {0.5f, 0.0f, 0.0f, 0.0f,
				 			 0.0f, 0.5f, 0.0f, 0.0f,
							 0.0f, 0.0f, 0.5f, 0.0f,
							 0.5f, 0.5f, 0.5f, 1.0f};

    glTexGenfv( GL_S, GL_EYE_PLANE, x );
    glTexGenfv( GL_T, GL_EYE_PLANE, y );
    glTexGenfv( GL_R, GL_EYE_PLANE, z );
    glTexGenfv( GL_Q, GL_EYE_PLANE, w );

    glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
    glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
    glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
    glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );

	glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    glEnable( GL_TEXTURE_GEN_R );
    glEnable( GL_TEXTURE_GEN_Q );

    // Set up the depth texture projection
	// !!!ATTENTION!!!
	// Note again that the multiplication order is different in OpenGL than in Direct3D
	// In Direct3D you'd do the following: bias * m_LookAtMatrix * m_lightProjection
	// In OpenGL you do this: bias * m_lightProjection * m_LookAtMatrix
    glMatrixMode(GL_TEXTURE);

    glMatrixMode (GL_TEXTURE);
    glLoadIdentity();
    glTranslatef(0.5,0.5,0.5);
    glScalef(0.5,0.5,0.5);
    glMultMatrixf(lightProjectionMatrix);
    glMultMatrixf(lightViewMatrix);

    //and now the inverse of the cameraViewMatrix
    //Todo: use a more cost-effective way to calculate the inverse!
    Matrix4f inv;
    glGetFloatv(GL_MODELVIEW_MATRIX, inv);
    inv= inv.inverse();
    glMultMatrixf(inv);


	//glLoadMatrixf(bias);
	//glMultMatrixf(lightProjectionMatrix);
	//glMultMatrixf(lightViewMatrix);
    //glMultMatrixf(cameraProjectionMatrix);
    //glMultMatrixf(cameraViewMatrix);

// or the other
/*
    glMatrixMode (GL_TEXTURE);
    glLoadIdentity();
    glTranslatef(0.5,0.5,0.5);
    glScalef(0.5,0.5,0.5);
    glMultMatrixf(lightProjectionMatrix);
    glMultMatrixf(lightViewMatrix);

    Matrix4f myMV, inv;
    glGetFloatv(GL_MODELVIEW_MATRIX, myMV);
    inv=myNV.invert();

    glMultMatrixf(inv);
*/
    glActiveTexture(GL_TEXTURE0);
	glMatrixMode(GL_MODELVIEW);
}


void Renderer::draw3D(){
    for (int i=Renderer::actorList.size()-1;i>=0;i--)
      if (!Renderer::actorList[i]->bHidden)
        Renderer::actorList[i]->draw();
}

void Renderer::draw2D(){
}

void Renderer::drawBackground(){

glEnable(GL_TEXTURE_2D);
glDepthMask(GL_FALSE);

if (backgroundTex!="")
  glBindTexture(GL_TEXTURE_2D, textureList[backgroundTex]);

    glColor4f(1.0,1.0,1.0,1.0);
    glBegin(GL_POLYGON);
        glTexCoord2f(0.0,0.0);
		glVertex3f(0,0,0.0);
        glTexCoord2f(1.0,0.0);
		glVertex3f(Input::screenX,0,0.0);
        glTexCoord2f(1.0,1.0);
		glVertex3f(Input::screenX,Input::screenY,0.0);
        glTexCoord2f(0.0,1.0);
		glVertex3f(0,Input::screenY,0.0);
	glEnd();
glDisable(GL_TEXTURE_2D);
glDepthMask(GL_TRUE);
//glDisable(GL_BLEND);
}

//************************************************************
//
//Picking: determining what Actor the mouse points to
//         and mouse 3d coordinate
//
//************************************************************


//picking needs mouse coordinates
void Renderer::pick(int x, int y){

    //needs mouse coordinates
	GLint viewport[4];

    //set Input::mouse3d to very very far away, in case we point into nirvana!
    Input::mouse3D=Vector3f(1000000,1000000,1000000);

	glSelectBuffer(BUFSIZE,selectBuf);
	glRenderMode(GL_SELECT);
    glInitNames();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glGetIntegerv(GL_VIEWPORT,viewport);

	gluPickMatrix(x,viewport[3]-y,
			3,3,viewport);


  	gluPerspective(fov,(screenY==0)?(1):((float)screenX/screenY),nearClip,farClip);


	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();


    //set camera
	gluLookAt(camLoc->x, camLoc->y,camLoc->z,
		      camLook->x,camLook->y,camLook->z,
			  0.0f,1.0f,0.0f);



    glShadeModel(GL_FLAT);
    for (int i=0; i<Renderer::actorList.size(); i++)
      {
      if (Renderer::actorList[i]->bPickable)
       {
       glPushName(i);
	    glPushMatrix();
         Renderer::actorList[i]->drawCollision();
        glPopMatrix();
       glPopName();
       }
      }
    glShadeModel(GL_SMOOTH);
	int hits;

	glFlush();        //force Render

	// returning to normal rendering mode
	hits = glRenderMode(GL_RENDER);

	// if there are hits process them
	if (hits != 0)
	   processHits(hits,selectBuf,x,y);

}



void Renderer::processHits (GLint hits, GLuint buffer[], int cursorX, int cursorY){
    double minZ=connectHits(hits,buffer);

    GLint viewport[4];
	GLdouble modelview[16];
	GLdouble projection[16];
	GLdouble winX, winY, winZ;
	GLdouble posX, posY, posZ;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(fov,(screenY==0)?(1):((float)screenX/screenY),nearClip,farClip);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	gluLookAt(camLoc->x, camLoc->y,camLoc->z,
		      camLook->x,camLook->y,camLook->z,
			  0.0f,1.0f,0.0f);

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

	winX = cursorX;
	winY = viewport[3] - (float)cursorY;
    winZ = minZ/pow(2.0f,32.0f);  //from the Z-Buffer

	gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

    Input::mouse3D.x=posX;
    Input::mouse3D.y=posY;
    Input::mouse3D.z=posZ;
}

double Renderer::connectHits(GLint hits, GLuint buffer[]){
    //determine the length of the buffer
    int length=sizeof (buffer);
    int numberOfNames=0;
    int i=0;                   //buffer pointer
    int actorListPlace=0;      //reference to the actor list
    double minZ=0.0f;           //minimum Z coordinate of the hit
    double maxZ=0.0f;           //maximum Z coordinate of the hit
    double smallestZ=0.0f;      //smallest Z coordinate of the hit
    Actor *mouseActor=NULL;         //actor pointer that was hit
    Actor *nearestActor=NULL;         //actor pointer that was hit
    //determine the actor

    //while still stuff in the buffer:
    for (int h=0;h<hits;h++)
    {

     //get the number of names
       numberOfNames=buffer[i++];  //i = 1
       minZ=buffer[i++];         //i = 2
       maxZ=buffer[i++];         //i = 3

       if (smallestZ==0.0f)
         smallestZ=minZ+1000;

       for (int n=0;n<numberOfNames;n++)
         {
         //get Actor pointer
         actorListPlace=buffer[i+n];

         mouseActor=Renderer::actorList[actorListPlace];

         //then assign actor pointer if Z is smallest
         if (minZ<smallestZ)
           {
           nearestActor=mouseActor;
           smallestZ=minZ;
           }
         i++;
         }
    }

    Input::worldTarget=nearestActor;
    return smallestZ;
}

//************************************************************
//
//       Texture Loading and Initialisation functions
//
//
//************************************************************

//generates a texture from a RAW file - needs implementation of textureList!
GLuint Renderer::LoadTextureRAW( const char * filename,int size, int wrap ){

    GLuint texture;
    int width, height;
    BYTE * data;
    FILE * file;

    // open texture data
    file = fopen( filename, "rb" );
    if ( file == NULL ) return 0;

    // allocate buffer
    width = size;
    height = size;
    data = (BYTE*) malloc( width * height * 3 );

    // read texture data
    fread( data, width * height * 3, 1, file );
    fclose( file );

    //allocate texture List
    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;
}

GLuint Renderer::LoadTextureTGA( const char * filename, int size, int wrap ){

    GLuint texture;

    FIBITMAP * myBitmap = FreeImage_Load(FIF_TARGA,filename,0);

    FreeImage_FlipVertical(myBitmap);

    //allocate texture List
    glGenTextures( 1, &texture );

    // select our current texture
    glBindTexture( GL_TEXTURE_2D, texture );

    // when texture area is small, bilinear filter the closest mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
    // 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

    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, FreeImage_GetWidth(myBitmap), FreeImage_GetHeight(myBitmap), 0, GL_BGRA, GL_UNSIGNED_BYTE, FreeImage_GetBits(myBitmap) );

    FreeImage_Unload(myBitmap);

    return texture;
}


//List removal and (later) sorting
bool Renderer::removeActor(Actor * a){

for (int i=0;i<actorList.size();i++)
  {
  if (actorList[i]==a)
   {
   for (int j=0;j<actorList.size();j++)
      actorList[j]->checkReferences(i);
   actorList.erase(actorList.begin()+i);
   }
  }
}
