VGA – Tutorial 14 – Denthor

                       --==[ PARTE 14 ]==--

Para obter os programas mencionados neste tutorial, por favor baixe o zip com a versão antiga do tutorial, neste link.

Introdução

Olá! Os exames estão pertos (de novo 🙁 ), então achei que era melhor fazer esse tutorial. Como de costume, parece ter havido algum grande atraso entre esse e o anterior… desculpem por isso 😉

Bem, esse treinamento é principalmente sobre quatro coisas: Glenzing, polígonos mais rápidos, ponto fixo e assembly. O programa de amostra é basicamente o do tutorial 9 reescrito para incluir tudo isso acima.

Eu vou passar nesse assuntos pela ordem, e espero que você não tenha problemas para pegar o conceito. A propósito, algum de vocês lê os arquivos textos? Eu me encontro respondendo questões via email, etc, que foram discutidas na parte de texto dos treinamentos… ah, bem, vou escrever tudo errado então 😉

Por favor, não envie email para smith9@batis.bis.und.ac.za mais… eu não sei por quanto tempo mais a conta será válida (Como uma pessoa não-BIS entrar numa máquina com BIS UNIX no diretório BIS2? Se seu nome for Denthor, imagino 😉 Bem, já tive 8 meses de uso dela. A conta expira no dia do Natal, de qualquer modo…) Então, por favor, mande todas as mensagens para denthor@beastie.cs.und.ac.za

Se você gostaria de me contactar, ou ao time, há muitos modos que você pode fazê-lo: 1) Escrever uma mensagem para Grant Smith/Denthor/Asphyxia em email
privado na ASPHYXIA BBS.
2) Escrever para Denthor, Eze, Goth, Fubar ou Nobody na Connectix.
3) Escrever para:
Grant Smith
P.O.Box 270 Kloof
3640
Natal
África do Sul
4) Ligar para mim (Grant Smith) no número (031) 73 2129
(deixe uma mensagem se você ligar quando eu estiver na faculdade)
Ligue para +27-31-73-2129 se você está ligando de fora da África do Sul (a conta é sua ;-))
5) Escrever para denthor@beastie.cs.und.ac.za
6) Escrever para asphyxia@beastie.cs.und.ac.za para falar com todos nós de uma vez.

OBS1 : Se você é um representante de uma companhia ou BBS e quer que a ASPHYXIA faça um demo para você, mande um email pra mim; podemos discutir.
OBS2 : Se você fez/tentou fazer um demo, MANDE PARA MIM! Estamos nos sentindo muito solitários e queremos encontrar/ajudar/trocar código com outros grupos de demos. O que você tem a perder? Mande uma mensagem aqui e podemos ver como transferir. Nós realmente queremos ouvir de você.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

O que é glenzing?

Essa é fácil. Imagine, num objeto 3D, que todos os lados sejam feitos de vidro colorido. Isso significa que toda vez que você olhar por aquele lado, tudo vai ficar tingido de certa cor.

Em ascii …


+---------+
| <--|---Azul claro
| |
+--------+ |
| | <-|-----|---Azul escuro
| +---|-----+
| <--|---------Azul claro
+--------+

Então, onde os dois lados se sobrepõem, o valor da cor dos dois lados são adicionados. Fácil, não? Também é fácil de codificar. É assim que você faz:

Sete sua pallete para uma boa gama de cores.
Desenhe seu primeiro polígono.
Enquanto desenhar o polígono 1, ao invés de colocar uma cor no pixel, pegue o pixel do fundo, adicione 1 a ele, e então use esse resultado.
Desenhe seu segundo polígono.
Enquanto desenhar o polígono 2, ao invés de colocar uma cor no pixel, pegue o pixel do fundo, adicione 2 a ele, e então use esse resultado.
e assim por diante.

Assim, se a cor atrás do polígono 1 era 5, você coloca o pixel com cor 6 na verdade.

Se você fizer isso para cada pixel de cada lado de seu objeto 3D, você está fazendo glenzing. Isso é obviamente um pouco mais devagar que apenas desenhar um item diretamente, mas no programa de amostra ele vai bem rapidinho… isso é por causa das seções seguintes…

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Polígonos mais rápidos

No tutorial 9, você provavelmente notou que estávamos usando uma multiplicação para cada linha do polígono que desenhamos. Isso não é bom. Vamos descobrir como acelerar um pouco, vamos…

