VGA – Tutorial 1 – Denthor

                  --==[ PARTE 1 : O Básico]==--

Autor: DENTHOR do ASPHYXIA
Atualizado por Snowman
Traduzido por Krull >>> tradução revisada e atualizada em 2019

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

Introdução

Olá! Aqui é o Denthor do ASPHYXIA, ou Grant Smith. Este programa de treinamento tem como alvo todos os jovens que fazem demos por aí. Estou assumindo que o leitor é bem jovem, tem um pouco de noção de matemática da 6ª serie, ja tenha feito alguns programas antes, provavelmente em BASIC, e quer aprender como escrever seu próprio demo sozinho.

É isso que eu vou fazer. Descrever como certas rotinas funcionam, e até dar algum código fonte de como se faz. O código fonte assume que você tenha uma placa de vídeo VGA que suporte a resolução de 320x200x256. Vou também assumir que você tenha o Turbo Pascal 6.0 ou maior (isso por que parte do código fonte vai estar em Assembly, e o Turbo Pascal 6.0 torna isso incrivelmente fácil de se usar). [Além disso, foi incluído código fonte em C++, de modo que agora você tem uma opção]. Ao final da primeira “rodada” de seções, você estará preparado para codificar algum demos legal sozinho. A informação que você precisa, eu vou te passar, mas é você quem decide a maneira mais espetacular de usá-la. Por que não baixar alguns de nossos demos para ver par aonde estou tentando guiá-lo?

[Nota: essas coisas entre colchetes foram adicionadas por Snowman. O texto original foi mantido inalterado quase todo, exceto pela inclusão do material em C++]

Estarei postando uma parte por semana na Mailbox BBS. Eu já tenho a primeira “rodada” de seções prontas, mas se você também quiser seções em outras áreas de código, deixe uma mensagem para Grant Smith, por e-mail, ou abra um chat aqui nesse forum. Eu vou fazer um pouco de moderação e apontar coisas que podem ter sido feitas erradas.

Nesta, a primeira parte, eu vou mostrar como você deveria definir seu programa Pascal ou C++, para entrar no modo gráfico de vídeo em 320x200x256 sem usar arquivos BGI, e vários métodos de putpixel e um utilitário de clearscreen.

NOTA : Eu jogo código fonte durante todas as minhas explicações. Você não precisa copiar tudo em todos os lugares, no final de cada parte eu vou colocar um programinha que usa todas as novas rotinas que aprendemos. Se você não entendeu uma seção por completo, deixe uma mensagem me dizendo o que você não entendeu, ou me perguntando como eu consegui alguma coisa, etc, e eu vou tentar explicar. Uma última coisa: quando você achar um erro que eu tenha feito, mande um email pra mim, e eu vou consertar. Contudo, eu não sei C++ atualmente, assim, se você tiver problemas com esse código fonte, contate o Christopher Mann.

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

OBS

Oi, de novo! Sinto ter que colocar isso, mas vamos lá. Todo código fonte obtido dessa série de programas de instrução será usado sob sua própria conta e risco. Denthor e o grupo ASPHYXIA não serão responsáveis por quaisquer perdas ou danos sofridos por qualquer um, pelo uso desse código. Olha, pessoal, o código que vou dar para vocês já foi usado por nós em Demos, Aplicativos, etc, e nunca tivemos alguma reclamação de defeitos em máquinas, mas se algo der errado em seu computador, não nos culpe. Desculpe, mas é assim que é.

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

O modo MCGA e como se entrar nele em Pascal ou em C++ sem usar BGI

Vamos encarar: BGIs são praticamente sem valor para a programação de demos. É difícil encontrar algo que seja mais devagar que as units de BGI para fazer gráficos. Outra coisa é, elas não são, na verdade, para telas de 256 cores, de maneira alguma. Você tem que obter uma BGI específica 256VGA para conseguir isso em Pascal, e não vale a pena.

Então, a pergunta continua, como entrar no modo MCGA 320x200x256 em Pascal ou C++ sem BGI? A resposta é simples: linguagem Assembly. Obviamente, assembly tem um monte de funções para controlar a placa VGA, e esse é apenas uma delas. Se você olhar no Guia de Assembly do Peter Norton, ele diz isso …

INT 10h, 00h (0) Define o modo de Vídeo

Acerta o modo de Vídeo 

   Ao entrar:     AH         00h
                  AL         modo de vídeo

   Retorno:       Nenhum

   Registradores destruídos:   AX, SP, BP, SI, DI

Tudo bem, ok, mas o que isso significa? Significa que se você plugar o modo de vídeo em AL e chamar a interupção 10h, SHAZAM! você está no modo de vídeo que você escolheu. Agora, o modo de vídeo MCGA é o 13h, e aqui está como se faz:

PASCAL] 
Procedure SetMCGA;
   BEGIN
     asm
           mov     ax,0013h
           int     10h
     end;
   END;
 [C++] 
void SetMCGA() {
_AX = 0x0013;
geninterrupt (0x10);
}

Pronto! Uma chamada àquela rotina, e BANG você está no modo 320x200x256. Nós ainda não podemos fazer nada, na verdade, então para voltar ao modo texto, você define o modo de vídeo para 03h, como visto abaixo:

[PASCAL] 
Procedure SetText;
   BEGIN
     asm
           mov     ax,0003h
           int     10h
     end;
   END;
 [C++] 
void SetText() {
_AX = 0x0003;
geninterrupt (0x10);
}

