
/*  
O programa mostra um sistema de coordenadas (setas) para auxiliar na 
criação das imagens e também algumas funções de teclado: 

x e X : gira o desenho em torno do eixo x 
y e Y : gira o desenho em torno do eixo y 
z e Z : gira o desenho em torno do eixo z 
(mas para girar o desenho é melhor usar as setas) 
e ou E (toggle) : apresenta ou não as setas 
p : Aumenta a profundidade quando em perspectiva 
P : Diminui a profundidade quando em perspectiva 
o ou O (toggle) : alterna entre perspectiva e projeção ortográfica 
1 : mostra as setas somente para o semi-plano positivo. 
2 : mostra as setas para ambos os semi-planos. 

setas do teclado (comportamento default) 
esquerda e direita : giram a imagem para a esquerda e para a direita 
p/ cima e p/ baixo: giram a imagem para cima e para baixo 

Ao pressionar m ou M (toggle) : o comportamento das setas mudam para: 
esquerda e direita: deslocam a imagem para esquerda e para a direita. 
p/ cima e p/ baixo: deslocam a imagem para cima e para baixo. 

*/


#include <windows.h>

#pragma hdrstop

#include <dos.h>
#include <stdio.h>
#include <math.h>

#include <gl/glut.h>

// Definições de Macros
#define drawOneLine(x1,y1,x2,y2)  glBegin(GL_LINES);  \
   glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd(); glFlush();


void inicializacao(void);
void teclado(unsigned char tecla, int x, int y);
void desenhar(void);
void redesenhar(int w, int h);
void setas(int tecla, int x, int y);
void eixos(float tamanho, int lados);
void pista(void);
void carro(void);
void obstaculos(void);
void partes(float eixotranslacao1X, float eixotranslacao1Y, float angulo,
            float eixotranslacao2X, float eixotranslacao2Y,
            float escalaX, float escalaY, float escalaZ, float cubo);

float c_x=0, c_y=0, c_z=-6;
float ang_x=0, ang_y=0, ang_z=0;
float matriz_modelamento[16];
float W=1,H=1;

int deslocamento=0, duplo=0, perspectiva=1, apresentar_eixos=1  ;

int main(int argc, char* argv[])
{
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
        glutInitWindowPosition(100,150);
        glutInitWindowSize(500,500);
        glutCreateWindow("Projeto Corrida");
        inicializacao();
        glutDisplayFunc(desenhar);
        glutKeyboardFunc(teclado);
        glutReshapeFunc(redesenhar);
        glutIdleFunc(desenhar);
        glutSpecialFunc(setas);
        glutMainLoop();

        return 0;
}

void inicializacao(void)
{
        glClearColor(0,0,0,0.5);
        glEnable(GL_DEPTH_TEST);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(c_x,c_y,c_z);
}

void teclado(unsigned char tecla, int x, int y)
{
        switch(tecla)
        {
                case 'x' : glRotatef(-5,1,0,0); break;
                case 'X' : glRotatef(5,1,0,0);  break;
                case 'y' : glRotatef(-5,0,1,0); break;
                case 'Y' : glRotatef(5,0,1,0);  break;
                case 'z' : glRotatef(-5,0,0,1); break;
                case 'Z' : glRotatef(5,0,0,1);  break;

                case 'm' :
                case 'M' : deslocamento = !deslocamento; break;

                case 'e' :
                case 'E' : apresentar_eixos = !apresentar_eixos; break;

                case 'p' :
                        glGetFloatv(GL_MODELVIEW_MATRIX,matriz_modelamento);
                        glMatrixMode(GL_MODELVIEW);
                        glLoadIdentity();
                        c_z -= 0.1;
                        glTranslatef(0,0,-0.1);
                        glMultMatrixf(matriz_modelamento);
                break;
                case 'P' :
                        glGetFloatv(GL_MODELVIEW_MATRIX,matriz_modelamento);
                        glMatrixMode(GL_MODELVIEW);
                        glLoadIdentity();
                        c_z += 0.1;
                        glTranslatef(0,0,0.1);
                        glMultMatrixf(matriz_modelamento);
                break;


                case 'o' :
                case 'O' :
                        glMatrixMode(GL_PROJECTION);
                        glLoadIdentity();
                        if(perspectiva)
                        {
                                glOrtho(-3,3,-3,3,-10,10);
                                perspectiva = 0;
                        }
                        else
                        {
                                gluPerspective(45,W/H,0.1,50);
                                perspectiva = 1;
                        }
                        glMatrixMode(GL_MODELVIEW);
                break;


                case '1' : duplo = 0; break;
                case '2' : duplo = 1; break;

                default : exit(0);
        }
}