Com o método de multiplicar, nós íamos em cada linha, para calcular os valores mínimo de x e máximo de x para aquela linha.

                  +
           ------/-\------- Achar min x e max x, desenhar uma reta
                /   \        entre eles.
              +      +
                \   /
                 \ /
                  +

Que tal se calculássemos todos os min e max X para cada linha primeiro, e então apenas passássemos por um array desenhando-as? Poderíamos fazê-lo “escaneando” cada lado por vez. Aqui está como nós fazemos isso:

                    + 1
                   /
                  /
               2 +

Vamos do ponto 1 ao ponto 2. Para cada Y que nós descemos, nos movemos a um valor X constante. Esse valor é calculado desse modo:

       xchange := (x1-x2)/(y1-y2)

Lembra-se de gradientes? Isso é como você calculava a inclinação da reta láááá na escola. Você nunca achou que isso teria algum uso, não é? 😉

De qualquer forma, com esse valor podemos fazer o seguinte:

For loop1:=y1 to y2 do BEGIN
  [ Ponha alguma coisa legal aqui ]
  x:=x+xchange;
END;

e vamos passar em todos os valores X que precisamos para aquela reta. Esperto, hein?

Agora vamos à parte esperta. Você tem um array, de 0 a 199 (que são todos os valores possíveis para Y que seu polígono pode ter na tela). Dentro dele, você tem 2 valores, que podem ser seu min x e seu max x. Você começa com min x sendo um número gigante, e max x sendo um número baixo. Então você escaneia um lado. Para cada y, verifique se um dos seguintes aconteceu:
Se o valor X é menor que minX no seu array, faça minX ser igual
a esse valor X
Se o valor X é maior que maxX no seu array, faça maxX ser igual
a esse valor X

O loop agora parece com esse:

For loop1:=y1 to y2 do BEGIN
  if x>poly[loop1,1] then poly[loop1,1]:=x;
  if x<poly[loop1,1] then poly[loop1,1]:=x;
  x:=x+xchange;
END;

Fácil? faça isso para todos os quatro lados (você pode mudar isso para polígonos com números diferentes de lados), e então você tem todos os valores mínimos e máximos de x que você precisa para desenhar seu polígno.

No programa de amostra, se você substituir a rotina Hline com aquela que desenha sólidos, você poderia usar a drawpoly para sólidos.

Até essa procedure é acelerada na próxima seção, em ponto fixo.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

O que é ponto fixo?

Você já notou como os números reais são lentos? Eu digo leeeeentos. Você pode ganhar um grande aumento de velocidade na maioria dos programas se transformar seus reais em inteiros, words, etc. Mas, ouço vocês chorando, o que acontece com o pedaço fracionário tão necessário, depois do ponto decimal? A resposta? Você guarda esse pedaço. Aqui está como.

Digamos que você tem uma word, que tem 16 bits. Se você quiser usá-la como um valor de ponto fixo, você pode separá-la em duas seções, uma delas guarda o valor inteiro, e a outra segura a fração.

         00000000  00000000   <-Bits
         Inteiro   Fração

O número 6.5 seria mostrado então desse modo:

         Byte Superior   :  6
         Byte Inferior   :  128

128 é a metade (ou .5) de 256, e no caso da seção com a fração, 256 seria igual a 1 número inteiro.

Então, digamos que tivéssemos 6.5 * 2. Usando reais isso seria um MUL lento, mas com ponto fixo…

     Byte Superior        :  6     
     Byte Inferior    :  128
     Valor       :  1664   <-Isso é o valor verdadeiro da word, isto é, (byte superior*256)+byte inferior.         
        Isso é como o computador vê a word.

     1664 shl 1 = 3328    <-shl 1 é o mesmo que *2, apenas mais rápido.
     Byte Superior        :  13
     Byte Inferior    :  0

Como você pode ver, conseguimos o resultado certo! E numa fração do tempo que uma multiplicação de um real poderia ter levado. Você pode adicionar e subtrair valores de ponto fixo sem brigas, e multiplicar e dividir por valores normais também. Quando você precisar da parte inteira do número, pode ler só o byte superior, ou fazer o seguinte

                 inteiro = word shr 8
     exemplo:     1664 shr 8 = 6

