Warsztat.GDCompo!ProjektyMediaArtykułyQ&AForumOferty pracyPobieranie

Opisz napotkaną sytuację, a redakcja niezwłocznie znajdzie rozwiązanie!

wyślij anuluj

Tryb 13h

Tekst został importowany z Warsztatowych artykułów. Jego oryginalnym autorem jest £ukasz "Lux" Więcek. Jeżeli został importowany poprawnie, usuń ten szablon!

To jest mój pierwszy tekst, więc proszę o wyrozumiałość... :-)

Wstęp

Tryb 13h (dziesiętnie 19) jest trybem graficznym VGA, a jego nazwa bierze się z numeru wśród trybów na karcie VGA. Potrafi on wyświetlać obraz w rodzielczości 320x200 przy 256 kolorach.

Wielu poczatkujacych programistów używających wcześniej tzw. grafiki BGI (640x480x16 kolorów) zauważyło pewnie małą ilości kolorów, powolną pracę i uciążliwe migotanie obrazu. Jak temu zaradzić? Odpowiedź jest prosta - używając trybu 13h. Żeby nie było niejasności zróbmy

Porównanie trybu 13h i grafiki BGI

Tryb13hBGI
Rozdzielczość i kolory320x200x256640x480x16
Rozmiar buforu ekranu64 KBmin. 150 KB
Możliwość buforowania ekranuTakNie
Prędkość działaniaDużaMała
Plusy+ 256 kolorów
+ Duża prędkość działania
+ Mały bufor ekranu i możliwość usunięcia migotania obrazu
+ Rozdzielczość wyższa niż w przypadku trybu 13h
Minusy- Niska rozdzielczość- 16 kolorów
- Powolne działanie
- Brak możliwość usuniecia migotania ekranu i duży rozmiar buforu ekranu

Jak widiać tryb 13h wygrywa dość wyraźnie. Ma jeszcze jedną zaletę - świetnie nadaje się do pisania efektów graficznych (efektu ognia, śniegu, gwiazd 3D, wody, wybuchów, plazmy itd.). Można w nim robić nawet grafikę trójwymiarową. Zastosowań jest bardzo wiele. Aby skorzystać z jego możliwośći musimy napisać

Podstawowe procedury graficzne

UWAGA!
Nazwy procedur zostały wymyślone przeze mnie i jeśli chcesz to możesz je zmienić na inne. (np. identyczne jak w module Graph).

Czym będą się zajmowały? Dosłowie wszystkim co do tej pory mieliśmy pod ręką (w nawiasie nazwa procedury lub funkcji z grafki BGI) - Ustawieniem trybu graficznego (InitGraph), zamykaniem go (CloseGraph), stawianiem pikseli (PutPixel) i pobieraniem ich z ekranu (GetPixel). Dodatkowo napiszemy proedury rysujące linię poziomą i pionową, których nie było w BGI, ale są bardzo przydatne i procedury rysujące prostokąt (Rectangle) i wypelniny prostokat (Bar) oraz wypełniony prostokąt z ramką (tego nie ma w grafice BGI). Całość umieścimy w module, który będzie można łatwo wykorzystać (tak samo jak moduł Graph).

Aby uruchomić tryb 13h należy do rejsetru AH funkcję 00h, a do rejestru AL załadować numer trybu pracy karty graficznej VGA i wywołać przerwanie 10h. Rejesry AH i AL znajdują się w rejestrze AX, więc wystarczy tam załadować numer trybu pracy karty graficznej. Procedurą, która będzie to realizowała będzie Init13h (odpowiednik InitGraph):

procedure Init13h; assembler; asm mov ax, 0013h int 10h end;

Procedura zamykająca tryb 13h (Close13h) ma za zadanie powrócenie do trybu tekstowego, czyli załadowaniem do rejestru AX numeru trybu pracy karty graficznej 03h (80x25 znaków).

procedure Close13h; assembler; asm mov ax, 0003h int 10h end;

Kiedy mamy już uruchomiony tryb 13h, możemy coś narysować. Aby postawić pojedynczy piksel należy do bufora wideo składającego się z 64000 bajtów (określających kolejno ułorzone piksele) zapisać liczbę określającą jego kolor. Np. zapisanie do 1 bajtu buforu wideo liczby 15 powoduje wyświetlenie na ekranie białego piksela o współrzędnych x:0, y:0. Bufor wideo znajduje się w komórkach pamięci od A000:0000 do A000:FFFF. Żeby zapisać więc piksel opisany powyżej (pierwszy piksel na ekranie) należy wpisać następującą linijkę kodu:

Mem[$A000:$0000] := 15;

