Desenhando linhas e pontos

Capítulo 2. Desenhando linhas e
pontos

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.

Exemplo 2-1. programa linha.c

#include <GL/glut.h>
#include <stdlib.h>

// prototipos das funcoes
void init(void);
void display(void);
void keyboard(unsigned char key, int x, int y);

// funcao principal
int main(int argc, char** argv){
  glutInit(&argc, argv);                              // inicializa o glut
  glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);           // especifica o uso de cores e buffers
  glutInitWindowSize (256, 256);                          // especifica as dimensoes da janela
  glutInitWindowPosition (100, 100);                      // especifica aonde a janela aparece na tela
  glutCreateWindow ("Desenhando uma linha");              // cria a janela
  init();
  glutDisplayFunc(display);                               // funcao que sera redesenhada pelo GLUT
  glutKeyboardFunc(keyboard);                             // funcoes de teclado
  glutMainLoop();                                         // mostra todas as janelas criadas
  return 0;
}

// definicao de cada funcao

void init(void){
  glClearColor(1.0, 1.0, 1.0, 1.0);    // cor de fundo
  glOrtho (0, 256, 0, 256, -1 ,1);     // modo de projecao ortogonal
} 

void display(void){
  glClear(GL_COLOR_BUFFER_BIT);               // limpa a janela
  glColor3f (0.0, 0.0, 0.0);                  // cor da linha
  glBegin(GL_LINES);
  glVertex2i(40,200);  glVertex2i(200,10);    // coordenadas inicial e final da linha
  glEnd();
  glFlush();
}

void keyboard(unsigned char key, int x, int y){
  switch (key) {
  case 27:                                         // tecla Esc (encerra o programa)
	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
.

2.1. Descrição do programa linha.c

#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, 256×256 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 apresentados, 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.