Kurs programowania w asemblerze
Tryb 13H
Wstęp
Zacznę od wyjaśnienia, co to jest to tajemnicze 13H. Otóż tryb 13H jest to pewien tryb graficzny, który można uzyskać na chyba każdej karcie graficznej bez żadnych dodatkowych sterowników. Daje on nam rozdzielczość 320x200 i 256 kolorów. Dzięki temu można tworzyć programy wykorzystujące więcej kolorów, np. ogień w bardzo prosty sposób. Ogień jest świetnym przykładem efektu graficznego, którego nie da się uzyskać w zwykłym (standardowym) trybie graficznym dostępnym np. w Turbo Pascal-u (tam mamy 16 kolorów). Tryb ten ma również inne zalety. Bardzo łatwo się go używa (programuje) i nasze procedury zapisane w Asemblerze są szybsze i pewniejsze.
Artykuł który czytasz jest dość specyficzny. Może go czytać zarówno programujący w Pascalu, C/C++, czy Asemblerze. Starałem się wszystko jak najdokładniej tłumaczyć i popierać przykładami (w tych językach). Życzę miłej nauki!
Opis
Jak już wspomniałem tryb ten daje nam rozdzielczość 320x200 i 256 kolorów. Przypominam jednak że współrzędne podajemy od 0, czyli X: 0..319 i Y:0..199. Zajmuje więc 64000 bajtów pamięci (320x200=64000). Wiemy również, że mniej więcej tyle właśnie zajmuje jeden segment pamięci komputera. Segment pamięci ekranu w trybie 13H zaczyna się o adresie A000H. Literka H oznacza, że liczba zapisana jest w systemie szesnastkowym.
Włączenie/Wyłączenie trybu graficznego
Do obsługi trybu graficznego służy przerwanie 10H. Funkcja 0H (Ah=0) ma za zadanie zmiany trybu graficznego/tekstowego. Dostępne są następujące tryby:
| AL | Rodzaj | Rozdz. | Kolory | Karta | Segment pamięci |
|---|---|---|---|---|---|
| 0 | tekstowy | 40x25 | 16/8 | CGA/EGA | B800H |
| 1 | tekstowy | 40x25 | 16/8 | CGA/EGA | B800H |
| 2 | tekstowy | 80x25 | 16/8 (odcieni) | CGA/EGA | B800H |
| 3 | tekstowy | 80x25 | 16/8 | CGA/EGA | B800H |
| 4 | graficzny | 320x200 | 4 | CGA/EGA | B800H |
| 5 | graficzny | 320x200 | 4 (odcienie) | CGA/EGA | B800H |
| 6 | graficzny | 640x200 | 2 | CGA/EGA | B800H |
| 7 | tekstowy | 80x25 | 3 | MDA/EGA | B000H |
| 0DH | graficzny | 320x200 | 16 | EGA/VGA | A000H |
| 0EH | graficzny | 640x200 | 16 | EGA/VGA | A000H |
| 0FH | graficzny | 540x350 | 3 | EGA/VGA | A000H |
| 10H | graficzny | 640x350 | 4 lub 16 | EGA/VGA | A000H |
| 11H | graficzny | 640x480 | 2 | VGA | A000H |
| 12H | graficzny | 640x480 | 14 | VGA | A000H |
| 13H | graficzny | 320x200 | 156 | VGA | A000H |
My włączamy tryb 13H, czyli nasza procedura Init13H wygląda tak: (pascal)
Procedure Init13H; Assembler;
Asm;
MOV AX,0013H;
INT 10H
end;
wersja dla C/C++
[c]
void Init13H (void)
{
union REGS regs;
regs.h.ah=0x00;
regs.h.al=0x13;
int86(0x10,®s,®s);
}
[/c]
Na koniec pracy w grafice trzeba ten tryb zamknąć, a dokładniej mówiąc wywołać tryb standardowy tekstowy (3). Nasza procedura Close13H wygląda więc tak:
Procedure Close13H; Assembler;
Asm;
MOV AX,0003H
INT 10H
End;
a dla C:
[c]
void Close13h (void)
{
union REGS regs;
regs.h.ah=0x00;
regs.h.al=0x03;
int86(0x10,®s,®s);
}
[/c]
Instrukcje
Punkt o współrzędnych [0,0] ma więc adres A000H:0. Tak więc punkt o współrzędnych [X,Y] znajduje się w pamięci pod adresem A000:Y*320+X.
Turbo Pascal daje nam możliwość odwoływania się do komórek pamięci za pomocą instrukcji MEM. Jeśli chcemy odczytać wartość danej komórki piszemy:
X:=MEM[segment:offset];
Jeśli chcemy zmienić wartość danej komórki, napiszemy:
MEM[segment:offset]:=X;
Prosta procedura rysująca punkt na ekranie mogłaby wyglądać więc tak:
Procedure PutPixel(X,Y : Integer; Kolor : Byte);
Begin
MEM[$A000:Y*320+X]:=Kolor;
End;
Funkcja odczytująca kolor punktu mogłaby wyglądać tak:
Function GetPixel(X,Y : Integer) : Byte;
Begin
GetPixel:=MEM[$A000:Y*320+x];
End;
Obie te instrukcje ze względu na działanie matematyczne (Y*320+X) oraz użycie Pascal-owej instrukcji MEM są bardzo wolne. Dlatego należy używać procedury do wstawiania punktu napisanej w Asemblerze. Wiemy, że ten język jest najszybszy. W Asemblerze nasza procedura PutPixel wyglądałaby np. tak:
Procedure PutPixel(X,Y : Integer; Kolor : Byte); Assembler;
Asm
MOV AX,0A000H
MOV ES,AX ; ES - segment pamięci ekranu
MOV DX,Y ; DX=Y
MOV DI,X ; DI=X
SHL DX,6 ; DX:=DX*64 [DX=Y*64]
ADD DI,DX ; DI:=DI+DX [DI=X+Y*64]
SHL DX,2 ; DX=DX*4 [DX=DX*64*4=DX*256, DX=Y*256]
ADD DI,DX ; DI:=DI+DX [DI=X+Y*64+Y*256 =X+Y(256+64)]
MOV AL,Kolor ; AL=kolor
MOV ES:[DI],AL ; MEM[ES:DI]:=AL;
End;
Sprytne nie. Ta procedura jest znacznie szybsza od poprzedniej. Działa w następujący sposób:
MOV AX,0A000H MOV ES,AX
W rejestrze ES mamy teraz segment naszego ekranu. Wystarczy wykonać działanie Y*320+X. Można to zrobić używając instrukcji MUL, która służy do mnożenia, jednak jest ona strasznie wolna. Lepiej zastosować tutaj SHL, czyli przesunięcie logiczne. Jest znacznie szybsze, a można za pomocą niego wykonać mnożenie przez potęgę liczby 2. Działanie 320*Y zapisujemy jako Y*256+Y*64. Liczby 256 i 64 są potęgami liczby 2. Dlaczego akurat 256 i 64? Bo wiemy ze wzoru (a+b)*C=A*c+b*c, czyli (256+64)*Y.
Instrukcja GetPixel w Asemblerze jest bardzo podobna.
Function GetPixel(X,Y : Integer) : Byte; Assembler
Asm;
MOV AX,0A000H
MOV ES,AX
MOV DX,Y
MOV DI,X
SHL DX,6
ADD DI,DX
SHL DX,2
ADD DX,DI
MOV AL,ES:[DI]
MOV @Result,AL
End;
No dobra. Wiemy już jak włączyć tryb graficzny, jak go wyłączyć. Umiemy stawiać punkty, a nawet sprawdzać kolor już postawionych. Zróbmy teraz coś trudniejszego. Narysujmy linię prostą! Jest wiele algorytmów rysowania linii. Ja przedstawię jeden z nich. Algorytm Bresenhama:
Procedure Linia(x1,y1,x2,y2,Kolor : integer);
var c,i : integer;
sx,sy,y,x : real;
begin
if x2<x1 then
begin
c:=x1;
x1:=x2;
x2:=c;
end;
if y2<y1 then
begin
c:=y2;
y2:=y1;
y1:=c;
end;
if (x2-x1)>(y2-y1) then
begin
sy:=(y2-y1)/(x2-x1);
y:=y1;
for i:=x1 to x2 do
begin
putpixel(i,round(y),Kolor);
y:=y+sy;
end;
end else
begin
sx:=(x2-x1)/(y2-y1);
x:=x1;
for i:=y1 to y2 do
begin
putpixel(round(x),i,Kolor);
x:=x+sx;
end;
end;
end;
To prosty algorytm, ale nie będę się tutaj nad nim rozpisywał. Zapraszam do zajrzenia do działu ALGROYTMY tam zostanie dokładnie omówiony. Zachęcam również do ściągnięcia pliku CirLine, gdzie Mark Feldman opisuje algorytm rysowania linii i koła. Zajrzyj także do działu Źródła algorytmów i Teksty
CDN...
Programy
Przykładowe programy w Turbo Pascalu.
| RAY | Poruszanie się w trójwymiarowej przestrzeni | 9 KB | ??? |
| Koniec | Efekt płynącego pionowo tekstu | 1 KB | Binboy |
| Napis | Obracany napis | 1 KB | Binboy |
| Obrót | Napis wyginający się na sinusoidzie i obracający się o 360 stopni | 1 KB | Binboy |
| Prostopadłościan | Obracane wierzchołki prostopadłościanu | 1 KB | Binboy |
| Scrool | Płynący tekst | 1 KB | Binboy |
| Sinusoidalny napis | Napis płynący po sinusoidzie | 1 KB | Binboy |
| Gwiazdy | Latające gwiazdy | 1 KB | Binboy |
| Wyginas | Napis wyginający się po sinusoidzie | 1 KB | Binboy |
| Water | Fajny efekt z wodą | 7 KB | ??? |
| Laser | Bardzo ciekawy efekt graficzny | 5 KB | ??? |
| Cień | Obracający się, cieniowany trójkąt | 15 KB | ??? |
| Lupa | Efekt lupy | 77 KB | ??? |
| Floor | Teksturowanie powierzchni | 5 KB | ??? |
| Pixturn | Trójwymiarowy tunel | 7 KB | ??? |
Przykładowe programy w asemblerze.
| Dots | Obracająca się, stworzona z punktów kula | 12 KB | ??? |
| Filld | Obracający się, wypełniony kolorami sześcian | 8 KB | ??? |
| Gouraud | Obracający się sześcian z cieniowaniem | 12 KB | ??? |
| Gwiazdy | Latające gwiazdy | 3 KB | ??? |
| Linie | Obracający się, wykonany z linii sześcian | 7 KB | ??? |
| Plazma | Ciekawy efekt graficzny | 91 KB | ??? |
| Scape | Trójwymiarowa powierzchnia | 103 KB | ??? |
| Scrool | Prosty scrool z ciekawą czcionką | 28 KB | ??? |
| Tunel | Trójwymiarowy tunel | 10 KB | ??? |
Moduły potrzebne do uruchomienia niektórych programów.
| Graphhigh | Moduł do obsługi różnych trybów graficznych, m.in. VESA (wysokie rozdzielczości) | 6 KB | Binboy |
| Graphics | Moduł do obsługi trybu graficznego 13H. Umożliwia m.in. wstawianie grafiki PCX. Jest w wersji skompilowanej. | 4 KB | Binboy |
| Vga_lib | Szybki moduł graficznych do trybu 13H | 12 KB | ??? |
| Vlib | Moduł graficzny | 2 KB | Grend |
| Gif | Moduł umożliwiający wyświetlanie plików graficznych GIF | 7 KB | ??? |
| Pcx | Moduł do obsługi plików graficznych PCX | 5 KB | Bartok |
| Ikey | Moduł do obsługi klawiatury. Umożliwia kontrolowanie kilku klawiszy jednocześnie | 1 KB | Bartok |
| Mysz | Moduł do obsługi myszki | 2 KB | ??? |
| Cosin | Moduł wspomagający obliczenia SIN i COS | 0.5 KB | Grend |