No dobrze, ale jak napisać procedurę rysującą piksel o dowolnych współrzędnych? Nic prostszego - wystarczy w offsecie (drugiej części adresu) wpisać następujące działanie: y*320+x. Załóżmy, że mamy piksel wsp. x:0, y:0. 0*320+0 = 0. Inny przykład x:20, y:30. 20*320+30 = 6430. Jeszcze inny x:319, y:199. 199*320+319 = 63999.

Należy pamiętać o tym, że wszystkie tablice, zmienne i inne typy danych są indeksowane od 0, a nie od 1.

Moglibyśmy napisać już procedurę wyświetlacjącą pojedynczy piksel, ale miałaby ona jedną wadę - mnożenie. Jest to jedna z najwolniejszych operacji procesora i należy go unikać kiedy tylko jest to możliwe.

Można to zrobić używając operacji przesuwania bitów. Polega ona na przesunięciu bitów w prawo lub w lewo. Załóżmy, że mamy liczbę 4 (dwójkowo 0100). Po przesunięciu bitów w lewo otrzymamy liczbę 8 (dwójkowo 1000), a po przesunięciu bitów w prawo otrzymamy liczbę 2 (0010 dwójkowo). Jak łatwo można zauważyć przesuwanie bitów w lewo powoduje podwojenie liczby, a przesuwanie w prawo podzielenie przez 2. Problemem jest to, że liczba 320 nie jest wielokrotnością dwójki. Jak temu zaradzić? Można ją podzielić na dwie liczby 256 i 64, które są wielokrotnościami liczby 2. Wyglądałoby to tak: y*320 = (y*256) + (y*64) = (y*2^8) + (y*2^6) = (y shl 8) + (y shl 6).

UWAGA!
Znaczek "^" oznacza "do potęgi". Shl oznacza przesuwanie bitów w lewo (Shift left), a Shr przesuwanie bitów w prawo (Shift right).

Możemy już napisać procedurę stawiającą piksel na ekranie - w Pascalu...

procedure PutPixel (x, y : Word; Color : Byte); begin Mem[$A000:(y shl 8) + (y shl 6) + x] := Color; end;

...i w assemblerze:

procedure PutPixel (x, y : Word; Color : Byte); assembler; asm mov ax, y mov di, ax { skopiuj y } shl ax, 8 shl di, 6 add di, ax add di, x mov ax, 0a000h mov es, ax mov al, Color mov byte ptr es:[di], al end;

Funkcja pobierająca piksel z ekranu wygląda bardzo podobnie:

function GetPixel (x, y : Word) : Byte; assembler; asm mov ax, y mov di, ax shl ax, 8 shl di, 6 add di, ax add di, x mov ax, 0a000h mov es, ax mov al, es:[di] end;

Procedury rysujące linię poziomą (LineH) i pionową (LinieV) są bardzo proste (w Pascalu). Linia pozioma - przechodzimy w pętli przez piksele linii od x1 do x2 i rysujemy piksele o współrzednych licznik_petli, y. W linii pionowej jest bardzo podobnie tylko zamiast x1 i x2 jest y1 i y2, a zamiast y jest x. Procedury rysujące linię poziomą (LinieH) i pionową (LinieV):

procedure LineH (x1, x2, y : Word; Color : Byte); var I : Word; { licznik petli } begin for I := x1 to x2 do PutPixel (I, y, Color); end; procedure LineV (y1, y2, x : Word; Color : Byte); var I : Word; { licznik petli } begin for I := y1 to y2 do PutPixel (x, I, Color); end;

W Assemblerze jest nieco trudniej. W linii poziomej można użyć kopiowania bloków pamięci, ponieważ piksele w linii poziomej są ułożone tak samo jak w buforze wideo. W linii pionowej trzeba użyć pętli. Kody procedur:

procedure LineH (x1, x2, y : Word; Color : Byte); assembler; asm mov cx, x2 sub cx, x1 add cx, 1 mov ax, y mov di, ax shl ax, 8 shl di, 6 add di, ax add di, x1 mov ax, 0a000h mov es, ax mov al, Color cld rep stosb end; procedure LineV (y1, y2, x : Word; Color : Byte); assembler; asm mov cx, y2 sub cx, y1 add cx, 1 mov ax, y1 mov di, ax shl ax, 8 shl di, 6 add di, ax add di, x mov ax, 0a000h mov es, ax mov al, Color @rysuj_linie: mov es:[di], al add di, 320 loop @rysuj_linie end;

Pozostałe procedury są bardzo proste, więc nie będziemy ich pisać w Assemblerze.

Prostokąt:

procedure Rectangle (x1, y1, x2, y2 : Word; Color : Byte); begin LineH (x1, x2, y1, Color); LineH (x1, x2, y2, Color); LineV (y1, y2, x1, Color); LineV (y1, y2, x2, Color); end;

