Krótkie wprowadzenie
Używanie modułu graph ma wiele zalet, ale chyba więcej wad. Nadaje się dobrze do tworzenia programów, które nie wymagają szybkiej grafiki, np. zegar wskazówkowy, statyczne rysunki. Graph udostępniony przez Borlanda nie zezwala na uruchomienie grafiki powyżej 16 kolorów (trzeba ściągnąć pliki do SVGA). Jest wolny. Co zrobić żeby napisać szybką grę, lub odtwarzać animacje?
Wystarczy oprogramować część grafiki w assemblerze. Wcale nie jest do tego potrzebna wybitna znajomość tego języka. Zanim zaczniesz programować musisz poznać kilka prawd o grafice, które przyśpieszą Twoje projekty także w module graph.
1) Grafika podzielona jest na banki (bloki) pamięci (64KB) Oznacza to że nigdy tak na prawdę nie mamy dostępu do całego ekranu na raz. Żeby narysować obraz musimy po kolei wypełnić bank pamięci, potem zrzucić go do karty graficznej i na nowo -kolejny blok.
W module graph, komputer robi to za nas, ale warto pamiętać o pewnym szczególe. Przełączanie bloków jest b. czasochłonne. Gdybyś np. projektował gwiazdy i rysował w dowolnym miejscu ekranu (każdą w losowej pozycji) efekt będzie kilkadziesiąt razy wolniejszy niż gdybyś robił to po kolei -rysując od górnej lini do dolnej.
Informacje techniczne:Adres akualnie używanego banku pamięci: $A000:00
Tam są 64KB danych o tworzonej grafice. Po zmianie wartości w tej pamięci, zmieni się zawartość ekranu!
pozycja := Y * szerokosc_ekranu + x;
np. $MEM[$a000:pozycja]:= kolor;
Kopiowanie: najlepiej napisać własną funkcję kopiującą bufor pamięci do aresu $A000:0, najprościej skorzystać z Move - najlepiej napisać Move32 -4 krotnie szybsza.
2) Pamięć karty graficznej jest kilkadziesiąt razy wolniejsza od zwykłej W takim razie zamiast rysować bezpośrednio na karcie lepiej narysować coś w pamięci, a potem najszybszą możliwą techniką wrzucić na ekran. Przyda Ci się bufor pamięci, w którym będziesz przechowywał dane.
3) Operacje mnożenia i dzielenia są wolne Mnożenie wymaga kilku taktów procesora, dzielenie kilkudziesięciu. Przy grafice nie opłaca się więc używać procedur, które dla każdego piksela liczą pozycję. Lepiej kopiować bitmapy i rysować linie - szczególnie poziome! W przeciwnym wypadku nie licz że wyjdziesz ponad 100FPS.
Zamiast mnożenia stosuj SHL lub << w C, zamiast dzielenia gdy to tylko możliwe SHR i >>. Jest to przesunięcie bitowe, czyli mnożenie przez potęgę dwójki. Dla przykładu:
1 shl 1 = 2
1 shl 2 = 4
1 shl 3 = 8
320=256+64; 640=512 + 128
może powiesz że to oczywiste, ale
poz:= y*320+x jest znacznie wolniejsze niż:
poz:=(y shl 8)+(y shl 6)+x { (y*256+y*64 czyli y*320) }
po opragramowaniu tej procedury w assemblerze otrzymujemy szybki wynik. Warto korzystać, tymbardziej, że liczby
320, 640 -czyli rozdzielczość poziomą można łatwo wyliczyć w szybki sposób
4) Monitor ma powrót pionowy To znaczy, że po narysowaniu ekranu jest chwila pauzy w monitorze, po czym znowu przystępuje do rysowania kolejnej klatki. Jeśli rysujesz szybciej niż częstotliwość monitora i tak nie zyskasz lepszego wyglądu, nawet pogorszysz go. Obraz może być urywany bo kopiujesz bufor gdy monitor rysuje. Wyświetli więc chwilowo jedną klatkę u góry nową i u dołu starą. To jest brzydkie. Lepiej poczekać do momentu pauzy i wtedy zdążyć skopiować całą klatkę. Wtedy monitor narysuje obraz bez żadnego mignięcia.
Ogólny algorytm rysowania klatki animacji
Teraz lepiej będziesz mógł zrozumieć dlaczego grafikę projektuje właśnie w taki sposób. Poniżej kolejność
na początku programu- utworzenie bufora ekranu
w pętli rysującej- narysowanie grafiki w buforze
- oczekiwanie na powrót pionowy
- skopiowanie bufora ekranowego do karty graficznej
Zachęcam teraz do poduczenia się podstaw assemblera i analizowania kodu źródłowego modułu Graph10Eh