C dla każdego (cz. 6.)
Malowanie po ekranie
W dzisiejszej części zajmiemy się rysowaniem.
Wysokopoziomowe funkcje graficzne jako jednego z
argumentów wymagają wskaźnika na RastPort (patrz
"graphics/rastport.h"). Jest to struktura
zawierająca informacje niezbędne do prac
graficznych, jednak nas interesuje tylko część
danych w niej zawartych. Każde otwarte okno ma
własny RastPort. Jego adres można znaleˇć w polu
"RPort" struktury "Window".
RastPort można traktować jako "czarną skrzynkę",
potrzebną do rysowania. Jest ona dość wygodna.
Używając różnych funkcji graficznych, podajemy
współrzędne punktów względem lewego górnego rogu
RastPortu. Podanie współrzędnych "wystających"
poza RastPort nie powoduje żadnych problemów --
funkcje graficzne narysują tylko tyle, ile się
zmieści. W RastPorcie zapisane jest również
położenie kursora graficznego, tryb rysowania,
aktualne kolory, wzór linii itp.
Położenie kursora zapisane jest w polach "cp_x" i
"cp_y", po inicjalizacji RastPortu (w naszym
wypadku otwarciu okna) kursor znajduje się w
punkcie (0, 0), co zwykle wypada na górnej listwie
okna. Po dodaniu w tagu "WA_Flags" flagi
"WFLG_GIMMEZEROZERO" niedogodność ta znika, punkt
(0, 0) wypada w lewym górnym rogu wnętrza okna,
ale obsługa okien jest wolniejsza, a także większe
jest zapotrzebowanie na pamięć, więc nie radzimy
używać tego atrybutu. Przy opisywaniu gadżetów
pokażemy, jak można się obejść bez pomocy GZZ.
Kolor tła jest odnotowany w polu "BgPen" (BPen),
kolor "atramentu" w "FgPen" (APen). Nie wolno
bezpośrednio (instrukcją przypisania) zmieniać
kolorów, zapisanych w strukturze. Do tego celu
przeznaczone są funkcje biblioteki
"graphics.library":
void SetAPen( struct RastPort *rp, unsigned long
pen );
void SetBPen( struct RastPort *rp, unsigned long
pen );
Pierwsza z nich zmienia kolor atramentu, druga
kolor tła. Obie funkcje wymagają jako argumentów
wskaźnika na RastPort oraz numeru koloru.
Dane zawarte w polach "FgPen" i "BgPen" można było
odczytywać. Zapisana tam wartość to numer koloru.
Jednak od systemu 3.0 pojawiły się specjalne
funkcje, zwracające numery kolorów jako wartość
typu ULONG. Jest to przygotowane nieco na wyrost,
ponieważ kości AGA mają ośmiobitowy blitter, czyli
256 rejestrów kolorów, w związku z czym do
zapisania koloru wystarczy jeden bajt. Polecam
jednak stosowanie tych funkcji, ponieważ przy
jeszcze nowszych kościach może to być konieczne
(przy założeniu, że będą jakieś "nowsze kości" --
miejmy nadzieję, że Escom nas nie zawiedzie).
ULONG GetAPen( struct RastPort *rp );
ULONG GetBPen( struct RastPort *rp );
Ponieważ nie wszystkie Amigi mają powyższe
funkcje, należy sprawdzać wersję biblioteki (było
to przerabiane w pierwszej części), możesz to
również zobaczyć w listingu 9.: funkcje
dajKolorA() i dajKolorB(). Jeżeli masz inkludy z
systemu starszego niż 3.0, wystąpią problemy ze
skompilowaniem tego listingu, ponieważ kompilator
stwierdzi, że nie zadeklarowano niektórych
funkcji. Sugeruję więc posiadaczom starszych
inkludów zmodyfikować nieco program, usuwając
wywołania nieznanych kompilatorowi funkcji, a
następnie poszukać nowszych plików nagłówkowych.
Listing nr 9
Tak samo ma się sprawa z polem "DrawMode", w
którym odnotowany jest sposób (tryb) rysowania po
oknie. Do jego zmiany służy funkcja:
void SetDrMd( struct RastPort *rp, unsigned long
drawMode );
Do jego odczytania zaś używamy:
ULONG GetDrMd( struct RastPort *rp );
Pojawiła się ona wraz z opisanymi wcześniej
funkcjami GetAPen() i GetBPen() -- w wypadku
starszych systemów należy po prostu odczytać pole
RastPortu "DrawMode".
Są zdefiniowane następujące tryby rysowania:
JAM1:
Tylko kolor atramentu jest umieszczany na
RastPorcie.
JAM2:
Zarówno kolory atramentu, jak i tła są
umieszczane na RastPorcie. Tryb ten można
odróżnić od JAM1 tylko w wypadku, gdy na
RastPorcie umieszczane są napisy lub rysunki (o
tym póˇniej).
COMPLEMENT:
Jest wykonywana różnica symetryczna (XOR)
obecnej zawartości RastPortu i tego, co ma być
narysowane.
INVERSVID:
Wykonywana jest inwersja kolorów.
Powyższe tryby można swobodnie mieszać ze sobą,
jednak niektóre kombinacje nie mają sensu.
Podejrzewam, że znaczenie poszczególnych trybów
nie jest jeszcze zrozumiałe, myślę jednak, że się
to nieco przejaśni po zapoznaniu się z działaniem
przykładu. Do testowania sugeruję użyć rysowania
napisów, ponieważ tylko w tym wypadku rysowany
jest kolor tła, co pozwala odróżnić tryb JAM1 od
JAM2.
Proponujemy teraz zajrzeć do przykładu:
Listing nr 9
Przykład ten to demonstracja użycia najprostszych
funkcji graficznych systemu operacyjnego. Przy
użyciu odpowiednich klawiszy (bądź klikając
jednokrotnie na gadżecie zamykania okna) można się
przełączać pomiędzy różnymi trybami pracy
programu, takimi jak: rysowanie elips, punktów,
zmiana kolorów itp. Rodzaj trybu, w jakim program
znajduje się w danym momencie, jest wyświetlany na
listwie tytułowej okna. Rysuje się za pomocą
myszy, w sposób często niezbyt elegancki (można
np. rysować po listwie tytułowej) i nieintuicyjny
(nie jest tak od razu oczywiste, co w danym trybie
robi przycisk lewy, a co prawy), ale ma to być
tylko przykład, a nie jakiś użyteczny program.
Gdyby chcieć zrobić to elegancko, to należałoby
skorzystać z gadżetów, a na razie nie umiemy z
nich korzystać. Szczegółowy opis listingu
zamieszczony zostanie w następnym odcinku kursu.
Oto najczęściej powtarzające się w listach do mnie
pytania:
1. Pytacie jak kompilować listingi. W kompilatorze
SAS/C 6.x robi się to z Shella pisząc "SC
nazwa_listingu.c LINK". Nie polecamy osobnego
wywoływania linkera (slink), gdyż jest to bardziej
skomplikowane.
2. W części 1, w listingu 3, w pętli "for"
znajduje się instrukcja "licznik--". Powinno być
oczywiście "licznik- -" (słownie: licznik minus
minus).
3. W części 3, w listingu 5, zmienna
"IntuitionBase" jest zmienną lokalną. Kompilator
SAS/C skompiluje ten przykład bez zarzutu, ale
chyba wszystkie inne kompilatory się "udławią" -
zmienna ta powinna być globalna.