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