Exercício II

Disciplina: Computação Gráfica
Professora: Soraia R. Musse

 

 Usando OpenGL

 

O objetivo desta aula é trabalhar com as transformações geométricas usando a biblioteca OpenGL.

Clicando aqui, você pode obter os códigos fontes que serão utilizados na aula de hoje.

Este programa possui as implementações do exercício anterior.

 

Inicialmente, verifique o conteúdo do programa fonte fornecido para entender como foi implementado o zoom, o pan e quais são as teclas usadas para interação. Depois, compile e execute o programa que abrirá uma janela com fundo preto, uma casinha e duas linhas que representam os eixos cartesianos. Aplique zoom e pan. Observe atentamente o código para entender o seu funcionamento e observe os métodos implementados.

Agora altere o código fonte conforme descrito a seguir para implementar as transformações geométricas para as várias instâncias da casinha separadamente. A cada alteração, compile e execute novamente o programa para verificar os resultados obtidos.

Crie uma classe chamada Instancia que contenha os atributos apresentados abaixo na Instancia.h:

 

#pragma once
class Instancia
{
public:
Instancia(void);
~Instancia(void);

float getTx(void);
float getTy(void);
float getEx(void);
float getEy(void);
float getAngulo(void);
void incrementaAngulo();
void decrementaAngulo();
void incrementaTx();
void incrementaTy();
void incrementaEx();
void incrementaEy();
void decrementaTx();
void decrementaTy();
void decrementaEx();
void decrementaEy();

private:
float tx, ty;
float ex, ey;
float angulo;
};

Acrescente um construtor nesta classe que não recebe parâmetros e inicializa ex e ey com 1 e os demais atributos com 0, conforme abaixo:

Instancia::Instancia(void)
{
 
    ex = ey = 1;
    tx = ty = 0;
    angulo =0;
}
 

Além de acrescentar métodos get para todos os atributos a classe Instancia, acrescente também métodos para incrementar e decrementar cada atributo, conforme mostra o exemplo abaixo. Porém, considere que os atributos tx, ty, ex e ey devem ser incrementados e decrementados em apenas 0.1 unidade.

 
void Instancia::incrementaAngulo() 
{
    angulo+= 1;
}
void Instancia::decrementaAngulo() 
{
    angulo= angulo - 1;
}
 
Em seguida, crie um atributo vector para armazenar objetos Instancia, chamado casas e instancie-o no método main ou inicializa: 
 
#include "Instancia.h"
#include <vector>
 
using namespace std;
 
 
vector<Instancia> casas;
 
int instanciaSelecionada = 0;
 
 
/*Inclua no main*/  
Main()
 
Instancia casa;
 
    casas.push_back(casa);
 

Como vamos trabalhar com várias instâncias da casinha, a idéia é que este atributo (instanciaSelecionada) irá guardar qual é a instância selecionada em cada momento, se é a primeira (0), a segunda (1), a terceira (2), e assim por diante. Somente após uma instância ser selecionada é que será possível alterar as transformações geométricas aplicadas sobre ela.

Agora altere o método TeclasEspeciais dando o tratamento definido a seguir para cada uma das teclas listadas. Considere que apenas os parâmetros de instanciamento de uma instância deverão ser alterados em cada momento.

·         PAGE_DOWN: cada vez que esta tecla for pressionada, o atributo instanciaSelecionada deve ser decrementado, de maneira que a instância anterior à atual seja selecionada. Lembre que a instância selecionada representa o índice do vector  de instâncias, e, portanto, este número não pode ser negativo. Assim, caso seja menor que zero, faça instanciaSelecionada receber o valor da última posição ocupada do ArrayList.

·         PAGE_UP: cada vez que esta tecla for pressionada, o atributo instanciaSelecionada deve ser incrementado, de maneira que a instância posterior à atual seja selecionada. Lembre que a instância selecionada representa o índice do vector de instâncias, e, portanto, este número não pode ser maior que o número de instâncias criadas e armazenadas no vector. Assim, caso seja maior que o número de instâncias armazenadas (definido em casa.size), faça instanciaSelecionada receber zero.

