#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "mesh.h"
#include "dcimage.h"
#include "objloader.h"
using namespace std;

#define PI 3.14159263
#define PIdiv180 (PI/180.0)
#define ITEM_1   1
#define ITEM_2   2
#define ITEM_3   3
#define ITEM_4   4

//#################################################################
//################    DECLARAÇÃO DE VARIAVEIS 1   ##################
//#################################################################

GLenum render = GL_LINES;
Mesh paisagem[6];
bool smooth;
bool mov = false;
GLfloat density = 0.004; // maior numero, maior a densidade
GLfloat fogColor[4]={0.5,0.5,0.5,1};
DCImage img[12];
GLuint textureObjects[3];
int subMenu1,subMenu2;
MassaMola teste;

// Shader handles
GLuint v,f;
GLuint p;
int choice;
//#################################################################


//#################################################################
//################         FUNÇÕES COMUNS        ##################          
//#################################################################


void drawMeshFile2(MassaMola* m){
  glVertexPointer(3,GL_FLOAT,0,m->verts);
  //glNormalPointer(GL_FLOAT,0,m->vertNorm);
  //glTexCoordPointer(2,GL_FLOAT,0,m->uvs);
  glDrawElements (render,m->nbrTris*3,GL_UNSIGNED_INT,m->tris);
}
//MESH COM TEXTURA
void drawMeshFile(Mesh* m){
  glVertexPointer(3,GL_FLOAT,0,m->verts);
  glNormalPointer(GL_FLOAT,0,m->vertNorm);
  
  glTexCoordPointer(2,GL_FLOAT,0,m->uvs);
  
  glDrawElements (render,m->nbrTris*3,GL_UNSIGNED_INT,m->tris);
}
//TEXTURA
void textureMagic(){
     GLenum err = glewInit();
     
     glGenTextures(2,textureObjects);
     
     glBindTexture(GL_TEXTURE_2D,textureObjects[0]);
     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);
     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
     glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_LINEAR);
     img[0].load("texturas/nave.raw"); //passa o nome do arquivo da imagem que contém a textura
     glTexImage2D(GL_TEXTURE_2D,0,3,img[0].width,img[0].width,0,GL_RGB,GL_UNSIGNED_BYTE,img[0].data);
     
     glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
     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);
     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
     glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_LINEAR);
     img[1].load("texturas/snow.raw");
     glTexImage2D(GL_TEXTURE_2D,0,3,img[1].width,img[1].width,0,GL_RGB,GL_UNSIGNED_BYTE,img[1].data);
     
     img[2].load("texturas/teste1.raw");
     img[3].load("texturas/teste3.raw");
     img[4].load("texturas/teste2.raw");
     
     glBindTexture(GL_TEXTURE_2D,textureObjects[2]);
     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);
     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
     glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_LINEAR);
     img[5].load("texturas/housemap.raw");
     glTexImage2D(GL_TEXTURE_2D,0,3,img[5].width,img[5].width,0,GL_RGB,GL_UNSIGNED_BYTE,img[5].data);
     
     img[6].load("texturas/teste4.raw");
     img[7].load("texturas/teste5.raw");
     img[8].load("texturas/teste6.raw");
     img[9].load("texturas/teste7.raw");
     img[10].load("texturas/teste8.raw");
     img[11].load("texturas/teste9.raw");
     
     
     glActiveTexture(GL_TEXTURE0);
     glEnable(GL_TEXTURE_2D);
}
//LUZ
void setupRC(){
    glEnable(GL_LIGHTING);
	glDepthFunc(GL_LESS);	// O tipo de teste de profundidade a ser feito
	glEnable(GL_DEPTH_TEST);// Habilita o teste de profundidade
	glFrontFace(GL_CCW);	// Seta o sentido anti-horário para composição de triângulos (regra da mão direita)

	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);    // Limpa o buffer de cor e profundidade
    
    GLfloat diffuseLight[] = { 0.7, 0.7, 0.7, 1.0 };	/// RGBA, varie os 3 primeiros parametros para mudar a cor e a intensidade da luz.   
    glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseLight );	/// Cria a fonte de luz
    glEnable( GL_LIGHT0 );
    
    glEnable( GL_COLOR_MATERIAL );
	glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
	
	GLfloat ambientLight[] = { 0.025, 0.025, 0.025, 1.0 };		/// Define cor e intensidade da luz ambiente
    glLightfv( GL_LIGHT0, GL_AMBIENT, ambientLight );		/// Adiciona a componente ambiente
    
    GLfloat spectre[] = { 1.0, 1.0, 1.0, 1.0 };

    
    glMaterialfv( GL_FRONT, GL_SPECULAR, spectre );
    glMateriali( GL_FRONT, GL_SHININESS, 128 ); 
	
	GLfloat lightPos[] = { -200.0, 200.0, 0.0, 1.0 };
	glLightfv( GL_LIGHT0, GL_POSITION, lightPos );
}
//RESHAPE
void reshape(int width,int height){
   glViewport(0,0,width,height);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   gluPerspective(45.0f,(float)640/(float)480,0.1f,1000.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}


//fog
void fog(){
     glEnable(GL_DEPTH_TEST);
     glEnable(GL_FOG);
     glFogi(GL_FOG_MODE,GL_EXP2);
     glFogfv(GL_FOG_COLOR,fogColor);
     glFogf(GL_FOG_DENSITY,density);
     glHint(GL_FOG_HINT,GL_NICEST);
}

//translada vértices da mesh no eixo Z
void translateZ(float aux, Mesh *mesh){
     for (int v=0; v < mesh->nbrVerts; v++){
        mesh->verts[v].z += aux;
     }
}
//translada vértices da mesh nos eixos XY
void translateXY(float aux, Mesh *mesh){
     for (int v=0; v < mesh->nbrVerts; v++){
        mesh->verts[v].x += aux;
        mesh->verts[v].y += aux;
     }
}

void menuCallback (int id) { 
     // só é usado para a iniciação do menu
}

void subMenuCallback (int id) {
  switch (id) {
  case ITEM_1:
    glutChangeToMenuEntry(1,"LINES",ITEM_1);
    glutChangeToMenuEntry(2,"triangles",ITEM_2);
    render = GL_LINES;
    break;
  case ITEM_2:
    glutChangeToMenuEntry(1,"lines",ITEM_1);
    glutChangeToMenuEntry(2,"TRIANGLES",ITEM_2);
    render = GL_TRIANGLES;
    break;
  case ITEM_3:
    glutChangeToMenuEntry(1,"SMOOTH",ITEM_3);
    glutChangeToMenuEntry(2,"normal",ITEM_4);
    smooth = true;
    break;
  case ITEM_4:
    glutChangeToMenuEntry(1,"smooth",ITEM_3);
    glutChangeToMenuEntry(2,"NORMAL",ITEM_4);
    smooth = false;
    break;
  }
  glutPostRedisplay();
}

char* readStringFromFile(char *fn) {

    FILE *fp;
    char *content = NULL;
    int count=0;

    if (fn != NULL) {
        fp = fopen(fn,"rt");

        if (fp != NULL) {
      
            fseek(fp, 0, SEEK_END);
            count = ftell(fp);
            rewind(fp);

            if (count > 0) {
                content = (char *)malloc(sizeof(char) * (count+1));
                count = fread(content,sizeof(char),count,fp);
                content[count] = '\0';
            }
            fclose(fp);
        }
    }
    return content;
}

void setShaders(int shader) {

    char *vs = NULL,*fs = NULL,*fs2 = NULL;


    glewInit();
    if (glewIsSupported("GL_VERSION_2_0"))
        printf("Ready for OpenGL 2.0\n");
    else {
        printf("OpenGL 2.0 not supported\n");
        exit(1);
    }

    v = glCreateShader(GL_VERTEX_SHADER);
    f = glCreateShader(GL_FRAGMENT_SHADER);

    if(shader==1){
       vs = readStringFromFile("shaders/toonf2.vert");
       fs = readStringFromFile("shaders/toonf2.frag");
    }
    else if(shader==2){
          vs = readStringFromFile("shaders/flatten.vert");
          fs = readStringFromFile("shaders/flatten.frag");
    }
    else if(shader==3){
          vs = readStringFromFile("shaders/color.vert");
          fs = readStringFromFile("shaders/color.frag");
    }
    else if(shader==5){
          vs = readStringFromFile("shaders/teste.vert");
          fs = readStringFromFile("shaders/teste.frag");
    }
       
    const char * vv = vs;
    const char * ff = fs;

    glShaderSource(v, 1, &vv,NULL);
    glShaderSource(f, 1, &ff,NULL);

    free(vs);free(fs);

    glCompileShader(v);
    glCompileShader(f);

    p = glCreateProgram();
    glAttachShader(p,v);
    glAttachShader(p,f);

    glLinkProgram(p);
    glUseProgram(p);
}

//#################################################################


//#################################################################
//################            CLASSES            ##################
//#################################################################

class Nave{
   public:
      Mesh *mesh;
      int velocidade;
      float pos[3];
      float angulo[2]; //varia de 90 até 270
      Nave(){ 
              velocidade = 1;
              angulo[0] = 180;
              angulo[1] = 90;
              pos[0] = 0;
              pos[1] = 0;
              pos[2] = 0;
      }
      void desenhaNave(){
           glPushMatrix();
           glTranslatef(pos[0],pos[1],pos[2]);
           //glutSolidSphere(12,16,16);
           glPushMatrix();
              glRotatef(angulo[1],1,0,0);
              glPushMatrix();
                 glRotatef(angulo[0],0,1,0);
                 glDisable(GL_TEXTURE_2D);
                 glPushMatrix();
                    glTranslatef(5,8,2);
                    glRotatef(90,0,0,1);
                    glColor3f(1,0,0);
                    drawMeshFile(&teste);
                 glPopMatrix();
                 glEnable(GL_TEXTURE_2D);
                 glScalef(0.1,0.1,0.1);
                 glColor3f(1,1,1);
                 drawMeshFile(mesh);
              glPopMatrix();
           glPopMatrix();
           glPopMatrix();
      }
};

class Camera{
   public:
      float pos[3];
      bool escolhida;
      //float angulo; //varia de 90 até 270
      Camera(){ 
              pos[0] = 0;
              pos[1] = 0;
              pos[2] = 0;
      }
};

class Casa{
   public:
      Mesh* mesh;
      bool l_esq, l_dir;
      float pos[3];
      Casa(){ 
              pos[0] = 0;
              pos[1] = 0;
              pos[2] = 0;
              l_esq = false;
              l_dir = false;
      }
      void desenhaCasa(int num){
         glBindTexture(GL_TEXTURE_2D,textureObjects[2]);
         for (int i=0; i<num; i++){
            glPushMatrix();
               if ((l_esq)&&(l_dir)){  // casas dos dois lados
                   if (i%2==0) 
                      glTranslatef(pos[0],pos[1],pos[2]+(i*50)+20);
                   else
                      glTranslatef(-pos[0]+6,pos[1],pos[2]+(i*50));
               }
               else if (l_esq) // casass do lado esquerdo
                  glTranslatef(pos[0],pos[1],pos[2]+(i*100)+20);
               else // casas do aldo direito
                  glTranslatef(-pos[0]+6,pos[1],pos[2]+(i*100));
               glScalef(0.1,0.1,0.1);
               glRotatef(90,0,0,1);
               glPushMatrix();
                  glRotatef(90,0,1,0);
                  drawMeshFile(mesh);
                  glPopMatrix();
               glPopMatrix();
         }
      }
};

class Terreno{
   public:
      Mesh plano;
      bool ativo;
      Casa casa;
      float pos[3];
      Terreno(){
                pos[0]=0;
                pos[1]=0;
                pos[2]=0;
      }
      void desenhaTerreno(int num_casas){
           glPushMatrix();
               //desenhas plano
               glPushMatrix();
                  glColor3f(1,1,1);
                  glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
                  drawMeshFile(&plano);
               glPopMatrix();
               //desenha casas
               glPushMatrix();
                  glTranslatef(pos[0],pos[1],pos[2]);
                  casa.desenhaCasa(num_casas);
               glPopMatrix();
               //desenhas esferas
               glDisable(GL_TEXTURE_2D);
               for (int i=0; i<50; i++){
                   glPushMatrix();
                      glColor3f(1,0,0);
                      glTranslatef(-62,0,pos[2]+(-i*10)); //esferas laterais
                      glutSolidSphere(1,16,16);
                   glPopMatrix();
                   glPushMatrix();
                      glColor3f(1,0,0);
                      glTranslatef(62,0,pos[2]+(-i*10)); //esferas laterais
                      glutSolidSphere(1,16,16);
                   glPopMatrix();
               }
               glEnable(GL_TEXTURE_2D);
           glPopMatrix();
      }
};



//#################################################################


//#################################################################
//################      VARIAVEIS E FUNÇÕES      ##################
//#################################################################


Nave nave;
Camera camera[2];
Terreno terreno[3];
//int distancia = 0;

//ajusta valores da nave, do terreno, e da câmera
void recalculaDistancia(){
     for (int i=0;i<3;i++){
         if ((terreno[i].pos[2]-nave.pos[2]<=nave.velocidade-1)&&(terreno[i].pos[2]-nave.pos[2]>=0)){ //se a diferença da posição do terreno em relação a nave da nave for <= a velocidade da nave
            if ((i==0)&&(terreno[i].pos[2]!=0)){
               terreno[2].pos[2] -=1500;
               translateZ(-1500,&(terreno[2].plano));
            }
            else{
                terreno[i-1].pos[2] -=1500;
                translateZ(-1500,&(terreno[i-1].plano));
            }
         }
     }
     
     //limites pra nave - horizontal
     if (nave.pos[0]<-50)
        nave.pos[0]=-50;
     else if (nave.pos[0]>50)
          nave.pos[0]=50;
     if (nave.angulo[0]<=130)
        nave.angulo[0]=130;
     else if (nave.angulo[0]>=230)
          nave.angulo[0]=230;
          
     //limites pra nave - vertical
     if (nave.pos[1]<-50){
        nave.pos[1]=-50;
        camera[1].pos[1] = 100;
     }
     else if (nave.pos[1]>50){
          nave.pos[1]=50;
          camera[1].pos[1] = 200;
     }
     if (nave.angulo[1]<=60)
        nave.angulo[1]=60;
     else if (nave.angulo[1]>=120)
          nave.angulo[1]=120;
}

//ajusta as câmeras
void incrementaPos(){
     //velocidade da nave
     nave.pos[2] -= nave.velocidade; 
     
     //posição da camera 1
     camera[0].pos[2] = nave.pos[2] + 120;
     
     //posição da camera 2
     camera[1].pos[2] = nave.pos[2] -40; //mesma da display
}

//varia de 90 até 270
void turn(){
     if ((nave.angulo[0]<=182)&&(nave.angulo[0]>=178)){
        nave.angulo[0] = 180;
        if ((nave.angulo[1]<=92)&&(nave.angulo[1]>=88)){
           nave.angulo[1] = 90;
           mov = false;
           //return;
        }
     }
     
     float m = (180 - nave.angulo[0])/10;
     nave.angulo[0] += m;
     
     m = (90 - nave.angulo[1])/10;
     nave.angulo[1] += m;
     
}

void retornoMov(int key, int x, int y){
     mov = true;
}

void colisaoTerreno(){
     for (int t=0; t<3; t++){
         for (int i=0; i<terreno[t].plano.nbrVerts; i++){
            if (sqrt(
            pow(nave.pos[0]-terreno[t].plano.verts[i].x,2) + 
            pow(nave.pos[1]-terreno[t].plano.verts[i].y,2) + 
            pow(nave.pos[2]-terreno[t].plano.verts[i].z,2) ) 
            < 10){
                  //desvia para direita
                  if (nave.pos[0]>terreno[t].plano.verts[i].x){
                     nave.angulo[0]-=10;
                     nave.pos[0]+=2;
                  }
                  //desvia para esquerda
                  else if (nave.pos[0]<terreno[t].plano.verts[i].x){
                     nave.angulo[0]+=10;
                     nave.pos[0]-=2;
                  }
                  //desvia para cima
                  else{
                       nave.angulo[1]+=10;
                       nave.pos[1]+=2;
                  }
                  mov = true;
                     turn();
            }
         }
     }
}
     

//FAZ TUDO
void idle(void){
     incrementaPos();
     
     if (mov){
            turn();
     }
     
         
     recalculaDistancia();
     
     colisaoTerreno();
     
     if (smooth){
        glShadeModel(GL_SMOOTH);
     }
     else{
          glShadeModel(GL_FLAT);
     }
     teste.simulaFisica(0.002);
    

     glutPostRedisplay();
}

//COMANDOS EXTRAS
void key(unsigned char k, int x, int y) {
     switch (k){
            case '1' :
                 camera[0].escolhida = true;
                 camera[1].escolhida = false;
                 break;
            case '2' :
                 camera[0].escolhida = false;
                 camera[1].escolhida = true;
                 break;
            
            case '=' :
                 if (nave.velocidade<4)
                    nave.velocidade++;
                 break;
            case '-' :
                 if (nave.velocidade>0)
                    nave.velocidade--;
                 break;
            
     }
}

//COMANDOS DE MOVIMENTAÇÃO
void directions(int x,int y,int z){
     switch (x){
            case GLUT_KEY_UP :
                 if (nave.pos[1]>=-49) // só implementa o angulo se nao passar do limite
                    nave.angulo[1] -= 2;
                 nave.pos[1] -= 1;
                 camera[1].pos[1] -= 1;
                 break;
            case GLUT_KEY_DOWN :
                 if (nave.pos[1]<=49) // só implementa o angulo se nao passar do limite
                    nave.angulo[1] += 2;
                 nave.pos[1] += 1;
                 camera[1].pos[1] += 1;
                 break;
            case GLUT_KEY_RIGHT :
                 if (nave.pos[0]<=49) // só implementa o angulo se nao passar do limite
                    nave.angulo[0] -= 2;
                 nave.pos[0] += 1;
                 break;
            case GLUT_KEY_LEFT :
                 if (nave.pos[0]>=-49) // só implementa o angulo se nao passar do limite
                    nave.angulo[0] += 2;
                 nave.pos[0] -= 1;
                 break;
     }
}

//#################################################################


//#################################################################
//################         LOOP PRINCIPAL       ###################          
//#################################################################

void display(void){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Clear the colour and depth buffer

glLoadIdentity(); // Clear matrix stack

    //cout << "Molas: " << teste.nbrMolas << ";  Massas: " << teste.nbrMassas << endl;
    // system ("pause");
    
    //escolhe a câmera
    if (camera[0].escolhida){
       gluLookAt(camera[0].pos[0], camera[0].pos[1], camera[0].pos[2], nave.pos[0], nave.pos[1], nave.pos[2], 0, 1, 0); // colocar 0 no x e y do focus
    }
    else{
        gluLookAt(camera[1].pos[0], camera[1].pos[1], camera[1].pos[2], 0, 0, nave.pos[2]-40, 0, 0, -1);
    }
    
    //desenha terrenos
    
    //terrenos 0
    terreno[0].desenhaTerreno(10);
    glPushMatrix();
       glTranslatef(terreno[0].pos[0]-179,terreno[0].pos[1]-60,terreno[0].pos[2]);
       glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
       glColor3f(1,1,1);
       drawMeshFile(&paisagem[0]);
    glPopMatrix();
    glPushMatrix();
       glTranslatef(terreno[0].pos[0]+59,terreno[0].pos[1]-60,terreno[0].pos[2]);
       glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
       glColor3f(1,1,1);
       drawMeshFile(&paisagem[3]);
    glPopMatrix();
    
    //terrenos 1
    terreno[1].desenhaTerreno(3);
    glPushMatrix();
       glTranslatef(terreno[1].pos[0]-179,terreno[1].pos[1]-60,terreno[1].pos[2]);
       glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
       glColor3f(1,1,1);
       drawMeshFile(&paisagem[2]);
    glPopMatrix();
    glPushMatrix();
       glTranslatef(terreno[1].pos[0]+59,terreno[1].pos[1]-60,terreno[1].pos[2]);
       glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
       glColor3f(1,1,1);
       drawMeshFile(&paisagem[5]);
    glPopMatrix();
    
    
    //terrenos 2
    terreno[2].desenhaTerreno(2);
    glPushMatrix();
       glTranslatef(terreno[2].pos[0]-179,terreno[2].pos[1]-60,terreno[2].pos[2]);
       glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
       glColor3f(1,1,1);
       drawMeshFile(&paisagem[1]);
    glPopMatrix();
    glPushMatrix();
       glTranslatef(terreno[2].pos[0]+59,terreno[2].pos[1]-60,terreno[2].pos[2]);
       glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
       glColor3f(1,1,1);
       drawMeshFile(&paisagem[4]);
    glPopMatrix();

    //fog não afetará quem estiver aqui
    glDisable(GL_FOG);
       glBindTexture(GL_TEXTURE_2D,textureObjects[0]);
       nave.desenhaNave();
    glEnable(GL_FOG);
    
glEnable(GL_NORMALIZE);
glFlush(); // Makes sure that we output the model to the graphics card
glutSwapBuffers();
glutPostRedisplay();
}

//#################################################################


//#################################################################
//################          INIT E MAIN          ##################          
//#################################################################

void init(){
   glClearColor(0.5,0.5,0.5,0); //muda cor da janela
   glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
   glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
   glEnable(GL_DEPTH_TEST); // Enables Depth Testing
   glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading

   glEnableClientState(GL_VERTEX_ARRAY);
   //glEnableClientState(GL_COLOR_ARRAY);
   glEnableClientState(GL_NORMAL_ARRAY);
   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   
   //inicia função de iluminação
   setupRC();
   
   //inicializa mesh da nave
   nave.mesh=ObjLoader::ReadMesh("spaceship.3ds");
   nave.mesh->initNeighbors();
   nave.mesh->calcNormals();

   
   //definição de posição inicial das casas
   terreno[0].casa.l_esq = terreno[0].casa.l_dir = true;
   terreno[1].casa.l_esq = true;
   terreno[2].casa.l_dir = true;
   
   terreno[0].casa.pos[0] = -50;
   terreno[0].casa.pos[1] = -56;
   
   terreno[1].casa.pos[0] = -50;
   terreno[1].casa.pos[1] = -5;
   terreno[1].casa.pos[2] = 100;
   
   terreno[2].casa.pos[0] = -50;
   terreno[2].casa.pos[1] = -5;
   terreno[2].casa.pos[2] = 300;
   
   
   //chama as texturas
   textureMagic();
   
   //atribui os valores da textura para a malha
   long k = 0;
   for( int i = 0; i < 256; i++ ){
          for( int j = 0; j < 256; j++ ){
               //mudar indice de img[] para alterar textura de relevo
             terreno[0].plano.matrix[j][i].r = (unsigned char)img[2].data[k++];
             terreno[1].plano.matrix[j][i].r = (unsigned char)img[3].data[k];
             terreno[2].plano.matrix[j][i].r = (unsigned char)img[4].data[k];
             paisagem[0].matrix[j][i].r = (unsigned char)img[6].data[k];
             paisagem[1].matrix[j][i].r = (unsigned char)img[7].data[k];
             paisagem[2].matrix[j][i].r = (unsigned char)img[8].data[k];
             paisagem[3].matrix[j][i].r = (unsigned char)img[9].data[k];
             paisagem[4].matrix[j][i].r = (unsigned char)img[10].data[k];
             paisagem[5].matrix[j][i].r = (unsigned char)img[11].data[k];
             
             terreno[0].plano.matrix[j][i].g = (unsigned char)img[2].data[k++];
             terreno[1].plano.matrix[j][i].g = (unsigned char)img[3].data[k];
             terreno[2].plano.matrix[j][i].g = (unsigned char)img[4].data[k];
             paisagem[0].matrix[j][i].g = (unsigned char)img[6].data[k];
             paisagem[1].matrix[j][i].g = (unsigned char)img[7].data[k];
             paisagem[2].matrix[j][i].g = (unsigned char)img[8].data[k];
             paisagem[3].matrix[j][i].g = (unsigned char)img[9].data[k];
             paisagem[4].matrix[j][i].g = (unsigned char)img[10].data[k];
             paisagem[5].matrix[j][i].g = (unsigned char)img[11].data[k];
             
             terreno[0].plano.matrix[j][i].b = (unsigned char)img[2].data[k++];
             terreno[1].plano.matrix[j][i].b = (unsigned char)img[3].data[k];
             terreno[2].plano.matrix[j][i].b = (unsigned char)img[4].data[k];
             paisagem[0].matrix[j][i].b = (unsigned char)img[6].data[k];
             paisagem[1].matrix[j][i].b = (unsigned char)img[7].data[k];
             paisagem[2].matrix[j][i].b = (unsigned char)img[8].data[k];
             paisagem[3].matrix[j][i].b = (unsigned char)img[9].data[k];
             paisagem[4].matrix[j][i].b = (unsigned char)img[10].data[k];
             paisagem[5].matrix[j][i].b = (unsigned char)img[11].data[k];
             
             
          }
   }
   
   for (int i=0;i<6;i++){
      paisagem[i].criaPlano(12,50,10);
      paisagem[i].initNeighbors();
      paisagem[i].calcNormals();
   }
   
   //smooth para a iluminação
   smooth=true; //smooth
   
   //defini a câmera inicial
   camera[0].escolhida = true;
   camera[1].escolhida = false;
   
   //posição fixa das câmeras
   camera[0].pos[1] = 20;
   camera[1].pos[1] = 150;
   
   //inicializa mesh...
   for (int i=0;i<3;i++){
      // ...dos planos
      terreno[i].plano.criaPlano(24,100,5);
      terreno[i].plano.initNeighbors();
      terreno[i].plano.calcNormals();
      // ...das casas
      terreno[i].casa.mesh=ObjLoader::ReadMesh("house.3ds");
      terreno[i].casa.mesh->initNeighbors();
      terreno[i].casa.mesh->calcNormals();
   }
   
   //coloca terrenos mais para a frente
   terreno[1].pos[2] = -500;
   terreno[2].pos[2] = -1000;

   //coloca planos (meshs) mais para a frente
   translateZ(-500,&(terreno[1].plano));
   translateZ(-1000,&(terreno[2].plano));
   
   translateXY(-60,&(terreno[0].plano));
   translateXY(-60,&(terreno[1].plano));
   translateXY(-60,&(terreno[2].plano));
   
   teste.criaMassaMola(20,10,1);
   teste.initNeighbors();
   teste.calcNormals();
   
   cout << "Escolha um shader:" << endl;
   cout << "1- Toon Shader" << endl;
   cout << "2- Flatten Shader" << endl;
   cout << "3- Color Shader" << endl;
   cout << "4- Default" << endl;
   cout << "5- TESTE" << endl;
   cin >> choice;
   
   if(choice!=4){        
      setShaders(choice);
   }

}

int main(int argc, char *argv[]){
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE); // We want rgb display functionality
   glutInitWindowSize(640,480); // Set the window dimensions
   glutInitWindowPosition(0,0); // Set the window starting point
   glutCreateWindow("Trabalho Final"); // Set the caption and launch the window

   init();
   fog();

   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutSpecialFunc(directions);
   glutKeyboardFunc(key);
   glutIdleFunc(idle);
   glutSpecialUpFunc(retornoMov);
   glutIgnoreKeyRepeat(0);
   
   subMenu1=glutCreateMenu(subMenuCallback);
   glutAddMenuEntry("LINES",ITEM_1);
   glutAddMenuEntry("triangles",ITEM_2);
   
   subMenu2=glutCreateMenu(subMenuCallback);
   glutAddMenuEntry("SMOOTH",ITEM_3);
   glutAddMenuEntry("normal",ITEM_4);
   
   glutCreateMenu(menuCallback);
   glutAddSubMenu("Render",subMenu1);
   glutAddSubMenu("Iluminação",subMenu2);
   glutAttachMenu(GLUT_RIGHT_BUTTON);

   glutMainLoop();
   
   //delete nave;

   return 0;
}
