Capítulo 3. Preenchimento de regiões
- Índice
- 3.1. Descrição
do programa preenchimento.c - 3.2. Programas relacionados
- 3.3. Exercícios
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 32×32 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.