·         F1: quando esta tecla for pressionada, deverá ser criada uma nova instância, que deverá ser armazenada no vector. Lembre de atualizar o atributo instanciaSelecionada para que ele "aponte" para esta última instância criada.

·         RIGHT: quando esta tecla for pressionada, a instância selecionada deverá sofrer uma translação para a direita.

·         LEFT: quando esta tecla for pressionada, a instância selecionada deverá sofrer uma translação para a esquerda.

·         UP: quando esta tecla for pressionada, a instância selecionada deverá sofrer uma translação para cima.

·         DOWN: quando esta tecla for pressionada, a instância selecionada deverá sofrer uma translação para baixo.

·         F3: quando esta tecla for pressionada, a instância deverá ser rotacionada para a esquerda.

·         F2: quando esta tecla for pressionada, a instância deverá ser rotacionada para a direita.

·         F5: quando esta tecla for pressionada, a instância deverá aumentar de tamanho (aumente a escala em x e y proporcionalmente).

·         F6: quando esta tecla for pressionada, a instância deverá diminuir de tamanho (diminua a escala em x e y proporcionalmente).

Agora acrescente os comandos abaixo no método Desenha, logo após a chamada para o método desenhaEixos() (elimine os comandos existentes após a chamada para o método desenhaEixos() e acrescente os listados abaixo):

 
               // Aplica transformações geométricas e exibe as instâncias da casinha
 
for(int i =0; i <casas.size();i++) {
 
    glPushMatrix();
 
    glTranslatef(casas[i].getTx(), casas[i].getTy(), 0.0f);
    glScalef(casas[i].getEx(), casas[i].getEy(), 1.0f);
    glRotatef(casas[i].getAngulo(), 0.0f, 0.0f, 1.0f);
    if (instanciaSelecionada==i)
        glColor3f(1,1,1);
    else
        glColor3f(0,0,1);
    desenhaCasinha();
 
    glPopMatrix();
 
    }

Experimente colocar em comentário os comandos glPushMatrix(); e glPopMatrix();, e execute o programa novamente. O que acontece? Lembre que OpenGL trabalha com uma matriz de transformação corrente que "acumula" as transformações geométricas. Portanto, as funções glPushMatrix e glPopMatrix são usadas para definir o escopo das transformações. A glPushMatrix é utilizada para guardar a matriz de transformação corrente na pilha, e a glPopMatrix para recuperar a matriz de transformação corrente da pilha.

O objetivo das alterações realizadas até aqui foi de permitir a criação de várias instâncias da casinha que podem ser manipuladas de forma independente através das transformações de escala, rotação e translação, como exemplificado na próxima figura. Por isso, foi necessário armazenar os parâmetros de instanciamento para guardar as transformações que devem ser aplicadas em cada instância da casinha.

http://www.inf.pucrs.br/%7Emanssour/CG/pJava-TG-2D/exemplo.png

Agora vamos ver como acrescentar caracteres no desenho. Para isto, será usada a classe TextRenderer. Comece criando um novo atributo na classe Desenha e inicializando-o no método init, conforme exemplificado abaixo.

 
void desenhaTexto(void *font, char *string) {
    while(*string)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *string++);
}

Agora inclua os comandos abaixo no final do método display. Depois execute a aplicação e veja o resultado.

 
...
    glColor3f(0,0,0);
 
    glPushMatrix();
 
    glTranslatef(0,0,0);
    glScalef(0.2,0.2,0.2);
    glLineWidth(100);
    glRasterPos2f(0,0);
 
 desenhaTexto(GLUT_BITMAP_TIMES_ROMAN_24,"Casinha");
 
    glPopMatrix();
 
    glutSwapBuffers();
 
 
    glFlush();
...