void desenhar(void)
{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if(apresentar_eixos) eixos(0.5,duplo);

        glPushMatrix();
                glScalef(0.01,0.02,0.01);
                glTranslatef(-300,-150,0);
                pista();
        glPopMatrix();

        glPushMatrix();
                carro();
        glPopMatrix();

        glPushMatrix();
                obstaculos();
        glPopMatrix();

        glFlush();
        glutSwapBuffers();
}

void redesenhar(int w, int h)
{
        glViewport(0,0,w,h);
        if(h==0) h=1;
        W=w;
        H=h;
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        if(perspectiva)
                gluPerspective(45,w/h,0.1,50);
        else
                glOrtho(-3,3,-3,3,-10,10);
        glMatrixMode(GL_MODELVIEW);
}

void setas(int seta, int x, int y)
{
        glGetFloatv(GL_MODELVIEW_MATRIX,matriz_modelamento);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        if(!deslocamento) glTranslatef(c_x,c_y,c_z);

        switch(seta)
        {
                case GLUT_KEY_RIGHT :
                        if(deslocamento)
                        {
                                glTranslatef(0.1,0,0);
                                c_x += 0.1;
                        }
                        else
                                glRotatef(5,0,1,0);
                break;

                case GLUT_KEY_LEFT :
                        if(deslocamento)
                        {
                                glTranslatef(-0.1,0,0);
                                c_x -= 0.1;
                        }
                        else
                                glRotatef(-5,0,1,0);
                break;

                case GLUT_KEY_UP :
                        if(deslocamento)
                        {
                                glTranslatef(0,0.1,0);
                                c_y += 0.1;
                        }
                        else
                                glRotatef(-5,1,0,0);
                break;

                case GLUT_KEY_DOWN :
                        if(deslocamento)
                        {
                                glTranslatef(0,-0.1,0);
                                c_y -= 0.1;
                        }
                        else
                                glRotatef(5,1,0,0);
                break;

                default:
                        exit(0);
        }

        if(!deslocamento) glTranslatef(-c_x,-c_y,-c_z);
        glMultMatrixf(matriz_modelamento);

}

void eixos(float tamanho, int lados)
{
        // Eixo X
        glColor3f(1,0,0);
        glBegin(GL_LINES);
                if(lados)
                        glVertex3f(-tamanho,0,0);
                else
                        glVertex3f(0,0,0);
                glVertex3f( tamanho,0,0);
        glEnd();
        // Setas do eixo X
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
        glBegin(GL_TRIANGLES);
                glVertex3f(tamanho,0,0);
                glVertex3f(tamanho-0.2,0.05,0);
                glVertex3f(tamanho-0.2,-0.05,0);
                glVertex3f(tamanho,0,0);
                glVertex3f(tamanho-0.2,0,0.05);
                glVertex3f(tamanho-0.2,0,-0.05);
        glEnd();

        // Eixo Y
        glColor3f(0,1,0);
        glBegin(GL_LINES);
                if(lados)
                        glVertex3f(0,-tamanho,0);
                else
                        glVertex3f(0,0,0);
                glVertex3f(0, tamanho,0);
        glEnd();
        // Setas do eixo Y
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
        glBegin(GL_TRIANGLES);
                glVertex3f(0,tamanho,0);
                glVertex3f(0.05,tamanho-0.2,0);
                glVertex3f(-0.05,tamanho-0.2,0);
                glVertex3f(0,tamanho,0);
                glVertex3f(0,tamanho-0.2,0.05);
                glVertex3f(0,tamanho-0.2,-0.05);
        glEnd();

        // Eixo Z
        glColor3f(0,0,1);
        glBegin(GL_LINES);
                if(lados)
                        glVertex3f(0,0,-tamanho);
                else
                        glVertex3f(0,0,0);
                glVertex3f(0,0, tamanho);
        glEnd();
        // Setas do eixo Z
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
        glBegin(GL_TRIANGLES);
                glVertex3f(0,0,tamanho);
                glVertex3f(0.05,0,tamanho-0.2);
                glVertex3f(-0.05,0,tamanho-0.2);
                glVertex3f(0,0,tamanho);
                glVertex3f(0,0.05,tamanho-0.2);
                glVertex3f(0,-0.05,tamanho-0.2);
        glEnd();

        glFlush();
}