BANG! Estamos de volta ao modo texto! “Agora, pra que serve isso”, suas mentes estão gritando… “Podemos entrar naquele modo, mas como podemos realmente MOSTRAR algo na tela?” Para tal, você deve seguir para a próxima seção….

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

Limpando a tela com uma cor específica

Agora que estamos no modo MCGA, como limpamos a tela? A resposta é simples: Você só precisa se lembrar que o endereço base da tela é a000h. A partir de a000h, os próximos 64000 bytes são o que na verdade é mostrado na tela (Nota: 320 * 200 = 64000). Assim, para limpar a tela, você deve usar o comando fillchar desse jeito:

[PASCAL]
  FillChar (Mem [$a000:0],64000,Col);
[C++]
  memset(vga, Col, 0xffff);  
   // "vga" é um ponteiro para o endereço 0xa000

O que o comando mem passa é o segmento base e o offset de uma parte da memória: neste caso a base da tela é o segmento, e estamos começando do topo da tela; offset (deslocamento) 0. O 64000 [0xffff] é o tamanho da tela (veja acima), e Col é um valor entre 0 e 255, que representa a cor com que se deseja limpar a tela.

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

Colocando um pixel na tela (dois métodos diferentes)

Se você olhar no Norton Guides sobre colocar um pixel na tela, vai ver isso:

Escreve um ponto de pixel de uma cor especificada em uma coordenada especificada na tela.

Ao entrar:     AH         0Ch
               AL         cor do pixel
               CX         posição horizontal do pixel
               DX         posição vertical do pixel
               BH         número de página da tela (para modos gráficos com mais de 1 pagina)

Retorno:       Nenhum

Registradores destruídos:      AX, SP, BP, SI, DI

Como visto no nosso exemplo SetMCGA, você deveria escrever isso dessa maneira:

[PASCAL] 
Procedure INTPutpixel (X,Y : Integer; Col : Byte);
   BEGIN
     asm
        mov        ah,0Ch
        mov        al,[col]
        mov        cx,[x]
        mov        dx,[y]
        mov        bx,[1]
        int        10h
     end;
   END;
[C++] 
void INTPutpixel(int x, int y, unsigned char Col) {
     _AH = 0x0C;
     _AL = Col;
     _CX = x;
     _DX = y;
     _BX = 0x01;
     geninterrupt (0x10);
   }

O X seria a coordenada-x, e o Y seria a coordenada-y, e Col seria a cor do pixel a colocar a tela. Note que o MCGA tem 256 cores, numerados de 0 a 255. A pallette startoff tem baixa qualidade, e eu vou mostrar como alterá-la na minha próxima lição, mas por enquanto você terá que caçar cores que se encaixem no que você vai querer fazer. Felizmente, um byte vale de 0 a 255 [em C++, “byte”=”unsigned char”], então é isso o que passamos para a variável Col. Dê uma olhada no que se segue.

CGA = 4 cores.
4x4 = 16
EGA = 16 cores.
16x16 = 256
VGA = 256 cores.
Assim, um EGA é um CGA ao quadrado, e um VGA é um EGA ao quadrado ;-)

De qualquer modo, de volta à realidade. Embora a procedure/function acima seja escrita em Assembly, ela é muuuuito lenta. “Por que?”, ouço suas mentes gritando. A razão é simples: ela usa interrupções (chama a INT 10h). Interrupções são leeeeentas… o que é ok para entrar no modo MCGA, mas não para tentar colocar um pixel rapidamente. Então, por que não tentamos o seguinte…

PASCAL] 
Procedure MEMPutpixel (X,Y : Integer; Col : Byte);
   BEGIN
     Mem [VGA:X+(Y*320)]:=Col;
   END;
[C++] 
void MEMPutpixel (int x, int y, unsigned char Col) {
     memset(vga+x+(y*320),Col,1);
   }

O comando mem/memset, como visto acima, permite apontar para um certo ponto na memoria… O ponto de inicio é a000h, a base da memória VGA, e então especificamos o quanto pra dentro dessa memória começamos.

Pense em seu monitor dessa forma. Ele começa no canto superior esquerdo como sendo o 0. Ao passo que você aumenta esse número, você começa a andar pela tela para a direita, até chegar em 320. Em 320, você terá percorrido a tela toda e volta ao lado esquerdo, um pixel para baixo. Isso até você atingir 63999, no fundo à direita da tela. É assim que chegamos à equação X+(Y*320). Para todo aumento em Y devemos aumentar o número em 320. Uma vez que estamos no início da linha Y que queremos, adicionamos X o quanto queremos que seja. Isso nos dá o ponto exato de memória em que queremos estar, e então o setamos igual ao valor do pixel que queremos.

O método MEM de putpixel é muito mais rápido, e é mostrado no programa de amostra no fim dessa lição. O time da ASPHYXIA não usa nem putpixel; usamos um putpixel do tipo DMA-direto-na-tela-mata-sua-mae-com-um-machado que é rápidão. Nós vamos mostrá-la. Mas só para aqueles de vocês que nos mostrarem que estão falando sério sobre codificação. Se você fizer alguma coisa, mande para mim, estarei muito interessado em ver. Lembre-se, se você conseguir alguma coisa desses treinamentos, mencione isso nos seus demos, ou MANDE SEU DEMO PARA NÓS!

Bem, depois disso vem o programa demo; divirta-se com ele, ENTENDA-O, e semana que vem eu vou começar com alguma diversão com a pallette.

Vejo vocês todos mais tarde,
– Denthor
– Krull

A Nova Krull's HomePage