Jonh Edson Ribeiro de Carvalho | IC-UFF
Computação Visual e Interfaces
 
 
Tutorial OpenGL

Capítulo 3. Preenchimento de regiões

O propósito desta lição é aprender funções básicas do OpenGL que tratam do preenchimento de regiões. Será mostrado um programa de desenho de polígonos com preenchimento interno com cores sólidas, padrões e combinações de cores. O programa analisado, preenchimento.c, é mostrado no Exemplo 3-1.

Exemplo 3-1. programa preenchimento.c

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

GLubyte tux[] = {
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x7f,  0xfe,  0x0, 
 0x0,  0xc4,  0x23,  0x0, 
 0x1,  0x83,  0x21,  0x80, 
 0x1,  0x7,  0xe0,  0x80, 
 0x1,  0x7,  0xf0,  0x80, 
 0x1,  0x8f,  0xf9,  0x80, 
 0x0,  0xff,  0xff,  0x0, 
 0x0,  0x4f,  0xf1,  0x0, 
 0x0,  0x6f,  0xf1,  0x0, 
 0x0,  0x2f,  0xf3,  0x0, 
 0x0,  0x27,  0xe2,  0x0, 
 0x0,  0x30,  0x66,  0x0, 
 0x0,  0x1b,  0x1c,  0x0, 
 0x0,  0xb,  0x88,  0x0, 
 0x0,  0xb,  0x98,  0x0, 
 0x0,  0x8,  0x18,  0x0, 
 0x0,  0xa,  0x90,  0x0, 
 0x0,  0x8,  0x10,  0x0, 
 0x0,  0xc,  0x30,  0x0, 
 0x0,  0x6,  0x60,  0x0, 
 0x0,  0x3,  0xc0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0
};

GLfloat r,g,b;

void init(void);
void display(void);
void keyboard(unsigned char key, int x, int y);
void mouse(int button, int state, int x, int y);

int main(int argc, char** argv){
  glutInit(&argc, argv);
  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize (256, 256); 
  glutInitWindowPosition (100, 100); 
  glutCreateWindow ("Preenchendo regiões");
  init();
  glutDisplayFunc(display); 
  glutKeyboardFunc(keyboard);
  glutMouseFunc(mouse);
  glutMainLoop();
  return 0;
}

void init(void){
  glClearColor(1.0, 1.0, 1.0, 1.0);
  glOrtho (0, 256, 0, 256, -1 ,1);
  r=0; g=1; b=0;
}

void display(void){
  int i;
  glClear(GL_COLOR_BUFFER_BIT);
  glDisable(GL_POLYGON_STIPPLE);

  glPolygonMode(GL_BACK, GL_LINE);
  glColor3f(1.0, 0.0, 0.0);
  glBegin(GL_POLYGON);
  glVertex2i(30,226);  glVertex2i(113,226);
  glVertex2i(113,143); glVertex2i(30,143); 
  glEnd();

  glPolygonMode(GL_BACK, GL_FILL);
  glColor3f(r, g, b);
  glBegin(GL_POLYGON);
  glVertex2i(143,226); glVertex2i(226,226);
  glVertex2i(226,143); glVertex2i(143,143); 
  glEnd();

  glBegin(GL_POLYGON);
  glColor3f(1.0, 0.0, 0.0);  glVertex2i(30,113);  
  glColor3f(0.0, 1.0, 0.0);  glVertex2i(113,113);
  glColor3f(0.0, 0.0, 1.0);  glVertex2i(113,30);  
  glColor3f(1.0, 1.0, 0.0);  glVertex2i(30,30); 
  glEnd();

  glEnable(GL_POLYGON_STIPPLE);
  glColor3f(1.0, 0.0, 1.0);
  glPolygonStipple(tux);
  glBegin(GL_POLYGON);
  glVertex2i(143,113); glVertex2i(226,113);
  glVertex2i(226,30); glVertex2i(143,30); 
  glEnd();
  glFlush();
  glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y){
  switch (key) {
  case 27:
	exit(0);
	break;
  }
}

void mouse(int button, int state, int x, int y){
  switch (button) {
  case GLUT_LEFT_BUTTON:
	if (state == GLUT_DOWN) {
	  r=(GLfloat)rand()/(RAND_MAX+1.0);
	  g=(GLfloat)rand()/(RAND_MAX+1.0);
	  b=(GLfloat)rand()/(RAND_MAX+1.0);
	  glutPostRedisplay();
	}
	break;
  }
}