Wypełniony prostokąt:

procedure Bar (x1, y1, x2, y2 : Word; Color : Byte); var I : Word; begin for I := y1 to y2 do LineH (x1, x2, I, Color); end;

Wypełniony prostkąt z ramką (Color - kolor ramki, FillColor - kolor wypełnienia):

procedure FillRectangle (x1, y1, x2, y2 : Word; Color : Byte; FillColor : Byte); begin Rectangle (x1, y1, x2, y2, Color); Bar (Succ(x1), Succ(y1), Pred(x2), Pred(y2), FillColor); end;

UWAGA!
Funkcje Succ i Pred służą odpowiednio do: powiększania i pomniejszania liczby całkowitej o 1. Zamiast Succ(Liczba) można napisać Liczba+1, a zamiast Pred(Liczba) można napisać Liczba-1.

Zakończenie

Na razie to by było tyle. Napisałem również 2 moduły, w których znajdują się wszystkie omawiane tutaj procedury i funkcje - G13hP (wolniejszy, napisany w Pascalu) i G13hA (szybszy, napisany w Assemblerze). Polecam również najnowszą wersję mojego modułu do obsługi grafiki w trybie 13h - Space Graph Jeśli masz jakieś uwagi, komentarze, opinie, sugestie, pytania itd. to napisz do mnie.

Pobierz załącznik

Literatura:
Tworzenie gier 2D i 3D w języku Turbo Pascal - Piotr Besta, wyd. Helion.

Tekst dodał:
lpg
30.03.2006 22:33

Ostatnia edycja:
lpg
30.03.2006 22:33

Kategorie:

Aby edytować tekst, musisz się zalogować.

# Edytuj Porównaj Czas Autor Rozmiar
#1 edytuj 30.03.2006 22:33 lpg 9.69 KB
Zwykły
Do sprawdzenia
Do akceptacji
  • ~Belm 10 sierpnia 2007 14:32
    13h? Kurde, jeszcze FLI dla Commodorka przewałkujcie. Przecież od wieków nikt tego nie używa...
  • ~mucha 27 stycznia 2008 03:28
    Po co piszesz assembler za każdą funkcją, to nic nie daje ( używane dawno temu przez Delphi 1 )
  • ~programmer 11 lutego 2008 16:19
    Chciałem mieć tego "booka". I zamiast Succ i Pred lepiej jest Inc i Dec ...

    Turbo Pascal .... co nie ??
  • ~Lolek 17 lutego 2008 17:23
    Większość programów biurowych opiera się jeszcze na dosie, poza tym spróbujcie napisać własny system w "asm" a nie bazować na komercji...
  • Michał Korman (@dynax) 11 czerwca 2008 14:49
    "Jak widiać tryb 13h wygrywa dość wyraźnie."

    Ocaniasz strasznie subiektywnie. Po pierwsze - w trybie BGI można ustawić nawet 32 kolory. Po drugie - można usunąć migotanie poprzez podwójne buforowanie. Po trzecie - BGI wcale nie jest wolny. Gdyby był powolny to nikt by w nim nie pisał.
  • ~szuszu 06 grudnia 2008 17:36
    Witam. Co do zamiennego stosowania cucc i inc, oraz pred i dec, to pozwolę się nie zgodzić. Procedura inc(x) zwiększy wartość przechowywaną przez x o 1, a funkcja succ(x) zwróci powiększoną wartość x o 1, ale sama zmienna x pozostanie bez zmian. Pozdrawiam.
  • ~lux 04 marca 2009 12:04
    Jak pisałem ten artykuł to miałem niewiele więce lat niż ten tryb ma numerek, ale bez h na końcu :P Dynax: ile gier wykorzystywało BGI a ile 13h? Może masz rację, ale wtedy jeśli dobrze pamiętam, nie było łatwego zarządzania pamięcią (640 KB i można było alokować bloki po 64 KB). W Turbo Pascalu były jakieś demka tego i wszystki migotały. Ale można było za to rysować ładne wykresy (wysoka rozdzielczość) :-) A tak w ogóle to ciekawostka - można pisać w BGI pod Windowsem korzystając z tego: http://codecutter.org/tools/winbgim/
  • ~maniek 09 kwietnia 2009 19:35
    "Po drugie - można usunąć migotanie poprzez podwójne buforowanie."

    Jestem bardzo ciekaw jak??
  • Napisz komentarz:
    Aby dodać swój komentarz, musisz się zalogować.
Licencja Creative Commons

Warsztat używa plików cookies. | Copyright © 2006-2017 Warsztat · Kontakt · Regulamin i polityka prywatności
build #ff080b4740 (Tue Mar 25 11:39:28 CET 2014)