Como você pode ver, a fração é truncada. Obviamente, quanto mais bits você separar para a seção da fração, mais preciso será seu cálculo, mas menor será o número inteiro que você poderá ter. Por exemplo, nos números acima, o valor máximo de seu número acima era 256, bem longe do máximo 65535 de uma word normal (não-ponto fixo).

Há muitas brigas ao usar ponto fixo (vá em frente, tente dar um shift num número negativo), a maioria das quais tem a ver com fato que você tem diminuído severamente o número máximo que você pode ter, mas confie em mim, a velocidade vale a pena (com longintegers, e/ou registradores extendidos do 386, você pode até ter ponto fixo 16×16, o que significa alta precisão e valores máximos altos)

Tente escrever um programa usando ponto fixo. Não é difícil e você vai consegui-lo perfeitamente, bem fácil. Confie em mim, eu sou um
programador de demos 😉

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Assembly

No programa de amostra eu usei um ou dois comandos em assembly que eu não discuti com vocês… aqui estão eles…

imul valor
Isso é o mesmo que mul, mas para valores inteiros.
Ele multiplica ax pelo valor. Se o valor for uma
word, ele retorna o resultado em DX:AX

sal registrador,valor
Esse é o mesmo que shl, mas é aritmético,
em outras palavras, ele trabalha com inteiros.
Se você tivesse que fazer shl num valor negativo,
o resultado poderia não fazer nenhum sentido
para você.

rcl registrador,valor
Isso é o mesmo que shl, mas depois de fazer
o shift, o valor no flag de carry é colocado
no bit mais à direita, que ficou vago. O flag
de carry é setado quando você faz uma operação
onde o resultado é maior que o maior valor
possível da variável (geralmente 65535 or 32767)
por exemplo:
mov ax,64000
shl ax,1 {<- flag de carry agora = 1}

Para mais informações sobre shift, etc, releia o tutorial 7, ele fala sobre esse conceito em detalhes.

(by Krull: a explicação a seguir requer que você esteja usando o Turbo Pascal)
O programa de amostra é basicamente o tutorial 9 reescrito. Para ver como as coisas em assembly funcionam, faça o seguinte… entre em modo de 50 linhas (MUITO mais fácil de depurar), aperte Alt-D e então R. Aparece uma pequena caixa com todos os seus registradores, segmentos, etc, e seus valores. Mova-a para onde você quiser, então volte à tela do seu programa (aperte ALT e o número da tela), e mude o tamanho da janela de modo que você tenha as duas na tela de uma vez (Alt-5 para alterar o tamanho) então use F4, F7 e F8 para andar passo a passo no programa (você sabe como). O valor atual dos registradores sempre estará naquela caixa.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Fechando

Bem, é isso aí. O programa de amostra pode começar sendo um pouco intimidador para alguns quando olham para ele pela primeira vez, mas apenas lembre-se de lê-lo com o tutorial 9, está muito pouco diferente, só que agora tem ponto fixo e um pouco de assembly.

Antes que eu esqueça, com o Tutorial 13 o programa trava se você tiver checagem de erros ligada. É assim que você resolve:

1) Desligue a checagem de erro ou
2) Faça o logo ser um ponteiro, e pegue e libere a memória ou
3) Leia o logo diretamente para a tela ou
4) Use o comando {$M ……} com vários valores no topo do programa
até que funcione.

Eu prefiro as opções 3 ou 2, mas, ei… o problema era que o logo era muito grande (16k), e o Pascal gosta de reclamar 😉

Eu estou em dúvida se eu deveria continuar fazendo quotes… aqui está uma conversa que tive com a Pipsy, depois que a conversa em grupo mudou pra ver se éramos normais ou não…

Eu : Eu sou normal.
Pipsy : Não você não é.
Eu : Prove.
Pipsy : Olha só para seus quotes em seus treinamentos.
Eu : O quê? Você acha que eles são estranhos?
Pipsy : Esquisitos demais.
EU : Você quer dizer que existe uma linha de esquisitice, e eu a cruzei?
Pipsy : Sim.

Foi meio um corte de conversa aquilo, então paramos ali.

De qualquer modo, esse treinamento não terá quote… que tal um disclaimer? Sinta-se livre para usá-lo em suas mensagens…


As visões expressas acima são minhas e não da Novell. Na verdade, eu nunca trabalhei com eles na minha vida!

Byeeee….

  • Denthor
    18:57
    9-9-94
  • Krull

A Nova Krull's HomePage