Moduł GRAPH, podstawy grafiki 2D cz.1

Transkrypt

Moduł GRAPH, podstawy grafiki 2D cz.1
Podstawy Programowania
Wykład czternasty:
Grafika (moduł Graph) – część pierwsza
1. Wstęp
Współczesne karty graficzne pozwalają na tworzenie przestrzennej, realistycznej
grafiki komputerowej. Niestety język Pascal, a konkretniej jego odmiana stworzona przez firmę Borland i udostępniona w postaci pakietu Turbo Pascal, nie
pozwala na obsługę zaawansowanych funkcji takich kart. Dostarczany wraz
z tym środowiskiem moduł graph pozwala obsługiwać karty graficzne w trybie
zgodności ze standardem VGA udostępniając kilka trybów graficznych
o względnie małej rozdzielczości (maksimum 1024x768 pikseli) i liczbie kolorów
(maksimum 256)1. Istnieje możliwość dostępu do trybów graficznych
o wyższych rozdzielczościach i większej liczbie kolorów, ale wymaga ona użycia
przerwań BIOS i nie będzie ona tu opisywana2. Pomimo skromnych możliwości
moduł graph może być przydatny do uzyskania kilku ciekawych efektów
graficznych i do zwiększenia „atrakcyjności wizualnej” napisanych w języku
Pascal programów.
2. Ogólny opis modułu graph
Pomimo, że możliwości graficzne, jakie oferuje moduł graph ze współczesnego
punktu widzenia są dosyć skromne, to jego rozmiary są dosyć znaczne.
Elementy w nim zgromadzone możemy podzielić na cztery kategorie: związane
z inicjalizacją trybu graficznego, związane z zarządzaniem trybem graficznym,
związane z wyświetlaniem obrazu i związane z wyświetlaniem tekstu. Najważniejsze z nich zostaną omówione w następnych rozdziałach.
3. Elementy modułu graph związane z inicjalizacją trybu graficznego
Inicjalizacja trybu graficznego (pierwsze włączenie) dokonywane jest za pomocą
procedury InitGraph. Przyjmuje ona trzy argumenty wywołania. Pierwsze dwa
są typu integer i muszą być zmiennymi, ostatni jest typu string i może być
zmienną lub ciągiem znaków. Pierwszy parametr wywołana określa sterownik,
jaki ma zostać użyty do uruchomienia trybu graficznego. W module graph
zostały zdefiniowane stałe pozwalające określić rodzaj sterownika. Oto niektóre
z nich: Detect (0) – procedura initgraph automatycznie3 rozpozna kartę graficzną jaka zainstalowana jest w systemie, dobierze dla niej odpowiedni sterownik
i wybierze najlepszy tryb wyświetlania, CGA (1) – sterownik dla karty CGA, lub
1 Podane wartości maksymalne odnoszą się do karty IBM851, rzadko obecnie spotykanej.
2 Tryby o wyższych rozdzielczościach należą do standardu VESA. Więcej o tych trybach
i sposobach ich używania można przeczytać w książce autorstwa P.Metzgera i A.Jełowickiego pt
„Anatomia PC” lub „Tworzenie gier 2D i 3D w języku Turbo Pascal” autorstwa Piotra Besty.
3 lub jak niektórzy wolą „automagicznie” :-)
2
zgodnej z tym standardem, EGA (3) i EGA64 (4) – sterowniki kart EGA, lub
zgodnych z tym standardem, EGAMono - sterownik monochromatycznych kart
EGA, lub zgodnych z tym standardem, HercMono (7) – sterownik kart Hercules
lub zgodnych z tym standardem, VGA (9) – sterownik kart VGA lub zgodnych
z tym standardem. Ponieważ wszystkie współcześnie produkowane karty są
zgodne ze standardem VGA najlepiej jest używać sterownika tej karty lub
pozwolić procedurze initgraph automatycznie wykryć rodzaj sterownika. Drugi
parametr określa tryb graficzny jaki ma zostać użyty. Każdy z wymienionych
wcześniej rodzajów kart graficznych oferuje kilka różnych trybów graficznych.
Ze względów pragmatycznych zapoznamy się tylko z trybami oferowanymi przez
karty VGA i zgodne z nimi. Karty te oferują trzy tryby. Zostały zdefiniowane odpowiednie stałe w module graph, które ułatwiają wybór tych trybów: VGALo (0)
– tryb wyświetlania o rozdzielczości 640x200 pikseli, 16 kolorach i 4 stronach,
VGAMed (1) – tryb o rozdzielczości 640x350 pikseli, 16 kolorach i 2 stronach,
VGAHi (2) – tryb o rozdzielczości 640x480 pikseli, 16 kolorach i jednej stronie.
Piksel jest najmniejszym pojedynczym punktem, który można wyświetlić na
ekranie w trybie graficznym. Pierwsza liczba w oznaczeniu rozdzielczości
oznacza liczbę pikseli w poziomie, a druga w pionie. Strony są użyteczne
w tworzeniu animacji. Jedna strona może być w danej chwili wyświetlana,
podczas gdy na pozostałych tworzone są kolejne klatki animacji. Trzecim
parametrem wywołania procedury initgraph jest ścieżka dostępu do katalogu,
w którym znajduje się plik ze sterownikiem do karty graficznej (zazwyczaj pliki
sterowników kart graficznych są umieszczone w katalogu BGI, który jest
podkatalogiem katalogu, w którym znajduje się kompilator). Jeśli plik
sterownika4 znajduje się w katalogu bieżącym, to wystarczy jako ścieżkę dostępu podać pusty łańcuch znaków (''). Jeśli zmiennej, która będzie pierwszym
argumentem wywołania przypiszemy wartość stałej Detect, to procedura
initgraph wywoła inną procedurę o nazwie DetectGraph, celem wykrycia
optymalnego sterownika i trybu graficznego. Procedura ta przyjmuje jako parametry wywołania dwie zmienne typu integer. W pierwszej zapisuje numer
sterownika, w drugiej numer trybu graficznego. Tę procedurę możemy również
wywołać samodzielnie, przed wywołaniem initgraph, choć nie jest to często
stosowane rozwiązanie. Jeśli po włączeniu trybu graficznego zachodzi konieczność chwilowego skorzystania z trybu tekstowego, to możemy dokonać
przełączenia trybów za pomocą procedury RestoreCrtMode, która nie
przyjmuje żadnych parametrów wywołania. Przywracany jest tryb tekstowy,
który był używany przed włączeniem trybu graficznego. Aby powrócić do trybu
graficznego wywołujemy procedurę SetGraphMode. Przyjmuje ona tylko jeden
parametr wywołania i może nim być zmienna, wyrażenie lub wartość
4 W przypadku kart VGA i kompatybilnych plik sterownika nazywa się EGAVGA.BGI.
3
określająca numer trybu graficznego. Najczęściej stosuje się jedną z opisanych
wyżej stałych. Jeśli chcemy skończyć pracę w trybie graficznym, to wywołujemy
procedurę CloseGraph. Nie wymaga ona żadnych parametrów wywołania.
Typowa procedura inicjalizująca tryb graficzny może mieć następującą postać:
procedure inicjalizuj;
var
sterownik,tryb,kod:integer;
begin
sterownik:=detect;
initgraph(sterownik,tryb,'c:\tp\bgi');
kod:=GraphResult;
if kod <> grOK then
begin
grapherrormsg(kod);
halt(1);
end;
end;
Działanie funkcji graphresult i grapherrormsg zostanie opisane w następnym
rozdziale. Jeśli użyjemy tej procedury, to musimy zapewnić, że sterownik karty
graficznej znajdzie się w określonym przez trzeci parametr wywołania procedury katalogu. Jeżeli chcemy uniknąć tego dosyć niewygodnego rozwiązania
możemy plik sterownika dołączyć do pliku wykonywalnego naszego programu.
Procedura inicjalizuj w tym wypadku powinna mieć następującą postać:
procedure EGAVGAdriver; external;
{$L EGAVGA.OBJ }
procedure inicjalizuj;
var
grdriver,grmode:integer;
begin
grdriver:=detect;
registerbgidriver(@EGAVGAdriver);
initgraph(grdriver,grmode,'');
if graphresult<>grOK then halt(1);
end;
4
Przed definicją tej procedury powinna być zadeklarowana procedura sterownika karty. Jest to procedura zewnętrzna5, zdefiniowana w innym pliku. O tym
jak się nazywa ten plik informujemy kompilator za pomocą dyrektywy $L, tak
jak to jest pokazane w kodzie źródłowym. W procedurze inicjalizuj przed wywołaniem initgraph wywołujemy procedurę RegisterBGIDriver. Jako parametr
wywołania przyjmuje ona wskaźnik6 na procedurę sterownika. Plik
EGAVGA.OBJ uzyskujemy z pliku EGAVGA.BGI konwertując go za pomocą
programu binobj dostarczanego wraz ze środowiskiem Turbo Pascala.
W przypadku opisywanego pliku sterownika program ten wywołujemy z wiersza
poleceń następująco:
binobj egavga.bgi egavga.obj EGAVGAdriver
4. Elementy modułu graph związane z organizacją pracy w trybie graficznym
Użyta w procedurze inicjalizującej funkcja GraphResult zwraca kod poprawności wykonania operacji graficznej, przeprowadzonej bezpośrednio przed jej
wywołaniem. Jeśli operacja ta zakończyła się pomyślnie, to zwracana jest
wartość 0 (zero), jeśli nie wartość różna od zera. W module graph zostały
zdefiniowane stałe odpowiadające wartościom sygnalizującym poszczególne
błędy. Wartości zero odpowiada stała grOK. Nazwy pozostałych stałych nie
będą tu przytaczane. Jeśli chcemy uzyskań komunikat (w języku angielskim)
opisujący rodzaj błędu, to możemy wywołać procedurę GraphErrorMsg.
Przyjmuje ona jeden parametr wywołania będący wartością, wyrażeniem lub
zmienną oznaczającą kod błędu. Funkcja graphresult „współpracuje” między
innymi z następującymi podprogramami modułu graph: bar, bar3d,
clearviewport, closegraph, detectgraph, drawpoly, fillpoly, getgraphmode,
imagesize, initgraph, pieslice, registerbgidriver, setallpalette, setfillpattern,
setfillstyle,
setgraphbufsize,
setgraphmode,
setlinestyle,
settextjustify,
settextstyle. Aby poznać nazwę trybu graficznego w którym pracujemy, lub
który nas interesuje, możemy posłużyć się funkcją GetModeName. Jako
parametr wywołania pobiera ona numer trybu, którego nazwę chcemy uzyskać,
a zwraca wartość typu string, zawierającą nazwę trybu. Tworząc obraz w trybie
graficznym posługujemy się współrzędnymi. Układ współrzędnych we
wszystkich trybach graficznych jest zorganizowany tak, jak pokazano to na
rysunku:
5 O tym informuje słowo kluczowe external.
6 Inaczej adres procedury. Wskaźniki będą tematyką następnych wykładów.
5
0
maxX
0
maxY
Aby poznać wartość maksymalnej rzędnej i odciętej w bieżącym trybie graficznym użyjemy funkcji GetMaxX i GetMaxY. Wartości zwracane przez te funkcje
są typu integer. Procedura GetModeRange zwraca numery trybów o najmniejszej i największej rozdzielczości dla danego sterownika. Przyjmuje ona trzy
parametry wywołania. Pierwszym jest zmienna, wyrażenie lub wartość typu
integer będąca numerem sterownika. Jeśli chcemy poznać wymienione tryby
dla bieżącego sterownika, to pierwszym parametrem wywołania getmoderange
może być stała CurrentDriver (-128). Dwa następne parametry są zmiennymi
typu integer. Pierwsza będzie zawierała numer trybu o najmniejszej rozdzielczości, druga o największej. Jeśli chcemy operacje graficzne związane z rysowaniem lub wyświetlaniem tekstu ograniczyć tylko do pewnego wycinka powierzchni ekranu, to możemy zdefiniować okno, które w języku angielskim nazwane zostało viewport. Do tworzenia takiego okna służy procedura
SetViewPort. Przyjmuje ona pięć argumentów wywołania. Pierwsze cztery są
typu integer, ostatni typu boolean. Pierwsza para argumentów wywołania to
współrzędne lewego, górnego rogu okna, druga to współrzędne prawego dolnego
rogu okna. Ostatni parametr określa, czy umieszczane w oknie elementy mogą
„wystawać” poza okno, czy nie. Jeśli ma on wartość true, to rysowanie
ograniczone jest tylko do obszaru okna. Zamiast bezpośrednio stosować wartości true i false możemy użyć stałych ClipOn (true) i ClipOff (false). Do „wyczyszczenia” bieżącego okna używamy procedury ClearViewPort, która nie
przyjmuje żadnych parametrów wywołania. Aby poznać parametry bieżącego
okna możemy posłużyć się procedurą GetViewSettings. Przyjmuje ona tylko
jeden parametr wywołania będący zmienną typu ViewPortType.
ViewPortType = record
x1,y1,x2,y2:integer;
Clip: boolean;
end;
6
Powyżej podana jest definicja tego typu w module graph. Pola x1, y1, x2, y2 są
przeznaczone do przechowywania wartości współrzędnych odpowiednich rogów
okna, natomiast pole Clip informuje, o tym, czy wyświetlanie jest ograniczone
do obszaru okna, czy też nie. Do „czyszczenia” zawartości całego ekranu jest
używana procedura ClearDevice, która nie przyjmuje żadnych parametrów
wywołania. Kursor w trybie graficznym jest niewidoczny. Aby poznać jego
położenie możemy użyć funkcji GetX i GetY. Obie te funkcje zwracają wartości
typu integer i nie pobjerają żadnych parametrów wywołania. Współrzędne
kursora są liczone względem bieżącego okna. Aby umieścić kursor w wybranym
miejscu na ekranie wywołujemy procedurę MoveTo. Przyjmuje ona dwa
argumenty wywołania, które mogą być zmienną, wyrażeniem lub wartością
typu integer i które stanowią współrzędne nowego położenia kursora. Dzięki
procedurze MoveRel mamy możliwość przemieszczenia kursora o pewien
ustalony przez nas wektor, względem bieżącego jego położenia7. Procedura ta
również przyjmuje dwa parametry typu integer, które są odpowiednio składową
poziomą i pionową wektora. Jeśli korzystamy z mechanizmu stron do tworzenia
animacji, to procedura SetActivePage określa nam stronę, na której będzie
rysowana bieżąca klatka, a SetVisualPage, stronę, która będzie wyświetlana.
Obie procedury przyjmują jeden parametr wywołania, który jest typu word
i który jest numerem strony. Jeśli używamy sterowników do kart EGA, EGA64
lub VGA, to równocześnie na ekranie możemy wyświetlić 16 kolorów. W module
graph zdefiniowano stałe o odpowiednich nazwach dla każdego z nich (są
dokładnie takie same, jak w module crt). Istnieje ponadto możliwość stworzenia
swojej palety barw. Oferuje ją procedura SetAllPalette. Przyjmuje ona za
parametr wywołania zmienną typu PaletteType. Ten typ w module graph
został zdefiniowany następująco:
PaletteType = record
Size : Byte;
Colors : array[0..MaxColors] of ShortInt;
end;
gdzie stała MaxColors ma wartość 15. Pole Size określa rozmiar palety
kolorów, czyli ile elementów tablicy Colors będzie miało znaczące wartości.
Wartość elementu określa numer koloru. Oznacza to, że jeśli np. w elemencie
tej tablicy o indeksie 0 (czarny) umieszczę wartość 4 (zielony), to elementy,
które dotychczas rysowałbym na czarno będę rysował na zielono. Aby zmienić
tylko jeden kolor w palecie możemy użyć zamiast SetAllPalette procedury
7 Np. cztery piksele w prawo i dwa w dół.
7
SetPalette. Przyjmuje ona dwa parametry wywołania jeden typu word, drugi
typu shortint i są to: numer koloru który ma być zmieniony i numer koloru na
jaki ten kolor chcemy zmienić. Na bardziej elastyczną manipulację kolorami
palety pozwala nam procedura SetRGBPalette. Przyjmuje ona cztery
argumenty wywołania, wszystkie typu integer. Pierwszym jest numer koloru
w palecie, który ma być zmieniony, a następne trzy określają, odpowiednio,
składową czerwoną, zieloną i niebieską tego koloru. Należy zauważyć, że tylko
wartości młodszych bajtów, trzech ostatnich parametrów są używane przez tę
procedurę. Funkcja GetMaxColor zwraca wartość typu word określającą
maksymalny numer koloru dla bieżącego trybu graficznego. Do określenia
koloru, w jakim będą wyświetlane elementy obrazu służy procedura SetColor,
natomiast do określenia koloru tła na jakim te elementy będą rysowane służy
procedura SetBkColor. Obie one przyjmują jeden parametr wywołania, który
jest typu word. Funkcje GetColor i GetBkColor zwracają wartości typu word
będące numerami bieżących kolorów odpowiednio: rysowanych elementów i tła.
Procedura SetWriteMode określa sposób rysowania obrazu, a właściwie
sposób „nakładania” go na istniejące tło. Przyjmuje ona tylko jeden parametr
wywołania typu integer. Najczęściej parametrem tym jest jedna z następujących
stałych: NormalPut lub CopyPut (0) oznaczają, że element będzie po prostu
zastępował fragment tła na którym będzie rysowany, XORPut (1) oznacza, że
będzie wykonywana operacja xor dla każdego piksela rysowanego elementu
i odpowiadającego mu piksela tła, na którym jest rysowany, OrPut (2) –
podobnie jak poprzednio, ale wykonywana jest operacja or, AndPut (3) –
wykonywana jest operacja and, NotPut – każda wartość piksela (kolor) jest
negowana przed narysowaniem elementu. Do uzyskania numeru koloru piksela
o wybranych współrzędnych możemy użyć funkcji GetPixel. Przyjmuje ona dwa
parametry wywołania, typu integer, które określają rzędną i odciętą piksela,
natomiast zwraca wartość typu word, która jest numerem koloru piksela. Do
pobrania bieżącej palety kolorów służy procedura GetPalette, która przyjmuje
jako parametr wywołania jedną zmienną typu PaletteType. Rozmiar palety
(liczbę
dostępnych
kolorów)
możemy
poznać
wywołując
funkcję
bezparametrową o nazwie GetPaletteSize. Zwraca on wartość typu integer.
Procedura SetLineStyle pozwala określić styl rysowanej linii. Procedura ta
przyjmuje trzy argumenty wywołania, wszystkie typu word. Pierwszy z nich
określa rodzaj stylu i może być następującą stałą: SolidLn (0) – linia ciągła,
DottedLn (1) – linia „kropkowana”, CenterLn (2) – linia symetrii (używana
w rysunkach technicznych), DashedLn (3) – linia „kreskowana”, UserBitLn (4)
– stała pozwalająca określić własny rodzaj linii. Jeśli jest ona podana jako
pierwszy parametr wywołania SetLineStyle, to ma znaczenie wartość drugiego
parametru wywołania tej procedury. Jest to tzw. wzorzec bitowy linii (0 – piksel
8
wygaszony, 1 – piksel zapalony). Trzeci parametr określa grubość linii
i najczęściej jest jedną z dwóch stałych: NormWidth (1) – normalna szerokość
linii, ThickWidth (3) – linia pogrubiona. Niektóre z figur lub brył w trybie
graficzny są rysowane wypełnione, inne można wypełnić. Rodzaj wypełnienia
można określić za pomocą procedury SetFillStyle, przyjmującej dwa
parametry wywołania, oba typu word. Pierwszy z nich jest numerem wzorca,
drugi numerem koloru wypełnienia. Istnieje możliwość zdefiniowania własnego
wzorca wypełnienia, za pomocą procedury SetFillPattern. Przyjmuje ona dwa
argumenty wywołania. Pierwszy jest typu FillPatternType, drugi jest typu word
i określa kolor wzorca. Typ FillPatternType jest zdefiniowany w module graph
następująco:
FillPatternType = array [1..8] of Byte;
Wartość każdego elementu tej tablicy jest traktowana jako wzorzec bitowy
zapisany w wierszu macierzy o rozmiarach 8x8. Jeśli rysowane na ekranie koło
lub okrąg wydają się nam eliptyczne, możemy tę wadę skorygować używając
funkcji SetAspectRatio, która ustala stosunek szerokości do wysokości
ekranu. Przyjmuje ona dwa argumenty wywołania typu word określające nową
szerokość i wysokość ekranu i zwraca również wartość typu word. Niestety
dokumentacja elektroniczna nie podaje znaczenia tej wartości. Najczęściej jest
ona w programach ignorowana. Do poznania stosunku szerokości i wysokości
ekranu służy procedura GetAspectRatio, która pobiera jako parametry
wywołania dwie zmienne typu word. Do tych zmiennych zostanie zapisana po
wywołaniu procedury odpowiednio szerokość i wysokość ekranu.
5. Elementy modułu graph służące do tworzenia obrazu
Moduł graph dostarcza wielu podprogramów służących do tworzenia prostych
obiektów graficznych (zwanych w grafice komputerowej prymitywami) oraz do
tworzenia bardziej złożonych elementów obrazu. Najprostszym elementem
obrazu komputerowego w trybie graficznym jest piksel. Możemy „narysować”
pojedynczy piksel, określając jego kolor za pomocą procedury PutPixel.
Przyjmuje ona trzy parametry wywołania. Pierwsza para tych parametrów jest
typu integer i określa współrzędne piksela (odpowiednio rzędną i odciętą),
natomiast trzeci parametr jest typu word i określa kolor jaki piksel ma przyjąć.
Odcinek jest obiektem graficznym złożonym z punktów, czyli pikseli. Taki
odcinek możemy narysować za pomocą jednej z trzech procedury. Procedura
Line przyjmuje cztery parametry typu integer, które są współrzędnymi punku
początkowego i końcowego odcinka. Procedura LineTo rysuje odcinek od
9
punktu, w którym bieżąco znajduje się kursor, do punktu o podanych
współrzędnych. Współrzędne te są przekazywane za pomocą dwóch
parametrów wywołania typu integer. Na podobnej zasadzie działa procedura
LineRel, ale jako parametry przyjmuje długość poziomą i pionową wektora8,
który posłuży do wyliczenia punktu końcowego odcinka. Współrzędne tego
punku są liczone względem bieżącego położenia kursora. Do narysowania
prostokąta możemy się posłużyć procedurą rectangle, która przyjmuje cztery
parametry typu integer określające położenie lewego górnego i prawego dolnego
rogu rysowanego prostokąta. Jeśli chcemy, żeby ten prostokąt był wypełniony,
to zamiast procedury rectangle użyjemy procedury bar wywoływanej
w identyczny sposób (z dokładnością do nazwy). Do rysowania okręgów na
ekranie służy procedura Circle. Dwa pierwsze parametry wywołania tej
procedury określają współrzędne środka tego okręgu (są typu integer),
natomiast ostatni parametr jest typu word i określa długość promienia okręgu.
Fragment okręgu, czyli łuk możemy narysować za pomocą procedury Arc.
Przyjmuje ona pięć parametrów. Pierwsze dwa są typu integer i określają
współrzędne środka okręgu, którego wycinek stanowi rysowany łuk. Ostatni
parametr typu word określa promień tego okręgu, natomiast trzeci i czwarty
parametr są typu word i określają kąt początkowy, od którego jest rysowany
łuk i kąt końcowy. Miara obu kątów jest wyrażona w stopniach. Jeśli chcemy,
aby nasz łuk był wypełniony, to używamy procedury PieSlice9 wywoływanej
w ten sam sposób. Do rysowania elips lub ich fragmentów służy procedura
Ellipse. Przyjmuje ona sześć parametrów wywołania. Pierwsze dwa są typu
integer, cztery kolejne są typu word. Dwa pierwsze to współrzędne środka
elipsy, dwa kolejne to kąt początkowy i końcowy (jeśli ma być pełna elipsa, to
muszą to być odpowiednio: 0 i 360), a dwa kolejne, to długość półosi poziomej
i pionowej elipsy. Jeśli rysujemy fragment elipsy, który ma być wypełniony, to
używamy procedury Sector wywoływanej w identyczny sposób jak Ellipse. Całą
i wypełnioną elipsę możemy narysować za pomocą procedury FillEllipse.
Pobiera ona cztery argumenty wywołania. Dwa pierwsze są typu integer, dwa
pozostałe typu word. Pierwsza para określa położenie środka elipsy, trzeci
parametr określa długość półosi poziomej, czwarty długość półosi pionowej
elipsy. Do narysowania dowolnej figury może posłużyć nam procedura
DrawPoly. Przyjmuje ona dwa parametry wywołania. Pierwszy, typu word,
określa liczbę charakterystycznych punktów rysowanej figury, natomiast drugi
jest tablicą rekordów typu PointType, które określają współrzędne tych
punktów. Typ PointType jest zdefiniowany następująco:
8 Podobnie jak ma to miejsce w przypadku MoveRel.
9 Dosłowne tłumaczenia z angielskiego: „kawałek ciasta”. Ten element graficzny służy najczęściej
do tworzenia wykresów kołowych.
10
PointType = record
X,Y:integer;
end;
Jeśli chcemy, aby nasza figura była wypełniona, zamiast DrawPoly użyjemy
FillPoly. Sposób wywołania tej procedury nie zmienia się. Do narysowania
prostopadłościanu możemy użyć procedury Bar3d. Przyjmuje ona sześć
parametrów wejściowych. Pierwsze dwie pary są współrzędnymi lewego górnego
i prawego dolnego rogu „przedniej” ściany prostopadłościanu. Kolejny
parametr, typu word określa „głębokość” prostopadłościanu, natomiast ostatni,
typu
boolean
określa,
czy
ma
być
widoczny
wierzchołek
tego
prostopadłościanu, czy też nie. Zamiast wartości true i false możemy użyć, jako
tego parametru, stałych TopOn (true) i TopOff (false). Czasem zachodzi
konieczność skopiowania fragmentu obraz i umieszczenia go w innym miejscu.
Aby skopiować wybrany fragment obrazu należy użyć procedury GetImage.
Przyjmuje ona pięć parametrów wywołania. Pierwsze cztery są typu integer
(może to być zmienna, wartość lub wyrażenie). Pierwsza para jest
współrzędnymi lewego, górnego rogu kopiowanego obszaru, druga – prawego
dolnego rogu (obszar ten jest prostokątny). Ostatni parametr może być
zdereferencjonowanym wskaźnikiem10 typu pointer. Ten wskaźnik zawiera
adres dynamicznie przydzielonego obszaru pamięci, w którym będzie zapisany
skopiowany fragment obrazu. Pamięć tą możemy przydzielić za pomocą
procedury getmem. Dla tej procedury musimy określić ilość pamięci, którą ma
przydzielić. Możemy to uczynić za pomocą funkcji ImageSize. Zwraca ona
wartość typu word, będącą liczbą bajtów zajmowanych przez dany fragment
obrazu, a pobiera cztery parametry wywołania typu integer, określające
współrzędne lewego górnego i prawego dolnego rogu kopiowanego fragmentu
obrazu. Wklejenia obrazu dokonujemy za pomocą procedury PutImage.
Przyjmuje ona dwa parametry wywołania. Pierwsze dwa są typu integer
i określają współrzędne, w których ma znaleźć się lewy, górny róg wklejanego
obrazu, trzecim parametrem może być zdereferencjonowany wskaźnik
zawierający adres pamięci, w której jest umieszczony wklejany obraz11,
natomiast jako ostatni parametr określa sposób umieszczenia obrazu na tle
i powinna to być jedna ze stałych, które były opisywane wraz z procedurą
SetWriteMode12.
10 Temat wskaźników będzie poruszany na następnych wykładach.
11 Ta pamięć pełni rolę podobną do roli schowka w systemie MS Windows.
12 Proszę zauważyć, że zastosowanie XORPut pozwoli w prosty sposób uzyskać efekt operacji „cofnij” (ang. undo). Wystarczy ponownie nałożyć obraz, aby go usunąć.
11
6. Elementy modułu graph związane z tekstem
Niestety moduł graph nie dysponuje tak wygodną w użyciu procedurą
wypisywania tekstu, jaką jest write. Dostępne są dwie procedury wykonujące,
takie operacje, ale wypisujące tylko łańcuchy znaków. Jeśli chcemy wypisać
wartość innego typu, to musimy ją skonwertować na typ string. Pierwszą z tych
procedur jest outtext, drugą jest outextxy. Pierwsza przyjmuje tylko jeden
parametr wywołania typu string, druga trzy, z czego dwa pierwsze są
współrzędnymi (typ integer) punktu na ekranie, od którego będzie wypisywany
tekst, natomiast trzeci jest zmienną typu string lub łańcuchem znaków. Aby
określić sposób wypisywania tekstu na ekranie możemy posłużyć się procedurą
SetTextStyle. Pobiera ona trzy parametry wywołania typu word. Pierwszy
parametr określa krój pisma, drugi kierunek, natomiast trzeci rozmiar znaków.
Dostępnych jest kilka stałych zdefiniowanych w module graph, które mogą być
użyte jako wartość pierwszego parametru. Są to: DefaultFont (0) – domyślny
krój, TriplexFont (1) – krój „triplex” (znaki są wygładzone), SmallFont (2) –
małe znaki, SansSerifFont (3) – krój bezszeryfowy, GothicFont (4) – krój
gotycki. Jako wartość drugiego parametru możemy zastosować stałe: HorizDir
(0)
–
kierunek
poziomy,
(1)
VertDir
–
kierunek
pionowy.
Procedura
SetTextJustify pozwala określić wyrównanie tekstu w pionie i poziomie.
Przyjmuje ona dwa parametry typu word. Pierwszy z nich może być jedną
z trzech stałych, określających sposób wyrównania tekstu w poziomie:
LeftText (0) – wyrównanie do strony lewej, CenterText (1) – wyśrodkowanie
tekstu, RightText (2) – wyrównanie do strony prawej tekstu. Jako drugi
parametr wywołania, określający wyrównanie tekstu w pionie, może zostać
przekazana jedna z trzech następujących stałych: BottomText (0) –
wyrównanie w dół, CenterText (1) – wyśrodkowanie i TopText (2) –
wyrównanie w górę. Jeśli chcemy poznać wymiary tekstu w pikselach, to
możemy zastosować dwie funkcje: TextHight – która zwraca wartość typu
word, określającą wysokość tekstu i TextWidth, która również zwraca wartość
TextSettingsType = record
Font:Word;
Direction: Word;
CharSize: Word;
Horiz: Word;
Vert: Word;
end;
12
typu word, ale określającą szerokość tekstu. Obie funkcje jako parametr
wywołania przyjmują łańcuch znaków lub zmienną typu string. Jeśli chcemy
poznać parametry wyświetlania tekstu, to musimy użyć procedury
GetTextSettings. Przyjmuje ona tylko jeden parametr wywołania, będący
zmienną typu TextSettingsType. Definicja typu, która jest umieszczona
w module graph została podana w ramce na poprzedniej stronie. Pole Font
zawiera informacje o kroju, pole Direction zawiera informacje o kierunku
wypisywania, pole CharSize zawiera informacje o rozmiarze znaków, pole Horiz
zawiera informacje o wyrównaniu pionowym tekstu, pole Vert o wyrównaniu
poziomym.
13