Para compilar e executar o programa preenchimento.c, salve-o juntamente com o arquivo Makefile em um diretório e execute a seguinte seqüência de comandos:

$ make preenchimento
$ preenchimento

A saída do programa preenchimento é mostrado na Figura 3-1.

3.1. Descrição do programa preenchimento.c

Serão descritas aqui apenas as partes do programa que acrescentam conceitos novos em relação aos exemplos anteriores.

GLubyte tux[] = {
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x7f,  0xfe,  0x0, 
 0x0,  0xc4,  0x23,  0x0, 
 0x1,  0x83,  0x21,  0x80, 
 0x1,  0x7,  0xe0,  0x80, 
 0x1,  0x7,  0xf0,  0x80, 
 0x1,  0x8f,  0xf9,  0x80, 
 0x0,  0xff,  0xff,  0x0, 
 0x0,  0x4f,  0xf1,  0x0, 
 0x0,  0x6f,  0xf1,  0x0, 
 0x0,  0x2f,  0xf3,  0x0, 
 0x0,  0x27,  0xe2,  0x0, 
 0x0,  0x30,  0x66,  0x0, 
 0x0,  0x1b,  0x1c,  0x0, 
 0x0,  0xb,  0x88,  0x0, 
 0x0,  0xb,  0x98,  0x0, 
 0x0,  0x8,  0x18,  0x0, 
 0x0,  0xa,  0x90,  0x0, 
 0x0,  0x8,  0x10,  0x0, 
 0x0,  0xc,  0x30,  0x0, 
 0x0,  0x6,  0x60,  0x0, 
 0x0,  0x3,  0xc0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0, 
 0x0,  0x0,  0x0,  0x0
};

Define o vetor tux[], do tipo GLubyte, para representar o padrão de preenchimento de polígonos utilizado neste exemplo.

Existem dois métodos principais para preencher regiões utilizando padrões. O mais comum utiliza texturas, mas não será abordado nesta lição. O outro método consiste em definir um mapa de bits monocromático de 32x32 pixels, representando a máscara para o padrão que se deseja desenhar. O padrão utilizado neste exemplo é mostrado na Figura 3-2.

A máscara de desenho (vetor tux[]) é formada por um conjunto de números representados na forma hexadecimal. Para construir este vetor, toma-se cada linha do mapa de bits de baixo para cima. Cada 8 pixels de uma linha da figura equivalem aos bits componentes de um elemento do vetor. Os bits mais significativos ficam à esquerda e os menos significativos à direita. Seguindo esta receita, então a linha 8 da Figura 3-2, representada pela seqüência de bits 00000000110001000010001100000000, equivalerá à seqüência "0x0, 0xc4, 0x23, 0x0" do array tux[].

  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);

A função glutInitDisplayMode() avisa GLUT para utilizar dois buffers no desenho de cenas: um principal e outro auxiliar. Todos os objetos deverão desenhados no buffer auxiliar. Quando a função glutSwapBuffers() for chamada, o buffer auxiliar passa a ser o principal, e o principal toma o lugar do auxiliar. Assim, a imagem gerada é apresentada de uma só vez na tela, evitando cintilações e a visualização do processo de desenho, efeitos indesejáveis principalmente em animações.

  glutMouseFunc(mouse);

Define que função GLUT deverá chamar quando ocorrerem eventos de mouse. Quando o usuário pressiona ou solta uma dos botões do mouse, cada pressionamento ou soltura gera uma chamada de mouse. A função de chamada passada como argumento para glutMouseFunc() deve possuir o seguinte protótipo:

void funcao()(int button, int state, int x, int y);