// Desenha o carro 
void carro(void)
{
   /* Construcao do Retangulo maior que eh a base do carro */

   glPushMatrix();
          partes(-1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.4, 1.0, 0.65);
   glPopMatrix();
   
   /* Construcao do cockpit que eh o retangulo
      menor dentro da base do carro
   */
   glPushMatrix();
          partes(1.0, 0.0, 180.0, 1.0, 0.0, 1.0, 0.4, 1.0, 0.25);
   glPopMatrix();

   /* Construcao das Rodas */ 
   
   /* Roda Inferior Esquerda  */
   glPushMatrix();
          partes(1.0, 1.0, 180.0, 1.2, 1.17, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();

   /* Roda Inferior Direita */
   glPushMatrix();
          partes(1.0, 1.0, 180.0, 0.8, 1.17, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();

   /* Roda Superior  Esquerda  */
   glPushMatrix();
          partes(1.0, 1.5, 180.0, 1.2, 1.34, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();

      /* Roda Superior Direita   */
   glPushMatrix();
          partes(1.0, 1.5, 180.0, 0.8, 1.34, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();

   glFlush();
}

// Desenha os obstaculos 
void obstaculos(void)
{
   GLUquadricObj *qobj;

   /* Construcao de um carro servindo como obstaculo
    Retangulo maior que eh a base do carro */

   glPushMatrix();
          partes(0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.4, 1.0, 0.65);
   glPopMatrix();
   
   /* Construcao do cockpit que eh o retangulo
      menor dentro da base do carro
   */
   glPushMatrix();
          partes(2.5, 0.0, 180.0, 1.0, 0.0, 1.0, 0.4, 1.0, 0.25);
   glPopMatrix();

   /* Construcao das Rodas */ 
   
   /* Roda Inferior Esquerda  */
   glPushMatrix();
          partes(2.5, 1.0, 180.0, 1.2, 1.17, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();
                  
   /* Roda Inferior Direita     */
   glPushMatrix();
          partes(2.5, 1.0, 180.0, 0.8, 1.17, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();
                    
   /* Roda Superior  Esquerda    */
   glPushMatrix();
          partes(2.5, 1.5, 180.0, 1.2, 1.34, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();    

      /* Roda Superior Direita    */
   glPushMatrix();
          partes(2.5, 1.5, 180.0, 0.8, 1.34, 1.5, 0.75, 1.0, 0.10);
   glPopMatrix();     

   qobj = gluNewQuadric();
   gluQuadricDrawStyle(qobj, GLU_LINE);  /* all polygons wireframe */
   gluQuadricNormals(qobj, GLU_NONE);  

   glPushMatrix();
         glTranslatef (-1.0, -1.0, 0.0);
         gluCylinder(qobj, 0.1, 0.1, 0.5, 10, 5);
   glPopMatrix();

   glPushMatrix();
         glTranslatef (1.5, 1.0, 0.0);
         gluCylinder(qobj, 0.1, 0.1, 0.5, 10, 5);
   glPopMatrix();

   glFlush();
}

// Desenha as partes do carro

void partes(float eixotranslacao1X, float eixotranslacao1Y, float angulo,
            float eixotranslacao2X, float eixotranslacao2Y,
            float escalaX, float escalaY, float escalaZ, float cubo)
{
   glTranslatef (eixotranslacao1X, eixotranslacao1Y, 0.0);
   glRotatef (angulo, 0.0, 0.0, 1.0);
   glTranslatef (eixotranslacao2X, eixotranslacao2Y, 0.0);
   glPushMatrix();
   glScalef (escalaX, escalaY, escalaZ);
   glutWireCube (cubo);
   glPopMatrix();
}


// Desenha a pista
void pista(void)
{
 
/* Especifica a cor branca para todas as linhas  */
   glColor3f (1.0, 1.0, 1.0);
   glScalef(1.5, 0.5, 1.0);    
     
   drawOneLine( -100.0, 150, 800.0, 150);    /* primeira linha */
   
   drawOneLine (-100.0, 450, 800.0, 450);    /* terceira linha */
      
/* Especifica a linha tracejada  */
   glEnable (GL_LINE_STIPPLE);

   glLineStipple (5, 0x1C47);  /*  dash/dot/dash  */
   drawOneLine (-100.0, 300.0, 800.0, 300.0);

   glDisable (GL_LINE_STIPPLE);
   
     // Executa os comandos OpenGL
     glFlush();

}



