O propósito desta lição é entender recursos fundamentais da biblioteca OpenGL e da biblioteca auxiliar GLUT, tais como abrir uma janela, definir sistemas de coordenadas, limpar a tela e especificar cores de desenho. Este propósito será alcançado através da análise do programa linha.c, mostrado no Exemplo 2-1, cuja única funcionalidade desenhar uma reta entre dois pontos de uma janela gráfica.
#include <GL/glut.h> #include <stdlib.h> void init(void); void display(void); void keyboard(unsigned char key, int x, int y); int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (256, 256); glutInitWindowPosition (100, 100); glutCreateWindow ("Desenhando uma linha"); init(); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } void init(void){ glClearColor(1.0, 1.0, 1.0, 1.0); glOrtho (0, 256, 0, 256, -1 ,1); } void display(void){ int i; glClear(GL_COLOR_BUFFER_BIT); glColor3f (0.0, 0.0, 0.0); glBegin(GL_LINES); glVertex2i(40,200); glVertex2i(200,10); glEnd(); glFlush(); } void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; } } |
Para compilar e executar o programa linha.c, salve-o juntamente com o arquivo Makefile em um diretório e execute a seguinte seqüência de comandos:
$ make linha
$ linha |
A saída do programa linha é mostrado na Figura 2-1.
#include <GL/glut.h> #include <stdlib.h> |
Estes includes definem os protótipos das funções utilizadas pelo programa. stdlib.h contém o protótipo da função exit(3); O arquivo de cabeçalho glut.h inclui, além dos protótipos das funções GLUT, os arquivos gl.h e glu.h, que contém os protótipos das funções principais e auxiliares do OpenGL.
void init(void); void display(void); void keyboard(unsigned char key, int x, int y); |
Funções implementadas após a função main devem ser prototipadas aqui, de modo a evitar erros de compilação.
int main(int argc, char** argv){ |
Todo programa em C/C++ inicia com a função main.
glutInit(&argc, argv); |
Inicializa a biblioteca GLUT e negocia uma seção com o gerenciador de janelas. É possível passar argumentos para a função glutInit provenientes da linha de execução, tais como a variável de ambiente DISPLAY, ou informações sobre a geometria da tela.
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); |
Informa à biblioteca GLUT o modo do display a ser utilizado quando a janela gráfica for criada. O flag GLUT_SINGLE força o uso de uma janela com buffer simples, significando que todos os desenhos serão feitos diretamente nesta janela. O flag GLUT_RGB diz que o modelo de cor utilizado será o RGB.
glutInitWindowSize (256, 256); glutInitWindowPosition (100, 100); |
Define o tamanho inicial da janela, 256x256 pixels, e a posição inicial do seu canto superior esquerdo na tela, (x, y)=(100, 100).
glutCreateWindow ("Desenhando uma linha"); |
Cria uma janela e define seu título como "Desenhando uma linha".
init(); |
Nesta função é definido o estado inicial do OpenGL, antes de qualquer desenho seja feito.
glutDisplayFunc(display); |
Define display() como a função de desenho (display callback) para a janela corrente. Quando GLUT determina que esta janela deve ser redesenhada, a função de desenho é chamada. A função de desenho deve possuir o seguinte protótipo:
void funcao()
(void);
glutKeyboardFunc(keyboard); |
Indica que sempre que uma tecla for pressionada no teclado, GLUT deverá chama a função keyboard() para tratar eventos de teclado (keyboard callback). A função de teclado deve possuir o seguinte protótipo:
void funcao()
(unsigned char key, int x, int y);
glutMainLoop(); |
Inicia o loop de processamento de desenhos com GLUT. Esta rotina deve ser chamada pelo menos uma vez em um programa que utilize a biblioteca GLUT.
return 0; } |
Finaliza o programa.
void init(void){ glClearColor(1.0, 1.0, 1.0, 1.0); |
Especifica as intensidade de vermelho (RED), verde (GREEN) e azul (BLUE) utilizadas para limpar a janela. Cada parâmetro pode varia de 0 a 1, o equivalente a uma variação de 0 a 255, usada convecionalmente no sistema de janelas. O último argumento é o canal alfa, usado para compor superfícies transparentes ou translucentes. Como estes conceitos ainda não foram, o canal alfa deve ser mantido com valor igual a 1.
glOrtho (0, 256, 0, 256, -1 ,1); } |
A função glOrtho define as coordenadas do volume de recorte (clipping volume), possuindo o seguinte protótipo:
void glOrtho()
( GLdouble left , GLdouble right , GLdouble bottom , GLdouble top , GLdouble zNear , GLdouble zFar );
Os parâmetros left e right especificam as coordenadas esquerda e direita, respectivamente, dos planos de corte verticais. Os parâmetros bottom e top especificam as coordenadas inferior e superior, respectivamente, dos planos de corte horizontais. zNear e zFar, por sua vez, especificam a coordenada mais próxima e mais distante do observador, respectivamente, no eixo de profundidade. Assim, o volume de recorte definido no exemplo será xmin=0 e xmax=256; ymin=0 e ymax=256; zmin=-1 e zmax=1.
void display(void){ int i; glClear(GL_COLOR_BUFFER_BIT); |
A função glClear() serve para limpar buffers utilizados pelo OpenGL com valores pré-definidos. A máscara utilizada neste exemplo, (GL_COLOR_BUFFER_BIT, diz à função glClear() que apenas o buffer de desenho deve ser limpo. Após a execução desta função, a tela ficará branca, uma vez que a init() define (R, G, B)=(1.0, 1.0, 1.0) como cor de limpeza de tela.
glColor3f (0.0, 0.0, 0.0); |
Especifica (R, G, B)=(0, 0, 0), preto, como a cor de desenho. Todos os objetos desenhados a partir daqui terão cor preta.
glBegin(GL_LINES); glVertex2i(40,200); glVertex2i(200,10); glEnd(); |
As funções glBegin() e glEnd() delimitam os vértices de uma primitiva de desenho ou de um grupo de primitivas. O parâmetro passado para a função especifica o tipo de primitiva a ser desenhado. Neste exemplo, o parâmetro GL_LINES indica que os vértices especificados devem ser tratados como pares de pontos que comporão segmentos de reta independentes. A função glVertex2i() define as coordenadas de um vértice.
void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; } } |
Conforme mencionado, a função keyboard() serve para tratar eventos de teclado. Sua implementação especifica que quando a tecla ESC (keycode=27) for pressionada o programa deverá ser finalizado.