void display(void){
  int i;
  glClear(GL_COLOR_BUFFER_BIT);
  glDisable(GL_POLYGON_STIPPLE);

As funções glDisable() e glEnable() permitem habilitar diversas habilidades do OpenGL. O parâmetro GL_POLYGON_STIPPLE passado para essa função desabilita o desenho de polígonos utilizando padrões de desenho. Quando GL_POLYGON_STIPPLE é habilitado, OpenGL usa o padrão corrente para desenhar.

  glPolygonMode(GL_BACK, GL_LINE);
  glColor3f(1.0, 0.0, 0.0);
  glBegin(GL_POLYGON);
  glVertex2i(30,226);  glVertex2i(113,226);
  glVertex2i(113,143); glVertex2i(30,143); 
  glEnd();

Neste trecho, a função glPolygonMode() indica que a parte de trás dos polígonos (GL_BACK) será desenhada apenas com a linha de contorno externo (GL_LINE), de cor vermelha, conforme especificado pela função glColor3f(). As funções glBegin()/glEnd() são usadas agora para iniciar o traçado de um polígono (GL_POLYGON) de coordenadas especificadas pela função glVertex2i(). O resultado é o contorno retangular vermelho mostrado na Figura 3-2.

  glPolygonMode(GL_BACK, GL_FILL);
  glColor3f(0.0, 1.0, 0.0);
  glBegin(GL_POLYGON);
  glVertex2i(143,226); glVertex2i(226,226);
  glVertex2i(226,143); glVertex2i(143,143); 
  glEnd();

A função glPolygonMode() indica agora que a parte de trás dos polígonos será desenhada apenas com preenchimento sólido (GL_FULL). A cor de desenho agora é (R, G, B) = (0, 1, 0), de modo que o resultado da execução desse trecho de código é o retângulo verde mostrado na Figura 3-2.

  glBegin(GL_POLYGON);
  glColor3f(1.0, 0.0, 0.0);  glVertex2i(30,113);  
  glColor3f(0.0, 1.0, 0.0);  glVertex2i(113,113);
  glColor3f(0.0, 0.0, 1.0);  glVertex2i(113,30);  
  glColor3f(1.0, 1.0, 0.0);  glVertex2i(30,30); 
  glEnd();

Este trecho de código demonstra uma característica peculiar de preenchimento. Como cada vértice é desenhado com uma cor diferente, OpenGL interpola estas cores para compor as tonalidades do interior do polígono, gerando um preenchimento bastante colorido.

  glEnable(GL_POLYGON_STIPPLE);
  glColor3f(1.0, 0.0, 1.0);
  glPolygonStipple(tux);
  glBegin(GL_POLYGON);
  glVertex2i(143,113); glVertex2i(226,113);
  glVertex2i(226,30); glVertex2i(143,30); 
  glEnd();

O preenchimento com padrões é agora habilitado pela função glEnable(). A função glColor3f() define magenta, combinação das tonalidades puras vermelho (R=1) e azul (B=1), como a nova cor de desenho. A função glPolygonStipple() define o novo padrão de preenchimento de polígonos, representado pelo vetor tux[]. Em seguida, o par glBegin()/glEnd() desenha o último polígono, preenchindo com o padrão "tux".

  glFlush();

A função glFlush() faz com que qualquer comando OpenGL ainda não executado seja executado o mais rápido possível pelo mecanismo de exibição. OpenGL freqüentemente executa comandos aos lotes, de modo a tornar mais eficiente o processo de exibição, principalmente quando os programas são executados via rede. Neste caso, quando os comandos executados um a um, o programa pode se tornar ineficiente, considerando as sobrecargas existentes em um barramento de rede. Caso o programa desenvolvido seja destinado ao uso somente local, a função glFlush() torna-se desnecessária. Entretanto, se o programa é feito para funcionar bem tanto localmente quanto em rede, deve ser incluída uma chamada à função glFlush() no final de cada quadro ou cena.

void mouse(int button, int state, int x, int y){
  switch (button) {
  case GLUT_LEFT_BUTTON:
	if (state == GLUT_DOWN) {
	  r=(GLfloat)rand()/(RAND_MAX+1.0);
	  g=(GLfloat)rand()/(RAND_MAX+1.0);
	  b=(GLfloat)rand()/(RAND_MAX+1.0);
	  glutPostRedisplay();
	}
	break;
  }
}

A função de tratamento de eventos de mouse verifica se algum botão é pressionado. Caso o botão esquerdo (GLUT_LEFT_BUTTON) seja pressionado (GLUT_DOWN), serão gerados três valores aleatórios para as variáveis r, g e b, na faixa [0,1]. Quando a função glutPostRedisplay() é executada, a função display é chamada novamente, fazendo com que a janela corrente seja redesenhada e o polígono no canto superior esquerdo dessa janela mude de cor.

CopyLeft Webmaster |Atualizado em 22/11/2003
Contato   Pesquisas e Projetos  Publicações   Home