Vous êtes sur la page 1sur 382

Primeiro Captulo de um desenvolvedor de jogos

A dificuldade
Agora que voc tem em mente as duas primeiras regras de um desenvolvedor de jogos,
vamos comear a comentar sobre a dificuldade de se fazer um jogo.
Desenvolver jogos eletrnicos no apenas fazer um programa de computador, uma
ARTE!
Como um artista, voc deve saber e ter conhecimento sobre vrias reas. E como uma
obra de arte, um jogo custa muito dinheiro para fazer. ( Se voc usa tempo para faze-lo,
no se esquea que tempo dinheiro ).
Se voc j um programador, imagine um programa como o notepad do windows.
Ele possui vrios processos e regras, e difcil de fazer um programa como ele. Jogos
so ainda mais difceis, jogos so muito mais complexos.
Por que fazer um jogo no apenas s programar e testar, voc precisa divertir, precisa
de grficos, de msica, de interao, e tambm de um projeto de software, de um
projeto de designer, de um projeto de leveis, entre outra coisas.
Se voc no um programador, para fazer um jogo voc precisa ter conhecimentos na
seguintes reas:
- Artes grficas
- Planejamento de Roteiro
- Anlise de sistema
- Matemtica
- Lgica
- Psicologia
- Fsica
- Engenharia
Ter conhecimento no quer dizer saber tudo, mais ao demonstrar essas reas queremos
te dizer que desenvolver um jogo no fcil!!!!
No fcil por que:
- demora, leva tempo
- por que precisa de uma equipe, e por isso, relacionamento entre pessoas
- precisa de dedicao
E agora chegamos ao ponto mais importante, dedicao.

No estamos querendo fazer voc desistir de criar jogos. Mais se voc no tem
dedicao pode parar de ler por aqui e procurar outra rea para estudar.
Aaaaaaaeeee, antes que voc desista, o exemplo explica o por que da frase assustadora:
A Nintendo uma das maiores desenvolvedoras de jogos do mundo. Eles
desenvolveram muitas tecnologias que so usados em todos os vdeo-games modernos.
Para programar o primeiro jogo 3D eles demoraram cerca de 10 anos.
Levando isso em considerao, voc acha que, se comear a estudar Open GL (
biblioteca para gerar grficos 3D para computadores ) agora, em 1 ms vai conseguir
fazer um jogo como o Mario 64 ?
Se voc no for programador, no mnimo vai demorar 1 ms para gerar seu primeiro
grfico 2D, imagina 3D.
Por isso, s continue se voc tiver dedicao, vontade e paixo por jogos.






Original

Evoluo de Plataforma

Evoluo nos Grficos




Mario 64 - Totalmente ambientado em 3D Um dos Primeiros 3D da nintendo



Segundo Captulo de um desenvolvedor de jogos
A felicidade
Meus Parabns.
Se voc est aqui por que voc tem garra e vontade para desenvolver jogos.
Espero que voc continue assim at o final! O caminho LONGOOOO!!!
A partir de agora, voc precisa decidir que rea seguir.
No sei se voc sabe, mais os jogos so feitos por vrias pessoas, essas pessoas
geralmente so especializadas em uma determinada rea.
As principais reas que voc pode escolher so:
Game Designer Desenvolvedor de Jogos
o principal criador de um jogo, ele quem define como o jogo vai ser, quais as
principais regras e objetivos do jogo.
Ele descreve como vai ser o ambiente, as imagens, qual o tipo de som e todos os fatores
para a criao do jogo.
Principais funes:
- Desenvolve a historia ou trama do jogo
- Desenvolve as regras do jogo
- Cria os personagens do jogo ( caso existir )
- Cria o objetivo do jogo
- Desenvolve a jogabilidade do jogo ( a forma que o jogo vai
ser jogado )
- Cria uma concepo bsica do jogo, que pode ser
desenhada como uma historia em quadrinhos
- Cria o Document Designer que o documento que descreve
o jogo em geral
- Descreve como quer que as coisas apaream para o usurio(
2D, 3D, tcnicas de desenho )



Imagem conceitual de uma mquina de
Pin-Ball desenhada por um Game Designer
onde ele demonstra os principais
funcionamentos da maquina

Designer Grfico
o desenhista do jogo, o criador das artes, movimentos ou modelos em 3D.
Principais funes:
- Desenhista conceitual dos cenrios / personagens / objetos
do jogo
- Desenhista computacional
- Modelador 3D
- Animador





Imagem conceitual de
Hanzo ( Samurai Shadow )
em papel
Imagem conceitual de um personagem
de Dungeons and Dragons tratada no
photo shop

Level Designer
o responsvel pela criao dos leveis( fases ), o ambiente onde o jogador vai jogar.
Ele modela o mundo do jogo.



Imagens em papel dos leveis de Super
Mario Bros 3
Imagem de um level sendo
criado no programa 3D Game
Studio

Programador
responsvel por fazer as idias do game designer virarem realidade. Ele desenvolve as
rotinas do jogo para que todas as regras sejam atendidas.
Principais funes:
- Responsvel pela inteligncia artificial
- Responsvel pela programao dos controles
- Responsvel pela jogabilidade
- Responsvel pela fsica
- Responsvel por fazer as regras do Game Designer
funcionar perfeitamente
- Responsvel pelos motores ( rotinas que fazem o jogo
funcionar )



Imagens do ambiente de programao do 3D Game Studio
Terceiro Captulo
Desafios
Muitos desenvolvedores de jogos brasileiros desistem de seus projetos. Isso por que eles
no tem em mente tudo o que foi citado at aqui.
Fazer um jogo profissional difcil, voc leu todas as reas que algum precisa saber
para ser um profissional. Por isso, muito mais fcil ter uma equipe para desenvolver
jogos do que trabalhar sozinho.
Nesse site voc vai aprender sozinho os principais passos para fazer um jogo. Mais voc
s deve fazer um jogo profissional quando tiver uma equipe. Enquanto voc estiver
lendo esse site, faa jogos pequenos, jogos rpidos e tente sempre termina-los.
Se voc apostar em um jogo grande, e no conseguir faze-lo, vai ser muito frustrante
para voc. Por isso, acompanhe todos os passos do tutorial para que voc no perca
tempo!
Uma das maiores dificuldades dos desenvolvedores de jogos brasileiros de se
encontrar uma equipe para fazer um projeto. Isto acontece por que no existe muita
gente especializada no mercado.
O foco principal deste site vai ser a criar a base de conhecimento em programao de
jogos. Mais lembre-se que esta no a nica rea que voc pode atuar.
Quarto Capitulo
O programador
Ser um programador muito legal... ser programador de jogos melhor ainda. O
Programador aquele cara que constri os programas para o outros usarem.
Atravs de lgica, ele cria rotinas que so interpretadas por um hardware que executa os
comandos.
Hoje em dia os programadores usam os computadores para interpretar suas lgicas.
Ento, antes de ser um programador voc precisa aprender como um computador
funciona.
Desta mesma forma, antes de programar um jogo para um X-Box voc precisa entender
como funciona um X-Box.
Para ser um bom programador de jogos voc precisa saber tudo o que possvel fazer
em um computador atualmente.
Voc precisa entender como a lgica de programao funciona.
Voc precisa ter imaginao, e disposio em estudar MUITOOOO..

Existe uma definio criada por Por Rodrigo Strauss do site www.1bit.com.br que
muito boa:

Um usurio sabe que quando ele pressiona a tecla "A", aparece a letra "A" na tela. Um
bom programador vai alm, e sabe que resumidamente, ao pressionar a tecla "A", o
teclado vai disparar um sinal eltrico que quando chegar no computador, vai disparar
uma interrupo de processador, que ser tratada por um driver que colocar isso em
uma fila, que ser lida pelos programas. Nem sempre voc precisar saber todos os
detalhes. O fato que o bom programador teve curiosidade suficiente para descobrir
como isso funciona.
Isso resume o que voc precisa ser e fazer a partir de agora, caso queria ser um
programador de jogos


Quinto Capitulo
Iniciando
Para entender como funciona um jogo, voc precisa entender como funciona um
programa. Um jogo um programa, e como um programa, ele executa vrias
rotinas internas em um computador.
Um programa envia mensagens para o windows, o windows envia mensagens para
o processador e o processador processa essas mensagens e executa os comandos
determinados pelo programa. Esses comandos podem, por exemplo, mostrar
mensagens na tela.
Um computador composto por:
Um monitor que um dispositivo de sada. Sada de informaes.

No monitor ser mostrado o jogo para o usurio.
A nica coisa que voc, como programador pode fazer, pedir para
o processador mostrar/desenhar alguma coisa na tela do monitor. O
processador poder enviar ele mesmo ou atravs do windows
informaes para o monitor.


Um teclado que um dispositivo de entrada. Entrada de informaes.

A partir do teclado o jogador ir enviar informaes para o seu jogo.
Cada tecla deve ser interpretada pelo seu jogo. Ele pode enviar seu
prprio nome ou mesmo ficar apertando as teclas direcionais para
mover um personagem.

Um mouse que um dispositivo de entrada. Entrada de informaes.

Assim como o teclado, o mouse pode enviar informaes para seu
jogo. Cada tecla do mouse deve ser interpretada pelo seu jogo.

As caixas de som que um dispositivo de sada. Sada de informaes.

As caixas de som so muito importantes em um jogo, pois por ela
que sai o som que envolve o jogador no ambiente do jogo. Voc
como programador pode enviar informaes para o processador
enviar o som do jogo para a sada de som.

A placa me que um dispositivo de entrada e de sada.

atravs da placa me que o processador recebe e envia
informaes para os outros dispositivos de entrada e sada. Voc no
vai precisar entender detalhes muitos avanados sobre a placa me,
j que voc no vai enviar comandos para ela.

O HD que um dispositivo de armazenamento e consequentemente de entrada e sada.

no HD ( Hard Disk ) que ficam gravadas todos os jogos e
programas de seu computador. Toda a informao gravada no HD
no perdida quando o computador desligado.
Voc vai usar o HD para, por exemplo, salvar o progresso do
jogador ( Save Game / Salvar jogo ) em seu jogo.

A memria RAM que um dispositivo de entrada e sada.

A memria RAM ( Random Access Memory ) vai ser sua maior
amiga ao desenvolver jogos. Ela o dispositivo que grava
informaes temporariamente. Toda vez que o computador
desligado, o valor contido nela ser perdido.
Geralmente, quando voc sai de um programa/jogo, mesmo esse
sendo feito por voc, o Windows libera o que voc colocou na
memria para outros programas.
A memria vai servir, por exemplo, para voc guardar a posio do
personagem atual, ou um desenho que quer mostrar na tela. Ela
funciona como o HD, s que a leitura que o processador faz nela
bem mais rpida .

O processador que um dispositivo de entrada e sada;

O processador o principal responsvel por fazer seu computador
funcionar ( e seus video-games tambm );
No processador executado todas as aritmticas necessrias para
resolver os problemas computacionais. O processador executa os
comandos enviados pelos dispositivos de entrada, e retorna o
resultado para os dispositivos de sada.
Ele pode executar apenas uma operao por vez.
Cada tarefa de seu programa/jogo ser executado em ordem pelo
processador, e as tarefas do sistema operacional tambm.


Exerccios
De Conhecimento:
1 - Entender como funciona um Hard Disk ( HD )
2 - Entender como funciona a Memria RAM
3 - Ententeder como funciona a Memria ROM




Sexto Captulo
Central de Computao
Iremos abordar mais profundamente o processador, que um item importante para
nosso estudo.
De acordo com a Wikipedia:
"O processador a parte mais fundamental para o funcionamento de um computador.
Processadores so circuitos digitais que realizam operaes como: cpia de dados,
acesso a memrias e operaes lgicas e matemticas.
Os processadores comuns trabalham apenas com lgica digital binria. Existem
processadores simples, que realizam um nmero pequeno de tarefas, que podem ser
utilizados em aplicaes mais especficas, e tambm existem processadores mais
sofisticados, que podem ser utilizados para os mais diferentes objetivos, desde que
programados apropriadamente.
Processadores geralmente possuem uma pequena memria interna, portas de entrada e
de sada, e so geralmente ligados a outros circuitos digitais como memrias,
multiplexadores e circuitos lgicos. Muitas vezes tambm um processador possui uma
porta de entrada de instrues, que determinam a tarefa a ser realizada por ele. Estas
seqncias de instrues geralmente esto armazenadas em memrias, e formam o
programa a ser executado pelo processador.
Em geral, fala-se que um processador melhor do que outro na medida em que ele pode
realizar uma mesma tarefa em menos tempo, ou com mais eficincia. Processadores
podem ser projetados para tarefas extremamente especficas, realizando-as com
eficincia insupervel. Este o caso nos processadores que controlam eletrodomsticos
e dispositivos simples como portes eletrnicos e algumas partes de automveis. Outros
visam uma maior genericidade, como nos processadores em computadores pessoais"
Neste texto da Wikipedia, demonstrado que seu processador entende apenas lgica
binria. Mais o que isto?
Lgica binria lgica baseada em dois nmeros importantes, 0 e 1.
Sendo que seu processador s entende 0 e 1 que quer dizer
basicamente, 1 para ligado e 0 para desligado.

- Abra a sua calculadora ( Iniciar > Executar > calc ), coloque em modo de exibio
Cientfica ( Exibir > Cientfica ), agora digite sua idade e selecione a opo BIN ( de
binrio ). O nmero que vai aparecer a sua idade em cdigo binrio, ou seja, a sua
idade para o processador.
15 anos = 1111
20 anos = 10100
21 anos = 10101


Neste momento voc no precisa entender como este cdigo funciona. Mais com
certeza voc deve ter achado um pouco complicado.
Ento, para fazer o processador entender um cdigo nosso, deveriamos escreve-lo em
binrio? J pensou que trabalhera??
10010101 00010101 01001010 10101010 01100101 ( Mostra um ponto na tela ??? O
que isto faz ? )
Com certeza, bem facil para o processador entender isso ai. Mais para ns no.
Foi pensando na dificuldade de ler/escrever estes cdigos que foram criadas as
linguagens de programao de computadores.


Essas linguagens nada mais so do que cdigos em que conseguimos ler facilmente,
que posteriormente so transformados em 0 e 1s para o processador ler.

Logo, no precisamos escrever uma infinidade de 0 e 1 para mostrar um ponto na tela,
basta que escrevamos um ESCREVER_NA_TELA( . ).
Como as linguagens de programao ajudaram muito os programadores a criar coisas
mais rpidas, muitas linguagens foram criadas. Algumas melhores outras piores. Isso
no importa, o que importa que elas resolvem os problemas computacionais.

Exemplo de linguagens:
Visual Basic
Java
C++
PHP
Pascal
Perl
Cobol
Assembly
Python
Rubi
e muitas mais!!
1 - Cada linguagem tem suas particularidades.
2 - Nosso principal objetivo agora encontrar uma linguagem boa
para criao de jogos.
Iremos usar a linguagem para resolver nossos problemas. E nossa
busca aprender a criar jogos.
E para criar jogos iremos utilizar a Linguagem C++.


Tudo o que voc escutou de bom e de mal sobre outras linguagens esquea, tudo o que
voc escutou de bom e de ruim sobre C++ tambm esquea.
C++ a linguagem que voc vai usar para seguir os tutoriais desde site. O site aborda
lgica e para isso voc no precisa entender tudo sobre C++;

A partir de agora voc um programador e no interessa a
linguagem que voc conhece, e sim o que voc sabe fazer com
ela.


Exerccios
De Conhecimento:
1 - Como funciona a linguagem C++ ?
2 - Como funciona a linguagem Java ?
3 - O que a linguagem Assembly ?
4 - Como funciona a linguagem PHP ?


Stimo Captulo
O Compilador
C++ uma linguagem de alto nvel, ou seja, facil para um ser humano entender o que
escrito em C++.
S que o programador tambm pode digitar cdigos em baixo nivel com C++. Cdigo
em baixo nivel, so cdigos que o processador entende, mais prximo do cdigo de
mquina.
Bjarne Stroustrup desenvolveu o C++ e deste os anos 90 ela uma das linguagens mais
utilizadas no mundo. Por isso, muito mais facil achar contedo de programao de
jogos em C++ do que em Pascal por exemplo.
Para que o processador possa entender o que a gente quer que ele
faa, nosso cdigo em C++ precisa ser interpretado para cdigo de
mquina.
E quem faz isso o compilador.


O compilador compila seu cdigo, gerando um EXE que vai ser lido
facilmente pelo processador.


Wikipedia:
"Classicamente, um compilador traduz um programa de uma linguagem textual
facilmente entendida por um ser humano para uma linguagem de mquina, especfica
para um processador e sistema operacional."
Baixe aqui o compilador que iremos utilizar para demonstrar os exemplos de
aprendizado:
DEV-C++ para PDJ
Voc tambm pode utilizar o Visual C++ ou o Code::Blocks.
Vamos ver as primeiras linhas de cdigo.
1 - Abra o DEV-C++ pela PDJ
2 - Clique em Arquivo > Novo > Projeto
DICAS IMPORTANTES...
- Para cada programa, sempre crie um novo projeto.
- Salve esse novo projeto sempre em pastas diferentes para manter a
organizao de arquivos.

- Um programador acima de tudo organizado!

- Sempre utilize estes passos para os prximos projetos.


3 - Selecione Aplicao Console, digite um nome para seu projeto e clique em OK.
Aps salvar o projeto, ele vai trazer uma folha em branco com um cdigo pr-definido.

CDIGO...

/*
* PDJ - Programadores e Desenvolvedores de Jogos
* http://www.pdj.com.br - LordVader
*
* Autor :
* Data :
* Desc : Aplicao bsica para Console
*
*/
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
return 0;
}

FIM DE CDIGO


4 - Clique em Executar > Compilar ( Salve o arquivo com o cdigo )
VOC PRECISA SABER...
- Geralmente, o primeiro arquivo do projeto contem o nome de Main
( main.cpp )
- Procure salvar os arquivos com nome minusculos ( main.cpp,
main.c, teste.c, principal.cpp, calculadora.c )
- Arquivos .cpp so arquivos em C++
- Arquivos .c so arquivos do C padro


Ao executar este processo, voc est pedindo ao compilador para ele verificar se no
existe nenhum erro em seu codigo.
No final, se no tiver nenhum erro, o compilador vai gerar o cdigo exe.

5 - Agora clique em Executar > Executar
Se tudo der certo, vai aparecer uma tela preta e logo ela vai sumir. Isto normal.
Voc conseguiu executar o seu programa, MAS como voc no pediu nada, o
processador no vai executar nada.
Vamos estudar o cdigo padro de um programa em C++.
Todos os seus projetos vo ter as seguintes linhas:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
return 0;
}

Bom.... as linhas em verde

/*
* PDJ - Programadores e Desenvolvedores de Jogos
* http://www.pdj.com.br - LordVader
*
* Autor :
* Data :
* Desc : Aplicao bsica para Console
*
*/

So linhas de comentrios. Comentrios so textos que o programador escreve para
explicar o que o arquivo de programao atual faz.
Observe que voc pode escrever o que voc quiser, o compilador no vai ler essas linhas
e elas vo ficar fora de seu arquivo .exe.
Comentrios so feitos usando:
// comentrio de uma linha
/*
comentrio de vrias
linhas
*/
Por enquanto no se preocupe com comentrios, vamos abordar o assunto mais tarde.
Deixe o seu programa como as linhas abaixo:

CDIGO...

#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
cout << "Imprimir na tela" << endl;
cout << "abcdefghijklmnopgqrstuvxyzw" << endl;
system("pause");
return 0;
}

FIM DE CDIGO...

Agora seu programa vai imprimir a mensagem na tela, e ele no vai se fechar at que
voc precise enter.
Parabns, esse o seu primeiro programa.

Oitavo Captulo
A linguagem C++
Acompanhando o cdigo do captulo passado, voc deve ter precebido que preciso
escrever bastante coisa para se mostrar um simples texto na tela.
Bom, a principio, isso o que o programa faz, mostra um simples texto. Porm, para
mostrar um simples texto, o processador precisa preparar vrias coisas antes, por isso
preciso todo aquele cdigo.
Vamos conhece-lo melhor:

CDIGO...

#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
cout << "Imprimir na tela" << endl;
cout << "abcdefghijklmnopgqrstuvxyzw" << endl;
system("pause");
return 0;
}

FIM DE CDIGO...

A primeira linha a de:
#include <iostream>
Essa linha diz para o compilador que voc quer incluir em seu programa a biblioteca
que est entre < >.
O nome da biblioteca que voc est incluindo no programa a iostream.
Se lembra que voc estudou os dispositivos de entrada e saida de dados do capitulo 5 ?
Pois ento, essa biblioteca iostream que ajuda seu programa a controlar aqueles
dispositivos. A biblioteca iostream envia informaes para o processador sobre como
mostrar as mensagens na tela.
O nome da biblioteca j diz, IO stream.
VOC PRECISA SABER...
IO quer dizer Input / Output ou entrada e sada de dados. E stream
que quer dizer fluxo de dados.


com essa biblioteca que voc vai conseguir mandar comandos para o processador
para imprimir na tela ou recuperar teclas digitadas no teclado.
Basicamente, essa biblioteca trata streams( fluxo de dados ) de entrada e sada.
O comando #include pode incluir vrios tipos de biblioteca no seu programa. Voc
pode por exemplo, incluir a biblioteca do Direct X para fazer grficos 3d por exemplo.
Exemplo demonstrativo:
#include <directx>
o segundo comando:
using namespace std;
um comando mais complexo de orientao a objetos.
Ele diz para o compilador que, voc quer usar o namespace std.
VOC PRECISA SABER...
Um namespace um conjunto de funes que faz parte de alguma
biblioteca que voc incluiu usando include.


Nessa caso, queremos usar o namespace std da biblioteca iostream.
Ok, queremos usar o namespace da std, e um namespace um conjunto de funes.
Mais o que uma funo????
Uma funo nada mais do que um conjunto de comandos simples, agrupados para
serem executados quando houver a chamada da funo.

Ento, se funo um conjunto de comandos, meu programa ou jogo tambm uma
funo ?
Seu programa parecido com uma funo! Seu programa como uma funo, que
executa vrios comandos.
Toda vez que voc clicar para executar, o compilador ir chamar seu programa que
executar funes, as funes iro executar uma ordem de comandos no processador.
- Observe que essa funo que estamos explicando diferente de
uma funo matemtica.

- Observe tambm que, seu programa parecido com uma funo,
que pode executar outras funes.

- Seu programa pode possuir infinitas funes, e essas funes
podem conter infinitos comandos.

Bom, no esquente a cabea com namespace e nem com funes, voc vai entender
melhor quando fizer voc mesmo.
Voc s precisa gravar:
Namespace um conjunto de funes e objetos
VOC PRECISA SABER...
Funes um conjunto de comandos.
Uma funo tem um nome, quando voc chama o nome da funo
no programa, todos os comandos que esto na funo sero
executados.


A extrutura de um programa em C++ feita a partir de funes.
Para saber qual funo executar primeiro, foi criada uma funo principal chamada
main.
VOC PRECISA SABER...
Main sempre a primeira funo de seu programa que ser
executada.


Por isso, a proxima linha:
int main(int argc, char *argv[])
a linha de inicio da funo main que a funo principal de cada programa.

Desta linha para baixo estaro todos os comandos que sero executados quando a
funo main for chamada.
A funo main comea com int. Esse primeiro parametro e todos os outros sero
estudados mais tarde.
Os parametros entre parenteses( (int argc, char *argv[]) ) tambm sero estudados mais
tarde.
Para o compilador saber qual os comandos pertencem as funes, foi especificado que
toda funo comea com { e termina com }
Ento os { } so os delimitadores da funo. No nosso exemplo, a funo main possui
os seguintes comandos:
cout << "Imprimir na tela" << endl;
cout << "abcdefghijklmnopgqrstuvxyzw" << endl;
system("pause");
return 0;

Exemplo de outras funes:
parametro somar( parametros )
{
..... // comandos
.....
}
parametro fazer( parametros )
{
..... // comandos
.....
}

parametro teste( parametros )
{
..... // comandos
.....
}

Observe que todo comando dentro de uma funo vem depois do {, e depois do ultimo
comando da funo tem um }.

Continuando com o cdigo do capitulo 7, o prximo comando o comando que
imprime na tela:
cout << "Imprimir na tela" << endl;
cout uma funo do namespace std.
Quando o compilador ler que voc est usando cout, ele executa todos os comandos da
funo cout.
Um deles seria, ler o que voc digitou e outro comando seria mostrar na tela o que voc
digitou entre "".
O comando
system("pause");
um do sistema windows que diz para o processador esperar para executar os proximos
comandos.
Esse comando system uma funo e provavelmente ele foi feito da seguinte forma:

parametro system( valor_que_o_usuario_vai_digitar )
{
... comandos para entender o que o usurio quer, no caso pause para pausar
... comandos para executar o que o usurio pediu, no caso para pausar, ento manda
o processador parar a execuo do programa
}
O ltimo comando return 0; voc tambm esturar mais tarde. Ele est ali para indicar
para o windows que tudo executou perfeitamente.

Nono Captulo
Fim do tutorial bsico
Bom, se voc chegou at aqui, parebns!!
Agora voc j sabe que no main vai o cdigo do seu jogo e est pronto para criar
programas em C++.
Daqui para frente abordaremos a linguagem C++ e voc vai aprender treinando.

Faa os exerccios!!!
impossvel aprender a fazer um jogo se voc no fizer os exerccios.
Siga sua linha de tempo, estude pouco por dia e domine o que voc estudou.
Pratique os exercicios e tente modifica-los para ter novas idias.
Iremos tambm mostrar programas para voc compilar.
Leia esses programas, ele iro ajudar voc a se familiarizar com cdigos em C++.
10 - Iniciando na rea de programao
Estou disposto a aprensentar neste site um tratamento completo ao leitor sobre
programao em c++.
A linguagem C++ foi desenvolvida por Bjarne Stroustrup e AT&T no nicio dos anos
80, e hoje a linguagem orientada mais tilizada no mundo.
Como guia, estarei usando o livro " C++ como programar "
LINK - C++: Como Programar - M.D. DEITEL & PAUL J. DEITEL
A histria (AGE OF C++)

Antigamente com a evoluo dos computadores, os cartoes foram trocados por
linguagem de mquina, sendo assim, os computadores s entendiam 0 e 1.
0 e 1 era a linguagem de mquina existente e por isso era muito complicado escrever
programas para um computador, sendo que cada computador tinha uma arquitetura
diferente e com isso os programas escritos em linguagem de mquina tinham que ser
reescritos de mquina para mquina.
Exemplo: 01010110101001010101 010101 01001010 100 10
Para amenizar isto, surgio a linguagem simblica, e estes eram escritos em programas
tradutores chamados ASSEMBLERS ( montadores ) que foram desenvolvidos para
converter simbolos para linguagem de mquina.
Exemplo:
load base
add valor
store recebe
Embora mais fceis de entender, ainda se tinha o problema de portabilidade em relao
a arquitetura. Foi ai que criaram as linguagens de alto nvel como o C.
Podemos fazer a operao acima em forma de alto nivel da seguinte maneira:
recebe = base + valor
C++ a evoluo do C que venho do BCPL ( B ). A linguagem B era usada para
desenvolver sistemas operacionais como o UNIX em 1970. E a linguagem C venho logo
em seguida em 1972. E ento C tomou o lugar de B para desenvolver o sistema
operacional UNIX.
Depois da decada de 70 o C foi muito modificado. E isso acaretava em problemas de
portabilidade. At que criaram o padro ANSI que o que veremos e que o mais
amplamente usado.
C++ a exteno do C e foi desenvolvido por Bjarne Stroustrup.
Alm das vrias modificaes, a principal se tornou a possibilidade de programao
Orientada a Objetos. Os programas orientados so mais fceis de entender, corrigir e
modificar.

VOC PRECISA SABER...
Lembro que C++ uma linguagem hibrida, possvel programar
orientado a objetos como tambm programar no estilo semelhante a
C, estruturado.
Os cdigos em C++ so caso sensitivo, ou seja, tudo que for
digitado em maiusculo diferente de tudo que for digitado em
minusculo

a diferente de A
b diferente de B
fazer diferente de Fazer




11 - Iniciando um novo programa
Crie um novo programa.
Digite no arquivo main.cpp as seguintes linhas:

CDIGO...

// Programa de impresso do hello world na tela
#include <iostream>
int main()
{
std::cout << "Hello World!";
return 0;
}

FIM DE CDIGO...

- No comeo sempre diga o que o programa ir fazer em forma de comentrio
Para conferir se est tudo ok, basta compilar. E depois voc pode executar (build).
A princpio parece difcil.. mas ainda no hehehe.
Comeamos escrevendo o que o programa ir fazer.

Em C++ as linhas de comentrios comeam com // ou ( e para varias linhas ) /* */.
Depois incluimos a biblioteca iostream.
Para incluir qualquer biblioteca basta usar o comando #include < nome da biblioteca >
Neste caso incluimos a iostream que possui as funes necessrias para mostrar texto na
tela. Ela tambm possu a funo para receber caracteres do teclado e funes de erros,
das quais veremos mais para frente.
Na prxima linha temos int main() {.
VOC PRECISA SABER...
int em C++ quer dizer inteiro. E main uma funo pois segue com
um ( ).

No C++ tudo que estiver em main( ) vai ser executado primeiro.
E o programa s funcionar se tiver uma funo main, ou
funo principal.

Quando voc aprender sobre funes, ir saber por que existe o int de inteiro na frente
do main.
Logo abaixo temos std::cout << "Hello World!"; , este o comando que imprime na
tela, por isso ele terminado com um ponto e virgula ( ; ).
std::cout o comando de impresso. Aqui estamos usando std de forma diferente, sem
usar o namespace por completo.
Observe que std um objeto de iostream e cout uma funo do objeto std.
Os :: o operador de escopo. Veremos isso mais para frente em c++ tambm.
Abaixo, como toda funo retorna algo. Est retornar o inteiro 0. E assim temos o fim
do programa.
Outro Exemplo:

CDIGO...

// Programa de impresso simples
#include <iostream>
int main()
{
std::cout << "Hello World!";
std::cout << " Este programa imprime 3 frazes ";
std::cout << " Die by Steel";
system("pause");

return 0;
}

FIM DE CDIGO...





12 - As variveis
At agora a gente aprendeu somente a escrever na tela. Antes de avanar voc precisa
saber de uma teoria importante.
Todas as linguagens de programao possuem variveis.
Uma varivel um espao para armazenar valores na memria.

Se lembra da memria RAM???
Para que voc entenda o que uma varivel, imagine o dinheiro no Couter Strike. Voc
vai ganhando dinheiro para comprar as armas. Durante o jogo
este dinheiro est guardado para que, no prximo round voc possa usar.
Esse dinheiro, ou melhor, esse valor nmerico fica gravado na memria,
mais especificamente na memoria RAM vista no capitulo 5.
Um outro exemplo de varivel a pontuao dos jogos. Nos jogos antigos sempre
existiam os records.
Esses records so valores salvos em variveis que ficam salvos na memria RAM.
A varivel o nome que voc d ao espao para armazenar a pontuao na memoria
RAM.
Ento, uma vriavel sempre possui um valor que pode ser variado.

No caso dos jogos, agora voc pode ter 100 pontos, aps matar um chefe voc pode ter
110 pontos.
Em Matemtica, varivel uma entidade capaz de manifestar diferenas em valor,
assumindo, inclusive, valores numricos. Diz-se que a varivel possui qualquer valor
dentro de um campo determinado.
Ns podemos armazenar na memoria RAM diversos tipos de
valores, e tambm podemos armazenar muitos valores.
Para tornar esse armazenamento organizado, foram criados as
variveis e seus tipos.

Toda varivel possui um tipo.
Um tipo pode ser do tipo Nmero ( 1, 2, 3, 4, 5 ... ) , Caracter( a, b, c, d, e, f ... ),
boleano ( Verdadeiro ou Falso ).
Ento:
Uma varivel pode guardar na memoria RAM um valor pertencente a um tipo pr-
definido.
Vamos ver um exemplo em cdigo C++

CDIGO...

#include <iostream>

int main()
{
int num;

system("pause");
return 0;
}

FIM DE CDIGO...

O cdigo acima no mostra mensagens na tela.
Aqui criamos uma varivel chamada num e ela do tipo int.
int quer dizer que podemos armazenar Nmeros inteiros nessa varivel.
Bom, esse num ainda est vazio. Ele ainda no guardou nada na memria.
Vamos armazenar um valor na memria.

CDIGO...

#include <iostream>

int main()
{
int num;

num = 10;

system("pause");
return 0;
}

FIM DE CDIGO...

Agora sim, nossa varivel num possui o valor 10, e 10 est guardado na memoria RAM
em uma posio que tem o nome num.

Imagine que num a pontuao de seu jogo e agora queremos mostra-lo na tela.

CDIGO...

#include <iostream>

int main()
{
int num;

num = 10;

std::cout << num << std::endl;

system("pause");
return 0;
}

FIM DE CDIGO...

Pronto.. Dizemos para o compilador que queremos imprimir o valor de num.
DICAS IMPORTANTES...
Observe que num diferente que "num"

Todo texto em C++ deve estar entre aspas "".


Como num uma varivel que tem um valor, a gente pode mudar seu valor.

CDIGO...

#include <iostream>

int main()
{
int num;

num = 10;

std::cout << num << std::endl;

num = 15;

std::cout << num << std::endl;

system("pause");
return 0;
}

FIM DE CDIGO...

Execute o comando acima e veja que agora ele imprime 10 e depois 15.
VOC PRECISA SABER...
Existem 2 tipos de variveis.

As variveis estticas que so espaos criados na memria pelo
processador antes do programa executar.
E variveis dinmicas que so espaos criados na memoria pelo
processador aps a execuo do programa.




Observe que existem vrios tipos de variveis.
Variveis so espaos na memria que podemos usar para diversas coisas.
Uma coisa interessante do C++ que em vrios compiladores ele no inicia a varivel
em branco, ou seja, o espao nunca vem em branco, vem sempre com alguma coisa.
Esse espao pode ser do tipo que guarda numeros inteiros, do tipo que guarda letras,
entre outros.

VOC PRECISA SABER...
Uma varivel sempre deve ser iniciada antes de ser utilizada em
C++.


Para iniciar uma varivel inteira por exemplo:
int numero;
Pronto, existe um espao na memria que grava numeros inteiros com o nome de
numero.
Podemos iniciar tambm uma varivel com ponto flutuante ( que armazena: 10.51,
164.456, 22,134 )
double numero2;
VOC PRECISA SABER...
Lembrando que no se deve iniciar variveis com nmeros na
frente da palavra, nem com linhas (-, _ ) ou caracteres invlidos.


DICAS IMPORTANTES...
Utilize nomes de variveis fceis de ler e de saber o que .
Utilize nomes de variveis em letras minsculas.


Podemos iniciar as variveis j com um valor. Para isto basta igualar ela a alguma coisa:
bool teste = false;
int variavel = 10;
Em C++ podemos tambm iniciar vrias variveis de uma vez s, separando com
virgulas.
int numero1 = 10,
numero2 = 20,
numero3 = 30; // encerrar sempre com ponto e virgula, seguir a identao.

13 - Variveis e aritmtica
Iremos trabalhar muito com as variveis do tipo int para que voc se acostume com a
linguagem.
Atravs de nosso programa podemos realizar contas matemticas. Aritmtica ser
utilizada por voc em vrios jogos.
Vamos conhecer o que podemos fazer em C++.

CDIGO...

// Exemplo de Adio

#include <iostream>

int main()
{
// memria que iremos usar
int num1;
int num2;

// iniciando a memria
num1 = 10;
num2 = 5;

// adio
num1 = num1 + num2;

std::cout << num1;

system("pause");
return 0;
}

FIM DE CDIGO...

O Programa acima soma duas variveis.
Na linha:
num1 = 10; a varivel num1 recebe e passa a armazenar o valor 10.

Le-se essa linha como num1 igual a 10
na linha de adio
num1 = num1 + num2;

Le-se que: num1 igual a num1 mais num2;
Ao executar o programa, o computador vai fazer a adio da seguinte forma
num1 = 10 + 5
Da mesma forma que usamos o +, podemos usar todos os outros operadores
matemticos que so:
+ Operador de Adio
- Operador de Subtrao
/ Operador de Diviso
* Operador de Multiplicao
% Operador de Mod ( pega o resto da diviso )
++ Incrementa 1
-- Decrementa 1
&& E logico ( and em pascal )
|| Ou lgico ( or em pascal )
< Menor
> Maior
<= Menor ou igual
>= Maior ou igual
?: Teste ( representa o if em uma condio)
= Atribuio
== Igualdade
!= Negao logico ( <> no pascal )

CDIGO...

#include <iostream>
using std::cout;
using std::endl;
#include <cmath> // biblioteca padro para operaes matemticas
int main()
{
int numero1 = 10,
numero2 = 10;

cout << numero1 + numero2 << endl; // 10
cout << numero1 - numero2 << endl; //0
cout << numero1 / numero2 << endl; //1
cout << numero1 * numero2 << endl; //100
cout << numero1 % numero2 << endl; //0 ( 10 / 10 = 1, resto = 0)
system("pause");

return 0;
}

FIM DE CDIGO...

Vamos nos familizar com o cdigo acima:
using std::cout; e using std::endl; praticamente a mesma coisa que usar o
namespace inteiro, s que aqui estamos dizendo ao compilador
que queremos usar apenas um comando do namespace std.

O comando endl da std::endl indica que voc quer pular de linha.
Nas linhas abaixo estamos executando uma adio, uma subtrao, uma diviso ( / ),
uma multiplicao ( * ) e recuperando o resto da diviso ( com modulo % )
VOC PRECISA SABER...
O operador % modulo retorna o resto da diviso

Observe que, como estamos apenas escrevendo na tela, nenhuma variavel guarda o
valor final das operaes.
ou seja:
numero1 + numero2

diferente disso
numero1 = numero1 + numero2
No segundo exemplo, numero 1 guarda a resposta da adio. No primeiro exemplo, a
resposta perdida.

VOC PRECISA SABER...
As operaes matemticas em C++ so iguais na matemtica, onde
se devem respeitar a ordem dos operadores.
Exemplo:
10 / 5 + 4
Primeiro C++ ir executar 10 / 5 como na matemtica, depois o
resultado de 10/5 com + 4.

Podemos tambm atribuir variveis de forma abreviada com esses operadores tornando
assim o programa ainda mais rpido.
Exemplos:
int numero;

numero += 10; // numero igual a numero mais 10
numero++; // numero mais 1 depois da execuo desta linha
numero *= 10; // numero igual a numero vezes 10
++numero; // numero mais 1 depois da leitura deste comando


Exerccios
Segue um exemplo mais completo de um programa de soma.
Compile este programa. Com a ajuda deste programa, tente resolver o exerccio abaixo.
Aconcelhamos a voc digitar o cdigo abaixo. As vezes d preguia e voltade de copiar
e colar. Mais digitando o cdigo ajuda a gravar o padro de
programao.

CDIGO...

// Esse programa imprime valores de resultados matemticos
#include <iostream>
using std::cout;
using std::endl;
int main()
{
cout << "Programa de Impresso" << endl;

// variveis podem ser criadas em qualquer parte de seu programa
int num1 = 0;
int num2 = 0;
int num3 = 0;
int resultado = 0;
num1 = 10;
cout << num1 << endl;
num2 = 1;

cout << num2 << endl;
num3 = num1 + num2;
cout << num3 << endl;
// soma mais 1 em num3
num3++;
cout << num3 << endl;
num3--;
cout << num3 << endl;
// isso quer dizer, num3 fica igual a ele mesmo + num1
num3 += num1;
cout << num3 << endl;
num3 -= num1;
cout << num3 << endl;
num3 *= num1;
cout << num3 << endl;
// sempre que um operador for executado primeiro,
// importante usar entre parenteses como na matemtica
num3 = ( num2 * num1 ) + num1;
cout << num3 << endl;
// isso quer dizer que,
// num3 fica igual a ele mesmo + a multiplicao de num1 * num1.
num3 += ( num1 * num1 );
cout << num3 << endl;

// nmeros podem ser usados livrementes
cout << 5 + 12 << endl;
cout << 5 + num3 << endl;
// s que eles so perdidos aps o processador completar a aritmtica

// aprenda sobre o mod, ou mdulo!!
cout << 5 % 2 << endl;
cout << 6 % 2 << endl;
cout << 7 % 2 << endl;
cout << 8 % 2 << endl;
cout << 9 % 2 << endl;
cout << 10 % 2 << endl;

// mod retorna o resto da diviso
// mod diferente de diviso
cout << 5 / 2 << endl;
cout << 6 / 2 << endl;
cout << 7 / 2 << endl;
cout << 8 / 2 << endl;
cout << 9 / 2 << endl;
cout << 10 / 2 << endl;
// observe os resultados abaixo
num3 = num1 + num1 * num3;
cout << num3 << endl;
num3 = ( num1 + num1 ) * num3;
cout << num3 << endl;

system("pause");
return 0;
}

FIM DE CDIGO...

Leia o cdigo, compile e teste todos os resultados. S assim voc vai entender como
funciona.
A Calc do windows ajuda. :)
Exercdios Propstos:
1 - Crie um programa com 5 variveis.
Inicie as variveis com nmeros.
Utilize 5 vezes os operadores de Soma, subtrao, multiplicao e diviso.
Mostre os resultados na tela.
Todas as variveis devem ser usadas nas operaes.

Resposta dos Exerccios
Segue resposta do exerccio do Captulo 13
O programa que voc digitou pode estar bem diferente do programa abaixo. Isso
normal, j que cada um pensa de uma forma diferente para se
fazer um programa.
Caso voc no tenha conseguido resolver o exerccio, leia o programa abaixo com
ateno. Tente execut-lo.

Exercdios Propstos:
1 - Crie um programa com 5 variveis.
Inicie as variveis com nmeros.
Utilize 5 vezes os operadores de Soma, subtrao, multiplicao e diviso.
Mostre os resultados na tela.
Todas as variveis devem ser usadas nas operaes.

CDIGO...

// Esse programa imprime valores de resultados matemticos
#include <iostream>
using std::cout;
using std::endl;
int main()
{
// variveis do mesmo tipo podem ser criadas da seguinte maneira:
int num1, num2, num3, num4, num5;
num1 = 1;
num2 = 5;
num3 = 10;
num4 = 15;
num5 = 30;
// 5 vezes com o operador de soma
cout << num1 + num2 + num3 + num4 + num5 << endl;
cout << num1 + num1 + num2 + num2 + num3 + num3 + num4 + num4 + num5 +
num5 << endl;
cout << num1 + ( num2 + num3 + num4 + num5 ) << endl;
cout << num1 + ( num2 + num3 ) + ( num4 + num5 ) << endl;
cout << num5 + num1 + num3 + num2 + num4 << endl;
// 5 vezes com o operador de subtrao
cout << num1 - num2 - num3 - num4 - num5 << endl;
cout << num1 - num1 - num2 - num2 - num3 - num3 - num4 - num4 - num5 - num5
<< endl;
cout << num1 - ( num2 - num3 - num4 - num5 ) << endl;
cout << num1 - ( num2 - num3 ) - ( num4 - num5 ) << endl;
cout << num5 - num1 - ( num3 - num2 - num4 ) << endl;
// 5 vezes com o operador de multiplicao
cout << num1 * num2 * num3 * num4 * num5 << endl;
cout << num1 * num1 * num2 * num2 * num3 * num3 * num4 * num4 * num5 *
num5 << endl;
cout << num1 * ( num2 * num3 * num4 * num5 ) << endl;
cout << num1 * ( num2 * num3 ) * ( num4 * num5 ) << endl;
cout << num5 * num1 * ( num3 * num2 * num4 ) << endl;
// 5 vezes com o operador de diviso
cout << num1 / num2 / num3 / num4 / num5 << endl;
cout << num1 / num1 / num2 / num2 / num3 / num3 / num4 / num4 / num5 / num5 <<
endl;
cout << num1 / ( num2 / num3 / num4 / num5 ) << endl;
cout << num1 / ( num2 / num3 ) / ( num4 / num5 ) << endl;
cout << num5 / num1 / ( num3 / num2 / num4 ) << endl;

system("pause");

return 0;
}


FIM DE CDIGO...

possvel que em seu programa e no meu, nas operaes de diviso de um erro. Esse
erro acontece por que no possivel dividir por 0.


14 - Condies
Ainda no conseguimos fazer um jogo.. Mais uma calculadora j possivel heheheh.
Bom, iremos agora aprender uma das coisas mais importantes na programao de jogos.
O tratamento de condies.
Uma condio uma forma de mostrar ao computador que, dependendo de um valor,
ele pode fazer uma coisa ou outra.
Traduzindo isso, ficaria algo como, dependendo do boto do joystick apertado, o
personagem deve fazer uma coisa ( pular ) ou outra ( atirar ).
O boto do joystick apertado a condio para que um teste seja feito.
Um teste em C++ feito com as Extruturas de Controle
Vamos conhece-las uma a uma. importante voc no pular este captulo sem aprender
este conceito.
A mais bsica a extrutura if.
Em C++ escrevemos uma estrutura if da seguinte maneira:
if ( ..condio.. )
{
..aoes..;
}
O if possui tambm uma subcondio seno ( else ) :

if ( ..condio.. )
{
.. aes ..;
}
else
{
..outras aoes ..;
}
ou at
if ( ..condio.. )
{
.. aes ..;
}
else if ( .. condio .. )
{
.. aes ..;
}
Lembrando que todos os blocos so sempre divididos com { }.
DICAS IMPORTANTES ...
Sempre utilize os { } para abrir e fechar um bloco de cdigo. No
seja preguioso.



CDIGO...

// Exemplo de if

#include <iostream>

int main()
{
// memria que iremos usar
int num1;
int num2;

// iniciando a memria
num1 = 10;
num2 = 5;

if ( num1 == num2 )
{
std::cout << num1 << " eh maior que " << num2;
}
else
{
std::cout << num1 << " No eh maior que " << num2;
}

system("pause");
return 0;
}

FIM DE CDIGO...

O programa acima demonstra um if bsico.
A condio nele a de testar se o valor de num1 que 10 igual ao valor de num2 que
5.

Se os valores fossem iguais, o primeiro bloco seria executado pelo compilador.
Como os nmeros no so iguais, o compulador ir ler o segundo bloco.
Esse tipo de extrutura se l da seguinte maneira:
Se num1 igual a num2 ento
{ Faa o seguinte cdigo }

Se no
{ Faa o seguinte cdigo }

Compile o cdigo e altere os valores para entender a extrutura.
Esse extrutura muito importante. E existem vrios tipos de testes que podem ser feitas
nela.
== Testa se um valor igual ao outro
> Testa se o valor da esquerda maior que o valor que est na direita
< Teste se um valor menor que
>= Testa se o valor maior ou igual
<= Teste se o valor menor ou igual
!= Teste se o valor diferente de ( em algumas linguagens se usa <> )
- Dentro de uma expresso de teste, podemos usar valores de variveis ou valores
digitados:
if ( a > 10 )
- Dentro de uma expresso de teste, podemos realizar contas matemticas:
if ( num == ( a + 10 ) )
Neste caso, primeiro a soma executada, e depois o teste realizado pelo computador
Uma outra coisa importante das extruturas de controle que elas no precisam
necessriamente testar apenas uma condio.
Elas podem testar vrias condies com a ajuda dos seguintes operadores
&& E logico ( and em pascal )
|| Ou lgico ( or em pascal )
Com o && podemos testar duas condies.
Se uma condio for verdadeira E outra condio tambm for verdadeira.

CDIGO...

// Exemplo de &&

#include <iostream>

int main()
{
// memria que iremos usar
int num1;
int num2;

// iniciando a memria
num1 = 10;
num2 = 10;

if ( num1 == num2 && num2 == 10 )
{
std::cout << num1 << " eh maior que " << num2 << " - E num2 igual a 10";
}
else
{
std::cout << num1 << " No eh maior que " << num2;
}

system("pause");
return 0;
}

FIM DE CDIGO...

O teste acima se l da seguinte forma:
se ( num1 for igual a num2 E num2 for igual a 10 ) ento { faa o que tem nesse bloco }
se no { faa o que tem nesse bloco }
VOC PRECISA SABER...
Primeiro o compilador testa a condio 1 que a num1 == num2

- Se a condio 1 for verdadeira, o compilador vai ento testar a
condio 2 que num2 == 10

- Se a condio 2 tambm for verdadeira o primeiro bloco ser
executado.

- Se nenhuma das condies forem verdadeira o segundo bloco ser
executado.

- Se apenas uma das condies forem verdadeira o segundo bloco
ser executado ( isso por que uma das condies falsa )

Voc precisa entender com clareza o que foi escrito acima! Para isso, s testando e
escrevendo cdigos.
Veja o teste a seguir:

CDIGO...

// Exemplo avanado de &&

#include <iostream>

int main()
{
// memria que iremos usar
int num1;
int num2;
int num3;

// iniciando a memria
num1 = 10;
num2 = 10;
num3 = 5;

if ( num1 == num2 && num2 == 10 )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}

// a primeira verdade, mais a segunda no
if ( num1 == num2 && num2 == num3 )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}

// nenhuma verdadeira
if ( num1 == num3 && num2 == num3 )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}

// a primeira no verdadeira
if ( num1 == num3 && num2 == ( num3 + num3 ) )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}


system("pause");
return 0;
}

FIM DE CDIGO...

O ato de testar duas ou mais condies ( sim, voc pode usar quantos && quiser )
muito importante e voc precisa dominar isso.
Imagine a seguinte situao. Voc quer testar se o personagem pode usar uma arma,
mais ele s pode usar se tiver tiros.
O teste seria mais ou menos:
if ( botao_pulo == true && quantidade_tiros > 0 )
se ( O boto de pulo foi apertado E a quantidade de tiros for maior que 0 ) ento { ...
atira ... } seno { No atira }


15 - Condies com OU ( || )
Com o || ( OU lgico ) podemos testar duas condies tambm, porm a forma de teste
muda um pouco.
Ele funciona da seguinte forma Se uma condio for verdadeira OU outra condio
tambm for verdadeira.

CDIGO...

// Exemplo de ||

#include <iostream>

int main()
{
// memria que iremos usar
int num1;
int num2;

// iniciando a memria
num1 = 10;
num2 = 10;

if ( num1 == num2 || num2 == 10 )
{
std::cout << num1 << " eh maior que " << num2 << " - OU num2 igual a 10";
}
else
{
std::cout << num1 << " No eh maior que " << num2;
}

system("pause");
return 0;
}

FIM DE CDIGO...

O teste acima se l da seguinte forma:
se ( num1 for igual a num2 OU num2 for igual a 10 ) ento { faa o que tem nesse bloco
} se no { faa o que tem nesse bloco }
VOC PRECISA SABER...
Primeiro o compilador testa a condio 1 que a num1 == num2

- Se a condio 1 for verdadeira, o primeiro bloco j ser executado

- Se a condio 2 tambm for verdadeira o primeiro bloco ser
executado.

- Se nenhuma das condies forem verdadeira o segundo bloco ser
executado.

- Se apenas uma das condies forem verdadeira o primeiro
bloco que ser executado ( isso por que uma das condies falsa,
mais estamos testando uma ou outra )

Grave isso!
Veja o teste a seguir:

CDIGO...

// Exemplo avanado de ||

#include <iostream>

int main()
{
// memria que iremos usar
int num1;
int num2;
int num3;

// iniciando a memria
num1 = 10;
num2 = 10;
num3 = 5;

if ( num1 == num2 || num2 == 10 )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}

// a primeira verdade, mais a segunda no
if ( num1 == num2 || num2 == num3 )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}

// nenhuma verdadeira
if ( num1 == num3 || num2 == num3 )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}

// a primeira no verdadeira
if ( num1 == num3 || num2 == ( num3 + num3 ) )
{
std::cout << "As duas condicoes sao verdadeiras " << std::endl;
}


system("pause");
return 0;
}

FIM DE CDIGO...

Voc vai precisar saber usar o OU quando voc quiser que seu personagem faa tal
coisa, mais para fazer tal coisa ele precisa de 1 item mgico ou 1 item simples. Nesta
hora voc vai usar um OU por exemplo.

O teste seria mais ou menos:
if ( botao_pulo == true && ( item_magico > 0 || item_simples > 0 ) )
se ( O boto de pulo foi apertado E ( o a quantidade de item_magico for maior que 0
OU a quantidade de item simples for maior que zero) ) ento { ... atira ... } seno { No
atira }

Observe que neste exemplo acima eu cito 3 condies em 1 nica extrutura de controle.
E nesta mesma usamos os tipos E ( && ) e OU ( || )
Como na matemtica, as condies OU que esto entre parenteses que sero
executadas primeiro.

AGORA, hora de treinar meu amigo.
J est quase na hora de fazer seu primeiro jogo de computador! E j estamos perto de
trabalhar com grficos!!
Parabns por ter chegado at aqui.


Exerccios
1 - Crie um programa com 2 variveis.
Inicie as variveis com nmeros.
Faa um teste para saber qual das duas tem o maior nmero.
Mostre os resultados na tela.
2 - Crie um programa com 3 variveis.
Inicie as com nmeros.
Faa diversos testes para saber qual delas a maior.
Para isso, crie uma outra varivel que vai guardar sempre o valor da maior.
Assim voc sempre testa ela com uma das 3.
Mostre na tela qual a maior das 3.


Resposta dos Exerccios
Segue resposta do exerccio do Captulo 15
O programa que voc digitou pode estar bem diferente do programa abaixo. Isso
normal, j que cada um pensa de uma forma diferente para se
fazer um programa.
Caso voc no tenha conseguido resolver o exerccio, leia o programa abaixo com
ateno. Tente execut-lo.

Exercdios Propstos:
1 - Crie um programa com 2 variveis.
Inicie as variveis com nmeros.
Faa um teste para saber qual das duas tem o maior nmero.
Mostre os resultados na tela.

CDIGO...

#include <iostream>
using std::cout;
using std::endl;
int main()
{
int num1 = 5;
int num2 = 10;

if ( num1 > num2 )
{
cout << "Num1 maior que Num2" << endl;
}
else
{
cout << "Num2 maior que Num1" << endl;
}
system("pause");
return 0;
}

FIM DE CDIGO...


2 - Crie um programa com 3 variveis.
Inicie as com nmeros.
Faa diversos testes para saber qual delas a maior.
Para isso, crie uma outra varivel que vai guardar sempre o valor da maior.
Assim voc sempre testa ela com uma das 3.
Mostre na tela qual a maior das 3.

CDIGO...

#include <iostream>
using std::cout;
using std::endl;
int main()
{
int num1 = 55;
int num2 = 50;
int num3 = 30;

// varivel auxiliar
int auxiliar = 0;


auxiliar = num1;

// testamos a 1 com a 2
if ( auxiliar > num2 )
{
// testamos a 1 com a 3
if ( auxiliar > num3 )
{
cout << "Num1 maior que Num2 e Num3" << endl;
}
else
{
cout << "Num3 maior que Num1 e Num2" << endl;
}
}
else
{
// atribui num2 para auxiliar
auxiliar = num2;

if ( auxiliar > num3 )
{
cout << "Num2 maior que Num1 e Num3" << endl;
}
else
{
cout << "Num3 maior que Num1 e Num2" << endl;
}
}
system("pause");
return 0;
}

FIM DE CDIGO...

O uso de uma varivel auxiliar ajuda a desenvolver uma lgica melhor para o programa.
Abuse a vontade de testes de if e variveis auxiliares.
Sempre use a identao correta.
Se voc no conseguiu fazer o ltimo exerccio. Tente alterar o cdigo acima para testar
4 variveis.
Depois tente reescrever todo o cdigo.



16 - Estruturas de repetio
Agora iremos aprender um assunto que muito usado durante o desenvolvimento de um
jogo.
Uma estrutura de repetio permite ao programador especificar que uma ao deve ser
repetida enquanto alguma condio for verdadeira.

Exemplo:
Enquanto existir itens na minha lista de compras
Compra prximo item e Exclu-lo da minha lista.

O exemplo acima mostra que enquanto existir um item na minha lista de compras o
programa vai executar a funo compra mais itens e a funo excluir da minha lista.

Somente aps no existir mais itens em minha lista a condio se torna falsa e a
estrutura desfeita.

Dessa forma podemos dar um exemplo de um loop principal de um jogo:
Enquanto no for pressionado ESC
Executa movimentos, animaes, controle de perifricos, tratamento de mensagens...

Dessa forma fica fcil de perceber a importncia da estrutura de repetio dentro de um
jogo.
Ao total temos 3 tipos de estruturas de repetio.

Em C++ so eles:
while () {}
do while () {}
for () {}

WHILE (){}
O comando while precedido de uma condio para que o looping acontea.
Traduzindo ao p da letra while significa Enquanto.


CDIGO...

// Exemplo de while
#include <iostream>
using namespace std;
int main()
{
int iNumero = 0;

while ( iNumero != 9 )
{
cout << "Digite um numero.: ";
cin >> iNumero;
}

cout << "PROGRAMA FINALIZADO" << endl;
system("pause");
return 0;
}

FIM DE CDIGO...

Se voc executar o cdigo acima ir perceber que enquanto o usurio digitar nmeros
diferentes de nove o programa continua escrevendo a mensagem Digite um numero.: .
Assim que o 9 for digitador o programa escreve a mensagem PROGRAMA
FINALIZADO e pausa o resultado para o usurio analisar.

DO WHILE (){}
O comando do while precedido do cdigo em seguida de uma condio para que o
looping acontea.

Basicamente o cdigo abaixo tem a mesma funo que o anterior s que ao invs de
declarar a condio no topo da estrutura ela declarada no final da estrutura.
O comando do while no muito utilizado, mais facil usar o while comum.

CDIGO...

#include <iostream>
using namespace std;
int main()
{
int iNumero = 0;

do
{
cout << "Digite um numero.: ";
cin >> iNumero;
} while ( iNumero != 9 );
cout << "PROGRAMA FINALIZADO" << endl;

system("pause");
return 0;
}

FIM DE CDIGO...

O resultado do cdigo acima semelhante ao resultado do cdigo escrito com a
estrutura while.

A estrutura de repetio do/while semelhante estrutura while.
Na estrutura while a condio de continuao do lao testada no principio do lao
antes do corpo do lao ser executado.

A estrutura do/while testa a condio de continuao do lao depois do corpo do lao a
ser executado; assim, o corpo do lao ser executado pelo menos uma vez. Note que no
necessrio usar chaves no comando do/while, mas ns usamos para uma melhor
visualizao do cdigo e para evitar confuso com o comando while.


FOR () {}
O comando for um contador, ele precedido de uma expresso.
Para determinar essa expresso precisamos prestar ateno para os seguintes itens:
1. O nome de uma varivel de controle do contador
2. O valor inicial da varivel
3. A condio que testa a condio final da varivel
4. O incremento ou decremento pelo qual a varivel de controle modificada a
cada execuo do lao.
Nessa estrutura o lao controlado por um contador. Ou seja, nos dois exemplos acima
ns dependamos de uma interveno do usurio ou de algum resultado para tornar no a
condio do lao satisfatria. Agora, nosso lao ter, inicio, meio e fim que ns iremos
pr-determinar.

CDIGO...

#include <iostream>
using namespace std;
int main()
{
int i = 0;

for ( i=0; i<10; i++ )
{
cout << "Contador.: " << i << endl;
}

cout << endl;
for ( i=9; i>=0; i-- )
{
cout << "Contador.: " << i << endl;
}
cout << "PROGRAMA FINALIZADO" << endl;
system("pause");

return 0;
}

FIM DE CDIGO...

No exemplo acima declaramos a varivel i como sendo nosso contador.

Ao declarar a estrutura for na primeira vez iniciamos o contador com 0, testamos se ele
menor que 10, em seguida incrementamos a varivel. Dessa forma o programa acima
ir escrever os nmeros de 0 a 9 na tela. No segundo comando for fizemos o contador
mostrar o nmero em ordem decrescente.

Comando break
O comando break altera o fluxo de controle da estrutura de repetio. Dessa forma,
podemos parar a execuo do lao de imediato assim que uma condio for satisfatria.
A execuo do programa continua com o primeiro comando depois da estrutura.

CDIGO...

#include <iostream>
using namespace std;
int main()
{
int x = 0;
for ( x=0; x<10; x++ )
{
if (x == 5 )
{
break;
}

cout << "Valor de X.: " << x << endl;
}
cout << "A estrutura saiu do laco com x igual a " << x << endl;
system("pause");

return 0;

}

FIM DE CDIGO...

Note que sem usarmos o comando break a estrutura deveria imprimir na tela uma
numerao de 0 a 9. No entanto, inclumos uma estrutura de seleo if para sair do lao
assim que o valor de x for igual a 5.

Dessa forma, todos os comandos dentro da estrutura de repetio aps o break so
ignorados e o prximo comando a ser executado passa a ser o primeiro comando aps o
lao for, nesse caso, a mensagem que mostra o valor de x aps a sada do lao.

Comando continue
O comando continue quando executado numa estrutura de repetio tambm altera o
fluxo de controle. Dessa forma, salta os comandos restantes no corpo dessa estrutura e
prossegue com a prxima repetio do lao. Diferente do comando break que sai da
estrutura, a execuo do programa com o comando continue continua com o primeiro
comando dentro da estrutura de repetio.


CDIGO...

#include <iostream>
using namespace std;
int main()
{
int x = 0;

for ( x=0; x<10; x++ )
{
if ( x == 5 )
{
continue;
}

cout << "Valor de X.: " << x << endl;
}
cout << "A estrutura saiu do laco com x igual a " << x << endl;
system("pause");

return 0;
}

FIM DE CDIGO...

O cdigo acima dever imprimir na tela nmeros de 0 a 9 com exceo do numero 5.

Esse exemplo utiliza o mesmo cdigo que o primeiro exemplo com o comando break.

S que ao invs de sair do lao quando o valor de x igual a 5 o programa pula a
impresso do numero 5 na tela e continua imprimindo os outros valores. Dessa forma
temos todos os nmeros de 0 a 9 na tela com exceo do nmero 5.


Exerccios
1 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio while e a varivel, imprima de 1 a 10 na tela.
Quando sair do while, imprima a string "fim do programa".
2 - Crie um programa com 2 variveis.
Inicie as com nmeros.
Usando o comando de repetio while, imprima de 1 a 10 e de 10 a 1 na tela
sucessivamente.
Quando sair do while, imprima a string "fim do programa".
3 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio while e a varivel, imprima de 1 a 2999 na tela.
Quando sair do while, imprima a string "fim do programa".
4 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio for e a varivel, imprima de 1 a 2999 na tela.
Quando sair do for, imprima a string "fim do programa".
5 - Crie um programa com 2 variveis.
Inicie as com nmeros.
Usando o comando de repetio for, imprima de 1 a 10 e de 10 a 1 na tela
sucessivamente.
Quando sair do for, imprima a string "fim do programa".
6 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio for e a varivel, imprima de 2 a 50 na tela, imprima
apenas os nmeros pares ( pulando de 2 em 2 ).
Quando sair do for, imprima a string "fim do programa".



Resposta dos Exerccios
Segue resposta do exerccio do Captulo 16
O programa que voc digitou pode estar bem diferente do programa abaixo. Isso
normal, j que cada um pensa de uma forma diferente para se
fazer um programa.
Caso voc no tenha conseguido resolver o exerccio, leia o programa abaixo com
ateno. Tente execut-lo.

Exercdios Propstos:
1 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio while e a varivel, imprima de 1 a 10 na tela.
Quando sair do while, imprima a string "fim do programa".

CDIGO...

#include <iostream>

int main()
{
int num = 1;

// enquanto num for menor ou igual a 10
while ( num <= 10 )
{
std::cout << num << std::endl;

// num = num + 1;
num++;
}

std::cout << "fim do programa" << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...


2 - Crie um programa com 2 variveis.
Inicie as com nmeros.
Usando o comando de repetio while, imprima de 1 a 10 e de 10 a 1 na tela
sucessivamente.
Quando sair do while, imprima a string "fim do programa".

CDIGO...

#include <iostream>

int main()
{
int num1 = 1;
int num2 = 10;

// enquanto num for menor ou igual a 10
while ( num1 <= 10 )
{
//std::cout << num1 << std::endl;
//std::cout << num2 << std::endl;

// pode ser assim tbm
std::cout << num1 << "\t" << num2 << std::endl;

// num = num + 1;
num1++;
num2--;
}

std::cout << "fim do programa" << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...


3 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio while e a varivel, imprima de 1 a 2999 na tela.
Quando sair do while, imprima a string "fim do programa".

CDIGO...

// Este programa apenas para ilustrar como o processador rapido.
// No tenha medo de usar valores altos em seus programas
#include <iostream>

int main()
{
int num1 = 1;


// enquanto num for menor ou igual a 2999
while ( num1 <= 2999 )
{
std::cout << num1 << std::endl;

num1++;
}

std::cout << "fim do programa" << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...


4 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio for e a varivel, imprima de 1 a 2999 na tela.
Quando sair do for, imprima a string "fim do programa".

CDIGO...

#include <iostream>

int main()
{
int num1 = 1;

for ( num1=1; num1 <= 2999; num1++ )
{
std::cout << num1 << std::endl;
}

std::cout << "fim do programa" << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...

5 - Crie um programa com 2 variveis.
Inicie as com nmeros.
Usando o comando de repetio for, imprima de 1 a 10 e de 10 a 1 na tela
sucessivamente.
Quando sair do for, imprima a string "fim do programa".

CDIGO...

#include <iostream>

int main()
{
int num1 = 1;
int num2 = 10;

for ( num1=1; num1 <= 10; num1++ )
{
//std::cout << num1 << std::endl;
//std::cout << num2 << std::endl;

std::cout << num1 << "\t " << num2 << std::endl;

// num2 = num2 - 1
num2--;
}

std::cout << "fim do programa" << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...

6 - Crie um programa com 1 varivel inteira.
Inicie a varivel com 1.
Usando o comando de repetio for e a varivel, imprima de 2 a 50 na tela, imprima
apenas os nmeros pares ( pulando de 2 em 2 ).
Quando sair do for, imprima a string "fim do programa".

CDIGO...

#include <iostream>

int main()
{
int num1 = 2;


for ( num1=2; num1 <= 50; num1++ )
{
std::cout << num1 << std::endl;

// incrementa + 1, na primeira passada num1 = 3
num1++;

// ao voltar para o for, num1 = 4
}

std::cout << "fim do programa" << std::endl;


std::cout << "Outra forma de resolver" << std::endl;


// operadores +=, -= e *= tambm podem ser utilizados
// cuidado com a complexibilidade
for ( num1=2; num1 <= 50; num1 += 2 )
{
std::cout << num1 << std::endl;
}

std::cout << "fim do programa" << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...

Resolver os exerccios muito importante, para treinar sua lgica de programo.
Tente inventar novos exerccios e exercitas os comandos.



17 - Criando Funes
Ns iremos falar agora, cada vez mais assuntos abordando programao de jogos
diretamente.
importante conhecer o bsico sobre programao, lendo os capitulos anteriores para
no se perder durante os estudos.

Entender e resolver os exerccios ajuda a compreender como programar melhor um
jogo.
Todo jogo clssico possui comandos bsicos.
Por exemplo, no Super Mario podemos fazer o Mario sair pulando. Sempre que o boto
de pulo precionado, ele vai pular.

Para fazer o Mario pular, os programadores programaram uma sequncia de cdigos.
Geralmente essa sequencia de cdigos conhecida como uma funo.
DICAS IMPORTANTES...
- Uma funo um conjunto de cdigo separado do programa
principal, que executa varias operaes especiais no programa.
- Esse conjunto de cdigo pode ser chamado pelo programa
principal infinitamente
Desta forma, no perdemos tempo escrevendo como o Mario pula
mais de uma vez em um mesmo programa, o que ajuda na
produtividade ao se contruir um jogo.

Definio de Funes
Cada programa em C++ apresenta uma funo denominada main, que a funo
principal, dentro dela podemos chamar vrias outras funes.. e agora veremos como
criar nossas proprias funes.
Para criar uma funo em C++ devemos seguir os seguintes padres:
1 tipo de valor de retorno ( lembrando que uma funo pode retornar algo )
2 nome da funo
3 lista de argumentos
4 declarao de comandos
ou
tipo de valor de retorno nome da funo (lista de argumentos)
{
declarao
}
Como C++ uma lingaguem muito rica, alguns parametros foram adotados para que o
programa fique mais rpido.
Uma delas o Prototipo da funo.
VOC PRECISA SABER...
Toda funo de biblioteca padro possui um prototipo de funo, e
assim sendo, para seguir uma boa engenharia de softwere, seria
interessante que cada funo nossa tambm tive-se seu prototipo.
Toda funo composta por um prototipo e seu retorno .. ( no
obrigatorio o uso de prototipo )


Vamos declarar uma funo que vai somar 2 valores
int soma( int, int) ; // prototipo da funo... diz ao compilador que a funo soma vai
retornar um int e receber dois argumentos int
int soma( int valor1, int valor2)
{
return valor1 + valor2
}
Quando quisermos que uma funo no retorne nada ou no receba nada, usamos
o tipo Void.
void mensagem ( void ) // prototipo de mensagem, nao retorna nada, nao recebe nada
void mensagem ( void )
{
cout << "MENSAGEM";
}
De incio parece chato ficar escrevendo o prototipo. Mas o prototipo de funo um
dos recursos mais importantes de C++. Um prototipo diz ao compilador o nome da
funo, o tipo dos dados retornados, o nmero de parametros que a funo espera
receceber e a ordem na qual estas sero recebidas.

Com o prototipo a funo avaliada. E com ele podemos escrever a funo aonde
quisermos, pois ela sempre tem que estar criada antes de ser usada. Veremos mais tarde
exemplos que sero obrigatorios o uso de prototipos, por isso espero que voc se
acostume a usa-los.
Exemplo com ajuda de Prototipo:

CDIGO...

// Programa com funes e seus prototipos
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include <cmath>
int quadrado (int); // prototipo da funcao quadrado
int cubo (int); // prototipo da funcao cubo
void msg (void);

int main()
{
int numero = 2;
double num = -2.5;
cout << "O quadrado de "
<< numero
<< " e "
<< quadrado(numero)
<< endl;
cout << "O cubo de "
<< numero
<< " e "
<< cubo(numero)
<< endl;
// outras funcoes padroes
cout << fabs(num) << endl;
cout << pow( numero, 4) << endl;
cout << sqrt( numero ) << endl; // raiz quadrada

msg();

cin;
return 0;
}
// com prototipos podemos iniciar as funes depois
int quadrado ( int valor )
{
valor *= valor;
return valor;
}
int cubo ( int valor )
{
valor *= valor * valor;
return valor;
}
void msg ()
{
cout << "VOID no retorna"
<< endl;
}

FIM DE CDIGO...


Funes em C++ um assunto bastante complexo, C++ possui vrias formas e
maneiras de se trabalhar com funes criadas pelo usurio, o que faz dessa
linguagem muito potnte. De incio vamos ver algumas funes das bibliotecas
padres.
Funes da biblioteca <cmath>
cos (x) coseno de x
exp(x) funo exponencial
fabs(x) valor absoluto ( tira o - )
fmod (x, y ) mode de numero ponto flutuante x/y
log ( x ) logaritmo natural de x
pow( x, y ) x elevado a potncia de y
sin ( x ) seno de x
sqrt( x) raix quadrada
tan(x) tangente de x




18 - Usando Funes
Vamos exercitar o uso de funes.
Entender como elas funcionam vai ser crucial para a criao de um jogo.
Primeiro, voc precisa ter em mente sempre:
- Voc pode criar quantas funes voc quiser.
- Voc pode criar quantas variveis voc quiser.
- Dentro das funes voc pode criar quantos if ou extruturas de
repetio quiser ( while, for )
- Toda varivel criada dentro da funo s percente a ela mesma. Ela
no pode ser utilizada pelo programa.
- Cuidado para no chamar a funo dentro dela mesma, isso pode
causar loop infinito no programa.

Programas exemplos:
O exemplo abaixo mostra que uma variavel criada em main diferente de uma varivel
criada em uma funo.

CDIGO...

#include <iostream>

void imprime();

int main()
{
int numero;

numero = 10;

std::cout << numero << std::endl;

// chamando a funo
imprime();


system("pause");
}

void imprime()
{
int numero;

numero = 20;

std::cout << numero << std::endl;
}

FIM DE CDIGO...


O Programa abaixo mostra que uma varivel do main pode ser acessada pela funo,
passando ela por parametro.
Ainda assim, a variavel da funo diferente da do main. E cuidado com nomes
repetidos.

CDIGO...

#include <iostream>

void imprime( int );

int main()
{
int numero;

numero = 10;

std::cout << numero << std::endl;

// chamando a funo
imprime( numero );


system("pause");

return 0;
}

void imprime( int vnumero )
{
int numero;
numero = 20;


std::cout << numero << std::endl;
std::cout << vnumero << std::endl;
}

FIM DE CDIGO...




O exemplo a seguir mostra como enviar vrios valores para uma mesma funo.

CDIGO...

#include <iostream>

void imprime( int, int );

int main()
{
int numero1;
int numero2;

numero1 = 10;
numero2 = 50;


std::cout << numero1 << "\t" << numero2 << std::endl;

// chamando a funo
imprime( numero1, numero2 );


system("pause");

return 0;
}

void imprime( int vnumero1, int vnumero2 )
{
int numero;
numero = 20;


std::cout << numero << std::endl;
std::cout << vnumero1 << std::endl;
std::cout << vnumero2 << std::endl;
}

FIM DE CDIGO...



O programa de exemplo abaixo mostra que voc pode ter infinitas extruturas dentro das
funes.

CDIGO...

#include <iostream>

void imprime();

int main()
{

imprime();


system("pause");

return 0;
}

void imprime()
{
int numero1 = 0;
int numero2 = 0;

for ( numero1=10; numero1<999; numero1++ )
{
if ( numero1 == 500 )
{
while ( numero2 < 100 )
{
std::cout << numero2 << std::endl;
numero2++;
}
}

std::cout << numero1 << std::endl;
}


}

FIM DE CDIGO...


O exemplo abaixo mostra que uma funo pode chamar outra funo.

Pense nisso como, quando o Mario pula, ele tambm pode atirar fogo com o poder da
flor. ( funo de pulo chamando a funo de atirar fogo durante o pulo "ESSE exemplo
meramente ilustrativo, iremos ver isso na prtica de outra forma") .

CDIGO...

#include <iostream>

void imprime1();
void imprime2();

int main()
{

imprime1();

system("pause");

return 0;
}

void imprime1()
{
imprime2();

std::cout << "Funo 1" << std::endl;
}

void imprime2()
{
std::cout << "Funo 2" << std::endl;
}


FIM DE CDIGO...


Exemplo de utilizao de um retorno de uma funo

CDIGO...

#include <iostream>

int valor();

int main()
{
int numero = 0;
numero = 10;

numero = numero + 5 + valor();

std::cout << numero << std::endl;

system("pause");

return 0;
}

int valor()
{
int valor = 0;
valor = 10;

return valor;
}

FIM DE CDIGO...

Exerccio pratco
Usando tudo o que voc aprendeu at agora, resolva o seguinte problema de lgica:
- Crie 4 variveis que sero 2 notas para 1 aluno e 2 notas para outro aluno.
Crie 2 funes, uma para tirar a mdia de cada aluno e outra para ver qual o aluno que
tirou a maior mdia.
- Utilizando uma funo, crie um programa que cria graficos com letras.
Uma varivel deve informar o tamanho do grfico e um grfico deve ser gerado pela
funo.
Exemplo:
5 - #####
10 - ##########


Resposta dos Exerccios
Segue resposta do exerccio do Captulo 18
O programa que voc digitou pode estar bem diferente do programa abaixo. Isso
normal, j que cada um pensa de uma forma diferente para se
fazer um programa.
Caso voc no tenha conseguido resolver o exerccio, leia o programa abaixo com
ateno. Tente execut-lo.

Exercdios Propstos:
- Crie 4 variveis que sero 2 notas para 1 aluno e 2 notas para outro aluno.
Crie 2 funes, uma para tirar a mdia de cada aluno e outra para ver qual o aluno que
tirou a maior mdia.

CDIGO...

#include <iostream>

int media( int, int );

void maior_media( int, int );

int main()
{

int n1, n2; // aluno1
int v1, v2; // aluno2

n1 = 10;
n2 = 9;

v1 = 5;
v2 = 6;

int media1 = 0;
int media2 = 0;

media1 = media( n1, n2 );

std::cout << "Media do aluno1: " << media1 << std::endl;

// reutilizao da funo
media2 = media( v1, v2 );

std::cout << "Media do aluno2: " << media2 << std::endl;

maior_media( media1, media2 );



return 0;
}

int media( int nota1, int nota2 )
{
// use parenteses como na matemtica
return ( nota1 + nota2 ) / 2;
}

void maior_media( int aluno1, int aluno2 )
{
if ( aluno1 > aluno2 )
{
std::cout << "Aluno 1 tirou maior media que aluno2 " << std::endl;
}
else
{
if ( aluno2 > aluno1 )
{
std::cout << "Aluno 2 tirou maior media que aluno1 " << std::endl;
}
else
{
// caso as medias sejem iguai!!
std::cout << "Aluno 1 tirou a mesma media que o aluno2 " << std::endl;
}
}
}

FIM DE CDIGO...


2 - Utilizando uma funo, crie um programa que cria graficos com letras.
Uma varivel deve informar o tamanho do grfico e um grfico deve ser gerado pela
funo.
Exemplo:
5 - #####
10 - ##########

CDIGO...

#include <iostream>

void grafico( int );


int main()
{

int valor = 0;

valor = 38;
grafico( valor );

valor = 3;
grafico( valor );

valor = 15;
grafico( valor );

system("pause");

return 0;
}

void grafico( int total )
{
int i = 0;

for ( i=1; i<=total; i++ )
{
std::cout << "#";
}

std::cout << "\n";
}

FIM DE CDIGO...




19 - Array
O array uma das operaes em programao de jogos muito importante.
Um array uma variavel comum que pode armazenar mais de um valor porm esse
valor precisa ser sempre do mesmo tipo.
Um Array um grupo de posies de memoria consecutivas, todas de mesmo nome e
mesmo tipo. Para fazer referncia a uma posio particular de um array, especificamos
o nome do array e o nmero da posio daquele elemento no array.
Vamos criar um array de nome nmeros com 12 elementos.
O primeiro elemento referenciado como numeros[0] e o ultimo como numeros[11].
Assim podemos ter vrios valores em uma array e acessar esse valor atravez de um
indice que chadado de subscrito.
c[0] = 10
c[1] = 02
c[2] = 25
.
.
c[11] = 01
Um subscrito pode ser uma operao inteira. Por exemplo, se a = 5 e b = 6 o comando:
c[ a + b] += 2;
adiciona 2 ao elemento de array c[11].
e para imprimir um valor de uma posio de uma array:
cout << c[0] << endl;
ou seja, cada subscrito de uma array recebe um valor e esse valor interage em seu
programa como se fosse uma variavel simples.
Operao matemtica
c = numero[11] / 2
Uma array pode ser Iniciamos da seguinte forma
tipo nome[quantidade de elementos] = { valor dos elementos separado por virgurla };
int teste[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
ou apenas
int teste[10];
bool teste[2]
char teste[3]

CDIGO...

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
int numeros[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; // array de 10 elementos
inta=2, b=4;
cout << numeros[1] << endl;
cout << numeros[2] + 3 << endl;
cout << numeros[a + b] << endl;
cout << ++numeros[4] << endl;
cin;
return 0;
}

FIM DE CDIGO...


Observe que o valor 10 est no elemento numeros[0]
observe que numeros[a + b] igual a numeros[6]
observe que ++numeros[4] incrementa o valor de 6


Arrays Multidimensionais
Os arrays em C++ podem ter vrios subscritos, um uso comum de arrays com vrios
subscritos representar tabelas de valores que consistem em informaes organizadas
em linhas e colunas. Para identificar um elemento especifico de uma tabela, devemos
especificar dois subscritos: o primeiro identifica a linha do elemento e o segundo a
coluna.
com este tipo de array que iremos fazer graficos em 3D e cenrios
para jogos 2D.


coluna 0 coluna 1 coluna 2
linha 0 a[0][0] a[0][1] a[0][2]
linha 1 a[1][0] a[1][1] a[1][2]
linha2 a[2][0] a[2][1] a[2][2]
Um array com vrios subscritos pode ser inicializado em sua declarao da mesma
forma que um array de apenas um subscrito.
int array[2][2] = { {0,0}, {0,1} };

int array[2][2] = { {1} , {3,4} };
Assim sendo, na segunda linha, inicializamos array[0][0] com 1, array[1][0] com 3 e
array[1][1] com 4.
O Programa abaixo mostra como enviar esse tipo de varivel para
funes.



CDIGO...

// Inicializando arrays multidimensionais
#include <iostream>
using std::cout;
using std::endl;
void imprimir( int [][3] );
int main()
{
int array1[2][3] = { {1,2,3} , {4,5,6} },
array2[2][3] = { 1,2,3,4,5 },
array3[2][3] = { {1,2}, {4} };
cout << "Valores em array1 por linha: "<< endl;
imprimir( array1 );
cout << "Valores em array2 por linha: "<< endl;
imprimir( array2 );
cout << "Valores em array3 por linha: "<< endl;
imprimir( array3 );
std::cin;
return 0;
}
void imprimir ( int a[][3] )
{
for ( int i = 0; i<2; i++ )
{
for ( int j = 0; j<3; j++ )
cout << a[i][j] << ' ';
cout << endl;
}
}

FIM DE CDIGO...

Observe no exemplo acima que as forma de se iniciar so vrias, mas as formas de
trabalhar com arrays multidimencionais so iguais as unidimensionais, com a
possibilidade de se escrever dados em vrias colunas.


20 - Ponteiros
Sabemos que quando criamos uma varivel, um espao da memria reservado para
nosso programa.
Usaremos variveis do tipo ponteiro para saber que espao de memria este.
Ponteiros so muito utilizados em jogos para deixar o jogo com uma boa performace.
No se confunda com exemplos exagerados de ponteiros em outros sites, vamos manter
o bsico.
- Praticamente ponteiros so utilizados para refernciar memria e
criar novas variveis em tempo de execuo.
- Criar memria em tempo de execuo do jogo uma tarefa
complicada, por isso preste muita ateno ao utilizar ponteiros.


VOC PRECISA SABER...
Criar memria em tempo de execuo do jogo ( ou programa )
conhecido como alocao dinmica de memria


Declaramos ponteiros da seguinte forma
doube *numero1;
int *numero2;
Cada varivel que est sendo declarada como um ponteiro deve ser precedida de um *.
Assim sendo numero1 um ponteiro para um double e numero2 um ponteiro para um
inteiro.
Os ponteiros podem ser inicializados com 0 ou NULL. NULL o mesmo que 0, uma
constante definida em iostream.
O valor 0 o nico valor inteiro que pode ser atribudo diretamente a uma varivel
ponteiro, mais aconselhavel usar 0 do que NULL.
O &, ou operador de endereo, um operador unrio que retorna o endereo de seu
operando. com ele que atribuimos os valores aos ponteiros.


VOC PRECISA SABER...
& ( endereo da memria ) pode retornar o endereo da memria de
uma variavel.
O valor de uma varivel ponteiro sempre vai ser um endereo de
memria.


int y = 5;
int *Py;
Py = &y;
Diz-se ento, que a varivel Py aponta para y.
Ao imprimir o ponteiro temos o valor real de y.
cout << *Py << endl;
Observao: O ponteiro derreferenciado(*) tambm pode ser usado do lado esquerdo
de um comando.
*Py = 9; // atribui 9 a y
Ponteiros podem ser usados em funes, estas operaes so conhecidas como
chamando funes por referncia.
Neste exemplo elevamos ao cubo uma varivel usando uma chamada por referncia
com o ponteiro como argumento

CDIGO...


#include <iostream>
using std::cout;
using std::endl;
void cubo( int * );
int main()
{
int numero = 5;
cout << "O valor original de numero eh " << numero;
cubo( &numero );
cout << "\nO novo valor de numero eh " << numero << endl;
std::cin;
return 0;
}
void cubo ( int *Pn )
{
*Pn = *Pn * *Pn * *Pn; // no confunda o sinal aritmtico com o ponteiro
}

FIM DE CDIGO...

DICA
Ao longo de nosso aprendizado voc vai perceber que na maioria
das vezes os ponteiros so usados como argumentos de funes.

Isso acontece por que, em uma boa engenharia de softwere melhor
passar apenas um ponteiro para uma funo do que uma grande
quantidade de dados.


Exerccio pratco
Usando tudo o que voc aprendeu at agora, resolva os seguintes problemas de lgica:
- Crie um array que possa armazenar 10 valores ( um array com 10 elementos ou 10
posies )
Com a ajuda de um for, preencha algum valor nas posies do array.
Mostre os valores na tela.
- Crie um array multidimensional 10 x 10
Com a ajuda de um for, preencha algum valor nas posies do array
- Crie um array que possa armazenar 10 valores, inicie ele.
Use um ponteiro para mostrar o endereo da memria do ltimo elemento( ultima
posio ) e o valor que tem nesse ponto da memria.



Respostas dos Exerccios pratcos
Usando tudo o que voc aprendeu at agora, resolva os seguintes problemas de lgica:
- Crie um array que possa armazenar 10 valores ( um array com 10 elementos ou 10
posies )
Com a ajuda de um for, preencha algum valor nas posies do array.
Mostre os valores na tela.

CDIGO...

#include <iostream>

int main()
{

int array[10];

for ( int i=0; i<10; i++ )
{
array[i] = i+1;
}

for ( int a=0; a<10; a++ )
{
std::cout << array[a] << std::endl;
}

system("pause");

return 0;
}

FIM DE CDIGO...


- Crie um array multidimensional 10 x 10
Com a ajuda de um for, preencha algum valor nas posies do array.
Mostre os valores na tela.

CDIGO...

#include <iostream>

int main()
{

int array[10][10];

int linha = 0;
int coluna = 0;

int contador = 0;

for ( linha=0; linha<10; linha++ )
{
for ( coluna=0; coluna<10; coluna++ )
{
array[linha][coluna] = contador;
contador++;
}
}

for ( linha=0; linha<10; linha++ )
{
for ( coluna=0; coluna<10; coluna++ )
{
std::cout << array[linha][coluna] << "\t";
}

std::cout << " " << std::endl;
}

system("pause");

return 0;
}

FIM DE CDIGO...


- Crie um array que possa armazenar 10 valores, inicie ele.
Use um ponteiro para mostrar o endereo da memria do ltimo elemento( ultima
posio ) e o valor que tem nesse ponto da memria.

CDIGO...

#include <iostream>

int main()
{

int array[10];

for ( int i=0; i<10; i++ )
{
array[i] = i+1;
}

int * ponteiro;

ponteiro = & array[9];

std::cout << "Memoria: " << ponteiro << std::endl;
std::cout << "Valor : " << array[9] << " = " << *ponteiro << std::endl;

system("pause");

return 0;
}

FIM DE CDIGO...




21 - Organizao de Cdigo
Ao terminar a leitura do capitulo 20, voc j deve ter uma tima noo de programao.
- Essa noo que voc ganhou vale para qualquer linguagem de
programao.

- Essa noo que voc ganhou vale tambm para iniciar a produo
de um jogo em qualquer linguagem.

Todas as linguagens usam IF, FOR, arrays e ponteiros.. principalmente funes.
Por isso no interessa muito em qual linguagem voc est programando, e sim, o que
voc sabe fazer com ela.
Se voc est lendo a biblioteca, voc com certeza j escreveu algum cdigo em C++
para treinar sua programao e sua forma de pensar.

Antes de sair por ai programando jogos, precisamos ter uma certa organizao do
cdigo fonte dos programas, para que consigamos ler o mesmo cdigo algum outro dia.
VOC PRECISA SABER...
- A organizao de cdigo necessria para que voc possa entender
o que escreveu.

- A organizao de cdigo obrigatria para que voc possa
reutilizar seu cdigo fonte.

Para organizar o cdigo voc precisa seguir regras fundamentais e obrigatrias.
Declarando variveis
1 - Ao declarar variveis, voc deve tomar cuidado para no agrupar uma linha muito
grande de variveis.
Utilize sempre vrias linhas, dando um enter entre os tipos de variveis.

Exemplo totalmente errado que no deve ser usado:
int a, b, c, valor, numero, xab, contador, teste, coisa;
int a = 10, b, c, d=15, valor, coisa, variavel21, contador=0;

int numero_jogadores, posicao_peca_x, vari;
Exemplo correto:
int a = 0;
int b = 0;

int valor = 0;
int xab = 0;
int numero_jogadores = 0;

int posicao_peca_x = 0;

2 - Observe sempre de separar com espaos variveis que no combinam com as de
cima
( por exemplo, posicionamento de peas com nmeros de jogadores ).
Isto torna a leitura mais fcil.
3 - Sempre inicie as variveis.
4 - Sempre deixe espaos ao iniciar as variveis
Exemplo totalmente errado que no deve ser usado:
int a=0;b=30;
Exemplo correto:
int a = 0;
int b = 30;


5 - Ao iniciar as variveis, mantenha uma ordem nas atribuies;
Exemplo totalmente errado que no deve ser usado:
int aviao = 0;
int posicao_x = 0;
int posi = 0;
Exemplo correto:
int aviao = 0;
int posicao_x = 0;
int posi = 0;

Usando o exemplo acima, variveis que tem nome menor ficam longe das que tem
nome maior
Isso mantem o cdigo ainda mais organizado
Exemplo totalmente errado que no deve ser usado:
int aviao = 0;
int b=0;
int posicao_x = 0;
int x=0;
int posi = 0;
Exemplo correto:
int aviao = 0;
int posicao_x = 0;
int posi = 0;

int b = 0;
int a = 0;


6 - Tente sempre escrever o nome da varivel por exemplo, usando o separador _.
Se no for possvel, digite um comentrio sobre o que a varivel faz;
Exemplo totalmente errado que no deve ser usado:
int pos_per;
int px;
int py;
Exemplo correto:
int posicao_personagem;
int personagem_px; // posio x do personagem;
int personagem_py; // posicao y do personagem;

VOC PRECISA SABER...
Abreviar nome das variveis preguia.. se voc tem preguia ao
programar, ento desista de programar jogos.

7 - Mantenha distancia em nmeros na hora das operaes matemticas.
Utilize mais variveis para ajudar nas operaes, de forma que a operao fique fcil de
ler
Exemplo totalmente errado que no deve ser usado:
int num=0;
num = 10*(4/2*(3-1));
Exemplo correto:
int num = 0;
int auxiliar = 0;

auxiliar = ( ( 4 / 2 ) * ( 3- 1 ) );
num = 10 * auxiliar;

8 - IMPORTANTE: Indentar sempre os cdigos com extruturas de controle.
Exemplo totalmente errado que no deve ser usado:
if(a==1){ ....... }

while (ab!=true) {
....
}

for (i=0;i<10;i++) {
....
}
Todas as 3 formas acima esto erradas
Exemplo correto:
// Observe os espaos no parenteses, e use sempre a quebra de linha com a identao
if ( a == 1 )
{
........
}
while ( ab != true )
{
// nunca abra as chaves na linha de cima
......
}
// observe os espaos entre os parametros do for
for ( i=0; i<10; i++ )
{
.....
}

9 - Cuidar da identao quando o cdigo for muito grande
Exemplo totalmente errado que no deve ser usado:
( exemplo com cdigo maior ilustrativo, voc nao precisa entender o que est escrito )
bool selecao_direta( fila *pprimeiro ) {
fila *proximo,*atual,*menor;
int chave;
while (pprimeiro != NULL) {
proximo=(*pprimeiro).proximo;
atual=pprimeiro;
menor=atual;

while ( proximo != NULL )
{
if ( (*proximo).numero<(*menor).numero)
menor=proximo;

proximo=proximo->proximo;
}

chave = atual->numero;
atual->numero = menor->numero;
menor->numero = chave;
pprimeiro = pprimeiro->proximo;
}
return true;
}
Exemplo correto:
bool selecao_direta( fila *pprimeiro )
{

fila *proximo, *atual, *menor;

int chave;

while ( pprimeiro != NULL )
{
proximo = (*pprimeiro).proximo;
atual = pprimeiro;
menor = atual;
while ( proximo != NULL )
{

// nesse caso muito importante usar as chaves " { } " e identar o if
if ( (*proximo).numero < (*menor).numero )
{
menor = proximo;
}

proximo = proximo->proximo;
}

chave = atual->numero;
atual->numero = menor->numero;
menor->numero = chave;

pprimeiro = pprimeiro->proximo;
}
return true;
}


10 - No utilizar o comando Do While
O comando do while deixa as linguas de programao confusas, por isso, no
interessante utilizar
Qualquer cdigo em qualquer linguagem pode ser escrito seguido essas observaes
importantes.




21 - Adicional 1 - Organizao de Cdigo
Este captulo para quem j possu experincia em programao.
Recentemente fora levantado um tpico no nosso forum sobre a organizao do cdigo.
No captulo 21 ns aprendemos a melhor forma de se programar um jogo, organizando
o cdigo como programao e no como um projeto.
Com este tutorial adicional, pretendo dar mais dicas para tornar a programao de jogos
mais organizada.
Fazer um jogo um projeto que contm vrias etapas.
Nem sempre precisamos seguir todas as etapas, mais algumas so indispensveis para a
concluso sem atrasos ( perda de tempo ) do projeto.
Este tipo de contedo discutido em vrios sites e em vrias outras reas, simplesmente
por que um assunto relacionado ao tempo!
Quanto mais tempo gasto, mais caro se torna a sua idia.
Quanto mais organizada for a sua ideia e o seu projeto, melhor ele ser implementado e
mais rpido o jogo ser concludo.
Eu vou abordar aqui a criao de um jogo no estilo Arkanoid.
1 - A idia:
Como a idia criar um jogo ao estilo do Arkanoid,
precisamos estudar como este jogo funciona e descrever todos os funcionamentos e
idias do jogo.
Se voc est criando um jogo que ainda no foi inventado, o processo ser o mesmo.
A descrio da idia muito importante para sabermos o que realmente queremos fazer
e para adotar mudanas no projeto.
Exemplo:
- Um jogo aonde o jogador controla uma raquete ( ou shape ) que vai rebater uma ou
vrias bolas.
- O objetivo do jogo ser destruir todas as peas do cenrio, fazendo com que a bola
entre em contato com essas peas.
- Cada pea vai fazer com que uma ao seja disparada no jogo, criando novas bolas,
aumentando a velocidade, etc.
- Quanto todas as peas forem destruidas, o jogador enviado diretamente para a
proxima fase.
- Quando a bola no for rebatida, o jogador perde uma vida.
Observe que especificamos detalhes do jogo, sua descrio e regras.
A descrio inicia da idia no deveria ser mudada durante a execuo do projeto.
Observe que na minha idia de Arkanoid, mudei alguns conceitos do jogo original.
Neste ponto tambm, so definidas algumas historias e cenarios do jogo, no precisam
ser completas.

2 - Descrio de Regras
Agora iremos definir as regras do jogo.
Essas regras podem sofrer alteraes durante a execuo do projeto,
por que as vezes nem sempre conseguimos programar tudo o que queremos.
- O Jogo vai ter uma historia ?
- O jogo vai ter uma animao inicial ?? Como ela vai ser ?

- O Jogo vai ter uma tela inicial ? - Quais sero as opes do menu ?
- Quais sero as telas do jogo ? - Descrever as telas do jogo..
- Descrio das regras para o Jogador - Descrio das regras para o Jogador para cada
tela ou cenrio
- Descrio das regras do jogo para cada tela ou cenario
- Descrio das regras para upgrades, inimigos, jogabilidade

Quando voc for definir as regras, voc no precisa levar em considerao tecnologias
que sero utilizadas.
Isto por que, as regras podero ser alteradas mais tarde.
Esta no a hora de pensar em qual linguagem programar ou qual programa de
modelagem utilizar.

3 - Identificando atores e tarefas
Esta aqui uma das partes mais importantes ao se fazer um projeto pois ela define como
ser feita a programao.
Voc deve identificar atores de aes nas regras e idias descritas acima.
Nada muito tcnico ainda.
Exemplo:
- Bola
A bola pode se mover pelo cenario
A bola pode colidir com uma pea e destrui-la
A bola pode colidir com a raquete do jogador, que vai rebatela para outra direo
- Raquete do jogador
A raquete do jogador pode se mover apenas na horizontal para os lados
A raquete do jogador pode se mover mais rapido ou mais devagar
A raquete do jogador pode ter tamanhos diferentes
A raquete do jogador pode rebater a bola
- Cenario
O cenario pode ter tamanhos diferentes
O cenario pode ter vrias peas
O cenario pode ter uma imagem de fundo
O cenario pode ter apenas um jogador
O cenario pode ter vrias bolas
O cenario deve controlar para que as bolas no saiam de seus limites

Eu identifiquei alguns atores e tarefas deles acima.
Nem sempre se consegue identificar todos os atores, por isso talvez voc v precisar
alterar este parte mais tarde.
4 - Criando Classes e mtodos
Este mtodo de desenvolvimento no igual ao UML, Por favor, no confunda!
Os atores no UML so usurios e/ou outros meios externos que desenvolvem algum
papel em relao ao sistema.
Voc pode usar a UML para ajudar no seu projeto tambm.
Alm de definir os atores e possveis tarefas, voc vai definir diagramas que iro ajudar
voc a identificar quem sero as classes.
Estude UML tambm!
http://pt.wikipedia.org/wiki/UML
Aps identificar os atores do passo 3, podemos procurar quais deles sero classes, e
quais funes cada classe vai executar.
Pense da seguinte maneira!
Voc vai criar uma classe para alguma coisa que ir ter vrias variveis e que ir
desempenhar vrias tarefas no seu jogo.
Bola, Jogador e Cenrio desempenham vrias tarefas, como vimos acima, ento ficou
fcil de saber quem sero nossas classes.
Com as tarefas de cada um, tambm podemos conhecer de antemo quais sero os
metodos que cada um vai fazer.
Exemplo:
Classe Bola
metodo mover
metodo desenhar no cenario
metodo colisao com peas
metodo colisao com jogador
Neste ponto, nem sempre vamos descobrir todos os mtodos e todas as classes.
Porm, neste ponto j podemos descidir como vamos fazer as coisas e se conseguimos
fazer tais coisas.
Agora hora de descidir a linguagem de programao e como ser programado o jogo.
Agora tambm hora de decidir quais classes se comunicaro com outras classes.
Por exemplo:
A classe bola vai ter o mtodo que verifica a coliso? ou a classe cenario ?
Quem vai controlar as vidas ? O cenrio ou o jogador ?

Exemplo de cdigo:

CDIGO...

#ifndef BOLAS_H
#define BOLAS_H

#include <allegro.h>

class Bolas {

private:

// contadores auxiliares
int i;
int c;


public:

int posicao_x;
int posicao_y;

int tamanho;
int cor;

// controlam a velocidade da bola em x e em y
// desta forma ela pode ir para lugares diferentes na tela
int velocidade_x;
int velocidade_y;

// informam a direo de movimentao da bola
// pelo cenario

// para esquerda bola->direcao_x = -1;
// para cima bola->direcao_y = -1;
int direcao_x;
int direcao_y;
Bolas(); // funo construtor
~Bolas(); // funo destrutor

void iniciar( int pos_x, int pos_y ); // inicia objeto
void destrutor(); // reinicia variveis do objeto

void mostrar( BITMAP * fundo ); // imprime a bola no vetor fundo
void refresh(); // atualiza posio da bola

void adiciona_velocidade_x();
void remove_velocidade_x();

};

#endif

FIM DE CDIGO...


5 - Programao
Agora voc vai criar as classes que encontrou e tentar juntar todas as classes de forma
que o jogo rode no final.
Bom.. essa minha explicao foi bem superficial, j que isto bem complicado.
Ento vou mostrar como isto feito na prtica!
- Para programar um jogo voc deve ter noo de Orientao a Objeto bsica para criar
as classes.
- Para programar um jogo voc precisa ter alguma noo de UML para identificar
eventos e classes.
http://pt.wikipedia.org/wiki/Orienta%C3%A7%C3%A3o_a_objetos
http://pt.wikipedia.org/wiki/UML
http://bdjogos.com/adrw/c/classes.htm

Eu criei um jogo no estilo do Arkanoid para voc baixar.
O cdigo fonte est includo e voc poder alterar como quiser.
Neste cdigo fonte existem todos os comentrios que voc vai precisar para entender
como ler o cdigo e como organizar o projeto.


Clique aqui para fazer o download do cdigo fonte



Esta forma de programar jogos com certeza no a melhor forma que existe.
Eu apenas abordei um modo prtico de programar jogos, procure pesquisar mais sobre
isto.


21 - Adicional 2 - Jogo da memria com cdigo fonte
Para esse artigo preparei o cdigo fonte de um jogo da memria simples e objetivo a fim de
revisar e fixar os artigos vistos at o momento.

Parece bvio, mas mesmo assim bom deixar claro que essa no a nica forma de fazer
um jogo da memria.
O cdigo varia muito de cada programador.

Para quem no lembra o jogo da memria consiste em encontrar o par da carta que voc
acabou de virar.
Ao final do cdigo, teremos um resultado simples conforme abaixo:

O Jogo
Precisamos ter em mente como nosso jogo ir funcionar antes de comear a programar ele.

bom sempre fazer alguns rascunhos antes de organizar as idias oficiais.
Dessa forma teremos uma viso clara do que iremos precisar durante o desenvolvimento.

Nesse caso, as caractersticas desse jogo devem ser as seguintes:
1. Teremos um baralho de 32 cartas. 16 pares de desenhos.
2. A pontuao base inicial 100.
3. O Jogador inicia com 0 pontos.
4. Logo no inicio o jogo deve mostrar todas as cartas para que o jogador possa
memorizar.
5. Assim que o tempo de memorizao das cartas terminar o relgio para marcar o
tempo de jogo deve ser disparado.
6. A cada erro o jogador perde uma chance e espera 3 segundos para memorizar as
duas cartas erradas.
Se zerar as chances o jogo termina e a tabela de Recordes deve ser mostrada.
7. A cada seqncia de acertos a pontuao base deve ser multiplicada pela quantidade
de seqncias de acertos at o momento. Por exemplo, se acertar 2 pares seguidos
deve ser acrescentado na pontuao 2x100.

O jogo ter 3 nveis de dificuldade.
Em cada nvel teremos as seguintes alteraes:

Nvel 1:
1. Pontuao base deve ser 100.
2. Tempo para mostrar as cartas 15 segundos.
Nvel 2:
1. Pontuao base deve ser 150.
2. Tempo para mostrar as cartas 10 segundos.
Nvel 3:
1. Pontuao base deve ser 200.
2. Tempo para mostrar as cartas 5 segundos.
o A cada troca de nvel devem ser acrescentadas mais duas chances ao
jogador.
o Cada nvel de dificuldade ter um fundo e os desenhos das cartas alterados.
o Ao fim do jogo quando o jogador zerar os 3 nveis a tabela de recordes deve
aparecer.
o A tabela de recordes deve ter 9 posies e ser organizada pelo nvel e
pontuao mais altos.




Clique aqui para fazer o download do cdigo fonte




22 - Iniciando a programao de um jogo
Ol, a partir de agora voc est apto a programar seu primeiro jogo.
Vamos conferir tudo o que precisamos saber para programar um jogo:
Uma linguagem de programao ler agora
Inicializao de variveis ler agora
Os tipos de variveis ler agora
Condies ler agora
Extruturas de Controle ler agora
A Extrutura Case ( Switch em
C++ )
ler agora
Funes ler agora
Array ler agora
Ponteiro ler agora

Seria muito interessante que voc tambm tive-se conhecimentos sobre:
O conhecimento abaixo nao obrigatrio para continuar a ler o site, mais ajuda a
entender os cdigos de outras pessoas:
Extruturas de tipos ler agora
Classes ler agora
Orientao a Objetos ler agora
Alocao dinmica de memria ler agora
A Linguagem C++ ler agora

Caso voc tenha dvidas sobre estes assuntos, entre em contato no forum.
Continuando..., para fazer jogos, a primeira coisa que precisamos ter disponvel de uma
linguagem, a possibilidade de mostrar grficos na tela.
Algumas linguagens por padro, possui funes que permitem mostrar imagens na tela.
Em C++ iremos usar bibliotecas que ajudam a gente a imprimir imagens e usar os
dispositivos de entrada e sada, como a iostream que j aprendemos.
A Microsoft criou o DirectX, que possui essas funes que iremos chamar de interface
grfica.
Alm do DirectX podemos usar diversas outras existentes no mercado, tal como a SDL,
a Allegro ou o Open GL.

API, de Application Programming Interface (ou Interface de Programao de
Aplicativos) um conjunto de rotinas e padres estabelecidos por um software para
utilizao de suas funcionalidades por programas aplicativos -- isto : programas que
no querem envolver-se em detalhes da implementao do software, mas apenas usar
seus servios.
De modo geral, a API composta por uma srie de funes acessveis somente por
programao, e que permitem utilizar caractersticas do software menos evidentes ao
usurio tradicional.

Microsoft DirectX uma coleo de APIs que tratam de tarefas relacionadas a
programao de jogos para o sistema operacional Microsoft Windows, ou seja, quem
padroniza a comunicao entre software e hardware para a criao de jogos .
Direct3D uma das partes que formam o DirectX. utilizado principalmente para
desenvolver aplicativos em 3D interativos e em tempo real, como por exemplo, jogos de
computador.

A OpenGL (Open Graphics Library) uma especificao definindo uma API
multiplataforma e multi-linguagem para a escrita de aplicaes capazes de produzir
grficos computacionais 3D (bem como grficos computacionais 2D). A interface
consiste de cerca de 250 funes diferentes que podem ser utilizadas para desenhar
cenas tridimensionais complexas. A OpenGL bastante popular na indstria dos
videogames e compete diretamente com o Direct3D (no Microsoft Windows).

Simple DirectMedia Layer (SDL) uma biblioteca multimdia e multiplataforma
escrita em C (mas diretamente compatvel com C++ e possui interfaces para outras
linguagens de programao), que cria uma abstrao em vrias plataformas de grficos,
sons, e entrada de APIs, tornando possvel ao programador escrever um jogo de
computador ou outra aplicao multimedia j que ela pode rodar em GNU/Linux,
Windows, e muitas outras plataformas no oficialmente suportadas. Ela gerencia video,
eventos, audio digital, CD-ROM, som, threads, processamento de objetos
compartilhados, rede e tempo.

Em nossos tutoriais iremos utilizar a Allegro que muito parecida com a SDL e usa
como ncleo a DirectX.

23 - Conceito X e Y
Antes de ler este tutorial, leve em considerao de que voc j leu:
- A Biblioteca Allegro
- Instalao do Allegro no Dev-CPP
Instalao do Allegro no Visual Studio C++ 2005



Os nmeros naturais
Nmeros naturais ou nmeros que podem ser contados so os primeiros nmeros que
aprendemos na escola.
A muito tempo atraz a humanidade precisou inventar uma forma de contar seus
alimentos, seus habitantes ou suas criaes, desta forma surgio a oportunidade de
escrever nmeros em formas de digitos em algum lugar, e assim surgiram:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
Podemos representa-los em nossa programao atravez do tipo inteiro ( usando
principalmente unsigned "sem sinal" ).
int numero_natural = 6;
int array_numeros[3] = { 5, 10, 15 };

Os nmeros negativos
Algum tempo depois a humanidade precisou comercializar ou trocar seus objetos ou
comida. Ai foi inventado um dos conceitos mais importantes que o dbito de valores
ou os nmeros negativos. Os nmeros negativos so representados com um sinal de -
"menos" na frente de cada valor.
-1, -2, -3, -4, -5, -6, -7, -8, -9, - ...
Podemos representa-los em nossa programao atravez do tipo inteiro tbm.
int numero_negativo = -6;
int array_negativos[3] = { -5, -10, -15 };
Os nmeros inteiros, so somente constitudos dos nmeros naturais {0, 1, 2, ...} e dos
seus opostos {-1, -2, -3, ...}.

Os nmeros racionais e fraes
Em alguma determinada poca, tambm fomos obrigados a dividir comida com os
companheiros das cavernas, e foi dai que apareceram as nossas amigas fraes. Onde
um valor divido por outro.
10 / 2 = 5;
Quando uma frao no consegue dividir um nmero, surge os nmeros fracionais.
3 / 2 = 1.5
Estes nmeros so inseridos entre os nmeros inteiros e so representados em nossa
programao atravez do tipo float ou double.
doube valor = 1.666;
Um clssico exemplo de nmero racional o PI, muito utilizado na programao de
jogos.
No jogo Worms ele utilizado para saber aonde um projetil vai cair dependendo de um
angulo e fora de lanamento.
PI = 3.14159


Os nmero Reais
Os nmeros reais incluem os nmeros inteiros e os nmeros racionais. Eles so os mais
utilizados at hoje pela humanidade, e tambm so bastante complexos.
Os nmeros inteiros so contveis e os nmeros reais so nmeros incontveis.

O plano cartesiano
O Plano cartesiano um espao aonde podes visualizar 2 variveis importantes para a
programao de jogos.
As variveis X e Y.

No desenho acima temos o plano cartesiano, o plano sempre comea da posio 0 que
a origem. Esta origem nem sempre o meio do plano.
Esta origem pode ser por exemplo, o comeo de uma fase do jogo Super Mario Bros.
Andando para a direita em linha reta, estamos saindo do ponto de origem e adicionando
ao ponto X.
Andando para a direita e para cima, estamos saindo do ponto de origem e adicionando
ao ponto X e Y.
Resumindo, os pontos X e Y so coordenadas do plano cartesiano, e
com essas coordenadas que iremos escrever grficos na tela do
computador ou do video-game.
Todo ponto sempre representado por ( X, Y ), exemplo: ( 2, 3 )


Exemplos de vrios pontos X,Y em um plano cartesiano que poderia ser a tela de um
jogo:


Agora vamos brincar de escrever na tela usando os pontos X e Y.

CDIGO...

// Coordenadas X e Y
//Cdigo de Exemplo
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);



// nosso programa atual
// Testando coordenadas X e Y
int x = 0;
int y = 0;

textout_ex(screen, font, "Mensagem em 0,0 da tela", x, y, makecol(255, 0, 0), -1);

// Lao principal
while( !key[KEY_ESC] )
{

}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Neste momento voc no precisa saber os comandos que vc no conhece, apenas teste o
programa para entender a funo da varivel X e Y..
VOC PRECISA SABER...
Executando o exemplo acima, percebemos que no allegro, a
coordenada inicial do monitor bem em cima da tela na esquerda.
Isto muito importante, no open gl por exemplo, a coordenada
inicial bem no meio da tela.

O que acontece se almentar a varivel X ou Y ? Veja o exemplo:

CDIGO...

// Coordenadas X e Y
//Cdigo de Exemplo
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);



// nosso programa atual
// Testando coordenadas X e Y
int x = 0;
int y = 0;


x = x + 100;
textout_ex(screen, font, "Mensagem em 100,0 da tela", x, y, makecol(255, 0, 0), -1);

x = 0;
y = y + 100;
textout_ex(screen, font, "Mensagem em 0,100 da tela", x, y, makecol(255, 0, 0), -1);

x = x + 150;
y = y + 150;
textout_ex(screen, font, "Mensagem em 150,150 da tela", x, y, makecol(255, 0, 0), -
1);

// Lao principal
while( !key[KEY_ESC] )
{

}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Download do exemplo 1 - Clique Aqui
Download do exemplo 2 - Clique Aqui



24 - Movendo um objeto na tela
Neste tutorial iremos ver como mover um objeto na tela usando as coordenadas x e y.
Todo desenho, imagem ou objeto que pode ser inserido na tela em qualquer linguagem
de programao possui a propriedade X e Y.
Muitas vezes essas propriedades podem estar com outros nomes ( no caso do VB Top
e Left ).
No cdigo abaixo iremos ver alguns comandos novos. O mais importante so os
comandos de reconhecimento de teclado.
Atravz desses comandos ns modificaremos o valor de X e de Y e redesenhamos um
quadrado na tela na nova posio.
O cdigo bem fcil de se entender, precione ESC para sair do programa quando for
testar ele:


CDIGO...

// Movendo um objeto nas coordenadas x e y
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 0;
int y = 0;

// dimensao do quadrado
// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 100;


// Lao principal
while( !key[KEY_ESC] )
{
if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}

// esta funo limpa a tela ou um objeto que tem buffer no allegro
clear( screen );

// escrevemos um quadrado na tela na posio x e y que podem ter sido modificadas
rectfill( screen, x, y, x+tamanho, y+tamanho, makecol(255, 0, 0) );

// imprimimos as coordenadas x e y na tela para o usurio ver
textprintf_ex( screen, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( screen, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Analisando o cdigo acima, percebemos que temos alguns IFs que detectam certas
teclas do teclado.
Todas as teclas podem ser detectadas fcilmente pela allegro.
Veja as teclas possveis
Tabela do teclado
Download do exemplo 1 - Clique Aqui


Exerccio pratco
Antes de iniciar os exerccios, voc precisa ler o tutorial de:
- Retas e Figuras Geomtricas
Usando tudo o que voc aprendeu at agora, resolva os seguintes problemas para treinar
programao de jogos:
- Usando o programa exemplo de movimentao ( Movendo um objeto na tela ), faa
um circulo se mover pela tela.
- Usando o programa exemplo de movimentao, faa o objeto se mover pela tela de
forma que o programa v aumentando a velocidade do objeto.
Ele deve comear a se mover bem lento e ir ficando cada vez mais rapido.
- Crie uma tela com 10 quadrados de cores diferentes usando um lao for.
- Crie uma tela com 10 circulos de cores diferentes usando um lao for.
Sendo que um deve estar dentro do outro, de forma que o ltimo circulo desenhado seja
o menor dos circulos.


Respostas dos Exerccios
- Usando o programa exemplo de movimentao ( Movendo um objeto na tela ), faa
um circulo se mover pela tela.

CDIGO...

// Movendo um objeto nas coordenadas x e y
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 0;
int y = 0;

// dimensao do circulo
// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 50;


// Lao principal
while( !key[KEY_ESC] )
{
if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}

// esta funo limpa a tela ou um objeto que tem buffer no allegro
clear( screen );

circlefill( screen, x, y, tamanho, makecol(255, 50, 50) );

// imprimimos as coordenadas x e y na tela para o usurio ver
textprintf_ex( screen, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( screen, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...



- Usando o programa exemplo de movimentao, faa o objeto se mover pela tela de
forma que o programa v aumentando a velocidade do objeto.
Ele deve comear a se mover bem lento e ir ficando cada vez mais rapido.
Para resolver o exerccio, criamos uma varivel que controla a velocidade.. e criamos
tambm duas outras para verificar a troca de boto.
Caso o usurio aperte um boto diferente, a velocidade diminuida para 0;
Para ter a sensao de velocidade, tambm aumentamos o valor do rest.

CDIGO...

// Movendo um objeto nas coordenadas x e y
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 0;
int y = 0;

// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 30;

int velocidade = 0;

// esta uma varivel flag, que indica qual o ultimo botao apertado
int ultimo_botao = 0;
int botao_atual = 0;


// Lao principal
while( !key[KEY_ESC] )
{
if ( key[KEY_UP] )
{
y = y - velocidade;
velocidade++;
ultimo_botao = 1;
}

if ( key[KEY_DOWN] )
{
y = y + velocidade;
velocidade++;
ultimo_botao = 2;
}

if ( key[KEY_LEFT] )
{
x = x - velocidade;
velocidade++;
ultimo_botao = 3;
}

if ( key[KEY_RIGHT] )
{
x = x + velocidade;
velocidade++;
ultimo_botao = 4;
}

if ( botao_atual != ultimo_botao )
{
botao_atual = ultimo_botao;
velocidade = 0;
}

// esta funo limpa a tela ou um objeto que tem buffer no allegro
clear( screen );


circlefill( screen, x, y, tamanho, makecol(255, 50, 50) );

// imprimimos as coordenadas x e y na tela para o usurio ver
textprintf_ex( screen, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( screen, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(50);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...




- Crie uma tela com 10 quadrados de cores diferentes usando um lao for.

CDIGO...

// Criando 10 quadrados com cores diferentes entre si
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 1;
int y = 1;

// dimensao dos quadrados
// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 30;

for ( int i=0; i<10; i++ )
{
x = x + ( i + tamanho );
rectfill( screen, x, y, x+tamanho, y+tamanho, makecol(i*25, i*25, 0) );
}


// Lao principal
while( !key[KEY_ESC] )
{

}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


- Crie uma tela com 10 circulos de cores diferentes usando um lao for.
Sendo que um deve estar dentro do outro, de forma que o ltimo circulo desenhado seja
o menor dos circulos.

CDIGO...

// Movendo um objeto nas coordenadas x e y
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int cores[10] = { 50, 200, 130, 80, 140, 240, 30, 100, 222, 111 };

// bem no meio da tela
int x = SCREEN_W/2;
int y = SCREEN_H/2;

// O tamanho ser o raio, e este precisa ser alteravel
int tamanho = 30;

// o for ainda ir fazer 10 circulos
int i = 10;

for ( i=11; i>1; i-- )
{
tamanho = ( ( tamanho + i ) / 2) ;
circlefill( screen, x, y, tamanho * 5, makecol( cores[i], cores[i], cores[i]) );
}




// Lao principal
while( !key[KEY_ESC] )
{

}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...




25 - Double Buffer - Tcnica de desenhar na tela
Quando comeamos a desenhar vrios objetos primitivos na tela, e movemos ele atraves
do teclado ( na execuo do jogo ) ou mesmo animamos figuras .bmp, muitas vezes
percebemos que a imagem do jogo fica piscando.
O Nome deste efeito flicker, onde o monitor acaba imprimindo uma tela em preto
antes da nova imagem do jogo ser desenhada na varivel screen ( varivel que
representa o monitor no Allegro ). Formando a impresso de que a tela est piscando.
Para resolver este problema, utilizamos a tecnica de Double Buffer, ou seja, criar um
buffer ( lugar de armazenamento ) aonde desenhamos tudo o que deve ser desenhado na
tela, e s depois que tudo estiver desenhado no buffer, ai sim, imprimimos o buffer na
tela ( screen ).
Desta forma, a tela ( screen ) vai ter sempre a ultima imagem gerada para ela. E
enquanto tudo no for desenhado no buffer, a tela continua sendo a antiga. Assim a tela
no ir piscar mais.
Esse problema geralmente acontece quando o movimento do objeto for muito rpido ou
quando a tela atualizada antes de todos os objetos serem desenhados no screen.

A tecnica de double buffer no allegro bem simples e tambm vale para qualquer outra
biblioteca grfica ( aqui estamos dizendo, o exemplo est em allegro, mais voc pode
usar em DX ou Open GL )

Exemplo sem Double Buffer:
Possivelmente o quadrado vermelho e os textos ficaro piscando em sua tela

CDIGO...

// Coliso com os cantos da tela
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 0;
int y = 0;

// dimensao do quadrado
// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 100;


// Lao principal
while( !key[KEY_ESC] )
{
if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}

// esta funo limpa a tela ou um objeto que tem buffer no allegro
clear( screen );

// escrevemos um quadrado na tela na posio x e y que podem ter sido modificadas
rectfill( screen, x, y, x+tamanho, y+tamanho, makecol(255, 0, 0) );

// imprimimos as coordenadas x e y na tela para o usurio ver
textprintf_ex( screen, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( screen, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Exemplo com Double Buffer

CDIGO...

// Coliso com os cantos da tela
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 0;
int y = 0;

// dimensao do quadrado
// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 100;


// Criando BUFFER, ela um ponteiro para um BITMAP, pode ter qualquer nome
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);


// Lao principal
while( !key[KEY_ESC] )
{
if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}

// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
rectfill( buffer, x, y, x+tamanho, y+tamanho, makecol(255, 0, 0) );

// imprimimos as coordenadas x e y na tela para o usurio ver no buffer
textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( buffer, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

// imprime o buffer na tela
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

DICA...
Existe uma funo da allegro que faz a sincronizao vertical,
evitando tambm o efeito de flicker.
O nome da funo vsync();
Utilize ele antes de imprimir o buffer na tela( screen ).
vsync();
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

Download do exemplo 1 - Clique Aqui
Download do exemplo 2 - Clique Aqui


26 - Utilizando TILES

Tiles uma representao grfica de algo na tela, um conjunto de tiles( pedaos de
imagens ) que formar uma imagem maior.
VOC PRECISA SABER...
importante que voc tenha lido nosso artigo sobre imagens antes
de continuar.
Caso contrrio voc pode se ter dificuldades no entendimento de
algumas funes de manipulao de imagens que iremos utilizar ao
longo do cdigo.
- Desenhando imagens BMP na tela


Com tiles podemos fazer um cenrio, o que geralmente representar uma reduo de uso
de memria e armazenamento em disco do que utilizar um nico bitmap para a tela
inteira.
Geralmente, o correto trabalhar com tiles para as partes fixas do cenrio ou com pouca
mobilidade, por exemplo:
paredes e cho de um cenrio, objetos como bas, e outras coisas que no se "mexem"
muito e inclusive a gua, havendo ento uma troca seqencial das tiles que fazem parte
da gua de forma a dar a impresso de movimentao desta.

Nesse artigo iremos mostrar como montar um cenrio usando apenas tiles estticos, ou
seja, sem movimentao.
ARTE FINAL


TILES USADOS
Apenas amostra Pronto para ser utilizado



Baixar tiles
Converta as imagens de .jpg para .bmp atravez de algum programa de editorao
Com base na ilustrao acima devemos esclarecer os seguintes itens:
O tamanho do cenrio 640x480. Totalizando 307.200 pixels.
Todas as imagens foram salvas com 24bits de profundidade de cores. No entanto
configuramos o compilador para enxergar at 32bits.
O tamanho de cada Tile 32x32 pixels.
Com base nas informaes acima voc deve entender que a largura da tela de 640
pixels e a largura do nosso tile 32 pixels. Logo, j que nosso tile tem 32 pixels de
largura podemos colocar apenas 20 tiles na horizontal. J na altura, como ns temos 480
pixels podemos colocar apenas 15 tiles.

O tamanho dos tiles voc define conforme a necessidade do se projeto. A idia do artigo
dar uma viso geral de como montar um cenrio simples e esttico atravs de tiles.
DICA...
Para criar os tiles usamos o editor de imagens GLIMP.

uma ferramenta muito boa e tem uma opo que torna a vida do
design iniciante muito mais prtica. Essa opo se chama Tornar
encaixavel.

Se voc estiver fazendo a textura de uma grama ou um cho,por
exemplo, quando voc terminar poder tornar essa textura
encaixavel em todos os sentidos. Dessa forma voc no ter
problema na hora de visualizar os tiles um do lado do outro.
Assim o processo fica mais prtico mas no muito profissional
porque a imagem sofre uma pequena distoro. Para quem est
comeando vale a pena verificar.



Para facilitar o aprendizado voc poder baixar os tiles utilizados no exemplo acima.

CDIGO...

#include <allegro.h>

int main()
{
allegro_init();
install_keyboard();
set_color_depth(32);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
// COMENTADO NO FINAL - 1
int i=0;
int x=0;
int y=0;

const int xTile = 32; // Largura do Tile
const int yTile = 32; // Altura do Tile
// COMENTADO NO FINAL - 2

// Posies dos tiles no mapa bidimencional.
int Mapa[15][20] = {
3,3,3,3,4,5,5,5,5,6,2,2,1,10,10,8,9,9,9,9,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,7,7,9,9,9,9,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,7,7,9,9,9,9,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,7,8,9,9,9,9,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,7,8,8,8,8,8,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,7,7,7,7,7,7,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,7,7,7,7,7,7,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,0,10,7,7,10,0,
3,3,3,3,4,5,5,5,5,6,2,2,1,7,10,0,7,7,10,0,
3,3,3,3,3,4,5,5,5,6,2,2,1,7,0,10,7,7,10,0,
3,3,3,3,3,3,4,5,5,6,2,2,1,7,10,0,7,7,10,0,
3,3,3,3,3,3,4,5,5,6,2,2,1,7,0,10,7,7,10,0,
3,3,3,3,3,3,4,5,5,6,2,2,1,7,10,0,7,7,10,0,
3,3,3,3,3,3,4,5,5,6,2,2,1,7,0,10,7,7,10,0,
3,3,3,3,3,3,4,5,5,6,2,2,1,7,10,0,7,7,10,0};
// COMENTADO NO FINAL - 3

// Carregando o ponteiro com a imagem que possui todos os tiles
BITMAP *bmpTiles = NULL;
bmpTiles = create_bitmap(224,64);
bmpTiles = load_bitmap("tiles.bmp",NULL);

// Array que guarda as texturas separadas
BITMAP *bmpTexturas[11];

// Definindo o tamanho 32x32 para cada tile
for (i=0;i<11;i++)
{
bmpTexturas[i] = create_bitmap(xTile,yTile);
}

// A rotina abaixo separa cada tile e armazena no array.
blit(bmpTiles, bmpTexturas[0], 64, 0, 0, 0, xTile, yTile ); // Grama normal
blit(bmpTiles, bmpTexturas[1], 32, 0, 0, 0, xTile, yTile ); // Grama com areia
blit(bmpTiles, bmpTexturas[2], 0, 0, 0, 0, xTile, yTile ); // Areia
blit(bmpTiles, bmpTexturas[3], 96, 0, 0, 0, xTile, yTile ); // Agua funda
blit(bmpTiles, bmpTexturas[4], 128, 0, 0, 0, xTile, yTile ); // Agua funda com agua
clara
blit(bmpTiles, bmpTexturas[5], 160, 0, 0, 0, xTile, yTile ); // Agua clara
blit(bmpTiles, bmpTexturas[6], 192, 0, 0, 0, xTile, yTile ); // Agua clara com areia
blit(bmpTiles, bmpTexturas[7], 0, 32, 0, 0, xTile, yTile ); // Pedras
blit(bmpTiles, bmpTexturas[8], 32, 32, 0, 0, xTile, yTile ); // Parede
blit(bmpTiles, bmpTexturas[9], 64, 32, 0, 0, xTile, yTile ); // Piso
blit(bmpTiles, bmpTexturas[10], 96, 32, 0, 0, xTile, yTile ); // Flores
// COMENTADO NO FINAL - 4

//Monta o Cenrio
for (x=0;x<15;x++)
{
for (y=0;y<20;y++)
{
draw_sprite(screen,bmpTexturas[ Mapa[x][y] ], y*32, x*32 );
}
}
// COMENTADO NO FINAL - 5

//Escreve mercado na parede.
textout_ex(screen, font, "MERCADO", 540, 135, makecol(255,255,0), -1);

readkey();

//Desaloca as Texturas
for (i=0;i<11;i++)
{
destroy_bitmap(bmpTexturas[i]);
}

destroy_bitmap(bmpTiles);

allegro_exit();

return 0;
}

END_OF_MAIN();

FIM DO CDIGO


Passos para a preparao dos tiles com base nesse exemplo:
Definio do tamanho da tela de 640x480 pixels.
Profundidade de cores de 32 bits.
Criao dos tiles no tamanho de 32x32 pixels 24bits. Dessa forma temos
espao para 20 tiles na horizontal e 15 tiles na vertical.
Organizar todos os tiles em apenas um arquivo de imagem com fundo lils
conforme ilustrado acima. Dessa forma podemos extrair todas as texturas atravs
da funo blit.

Aps a preparao do tiles necessrio organizar o cdigo de maneira que fique clara a
montagem do cenrio usando os tiles criados.
// COMENTADO NO FINAL - 1

Bom, vamos pular as configuraes da tela e ver as 3 variveis criadas.

A varivei i apenas um contador auxiliar.
A varivel x e y vo ser utilizadas para percorrer o array bidimensional do mapa.

Logo abaixo das variveis temos mais duas variveis constantes que armazenam a
largura e a altura do tile.
Nesse exemplo possumos tiles de 32x32 pixels. Declarando o tamanho como sendo
global, posteriormente podemos efetuar mudanas sem ter que percorrer o cdigo atrs
de referncia ao tamanho do tile.
// COMENTADO NO FINAL - 2

A matriz que representar o layout do mapa deve ser bidimensional e deve ter como
tamanho a quantidade de tiles que podemos colocar na tela, nesse caso [15]x[20].
Voc vai notar que ao informar o tamanho do mapa eu inverti o x pelo y.

Dessa forma, fica fcil de visualizar o layout do cenrio atravs dos nmeros.
Normalmente o cdigo de montagem do cenrio monta o cenrio da esquerda para
direita e de cima para baixo. Se voc fizer da mesma forma que eu fiz o cenrio ser
montado de cima para baixo e da esquerda para a direita.
Voc ter que iniciar cada posio do mapa com o nmero do tile que queremos colocar
naquela posio. Para isso voc j deve ter em mente a organizao dos tiles e a
numerao que vai identificar cada uma na posio do mapa.
// COMENTADO NO FINAL - 3

Ao invs de carregarmos cada textura do mapa separadamente vamos carregar uma
imagem organizada e contendo todas as texturas.
Logo abaixo teremos um array de imagens que vai conter cada textura separada. Como
cada textura tem tamanho 32x32 fizemos uma rotina genrica para definir o tamanho de
todos seqencialmente. Em seguida carregamos cada posio do array de texturas com
cada imagem correspondente. Para esse efeito usamos a funo blit.
// COMENTADO NO FINAL - 4

At agora temos o mapa com cada posio iniciada com um nmero. Esse nmero
correspondente ao array de texturas. Por exemplo, na posio Mapa[0][0] temos o
nmero 3. Se voc pegar a textura[3] voc ver a imagem de gua escura conforme
nossa organizao, e assim sucessivamente com as outras posies.

A rotina para montar o cenrio simples. Devemos percorrer todas as posies do
array bidimensional Mapa identificando o nmero e representando atravs de
uma textura na tela.
Como nosso tile tem 32 pixels ento cada vez que voc desenhar uma imagem voc
deve pular 32 pixels para poder desenhar a prxima (x*xTile, y*yTile).
Caso contrrio uma imagem ficar em cima da outra. Imagine a posio x=0 e y=0.
Se desenharmos um tile nessa posio o tile vai ocupar 32 pixels na largura e 32
pixels na altura, portanto o prximo tile deve ser desenhado a partir da posio
x=32 e y=32. Por esse motivo a rotina de montagem do mapa est multiplicando a
posio x,y pelo tamanho de cada tile.

// COMENTADO NO FINAL - 5

Para finalizar, escrevemos na tela o texto MERCADO para caracterizar o local no
canto superior direito da tela.
Em seguida fizemos a destruio das imagens e a finalizao da biblioteca Allegro.


Caro leitor, chegamos ao fim do entendimento da montagem de tiles. Espero que o
exemplo acima tanha ajudado.
Qualquer dvida entre em contato com o pessoal da BDJogos atravs do frum.

Abrao
BDJogos
Download do exemplo 1 - Clique Aqui




27 - Detectando colises
O Ato de detectar colises entre desenhos muito importante para qualquer tipo de
jogo.
Em um jogo como o Super Mario por exemplo, no podemos sair da tela, nem podemos
tocar do lado dos inimigos.
Para isso foi programado uma deteco de coliso, que na verdade uma formula bem
simples.
Todo objeto na tela deve ter uma posio X e Y definida, desta forma,
podemos saber se o X e Y de um objeto est dentro da rea do X e Y de outro objeto.
Primeiro, vamos fazer a coliso de um objeto com a tela.
Sabemos que no Allegro, a posio 0,0 o limite esquerdo e do topo.

Usaremos uma varivel da Allegro para saber qual o tamanho mximo da tela para
pegar-mos o X e Y do limite direito e final da tela.
FRMULA
- A posio X do objeto no pode ser menor que zero
- A posio de X + o tamanho do objeto ( em X ) no pode ser maior
que o limite da tela. Se for maior, o objeto vai sair da tela.

- A posio Y do objeto no pode ser menor que zero
- A posio de Y + o tamanho do objeto ( em Y ) no pode ser maior
que o limite da tela. Se for maior, o objeto vai sair da tela.
Tome cuidado quando o objeto tiver um tamanho X diferente do
tamanho Y



CDIGO...

// Coliso com os cantos da tela
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);


// inicio da programao atual
int x = 0;
int y = 0;

// dimensao do quadrado
// variveis constantes nunca mudam durante a execuo do programa
const int tamanho = 100;


// Lao principal
while( !key[KEY_ESC] )
{
if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}

// limitando o quadrado dentro da tela
if ( x < 0 )
{
x = 0;
}

if ( (x+tamanho) > SCREEN_W )
{
x = SCREEN_W - tamanho;
}

if ( y < 0 )
{
y = 0;
}

if ( (y+tamanho) > SCREEN_H )
{
y = SCREEN_H - tamanho;
}


// esta funo limpa a tela
clear( screen );

// escrevemos um quadrado na tela na posio x e y
rectfill( screen, x, y, x+tamanho, y+tamanho, makecol(255, 0, 0) );

// imprimimos as coordenadas x e y na tela para o usurio ver
textprintf_ex( screen, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( screen, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Basicamente:

Imagine que as linhas pretas so os limites da tela.
Temos que, o x de nosso quadrado nunca pode ser menor que o x limite da tela.
Para resolver isso fizemos:
if ( x < 0 )
{
x = 0;
}
O mesmo para o y.
Agora, para testar os limites finais da tela:

Imagine que em x=100 o quadrado j est tocando no final da tela.
Para testar isso, fizemos o seguinte:
if ( (x+tamanho) > SCREEN_W )
{
x = SCREEN_W - tamanho;
}
Se imaginarmos que o SCREEN_W seja de 200, podemos dizer que
x ( 100 ) + tamanho ( 100 ) nunca pode ser maior que o SCREEN_W.
O mesmo acontece para y.
Dica
Fique esperto com estes testes quando o tamanho do objeto for
difrente para X e Y.



Agora vamos inserir um quadrado no meio da tela, e vamos fazer um teste de coliso
neste quadrado.


CDIGO...

// Coliso com os cantos da tela
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);

// inicio da programao atual
int x = 0;
int y = 0;
const int tamanho = 50;

const int obj_tam = 100;
const int obj_x = ( SCREEN_W - (obj_tam / 2) ) / 2;
const int obj_y = ( SCREEN_H - (obj_tam / 2) ) / 2;

bool colide = false;

// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);


// Lao principal
while( !key[KEY_ESC] )
{

if ( colide == false )
{
if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}
}



// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
rectfill( buffer, x, y, x+tamanho, y+tamanho, makecol(255, 0, 0) );

rectfill( buffer, obj_x, obj_y, obj_x+obj_tam, obj_y+obj_tam, makecol(0, 0, 255) );

// imprimimos as coordenadas x e y na tela para o usurio ver no buffer
textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( buffer, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

textprintf_ex( buffer, font, 10, 30, makecol(255,0,0), -1, "obj X: %d", obj_x);
textprintf_ex( buffer, font, 10, 40, makecol(255,0,0), -1, "obj Y: %d", obj_y);


// verifica se colide
if ( (x+tamanho) >= obj_x && x <= obj_x+obj_tam )
{
if ( (y+tamanho) >= obj_y && y <= obj_y+obj_tam )
{
textout_ex(buffer, font, "COLIDE", obj_x+25, obj_y+50, makecol(0, 255, 0), -
1);
}
}


// imprime o buffer na tela
vsync();
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Primeiro exemplo:

Neste caso, a imagem vermelha est fora dos limites da imagem do centro azul.

Neste caso, temos o vermelho dentro do limite X da imagem azul, porm, o vermelho
continua fora do limite Y, logo, ainda no temos uma coliso.
J temos este teste:

if ( (x+tamanho) >= obj_x && x <= obj_x+obj_tam )


Neste caso, temos o vermelho dentro do limite Y da imagem azul, porm, o vermelho
continua fora do limite X, logo, ainda no temos uma coliso.
Neste caso, j temos este teste:

if ( (y+tamanho) >= obj_y && y <= obj_y+obj_tam )


E no ltimo exemplo, temos a coliso em X e Y dentro dos limites nas imagem azul.
Juntando os 2 testes, temos:
// verifica se colide
if ( (x+tamanho) >= obj_x && x <= obj_x+obj_tam )
{
if ( (y+tamanho) >= obj_y && y <= obj_y+obj_tam )
{
textout_ex(buffer, font, "COLIDE", obj_x+25, obj_y+50, makecol(0, 255, 0), -
1);
}
}
Download do exemplo 1 - Clique Aqui
Download do exemplo 2 - Clique Aqui



27 - Detectando colises com uma funo
Usando o captulo 27, vamos praticar detectar coliso, usando uma funo e no
deixando que o objeto que est se movendo,
consiga se mover enquanto estiver colidindo.
O programa no muda muito, nem a formula, a nica diferena que precisamos juntar
os ifs em um nico if.


CDIGO...

// Coliso em uma funo
#include <allegro.h>

// funo que verifica coliso
bool colide( int, int, int, int, int, int );

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);

// inicio da programao atual
int x = 0;
int y = 0;

int x_atual = x;
int y_atual = y;

const int tamanho = 50;

const int obj_tam = 100;
const int obj_x = ( SCREEN_W - (obj_tam / 2) ) / 2;
const int obj_y = ( SCREEN_H - (obj_tam / 2) ) / 2;

bool colidindo = false;

// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);


// Lao principal
while( !key[KEY_ESC] )
{
x_atual = x;
y_atual = y;


if ( key[KEY_UP] )
{
y--;
}

if ( key[KEY_DOWN] )
{
y++;
}

if ( key[KEY_LEFT] )
{
x--;
}

if ( key[KEY_RIGHT] )
{
x++;
}

colidindo = colide( x, y, tamanho, obj_x, obj_y, obj_tam );

if ( colidindo == false )
{
x_atual = x;
y_atual = y;
}
else
{
// volta para os valores antigos
x = x_atual;
y = y_atual;
}

// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
rectfill( buffer, x_atual, y_atual, x_atual+tamanho, y_atual+tamanho, makecol(255,
0, 0) );

rectfill( buffer, obj_x, obj_y, obj_x+obj_tam, obj_y+obj_tam, makecol(0, 0, 255) );

// imprimimos as coordenadas x e y na tela para o usurio ver no buffer
textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( buffer, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

textprintf_ex( buffer, font, 10, 30, makecol(255,0,0), -1, "obj X: %d", obj_x);
textprintf_ex( buffer, font, 10, 40, makecol(255,0,0), -1, "obj Y: %d", obj_y);
textprintf_ex( buffer, font, 10, 50, makecol(255,0,0), -1, "colide: %d", colidindo);


// imprime o buffer na tela
vsync();
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

// funo que verifica coliso
bool colide( int x, int y, int tamanho, int obj_x, int obj_y, int obj_tam )
{
if ( x+tamanho > obj_x && x < obj_x+obj_tam && y+tamanho > obj_y && y <
obj_y+obj_tam )
{
return true;
}

return false;
}

FIM DE CDIGO...

Desta forma, ao chamar novamente a funo, podemos testar a coliso com outros
vrios objetos na tela.
Download do exemplo 1 - Clique Aqui


Exerccio pratco
- Utilizando o programa do captulo 27, crie uma classe para imprimir vrios quadrados
"objetos" na tela.
O quadrado que se move deve detectar coliso nos outros objetos inseridos.
Imprima 5 quadrados na tela de tamanho diferentes e verifique a coliso com todos eles.
- Faa com que uma bola ande de um lado para outro na tela, de forma que ele se colida
com o final da tela e volte para o inicio da tela.
- Faa com que uma bola ande por toda tela, colidindo com as paredes.
Quando a bola colidir, ela deve alterar para aonde ela vai colidir da prxima vez, de
forma que ela fique andando por toda a tela.

Os exerccios acima so bastante interessantes e tambm difceis.
Voc pode olhar as respostas caso no conseguir fazer, mais tentar resolver os
exerccios vai aumentar seu raciocnio lgico.
Para resolver o primeiro exerccio:



Respostas dos Exerccios
- Utilizando o programa do captulo 27, crie uma classe para imprimir vrios quadrados
"objetos" na tela.
O quadrado que se move deve detectar coliso nos outros objetos inseridos.
Imprima 5 quadrados na tela de tamanho diferentes e verifique a coliso com todos eles.

Preste ateno na forma que a classe foi criada.
Quanto mais prtica a classe ficar, melhor para seu jogo. Voc poder usar ela muito
mais fcil.
Evite complicaes.

CDIGO...

#ifndef PAREDE_H
#define PAREDE_H

// ARQUIVO: parede.h
// Data: 01/08/2007

class Parede {
public:

Parede( int, int, int, int );
void imprimir( BITMAP * );
bool colide( int, int, int, int );

private:

int x;
int y;
int tamanho_x;
int tamanho_y;
};

#endif

FIM DE CDIGO...


CDIGO...

#include <allegro.h>
#include "parede.h"

// ARQUIVO: parede.cpp
// Data: 01/08/2007

// Este o construtor do objeto
Parede::Parede( int x, int y, int tam_x, int tam_y )
{
this->x = x;
this->y = y;
this->tamanho_x = tam_x;
this->tamanho_y = tam_y;
}

// Essa funo imprime o objeto na tela,
// passamos o local aonde queremos imprimir
void Parede::imprimir( BITMAP *screen )
{
rectfill( screen, x, y, x+tamanho_x, y+tamanho_y, makecol(255, 255, 0) );
}

// Testa a coliso com o objeto atual ( isso quer dizer 1 de cada vez )
bool Parede::colide( int x, int y, int tamanho_x, int tamanho_y )
{
if (
( x+tamanho_x > this->x ) &&
( x < this->x+this->tamanho_x ) &&
( y+tamanho_y > this->y ) &&
( y < this->y+this->tamanho_y )
)
{
return true;
}

return false;
}

FIM DE CDIGO...


CDIGO...

// Coliso com vrios objetos
#include <allegro.h>
#include "parede.h"

// ARQUIVO: main.cpp
// Data: 01/08/2007

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);

// inicio da programao atual
int x = 0;
int y = 0;

int x_atual = x;
int y_atual = y;

const int tamanho_x = 20;
const int tamanho_y = 10;

const int total_paredes = 5;

bool colidindo = false;

// forma de iniciar vrios objetos com construtor
Parede aparede[total_paredes] = {
Parede( 300, 50, 10, 30 ),
Parede( 150, 150, 50, 30 ),
Parede( 300, 150, 150, 50 ),
Parede( 250, 250, 50, 150 ),
Parede( 500, 250, 80, 80 )
} ;

int i = 0;

// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);


// Lao principal
while( !key[KEY_ESC] )
{
x_atual = x;
y_atual = y;

if ( key[KEY_UP] )
{
y -= 5;
}

if ( key[KEY_DOWN] )
{
y += 5;
}

if ( key[KEY_LEFT] )
{
x -= 5;
}

if ( key[KEY_RIGHT] )
{
x += 5;
}


// Aqui vem o complicado
// Ns olhamos objeto por objeto, se colidir com um deles
// paramos o for e no deixamos nosso quadrado andar
for ( i=0; i<total_paredes; i++ )
{
colidindo = aparede[i].colide( x, y, tamanho_x, tamanho_y );

if ( colidindo == true )
{
i = total_paredes;
}
}

if ( colidindo == false )
{
x_atual = x;
y_atual = y;
}
else
{
// volta para os valores antigos
x = x_atual;
y = y_atual;
}


// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
rectfill( buffer, x_atual, y_atual, x_atual+tamanho_x, y_atual+tamanho_y,
makecol(255, 0, 0) );


// imprimimos as coordenadas x e y na tela para o usurio ver no buffer
textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( buffer, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);

textprintf_ex( buffer, font, 10, 50, makecol(255,0,0), -1, "colide: %d", colidindo);

// imprime todos os quadrados no destino ( buffer )
for ( i=0; i<total_paredes; i++ )
{
aparede[i].imprimir( buffer );
}

// imprime o buffer na tela
vsync();
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();


FIM DE CDIGO...

Preste muita ateno a forma que as paredes foram criadas.
Tambm preste ateno em como fazemos a coliso, olhando um objeto de cada vez.

Ser que em um jogo grande isso seria vlido??
Imagine testar a coliso desta forma em toda uma fase do Super Mario Bros ?
Quantos testes seriam necessrios?
Por enquanto no se preocupe com otimizao de cdigo, poderiam ter 5 mil objetos na
tela que o C++ iria
dar conta do recado. Utilize sua imaginao sem pensar que seu jogo ir ficar lento.

- Faa com que uma bola ande de um lado para outro na tela, de forma que ele se colida
com o final da tela e volte para o inicio da tela.

CDIGO...

// Bolinha andadora
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);

// inicio da programao atual
int x = 0;
int y = SCREEN_H/2;
int tamanho = 20;
bool colide = false;

int variavel = 1;

// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);


// Lao principal
while( !key[KEY_ESC] )
{

if ( variavel == 1 )
{
x += 5;
}
else
{
x -= 5;
}


// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
ellipsefill(buffer, x, y, tamanho, tamanho, makecol(255,255,0) );



// imprimimos as coordenadas x e y na tela para o usurio ver no buffer
textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( buffer, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);


// limitando o quadrado dentro da tela
if ( x < 0 )
{
variavel = variavel * (-1);
}

if ( (x+tamanho) > SCREEN_W )
{
variavel = variavel * (-1);
}


// imprime o buffer na tela
vsync();
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

- Faa com que uma bola ande por toda tela, colidindo com as paredes.
Quando a bola colidir, ela deve alterar para aonde ela vai colidir da prxima vez, de
forma que ela fique andando por toda a tela.

CDIGO...

// Bolinha coliso
#include <allegro.h>

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);

// inicio da programao atual
int x = 0;
int y = SCREEN_H/2;
int tamanho = 20;
bool colide = false;

int variavel_x = 10;
int variavel_y = 10;

// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);


// Lao principal
while( !key[KEY_ESC] )
{

if ( variavel_x == 1 )
{
x += variavel_x;
}
else
{
x -= variavel_x;
}

if ( variavel_y == 1 )
{
y += variavel_y;
}
else
{
y -= variavel_y;
}


// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
ellipsefill(buffer, x, y, tamanho, tamanho, makecol(255,255,0) );



// imprimimos as coordenadas x e y na tela para o usurio ver no buffer
textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "Variavel X: %d", x);
textprintf_ex( buffer, font, 10, 20, makecol(255,0,0), -1, "Variavel Y: %d", y);


// limitando o quadrado dentro da tela
if ( x < 0 )
{
variavel_x = variavel_x * (-1);
}

if ( (x+tamanho) > SCREEN_W )
{
variavel_x = variavel_x * (-1);
}

if ( y < 0 )
{
variavel_y = variavel_y * (-1);
}

if ( (y+tamanho) > SCREEN_H )
{
variavel_y = variavel_y * (-1);
}


// imprime o buffer na tela
vsync();
blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

// essa funo faz o allegro esperar um pouco antes de voltar para o while
rest(10);
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


28 - FPS - Quadros por segundo, Frames per second ou Frame Rate

Todo jogo possui animao, isto fato.
Animaes so geralmente quadros de desenhos que vo se mudando ( sobrepondo a
antiga ) gerando assim uma animao.
Este o exemplo de uma animao e alguns de seus quadros, que juntos formam a
animao.

=

Esta animao originalmente tem 12 quadros e ela executada a 100 milisegundos.
Se aumentarmos a taxa de milisegundos de cada quadro em separado, a animao vai
ficar ainda mais lenta.
Se diminuirmos a taxa de 100 milisegundos de cada quadro, a animao vai ficar bem
mais rpida.
Essa mudana de tempo nos quadros da animao influencia muito os jogos feitos para
computadores.
Geralmente, nosso programa roda na velocidade de clock tick do nosso processador.
Isto quer dizer que o programa pode rodar mais rpido em algumas mquinas e mais
lento em outras mquinas.
Isso influncia no s as animaes como tambm a jogabilidade.
Para que o jogo rode igual em qualquer mquina, precisamos criar um controle de
Frame Rate ( ou controle de FPS ).
Para isto, primeiro precisamos descobrir como contar os FPS de nosso programa.

DICA...
Esta tcnica de contar FPS e fazer o programa rodar em um FPS
igual para todas as mquinas pode e deve ser aplicado em qualquer
tipo de linguagem de programao para jogos ou animaes.

Cada linguagem tem uma forma diferente de se chegar nesse
resultado, mais a tecnica a mesma.Vamos aprender em Allegro um
cdigo completo.

Em DirectX podemos fazer a mesma coisa usando a funo do
windows GetTickCount(); que pega o total de ticks.
Em OpenGL podemos fazer a mesma coisa usando as funes do
GLUT .


VOC PRECISA SABER...
importante que voc tenha lido nosso artigo sobre como instalar
timers no Allegro.

- Controle de tempo



CDIGO...

#include <allegro.h>

// Exemplo da bolinha com contador de Frames por segundos

// global
int fps = 0;
int fps_antigo = 0;


// prototipo do contador de frames
void frame_rate();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);


BITMAP *buffer = NULL;

int x = 0;
int y = SCREEN_H/2;
int tamanho = 20;

install_timer();

// a cada 1 segundo mostra quantas vezes a imagem foi impressa na tela
install_int( frame_rate, 1000 );



bool colide = false;

int variavel_x = 10;
int variavel_y = 10;

// Criando BUFFER para double buffer
buffer = create_bitmap(800,800);



// Lao principal
while( !key[KEY_ESC] )
{

if ( variavel_x == 1 )
{
x += variavel_x;
}
else
{
x -= variavel_x;
}

if ( variavel_y == 1 )
{
y += variavel_y;
}
else
{
y -= variavel_y;
}

// limitando o quadrado dentro da tela
if ( x < 0 )
{
variavel_x = variavel_x * (-1);
}

if ( (x+tamanho) > SCREEN_W )
{
variavel_x = variavel_x * (-1);
}

if ( y < 0 )
{
variavel_y = variavel_y * (-1);
}

if ( (y+tamanho) > SCREEN_H )
{
variavel_y = variavel_y * (-1);
}

// limpa o nosso novo buffer
clear( buffer );

// escreve a bola no buffer
ellipsefill(buffer, x, y, tamanho, tamanho, makecol(255,255,0) );

textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );



blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

vsync();
::fps++;

}

destroy_bitmap( buffer );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

FIM DE CDIGO

No exemplo acima, criamos uma varivel global fps que incrementada sempre aps
que a imagem imprimida na tela.
Usando um timer do Allegro, sempre que passar 1 segundo, ns mostramos o total de
FPS que o Allegro conseguiu imprimir, tendo assim o total de frames impressos em 1
segundo.
Legal.. j sabemos a quantos quadros nosso programa roda, agora precisamos controlar
a taxa de quadros, sem influnciar na jogabilidade.
Nos exemplos anteriores do site, estavamos usando o comando rest() que fazia o
compilador esperar.Esta funo no deve ser usanda, por que durante a execuo do
comando rest() as teclas do teclado no so detectadas.
Agora precisamos controlar a taxa de frames de nosso programa.
A desciso da quantidade de frames por segundo o jogo vai rodar sua, voc pode usar
30 FPS que o limite mnimo para que o olho detecte transao da animao, ou 60 que
o valor mostrado no manual da Allegro.


CDIGO...

#include <allegro.h>

// Exemplo da bolinha com limitador de FPS

// global
int fps = 0;

int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();
// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);


BITMAP *buffer = NULL;

int x = 0;
int y = SCREEN_H/2;
int tamanho = 20;

install_timer();

// a cada 1 segundo mostra quantas vezes a imagem foi impressa na tela
install_int( frame_rate, 1000 );

install_int_ex( incrementa_speed, BPS_TO_TIMER(60) );


bool colide = false;

int variavel_x = 10;
int variavel_y = 10;

// Criando BUFFER para double buffer
buffer = create_bitmap(800,800);



// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{
if ( variavel_x == 1 )
{
x += variavel_x;
}
else
{
x -= variavel_x;
}

if ( variavel_y == 1 )
{
y += variavel_y;
}
else
{
y -= variavel_y;
}

// limitando o quadrado dentro da tela
if ( x < 0 )
{
variavel_x = variavel_x * (-1);
}

if ( (x+tamanho) > SCREEN_W )
{
variavel_x = variavel_x * (-1);
}

if ( y < 0 )
{
variavel_y = variavel_y * (-1);
}

if ( (y+tamanho) > SCREEN_H )
{
variavel_y = variavel_y * (-1);
}

// limpa o nosso novo buffer
clear( buffer );

// escreve o quadrado no buffer
ellipsefill(buffer, x, y, tamanho, tamanho, makecol(255,255,0) );

textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );

::fps_speed--;
::fps++;
}

blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);

vsync();

}

destroy_bitmap( buffer );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO

O programa acima pode parecer confuso.
Ns criamos um timer para que, a cada 60 clock tick ( usando a macro
BPS_TO_TIMER ) o contador de speed seja incrementado.
Quando acontecer os primeiros 60 clocks, o compilador vai entrar no while que atualiza
a lgica do jogo.
Enquanto o fps_speed no for menor que 0 ( o while vai fazer ele chegar bem rpido )
ele vai atualizando a lgica do jogo, mais no a tela.
Esta lgica faz com que o contador de FPS fique constante.
Execute o cdigo acima e faa testes alterando o valor que est na macro
BPS_TO_TIMER para conferir.
Para fazer com que o teclado obedea a velocidade em FPS preciso utilizar um Buffer
de teclado, que pode ser lido aqui:
http://www.bdjogos.com/biblioteca_conteudo.php?id=17

Com este tutorial suprimos uma das dvidas mais cabulosas na criao de jogos, a partir
deste captulo iremos demonstrar outras tcnicas importantes na programao de jogos.
Qualquer dvida entre em contato pelo forum.
http://www.bdjogos.com/forum


29 - Movimentao de Sprites

Sprites um conjunto de imagens que organizadas em uma determinada seqncia
simulam o movimento de algum objeto ou personagem. Praticamente todos os jogos 2D
possuem algum tipo de sprites.
Podemos definir como sprites a movimentao do jogador principal, as folhas caindo no
cho, os inimigos em movimento e principalmente os efeitos entre os objetos do
cenrio.
A seguir iremos selecionar alguns sprites prontos de jogos e coloc-los em movimento.
Se voc proferir escolher algum outro sprite segue uma seqncia de sites abaixo com
uma infinidade de sprites de jogos.
Links para Sprites
http://tsgk.captainn.net/
http://www.panelmonkey.org/category.php?id=1&theme=1
http://www.molotov.nu/?page=graphics


dragao.bmp

Especificaes
Qtde de Desenhos em x[0]:
Qtde de Desenhos em y[0]:
Largura total:
Largura individual:
Altura:
6
0
360 pixels
60 pixels
55 pixels


robocop.bmp

Especificaes
Qtde de Desenhos em x[0]:
Qtde de Desenhos em y[0]:
Largura total:
Largura individual:
Altura:
6
0
415 pixels
69 pixels
80 pixels


No se esquea de converter as imagens acima para bitmap.
O cdigo que iremos usar para movimentar o Robocop e o drago o mesmo.
Porm, antes de executar cada um necessrio fazer algumas configuraes com
relao s especificaes citadas acima.

CDIGO...

#include <allegro.h>

int main()
{
allegro_init();
install_keyboard();
set_color_depth(16);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

BITMAP *imgSprites = NULL;
imgSprites = load_bitmap("robocop.bmp",NULL);

BITMAP *Buffer = NULL;
Buffer = create_bitmap(SCREEN_W,SCREEN_H);

const int iSprite_Largura = 69; // Largura de um sprite
const int iSprite_Altura = 80; // Altura de um sprite
const int Qtde_Spritesx = 6; // Qtde de Desenhos em x[0] - Horizontal
const int Qtde_Spritesy = 0; // Qtde de Desenhos em y[0] - Vertical

const int iCiclo = 30; // Ciclo de troca de sprite

int iPosx = 0; // Posio x do corte.
int iPosy = 0; // Posio y do corte. Como apenas uma fileira ento y sempre vai ser
0

int buffer_animacao = 0; // Buffer para controle do ciclo

while (!key[KEY_ESC])
{
clear_bitmap( Buffer );
textprintf_ex(Buffer, font, 0, 0, makecol(0, 255, 255),-1,"ANIMACAO SPRITES");

// Controle para mudar o sprite
if(buffer_animacao == 0)
{
if (iPosx > 0 && iPosx == Qtde_Spritesx-1)
{
iPosx = 0;
}

if (Qtde_Spritesx > 0)
{
iPosx++;
}

buffer_animacao = iCiclo;

}
else
{
buffer_animacao--;
}

// Corta e desenha o sprite
masked_blit(imgSprites,Buffer,iPosx*iSprite_Largura,iPosy,SCREEN_W/2, SCRE
EN_H/2,iSprite_Largura,iSprite_Altura);

blit(Buffer,screen,0,0,0,0,SCREEN_W,SCREEN_H);
vsync();

}

destroy_bitmap(imgSprites);
destroy_bitmap(Buffer);

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DO CDIGO

Logo acima temos um cdigo genrico para a movimentao dos sprites na horizontal.
No processo para a movimentao dos sprites na vertical a nica coisa que muda o
eixo x para y.
Basicamente, o cdigo possui a informao da largura, altura e quantidade de sprites na
horizontal.
Com essas informaes possvel fazer um corte nas imagens com a funo blit vista
em outro artigo.
Para que as imagens no fossem trocadas na velocidade de processamento de cada
computador adicionamos um buffer de animao iCiclo.
Dessa forma nossa animao ter um movimento mais pausado e uma impresso de
movimento muito melhor.
Caro leitor chegamos ao fim do entendimento da movimentao de sprites. Se houver
alguma dvida ou dificuldade favor entrar em contato com o pessoal pelo Forum.

Abrao
BDJogos


Trocar de direo usando Sprite

Nesse artigo vou ilustrar o cdigo para movimentao do pacman em todas as direes
utilizando sprites.

Antes de iniciar o cdigo ser necessrio entender como esto organizados os sprites no
arquivo.
A tabela abaixo mostra que na vertical esto definidas as direes dos desenhos, Direita,
Esquerda, Cima e Baixo.

J na horizontal esto definidas as seqncias dos sprites que iro definir o movimento
do pacman.
Posies dos Sprites
Animao (x), Direo (y).

Sprite
1
Sprite
2
Sprite
3
Sprite
4
Sprite
5
Direita 0,0 25,0 50,0 75,0 100,0
Esquerda 0,25 25,25 50,25 75,25 100,25
Cima 0,50 25,50 50,50 75,50 100,50
Baixo 0,75 25,75 50,75 75,75 100,75
Ao selecionar a posio 0,0 voc dever desenhar na tela o pacman virado para a direita
e de boca fechada.

J na posio 100,0 o pacman est virado para a direita e de boca aberta.
Para fazer a simulao de movimento e de troca de direo necessrio juntar a tabela
acima com os direcionais do teclado.

Abaixo segue as especificaes dos sprites.
pacpac.bmp

Especificaes
Qtde de Desenhos em x[0]:
Qtde de Desenhos em y[0]:
Largura total:
Largura individual:
Altura:
5
4
125 pixels
25 pixels
25 pixels
OBS: Salvar a imagem acima como .BMP. O allegro no aceita o
tipo jpg.


O cdigo que iremos usar para movimentar o Robocop e o drago o mesmo.
Porm, antes de executar cada um necessrio fazer algumas configuraes com
relao s especificaes citadas acima.


O cdigo ser dividido em 3 arquivos. So eles:
main.cpp
Jogador.h
Jogador.cpp

CDIGO...

#include <allegro.h>
#include "cjogador.h"
// Arquivo: main.cpp

int main()
{
allegro_init();
set_color_depth(32);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

CJogador Jogador; // Instacia o Pacman

BITMAP *Buffer = NULL;
Buffer = create_bitmap(SCREEN_W,SCREEN_H);

while (!key[KEY_ESC])
{
clear_bitmap(Buffer);
textprintf_ex(Buffer, font, 0, 0, makecol(0, 255, 255),-1,"SPRITE EM
MOVIMENTO");

//Atualiza o Pacman na tela
Jogador.Atualiza(Buffer);

//Controle para Movimentao do Pacman na tela
Jogador.Controle(25);

blit(Buffer,screen,0,0,0,0,SCREEN_W,SCREEN_H);
vsync();
}

destroy_bitmap(Buffer);
delete Buffer;
allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DO CDIGO


main.cpp
Dentro desse arquivo possvel encontrar:
Referncia aos arquivos de recursos.
Inicializao da biblioteca allegro.
Referncia a classe Jogador (Pacman)
Loop principal do jogo.
Liberao dos ponteiros.
Encerramento do programa.


CDIGO...

#ifndef CJOGADOR_H
#define CJOGADOR_H

#include <allegro.h>
// Arquivo: cjogador.h

class CJogador
{

private:
BITMAP *imgJogador;
int iPosx;
int iPosy;
int iSpritex;
int iSpritey;

public:
int iLargura;
int iAltura;

CJogador();
~CJogador();
void Setax(int);
void Setay(int);
void Atualiza(BITMAP *buffer);
void Controle(int);
};

#endif

FIM DO CDIGO

Jocador.h
Arquivo de recurso responsvel por armazenar apenas a definio da classe Jogador.
Todas as caractersticas que o pacman vai possuir esto definidas nesse arquivo. So
elas:
Varivel Descrio
BITMAP *imgJogador Guarda imagem do Pacmam
int iPosx Posio x do pacman na tela
int iPosy Posio y do pacman na tela
int iSpritex Posio da animao do sprite
int iSpritey Posio da direo do sprite
int iLargura Armazena a largura de um sprite
int iAltura Armazena a altura de um sprite

Varivel Descrio
CJogador(); Construtor para iniciar as variveis da classe.
~CJogador(); Destrutor responsvel por liberar a imagem do
pacman da memria.
void Setax(int); Seta a posio x do pacman a partir de uma
velocidade passada por argumento.
void Setay(int); Seta a posio y do pacman a partir de uma
velocidade passada por argumento.
void Atualiza(BITMAP *buffer); Renderiza o pacman na tela.
void Controle(int); Controla a direo do pacman atravs das setas
do teclado.


CDIGO...

#include "cjogador.h"

// Arquivo: cjogador.cpp

static int iVelSprite = 4;

CJogador::CJogador()
{
this->imgJogador = load_bitmap("pacpac.bmp",NULL); // Sprites do PacPac
this->iPosx = 0; // Posio x do pacman na tela
this->iPosy = 0; // Posio y do pacman na tela
this->iLargura = 25; // Define a largura do sprite
this->iAltura = 25; // Define a altura do sprite
this->iSpritex = 0; // Inicia animao na posio zero.
this->iSpritey = 0; // Inicia virado para a direita
}

CJogador::~CJogador()
{
delete this->imgJogador;
}

void CJogador::Setax(int vx)
{
this->iPosx += vx;

if (vx<0) this->iSpritey = 25; // Vira Sprite para esquerda
if (vx>0) this->iSpritey = 0; // Vira o Sprite para a direita
}

void CJogador::Setay(int vy)
{
this->iPosy += vy;

if (vy<0) this->iSpritey = 50; // Vira o Sprite para Cima
if (vy>0) this->iSpritey = 75; // Vira o Sprite para Baixo
}

void CJogador::Atualiza(BITMAP *buffer)
{
if (iSpritex >= 100) iSpritex = 0;

masked_blit(imgJogador,buffer,this->iSpritex,this->iSpritey,this->iPosx,this-
>iPosy,this->iLargura,this->iAltura);
iVelSprite--;

if (iVelSprite<=0)
{
this->iSpritex += 25;
iVelSprite = 4;
}
}

void CJogador::Controle(int Vel)
{
static int Buffer_Teclado =0;
// A cada movimento reinicia o buffer do teclado.

if (Buffer_Teclado == 0)
{
if (key[KEY_UP])
{
this->Setay(-Vel);
Buffer_Teclado = 10;
}
else if (key[KEY_DOWN])
{
this->Setay(Vel);
Buffer_Teclado = 10;
}
else if (key[KEY_LEFT])
{
this->Setax(-Vel);
Buffer_Teclado = 10;
}
else if (key[KEY_RIGHT])
{
this->Setax(Vel);
Buffer_Teclado = 10;
}

}
else
{
Buffer_Teclado--;
}
}

FIM DO CDIGO

Jogador.cpp
Esse arquivo faz referencia ao arquivo de recursos Jogador.h. No entanto, ele guarda
apenas o cdigo responsvel pela movimentao do pacman na tela.
Caro leitor chegamos ao fim do entendimento da troca de sprites durante a animao.
Espero ter escrito um cdigo auto explicativo.
Se houver alguma dvida ou dificuldade favor entrar em contato com o pessoal pelo
Forum.

Abrao
BDJogos



30 - Rolagem de Cenrio ( Scroll ou Scrolling )

Existem vrias formas de se fazer um efeito de Scrolling.
Vamos aprender a fazer 3 tipos de Efeitos.
Scrolling falso
Um exemplo de scrolling falso o exemplo do espao aonde as estrelas vo passando,
umas bem lentas e outras rpidamente dando o efeito de que o cenrio est andando.
Um outro exemplo de um cenrio que tem a mesma imagem de fundo, quando o
personagem vai andando a imagem vai andando tambm, mais ela acaba sempre se
repetindo.
Vamos trabalhar com os 2 exemplos, primeiro, mostraremos nosso programa base que
mostra e limita os FPS.

CDIGO...

#include <allegro.h>

// PROGRAMA BASE

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(60) );


BITMAP *buffer = NULL;


// Criando BUFFER para double buffer
buffer = create_bitmap(800,800);

// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{
clear( buffer );

textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );

::fps_speed--;
::fps++;
}


blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}

destroy_bitmap( buffer );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...


Exemplo do espao estrelado.
O exemplo no tem muita complicao. O resultado se parece muito com os crditos de
vrios jogos ( Mega Man ).
Criamos uma classe que sempre fica verificando a posio do objeto, se o objeto est
fora da tela,
ele reposiciona o objeto para o comeo da tela com uma nova velocidade.
Preste ateno na forma como eu aloco cada objeto do array de estrelas, como eu uso
eles e como a memria desalocada.

CDIGO...

#ifndef STAR_H
#define STAR_H

// ARQUIVO: star.h
// Data: 18/08/2007

const int tamanho_total = 3;
const int velocidade_total = 15;

class Star {

private:

int velocidade;
int id;

public:

Star( int ); // construtor
~Star(); // destrutor

void iniciar( int ); // inicia o objeto
void verificar(); // verifica se no chegou no final da tela

int x;
int y;
int tamanho;

};

#endif

FIM DE CDIGO...


CDIGO...

#include <allegro.h>
#include <iostream>
#include "star.h"

// ARQUIVO: star.cpp
// Data: 18/08/2007


// construtor
Star::Star( int vid )
{
this->id = vid;

this->velocidade = 0;
this->x = 0;
this->y = 0;
this->tamanho = 0;

this->x = 1 + rand() % SCREEN_W;
this->y = this->id + rand() % ( this->id + 10 );

this->velocidade = ( 1 + rand() % (::velocidade_total) );
this->tamanho = 1 + rand() % (::tamanho_total);
}

// destrutor
Star::~Star()
{
this->velocidade = 0;
this->x = 0;
this->y = 0;
this->tamanho = 0;
}

// inicia o objeto
void Star::iniciar( int i )
{
if ( i == 0 )
{
i = 1;
}

this->y = i + rand() % ( i + 10 );

this->velocidade = ( 1 + rand() % (::velocidade_total) );
this->tamanho = 1 + rand() % (::tamanho_total);

this->x = SCREEN_W;
}

// verifica se no chegou no final da tela
void Star::verificar()
{
if ( this->x > 0 )
{

this->x -= this->velocidade;
}
else
{
this->iniciar( this->id );
}
}

FIM DE CDIGO...



CDIGO...

#include <allegro.h>
#include <iostream>
#include <ctime>
#include "star.h"

// ARQUIVO: main.cpp
// Data: 18/08/2007


// Exemplo de scrolling falso

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

srand( time(0) ); // determina a randomizao


install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(60) );


BITMAP *buffer = NULL;

int i = 0;
int total_estrelas = SCREEN_H;

Star *estrelas[total_estrelas];

// inicia as estrelas
for ( i=0; i< total_estrelas; i++ )
{
estrelas[ i ] = new Star( i );
}


// Criando BUFFER para double buffer
buffer = create_bitmap(800,800);

// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{
clear( buffer );

// imprime as estrelas na tela e verifica se ela no chegou no final da tela
for ( i=0; i< total_estrelas; i++ )
{
putpixel(buffer, estrelas[ i ]->x, estrelas[ i ]->y, makecol(255,255,255));
estrelas[ i ]->verificar();
}


textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );


::fps_speed--;
::fps++;
}


blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}

// apaga as estrelas da memoria
for ( i=0; i< total_estrelas; i++ )
{
delete estrelas[i];
}

destroy_bitmap( buffer );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...

Exemplo cenrio com imagem de fundo repetida.
Este um exemplo bastante utilizado em jogos de scroll vertical, como o Ninja Gaiden.
Faremos uma imagem de fundo passar lentamente, e uma imagem mais perto passar
bem rpido, passando a impresso de velocidade e movimentao do cenrio.
Vamos usar as seguintes imagens retiradas do Ninja Gaiden 3.

Este ser o cu, uma imagem que andar bem lentamente.
Agora vamos pegar a segunda paisagem que andar rapidamente, dando o efeito de
scroll.


Novamente iremos utilizar nosso travador de FPS.
A lgica do programa fazer copias das imagens, para que o usurio no perceba que
elas tem um inicio e um fim.
Iremos concatenar a imagem para fazer isso.


CDIGO...

#include <allegro.h>

// ARQUIVO: main.cpp
// Data: 20/08/2007


// Exemplo de scrolling falso

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(60) );


// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);

// Load das imagens .bmp ( converter de jpg para bmp )
BITMAP *img_fundo1 = NULL;
BITMAP *img_fundo2 = NULL;

img_fundo1 = load_bitmap("ceu1.bmp", NULL );
img_fundo2 = load_bitmap("cenario2.bmp", NULL );

// essas variveis so variveis auxiliares que ajudaro muito
BITMAP *fundo1 = NULL;
BITMAP *fundo2 = NULL;

fundo1 = create_bitmap( 1022, 180 );
fundo2 = create_bitmap( 780, 149 );

// estou criando o fundo em uma variavel auxiliar
blit(img_fundo1, fundo1, 0, 0, 0, 0, 511, 180 );
blit(img_fundo1, fundo1, 0, 0, 511, 0, 511, 180 );

// estou usando masked para ficar incolor a area rosa
masked_blit(img_fundo2, fundo2, 0, 0, 0, 0, 260, 149 );
masked_blit(img_fundo2, fundo2, 0, 0, 260, 0, 260, 149 );
masked_blit(img_fundo2, fundo2, 0, 0, 420, 0, 260, 149 );


// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{
clear( buffer );

masked_blit( fundo1, buffer, 0, 0, 0, 0, 1022, 180 );
masked_blit( fundo2, buffer, 0, 0, 0, 130, 780, 149 );

textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );


::fps_speed--;
::fps++;
}


blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}


destroy_bitmap( buffer );

destroy_bitmap( img_fundo1 );
destroy_bitmap( img_fundo2 );

destroy_bitmap( fundo1 );
destroy_bitmap( fundo2 );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...

Agora vamos implementar no cdigo acima, a rolagem do cenrio.
Observe no cdigo abaixo, que colamos 2 imagens iguais de fundo no buffer.. uma ao
lado da outra.
A lgica funciona da seguinte maneira.
Enquanto nosso contador for menor que o tamanho total de 1 imagem ( a mesma
imagem montada uma ao lado da outra ),
a gente vai incrementando ela e mostrando na tela a imagem na posio do contador.
Desta forma a imagem vai andando para o lado.

Para que a imagem seja repetida corretamente, a segunda imagem colada na posio
(total_fundo1*(-1))+x_fundo1)
Que igual a, -1022 + x_fundo1, isso vai fazer com que nossa segunda imagem fique
exatamente no final da primeira imagem, e isso tambm vai previnir de que o cenrio
seja quebrado.

CDIGO...

#include <allegro.h>

// ARQUIVO: main.cpp
// Data: 20/08/2007


// Exemplo de scrolling falso

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(30) );


// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);

// Load das imagens .bmp ( converter de jpg para bmp )
BITMAP *img_fundo1 = NULL;
BITMAP *img_fundo2 = NULL;

img_fundo1 = load_bitmap("ceu1.bmp", NULL );
img_fundo2 = load_bitmap("cenario2.bmp", NULL );

// essas variveis so variveis auxiliares que ajudaro muito
BITMAP *fundo1 = NULL;
BITMAP *fundo2 = NULL;

fundo1 = create_bitmap( 1022, 180 );
fundo2 = create_bitmap( 780, 149 );

// estou criando o fundo em uma variavel auxiliar
blit(img_fundo1, fundo1, 0, 0, 0, 0, 511, 180 );
blit(img_fundo1, fundo1, 0, 0, 511, 0, 511, 180 );

// estou usando masked para ficar incolor a area rosa
masked_blit(img_fundo2, fundo2, 0, 0, 0, 0, 260, 149 );
masked_blit(img_fundo2, fundo2, 0, 0, 260, 0, 260, 149 );
masked_blit(img_fundo2, fundo2, 0, 0, 520, 0, 260, 149 );
//masked_blit(img_fundo2, fundo2, 0, 0, 420, 0, 260, 149 );


// Inicio programao da rolagem
int velocidade_fundo1 = 1;
int velocidade_fundo2 = 6;

int total_fundo1 = 1022;
int total_fundo2 = 780;

int x_fundo1 = 0;
int x_fundo2 = 0;

// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{
clear( buffer );

// faz com que, antes que o segundo fundo termine, comee a imprimir o primeiro
fundo
if ( x_fundo1 < ( total_fundo1 ) )
{
x_fundo1 = x_fundo1 + velocidade_fundo1;
}
else
{
x_fundo1 = 0;
}

// vai passando o primeiro fundo
masked_blit( fundo1, buffer, x_fundo1, 0, 0, 0, 1022, 180 );

// imprime no final do primeiro fundo, e vai passando
masked_blit( fundo1, buffer, ((total_fundo1*(-1))+x_fundo1), 0, 0, 0, 1022, 180 );

if ( x_fundo2 < ( total_fundo2 ) )
{
x_fundo2 = x_fundo2 + velocidade_fundo2;
}
else
{
x_fundo2 = 0;
}

masked_blit( fundo2, buffer, x_fundo2, 0, 0, 130, 780, 149 );
masked_blit( fundo2, buffer, ((total_fundo2*(-1))+x_fundo2), 0, 0, 130, 780, 149
);

textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );

::fps_speed--;
::fps++;
}


blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}


destroy_bitmap( buffer );

destroy_bitmap( img_fundo1 );
destroy_bitmap( img_fundo2 );

destroy_bitmap( fundo1 );
destroy_bitmap( fundo2 );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...


Exemplo de scrolling verdadeiro
Imagine uma fase do Super Mario, quando o personagem chega no limite da tela, a tela
comea a andar, e os sprites de fundo comeam a se mover.
esse tipo de simulao que iremos mostrar agora.
O cdigo abaixo controlado pelo teclado. Utilize as setas para fazer o cenrio andar.
Para escrever o cdigo, primeiro precisamos saber que o personagem o centro da tela
da nossa rolagem ( ele no precisa estar no centro da tela necessariamente ).
Quando o personagem se mover, devemos mover todos os tiles do fundo na posio
oposta.
Para isso, precisamos tambm ter o tamanho total da tela, no caso, a fase do nosso jogo.
Nossa tela medir 500 px.
Ns vamos especificar o tamanho do cenario em 250 tiles.
Cada tile ter 50 px de tamanho total;
Iremos usar tambm a parte central da tela, desta forma, podemos ver o efeito de
scrolling.
Voc vai perceber que nossos cdigos esto comeando a aumentar hehehe.. Isto
normal.
A tcnica utilizada abaixo pode ser usada com um construtor de cenrios, basta entender
o algoritmo de rolagem que bem simples.

CDIGO...

#include <allegro.h>

// ARQUIVO: main.cpp
// Data: 22/08/2007

// Exemplo de scrolling verdadeiro

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(30) );

// Criando BUFFER para double buffer
BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);

// variveis comentadas no escopo do programa
const int tamanho_tela = 500;
const int inicial_tela = ( (SCREEN_W/2)-(tamanho_tela/2) );
const int cenario = 250; // tiles
const int tamanho_tile = 50;

// posio de nosso personagem
int personagem_pos = inicial_tela + 10;
int x = personagem_pos;

// auxiliares
int i = 0;
int total_for = 0;
int posicao = 0;

int posicao_cenario_inicial = inicial_tela;
int posicao_cenario = 0;



// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{

clear( buffer );

// este for faz com que seja mostrado apenas a parte do cenario visivel para o
usurio
// para isso ele s vai mostrar
// os tiles que cabem na tela ( tamanho_tela / tamanho_tile )
// mais a posio atual do cenario ( que incrementado quando se aperta uma tecla
)
// usamos o -1 para trocar o sinal da operao
total_for = ( tamanho_tela / tamanho_tile )+( posicao_cenario*(-1) );
for ( i=posicao_cenario; i<=total_for; i++ )
{
// aqui determinamos a posio correta de cada tile
// usamos a posicao_cenario_inicial para somar aonde comea o cenario
posicao = ( posicao_cenario + i ) * tamanho_tile;
posicao += posicao_cenario_inicial;

// impresso dos tiles nas posies corretas
rectfill(buffer, posicao, 230, posicao+tamanho_tile, 250, makecol(0,0,255) );
rect(buffer, posicao, 230, posicao+tamanho_tile, 250, makecol(255,0,0) );
textprintf_ex( buffer, font, posicao+1, 235, makecol(255,255,0), -1, "%d", i );
}


// esse ser nosso limite de tela
rect(buffer, inicial_tela, 10, inicial_tela+tamanho_tela, 250, makecol(0,255,0) );

// esse nosso personagem
personagem_pos = x;
rectfill(buffer, personagem_pos, 210, personagem_pos+10, 230,
makecol(255,255,0) );


textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );

::fps_speed--;
::fps++;
}


if ( key[KEY_RIGHT] )
{
// atualiza a posio do nosso personagem
if ( x < ( tamanho_tela + inicial_tela ) / 2 )
{
x++;
}
else
{
// do cenario
// nunca vai poder passar o limite do cenario
if ( (posicao_cenario ) > - ( ( cenario ) - (tamanho_tela / tamanho_tile) ) )
{
posicao_cenario--;
}
else
{
// atualiza a posio do nosso personagem
if ( x < (inicial_tela+tamanho_tela)-10 )
{
x++;
}
}
}
}

if ( key[KEY_LEFT] )
{
// atualiza a posio do nosso personagem
if ( x > ( tamanho_tela + inicial_tela ) / 2 )
{
x--;
}
else
{
// do cenario
// nunca vai poder passar o limite do cenario
if ( posicao_cenario < cenario && posicao_cenario < 0 )
{
posicao_cenario++;
}
else
{
// atualiza a posio do nosso personagem
if ( x > ( inicial_tela ) )
{
x--;
}
}
}

}

blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}


destroy_bitmap( buffer );



allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...

Teste o cdigo acima.. modifique o tamanho da tela, dos tiles ou do cenrio para ver os
efeitos.
Preste ateno na configurao da rolagem, que no exemplo est bem rpida.



30 - Scrolling de Tiles

No tutorial 26 "Utilizando Tiles" j foi explicado conceitos bsicos sobre tiles e sua
aplicao. Nesse tutorial, estarei mostrando uma tcnica chamada SCROLLING de
TILES (No importante que voc tenha lido o tutorial 26 antes de continuar neste
tutorial, pois estarei mostrando uma abordagem diferente sobre o assunto). Para
imprimir tiles na tela, usado um mapa para representar a posio de cada tile. Para
preenchermos uma tela de 640x480, e usando tiles de 32x32, precisaramos de 20 tiles
na horizontal e 15 na vertical. Com SCROLLING DE TILES, podemos ter o mapa do
tamanho que quisermos (no preciso nem dizer que o mapa representado por uma
matriz multidimensional). SCROLING DE TILES amplamente usado em jogos 2d,
como Mario ou Metroid.
Portanto, poderemos ter um mapa de tamanho qualquer, no importa a altura nem a
largura, nosso algoritmo deve imprimir os tiles na tela perfeitamente. Voc pode estar
pensando: " s imprimir todos os tiles na tela". Nada impede que voc faa isso, mas
seu jogo ficar extremamente lento. O correto imprimir somente a rea correspondente
ao tamanho da tela.
Bsico
O tutorial 26 mostrou um jeito fcil de imprimir tiles na tela. Nessa parte bsica, vou
mostrar outra forma de obter o mesmo resultado, ou seja, imprimir tiles carregando o
mapa a partir de um arquivo. Primeiro, precisamos declarar algumas constantes e
estruturas bsicas:

CDIGO...

/* Tamanho do tile */
#define TILEWH 32
typedef struct
{
BITMAP * bitmap;
} SPRITE;
typedef struct
{
SPRITE * sprite;
} TILE;
typedef struct
{
int w;
int h;
TILE ** tiles;
} MAP;
typedef struct
{
int w;
int h;
} MAPINFO;

FIM DE CDIGO...

A primeira estrutura, SPRITE, armazenar informaes do tile atual, que no nosso caso
vai ser somente esttico (imagem fixa).
A segunda estrutura, TILE, armazenar informaes sobre que tipo de SPRITE iremos
imprimir na tela.
A estrutura MAP armazenar o mapa, contendo a posio x e y da cada tile.

MAPINFO um estrutura adicional e ser explicada mais frente.
Os Tiles

Usarei tiles de 32x32px de tamanho neste tutorial. Portanto, o arquivo Bitmap deve ser
mltiplo de 32.
Poderamos carregar os tiles manualmente, mas um processo automatizado sempre
melhor, ento, criaremos uma funo para carregar os tiles a partir de um arquivo
Bitmap.
A funo ir retornar um vetor de SPRITE.

CDIGO...

/* Funo para carga de tiles */
SPRITE * load_tiles(const char * filename)
{
/* Armazenando o bitmap em uma varivel temporria */
BITMAP * tmp = load_bitmap(filename, NULL);
/* Verificando se o bitmap foi carregado */
if (tmp == NULL)
return NULL;
/* Pegando o nmero de tiles na horizontal e na vertical */
int xtiles = tmp->w / TILEWH;
int ytiles = tmp->h / TILEWH;
/* Total de tiles no bitmap */
int total = xtiles * ytiles;
/* Criando o vetor de SPRITE */
SPRITE * spr = (SPRITE *) malloc(sizeof(SPRITE) * total);
int x;
int y;
/* ndice para o vetor de SPRITE */
int i = 0;
/* Faa enquanto houver tiles na horizontal e na vertical */
for (y = 0; y < ytiles; y++)
{
for (x = 0; x < xtiles; x++)
{
/* Criando o BITMAP que vai armazenar o tile */
spr[i].bitmap = create_bitmap(TILEWH, TILEWH);
/* Copiando o pedao da imagem para o SPRITE */
blit(tmp, spr[i].bitmap, x * TILE, y * TILE, 0, 0, TILE,
TILE);
/* Prximo ndice */
i++;
}
}
/* Libere a memria alocada para o bitmap */
destroy_bitmap(tmp);
/* Retorne o vetor de SPRITE */
return spr;
}

FIM DE CDIGO...

Explicando

No cdigo acima, criamos uma rotina de carga de tiles. Um arquivo Bitmap requerido.
Para obtermos o nmero de tiles na horizontal e na vertical, basta pegar a altura e
largura do Bitmap e dividir pelo tamanho do tile.
int xtiles = tmp->w / TILEWH;
int ytiles = tmp->h / TILEWH;
Calculamos o total de tiles no bitmap
int total = xtiles * ytiles;
J temos condio de criar o vetor de SPRITE, que armazenar os tiles:
SPRITE * spr = (SPRITE *) malloc(sizeof(SPRITE) * total);
E o final: carregar os tiles do bitmap "tmp" no vetor.
int x;
int y;
int i = 0;
for (y = 0; y < ytiles; y++)
{
for (x = 0; x < xtiles; x++)
{
spr[i]->bitmap = create_bitmap(TILE, TILE);
blit(tmp, spr[i]->bitmap, x * TILE, y * TILE, 0, 0, TILE,
TILE);
i++;
}
}
Primeiro, declaramos uma varivel i, que armazenar o ndice no vetor de SPRITE
(nosso vetor de SPRITE linear).
Os dois laos de repetio FOR so usados para percorrer o bitmap "tmp" de cima para
baixo e da esquerda para a direita.

Para cada vez que o lao y for executado, o lao x ser executado N vezes.

Na prtica ficaria:
+-------+-------+-------+
| | | |
| 1 | 2 | 3 |
+-------+-------+-------+
Isso se tivssemos um BITMAP de 96x32. Se tivssemos um BITMAP de 96x96:
+-------+-------+-------+
| | | |
| 1 | 2 | 3 |
+-------+-------+-------+
| | | |
| 4 | 5 | 6 |
+-------+-------+-------+
| | | |
| 7 | 8 | 9 |
+-------+-------+-------+
Os tiles ficariam organizados nessa ordem no vetor. Para finalizar, criamos realmente o
BITMAP da estrutura SPRITE e "blitamos" o tile nele:
spr[i]->bitmap = create_bitmap(TILEWH, TILEWH);
blit(tmp, spr[i]->bitmap, x * TILEWH, y * TILEWH, 0, 0, TILEWH,
TILEWH);
Lembrando que a posio do tile definida pelos parmetros x e y dos laos.
Como nossos TILES tem 32x32 de tamanho, fica fcil encontrar sua posio no
BITMAP tmp, pois s multiplicar por 32.
O Mapa
Normalmente, tudo em um jogo colocado dentro de arquivos, no caso de mapas,
mais simples e voc ainda tem a possibilidade de criar outros mapas para seu jogo.
Pode-se usar programas como o Mappy ou Tile Studio, mas a verdade que VOC
deve fazer seu prprio editor de mapas. O mapa pode ser armazenado em arquivos texto
ou binrio.
Para usarmos arquivos texto, precisaramos criar um ANALISADOR LXICO para ler
os tokens. Escrever um analisador lxico (descente) no fcil, e outra coisa, o mapa
ficaria exposto (com qualquer editor de texto poderamos editar o mapa). Com arquivos
binrios, mais simples e para alterar o mapa ser necessrio um editor hexadecimal.
Usaremos o Mappy para criar os mapas, mas no usaremos sua API para imprimi-lo na
tela. Baixe o Mappy no endereo:
http://www.tilemap.co.uk/mappy.php
Basta descompact-lo e executar normalmente. Abra-o e uma tela como essa ser
apresentada:

Para criar um mapa, basta ir ao menu "File / New Map". Altere o tamanho do tile se
quiser, mas a configurao padro a de tiles de 32x32. Mais abaixo, coloque o
tamanho na horizontal (tiles wide) e na vertical (tiles high), lembrando que isso
significa o tamanho da tela em tiles, no em pixels. Crie um mapa com tiles de 32x32 e
a tela com 40 tiles na horizontal e 15 na vertical.
Depois de criar o mapa, s importar o tiles. Baixe os seguintes tiles (clique em cima
da imagem para fazer o download):

Agora, para importar, v no menu "File / Import", e escolha um arquivo .bmp contendo
os tiles que voc baixou ou os de sua escolha. Selecione o tile na janela direita e
depois pinte o mapa. Faa um mapa parecido com este:

Depois que o mapa estiver pronto, precisaremos gerar um arquivo.
Como no usaremos a API do Mappy, precisaremos exportar para um outro formato de
arquivo que seja fcil de abrirmos.

V no menu "Custom / Export binary file".

Uma janela abrir, basta clicar em OK e outra janela abrir.

Nela diz se voc quer ajustar os valores dos tiles (pode-se ajustar tanto para cima quanto
para baixo).
O valor "-1" o padro, mas devemos alterar para "0" pelo seguinte fato:
os tiles vazios so representados pelo nmero "0", e o nosso primeiro tile representado
pelo nmero "1", se colocarmos o valor de ajuste como "-1", nosso primeiro tile ser
"0", ou seja, ele ser um tile vazio!
Ao final, um arquivo .map ser criado. Segue-se a estrutura desse tipo de arquivo:
+----------------------+
| Cabealho |
+----------------------+
| Dados sobre a fase |
| |
| |
| |
+----------------------+
As primeiras informaes no arquivo referem-se ao tamanho do mapa (em tiles) na
horizontal e na vertical.
Usaremos a estrutura MAPINFO para obter essas informaes para depois ler o mapa.
Segue a rotina de carga de mapa:

CDIGO...

/* Rotina para carga de mapa */
MAP * load_map(const char * filename, SPRITE * spr)
{
/* Abrindo o arquivo de mapa */
FILE * file = fopen(filename, "rb");
/* Verificando se ele existe */
if (!file)
return NULL;
/* Alocando memria para o mapa */
MAP * map = (MAP *) malloc(sizeof(MAP));
/* Pegando informae sobre o mapa */
MAPINFO info;
fread(& info, sizeof(MAPINFO), 1, file);
/* Altura e largura do mapa */
map->w = info.w;
map->h = info.h;
/* Crie a matriz na vertical */
map->tiles = (TILE **) malloc(sizeof(TILE) * map->h);
int x;
int y;
int value;
for (y = 0; y < map->h; y++)
{
/* Crie a matriz na horizontal */
map->tiles[y] = (TILE *) malloc(sizeof(TILE) * map->w);
for (x = 0; x < map->w; x++)
{
/* Lendo o tipo de tile */
fread(& value, sizeof(int), 1, file);
/* Se o valor do tile for diferente de 0, atribua o
SPRITE, seno, NULL */
map->tiles[y][x].sprite = value != 0 ? & spr[value - 1] :
NULL;
}
}
/* Feche o handle de arquivo */
fclose(file);
/* Retorne o mapa */
return map;
}

FIM DE CDIGO...

Explicando
No cdigo acima, um arquivo de mapa requerido e o vetor de SPRITE contendo os
tiles.

Primeiramente, pegamos as informaes referentes ao mapa (altura e largura em tiles).
A partir da, s carregar o mapa. A leitura do mapa feita sequencialmente, quem
define a posio de cada tile so os laos de repetio FOR.

Lemos um inteiro de cada vez e verificamos se o seu valor no 0. Se for 0, o valor
NULL atribudo, seno, atribua o ponteiro para o vetor de SPRITE (lembrando que na
rotina de carga de tiles, os SPRITEs so carregados linearmente, comeando pelo ndice
0, que o primeiro tile).
Obs.: No Mappy, o primeiro tile representa o ndice 1, por isso a subtrao por 1.
Imprimindo o mapa
A rotina de impresso de mapa deste tutorial difere um pouco do tutorial 26. Se voc
reparar bem, o cdigo mostrado at agora parece ser uma extenso do allegro. Eis a
rotina de impresso de mapa:

CDIGO...

/* Rotina de impresso de mapa */
void draw_map(BITMAP * bitmap, MAP * map, int xpos, int ypos)
{
/* Posio inicial */
int xbegin = abs(xpos / TILEWH);
int ybegin = abs(ypos / TILEWH);
/* Verificando se no ultrapassa o mapa */
if (xpos > 0)
xbegin = 0;
if (ypos > 0)
ybegin = 0;
/* Posio final */
int xend = SCREEN_W / TILEWH + xbegin + 1;
int yend = SCREEN_H / TILEWH + ybegin + 1;
/* Verificando se no ultrapassa o mapa */
if (xend > map->w)
xend = map->w;
if (yend > map->h)
yend = map->h;
int x;
int y;
/* Imprima o mapa! */
for (y = ybegin; y < yend; y++)
for (x = xbegin; x < xend; x++)
if (map->tiles[y][x].sprite)
draw_sprite(bitmap, map->tiles[y][x].sprite->bitmap, x
* TILEWH + xpos, y * TILEWH + ypos);
}

FIM DE CDIGO...

Explicando
A rotina acima se prope a imprimir um MAPA no "BITMAP bitmap". As posies x e
y so tambm requeridas. Primeiro, pegamos as posies iniciais x e y de pintura da
tela. Como dito anteriormente, a tela fica sendo dividida em tiles, ento, devemos pegar
a posio do tile e no a posio na tela, portanto, devemos dividir as posies x e y
pelo tamanho do tile que estamos usando (32x32).
Se xpos for 16, dividido por 32, fica sendo 0,5. Arredondando d 0. Ento essa a
posio x inicial. O mesmo para ypos (abs() foi usando pois no adianta imprimir antes
da posio 0,0 da tela). os dois IF's verificam se as posies xpos e ypos so maiores
que 0, ento, a posio inicial x e y ficam sendo 0.
J encontramos as posies iniciais x e y, agora falta encontrar as posies finais. As
posies finais so fceis de encontrar: basta pegar o tamanho da tela em tiles (tanto na
horizontal quanto na vertical) e somar com o x e y inicial. O "+ 1" para que a rotina de
impresso imprima at para fora da tela (somente 1 tile a mais). Sem isso, os tiles no
sero impressos at que preencham a tela toda.
Sabendo as posies iniciais e finais, basta imprimir na tela. Antes de imprimir,
verificamos se o SPRITE nulo (NULL), e se no for, imprimimos ele na tela.
Encontramos a posio correta de cada tile multiplicando pelo tamanho do mesmo, ou
seja:
Tile: 0,0 - Posio: 0, 0
Tile: 0,1 - Posio: 0, 32
...
Tile: 1,1 - Posio: 32, 32
...
Acrecentamos tambm xpos e ypos posio do tile, para no dar um efeito de
MOSAICO na tela.
O Cdigo Completo
Para executar o cdigo abaixo, baixe o seguinte arquivo : mapa.map

CDIGO...

#include <allegro.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define TILEWH 32
#define SPEED 1
typedef struct
{
BITMAP * bitmap;
} SPRITE;
typedef struct
{
SPRITE * sprite;
} TILE;
typedef struct
{
TILE ** tiles;
int w;
int h;
} MAP;
typedef struct
{
int w;
int h;
} MAPINFO;
BITMAP * buffer;
SPRITE * load_tiles(const char *);
MAP * load_map(const char *, SPRITE *);
void draw_map(BITMAP *, MAP *, int, int);
int main(int argc, char ** argv)
{
allegro_init();
install_keyboard();
set_color_depth(16);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
buffer = create_bitmap(SCREEN_W, SCREEN_H);
SPRITE * spr = load_tiles("tiles.bmp");
if (!spr)
{
allegro_message("Falha ao carregar SPRITES!");
return 1;
}
MAP * map = load_map("mapa.map", spr);
if (!map)
{
allegro_message("Falha ao carregar MAPA!");
return 1;
}
int xmap = 0;
int ymap = 0;
int x = 0;
int y = 0;
while (!key[KEY_ESC])
{
if (key[KEY_LEFT])
xmap += SPEED;
if (key[KEY_RIGHT])
xmap -= SPEED;
clear(buffer);
draw_map(buffer, map, xmap, 0);
blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
}
destroy_bitmap(buffer);
allegro_exit();
return 0;
}
END_OF_MAIN();
SPRITE * load_tiles(const char * filename)
{
BITMAP * tmp = load_bitmap(filename, NULL);
if (!tmp)
return NULL;
int xtiles = tmp->w / TILEWH;
int ytiles = tmp->h / TILEWH;
int total = xtiles * ytiles;
SPRITE * spr = (SPRITE *) malloc(sizeof(SPRITE *) * total);
int x;
int y;
int i = 0;
for (y = 0; y < ytiles; y++)
{
for (x = 0; x < xtiles; x++)
{
spr[i].bitmap = create_bitmap(TILEWH, TILEWH);
blit(tmp, spr[i].bitmap, x * TILEWH, y * TILEWH, 0, 0,
TILEWH, TILEWH);
i++;
}
}
destroy_bitmap(tmp);
return spr;
}
MAP * load_map(const char * filename, SPRITE * spr)
{
FILE * file = fopen(filename, "rb");
if (!file)
return NULL;
MAP * map = (MAP *) malloc(sizeof(MAP));
MAPINFO info;
fread(& info, sizeof(MAPINFO), 1, file);
map->w = info.w;
map->h = info.h;
map->tiles = (TILE **) malloc(sizeof(TILE **) * map->h);
int x;
int y;
int value;
for (y = 0; y < map->h; y++)
{
map->tiles[y] = (TILE *) malloc(sizeof(TILE *) * map->w);
for (x = 0; x < map->w; x++)
{
fread(& value, sizeof(int), 1, file);
map->tiles[y][x].sprite = value != 0 ? & spr[value - 1] :
NULL;
}
}
fclose(file);
return map;
}
void draw_map(BITMAP * bitmap, MAP * map, int xpos, int ypos)
{
int xbegin = abs(xpos / TILEWH);
int ybegin = abs(ypos / TILEWH);
if (xpos > 0)
xbegin = 0;
if (ypos > 0)
ybegin = 0;
int xend = SCREEN_W / TILEWH + xbegin + 1;
int yend = SCREEN_H / TILEWH + ybegin + 1;
if (xend > map->w)
xend = map->w;
if (yend > map->h)
yend = map->h;
int x;
int y;
for (y = ybegin; y < yend; y++)
for (x = xbegin; x < xend; x++)
if (map->tiles[y][x].sprite)
draw_sprite(bitmap, map->tiles[y][x].sprite->bitmap, x
* TILEWH + xpos, y * TILEWH + ypos);
}

FIM DE CDIGO...

Fim
Chegamos ao final deste EXTENSO tutorial. Se houver alguma dvida, crtica ou
sugesto sobre o tutorial s ir no frum, ficarei muito grato. Num prximo tutorial,
estarei escrevendo sobre coliso com o cenrio (um dos assuntos mais comentados
sobre desenvolvimento de jogos).
Mais uma coisa: se voc quer ver a rotina de impresso de mapa trabalhar, altere o
cdigo da seguinte forma:
for (y = ybegin + 1; y < yend - 1; y++)
for (x = xbegin + 1; x < xend - 1; x++)
if (map->tiles[y][x].sprite)
draw_sprite(bitmap, map->tiles[y][x].sprite->bitmap, x *
TILEWH + xpos, y * TILEWH + ypos);
Voc pode incrementar o cenrio, imprimindo uma imagem de fundo atrs do mapa,
como um cu ou uma caverna.
Espero que tenham gostado do tutorial e at mais...


31 - Pulando e Subindo Morros

Chegamos em um dos captulos mais interessantes e tambm muito importante para
nossa linha de aprendizado.
Iremos aprender como fazer nosso personagem pular e subir morros.
Este captulo importante por que iremos introduzir a partir de agora um dos assuntos
mais complicados na programao de jogos: Matemtica e Fsica.
Nosso objetivo sempre deixar tudo muito claro, e por causa disso no iremos dar aulas
de fsica avanada aqui.
A idia deixar claro como certas coisas em jogos so feitas.
Muito jogos utilizam fsica, mais certamente, todos utilizam matemtica. Nenhum dos
dois assuntos difcil, basta que ele seja bem explicado e bem compreendido por quem
l.
O Algoritmo para fazer um personagem pular bem simples e ao mesmo tempo
sensacional.
Sensacional por que nele vemos como a fsica utilizada claramento nos jogos.
Para fazer um personagem pular, primeiro precisamos pensar como no mundo real.
O que faz com que a gente no saia voando por ai ??
A gravidade.
E quando tentamos pular, ou correr, ou se movimentar, o que nosso corpo precisa fazer
para sair do lugar?
Aplicar Fora.
Desta forma, temos que a gravidade sempre vai agir sobre nosso personagem ( assim
como no mundo real ),
e para que ele pule, basta aplicar uma fora X que ir se perder aos poucos e fazer o
objeto cair.
Veja o cdigo:
Para entender o cdigo, importante que voc j tenha lido os
seguintes tutoriais:

23 - Conceito X e Y
24 - Movendo um objeto na tela
28 - FPS - Quadros por segundo ou Frame Rate


Algoritmo de Pulo

CDIGO...

#include <allegro.h>

// Programa que simula pulos de um personagem

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(30) );

BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);

// Inicio do programa atual

// Esse ser nosso cho
const int limite_cenario = 300;

// posio do personagem
// nosso personagem ter 10 pixels
int x = 10;
int y = limite_cenario - 10;

// valida se o personagem j est no pulo
bool pulou = false;

// Gravidade: quanto maior, mais rpida ser a queda
const int gravidade = 2;

// Fora do pulo
int forca = 0;

// Lao principal
while( !key[KEY_ESC] )
{
while ( ::fps_speed > 0 )
{
clear( buffer );

// Caso o personagem nao esteja pulando
// e apertou a tecla espao
if ( key[KEY_SPACE] && pulou == false )
{
pulou = true;

// fora do pulo
forca = 30;
}

// movimentao do personagem
if ( key[KEY_RIGHT] )
{
x+=5;
}

// movimentao do personagem
if ( key[KEY_LEFT] )
{
x-=5;
}

// Isto vai fazer com que o personagem v voltado para o cho
forca = forca - gravidade;
y = y - forca;

// Esse if vai barrar nosso personagem de passar pelo cho ( limite )
if (y > limite_cenario-10)
{
y = limite_cenario-10;

pulou = false;
forca = 0;
}


textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );
textprintf_ex( buffer, font, 10, 30, makecol(255,0,0), -1, "Forca: %d", forca );

rectfill( buffer, x, y, x+10, y+10, makecol(255,255,0) );
rectfill( buffer, 0, 300, SCREEN_W, 310, makecol(255,0,0) );

::fps_speed--;
::fps++;
}

blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}

destroy_bitmap( buffer );

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...

Observe que, quanto mais fora voc der para o personagem, mais alto ele ir pular.
Quanto mais gravidade voc colocar, menor ser o tempo de pulo.
O cdigo alto explicativo, a gravidade sempre faz com que o personagem vai para
baixo ( ela exerce na fora ).
Quando o personagem quer pular, adicionamos fora, o que faz com que o personagem
v para cima.


Subindo Morros

Para fazer um personagem subir um morro, vamos utilizar o exemplo acima.
Aqui a idia j comea a complicar um pouco mais.
Quando o personagem vai subir um morro, primeiro temos que pensar em como vamos
fazer o morro.
Qual vai ser a coliso com o cenrio e de que forma o personagem vai aparecer ao subir
o morro.
Ns temos que responder cada uma dessas perguntas para resolver o problema.

Primeiro, no algoritmo de pulo, definimos um limite de cenrio, que no caso o cho.
Neste exemplo no poderemos mais fazer isto, simplesmente por que agora no teremos
mais um limite, j que agora o cho pode ser um morro de limite um pouco maior ( para
cima ou para baixo ).
Para isto precisamos fazer um jogo usando objetos para o cho que iro colidir com o
personagem e mante-lo na posio acima.
Vamos analisar uma soluo, observe o grfico:

Este grfico representa um plano cartesiano, ns temos um morro ( ou subida )
desenhada nele.
Nosso morro comea no ponto X( 0 ) e vai at o ponto X( 12 ).
Nosso morro tambm comea no ponto Y( 12 ) e vai at o ponto Y( 0 ).
Observe que o plano est como se fosse nosso monitor, quando maior o Y, mais para
baixo.
Agora imagine que nosso personagem andou at o ponto X(8).
A formula para a gente posicionar o personagem no ponto correto da subida :
( Nova posio de Y ) = (Tamanho total do morro ( no caso 12, o ponto incial Y ) ) - (
ponto atual do personagem, no caso X(8) )


Observe que essa formula s funciona com morros de pontos exatos, no caso, de 12 para
12, de 50 para 50 ou de 45 para 45.
Agora, para escrever nosso programa, pasta posicionar nosso y descontando o cho e o
tamanho do personagem.
Para fazer uma descida, basta inverter o sinal.
Veja o exemplo:

CDIGO...

#ifndef CHAO_H
#define CHAO_H

// Arquivo: chao.h
// Data: 29/08/2007

class Chao {

public:
Chao();
~Chao();

// verifica se colide com as coordenadas passadas
bool colide( int, int, int );

void setx( int ); // seta a posicao x
void sety( int ); // seta a posicao y
void set_tamanho( int ); // seta o tamanho do objeto

int getx(); // retorna posicao x
int gety(); // retorno posicao y
int get_tamanho(); // retorna tamanho do objeto

private:

int x;
int y;
int tamanho;


};

#endif

FIM DE CDIGO...



CDIGO...

#include "chao.h"

// Arquivo: chao.cpp
// Data: 29/08/2007

Chao::Chao()
{
setx(0);
sety(0);
set_tamanho(0);
}

Chao::~Chao()
{
setx(0);
sety(0);
set_tamanho(0);
}

// verifica se colide com as coordenadas passadas
bool Chao::colide( int x, int y, int tamanho )
{
if (
this->x + this->tamanho > x &&
this->x < x + tamanho &&
this->y + this->tamanho > y &&
this->y < y + tamanho
)
{
return true;
}

return false;
}

// seta a posicao x
void Chao::setx( int vx )
{
this->x = vx;
}

// seta a posicao y
void Chao::sety( int vy )
{
this->y = vy;
}

// seta o tamanho do objeto
void Chao::set_tamanho( int vtamanho )
{
this->tamanho = vtamanho;
}


// retorna posicao x
int Chao::getx()
{
return this->x;
}

// retorno posicao y
int Chao::gety()
{
return this->y;
}

// retorna tamanho do objeto
int Chao::get_tamanho()
{
return this->tamanho;
}


FIM DE CDIGO...



CDIGO...

#include <allegro.h>
#include "chao.h"

// PROGRAMA que simula subida e pulo na subida.
// Adriano Waltrick
// Arquivo: main.cpp
// Data: 06/09/2007

// variveis globais
int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade
void incrementa_speed();

int main()
{
allegro_init();
set_color_depth(16);
install_keyboard();
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

install_timer();
install_int( frame_rate, 1000 );
install_int_ex( incrementa_speed, BPS_TO_TIMER(30) );

BITMAP *buffer = NULL;
buffer = create_bitmap(800,800);

// Inicio do programa atual

// Esse ser nosso cho
const int limite_cenario = 300;

// posio do personagem
// nosso personagem ter 10 pixels
const int tamanho_personagem = 10;
int x = 10;
int y = limite_cenario - 100;

// novo y para quando estiver no morro
int novo_y = 0;

// valida se o personagem j est no pulo
bool pulou = false;

// Gravidade: quanto maior, mais rpida ser a queda
const int gravidade = 2;


// Fora do pulo
int forca = 0;
const int forca_maxima = 30;

// Variveis do cho
const int total_chao1 = 50;
const int total_chao2 = 5;
const int tamanho_chao = 30;
Chao *chao[total_chao1];
Chao *chao2[total_chao2];

// Criando as variaveis do morro de SUBIDA
const int morro1_altura = 100;
const int morro1_largura = 100;

const int morro_x = 200;
const int morro_x2 = 300;
const int morro_y = limite_cenario - tamanho_chao;
const int morro_y2 = ( limite_cenario - tamanho_chao ) - morro1_altura;

// criando um morro de descida
const int morro2_altura = 100;
const int morro2_largura = 100;

const int morro2_x = 550;
const int morro2_x2 = 450;
const int morro2_y = limite_cenario - tamanho_chao;
const int morro2_y2 = ( limite_cenario- tamanho_chao ) - morro2_altura;


// inicia o chao
int i = 0;
for ( i=0; i< total_chao1; i++ )
{
chao[ i ] = new Chao();
chao[i]->sety( limite_cenario - tamanho_chao );
chao[i]->setx( (i * tamanho_chao) + tamanho_chao );
chao[i]->set_tamanho( tamanho_chao );
}

// criando o cho em cima do morro
for ( i=0; i< total_chao2; i++ )
{
chao2[ i ] = new Chao();
chao2[i]->sety( (limite_cenario - tamanho_chao) - morro2_altura );
chao2[i]->setx( (i * tamanho_chao) + tamanho_chao + 270 );
chao2[i]->set_tamanho( tamanho_chao );
}





// Lao principal
while( !key[KEY_ESC] )
{

while ( ::fps_speed > 0 )
{

clear( buffer );

// Caso o personagem nao esteja pulando
// e apertou a tecla espao
if ( key[KEY_SPACE] && pulou == false )
{
pulou = true;

// fora do pulo inicial
forca = forca_maxima;
}

// movimentao do personagem
if ( key[KEY_RIGHT] )
{
x+=5;
}

// movimentao do personagem
if ( key[KEY_LEFT] )
{
x-=5;
}

textprintf_ex( buffer, font, 10, 10, makecol(255,0,0), -1, "FPS: %d", ::fps_antigo );
textprintf_ex( buffer, font, 10, 30, makecol(255,0,0), -1, "Forca: %d", forca );
textprintf_ex( buffer, font, 10, 40, makecol(255,0,0), -1, "x: %d y: %d", x, y );





// Isto vai fazer com que o personagem v voltado para o cho
forca = forca - gravidade;
y = y - forca;

// verifica se est no morro - SUBIDA
if ( x+tamanho_personagem >= morro_x && x+tamanho_personagem <=
morro_x2 )
{
novo_y = ( morro_y2 + (morro2_altura - tamanho_chao) ) - ( ( x-
tamanho_personagem ) - morro_x);

if ( y > novo_y )
{
y = novo_y;

pulou = false;
forca = 0;
}
}

// verifica se est no morro - DESCIDA
if ( x >= morro2_x2 && x <= morro2_x )
{
novo_y = (morro2_y2) + ( (x-tamanho_personagem) - morro2_x2 );

if ( y > novo_y )
{
y = novo_y;

pulou = false;
forca = 0;
}
}


// imprime chao e verifica colisao
for ( i=0; i< total_chao1; i++ )
{

rectfill( buffer, chao[i]->getx(), chao[i]->gety(), chao[i]->getx()+chao[i]-
>get_tamanho(), chao[i]->gety()+chao[i]->get_tamanho(), makecol(0,255,0) );

if ( i < total_chao2 )
{
rectfill( buffer, chao2[i]->getx(), chao2[i]->gety(), chao2[i]->getx()+chao2[i]-
>get_tamanho(), chao2[i]->gety()+chao2[i]->get_tamanho(), makecol(0,255,0) );
}

if ( chao[i]->colide(x, y, tamanho_personagem) == true )
{
y = chao[i]->gety() - tamanho_personagem;
pulou = false;
forca = 0;
}

if ( i < total_chao2 )
{
if ( chao2[i]->colide(x, y, tamanho_personagem) == true )
{
y = chao2[i]->gety() - tamanho_personagem;
pulou = false;
forca = 0;
}
}

}

// Esse if vai barrar nosso personagem de passar pelo cho ( limite )
if (y > limite_cenario - tamanho_personagem)
{
y = limite_cenario - tamanho_personagem;

pulou = false;
forca = 0;
}


rectfill( buffer, x, y, x+tamanho_personagem, y+tamanho_personagem,
makecol(255,255,0) );

line(buffer, morro_x, morro_y, morro_x2, morro_y2, makecol(255, 0, 0 ));
line(buffer, morro2_x, morro2_y, morro2_x2, morro2_y2, makecol(255, 0, 0 ));


::fps_speed--;
::fps++;
}

blit(buffer, screen, 0,0,0,0, SCREEN_W, SCREEN_H);
vsync();

}

destroy_bitmap( buffer );


// destroi cho 1 e 2
for ( i=0; i< total_chao1; i++ )
{
delete chao[ i ];

if ( i < total_chao2 )
{
delete chao2[ i ];
}
}

allegro_exit();
return 0;
}
END_OF_MAIN();

void frame_rate()
{
::fps_antigo = ::fps;
::fps = 0;
}

void incrementa_speed()
{
::fps_speed++;
}

FIM DE CDIGO...

Observe no cdigo acima que na lgica aprensentada:
novo_y = ( morro_y2 + (morro2_altura - tamanho_chao) ) - ( ( x-
tamanho_personagem ) - morro_x);
Ns executamas o ( x-tamanho_personagem ) - morro_x para ter o X relativo a posio
do morro.
E tambm executamos morro_y2 + (morro2_altura - tamanho_chao)
para ter o Y relativo ao Y do personagem.

Exerccio
Lendo todos os captulos at aqui, aprendemos os seguintes conceitos:
- Programao em C++ e desenvolvimento de lgica
- Como organizar o cdigo, o que muito importante
- Como funciona o loop principal de um jogo
- Como imprimir imagens na tela, e move-las
- Como fazer coliso
Com todos estes conceitos, tente praticar resolvendo os exerccios propostos abaixo:
1 - Faa um jogo da velha completo, com menu inicial.
O Jogador joga contra outro jogador. O jogo deve mostrar os pontos de cada jogador.
http://pt.wikipedia.org/wiki/Jogo_da_velha
2 - Faa um jogo de Pedra, Papel e Tesoura usando imagens.
O Jogo deve mostrar os pontos de cada jogador.
http://pt.wikipedia.org/wiki/Pedra%2C_papel%2C_tesoura
3 - Faa um jogo tipo o pong.
A raquete do jogador deve estar em baixo da tela,
e ele deve ficar rebatendo uma bola que tem sua velocidade aumentada cada vez que ela
rebate na requete.

A raquete deve ser controlada pelo teclado. Mostre quantas vezes o jogador conseguiu
rebater a bola.
Veja o jogo - http://www.zumzum.net/pong/ - Verso Java
4 - Utilizando o jogo pong do exerccio 3, mude a movimentao do teclado para
movimentao pelo mouse.
32 - O conceito do eixo Z - O mundo em 3 dimenses

Muitos jogos, desde os primeiros video games tentavam simular grficos em 3
dimenses.
Com o tempo a tcnica foi evoluindo, e o hardware dos video games tambm, at que
usar grficos em 3 dimenses ( 3D ) se tornou indispensvel.
Tudo isso comeou com os clssicos Wolfestein e Doom. E mais tarde tornando-se
obrigatrios a partir do surgimento de jogos como Super Mario 64, Quake e Resident
Evil.



Famoso jogo Wolfestein da ID Software,
um dos primeiros jogos que simulavam
com perfeio um ambiente em 3D.
Mesmo assim, os objetos eram todos
quadrades, e sem muita definio. No
existia sombra e nem luzes. Tambm no
existia efeitos de particulas.
Ainda mais famoso jogo da ID Software,
Doom ( imagem de Doom 2 )
revolucionou ainda mais.
A ambientao dele j era toda em 3D,
neste jogo j vemos efeitos de luzes e
particulas.
O Engine deste jogo foi utilizado em
vrios outros jogos posteriormente.





Super Mario 64 trouxe o principal mascote
da empresa Nintendo para o Mundo 3D. O
Jogo cheio de efeitos e cenrios gigantes.

A explorao mxima e os grficos so
muito bem trabalhados.
Quake ( imagem de Quake 2 ) foi um
outro grande sucesso da ID, mostrava
grficos avanadssimos e nesta epoca j
apelava para as placas 3D.
A partir daqui, jogos para PC exigiriam
cada vez mais fora dos hardwares.
Observe a evoluo da modelagem em 3D
deste jogo para o Wolf3D.


Famoso jogo da Capcom, Resident Evil.
Que mostrava excelentes grficos e uma jogabilidade totalmente em 3D, simulando o
mundo real.

Cada vez mais vemos jogos se mostrando muito parecidos com a realidade em que
vivemos, e com grficos to reais que torna-se obrigatrio no mercado de hoje,
aprendermos a programar jogos em 3D.
Leve em considerao tambm, que mesmo os celulares de hoje em dia esto tentando
executar Doom, fazendo com que o 3D no demore muito tambm para chegar aos
portteis.
Os Japoneses e Americanos demoraram 20 anos para dominar as
tcnicas de programao de jogos em 3D. No vai ser em 1 nico
dia em que conseguiremos o mesmo. Demoramos 31 captulos para
chegar at aqui e ainda falta bastante assunto para vermos.
Tambm preciso citar que no justo ter no Brasil cursos to caros
ensinando algo to fcil, precisamos liberar as informaes para que
o desenvolvimento de coisas novas venha de cada um, aumentando
o nvel de qualidade dos desenvolvedores Brasileiros.


Para fazer grficos em 3 Dimenses precisamos inserir no nosso plano cartesiano
normal, o eixo Z.
Teremos ento 3 eixos para trabalhar, os eixos X, Y e Z.
Leia para se lembrar : 23 - Conceito X e Y
E agora, inserimos o eixo Z, praticamente desta forma:


Olhando a figura acima podemos nos confundir, mais os pontos ainda funcionam como
antes.

O eixo Y determina a altura vindo de cima do monitor para baixo at o fim da tela. O
eixo X determina a largura, vindo do lado esquerdo do monitor para o lado direito.

E o eixo Z determina a profundidade!! Vindo da posio mais prxima para a posio
mais distante ( ou para o fundo ).

Desta forma teremos agora pontos da seguinte maneira:
int x = 10; // posio X
int y = 20; // posio Y
int z = 5; // posio Z de profundidade;
VOC PRECISA SABER...
Por padro, quando trabalhavamos com X e Y, os pontos 0,0 eram o
topo esquerdo do monitor.
Porm, quando trabalharemos com o eixo Z, os pontos X, Y e Z (
0,0,0 ) so exatamente o centro da tela.

Devido ao novo ponto Z, teremos tambm novas especificaes que precisamos saber
para poder entender como funciona o mundo 3D.
Antes de qualquer coisa, as tecnologias que trabalham em 3D especificaram conceitos
bsicos para nosso fcil entendimento.

Primeiro, tudo no mundo 3D visto por uma cmera.
Ento, no imprimiremos mais o objeto no espao da tela, a partir de agora,
imprimiremos o objeto em uma posio do mundo 3D.
Se a cmera estiver apontando para esta posio do mundo 3D em que o objeto est
impresso, ai sim ele aparecer na tela.
A rea em que a cmera est apontando ( no caso, visualizando ) conhecida como
frustum...
A partir de agora conheceremos vrios conceitos, e de extrema importncia mante-los
em nossa mente.
Tambm devido ao ponto Z, teremos vrios tipos de Coordenadas de Espaos.
O que eu quero dizer com isso?
Quero dizer que, alm das coordenadas de nossa tela, teremos vrias outras coordenadas
de espaos.
Por exemplo, teremos a coordenada da cmera ( ou observador ), teremos as
coordenadas dos objetos, dos cenrios, etc.
importante entendermos que teremos vrias coordenadas por que, nem sempre o
centro de um objeto ser exatamente no centro dele.
Quando um Modelador 3D fizer um objeto para o seu jogo, ele poder especificar qual
o centro do objeto, qual a largura do objeto e qual o tamanho do objeto. E por isso que
teremos vrias coordenadas de Espaos, por que cada objeto tem um espao prprio do
mundo 3D.
VOC PRECISA SABER...
Toda posio e orientao ( se est virado para frente, por exemplo )
de um objeto deve ser conhecida para que a gente possa fazer a
intereo com este objeto no mundo ( espao ) de nosso jogo.

Como iremos trabalhar com vrios coordenadas, em um determinado ponto teremos que
juntar tudo, e para isso iremos usar vrias funes de algebra linear. Vai ser bem fcil e
legal.
Segundo, quando trabalharmos com 3D, iremos trabalhar muito com vetores.
Um ponto X,Y,Z para a gente vai especificar uma posio, enquanto que um vetor para
a gente vai especificar um deslocamento ( displacement ).
Desta forma no se esquea que um vetor para a gente vai representar uma magnitude e
uma direo, nunca uma posio!


33 - O primeiro programa com OpenGL

Voc vai precisar instalar 2 bibliotecas no seu compilador para seguir os tutoriais daqui
para frente.
Veja como instalar em:
OpenGL - > Instalando do AllegroGL e a Glut no Dev-CPP
Ns iremos fazer todos os programas, quando possvel sempre duas vezes.
Uma vez com a ajuda do Allegro e AllegroGL e outra vez com a Ajuda do Glut, tudo
isto em cima da OpenGL.
Voc deve estar se perguntando.. u?? mais para que essa loucura?
- Simplemente por que j conhecemos a Allegro, ento ser mais fcil para a gente.

Como as funes utilizadas pela AllegroGL e a Glut so muito parecidas, vale a pena j
ir vendo como funciona a Glut para mais tarde
ter embasamento tcnico para outros tipos de programao como o DirectX.
Tentaremos fazer sempre todos os exemplos usando AllegroGL e Glut, mais nem
sempre isso vai funcionar..
Ou seja, mais desafio para mim e para voc :P ( ... e todo mundo endoidar / pirar /
enlouquecer junto )
Bom, primeiro, precisamos saber exatamente o que OpenGL:
OpenGL uma biblioteca de rotinas grficas para a impresso de grficos em 3
dimenses.
A OpenGL no uma linguagem de programao, ela uma API (Application
Programming Interface) assim como a Allegro, porm com vantagem de ter maior
velocidade para a gerao de grficos em 3 dimenses.
VOC PRECISA SABER...
A OpenGL No uma linguagem de Programao!


Nossos programas daqui para frente iro chamar funes da OpenGL para criao de
grficos primitivos, polgonos, iluminao, transparncia e efeitos especiais como
renderizao de objetos 3D.
Um programa escrito em OpenGL pode ser executado tanto no Linux quando no
Windows, isto quer dizer que a biblioteca portavel, e nosso programa tambm, porm
temos que ter em mente que a OpenGL no possu gerenciamento de janelas ou entrada
e sada de dados.
Por isto iremos usar a Allegro e a GLUT.

Como funciona a OpenGL

Eu li na Wikipedia que a OpenGL possui 250 funes, quando estivermos chamando
uma das funes o processo vai
funcionar da seguinte maneira:
1 - Os comandos sero guardados em um Buffer prprio da OpenGL.
1.2 - Alguns comandos bsicos sero processados
2 - A OpenGL vai executar a converso das matrizes e/ou vetores para os grficos (
Rasterizao )
3 - A OpenGL vai colocar a imagem final no Frame Buffer
( Frame buffer o buffer de imagens da OpenGL assim como nosso antigo BITMAP *
buffer ).
VOC PRECISA SABER...
Rasterizao o processo de converso entre representaes
vetoriais e matriciais


Primeiro Programa com AllegroGL

Meus amigos, este ser nosso programa base.
Eu estou usando praticamente o exemplo que j vem com o DevCPP.
O programa est o mais bsico possvel para que possamos entender as primeiras
funes utilizadas pelo AllegroGL e OpenGL.
Abaixo est o cdigo base e a explicao das funes:
VOC PRECISA SABER...
Este tutorial explica todas as funes utilizadas nos programas
abaixo.
A idia no gravar o nome das funes, mais apenas saber por
que elas esto ali.
Como este o programa base, voc no precisa se preocupar em
saber exatamente tudo o que o programa est fazendo, isto por
que, estas funes estaro em praticamente todos os programas.
Gravar o nome das funes pode tornar extressante a leitura do
tutorial, com o tempo iremos aprendendo como utiliza-las. Por isso,
no se preocupe com isto agora.



CDIGO...

// Exemplo de cdigo usando Allegro e AllegroGL
#include <allegro.h>
#include <alleggl.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glLoadIdentity();

allegro_gl_flip();


// Lao principal
while( !key[KEY_ESC] )
{
//Cdigo
}


allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


No programa acima, comeamos a fazer uso da exteno da Allegro, a AllegroGL
incluindo ela atravs do comando
#include <alleggl.h>
O cdigo segue como um programa com Allegro normal:
int allegro_init();
Nossa velha conhecida, funo macro responsvel por iniciar a biblioteca allegro.


int install_keyboard();
Esse comando responsvel por instalar e tornar as interrupes do teclado
disponveis para o nosso projeto.
Ns tambm j trabalhamos com ela anteriormente na Allegro.



int install_allegro_gl ()
Macro que inicia o addon AllegroGL, antes preciso ter iniciado a allegro
corretamente.



void allegro_gl_set ( int option, int value )
Nossa primeira funo de configurao nova.
Esta funo serve apenas para setar configuraes necessrias na AllegroGL.
Ela deve ser utilizanda antes de setar o modo grfico padro da Allegro.
Todas as opes para esta funo so inteiros.
No nosso programa base, iremos usar esta funo 3 vezes.
allegro_gl_set(AGL_Z_DEPTH, 8);
Seta o total de profundidade, neste caso, o total do ponto Z mximo.
allegro_gl_set(AGL_COLOR_DEPTH, 16);
Seta o total de profundidade de cores utilizadas no programa. Neste caso 16 bits.
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);
Quando setamos a opo AGL_SUGGEST, setamos uma opo especial.
Esta opo diz para o Allegro que estamos sugerindo as opes anteiores.

Caso, no for possivel usar AGL_Z_DEPTH = 8 ou AGL_COLOR_DEPTH = 16
ento o OpenGL vai procurar uma profundidade melhor para a gente.
Caso voc queria que seu programa use obrigatriamente as primeiras opes
setadas com allegro_gl_set, ento, no lugar de usar AGL_SUGGEST, use
AGL_REQUIRE.
Todas essas opes so usadas pela Allegro quando chamamos nossa conhecida
funes set_gfx_mode.
DICA...
Se voc no marcar as opes como Sugeridas (
AGL_SUGGEST ) ou requiridas ( AGL_REQUIRE ) as opes
sero ignoradas!


DICA...
Voc pode usar o separador binario | ( ou ) para setar vrias
opes ao usar o AGL_SUGGEST.




int set_gfx_mode(int card, int w, int h, int v_w, int v_h);
O comando acima responsvel por detectar a placa de vdeo, setar o tamanho da
tela em pixel e o posicionamento inicial x,y.

Como estamos usando OpenGL, temos um novo parametro para o card.
GFX_OPENGL_WINDOWED
As opes de card podem ser:
GFX_OPENGL_WINDOWED ( Windowed OpenGL graphics driver for
Allegro. )
Em janela windows.
GFX_OPENGL_FULLSCREEN ( Fullscreen OpenGL graphics driver for
Allegro. )
Em tela cheia.

GFX_OPENGL ( Non-specific OpenGL graphics driver for Allegro. )
Sem especificar.




Com todos estes comandos, configuramos nossa janela.
Agora iremos configurar as opes da Biblioteca OpenGL.
void glClear(GLbitfield mask);
Aqui ns j temos uma funo legal.
As funes apresentadas acima eram funes da Allegro ou da AllegroGL.
Esta funo, uma funo da OpenGL!!
Esta funo serve para limpar um buffer. Funciona mais ou menos como nossa
conhecida funo clear( BITMAP * ) da Allegro.
No nosso programa base, estamos limpando os buffers de
GL_COLOR_BUFFER_BIT e GL_DEPTH_BUFFER_BIT.
Essa funo pode combinar tambm vrios buffer ( do tipo GLbitfield ) com o
comando binrio | ( ou ).
GL_COLOR_BUFFER_BIT
o Buffer de cores da OpenGL.

GL_DEPTH_BUFFER_BIT
o Buffer de profundidade da OpenGL.
GL_ACCUM_BUFFER_BIT
um Buffer acumulativo de informaes
GL_STENCIL_BUFFER_BIT
Este Buffer armazena informaes especiais para cada pixel, como renderizar ou
no o mesmo.
particularmente til na criao de feitos especiais como sombreamento a partir
de fontes de luz mltiplas.




void glMatrixMode(GLenum mode);
Seta qual modo matrix ser utilizado pelo nosso programa.
Essa funo pode setar os seguintes valores:
GL_MODELVIEW
Aplica operaes em matrizes que esto sequencialmente guardadas na pilha
modelview matrix stack.

GL_PROJECTION
Aplica operaes em matrizes que esto sequencialmente guardadas na pilha
projection matrix stack.

GL_TEXTURE
Aplica operaes em matrizes que esto sequencialmente guardadas na pilha
texture matrix stack.

GL_COLOR
Aplica operaes em matrizes que esto sequencialmente guardadas na pilha color
matrix stack.





void glLoadIdentity( void);
Esta funo troca a matrix atual ( em que estamos trabalhando. No caso do
programa base, ainda no estamos trabalhando com nenhuma ) pela matrix
identidade!
Alguem ai se lembra da matrix identidade da matemtica?





void glFrustum( GLdouble left, GLdouble right, GLdouble bottom, GLdouble
top, GLdouble nearVal, GLdouble farVal);
Amigos, estava demorando para aparecer uma funo complicada.. eheheh, esta
uma delas.
Esta funo responsvel por multiplicar a matriz atual pela matriz de perspectiva.
Esta funo produz como resultado final uma projeo de perspectiva;
A matriz atual no a matriz passada na funo. A matriz atual ( ainda no
estamos trabalhando com nenhuma ) multiplicada pela matriz passada, e o
resultado colocado no lugar da matriz atual.
Basicamente essa funo vai dizer qual ser a posio de nossa camera com
relao aos objetos 3D.



void allegro_gl_flip ( void )
O OpenGL j trabalha por padro com double buffer. Ento, a gente no vai mais
precisar ficar criando buffers.
Tudo que escrito na tela pelo OpenGL colocado em um buffer de fundo.
Ao chamar a funo allegro_gl_flip o buffer de fundo se torna o buffer atual.
Cuidado, os buffers no so limpos com essa funo.


E assim temos nosso programa bsico iniciado.
Ele no mostra nada na tela at agora :)
Entender os comandos at aqui muito importante para nosso progresso.




Primeiro Programa com GLUT

Agora iremos fazer um comparativo.
Descrevemos um programa usando OpenGL com o Allegro, agora vamos fazer o
mesmo com a Glut e vamos visualizar as diferenas


CDIGO...

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

// Prototipos das funes que sero chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa Base");

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);


glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

glLoadIdentity();
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC
case 27 :
exit(0);
break;
}

glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

FIM DE CDIGO...


Precisamos ler nosso programa sempre a partir da funo main.
Alguns exemplos da internet podero mostrar outras funes antes da funo main, isto
bem normal.
Nosso programa com GLUT comea chamando a funo glutInit.
void glutInit(int *argcp, char **argv);
Essa funo serve para iniciar a biblioteca Glut.

Alguns parametros podem ser enviados para a funo, e esses parametros servem
para controlar a janela.
Veja no manual da Glut como esses parametros podem funcionar.


glutInitWindowSize e glutInitWindowPosition
Seta o tamanho inicial da janela e a posio em que ela ser mostrada.


void glutInitDisplayMode(unsigned int mode);
Seta os parametros de inicializao do OpenGL.
No nosso programa base estamos usando 3 parametros:
GLUT_RGB
Inicia a janela com modo RGB

GLUT_DOUBLE
Inicia a janela em modo double buffer da OpenGL

GLUT_DEPTH
Indica que nossa janela ter profundidade ( o eixo Z )



int glutCreateWindow(char *name);
Cria uma janela top-level window. O nome que voc dar para esta janela, ser o
nome utilizado pelo sistema operacional tambm.



void glutReshapeFunc(void (*func)(int width, int height));
Esta aqui uma funo muito importante.
Ela uma funo que recebe outra funo. Estas funes so funes muito
comuns em programas Win32, pois elas registram a chamada de outra funo.
Ao fazer o registro, sempre que um determinado comando acontecer, a funo
registrada ser chamada.
Neste caso, registramos a funo que ser chamada quando a janela for
Redimencionada.



void glutDisplayFunc(void (*func)(void));
Esta funo tambm uma funo que registra outra funo.
Ela registra uma funo que ir mostrar os grficos na tela.



void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y));
Ela registra uma funo que ir receber as interrupes de teclado.



void glutIdleFunc(void (*func)(void));
Registra uma funo para executar comandos ou executar animaes enquanto a
janela no estiver recebendo eventos do Sistema Operacional.



void glutIdleFunc(void (*func)(void));
Registra uma funo para executar comandos ou executar animaes enquanto a
janela no estiver recebendo eventos do Sistema Operacional.



glClearColor
Nossa primeira funo pura de OpenGL, ns j vimos a definio dela.
Ela vai dexar nossa tela preta.
Veja definio



glutMainLoop
Essa funo chama todos os Callbacks ( funes registradas ) para que o programa
funcione perfeitamente.
Ela vai chamar as funes de testes de teclado, de testes de redimencionamento da
janela, e at funes internas da Glut.
Esta funo no pode ser esquecida.


Alm da funo main, em um programa com GLUT ns tivemos que registrar funes
que seriam executadas pela GLUT posteriormente.
Dentro dessas funes, temos outras funes que precisamos conhecer.
A primeira funo a funo de rezise:
void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);
Essa funo especifica as novas coordenadas de janela para a OpenGL.



O resto das funes ns j conhecemos:

glMatrixMode - Veja definio
glLoadIdentity - Veja definio
glFrustum - Veja definio


A segunda funo a funo de display:
glutSwapBuffers
Ao chamar a funo o buffer de fundo da OpenGL se torna o buffer atual.


E as ltimas funes fazem uso da seguinte funo da GLUT:
glutPostRedisplay
Esta funo indica para a Glut que a janela atual precisa ser redesenhada.




Algumas explicaes

Conseguimos enfim ver todas as funes utilizadas pela AllegroGL e pela Glut para
criar uma janela usando OpenGL.
Quando voc compilar os programas acima, vai ver que uma janela preta ser aberta.
Basta apertar ESC para sair.
Praticamente as duas bibliotecas fizeram a mesma funo. A Glut de uma forma bem
diferente, se parece muito com um programa windows.
Ela registra funes para fazer a biblioteca funcionar, enquanto a AllegroGL mais
compacta e escreve apenas o que necessrio.
Voc deve ter percebido que o comando glFrustum ficou diferente para os dois
programas.
Eu fiz isso para que voc prestasse mais ateno quanto a este comando.
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0); // AllegroGL
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0); // GLUT
Voc pode usar os mesmos parametros para os 2 programas, mais no GLUT deve passar
a variavel ar devido a funo de redimencionamento.

Espero que voc tenha entendido e executado os dois programas!




34 - Imprimindo um Tringulo

Usando o programa base do captulo anterior, iremos imprimir um tringulo na tela.
Em toda tecnologia 3D, um tringulo composto por 3 pontos.
Cada ponto chamada de vrtice!
Usaremos o comando glBegin(GL_TRIANGLES) da OpenGL para imprimir nosso
triangulo.

void glBegin(GLenum mode)
void glEnd(void);
Os Comandos glBegin e glEnd so um dos comandos mais importantes da
OpenGL.
Juntos, glBegin e glEnd definem um grupo de vrtices que ser transformado em
um objeto primitivo.
O Comando glBegin pode receber os seguintes parametros:
GL_POINTS
Trata cada vrtice como se fosse um nico ponto.
GL_LINES
Trata cada par de vrtice como uma linha independente. preciso ter mais de uma
vrtice para usar este comando.

GL_LINE_STRIP
Imprime um grupo conectado de linhas, seguindo da primeira vrtice para a
ltima.
GL_LINE_LOOP
Imprime um grupo conectado de linhas, seguinda da primeira vrtice at a ltima
vrtice e voltando para a primeira.
Fazendo um ligamento entra a primeira e a ltima tambm.
GL_TRIANGLES
Trata cada trs vrtices como um tringulo independente.
GL_TRIANGLE_STRIP
Imprime um grupo conectado de tringulos. Um tringulo vai ser sempre impresso
sempre que a terceira vrtice for definida.
GL_TRIANGLE_FAN
Imprime um grupo conectado de tringulos. Ns vamos conhecer mais tarde a
diferena para o comando GL_TRIANGLE_STRIP.
GL_QUADS
Trata cada quatro vrtices como um quadrado independente.

GL_QUAD_STRIP
Imprime um grupo conectado de quadrados. Um quadrado vai ser sempre impresso
sempre que a um par de vrtices for definida aps um outro par de vrtices.
GL_POLYGON
Imprime um polgono convexo.
Ou seja, s ser possvel imprimir um polgono fechado, se nenhum de seus
ngulos internos ( do objeto final ) for maior que 180.




Para definir as vrteces do tringulo, iremos usar o comando glVertex.
glVertex
glVertex uma funo utilizada sempre com as funes glBegin / glEnd.
A funo glVertex pode definir pontos, linhas ou vrtices de polgonos.
A Cor atual, a coordenada de texturas ou nvoas tambm so definidas associando-
se com o comando glVertex.



Agora observe o cdigo para AllegroGL


CDIGO...

// Exemplo de cdigo usando Allegro e AllegroGL
#include <allegro.h>
#include <alleggl.h>

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();
allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);
// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 60.0);


glLoadIdentity();

// Colocando a cor para o triangulo
glColor3d( 255, 255, 255 );


// Iniciando nosso triangulo
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();


allegro_gl_flip();


// Lao principal
while( !key[KEY_ESC] )
{
//Cdigo
}


allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Agora executaremos os mesmos comandos no Glut.
O resultado deve ser o mesmo:

CDIGO...

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

// Prototipos das funes que sero chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa Base");

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);


glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 60.0);

glLoadIdentity() ;
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// Colocando a cor para o triangulo
glColor3d(255,255,255);

// Iniciando nosso triangulo
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();


glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC
case 27 :
exit(0);
break;
}

glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

FIM DE CDIGO...

Resultado do programa:


Observe que o tringulo impresso no limite dos nmeros, sempre partindo do centro
da tela.
Usar a profundidade neste exemplo no vai funcionar.
Sempre coloque uma cor para o objeto usando o comando glColor3d.

35 - Entendendo o sistema de coordenadas da OpenGL

No nosso ltimo programa, ns imprimimos na tela um tringulo nas seguintes
posies:
Ponto 1
x = 0.0f
y = 1.0f
Ponto 2
x = -1.0f
y = -1.0f
Ponto 3
x = 1.0f
y = -1.0f
At aqui tudo bem... o problema que quando o tringulo foi impresso, ele ocupou a
tela toda!

Mais como pode isso??
At antes de iniciarmos os estudos sobre grficos 3D, os limites da tela eram em pixels.
Geralmente o limite de x era 640 e de y era 480.
Ento como pode 1.0f equivaler 640 e ao mesmo tempo 480 ??
Bom, o que acontece que em OpenGL as representaes grficas so geradas
automaticamente a partir de conjuntos de dados, e geralmente, esses conjuntos so
representados por valores que variam de 0 at 1.

Com certeza bem estranho esse tipo de definio...
demorou mais eu achei a explicao para isso, que por sinal bem fcil.
Como a computao grfica evoluiu muito nos ltimos anos, foi necessrio desenvolver
aplicaes que possam rodar em diferentes plataformas.
Com o tempo foram criadas vrias placas aceleradores 3D ( famosas placas como
GForce e ATI Radeons da vida ) e para cada uma delas era necessrio escrever um
cdigo prprio, o que tornava o desenvolvimento ainda mais complicado.
A partir disso, foi necessrio desenvolver um padro para programas grficos que iria
facilitar escrever cdigos para diferentes tipos de hardware.
Muitos e muitos padres foram criados, mais o mais popular hoje em dia o OpenGL,
justamente a que estamos estudando.. ( isso foi pura coincidncia, eu no tinha a
mnima idia disto antes de escrever isso hehehehe ).
VOC PRECISA SABER...
A OpenGL oferece uma interface entre o software e o hardware
grfico!


Os hardwares 3D usam uma malha retangular de posies endereveis - a qual
denominada "retngulo de visualizao".
Todo hardwares de entrada e sada de grficos possu uma resoluo total, que o
nmero de pontos ( ou pixels ) horizontais e verticais que ele pode apagar ou acender.
Para trabalhar com OpenGL precisamos definir sistemas de coordenadas para
quantificar os dados sendo manipulados. Os pixels so endereados por dois nmeros
inteiros que do suas coordenadas horizontal e vertical, X, e Y.
No "retngulo de visualizao" o pixel endereado como (0,0) est geralmente no canto
inferior esquerdo.
Neste mesmo "retngulo de visualizao" o valor dcx+1 d o nmero da coluna, e
dcy+1 d o nmero da linha do pixel endereado.

As coordenadas (dcx,dcy) so chamadas de coordenadas do dispositivo, e podem
assumir apenas valores inteiros.

Coordenadas do dispositivo podem variar bastante para diferentes equipamentos, o
que levou utilizao de coordenadas normalizadas do dispositivo (NDC - normalized
device coordinates), para efeito de padronizao (ndcx,ndcy).

VOC PRECISA SABER...
NDCs so variveis reais, geralmente definidas no intervalo de 0 a 1


A vantagem da utilizao de NDCs que padres grficos podem ser discutidos usando
um sistema de coordenadas independente de dispositivos grficos especficos.
Ento.. voltando a nossa primeira pergunta, voc j deve ter entendido por que que, 1.0f
pode ser 640 ou 480.
Todos os dados grficos precisam ser transformados do sistema de coordenadas
independente para o sistema de coordenadas do dispositivo no momento de
visualizao, ou seja, do mapeamento de NDCs (reais) para as coordenadas do
dispositivo (inteiros, X e Y).
Para isto, existe a seguinte frmula:
ndc do X = ( x - "X inicial" ) / ( "X total" - "X inicial" );
ndc do Y = ( y - "Y inicial " ) / ( "Y total " - "Y inicial " );
Onde inicial o valor mnimo ( de X e Y ) e o Total o Valor Mximo ( de X e Y ).

isso..
Agora vamos brincar um pouco para entender melhor essas coordenadas, j que
praticando que se aprende.
Vamos montar um programa para testar as coordenadas:
GLfloat i = 0.0f;
glBegin(GL_POINTS);
for ( i = 1; i<=30; i++ )
{
glVertex3f( i/10, 0.0f, 0.0f);
glVertex3f( 0.0f, i/100, 0.0f);
}
glEnd();
O resultado vai ser este:

Voc pode executar o cdigo acima colocando na funo de display do glut ou antes de
dar um flip na tela com AllegroGL.
O programa acima, imprime vrios pontos distantes na horizontal.
Isso acontece por que fazemos um for de 1 at 10, e para cada ponto dividimos a
posio do ponto por 10.
Desta forma:
1 / 10 = 0,1
2 / 10 = 0,2
3 / 10 = 0,3
Os pontos ficam um pouco longe uns dos outros.
O programa acima tambm imprime vrios pontos bem prximos uns dos outros na
vertical.
Isso acontece por que fazemos um for de 1 at 10, e para cada ponto dividimos a
posio do ponto por 100.
Desta forma:
1 / 10 = 0,01
2 / 10 = 0,02
3 / 10 = 0,03
Fazendo com que os pontos fiquem uns mais prximos dos outros.
Acredito que com esse exemplo voc tenha entendido melhor o sistema de coordenadas
da OpenGL.

36 - Trabalhando com cores em OpenGL

Agora que entendemos como funciona o sistema de coordenadas, iremos entender como
manipular cores no OpenGL.
O sistema de cores da OpenGL muito parecido com o sistema de coordenadas.
Todas as cores vo de 0.0 at 1.0
Mais todas as cores so representadas no Padro RGB com 255 cores.
Se voc entendeu o tutorial anterior, vai deduzir tambm que 1.0 o limite de cores (
igual a 255 ).
Sabendo disto, vamos brincar um pouco com as cores e aprender como desenhar um
quadrado usando o tipo GL_QUADS
O programa abaixo em AllegroGL, imprime um quadrado Amarelo:


CDIGO...

// Exemplo de cdigo que imprime um quadrado usando Allegro e AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 01/10/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();
allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);
// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glColor3d(1,0,0);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glLoadIdentity();

// Colocando a cor
glColor3d( 255, 255, 0 );

// Iniciando nosso Quadrado
glBegin(GL_QUADS);
glVertex3f( 0.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 0.0f, 0.0f);
glEnd();


allegro_gl_flip();

// Lao principal
while( !key[KEY_ESC] )
{
//Cdigo
}


allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...



Bom, j conhecemos os parmetros para o glBegin GL_POINTS, GL_TRIANGLES e
agora GL_QUADS.
Estamos vendo um por um com calma para que a gente possa se acostumar com eles.
Primeiro, voc deve ter se assustado por que eu falei que deveriamos usar o sistema 0.0
e 1.0 para determinar as cores,
mais mesmo assim eu usei o sistema padro de RGB( 255, 255, 255 ).
O que acontece que o prprio OpenGL faz a converso internamente ( na definio
das vrtices no ).
Mais se voc passar os parmetros glColor3d( 1.0, 1.0, 0.0 ); vai ter os mesmos
resultados.

O GL_QUADS muito especial por que, ele mostra como os pontos devem ser
definidos para o OpenGL.
Teste o programa acima, invertendo a ordem dos pontos para a seguinte ordem:

// invertendo o primeiro pelo segundo
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 0.0f, 0.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 0.0f, 0.0f);
Resultado:


O quadrado ficar cortado, por que a forma de renderizar os pontos feita de ponto por
ponto.
Invertendo a ordem do primeiro ponto para o segundo, ao tentar montar a imagem o
OpenGL acaba cortando a parte de cima da figura.
Temos que ter muito cuidado com esse tipo de coisa.
Quando definimos uma cor fora do glBegin, a cor utilizada por todas as vrtices.
Ns tambm podemos definir cor para cada uma das vrtices separadamente.
Exemplo com Glut para no perder a prtica, baseado no exemplo acima.
O nico cdigo novo foi inserido na funo display, vamos treinar ler sempre cdigos
em AllegroGL e Glut.

CDIGO...


// Exemplo de cdigo de cores usando GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 01/10/2007
#include <GL/glut.h>
#include <stdlib.h>

// Prototipos das funes que sero chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa Base");

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);


glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 60.0);

glLoadIdentity() ;
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// Iniciando nosso Quadrado
glBegin(GL_QUADS);

glColor3d( 255, 255, 0 );
glVertex3f( 0.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);

glColor3d( 0, 0, 0 );
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 0.0f, 0.0f);

glEnd();

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC
case 27 :
exit(0);
break;
}

glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

FIM DE CDIGO...


O exemplo acima, definimos um amarelo para os 2 primeiros vrtices e um preto para
os 2 ltimos criando um efeito degrad bem legal.


Podemos tambm, definir uma cor para cada vrtice.. este conceito mais tarde vai ser
muito importante para a gente, e interessante brincar com isso tambm.
Exemplo em Glut

CDIGO...


// Exemplo de cdigo de cores usando GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 01/10/2007
#include <GL/glut.h>
#include <stdlib.h>

// Prototipos das funes que sero chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa Base");

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);


glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 60.0);

glLoadIdentity() ;
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// Iniciando nosso Quadrado
glBegin(GL_QUADS);

// amarelo
glColor3d( 255, 255, 0 );
glVertex3f( 0.0f, 0.0f, 0.0f);

// verde
glColor3d( 0, 255, 0 );
glVertex3f( 0.0f, 1.0f, 0.0f);

// vermelho
glColor3d( 255, 0, 0 );
glVertex3f( 1.0f, 1.0f, 0.0f);

// azul
glColor3d( 0, 0, 255 );
glVertex3f( 1.0f, 0.0f, 0.0f);

glEnd();

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC
case 27 :
exit(0);
break;
}

glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

FIM DE CDIGO...

Resultado muito louco:



37 - Rotacionando Objetos com OpenGL

Esse tutorial tem por finalidade mostrar de forma simples como feito o cdigo para
rotacionar uma figura geomtrica usando OpenGL.
Iremos utilizar um exemplo feito em AllegroGL e Glut como de custume.

A rotao feita atravs da funo glRotatef(ngulo, x, y, z),
que pode receber quatro nmeros float ou double (glRotated) como parmetro.
Neste caso, a matriz atual multiplicada por uma matriz de rotao de "ngulo" graus
ao redor do eixo definido pelo vetor "x,y,z" no sentido anti-horrio.
VOC PRECISA SABER...
O valor do ngulo pode variar de 0.0f a 360.0f ( lido em graus ).

Para que possamos entender melhor segue a tabela abaixo com alguns exemplos.

Cdigo Descrio
glRotatef (angulo, 0.0f, 0.0f, 0.0f); Se voc no especificar o eixo em que a
figura vai ser rotacionada a funo
usar multiplicao de matriz para
reduzir e inverter a figura geomtrica.
glRotatef (angulo, 1.0f, 0.0f, 0.0f); A figura geomtrica rotaciona no eixo
x.
como se o objeto estivesse dando
cambalhotas de frente para voc.


glRotatef (angulo, 0.0f, 1.0f, 0.0f); A figura geomtrica rotaciona no eixo
y.
como se o objeto estivesse dando
uma voltinha para voc.

glRotatef (angulo, 0.0f, 0.0f, 1.0f); A figura geomtrica rotaciona no eixo
z.
como se o objeto fosse um catavendo.
Ele roda em crculos.


Uma mesma funo glRotatef pode rotacionar mais de 1 eixo, exemplo para
rotacionar nos 3 eixos ( X, Y , Z )

glRotatef (angulo, 1.0f, 1.0f, 1.0f);

Todas as figuras geomtrica que estiverem abaixo da funo glRotatef sero rotacionadas no
mesmo sentido.
Em um tutorial prximo iremos explicar como fazer para rotazionar figuras iguais ou
diferentes em sentidos diferentes.


Ao exemplificar a funo glRotatef iremos usar o tipo GL_TRIANGLES para gerar um
tringulo na tela.

O cdigo abaixo foi implementado em AllegroGL.

CDIGO...

// Exemplo de cdigo que rotaciona objeto usando Allegro e AllegroGL
// Autor: Bruno A. Rovela
// BDJogos
// Data: 03/10/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{
float angulo = 0.0f;
float vx = 0.0f;
float vy = 1.0f;
float vz = 0.0f;

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();
allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 60.0);

// Lao principal
while( !key[KEY_ESC] )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glLoadIdentity();

glRotatef (angulo, vx, vy, vz);

glBegin(GL_TRIANGLES);
glColor3d( 255, 0, 0 );
glVertex3f( 0.0f, 0.3f, 0.0f); // Em Vermelho
glColor3d( 0, 255, 0 );
glVertex3f(-0.3f,-0.3f, 0.0f); // Em Verde
glColor3d( 0, 0, 255 );
glVertex3f( 0.3f,-0.3f, 0.0f); // Em Azul
glEnd();

if (key[KEY_X]) // Se apertar x rotaciona no eixo x
{
vx = 1.0f;
vy = 0.0f;
vz = 0.0f;
}

if (key[KEY_Y]) // Se apertar y rotaciona no eixo y
{
vx = 0.0f;
vy = 1.0f;
vz = 0.0f;
}

if (key[KEY_Z]) // Se apertar z rotaciona no eixo z
{
vx = 0.0f;
vy = 0.0f;
vz = 1.0f;
}

allegro_gl_flip();
angulo += 0.50f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM CDIGO...


O obetivo do programa acima mostrar na prtica como o objeto se comporta rotacionando
em eixos diferentes.
Note que para mudar a direo de rotao necessrio aperta X se voc quiser ver ele
rocaionar no eixo x,
apertar Y se vc quiser ver ele rotacionar no eixo Y ou Z se voc quiser ver ele rotacionar no
eixo z.
VOC PRECISA SABER...
Inverter as variveis ( x, y, z ) da funo de rotao de 1.0 para -1.0
faz com que seja invertida a forma de rotao



No inicio desse tutorial eu mencionei que o ngulo pode variar de de 0 a 360,
representados como 0.0f a 360.0f.

No entanto, o cdigo angulo += 0.50f; acrescenta 0.50f a cada renderizao de tela.
No existe nenhum tratamento para quando valor atingir 360.
Voc pode deixar o OpenGL se virar para converter e fazer o tratamento ou pode incluir uma
condio dizendo que o ngulo recebe 0.0f quando chegar em 360.0f.

A seguir iremos implementar o cdigo acima no Glut.

CDIGO...

// Exemplo de cdigo que rotaciona objeto usando GLUT
// Autor: Bruno A. Rovela
// BDJogos
// Data: 03/10/2007
#include <GL/glut.h>
#include <stdlib.h>

static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);

static float vx = 0.0f;
static float vy = 1.0f;
static float vz = 0.0f;

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(0,0);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa ROTAO");

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);

glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 60.0);

glLoadIdentity() ;
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
static float angulo = 0.0f;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glRotatef (angulo, vx, vy, vz);

// Iniciando nosso triangulo
glBegin(GL_TRIANGLES);
glColor3d(255,0,0);
glVertex3f( 0.0f, 0.3f, 0.0f); // Vermelho
glColor3d(0,255,0);
glVertex3f(-0.3f,-0.3f, 0.0f); // Verde
glColor3d(0,0,255);
glVertex3f( 0.3f,-0.3f, 0.0f); // Azul
glEnd();

angulo += 0.50f;
Sleep (1);

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 : // Caso aperte ESC sai do programa
{
exit(0);
break;
}
case 'x': // Caso aperte x rotaciona no eixo x
{
vx = 1.0f;
vy = 0.0f;
vz = 0.0f;
break;
}
case 'y': // Caso aperte y rotaciona no eixo y
{
vx = 0.0f;
vy = 1.0f;
vz = 0.0f;
break;
}
case 'z': // Caso aperte z rotaciona no eixo z
{
vx = 0.0f;
vy = 0.0f;
vz = 1.0f;
break;
}
}
glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

FIM CDIGO...



Caro leitor, chegamos ao fim do entendimento da funo responsvel por rotacionar as
figuras.
Se voc estiver com alguma dvida ou sugesto favor entrar em contato com os membros
pelo frum.

Abraos
BDJogos

ATUALIZADO: 09/10/2007

38 - Extruturando um Objeto 3D

At aqui estivemos aprendendo como desenhar pontos, um tringulo e um quadrado nas
3 coordenadas do mundo 3D.
Apartir deste tutorial, iremos demonstrar como criar realmente a extrutura de um objeto
3D.
Iremos aprender como, a partir de um triangulo, criar uma Tetraedro 3D ( a pirmide
um poliedro ) e como, a partir de um quadrado, criar um cubo 3D.
A primeira coisa que precisamos ter em mente , como um objeto em 3D.
Um cubo em 3D tem a seguinte representao grfica:

Os pontos rosas, so os nossos conhecidos pontos, ou vrtices.
Em programas de modelagem 3D esses pontos tambm podem ser chamados de Meshes
ou Vertex.
Como estudamos no captulo 34 o parmetro GL_QUADS imprime um quadrado na
tela sempre que o quarto ponto desenhado.
Esse quadrado que mostrado pela OpenGL chamado de Face.
Na figura acima, precisamos conseguir identificar, quantas faces tem um cubo:




Com isto, chegamos a concluso de que, teremos que imprimir 6 quadrados, sendo que
cada um deles vai ter 4 pontos.
Agora, vamos tentar identificar quantas faces tem um Tetraedro:





Como estudamos no captulo 34 o parmetro GL_TRIANGLES imprime um triangulo
na tela sempre que o terceiro ponto desenhado.
Esse triangulo que mostrado pela OpenGL chamado tambm de Face.
Agora precisamos identificar em quais coordenadas iremos imprimir cada ponto. E isso
no muito fcil.
No caso do Cubo 3D mais fcil, j que as coordenas so exatas.
Agora, entender as coordenadas do triangulo uma tarefa um pouco complicada.

Para escrever o Cubo eu irei criar uma primeira face da mesma forma que vinhemos
criando at aqui:
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );
Observe que os pontos esto posicionados a 0.30 pontos de distancia entre si.
Certo, esta a face da frente, para fazer a face de traz, basta adicionar 0.30 para a
coordenada Z tambm.
// face de traz
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
Beleza, acredito que tenha ficado fcil de entender agora. Mais esta a primeira vez que
usamos a coordenada Z.
Estamos tentando apresentar os pontos bases da OpenGL separadamente para que voc
no se confunda na leitura.
Usando o programa base, para fazer o cubo 3d, teremos o seguinte programa abaixo:


CDIGO...

// Exemplo de Cubo3D usando Allegro e AllegroGL - exemplo no completo
// Autor: Adriano Waltrick
// BDJogos
// Data: 09/10/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glLoadIdentity();

// Angulo para fazer o quadrado girar
GLfloat angulo;
angulo = 0.0f;

// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(angulo, 1.0f, 1.0f, 1.0f );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );


// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Voc vai perceber que o resultado do programa meio estranho..
meio que um cubo 3D renderizado errado, mostrando cores de fundo sobrepostas
pelas cores de cima,
e outra horas como se as cores de cima fossem incolor. Um resultado bem estranho.
Isto est acontecendo por que precisamos configurar o OpenGL para aceitar as
declaraes de profundidade.
Os comandos que usaremos para configurar a OpenGL sero estes:
void glShadeModel(GLenum mode);
Especifica a tcnica de sombreamento usada na hora da renderizao.
Por padro, a OpenGL interpola as cores dos objetos primitivos na hora da
impresso na tela.
Por isso aconteceu o resultado da imagem acima.
Este modo pode habilitar duas opes:
GL_FLAT
Este modo escolhe a cor de uma vrtice e traibui a todos os pixels ao seu lado.
GL_SMOOTH
praticamente a mesma coisa que o Flat, porm mais suavisado.
Independente do modo escolhido, as cores podem ser alteradas dependendo do tipo
de iluminao ( ainda no estamos usando );



void glClearDepth(GLclampd depth);
Especifica um valor que ser usado pela funo glClear para limpar o buffer de
profundidade ( depth buffer ).
Os valores podem ser 0 e 1



void glEnable(GLenum cap);
Esta funo serve para habilitar vrias funcionalidades da OpenGL
GL_DEPTH_TEST
Quando ativamos este parmetro, a OpenGL poder fazer comparaes de
profundade,
atualizando assim o buffer de profundidade ( depth buffer ).
No manual da OpenGL est escrito que,
mesmo tentando dizer que a profundidade maior que zero,
o sistema de profundidade no vai funcionar se o parmetro GL_DEPTH_TEST
no estiver habilitado.



void glDepthFunc(GLenum func);
Esta funo espeficica qual ser a funo de comparao usada para especificar o
sistema de profundidade.
As funes que podem ser escolhidas so:
GL_NEVER
Nunca ser comparado
GL_LESS
Sera comparado somente se o valor passado for menor que o valor antigo

GL_EQUAL
Sera comparado somente se o valor passado for igual ao valor antigo

GL_LEQUAL
Sera comparado se o valor passado for igual ou menor que o valor antigo

GL_GREATER
Sera comparado se o valor de profundidade passado for maior que o valor de
profundidade antigo

GL_NOTEQUAL
Compara qualquer valor que no for igual ao valor antigo

GL_GEQUAL
Compara se o valor for maior ou igual ao antigo

GL_ALWAYS
Sempre compara



void glHint(GLenum target, GLenum mode);
Especifica o modo de comportamento de alguma funo/objeto ( no prototipo da
funo, o Glenum target ).
Esta funo ser usada no nosso exemplo para melhorar a forma de renderizao.
Iremos passar o seguinte parmetro para a funo:
GL_PERSPECTIVE_CORRECTION_HINT

Indica qual a qualidade das cores, texturas e nublado ( fumaa ).
Quanto maior a qualidade, mais lento ser a aplicao.
Iremos usar a qualidade GL_NICEST.
GL_NICEST
A melhor qualidade de grficos do OpenGL.



Com todas essas funes e parmetros, teremos definido as seguintes linhas no nosso
programa:
glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

Veja o cdigo acima implementado no novo programa e seu resultado:

CDIGO...

// Exemplo de Cubo3D usando Allegro e AllegroGL - exemplo completo
// Autor: Adriano Waltrick
// BDJogos
// Data: 09/10/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();

// Angulo para fazer o quadrado girar
GLfloat angulo;
angulo = 0.0f;

// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(angulo, 1.0f, 1.0f, 1.0f );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );


// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


T ai.. o Cubo Perfeito..e girando ( por favor, compilem o exemplo ).
Agora, vamos configurar e executar o mesmo programa usando o glut!

CDIGO...


// Exemplo de Cubo3D usando GLUT - exemplo completo
// Autor: Adriano Waltrick
// BDJogos
// Data: 09/10/2007
#include <GL/glut.h>
#include <stdlib.h>

// Prototipos das funes que sero chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);

// Angulo para fazer o quadrado girar
GLfloat angulo;
// Main padro, o programa inicia aqui

int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa Base");

::angulo = 0.0f;

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);


glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);



glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(::angulo, 1.0f, 1.0f, 1.0f );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );

// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );

glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

::angulo += 0.2f;

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC
case 27 :
exit(0);
break;
}

glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

FIM DE CDIGO...


Certo.. conseguimos fazer o quadrado.
Para fazer o Tetraedo, funciona da mesma maneira.
O nico problema , achar os pontos 3D do Tetraedo, o que pode dificultar um pouco.
A primeira coisa que devemos fazer criar um tringulo no cho e achar o seu centro.
O centro dele ser o topo do poliedro. E ns sabemos que o centro est na metade dos 2
pontos de baixo.
Eu optei por iniciar como nos outros programas antigos, tendo a frente como referncia
para a primeira face.
Observe que eu usei muito como referencia o ponto mais alto do tringulo da primeira
face que 0.15.
Tende desenhar no papel para tentar visualizar o triangulo em 3D.. Desenhando um
triangulo, crie um ponto bem no centro dele, ele ser o
ponto mais alto do Tetraedo.
Use o cdigo abaixo nos displays para ver o resultado:

glBegin(GL_TRIANGLES);

// Face da Frente do tringulo, que acaba se tornando a base
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.15, 0.30, 0.00 );

// Face de baixo baixo
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.15, 0.15, 0.30 );

// Face da Esquerda
glColor3f( 0, 0 , 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.15, 0.30, 0.00 );
glVertex3f( 0.15, 0.15, 0.30 );
// Face da Direita
glColor3f( 255, 255 , 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.15, 0.30, 0.00 );
glVertex3f( 0.15, 0.15, 0.30 );

glEnd();

DICA...
Para deixar o cdigo mais fcil de ler e de forma organizada, estou
usando 2 cadas aps a virgula.
Da seguinte forma "0.00" quando estivermos trabalhando com
valores do estilo 0.10 ou 0.35.
Isto faz com que o cdigo no fique desorganizado.
Quanto mais organizado o cdigo, melhor ser para l-lo e alter-lo.



Exemplo aplicado no AllegroGL

CDIGO...

// Exemplo de Tetraedro usando Allegro e AllegroGL - exemplo completo
// Autor: Adriano Waltrick
// BDJogos
// Data: 09/10/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();

// Angulo para fazer o quadrado girar
GLfloat angulo;
angulo = 0.0f;

// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(angulo, 1.0f, 1.0f, 1.0f );



glBegin(GL_TRIANGLES);

// Face da Frente do tringulo, que acaba se tornando a base
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.15, 0.30, 0.00 );

// Face de baixo baixo
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.15, 0.15, 0.30 );

// Face da Esquerda
glColor3f( 0, 0 , 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.15, 0.30, 0.00 );
glVertex3f( 0.15, 0.15, 0.30 );
// Face da Direita
glColor3f( 255, 255 , 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.15, 0.30, 0.00 );
glVertex3f( 0.15, 0.15, 0.30 );

glEnd();


// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Uma das possveis sadas do programa:






39 - Escrevendo na tela com AllegroGL e GLUT

Ns avanamos rapidamente nossos estudos com o OpenGL,
o ato de escrever na tela a partir de agora vai ser necessrio para entender os
funcionamentos bases de nossos programas.
Existem muitos tutoriais ensinando a utilizar as funes da OpenGL, mais nenhum deles
explica detalhes importantes nos programas.
Isto acaba bloqueando o aprendizado da tecnologia, e pensando nisto nos vimos
obrigados a abordar este assunto agora!
A leitura deste tutorial obrigatria para o aprendizado da OpenGL.
E por incrvel que parea, este material escasso na internet!
Em todo jogo existe a necessidade de mostrar informaes na tela.
Essas informaes variam desde o status do personagem principal ao tempo de jogo
controlado pelo prprio cenrio.
VOC PRECISA SABER...
Mostrar informaes na tela ser imprescindvel para que possamos
compreender como funcionam algumas funes da OpenGL.


O objetivo desse artigo mostrar de uma maneira simples e objetiva como escrever na
tela usando a biblioteca AllegroGL e Glut.
A fonte utlizada no vai apresentar nenhum tipo de personalizao.
O cdigo a seguir mostra como escrever na tela usando o AllegroGL

CDIGO...

// Exemplo de como escrever na tela em AllegroGL
// Autor: Bruno A. Rovela
// BDJogos
// Data: 29/10/2007
#include <allegro.h>
#include <alleggl.h>

FONT *agl_font = NULL;

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();
allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 60.0);
glEnable(GL_TEXTURE_2D);

agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED,
250.0f);

// Lao principal
while( !key[KEY_ESC] )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glLoadIdentity();
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

allegro_gl_printf(agl_font, -0.25f, 0.20, 0.0f, makecol( 000, 255, 000), "EXEMPLO
- NOTA %d", 1000);
allegro_gl_printf(agl_font, -0.15f, 0.10, 0.0f, makecol( 255, 255, 000), " BD
JOGOS");
allegro_gl_printf(agl_font, -0.20f, 0.0f, 0.0f, makecol( 000, 000, 255), "Viva
Allegro GL");

allegro_gl_flip();
}

allegro_gl_destroy_font(agl_font);
allegro_exit();
return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Primeiramente precisamos declarar um ponteiro do tipo FONT.
O prximo passo habilitar o sistema de textura 2D do OpenGL.
Sistemas de texturas sero vistos com mais calma mais tarde... Sem ele no
conseguimos visualizar a fonte na tela.
Em seguida necessrio preencher o ponteiro com uma fonte texturizada.
VOC PRECISA SABER...
O tamanho da fonte dado em escala e se encontra no ltimo
argumento do comando allegro_gl_convert_allegro_font, nesse
caso 250.0f.
Quanto maior o valor da escala menor fica o tamanho da fonte na
tela.


Agora necessrio utilizar o comando que realmente ir escrever o texto na tela.
O comando allegro_gl_printf recebe como argumentos o tipo da fonte, posio x-y-z,
cor da fonte, texto e argumentos complementares.

E para finalizar, sempre que declaramos algum ponteiro necessrio desaloca-lo.
Nesse caso, o comando que ir desalocar a fonte da memria
allegro_gl_destroy_font.


O cdigo a seguir mostra como escrever na tela usando o GLUT

CDIGO...

// Exemplo de como escrever na tela em GLUT
// Autor: Bruno A. Rovela
// BDJogos
// Data: 15/10/2007
#include <GL/glut.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

static void display( void );
static void key( unsigned char key, int x, int y );
static void idle(void);
static void resize(int width, int height);

static void EspecialKey( int key, int x, int y );
void DesenhaTexto( char *string, float x, float y );

char texto[30];

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(0,0);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Teclado em OpenGL");

// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

strcpy(texto, "");

glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 60.0);

glLoadIdentity() ;
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

glColor3d( 0, 255, 0 );
sprintf( texto, "EXEMPLO - NOTA %d", 1000);
DesenhaTexto( texto, -0.25f, 0.20f );

glColor3d( 255, 255, 0 );
sprintf( texto, "BD JOGOS" );
DesenhaTexto( texto, -0.15f, 0.10f );

glColor3d( 0, 0, 255 );
sprintf( texto, "Viva Glut" );
DesenhaTexto( texto, -0.15f, 0.0f );

glutSwapBuffers();
}

static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
{
// Sai do programa quando o cdigo ASCII for "27" (ESC)
exit(0);
break;
}
}
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

void DesenhaTexto(char *string, float x, float y)
{
glPushMatrix();

// Posio no universo onde o texto ser colocado
glRasterPos2f(x, y);


// Exibe caracter a caracter
while(*string)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,*string++);
}

glPopMatrix();
}

FIM DE CDIGO...

No glut desenvolvemos uma funo responsvel por desenhar o texto na tela na posio
indicada pelo usurio.
O nome da funo DesenhaTexto e ela recebe como argumento um array de
caracteres (string) e a posio x,y onde ser posicionado o texto.
Ao executar o programa ele dever mostrar a mesma tela que o exemplo do AllegroGL
porm com uma fonte diferente.
A funo glRasterPos2f serve para especificar um ponto de rasterizao.


Observe que necessrio incluir:
#include <string.h>
#include <stdio.h>

A partir de agora essas funes que implementamos para escrever na tela sero
utilizadas em todos os nossos programas.


40 - Movimentando e transformando

Agora que sabemos como escrever na tela, podemos aprender as duas funes que ainda
faltam na OpenGL.
Primeiro vamos ver como movimentar um cubo 3D.
Voc deve estar pensando, no s alterar os parmetros x, y e z na hora de imprimir os
pontos ?
Sim, podemos fazer isto, mais seria uma tarefa ardua.
A OpenGL possui uma funo chamada glTranslatef que faz a movimentao e imprime
os pontos no local correto para a gente,
evitando uma trabalhera.
void glTranslatef( GLfloat x, GLfloat y, GLfloat z);
Esta funo produz uma translao ( Movimentao ). A matriz atual
multiplicada pela matriz de translao que usa os parmetros passados para a
funo.


VOC PRECISA SABER...
Para entender este captulo e seus cdigos, importante ter lido os
contedos citados abaixo:
- Utilizando teclado com GLUT

39 - Escrevendo na tela com AllegroGL e GLUT
38 - Extruturando um Objeto 3D




O cdigo a seguir mostra como movimentar um cubo 3D ( que gira sobre seu proprio
eixo ) nos eixos X e Y usando o AllegroGL
Teste o programa usando as teclas direcionais.

CDIGO...

// Exemplo de como movimentar um cubo ( que gira sobre seu eixo ) em AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 05/11/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);

// Criando uma FONT para poder escrever na tela as variveis X e Y
FONT *agl_font = NULL;
glEnable(GL_TEXTURE_2D);
agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED,
250.0f);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();

// Angulo para fazer o quadrado girar
GLfloat angulo;
angulo = 0.0f;

// Posies X e Y do quadrado
GLfloat x;
GLfloat y;

// variveis temporrias
GLfloat x_atual;
GLfloat y_atual;


// Iniciamos todas
x = y = x_atual = y_atual = 0.0f;

// Buffer de teclado
int buffer_teclado = 0;
const int iCiclo = 30;



// Lao principal
while( !key[KEY_ESC] )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();


if(buffer_teclado == 0)
{

if ( key[KEY_LEFT] )
{
x -= 100;
buffer_teclado = iCiclo;
}

if ( key[KEY_RIGHT] )
{
x += 100;
buffer_teclado = iCiclo;
}

if ( key[KEY_UP] )
{
y += 100;
buffer_teclado = iCiclo;
}

if ( key[KEY_DOWN] )
{
y -= 100;
buffer_teclado = iCiclo;
}


}
else
{
buffer_teclado--;
}


// Imprimimos as variaveis X e Y
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

allegro_gl_printf(agl_font, -0.9f, 0.9f, 0.0f, makecol( 000, 255, 000), "Variavel X:
%f", x );
allegro_gl_printf(agl_font, -0.9f, 0.8f, 0.0f, makecol( 000, 255, 000), "Variavel Y:
%f", y );


allegro_gl_printf(agl_font, -0.9f, 0.7f, 0.0f, makecol( 000, 255, 000), "Objeto X:
%f", x_atual );
allegro_gl_printf(agl_font, -0.9f, 0.6f, 0.0f, makecol( 000, 255, 000), "Objeto Y:
%f", y_atual );

// atualiza a variavel do objeto de acordo com o X e Y
x_atual = x / 640;
y_atual = y / 480;



// Posiciona o prximo objeto
glTranslatef( x_atual, y_atual, 0 );


// Rotaciona o prximo objeto
glRotatef(angulo, 1.0f, 1.0f, 1.0f );


// Imprime o CUBO
glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );


// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();


FIM DE CDIGO...

O cdigo acima auto-explicativo .
Sempre que apertamos as teclas direcionais, o objeto ir se movimentar no plano (x,y).
Eu coloquei ele girando em seu prprio eixo para demonstrar a diferena entre as
funes.
O cdigo a seguir mostra como movimentar um cubo 3D ( que gira sobre seu proprio
eixo ) nos eixos X e Y usando o GLUT

CDIGO...

// Exemplo de como movimentar um cubo ( que gira sobre seu eixo ) em GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 20/11/2007
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <GL/glut.h>
#include <stdlib.h>

// Prototipos das funes que sero chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void EspecialKey(int key, int x, int y);
static void idle(void);
static void resize(int width, int height);
void DesenhaTexto( char *string, float x, float y );

// Angulo para fazer o quadrado girar
GLfloat angulo;

// Posies X e Y do quadrado
GLfloat x;
GLfloat y;

// variveis temporrias
GLfloat x_atual;
GLfloat y_atual;

// Texto a ser desenhado
char texto[30];


// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Programa Base");

// iniciamos os valores
::angulo = 0.0f;
::x = ::y = ::x_atual = ::y_atual = 0;

// iniciamos texto
strcpy(texto, "");


// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutSpecialFunc(EspecialKey);
glutIdleFunc(idle);


glClearColor(0,0,0,0);
glutMainLoop();

return EXIT_SUCCESS;
}

// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);



glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();
}

// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


glColor3d( 0, 255, 0 );
sprintf( texto, "Variavel X: %f", ::x);
DesenhaTexto( texto, -0.9f, 0.9f );

sprintf( texto, "Variavel Y: %f", ::y);
DesenhaTexto( texto, -0.9f, 0.8f );

sprintf( texto, "Cubo X: %f", ::x_atual);
DesenhaTexto( texto, -0.9f, 0.7f );

sprintf( texto, "Cubo Y: %f", ::y_atual);
DesenhaTexto( texto, -0.9f, 0.6f );


// atualiza a variavel do objeto de acordo com o X e Y
::x_atual = ::x / 640;
::y_atual = ::y / 480;


// Posiciona o prximo objeto
glTranslatef( ::x_atual, ::y_atual, 0 );


// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(::angulo, 1.0f, 1.0f, 1.0f );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );

// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );

glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

::angulo += 0.2f;

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC
case 27 :
exit(0);
break;
}

glutPostRedisplay();
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}


static void EspecialKey(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_UP: // Caso direcional para CIMA - Aumenta valor de vy
{
::y += 100;
}
break;

case GLUT_KEY_DOWN: // Caso direcional para BAIXO - Diminui valor de vy
{
::y -= 100;
}
break;

case GLUT_KEY_LEFT:
{
::x -= 100;
}
break;

case GLUT_KEY_RIGHT:
{
::x += 100;
}
break;
}

}


void DesenhaTexto(char *string, float x, float y)
{
glPushMatrix();

// Posio no universo onde o texto ser colocado
glRasterPos2f(x, y);


// Exibe caracter a caracter
while(*string)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,*string++);
}

glPopMatrix();
}


FIM DE CDIGO...

O exemplo do GLUT muito importante!
Observe que nele usamos a nova funo, usamos a funo de escrever na tela e as
funes de manipulao de teclado.
O restante do cdigo muito parecido com o do AllegroGL, entender a abordagem
prtica das duas bibliotecas faz com que no tenhamos preconceitos com novas
bibliotecas ( SDL, Directx, Ogre ) que poderemos vir a aprender ou ser obrigados a usar
mais tarde.
Agora iremos conhecer uma funo para escalar nosso objeto:
void glScalef(GLfloat x, GLfloat y, GLfloat z);
Esta funo produz um fator no uniforme de escala ( Diminui ou aumenta ). A
matriz atual multiplicada pela matriz de escalar que usa os parmetros passados
para a funo.



O cdigo a seguir mostra como aumentar e diminuir um cubo 3D ( que gira sobre seu
proprio eixo ) nos eixos X e Y usando o AllegroGL
Teste o programa usando as teclas "A" e "Z".


CDIGO...

// Exemplo de como aumentar ou diminuir o tamanho de um cubo ( que gira sobre seu
eixo ) em AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 20/11/2007
#include <allegro.h>
#include <alleggl.h>

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);

// Criando uma FONT para poder escrever na tela as variveis X e Y
FONT *agl_font = NULL;
glEnable(GL_TEXTURE_2D);
agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED,
250.0f);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();

// Angulo para fazer o quadrado girar
GLfloat angulo;
angulo = 0.0f;

// Valor de Escala
GLfloat escala;
escala = 1.0f;

// Buffer de teclado
int buffer_teclado = 0;
const int iCiclo = 30;



// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();



if(buffer_teclado == 0)
{

if ( key[KEY_A] )
{
escala += 1.0f;
buffer_teclado = iCiclo;
}

if ( key[KEY_Z] )
{
escala -= 1.0f;
buffer_teclado = iCiclo;
}




}
else buffer_teclado--;


// Imprimimos as variaveis X e Y
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

allegro_gl_printf(agl_font, -0.9f, 0.9f, 0.0f, makecol( 000, 255, 000), "Escala: %f",
escala );




// Posiciona o prximo objeto
glScalef( escala, escala, escala );


// Rotaciona o prximo objeto
glRotatef(angulo, 1.0f, 1.0f, 1.0f );


// Imprime o CUBO
glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );


// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );


glEnd();



// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Observe que no exemplo acima estamos escalando em X, Y e Z. Isto d a impresso de
Zoom.
Um detalhe importante que temos que observar :

- Para aumentar a altura do objeto, devemos manter( salvar ) os parametros antigos de X
e Z iguais.
Exemplo: glScalef( 10, 50, 10 );
- Para aumentar a largura do objeto, devemos manter( salvar ) os parametros antigos de
Y e Z iguais.
Exemplo: glScalef( 50, 10, 10 );
Aumentar a profundidade de nosso objeto no vai funcionar por enquanto.
As teclas A e Z so geralmente utilizadas para fazer zoom.
Porm, o que fizemos acima no um zoom, na verdade estamos aumentando o
tamanho do objeto.
O efeito de zoom seria dado usando o comando glTranslatef passando como parametro
o eixo Z.
Porm, se fizermos isso agora no vai funcionar.
No podemos ver as modificaes dos parametros Z das funes por que a OpenGL tem
por padro a viso Ortogonal.
Voc precisa saber ...
Orthographic view / Viso Ortogonal
Em uma viso ortogonal todos os pontos do objeto so
perpendiculares ao plano de viso, e so projetados em paralelo.
Em geometria, perpendicularidade (ou ortogonalidade) uma noo
que indica se dois objectos (retas ou planos) fazem um ngulo de
90.


Este modo de viso ortogrfica muito parecido com os jogos Isomtricos.
A perspectiva do tipo isomtrica ocorre quando o observador est situado no infinito (e
portanto, as retas projetantes so paralelas umas s outras) e incidem
perpendicularmente ao Plano de Quadro ( Wikipedia ).
Exemplo de Projeo Ortogrfica do Blender 3D:
Na imagem abaixo vemos um plano com um cubo. Observe que as linhas de fundo do
programa esto sempre no mesmo angulo.

Exemplo de Projeo Perspectiva do Blender 3D:
Observe que esta projeo como o nosso olho v.. voltada ao horizonte.

Levando isto em considerao, ao tentar modificar o parametro de Z com o translate na
nossa viso atual, no iremos perceber o zoom.
Para perceber o zoom devemos fazer uma projeo perspectiva.
No se esquea que, quando aplicamos glRotate, glTranslate e glScale estamos
modificando as coordenadas do mundo 3D e no um objeto em si ( grupo de vertices )..
Isto muito importante para entender o sistema de cameras.



41 - Entendendo o sistema de Cmera

Este um dos captulos mais difceis de se entender.
Aps aprender as trasnformaes do plano devemos ser capazes de modificar nosso
plano de viso ( nossa cmera ).
- A cmera aponta para ( foca ) o que estamos vendo na cena.
Para movimentar a cmera devemos fazer trasnformaes ( glRotate, glTranslate ). A
chave destas transformaes so duas matrizes da OpenGL.
As trasnformaes tornam possveis projees 3D em coordenadas 2D de nossa tela.
A OpenGl nos fornece 3 tipos de transformaes:

1 - De viso
Especifica principalmente a localizao da camera.
Tambm responsvel por aumentar ou diminuir a rea aonde pode ser desenhado.
2 - De Modelagem
Movimenta os objetos pela cena e descreve as transformaes

3 - De Projeo
Especifica as rederizaes e o tamanho das impresses de tela
Neste captulo iremos aprender como modificar o sistema de coordenadas salvando o
sistema de coordenadas original.
Para isto usamos o comando glPushMatrix(); e glPopMatrix();
void glPushMatrix(void); e void glPopMatrix(void);
glPushMatrix armazena a matriz atual.
glPopMatrix retira da memria a matriz e da um replace na matriz atual.
Usando esses 2 comandos podemos rotacionar ( ou transformar em qualquer
sentido ) o plano sem mexer no antigo plano que j pode ter sido rotacionado( ou
transformado ) de alguma maneira.


Transformaes de Viso - Viewing Transformations
Primeiro precisamos entender nosso pontos de vista real no plano cartesiano.
Isto deve estar bem claro para a gente que j est programando em OpenGL..

Olhando para o monitor, estamos em linha reta ao eixo Z e a 90 graus do eixo X e Y.

A transformao de visualizao a primeira a ser realizada, pois ela determina a
posio da cena.
A posio de origem da cena na OpenGL ( 0,0,0 ).
Usando a transformao de viso podemos colocar o ponto de observao aonde a gente
precisa que ele esteja, e apontando para a direo aonde a gente quiser ( Imagine a
camera de Resident Evil ).
determinando uma transformao de viso que inserimos uma cmera em algum
ponto de nosso mundo 3D.

Transformaes de Modelagem - Modeling Transformations
basicamente o que fizemos no capitulo 40, onde manipulamos um objeto em
particular.
Com este tipo de transformao podemos rotacionar, aumentar ou diminuir e
movimentar objetos.

Transformaes de Projeo - Projection Transformations
a ltima transformao aplicada que serve para orientar a visualizao da cena.
Como j vimos, existem dois tipos de projeo, a ortogrfica e a perspectiva.
Na projeo ortogrfica, todos os poligonos so desenhados na tela relativo ao tamanho
da tela.
Na projeo perspectiva vemos os objetos como se simula-se a viso da vida real, para o
horizonte...
Na projeo perspectiva, os objetos mais longe so menores do que os objetos que esto
mais prximos.
Em nossos jogos com certeza iremos usar a Projeo Perspectiva.
Exemplo de Projeo Ortogrfica do Blender 3D:
Na imagem abaixo vemos um plano com um cubo. Observe que as linhas de fundo do
programa esto sempre no mesmo angulo.

Exemplo de Projeo Perspectiva do Blender 3D:
Observe que esta projeo como o nosso olho v.. voltada ao horizonte.



Usando a Matriz de Projees
Podemos ir alterando as matrizes de modelagem e projeo selecionando elas antes.
Por exemplo:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Todas as modificaes sero feitas na matriz de Modelview.
Desde os primeiros captulos sobre OpenGL vinhemos usando a projeo Ortogonal.
Isto por que a OpenGL no nos fornece os ajustes necessrios para escalonamentos e
perspectivas,
sendo que ns mesmos teremos que fazer isto.
Para criar um sistema de projeo perspectiva, precisamos usar um Frustum ( A rea em
que a cmera est apontando ( no caso, visualizando ) conhecida como frustum)...
Imagem do Frustum:

A funo que contrala o frustum ns j conhecemos:
void glFrustum( left, right, bottom, top, nearVal, farVal);
Com a AllegroGL podemos controlar apenas o glFrustum.
No AllegroGL no existe funo de controle de ngulo de cmera, s existe a funo
glFrustum do OpenGL.. ento,
em AllegroGL podemos mexer a cmera, mais no podemos alterar o ngulo de viso.
Na prpria OpenGL no existe essa funo.

Com o GLUT temos 2 outras funes muito interessantes para trabalhar com a cmera:
void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear,
GLdouble zFar);
Observe que tem quase os mesmos parametros do glFrustum.
Esse comando posiciona a camera perspectivamente ao angulo definido em fovy

void gluLookAt( GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble
centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble
upY, GLdouble upZ);
Define uma transformao da Cmera.
Transformando a camera, posicionamos ela mais fcilmente.

No exemplo abaixo temos um programa relativamente simples.
Neste programa em AllegroGL criei uma struct CAMERA que ter todos os valores de
configurao da cmera para o prximo exemplo.
Eu iniciei a cmera com os seguintes valores.. muito importante observar isto muito
bem:
cam.left = -01.0f;
cam.right = 01.0f;
cam.top = 01.0f;
cam.bottom = -01.0f;
cam.vnear = 01.0f;
cam.vfar = 10.0f;
Observe que a cmera est olhando exatamente para os eixos iniciais da OpenGL.
Apenas vnear e vfar est com valores diferentes pois eles indicam a profundidade da
cena.
Nossa profundidade comear em 1.0f ( Inicio da tela ) e terminar em 10.0f ( Fundo da
tela );
Usando as Teclas A e Z o objeto translocado para a nova posio criando um sistema
de zoom perfeito.
Observe que para fazer isto tambm tivemos que alterar nossa iniciao da cmera:
Ao invez de iniciar a cmera com Modelview, iniciamos ela com Projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

CDIGO...

// Exemplo de Zoom com AllegroGL sem funes especiais do GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 22/11/2007
#include <allegro.h>
#include <alleggl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

struct CAMERA
{
GLfloat left, right;
GLfloat top, bottom;
GLfloat vnear, vfar;
};

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

CAMERA cam;
cam.left = -01.0f;
cam.right = 01.0f;
cam.top = 01.0f;
cam.bottom = -01.0f;
cam.vnear = 01.0f;
cam.vfar = 10.0f;

glFrustum( cam.left, cam.right, cam.bottom, cam.top, cam.vnear, cam.vfar );


glShadeModel( GL_SMOOTH );
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );


// Iniciando matrix de objetos
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glEnable(GL_TEXTURE_2D);
FONT *agl_font = NULL;
agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED,
250.0f);

// Aplicao do Zoom
int Buffer_teclado = 0;
GLfloat posicao_z = -1.0f;

// para o quadrado girar
GLfloat angulo;
angulo = 0.0f;


// Lao principal
while( !key[KEY_ESC] )
{

if (Buffer_teclado == 0)
{

// Aumenta zoom
if ( key[KEY_A] )
{
posicao_z += 0.1f;
Buffer_teclado = 20;
}

// Diminui zoom
if ( key[KEY_Z] )
{
posicao_z -= 0.1f;
Buffer_teclado = 20;
}

}
else
{
Buffer_teclado -= 1;
}



glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glLoadIdentity();
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
allegro_gl_printf(agl_font, 0, 0.50, -1.01f, makecol( 000, 255, 000), "Valor %f",
posicao_z );



// Adiciona posio Z ao objeto
glTranslatef( 0, 0, posicao_z );

// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(angulo, 1.0f, 1.0f, 1.0f );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );


// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Execute o programa acima.
Agora preste muita ateno a alguns resultados:
1 - Quando iniciamos o programa, a imagem que aparece a seguinte:

Isto est acontecendo por que o quadrado est posicionado da seguinte maneira:

Observe que a viso da camera comea em 1.0, e por isso ela no consegue mostrar todo
o quadrado

2 - Se precionarmos Z, o Zoom ser diminuido:

Neste ponto, o quadrado est dentro da viso de nossa camera

Se precionarmos muito a tecla Z at o valor chegar a -10.1 , o quadrado no ir mais
aparecer na tela, pois ele chegou no limite da viso especificado para nossa cmera.

No cdigo abaixo, vamos fazer a movimentao da viso da cmera.
Quando forem apertadas as teclas direcionais, a cmera ir se mover ( observe que, no
o quadrado que se move );
Para isso, temos que novamente voltar a trabalhar com a matrix de projeo.

CDIGO...

// Exemplo de Zoom com AllegroGL sem funes especiais do GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 22/11/2007
#include <allegro.h>
#include <alleggl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

struct CAMERA
{
GLfloat left, right;
GLfloat top, bottom;
GLfloat vnear, vfar;
};

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

CAMERA cam;
cam.left = -01.0f;
cam.right = 01.0f;
cam.top = 01.0f;
cam.bottom = -01.0f;
cam.vnear = 01.0f;
cam.vfar = 10.0f;

glFrustum( cam.left, cam.right, cam.bottom, cam.top, cam.vnear, cam.vfar );

// Iniciando matrix de objetos
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel( GL_SMOOTH );
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glEnable(GL_TEXTURE_2D);
FONT *agl_font = NULL;
agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED,
250.0f);

// Aplicao do Zoom
int buffer_teclado = 0;
GLfloat posicao_z = -3.0f;

// para o quadrado girar
GLfloat angulo;
angulo = 0.0f;


// Lao principal
while( !key[KEY_ESC] )
{

if (buffer_teclado == 0)
{

// Aumenta zoom
if ( key[KEY_A] )
{
posicao_z += 0.1f;
buffer_teclado = 20;
}

// Diminui zoom
if ( key[KEY_Z] )
{
posicao_z -= 0.1f;
buffer_teclado = 20;
}

if ( key[KEY_UP] )
{
cam.top -= 0.1f;
cam.bottom -= 0.1f;
buffer_teclado = 10;
}

if ( key[KEY_DOWN] )
{
cam.top += 0.1f;
cam.bottom += 0.1f;
buffer_teclado = 10;
}

if ( key[KEY_LEFT] )
{
cam.left += 0.1f;
cam.right += 0.1f;
buffer_teclado = 10;
}

if ( key[KEY_RIGHT] )
{
cam.left -= 0.1f;
cam.right -= 0.1f;
buffer_teclado = 10;
}

if ( buffer_teclado == 10 )
{
// Iniciando a camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum( cam.left, cam.right, cam.bottom, cam.top, cam.vnear, cam.vfar );


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
}
else
{
buffer_teclado -= 1;
}






glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glLoadIdentity();
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
allegro_gl_printf(agl_font, 0, 0.50, -1.01f, makecol( 000, 255, 000), "Valor %f",
posicao_z );



// Adiciona posio Z ao objeto
glTranslatef( 0, 0, posicao_z );

// funo de rotao, estamos rotacionando em todos os ngulos
glRotatef(angulo, 1.0f, 1.0f, 1.0f );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.00, 0.00 );


// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );

// face de cima
glColor3f( 255, 255 , 255 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.30, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );
glVertex3f( 0.30, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.30, 0.00 );
glVertex3f( 0.00, 0.30, 0.30 );
glVertex3f( 0.00, 0.00, 0.30 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 0.30, 0.00, 0.00 );
glVertex3f( 0.30, 0.30, 0.00 );
glVertex3f( 0.30, 0.30, 0.30 );
glVertex3f( 0.30, 0.00, 0.30 );


glEnd();

// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Observe que a cmera sempre est apontando para frente!


A situao "A" e "B" indicam como seria a movimentao da cmera....


Criando uma Projeo com ngulo de cmera diferenciado
Nosso prximo desafio entender como fazer isto:




CDIGO...

// Exemplo de Cmera Simples com AllegroGL COM funes especiais do GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 22/11/2007
#include <allegro.h>
#include <alleggl.h>
#include <GL/Glut.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

struct CAMERA
{
GLfloat left, right;
GLfloat top, bottom;
GLfloat vnear, vfar;

GLfloat x, y, z;
GLfloat lookx, looky, lookz;
};

int main()
{
// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

CAMERA cam;
cam.left = -01.0f;
cam.right = 01.0f;
cam.top = 01.0f;
cam.bottom = -01.0f;
cam.vnear = 01.0f;
cam.vfar = 10.0f;

glFrustum( cam.left, cam.right, cam.bottom, cam.top, cam.vnear, cam.vfar );


// Iniciando matrix de objetos
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// isto ir fazer nosso efeito de perspectiva inicial
cam.x = 0;
cam.y = 5;
cam.z = 5;

cam.lookx = 0;
cam.looky = 0;
cam.lookz = 0;




glShadeModel( GL_SMOOTH );
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );



glEnable(GL_TEXTURE_2D);
FONT *agl_font = NULL;
agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED,
250.0f);

// Aplicao do Zoom
int buffer_teclado = 0;
GLfloat posicao_z = -2.0f;

// para o quadrado girar
GLfloat angulo;
angulo = 0.0f;



// Lao principal
while( !key[KEY_ESC] )
{

if (buffer_teclado == 0)
{
// move posio do olho da camera pelo eixo Z
if ( key[KEY_Z] )
{
cam.z += 0.1f;
buffer_teclado = 10;
}

// move posio do olho da camera pelo eixo Z
if ( key[KEY_X] )
{
cam.z -= 0.1f;
buffer_teclado = 10;
}

// move posio do olho da camera pelo eixo X
if ( key[KEY_A] )
{
cam.x -= 0.1f;
buffer_teclado = 10;
}

// move posio do olho da camera pelo eixo X
if ( key[KEY_D] )
{
cam.x += 0.1f;
buffer_teclado = 10;
}

// move posio do olho da camera pelo eixo Y
if ( key[KEY_W] )
{
cam.y -= 0.1f;
buffer_teclado = 10;
}

// move posio do olho da camera pelo eixo Y
if ( key[KEY_S] )
{
cam.y += 0.1f;
buffer_teclado = 10;
}



// Aumenta Zoom
if ( key[KEY_Z] )
{
posicao_z += 0.1f;
buffer_teclado = 20;
}

// Diminui zoom
if ( key[KEY_X] )
{
posicao_z -= 0.1f;
buffer_teclado = 20;
}

// move a camera
if ( key[KEY_UP] )
{
cam.top -= 0.1f;
cam.bottom -= 0.1f;
buffer_teclado = 10;
}

if ( key[KEY_DOWN] )
{
cam.top += 0.1f;
cam.bottom += 0.1f;
buffer_teclado = 10;
}

if ( key[KEY_LEFT] )
{
cam.left += 0.1f;
cam.right += 0.1f;
buffer_teclado = 10;
}

if ( key[KEY_RIGHT] )
{
cam.left -= 0.1f;
cam.right -= 0.1f;
buffer_teclado = 10;
}

if ( buffer_teclado == 10 )
{
// atualizando a camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum( cam.left, cam.right, cam.bottom, cam.top, cam.vnear, cam.vfar );


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
}
else
{
buffer_teclado -= 1;
}



glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

gluLookAt( cam.x, cam.y, cam.z, cam.lookx, cam.looky, cam.lookz, 0.0f, 1.0f,
0.0f);


glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//allegro_gl_printf(agl_font, 0, 0.50, -1.01f, makecol( 000, 255, 000), "Valor %f",
posicao_z );
allegro_gl_printf(agl_font, cam.x, cam.y+1.00, cam.z-1.0f, makecol( 000, 255, 000),
"Valor %f", posicao_z );


glPushMatrix();
// Adiciona posio Z ao objeto
glTranslatef( 0, 0, posicao_z );


glBegin(GL_QUADS);

// face da frente
glColor3f( 255, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 1.00, 0.00 );
glVertex3f( 1.00, 1.00, 0.00 );
glVertex3f( 1.00, 0.00, 0.00 );

// face de traz
glColor3f( 0, 255 , 0 );
glVertex3f( 0.00, 0.00, 1.00 );
glVertex3f( 0.00, 1.00, 1.00 );
glVertex3f( 1.00, 1.00, 1.00 );
glVertex3f( 1.00, 0.00, 1.00 );

// face de cima
glColor3f( 0, 0 , 255 );
glVertex3f( 0.00, 1.00, 0.00 );
glVertex3f( 0.00, 1.00, 1.00 );
glVertex3f( 1.00, 1.00, 1.00 );
glVertex3f( 1.00, 1.00, 0.00 );

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 0.00, 1.00 );
glVertex3f( 1.00, 0.00, 1.00 );
glVertex3f( 1.00, 0.00, 0.00 );

// face da esquerda
glColor3f( 0, 0, 255 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, 1.00, 0.00 );
glVertex3f( 0.00, 1.00, 1.00 );
glVertex3f( 0.00, 0.00, 1.00 );

// face da direita
glColor3f( 255, 0, 255 );
glVertex3f( 1.00, 0.00, 0.00 );
glVertex3f( 1.00, 1.00, 0.00 );
glVertex3f( 1.00, 1.00, 1.00 );
glVertex3f( 1.00, 0.00, 1.00 );


glEnd();


glBegin(GL_QUADS);

// face de baixo
glColor3f( 255, 255 , 0 );
glVertex3f( -3.00, 0.00, -3.00 );
glVertex3f( -3.00, 0.00, 3.00 );
glVertex3f( 3.00, 0.00, 3.00 );
glVertex3f( 3.00, 0.00, -3.00 );
glEnd();

glPopMatrix();



// imprime tudo
allegro_gl_flip();

angulo += 0.2f;

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Sada bsica do programa:

O programa acima relativamente bsico.
Usamos a funo gluLookAt que possiciona a cmera e indica para aonde a cmera vai
apontar.
Com as teclas ( A, W, S, D ) podemos alterar a posio da cmera.
Observe que, mesmo alterando a posio da cmera, sempre estamos olhando para o
ponto 0,0,0 ( a no ser quando atualizamos o Frustum ).
muito importante entender isto.
Por exemplo, se voc manter precionado a tecla A, a cena vai vir cade vez mais prxima
da tela, at se inverter.
Isto acontece por que a camera nunca para de olhar para o mesmo ponto, e ela quem
est se movendo. E ela inverte por que possvelmente seus pontos ficaram negativos.
O exemplo acima pode ser fcilmente aplicado ao GLUT.
VOC PRECISA SABER...
Como no exemplo, a funo gluLookAt no deve ser aplicada na
matrix projetiva!!!

Preste muita ateno na forma de iniciao da cmera, isto muito importante:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();


glFrustum( cam.left, cam.right, cam.bottom, cam.top, cam.vnear, cam.vfar );


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// Demais alteraes no mundo 3D, gluLookAt trabalha aqui
Observe que fizemos tambm uso das funes glPushMatrix(); e glPopMatrix();
Usamos essas funes para que as alteraes de cmera no interferisem diretamente em
nosso posicionamento de objetos.
Ainda no aprendemos tudo sobre cmeras em OpenGL :)

Utilizando texturas


A tcnica de pegar uma textura qualquer e aplicar sobre um objeto conhecida como
mapeamento de texturas.
Uma textura bem elaborada consegue trazer para o cenrio do jogo um pouco mais de
realidade.
Praticamente todos os jogos 3D possuem texturas.
Por exemplo, uma caixa quadrada de mandeira em 3D seria apenas um polgono 3D
sem a textura da caixa de madeira.
Conforme abaixo:



Com a textura aplicada ao polgono 3D conseguimos entender que o objeto mostrado na
tela trata-se de uma caixa.
Logicamente, quanto mais trabalhado e quanto mais texturas o cubo conter mais
realstico vai ser a caixa.

O mesmo acontece quando criamos um personagem.
Um personagem composto de muitos polgonos, vrtices, faces...Etc. Cada face tem
uma textura.

E cada textura responsvel pelo detalhe que trs ao boneco uma aparncia boa.
Segue abaixo alguns exemplos de personagens 3D conhecidos:


VOC PRECISA SABER...

O uso de texturas consiste em apenas dois passos bem simples:

- Carga
- Aplicao



Processo 1 - Carga de Texturas

Cada textura que voc carrega via OpenGL necessrio identifica-la atravs de um ID.

Esse nmero voc pode controlar manualmente onde voc ser responsvel em identicar
cada textura nova que voc carregar, ou pode fazer o OpenGL gerar esses nmeros
automaticamente pela Funo glGenTextures(). Mas nada garante que esses nmeros
sero seqnciais.

Aps gerar o nmero de identificao para as texturas voc precisa informar ao OpenGl
qual ser sua textura corrente, ou seja, a que voc ir usar.
A funo responsvel por essa linkagem glBindTexture().
VOC PRECISA SABER...
Normalmente as bibliotecas para a carga de textura em OpenGL
aceitam apenas tamanhos de Largura e Altura multiplos de 2,
exemplo: 2, 4, 6, 8, 16, 32, 64, 128, 512, 1024.


Para o exemplo que veremos mais adiante usaremos as imagens 256x256 abaixo.


No momento iremos fazer um breve descrio das funes comuns utilizadas na carga
de texturas em OpenGL. So elas:
void glEnable ( GLenum cap )
Essa funo responsvel por habilitar alguns recursos do OpenGL.

Nesse caso estamos habilitando o uso de texturas 2D com o Flag
GL_TEXTURE_2D.
No manual do OpenGL existem vrios outros recursos mas nesse caso s
precisamos habilitar a textura 2D.



void glPixelStoref ( GLenum pname , GLfloat param )
Essa Funo define a forma de armazenamentos dos pixels na textura.
Recebe como argumentos um Flag e o valor que ativa ou organiza esse Flag.
Nesse caso estamos utilizando:
Flag : GL_UNPACK_ALIGNMENT
Valor: 1
GL_UNPACK_ALIGNMENT: Especifica o alinhamento necessrio para o
incio de cada pixel na fila da memria.
Os valores admissveis so:
1: Alinhamento por byte
2: Linhas alinhadas ao mesmo nmero de bytes
4: Alinhamento por palavras
8: Incio em fileiras duplas palavra-frontais
No manual do OpenGL existe uma tabela de Flags referente a funo
glPixelStorei que podero ser utilizados.
Nesse caso, explicamos apenas o que iremos usar para no tornar o tutorial muito
extenso.



void glGenTextures ( GLsizei n , GLuint *textures )
Essa funo responsvel por gerar o nmero ID para as texturas.
Essa funo recebe como argumentos a quantidade de Ids que ela deve gerar e
onde devero ser armazenados os Ids gerados.

Como iremos utilizar apenas uma textura precisamos de um nico ID.
Nesse caso temos:
1: Quantidade de IDs que a funo dever gerar.
texture_id: Varivel onde ser armazenado os IDs.
A varivel que ir armazenar os IDs um array.
Assim fica flexvel para que utilizar mais texturas.



void glBindTexture ( GLenum target , GLuint texture )
Essa funo responsvel por informar ao OpenGL qual a textura iremos usar.
Recebe como argumentos um target e o nome da textura que iremos usar.
Nesse caso temos:
Target: GL_TEXTURE_2D
Nome / ID da Textura: texture_id[CUBE_TEXTURE]
O target pode ter os seguintes argumentos: GL_TEXTURE_1D,
GL_TEXTURE_2D, ou GL_TEXTURE_3D.



No exemplo que iremos usar mais adiante poderemos utilizar outras funes devido o
manuseio diferente entre as bibliotecas.
Essas funes sero explicadas em detalhes logo aps o cdigo de exemplo.


Processo 2 - Aplicao da Textura


Para a aplicao necessrio criar uma relao entre os vrtices da textura e os vrtices
dos polgonos, pelos quais se deseja aplicar a textura escolhida.
Na figura do lado esquerdo as letras A,B, C e D definem os vrtices da textura.
E os vrtices A1, B1, C1 e D1 do lado direito definem os vrtices do polgono 3D onde
deve ser aplicada a textura.
O processo de mapeamento de texturas em OpenGL consiste em "aplicar" a imagem 2D
sobre o polgono 3D de forma que os pontos A, B, C e D sejam encaixados sobre os
pontos A1, B1, C1 e D1.





Para permitir essa correspondncia entre a imagem 2D e o polgono 3D usa-se a funo
glTexCoord2f() antes da definio do ponto 3D.
Pode parecer complicado aplicar a textura no polgono 3D se voc estiver comeando,
apenas questo de prtica.

Abaixo segue trecho do cdigo responsvel por aplicar a textura 2D na parte da frente
do polgono 3D.
glTexCoord2f(0.0f, 0.0f); // Vrtice inferior esquerdo da textura
glVertex3f(-0.50f, -0.50f, 0.50f); // Vrtice inferior esquerdo do poligono
glTexCoord2f(1.0f, 0.0f); // Vrtice inferior direito da textura
glVertex3f( 0.50f, -0.50f, 0.50f); // Vrtice inferior direito do poligono
glTexCoord2f(1.0f, 1.0f); // Vrtice superior direito da textura
glVertex3f( 0.50f, 0.50f, 0.50f); // Vrtice superior direito do poligono
glTexCoord2f(0.0f, 1.0f); // Vrtice superior esquerdo da textura
glVertex3f(-0.50f, 0.50f, 0.50f); // Vrtice superior esquerdo do poligono


O sistema de coordenadas da textura tem como (0,0) o ponto inferior esquerdo da
imagem e como (1,1) o ponto superior direito.
Ou seja, na imagem acima temos as seguintes coordenadas para os pontos A, B, C e D.
Vrtice da
textura
Coordenadas
A 0,1
B 1,1
C 1,0
D 0,0

Supondo que o polgono 3D a face da frente de um cubo de aresta 2 com o centro no
ponto (0,0,0) teremos as seguintes coordenadas:
Face da frente
Vrtice do
polgono 3D
Coordenadas
x y z
A -0.50 -0.50 0.50
B 0.50 -0.50 0.50
C 0.50 0.50 0.50
D -0.50 0.50 0.50

Aps aplicar a textura voc vai notar que um lado voc consegue ler normalmente e do
outro lado est invertido.
como se fosse um espelho.
Para que o polgono 3D saia com todos os lados legveis as imagens da parte de dentro
do poligono devem estar todas invertidas.
Dessa forma se colocarmos o polgono em rotao conseguimos ler todos os lados de
fora.
Para fazer a face de fundo do polgono voc precisa mexer no eixo z para afastar a face
e inverter os valores de X para inverter a textura de maneira que quem estiver atrs dele
consiga ler.
Voc entender melhor aps compilar o cdigo fonte e mexer nas coordenadas.



Supondo que o polgono 3D a face do fundo de um cubo de aresta 2 com o centro no
ponto (0,0,0) teremos as seguintes coordenadas:
Face do fundo
Vrtice do
polgono 3D
Coordenadas
x y z
A 0.50 -0.50 0.50
B -0.50 -0.50 0.50
C -0.50 0.50 0.50
D 0.50 0.50 0.50

Trecho do cdigo:
glTexCoord2f(0.0f, 0.0f); // Vrtice inferior esquerdo da textura
glVertex3f(0.50f, -0.50f, 0.50f); // Vrtice inferior esquerdo do poligono
glTexCoord2f(1.0f, 0.0f); // Vrtice inferior direito da textura
glVertex3f(-0.50f, -0.50f, 0.50f); // Vrtice inferior direito do poligono
glTexCoord2f(1.0f, 1.0f); // Vrtice superior direito da textura
glVertex3f(-0.50f, 0.50f, 0.50f); // Vrtice superior direito do poligono
glTexCoord2f(0.0f, 1.0f); // Vrtice superior esquerdo da textura
glVertex3f(0.50f, 0.50f, 0.50f); // Vrtice superior esquerdo do poligono

void glTexCoord2f (Glfloat x, Glfloat y)
Essa funo responsvel pela aplicao da textura 2D no poligo 3D. Recebe
como argumentos apenas 2 valores do tipo Glfloat.



Exemplos

Nos exemplos abaixo, iremos aprender como utilizar texturas .TGA (Targa File
Format) e texturas .BMP.
Para isso iremos usar 2 bibliotecas diferentes.
A TGALib para o TGA e o GLAUX para o BMP.
DICA...
Clique aqui para saber como instalar as bibliotecas TGALib e
GLAUX.




Cdigo em Glut para carregar e aplicar texturas no formato TGA.

CDIGO...

// Exemplo de como utilizar textura TGA com GLUT usando a biblioteca TGALib
// Autor: Bruno A. Rovela
// BDJogos
// Data: 15/12/2007
// ATUALIZADO: 03/03/2008

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

// Qtd mxima de texturas a serem usadas no programa
#define MAX_NO_TEXTURES 2

static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);
static void CarregaTextura(char *, GLuint);
void init(void);

GLfloat angulo = 0;
float ratio = 0;
float fZoom = -2.0f;

// Array para guardar o ID (Identificao) das texturas.
GLuint texture_id[MAX_NO_TEXTURES] = {0,0};

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(0,0);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

angulo = 0.0f;
glutCreateWindow("Mapeamento de Textura - TGA");

init();
// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glutMainLoop();

return EXIT_SUCCESS;
}
// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
// Previne um erro caso a tela seja redimencionada para muito pequena
if(height == 0)
height = 1;
ratio = 1.0f * width / height;

// Reseta as coordenadas do sistema antes de modifica-las
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Seta o Viewpor para Janela Inteira.
glViewport(0, 0, width, height);

// Seta a camera
gluPerspective(80,ratio,1,200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 30,0,0,10, 0.0f,1.0f,0.0f);
}
// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();

// Movimenta o objeto em X, Y e Z. Nesse Caso ele est mais longe da camera
// porque s modificamos o valor de Z.
glTranslatef ( -1.0f, -0.0f, fZoom );

// Rotao do cubo nos 3 eixos
glRotatef(angulo, 1.0f, 0.0f, 0.0f );
glRotatef(angulo, 0.0f, 1.0f, 0.0f );
glRotatef(angulo, 0.0f, 0.0f, 1.0f );

// textura1.tga - Vermelho e Preto
glBindTexture ( GL_TEXTURE_2D, texture_id[0] );

glBegin(GL_QUADS);
// Face da frente
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f); // Vrtice inferior
esquerdo
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f); // Vrtice inferior direito
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f); // Vrtice superior direito
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f); // Vrtice superior
esquerdo
//Face do fundo
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face do topo
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face de baixo
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
// Face da direita
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
// Face da esquerda
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glEnd();
glPopMatrix();

glPushMatrix();

// Movimenta o objeto em X, Y e Z. Nesse Caso ele est mais longe da camera
// porque s modificamos o valor de Z.
glTranslatef ( 1.0f, -0.0f, fZoom );

// Rotao do cubo nos 3 eixos
glRotatef(angulo, 0.0f, 0.0f, 1.0f );
glRotatef(angulo, 0.0f, 1.0f, 0.0f );
glRotatef(angulo, 1.0f, 0.0f, 0.0f );

// textura2.tga - Azul e Branco
glBindTexture ( GL_TEXTURE_2D, texture_id[1] );

glBegin(GL_QUADS);
// Face da frente
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f); // Vrtice inferior
esquerdo
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f); // Vrtice inferior direito
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f); // Vrtice superior direito
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f); // Vrtice superior
esquerdo
//Face do fundo
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face do topo
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face de baixo
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
// Face da direita
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
// Face da esquerda
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glEnd();
glPopMatrix();

angulo += 0.05f;
glutSwapBuffers();
}
// Funo que chamada quando uma tecla pressionada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
{
// Sai do programa quando o cdigo ASCII for "27" (ESC)
exit(0);
break;
}
case 43 : // Tecla + (Aproxima o Cubo)
{
fZoom += 0.10f;
break;
}
case 45 : // Tecla - (Afasta o Cubo)
{
fZoom -= 0.10f;
break;
}
}
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

static void CarregaTextura(char *Filename, GLuint iIndex)
{
glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures (1, &texture_id[iIndex]);
glBindTexture ( GL_TEXTURE_2D, texture_id[iIndex] );

image_t temp_image;
tgaLoad ( Filename, &temp_image, TGA_FREE);
}

void init(void)
{
// Faz o OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);
glEnable ( GL_TEXTURE_2D );

//Carrega os arquivos de textura
CarregaTextura("textura1.tga", 0);
CarregaTextura("textura2.tga", 1);
}

FIM DE CDIGO...


Para executar o exemplo, faa o download da textura:
Textura TGA
tgaLoad ( Filename, &temp_image, TGA_FREE)
Essa funo exclusiva da biblioteca TGALib e responsvel por carregar a
textura no formato TGA.
Por ser uma funo exclusiva da biblioteca voc no vai conseguir compilar o
cdigo completo se no incluir corretamente a biblioteca no seu projeto.
Recebe como argumentos:
Nome da Textura: Filename Nome da textura informado pela funo
CarregaTextura.
Varivel de Armazenamento: &temp_image
Modo de Carregamento: TGA_FREE
No primeiro argumento certifique-se que o arquivo da textura esteja dentro da
pasta do projeto.
Em seguida a varivel temp_image do tipo image_t armazena a textura.

O ltimo argumento refere-se ao modo que voc ir abrir a imagem atravs da
biblioteca.
Nesse caso o modo TGA_FREE libera a imagem assim que ela no for mais
utilizada.

Se a sua placa de vdeo for de desempenho baixo voc pode diminuir a qualidade
da textura agrupando junto ao TGA_FREE o flag TGA_LOW_QUALITY
separado por | (pipe).
O resultado voc pode observar no desenho abaixo:
Qualidade Baixa Qualidade Alta

O comando ficaria da seguinte forma:
tgaLoad ( Filename, &temp_image, TGA_FREE | TGA_LOW_QUALITY);
Essa opo tambm exclusiva da biblioteca TGALib.

O exemplo acima mostra dois polgonos 3D com duas texturas de exemplo da BDJogos
em rotao constante.
Uma textura vermelha com preto e a outra azul com branco.

Voc pode manipular o Zoom do polgono com a tecla + (mais) e tecla - (menos).
Cdigo em Glut para carregar e aplicar texturas no formato BMP.



CDIGO...

// Exemplo de como utilizar textura BMP com GLUT usando a biblioteca GLAUX
// Autor: Bruno A. Rovela
// BDJogos
// Data: 15/12/2007
// ATUALIZADO: 03/03/2008

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include "glaux\glaux.h"

// Qtd mxima de texturas a serem usadas no programa
#define MAX_NO_TEXTURES 2

static void display(void);
static void key(unsigned char key, int x, int y);
static void idle(void);
static void resize(int width, int height);
void CarregaTextura(char*, GLuint);
void init(void);

// Array para guardar o ID (Identificao) das texturas.
GLuint texture_id[MAX_NO_TEXTURES] = {0,0};

GLfloat angulo = 0.0f;
float ratio = 0.0f;
float fZoom=-2.0f;

// Main padro, o programa inicia aqui
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(0,0);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

angulo = 0.0f;
glutCreateWindow("Mapeamento de Textura - BMP");

init();
// callbacks
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

glutMainLoop();

return EXIT_SUCCESS;
}
// Funo que chamada quando a janela redimencionada
static void resize(int width, int height)
{
// Previne um erro caso a tela seja redimencionada para muito pequena
if(height == 0)
height = 1;
ratio = 1.0f * width / height;

// Reseta as coordenadas do sistema antes de modifica-las
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Seta o Viewpor para Janela Inteira.
glViewport(0, 0, width, height);

// Seta a camera
gluPerspective(80,ratio,1,200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 30,0,0,10, 0.0f,1.0f,0.0f);
}
// Funo que chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

glPushMatrix();

// Movimenta o objeto em X, Y e Z. Nesse Caso ele est mais longe da camera
// porque s modificamos o valor de Z.
glTranslatef ( -1.0f, -0.0f, fZoom );

// Rotao do cubo nos 3 eixos
glRotatef(angulo, 1.0f, 0.0f, 0.0f );
glRotatef(angulo, 0.0f, 1.0f, 0.0f );
glRotatef(angulo, 0.0f, 0.0f, 1.0f );

// textura1.bmp - Vermelho e Preto
glBindTexture ( GL_TEXTURE_2D, texture_id[0] );

glBegin(GL_QUADS);
// Face da frente
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f); // Vrtice inferior
esquerdo
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f); // Vrtice inferior direito
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f); // Vrtice superior direito
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f); // Vrtice superior
esquerdo
//Face do fundo
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face do topo
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face de baixo
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
// Face da direita
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
// Face da esquerda
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glEnd();
glPopMatrix();

glPushMatrix();

// Movimenta o objeto em X, Y e Z. Nesse Caso ele est mais longe da camera
// porque s modificamos o valor de Z.
glTranslatef ( 1.0f, -0.0f, fZoom );

// Rotao do cubo nos 3 eixos
glRotatef(angulo, 0.0f, 0.0f, 1.0f );
glRotatef(angulo, 0.0f, 1.0f, 0.0f );
glRotatef(angulo, 1.0f, 0.0f, 0.0f );

// textura2.bmp - Azul e Branco
glBindTexture ( GL_TEXTURE_2D, texture_id[1] );

glBegin(GL_QUADS);
// Face da frente
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f); // Vrtice inferior
esquerdo
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f); // Vrtice inferior direito
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f); // Vrtice superior direito
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f); // Vrtice superior
esquerdo
//Face do fundo
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face do topo
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
// Face de baixo
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
// Face da direita
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.50f, 0.50f, -0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.50f, -0.50f, 0.50f);
// Face da esquerda
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.50f, -0.50f, -0.50f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.50f, -0.50f, 0.50f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.50f, 0.50f, 0.50f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.50f, 0.50f, -0.50f);
glEnd();
glPopMatrix();

angulo += 0.05f;
glutSwapBuffers();
}
// Funo que chamada quando uma tecla pressionada
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
{
// Sai do programa quando o cdigo ASCII for "27" (ESC)
exit(0);
break;
}
case 43 : // Tecla + (Aproxima o Cubo)
{
fZoom += 0.10f;
break;
}
case 45 : // Tecla - (Afasta o Cubo)
{
fZoom -= 0.10f;
break;
}
}
}

// Funo que executa rotinas padres da Glut
static void idle(void)
{
glutPostRedisplay();
}

void init(void)
{
// Faz a OpenGL aceitar profunidade
glShadeModel(GL_SMOOTH);
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glEnable(GL_TEXTURE_2D);
glDepthFunc(GL_LEQUAL);

//Carrega os arquivos de textura
CarregaTextura("textura1.bmp", 0);
CarregaTextura("textura2.bmp", 1);
}

//Funo para Carregar uma imagem .BMP
void CarregaTextura(char* Filename, GLuint Index)
{
AUX_RGBImageRec *imagemTextura = NULL;
FILE *FileHandle = NULL;

imagemTextura = auxDIBImageLoad(Filename);

glGenTextures(1, &texture_id[Index]);
glBindTexture(GL_TEXTURE_2D, texture_id[Index]);

gluBuild2DMipmaps( GL_TEXTURE_2D, // A textura 2D
3, // 3 Significa que uma textura "RGB"
imagemTextura->sizeX, // Largura do Bitmap
imagemTextura->sizeY, // Altura do Bitmap
GL_RGB, // O Bitmap est no formato RGB
GL_UNSIGNED_BYTE, // Tipo de dado de cada Pixel armazenado
imagemTextura->data); // Dados do Bitmap Atual

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
;
}

FIM DE CDIGO...

Para executar o exemplo, faa o download da textura:
Textura BMP


O resultado do cdigo acima em formato de BMP o mesmo do formato TGA.
Abaixo segue uma breve explicao da funo CarregaTextura que aparece em ambos
os cdigos.
static void CarregaTextura(char *Filename, GLuint iIndex)
Criamos a funo acima para tornar a cargar da textura mais simples e dinmica.
Essa funo recebe como argumentos:
Filename: Nome do arquivo de textura
iIndex: ID da textura.
Exemplo:
CarregaTextura("textura1.bmp", 0);
CarregaTextura("textura2.bmp ", 1);
Nesse caso estamos controlando o nmero de ID manualmente.
Nos exemplos acima a parte do cdigo abaixo:
#define MAX_NO_TEXTURES 2

Informa que vamos usar duas texturas.
Portanto temos apenas os IDs 0 e 1 disponveis.

Se precisarem usar trs ou mais texturas vocs devero mudar o cdigo acima para
quantas texturas quiserem e informar o nmero ID novo.
Exemplo para trs texturas diferentes.
#define MAX_NO_TEXTURES 3
CarregaTextura("textura1.bmp ", 0);
CarregaTextura("textura2.bmp ", 1);
CarregaTextura("textura3.bmp ", 2);
A funo abaixo serve para mudar a textura corrente. Voc deve informar o tipo de
textura e seu nmero ID.
glBindTexture ( GL_TEXTURE_2D, texture_id[1] );



GLint gluBuild2DMipmaps ( GLenum target , GLint internalFormat ,
GLsizei width , GLsizei height , GLenum format , GLenum type , const void
*data )
Essa funo responsvel por criar um mipmap.
Mipmaps so muitas texturas de diferentes tamanhos.
Por exemplo, quando um objeto com textura mapeada ou polgono move-se para o
longe,
o OpenGL escolhe automaticamente qual tamanho de textura utilizar para dar a
impresso de distncia ao usurio.
Normalmente utilizamos o GL_TEXTURE_2D para o primeiro parmetro.
Os outros parmetros so auto-explicativos.


void glTexParameteri(GLenum target,GLenum pname,GLint param )
Essa funo responsvel por informar ao OpenGL como ele deve desenhar as
texturas.
Segue o exemplo abaixo utilizado no cdigo para melhor entendimento.
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEARES
T);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
);
Quando ns utilizamos o GL_LINEAR, ns queremos que o OpenGL desenhe nossa
textura o mais suave que ele puder mas que o desenho de fundo seja mais lento que o
GL_NEAREST.

No exemplo acima ns setamos o GL_TEXTURE_MIN_FILTER para o
GL_NEAREST.

Isto significa que ns queremos que o OpenGL desenhe nossas texturas o mais rpido
que ele puder enquanto ele estiver se aproximando de ns.
Aqui est uma tabela dos possveis valores que voc possa ter no glTexParameteri();
2 PARMETRO 3 PARMETRO
GL_TEXTURE_MAG_FILTER GL_NEAREST
GL_LINEAR
GL_TEXTURE_MIN_FILTER GL_NEAREST
GL_LINEAR
GL_NEAREST_MIPMAP_NEAREST
GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR

Para mais detalhes referente os argumentos acima consulte o manual do OpenGL.





Qualquer dvida referente a carga e aplicao de texturas favor postar as dvidas no
forum para melhor exclarecimento.
Abraos.

ATUALIZADO 03/03/2008



43 - Trabalhando com Luzes

Uma forma de tornar nossas renderizaes mais bonitas e at reais aplicando luzes
sobre elas.
Ns s podemos ver as coisas quando temos uma iluminao ambiente. Quanto menor
for a iluminao ambiente menos vamos conseguir ver. Este tipo de situao precisamos
conseguir fazer tambm com a OpenGL, por isso vamos aprender agora como aplicar
luz no nosso ambiente.
Observe o exemplo abaixo da aplicao de luz ambiente em OpenGL com AllegroGL

CDIGO...

// Exemplo de Luz ambiente com AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 02/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();


// Cdigo para adio de luz ambiente

GLfloat param_1;
GLfloat param_2;
GLfloat param_3;
GLfloat param_4;

param_1 = 0.0f;
param_2 = 0.0f;
param_3 = 0.0f;
param_4 = 1.0f;

// iniciando um array de luz ambiente
GLfloat luz_ambiente[]= { param_1, param_2, param_3, param_4 };

// criando a luz
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);

// habilitamos a luz para o cenario
// este comando pode habilitar e desabilitar varias luzes
glEnable(GL_LIGHT1);

// habilitamos LUZES na OpenGL
glEnable(GL_LIGHTING);


GLfloat potencia_luz = 0;

int i = 0;

// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


luz_ambiente[0]= param_1;
luz_ambiente[1]= param_2;
luz_ambiente[2]= param_3;
luz_ambiente[3]= param_4;

if ( i < 1000 )
{
i++;

if ( i % 100 == 0 )
{
potencia_luz += 0.5f;
}

param_1 = potencia_luz;
param_2 = 0.50f;
param_3 = 0.50f;

}
else
{
i = 0;
potencia_luz = 0;
}

// atualiza luz 1
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);



glBegin(GL_QUADS);

glColor3f ( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );

glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glColor3f ( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



// imprime tudo
allegro_gl_flip();

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


No exemplo acima aplicamos a luz ambiente, aumentando sempre sua intensidade.
Para aumentar sua intensidade, criamos a varivel potencia_luz que incrementada.
Observe que usamos funes novas, vamos conhecer elas.
Neste programa ns usamos o comando
glLightfv
void glLightf( GLenum light, GLenum pname, GLfloat param);
O primeiro parmetro identifica o id da luz que iremos usar.
A OpenGL nos deixa usar por padro at 8 luzes ao mesmo tempo (
GL_LIGHT1... GL_LIGHT8 ).
Pname indica qual o tipo de luz que iremos usar.. sendo que existem os seguintes
tipos de luzes:
GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR
GL_POSITION
GL_SPOT_DIRECTION
GL_SPOT_EXPONENT
GL_SPOT_CUTOFF
GL_CONSTANT_ATTENUATION
GL_LINEAR_ATTENUATION
GL_QUADRATIC_ATTENUATION
No exemplo de cdigo acima apenas usamos o GL_AMBIENT, mais iremos
explicar outros parmetros em seguida.
E o ltimo parmetro o params que na verdade um array que configura o tipo
de luz que voc escolheu em Pname.
Iremos usar muitos desses arrays a partir de agora com a OpenGL.




No exemplo acima, usamos a funo glLightfv com o parmetro GL_AMBIENT para
criar uma luz ambiente.
GL_AMBIENT contem 4 parmetros que especificam a intensidade RGBA da luz.
VOC PRECISA SABER...
Definio de RGB da WIKIPEDIA
RGB a abreviatura do sistema de cores aditivas formado por
Vermelho (Red), Verde (Green) e Azul (Blue).

o sistema aditivo de cores, ou seja, de projees de luz.
O termo RGBA tambm usado, significando Red, Green, Blue e
Alfa.
Este no um modelo de cores diferente, e sim uma representao
uma vez que o Alpha usado para indicar transparncia.


O valor inicial da luz GL_AMBENT de (0, 0, 0, 1).
Observe que este tipo de luz inside sobre todos os objetos, at mesmo mudando sua cor
original.
No exemplo, estamos usando a luz vermelha que no vem de algum lugar.. ela
simplesmente ilumina em todas as direes.

Observe o exemplo abaixo da aplicao de luz difusa em OpenGL com AllegroGL

CDIGO...

// Exemplo de Luz difusa ( com posicionamento e luz ambiente ) com AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 02/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();


// Cdigo para adio de luz ambiente

GLfloat param_1;
GLfloat param_2;
GLfloat param_3;
GLfloat param_4;

param_1 = 0.0f;
param_2 = 0.0f;
param_3 = 0.0f;
param_4 = 1.0f;

// iniciando um array de luz ambiente
GLfloat luz_ambiente[]= { 0.0f, 1.0f, 0.0f, 1.0f };

// iniciando um array para luz difusa
GLfloat luz_difusa[]= { 0.5f, 0.5f, 0.5f, 1.0f };

// iniciando um array para posio da luz
GLfloat luz_posicao[]= { param_1, param_2, param_3, param_4 };

// criando a luz ambiente
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);

// criando a luz difusa
glLightfv(GL_LIGHT2, GL_DIFFUSE, luz_difusa );

// habilitamos a luz para o cenario
// este comando pode habilitar e desabilitar varias luzes
glEnable(GL_LIGHT1);
glEnable(GL_LIGHT2);

// habilitamos LUZES na OpenGL
glEnable(GL_LIGHTING);


GLfloat nova_posicao = 0;

int i = 0;

// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


luz_posicao[0]= param_1;
luz_posicao[1]= param_2;
luz_posicao[2]= param_3;
luz_posicao[3]= param_4;

if ( i < 5000 )
{
i++;

if ( i % 200 == 0 )
{
nova_posicao += 0.1f;
}

param_1 = 0;
param_2 = 0;
param_3 = nova_posicao;

}
else
{
i = 0;
nova_posicao = 0;
}


// atualiza posicao
glLightfv(GL_LIGHT2, GL_POSITION, luz_posicao);





glBegin(GL_QUADS);

glColor3f( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );


glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glColor3f( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



// imprime tudo
allegro_gl_flip();



}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


A luz difusa vai fazer uma fuso entre as cores selecionadas nos seus parmetros. Ela
funciona da mesma forma que a luz ambiente, com 4 valores RGBA, com a diferena de
tornar as cores mais speras e menos brilhantes.
Para usar a luz difusa, devemos usar tambm o tipo GL_POSITION, para possicionar a
nossa luz difusa.
No exemplo, voc deve ter percebido que a luz difusa vez o efeito de degrade.
Ns posicionamos a luz atraz dos objetos e vamos puxando ela para frente, formando ai
o efeito de degrade.
Quanto mais a luz se distancia do objeto, maior a intensidade que ela exerce sobre
ele...
Tente mudar a cor da luz difusa para vermelho para ver a funcionalide:

// iniciando um array para luz difusa
GLfloat luz_difusa[]= { 1.5f, 0.5f, 0.5f, 1.0f };
O brilho da luz difusa emitido para todas as direes.
E por fim, temos tambm uma importante luz.. a luz Especular
Observe o exemplo abaixo da aplicao de luz especular em OpenGL com AllegroGL

CDIGO...

// Exemplo de Luz especular ( com posicionamento e luz ambiente ) com AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 02/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);


glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

glLoadIdentity();


// Cdigo para adio de luz ambiente

GLfloat param_1;
GLfloat param_2;
GLfloat param_3;
GLfloat param_4;

param_1 = 0.0f;
param_2 = 0.0f;
param_3 = 0.0f;
param_4 = 1.0f;

// iniciando um array de luz ambiente
GLfloat luz_ambiente[]= { 0.0f, 1.0f, 0.0f, 1.0f };

// iniciando um array para luz difusa
GLfloat Especularidade[]= {0.0f, 1.0f, 0.0f, 1.0f };

// iniciando um array para posio da luz
GLfloat luz_posicao[]= { param_1, param_2, param_3, param_4 };

// criando a luz ambiente
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);

// criando a luz especular
glLightfv(GL_LIGHT2, GL_SPECULAR, Especularidade );

// habilitamos a luz para o cenario
// este comando pode habilitar e desabilitar varias luzes
glEnable(GL_LIGHT1);
glEnable(GL_LIGHT2);

// habilitamos LUZES na OpenGL
glEnable(GL_LIGHTING);


GLfloat nova_posicao = 0;

int i = 0;

// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


luz_posicao[0]= param_1;
luz_posicao[1]= param_2;
luz_posicao[2]= param_3;
luz_posicao[3]= param_4;

if ( i < 5000 )
{
i++;

if ( i % 200 == 0 )
{
nova_posicao += 0.1f;
}

param_1 = 0;
param_2 = 0;
param_3 = nova_posicao;

}
else
{
i = 0;
nova_posicao = 0;
}


// atualiza posicao
glLightfv(GL_LIGHT2, GL_POSITION, luz_posicao);


glMateriali( GL_FRONT, GL_SHININESS, 20 );
glMaterialfv( GL_FRONT, GL_SPECULAR, Especularidade );



glBegin(GL_QUADS);


glColor3f( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );


glEnd();



glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glColor3f( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



// imprime tudo
allegro_gl_flip();


}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...


Observe que diferente da luz difusa, o efeito da luz Especular parece ser mais bonito..
Ele aumenta o brilho e reala a cor do objeto.
No exemplo acima tivemos que usar o comando glMaterial
void glMaterial( face, GLenum pname, GLfloat param);
Este comando aplica parametros de luz para os objetos na tela.
face
Especifica quais faces sero atingidas pela luz.
Elas podem ser GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK.
pname
Especifica quais parametros sofrero mudanas... podem ser muitos parmetros, e
iremos ver alguns deles.
param
parmetros de mudanas.
Essa funo usada para alterar os parmetros nas equaes de iluminao da
OpenGL.
PNAME pode aceitar:

GL_AMBIENT
So 4 valores rgb que especificam o valor de reflexo do material
GL_DIFFUSE
So 4 valores rgb que especificam o valor de reflexo de difuso
GL_SPECULAR
So 4 valores rgb que especificam o valor de reflexo de brilho
GL_EMISSION
So 4 valores que especificam a intensidade da emisso de luz do material
GL_SHININESS
Um nico valor que determina o valor expoente RGBA da iluminao especular
do material. O Valor pode ser de
0 at 128
GL_AMBIENT_AND_DIFFUSE
Equivalente a chamar GL_AMBIENT e GL_DIFFUSE setando os mesmo
parmetros para o material
GL_COLOR_INDEXES
Contem 3 parmetros que especificam os indices de cores para ambiente, difusso e
especular lighting do material.
importante salientar que esses parmetros so para o material!! Eles no
alteram as propriedades das luzes.




Os comandos abaixo sero explicados em outros tutoriais
GL_SPOT_DIRECTION
GL_SPOT_EXPONENT
GL_SPOT_CUTOFF
GL_CONSTANT_ATTENUATION
GL_LINEAR_ATTENUATION
GL_QUADRATIC_ATTENUATION
Bom.. resumindo:
- Vimos neste tutorial como aplicar os 3 tipos de luzes da OpenGl em nossos
programas.

- Com esta tcnica no iremos ver sombras. Para ver as sombras dos objetos precisamos
usar outras tcnicas.
- Cada luz deve ser configurada individualmente.
- Cada objeto pode ter uma configurao de material, que pode alterar a forma em que
ele realado pela luz.
- Luzes e materiais interferem no sistema de cores da funo glColor
- Ainda no vimos como aplicar sombras.
- Ainda no vimos como direcionar nossa luz
- Ao trabalhar com luz, temos que aplicar funes de materiais nos objetos



44 - Materiais e Cores

No captulo anterior aprendemos como adicionar luzes ao nosso ambiente.
Voc deve ter percebido que, quando alteramos algumas propriedades da OpenGL
acontece algumas mudanas na forma de renderizar a cena.
Por exemplo, quando aplicamos a cor Amarela a um objeto, este objeto passa a ser
impresso na tela com a cor amarela.
Mais quando incluimos uma textura ou uma luz no ambiente, o objeto amarelo sofre
interferncia dessas funes e acaba tendo sua cor original trocada.
Neste capitulo iremos aprofundar ainda mais nossos conhecimentos sobre os Materiais
de Cores da OpenGL.
Primeiro, ns sabemos que a OpenGL trabalha com o padro RGBA que faz a mistura
de Cores e habilita a transparncia.
VOC PRECISA SABER...
Alpha Channel conhecido como Canal de Transparncia.
Sempre que falarmos em opacidade, estamos falando em
transparncia. Tornar um objeto NO opaco torna-lo transparente.

Quanto maior a opacidade do Objeto, menor a transparncia dele.

Basicamente, aprendemos 2 formas de adicionar cor aos nossos objetos.
- A primeira aplicando cor diretamente sobre objeto.

- A segunda aplicando cor sobre a superfcie do objeto, alterando assim as
propriedades da superfcie ( conhecido como Material ) atravs de configuraes ou
atravs da incidncia de luz.
Um dos problemas que ns iremos encontrar com relao de cores e luzes.
Por exemplo, se um objeto vermelho for luminado por uma luz azul, esse objeto ir
aparecer relativamente preto.
Isso acontece por que o objeto vermelho reflete luz vermelha e no azul e a luz contem
luz azul e no vermelho.

Vamos aprender como aplicar uma cor transparente
Os comandos responsveis por habilitar a transparncia so:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f ( 0.0f, 0.0f, 1.0f, 0.5f );
void glBlendFunc( GLenum sfactor, GLenum dfactor);
Esta funo especifca quanto de RGBA ser utilizado para o resultado de
transparncia.

sfactor especifca qual o metodo usado para escalar ( aumentar ou diminuir ) os
recursos de cores.
dfactor especifca qual o metodo usado para escalar as cores de destino, tornando-
as trasnparentes.

Existem vrios parmetros que podem ser utilizados nesta funo.
A indicada pela OpenGl so GL_SRC_ALPHA e
GL_ONE_MINUS_SRC_ALPHA.
Leia no site oficial para poder usar outros parmetros.



Exemplo em AllegroGL

CDIGO...

// Aplicando transparencia
// Autor: Adriano Waltrick
// BDJogos
// Data: 12/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


glLoadIdentity();



// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


glBegin(GL_QUADS);

glColor3f ( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );

glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glColor3f ( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



glBegin(GL_QUADS);

glColor4f ( 0.0f, 0.0f, 1.0f, 0.5f );
glVertex3f( -0.40, -0.40, 0.00 );
glVertex3f( -0.40, 0.40, 0.00 );
glVertex3f( 0.40, 0.40, 0.00 );
glVertex3f( 0.40, -0.40, 0.00 );

glEnd();

// imprime tudo
allegro_gl_flip();

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...



Observe que o quadro azul transparente.
Observe tambm que nossas cores originais no foram alteradas pela incluso da funo
de transparncia.


Veja no exemplo abaixo, como usar transparncia e textura com AllegroGL
Antes, leia:
Instalao de bibliotecas para texturas
http://www.bdjogos.com/biblioteca_conteudo.php?id=25

Como usar texturas
http://www.bdjogos.com/conteudo.php?link=capitulo_42.php

CDIGO...

// Exemplo de transparncia e textura com AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 13/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>
#include "glaux\glaux.h"

#include <stdlib.h>
#include <stdio.h>

void CarregaTextura(char* Filename, GLuint Index);
GLuint texture_id[1] = {0};

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);




//Carrega os arquivos de textura
CarregaTextura("textura.bmp", texture_id[0] );



glLoadIdentity();



// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();




glBegin(GL_QUADS);

glColor3f ( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );

glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glColor3f ( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



glPushMatrix();

glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glColor4f ( 1.0f, 1.0f, 1.0f, 0.7f );
glBindTexture ( GL_TEXTURE_2D, 1 );
glTexCoord2f(0.0f, 0.0f);
glVertex3f( -0.40, -0.40, 0.00 );
glTexCoord2f(0.0f, 1.0f);
glVertex3f( -0.40, 0.40, 0.00 );
glTexCoord2f(1.0f, 1.0f);
glVertex3f( 0.40, 0.40, 0.00 );
glTexCoord2f(1.0f, 0.0f);
glVertex3f( 0.40, -0.40, 0.00 );
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();




// imprime tudo
allegro_gl_flip();

}

allegro_exit();

return 0;
}
END_OF_MAIN();

//Funo para Carregar uma imagem .BMP
void CarregaTextura(char* Filename, GLuint Index)
{
AUX_RGBImageRec *imagemTextura = NULL;
FILE *FileHandle = NULL;

imagemTextura = auxDIBImageLoad(Filename);

glGenTextures(1, &texture_id[Index]);
glBindTexture(GL_TEXTURE_2D, texture_id[Index]);

gluBuild2DMipmaps( GL_TEXTURE_2D, // A textura 2D
3, // 3 Significa que uma textura "RGB"
imagemTextura->sizeX, // Largura do Bitmap
imagemTextura->sizeY, // Altura do Bitmap
GL_RGB, // O Bitmap est no formato RGB
GL_UNSIGNED_BYTE, // Tipo de dado de cada Pixel armazenado
imagemTextura->data); // Dados do Bitmap Atual

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
;
}

FIM DE CDIGO...

Usando glColor4f ( 1.0f, 1.0f, 1.0f, 0.7f ); ns obtemos uma textura com as cores
originais, adicionando apenas trasnparncia para ela...
Eu usei uma textura com as cores vermelho, verde e azul para exemplo.
Veja o resultado do programa.


DICA...
Se voc leu o cdigo, deve ter percebido a diferena no quadrado
que recebe a textura.

Sempre que voc utilizar cores e texturas, importante habilitar e
desabilitar as opes, por que se no a OpenGL acaba misturando
as cores e a renderizao no vai funcionar como deveria.
Por isso, faa bom uso das funes:

glPushMatrix();
glEnable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_2D);
glPopMatrix();



Bom, o que aconteceria se pegarmos o primeiro exemplo, aonde aplicamos cores e
transparncia
e aplicarmos iluminao nela ?


CDIGO...

// Aplicando cores, transparncia e luz - EXEMPLO no completo!! - AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 13/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


// iniciando um array de luz ambiente
GLfloat luz_ambiente[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat luz_difusa[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat luz_posicao[] = { 0.0f, 0.0f, 1.0f, 1.0f };

// criando a luz ambiente
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);
glLightfv(GL_LIGHT1, GL_DIFFUSE, luz_difusa);
glLightfv(GL_LIGHT1, GL_POSITION, luz_posicao);

glEnable( GL_LIGHT1 );
glEnable( GL_LIGHTING );

glLoadIdentity();


// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


glBegin(GL_QUADS);

glColor3f ( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );

glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glColor3f ( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



glBegin(GL_QUADS);

glColor4f ( 0.0f, 0.0f, 1.0f, 0.5f );
glVertex3f( -0.40, -0.40, 0.00 );
glVertex3f( -0.40, 0.40, 0.00 );
glVertex3f( 0.40, 0.40, 0.00 );
glVertex3f( 0.40, -0.40, 0.00 );

glEnd();

// imprime tudo
allegro_gl_flip();

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

No exemplo acima aplicamos uma luz ambiente e uma luz difusa.
Quando executamos o programa temos o horrvel resultado:

Nosso render perdeu as cores e a transparncia.
Isso acontece por que a luz interfere diretamente nas faces dos objetos.
Para mostrar as cores originais dos objetos, iremos precisar usar 2 funes importantes.
A glMaterial que j vimos e a glNormal.
Toda alterao de cor, transparncia ou aplicao de textura feita sobre as faces em
OpenGL.
E quando aplicamos esses valores a essas faces na verdade estamos criando um material
e aplicando a face.
Iremos usar a funo glNormal por que ela vai indicar para a OpenGL qual a face que
est visvel e que precisa ser iluminada.
Iremos usar a funo glMaterial para criar um material para cada objeto, fazendo com
que a luz no altere sua cor original.
void glNormal3f( GLfloat nx, GLfloat ny, GLfloat nz);
Essa funo especifca uma normal para uma face. Uma normal para uma face
um vetor ( reta ) perpendicular a 90 graus com a face.
Os valores podem ser de -1.0 a 1.0. E GL_NORMALIZE precisa esta ligado.
nx, ny e nz especificam qual o lado a face est apontando.


Alem disso ainda iremos usar
glEnable(GL_COLOR_MATERIAL);
Para habilitar as cores dos materiais e
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
Para indicar que as cores sero indicadas na face frontal.


CDIGO...

// Aplicando cores, transparncia e luz - EXEMPLO completo!! - AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 13/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


// iniciando um array de luz ambiente
GLfloat luz_ambiente[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat luz_difusa[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat luz_posicao[] = { 0.0f, 0.0f, -15.0f, 1.0f };

// criando a luz ambiente
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);
glLightfv(GL_LIGHT1, GL_DIFFUSE, luz_difusa);
glLightfv(GL_LIGHT1, GL_POSITION, luz_posicao);

glEnable( GL_LIGHT1 );
glEnable( GL_LIGHTING );
// habilita as cores do material
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_NORMALIZE);

glLoadIdentity();


// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();


glBegin(GL_QUADS);

glNormal3f(0.0, 0.0, 1.0);
glColor3f ( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );

glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glNormal3f(0.0, 0.0, 1.0);
glColor3f ( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();



glBegin(GL_QUADS);

glNormal3f(0.0, 0.0, 1.0);
glColor4f ( 0.0f, 0.0f, 1.0f, 0.5f );
glVertex3f( -0.40, -0.40, 0.00 );
glVertex3f( -0.40, 0.40, 0.00 );
glVertex3f( 0.40, 0.40, 0.00 );
glVertex3f( 0.40, -0.40, 0.00 );

glEnd();

// imprime tudo
allegro_gl_flip();

}

allegro_exit();

return 0;
}
END_OF_MAIN();

FIM DE CDIGO...

Agora sim, temos o exemplo de Luzes, Transparncias e cores.
Inclusive, se voc mudar a posio da luz, para perto, as cores originais vo ficar mais
escuras.
Faa o teste:
GLfloat luz_posicao[] = { 0.0f, 0.0f, -15.0f, 1.0f };
Mude para
GLfloat luz_posicao[] = { 0.0f, 0.0f, -5.0f, 1.0f };
Pronto.. agora temos um sistema de luzes com cores eficiente.
Se voc usar o exemplo acima com texturas, voc tambm no ter problemas.




Brightness = Luminance = Luminosidade
O Termo usado ai em cima representa o quanto uma luz vai iluminar um objeto
mudando sua cor original.
No confunda Brightness com Blend, blending o canal de transparncia.


CDIGO...

// Exemplo de Luz com textura, normal, Material e Brightness
// Autor: Adriano Waltrick
// BDJogos
// Data: 13/03/2008
#include <allegro.h>
#include <alleggl.h>

#include <GL/glut.h>
#include "glaux\glaux.h"

#include <stdlib.h>
#include <stdio.h>

void CarregaTextura(char* Filename, GLuint Index);
GLuint texture_id[1] = {0};

int main()
{

// Iniciaes bsicas da Allegro
allegro_init();
install_keyboard();

// Iniciao da AllegroGL
install_allegro_gl();

allegro_gl_set(AGL_Z_DEPTH, 8);
allegro_gl_set(AGL_COLOR_DEPTH, 16);
allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);

// Setando o Modo Grfico
set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Iniciando a camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);

glShadeModel( GL_SMOOTH );

// Faz a OpenGL aceitar profunidade
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LEQUAL);

// Maior qualidade nos grficos
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// carrega textura
glEnable(GL_TEXTURE_2D);
glDepthFunc(GL_LEQUAL);

//Carrega os arquivos de texturaC
CarregaTextura("textura.bmp", texture_id[0] );

// iniciando um array de luz ambiente
GLfloat luz_ambiente[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat luz_difusa[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat luz_posicao[] = {0.0f,0.0f,-1.0f,1.0f};

GLfloat luz_especular[] = { 1.0f, 1.0f, 0.0f, 1.0f };
GLfloat luz_posicao2[] = {3.0f,0.0f,-5.0f,1.0f};

// criando a luz ambiente
glLightfv(GL_LIGHT1, GL_AMBIENT, luz_ambiente);
glLightfv(GL_LIGHT1, GL_DIFFUSE, luz_difusa);
glLightfv(GL_LIGHT1, GL_POSITION, luz_posicao);

glLightfv(GL_LIGHT2, GL_SPECULAR, luz_especular);
glLightfv(GL_LIGHT2, GL_POSITION, luz_posicao2);


glEnable( GL_LIGHT1 );
glEnable( GL_LIGHT2 );
glEnable( GL_LIGHTING );


// habilita as cores do material
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_NORMALIZE);



glLoadIdentity();


GLfloat Especularidade[]= {1.0f, 1.0f, 0.0f, 1.0f };

glMateriali( GL_FRONT, GL_SHININESS, 120 );
glMaterialfv( GL_FRONT, GL_SPECULAR, Especularidade );


// Lao principal
while( !key[KEY_ESC] )
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();




glBegin(GL_QUADS);
glNormal3f(0.0, 0.0, 1.0);
glColor3f ( 0.0, 1.0, 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.00, -0.80, 0.00 );
glVertex3f( -0.80, -0.80, 0.00 );
glVertex3f( -0.80, 0.00, 0.00 );

glEnd();


glBegin(GL_TRIANGLES);

// Face da Frente do tringulo
glNormal3f(0.0, 0.0, 1.0);
glColor3f ( 1.0, 0 , 0 );
glVertex3f( 0.00, 0.00, 0.00 );
glVertex3f( 0.80, 0.00, 0.00 );
glVertex3f( 0.40, 0.80, 0.00 );

glEnd();




glPushMatrix();

glEnable(GL_TEXTURE_2D);

glBegin(GL_QUADS);
glNormal3f(0.0, 0.0, 1.0);
glColor4f ( 1.0f, 1.0f, 1.0f, 0.7f );
glBindTexture ( GL_TEXTURE_2D, 1 );
glTexCoord2f(0.0f, 0.0f);
glVertex3f( -0.40, -0.40, 0.00 );
glTexCoord2f(0.0f, 1.0f);
glVertex3f( -0.40, 0.40, 0.00 );
glTexCoord2f(1.0f, 1.0f);
glVertex3f( 0.40, 0.40, 0.00 );
glTexCoord2f(1.0f, 0.0f);
glVertex3f( 0.40, -0.40, 0.00 );
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();






// imprime tudo
allegro_gl_flip();

}

allegro_exit();

return 0;
}
END_OF_MAIN();

//Funo para Carregar uma imagem .BMP
void CarregaTextura(char* Filename, GLuint Index)
{
AUX_RGBImageRec *imagemTextura = NULL;
FILE *FileHandle = NULL;

imagemTextura = auxDIBImageLoad(Filename);

glGenTextures(1, &texture_id[Index]);
glBindTexture(GL_TEXTURE_2D, texture_id[Index]);

gluBuild2DMipmaps( GL_TEXTURE_2D, // A textura 2D
3, // 3 Significa que uma textura "RGB"
imagemTextura->sizeX, // Largura do Bitmap
imagemTextura->sizeY, // Altura do Bitmap
GL_RGB, // O Bitmap est no formato RGB
GL_UNSIGNED_BYTE, // Tipo de dado de cada Pixel armazenado
imagemTextura->data); // Dados do Bitmap Atual

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
;
}

FIM DE CDIGO...



Observe que no exemplo acima aplicamos iluminao direcionada amarelada no
triangulo vermelho, adicionando brilho amarelo.
As outras cores no foram influenciadas, o que muito importante.



Visualizao bidimensional na prtica (Viewports)

Para entender a visualizao bidimensional em OPEN GL precisamos conhecer o
conceito universo, que pode ser definido como sendo a regio, plano ou espao de
uma aplicao. Como qualquer objeto pelo qual devemos representar na tela envolve
coordenadas geomtricas necessrio adotar um sistema de referncia que ir definir
uma posio a qual todos os objetos estaro desenhados.

O sistema de referncia do universo (SRU) em Open GL consiste em definir as
coordenadas atravs do plano cartesiano normal em dois eixos (x e y).
Sendo x orientado para a direita e y orientado para cima.

Conforme a figura abaixo:


Entretanto o monitor adota o sistema de referncia da tela (SRT) que possui algumas
diferenas ao sistema SRU.
No SRT a origem fica no canto superior esquerdo do monitor.

Conforme abaixo:


Portanto, para mostrar a correta visualizao de um sistema para o outro necessrio
fazer uma converso ou mapeamento das coordenadas.

Veja a ilustrao abaixo:


Resumindo iremos sempre desenhar nossos objetos com base no sistema SRU, plano
cartesiano normal com eixos x e y.
Depois disso ser feita o mapeamento para a tela independente do dispositivo ou
resoluo da tela.
Como o universo infinito preciso especificar qual poro queremos mapear na tela.
A essa rea que delimita a rea de interessa do usurio chamamos de window ou janela
de seleo.

Uma window delimitada atravs das coordenadas de seus cantos (esquerdo, direito,
superior, inferior) no sistema SRU.

De forma anloga tambm necessrio definir em que parte desejamos exibir o
contedo na window no monitor.
Essa regio chamada de viewport ou janela de exibio, uma viewport normalmente
delimitada pelo tamanho da janela GLUT correspondente ao tamanho da resoluo do
monitor.

Segue abaixo uma ilustrao simples para entendimento:


Para mapear o objeto do sistema SRU para o sistema SRT necessrio apenas
especificar a viewport e a window, utilizando as funes abaixo:
void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);
Os valores especificadoes nos dois primeiros parmetros x e y definem a posio
da janela na tela enquanto os dois ltimos definem a largura e a altura dessa tela.
Se voc no especificar viewports no seu programa, o OpenGL assume o viewport
default e cria uma para trabalhar com toda a tela. Seria o mesmo que fazer:
Exemplo:
glViewport(0, 0, fLargura/2, fAltura/2);

int glutGet(GLenum state);
Funo responsvel por pegar informaes sobre os estados internos do GLUT. No
exemplo, ela foi usada para pegar a largura e altura atual da janela do programa.
Essa funo aceita muitos outros argumentos, para mais detalhe consulte o manual
de referncia do GLUT.
Exemplo:
glutGet(GLUT_WINDOW_WIDTH); // Pega a largura da janela
...
glutGet(GLUT_WINDOW_HEIGHT); // Pega a altura da janela

gluOrtho2D (Gldouble left, Gldouble right, Gldouble bottom, Gldouble top);
Essa funo serve para definir a window quando se est trabalhando com desenhos
2D. Seus parmetros correspondem especificamente cada borda da window. Isto :
x mnimo (borda esquerda - left) x mximo (borda direita - right) y mnimo
(borda inferior - bottom) y mximo (borda superior - top).
Exemplo:
gluOrtho2D (-win*aspecto, win*aspecto, -win, win);

Praticamente j trabalhamos em um viewport s que muitas vezes no declarado
explicitamente e sim por default do GLUT.
Entendido o que um viewport vamos ver como criar mais de um em um mesmo
ambiente. Basicamente, o procedimento :

- Definir viewport1
- Desenhar contedo na viewport1
- Definir viewport2
- Desenhar contedo na viewport2
Exemplo com 2 viewports



CDIGO...

001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:

#include <GL/glut.h>

void DesenhaQuadrado();
void DesenhaBorda();
void Inicializa();

static void Desenha(void);
static void TecladoNormal(unsigned char key, int x, int y);
void AlteraTamanhoJanela(GLsizei w, GLsizei h);
static void idle(void);

GLint iLargura = 0;
GLint iAltura = 0;
GLfloat win = 0.0f;
GLfloat aspecto = 0.0f;
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
GLfloat ratio = 0.0f;

GLboolean HabilitaViewport = true;

int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Desenhos Bidimensionais - Viewports");

glutDisplayFunc(Desenha);
glutReshapeFunc(AlteraTamanhoJanela);
glutKeyboardFunc(TecladoNormal);
glutIdleFunc(idle);

Inicializa();

glutMainLoop();

return 0;
}

static void Desenha(void)
{
//Limpa a tela de visualizao com a cor preta
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

//Canto inferior esquerdo
glViewport(0, 0, iLargura, iAltura);
DesenhaQuadrado();

if (HabilitaViewport)
{
//Canto superior direito
glViewport(440, 280, 200, 200);
DesenhaQuadrado();
DesenhaBorda();
}

glutSwapBuffers();
}

// Funo que chamada quando uma tecla apertada
static void TecladoNormal(unsigned char key, int x, int y)
{
switch (key)
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
{
case 27 : // ESC sai do programa
exit(0);
break;
case 32 : // Barra de espao Habilita/Desabilita Viewport
if (HabilitaViewport)
HabilitaViewport = false;
else
HabilitaViewport = true;
break;
}
}

// Funo que executa rotinas padres do GLUT
static void idle(void)
{
glutPostRedisplay();
}

void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
// Evita a divisao por zero
if(h == 0) h = 1;

ratio = 1.0f * w / h;
// Atualiza as variveis
iLargura = w;
iAltura = h;

aspecto = (iLargura / iAltura);

//Seleciona o sistema de coordenadas do tipo Projeo
glMatrixMode(GL_PROJECTION);
//Carrega a matriz inicial do sistema de coordenadas selecionado
glLoadIdentity();

//Define Janela(Window) de visualizao 2D
gluOrtho2D (-win*aspecto, win*aspecto, -win, win);
}

void DesenhaQuadrado()
{
static GLfloat fAngulo = 0.0;

glPushMatrix();
//Rotaciona o Objeto
glRotatef(fAngulo, 1.0f, 0.0f, 0.0f );
glRotatef(fAngulo, 0.0f, 1.0f, 0.0f );
glRotatef(fAngulo, 0.0f, 0.0f, 1.0f );
glColor3f(1.0,0.0,0.0);
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
//Desenha um Quadrado
glBegin(GL_QUADS);
glVertex2f(-0.25f, -0.25f);
glVertex2f(-0.25f, 0.25f);
glVertex2f( 0.25f, 0.25f);
glVertex2f( 0.25f, -0.25f);
glEnd();
glPopMatrix();

glColor3f(0.0,1.0,0.0);
glBegin(GL_QUADS);
glVertex2f(-0.95f, 0.95f);
glVertex2f(-0.85f, 0.95f);
glVertex2f(-0.85f, 0.85f);
glVertex2f(-0.95f, 0.85f);
glEnd();

fAngulo += 0.05f;
}

void Inicializa()
{
//Limpa a tela com a cor preta RGBA
glClearColor(0.0, 0.0, 0.0, 1.0);

//Define a espessura da linha que compe a borda de cada viewport
glLineWidth(3);
}

void DesenhaBorda()
{
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_LINES);
//Linha Topo
glVertex2f(-1.0, 1.0);
glVertex2f(1.0, 1.0);

//Linha Direita
glVertex2f(1.0, 1.0);
glVertex2f(1.0, -1.0);

//Linha Base
glVertex2f(1.0, -1.0);
glVertex2f(-1.0, -1.0);

//Linha Esquerda
glVertex2f(-1.0, -1.0);
glVertex2f(-1.0, 1.0);
glEnd();
}


FIM DE CDIGO...

Executando o cdigo acima voc ver duas viewports.
So elas: a default que fica de fundo e uma no canto superior direito da tela que possui
os mesmos objetos s que de forma reduzida.

Exemplo com 4 viewports


CDIGO...

001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:

#include <GL/glut.h>

void DesenhaQuadrado();
void DesenhaLosango();
void DesenhaPoligono();
void DesenhaTriangulo();
void DesenhaBorda();

void Inicializa();

static void Desenha(void);
static void TecladoNormal(unsigned char key, int x, int y);
void AlteraTamanhoJanela(GLsizei w, GLsizei h);
static void idle(void);

GLint fLargura = 0;
GLint fAltura = 0;
GLint win = 0;
GLfloat aspecto = 0;

int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

glutCreateWindow("Utilizando vrios Viewports");

glutDisplayFunc(Desenha);
glutReshapeFunc(AlteraTamanhoJanela);
glutKeyboardFunc(TecladoNormal);
glutIdleFunc(idle);

Inicializa();

glutMainLoop();
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:

return 0;
}

static void Desenha(void)
{
//Limpa a tela de visualisao com a cor preta

glClear(GL_COLOR_BUFFER_BIT);

//Canto inferior esquerdo
glViewport(0, 0, fLargura/2, fAltura/2);
DesenhaQuadrado();
DesenhaBorda();

//Canto superior esquerdo
glViewport(0, fAltura/2, fLargura/2, fAltura/2);
DesenhaTriangulo();
DesenhaBorda();

//Canto superior direito
glViewport(fLargura/2, fAltura/2, fLargura/2, fAltura/2);
DesenhaLosango();
DesenhaBorda();

//Canto inferior direito
glViewport(fLargura/2, 0, fLargura/2, fAltura/2);
DesenhaPoligono();
DesenhaBorda();

glFlush();
}

// Funo que chamada quando uma tecla apertada
static void TecladoNormal(unsigned char key, int x, int y)
{
switch (key)
{
// caso aperte ESC sai do programa
case 27 :
exit(0);
break;
}
}

// Funo que executa rotinas padres do GLUT
static void idle(void)
{
glutPostRedisplay();
}
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:

void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
// Evita a divisao por zero
if(h == 0) h = 1;

// Atualiza as variveis
fLargura = w;
fAltura = h;

aspecto = (float) fLargura/fAltura;

// Inicializa o sistema de coordenadas
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// e Define Janela de visualizao 2D
gluOrtho2D (-win*aspecto, win*aspecto, -win, win);
}

void DesenhaQuadrado()
{
glColor3f(1.0,0.0,0.0);
//Desenha um Quadrado
glBegin(GL_QUADS);
glVertex2f(-0.25f, -0.25f);
glVertex2f(-0.25f, 0.25f);
glVertex2f( 0.25f, 0.25f);
glVertex2f( 0.25f, -0.25f);
glEnd();
}

void DesenhaTriangulo()
{
glColor3f(0.0,1.0,0.0);
//Desenha um Tringulo
glBegin(GL_TRIANGLES);
glVertex2f(-0.25f, -0.25f);
glVertex2f( 0.0f, 0.25f);
glVertex2f( 0.25f, -0.25f);
glEnd();
}

void DesenhaPoligono()
{
glColor3f(1.0,1.0,1.0);
//Desenha um Poligono
glBegin(GL_POLYGON);
glVertex2f( 0.0f, 0.50f);
glVertex2f(-0.25f, 0.25f);
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
glVertex2f(-0.25f,-0.25f);
glVertex2f( 0.0f, -0.50f);
glVertex2f( 0.25f,-0.25f);
glVertex2f( 0.25f, 0.25f);
glEnd();
}

void DesenhaLosango()
{
glColor3f(0.0,1.0,1.0);
//Desenha um Losango
glBegin(GL_POLYGON);
glVertex2f(-0.25f, 0.0f);
glVertex2f( 0.0f, 0.25f);
glVertex2f( 0.25f, 0.0f);
glVertex2f( 0.0f, -0.25f);
glEnd();
}

void Inicializa()
{
glClearColor(0.0, 0.0, 0.0, 0.0);

//Define a espessura da linha que compe a borda de cada viewport
glLineWidth(3);
}

void DesenhaBorda()
{
glColor3f(1.0, 1.0, 0.0);

glBegin(GL_LINES);
//Linha Topo
glVertex2f(-0.96, 0.96);
glVertex2f(0.96, 0.96);

//Linha Direita
glVertex2f(0.96, 0.96);
glVertex2f(0.96, -0.96);

//Linha Base
glVertex2f(0.96, -0.96);
glVertex2f(-0.96, -0.96);

//Linha Esquerda
glVertex2f(-0.96, -0.96);
glVertex2f(-0.96, 0.96);
glEnd();
}


FIM DE CDIGO...

Executando o cdigo acima voc ver a viewport principal dividida em 4.
Em cada uma tem um desenho geomtrico diferente. Dessa forma fica claro a forma de
trabalhar com vrias janelas de exibio ao mesmo tempo.

Com essa tcnica de viewports podemos incrementar em nosso jogo um espelho
retrovisor, mini-mapa, radar, janela...etc. A imaginao e as aplicaes so infinitas...
Se houver alguma dvida vamos movimentar o frum.

Abrao!