Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

obrazek

Autor artykułu: mgr Jerzy Wałaszek

©2020 mgr Jerzy Wałaszek
I LO w Tarnowie

obrazek

Interpolacja

Biblioteka graficzna BGI

SPIS TREŚCI
Podrozdziały

Instalacja biblioteki graficznej BGI

Niektóre z omawianych w artykule zagadnień stają się bardziej zrozumiałe po zastosowaniu grafiki komputerowej. Dlatego postanowiłem wyposażyć kilka przykładowych programów w bibliotekę graficzną BGI (ang. Borland Graphic Interface). Jest ona na dzisiejsze czasy już przestarzała, jednak posiada bardzo istotne zalety: łatwość instalacji oraz prostotę używania. Możliwości biblioteki BGI nie są dzisiaj imponujące, jednak na nasze potrzeby wystarczają zupełnie. Poniższy opis dotyczy instalacji biblioteki BGI w środowisku Windows.

Zainstaluj środowisko CodeBlocks.

Pobierz na swój komputer archiwum bgi.zip.

Rozpakuj to archiwum w dowolnym miejscu na swoim dysku. Otrzymasz katalog bgi:

Wewnątrz katalogu bgi znajdują się cztery pliki:

Pliki graphics.h oraz winbgim.h przekopiuj do katalogu include wewnątrz swojej instalacji CodeBlocks. Jeśli nie zmieniałeś miejsca docelowego dla CodeBlocks, to katalog ten znajdziesz w:

C:\Pliki programów (x86)\CodeBlocks\MinGW\include

Plik libbgi.a przekopiuj do katalogu lib, który znajdziesz wewnątrz katalogu MinGW:

C:\Program files (x86)\CodeBlocks\MinGW\lib

Uruchom CodeBlocks i utwórz nowy projekt konsoli. Z menu wybierz opcję:

W oknie dialogowym Global compiler settings przejdź na zakładkę Linker settings:

W sekcji Link libraries kliknij na dole przycisk Add i w okienku ładowania pliku wybierz plik libbgi.a z katalogu lib, do którego go przekopiowałeś.

Do pola tekstowego w sekcji Other linker options przekopiuj poniższy tekst:

-lbgi -lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32

Zatwierdź zmiany przyciskiem OK.

Do edytora przekopiuj poniższy program:

Przykładowy program w języku C++
#include <iostream>
#include <graphics.h>

using namespace std;

int main()
{
   int gd = DETECT, gm;
   int x = 320, y = 240, r;

   initgraph(&gd, &gm, NULL);

   for(r = 25; r <= 125 ; r += 20)
      circle(x, y, r);

   getch();
   closegraph();
   return 0;
}

Skompiluj i uruchom program. Otrzymasz okno z rysunkiem:

Naciśnij dwa razy klawisz Enter (pierwsze naciśnięcie zamyka okno graficzne, drugie zamyka okno konsoli).

Aby nie powtarzać konfiguracji środowiska przy każdym nowym programie graficznym, zapisz swój projekt jako szablon. Z menu wybierz opcję:

Pojawi się okno dialogowe z prośbą o podanie nazwy szablonu:

Podaj taką nazwę, aby się kojarzyła z grafiką. U mnie będzie to bgi. Po zatwierdzeniu nazwy przyciskiem OK, pojawi się okno informujące o powodzeniu operacji:

CodeBlocks jest gotowe do używania biblioteki graficznej BGI. Nowy projekt tworzysz przez wybranie w kreatorze opcji User templates:

Wtedy zobaczysz nazwy dostępnych szablonów. Wybierasz bgi (u ciebie może mieć inną nazwę) i klikasz w przycisk Go:

Następnie wybierasz miejsce na swoim dysku, gdzie ma zostać utworzony projekt:

Pamiętaj, iż katalog projektu nie jest tutaj tworzony automatycznie. Musisz kliknąć w przycisk Utwórz nowy folder i wybrać nazwę dla katalogu, w którym zostanie umieszczony wybrany szablon projektu:

Projekt zostanie utworzony i w edytorze pojawi się program rysujący okręgi. To wszystko.

Bibliotekę BGI da się również zainstalować w Linuksie, jednak jest to zadanie dla raczej zaawansowanych użytkowników. Jeśli znasz dobrze język angielski (jeśli nie, to naucz się go koniecznie), zaglądnij tutaj:

https://askubuntu.com/questions/525051/how-do-i-use-graphics-h-in-ubuntu

Na początek:  podrozdziału   strony 

Struktura programu BGI

Opiszmy kilka potrzebnych nam funkcji dostępnych w bibliotece graficznej BGI. W implementacji dla Windows biblioteka ta otrzymała kilka dodatkowych funkcji, których nie było w oryginale lub ich działanie było ograniczone. Związane są one z własnościami środowiska graficznego współczesnych komputerów.

Bibliotekę BGI (ang. Borland Graphics Interface) stworzyła znana firma Borland w czasach panowania systemu DOS. Dlatego jej funkcje są dostosowane do możliwości tego systemu oraz do możliwości graficznych dostępnych w owym czasie kart grafiki (CGA, Hercules, EGA, VGA, itp.). Dzisiaj te możliwości wyglądają marnie, lecz wykorzystanie współczesnych kart grafiki komplikuje program i wymaga nauki dosyć zaawansowanych bibliotek graficznych. Tutaj BGI ma niewątpliwą zaletę dla początkujących programistów oraz studentów. Z tego powodu bibliotekę BGI wciąż się wykorzystuje na wielu uczelniach.

Oto kilka przykładowych obrazków na różnych kartach graficznych wczesnych komputerów IBM-PC:

CGA
Hercules
EGA
VGA

Filozofia pracy z biblioteką BGI jest następująca:

Każdy program korzystający z biblioteki BGI musi mieć dołączony plik nagłówkowy graphics.h. Inicjujemy system graficzny przez wywołanie funkcji initgraph() lub initwindow(). Następnie wykonujemy różne operacje graficzne w utworzonym oknie, po czym zamykamy system graficzny za pomocą funkcji closegraph().

void initgraph(int *graphdriver, int *graphmode, char *pathtodriver);

Funkcja inicjuje system graficzny biblioteki BGI.

graphdriver numer sterownika graficznego:
DETECT 0 (automatyczne wykrywanie)
CGA 1
MCGA 2
EGA 3
EGA64 4
EGAMONO 5
IBM8514 6
HERCMONO 7
ATT400 8
VGA 9
PC3270 10

Oryginalnie numer ten używany był do załadowania z dysku sterownika karty graficznej zainstalowanej w komputerze użytkownika. W obecnej wersji jest on używany jedynie do określenia maksymalnych rozmiarów tworzonego okna graficznego (każda karta grafiki posiadała określoną rozdzielczość). Najczęściej wykorzystuje się wartość DETECT, która ustawia rozmiar okna na maksymalny rozmiar dla wykrytego sterownika.

graphmode tryb graficzny dla wybranego sterownika:
Sterownik tryb   Wartość     Rozdzielczość Paleta    Liczba stron
CGA CGAC0 0 320 x 200 C0 1
  CGAC1 1 320 x 200 C1 1
  CGAC2 2 320 x 200 C2 1
  CGAC3 3 320 x 200 C3 1
  CGAHI 4 640 x 200 2 kolory 1
 
MCGA MCGAC0 0 320 x 200 C0 1
 
  MCGAC1 1 320 x 200 C1 1
  MCGAC2 2 320 x 200 C2 1
  MCGAC3 3 320 x 200 C3 1
  MCGAMED 4 640 x 200 2 kolory 1
  MCGAHI 5 640 x 480 2 kolory 1
 
EGA EGALO 0 640 x 200 16 kolorów 4
 
  EGAHI 1 640 x 350 16 kolorów 2
 
EGA64 EGA64LO 0 640 x 200 16 kolorów 1
 
  EGA64HI 1 640 x 350 4 kolory 1
 
EGA-MONO EGAMONOHI 3 640 x 350 2 kolory 1 w/64K
  EGAMONOHI 3 640 x 350 2 kolory 2 w/256K
 
HERC HERCMONOHI 0 720 x 348 2 kolory 2
 
ATT400 ATT400C0 0 320 x 200 C0 1
  ATT400C1 1 320 x 200 C1 1
  ATT400C2 2 320 x 200 C2 1
  ATT400C3 3 320 x 200 C3 1
  ATT400MED 4 640 x 200 2 kolory 1
  ATT400HI 5 640 x 400 2 kolory 1
 
VGA VGALO 0 640 x 200 16 kolorów 2
  VGAMED 1 640 x 350 16 kolorów 2
  VGAHI 2 640 x 480 16 kolorów 1
 
PC3270 PC3270HI 0 720 x 350 2 kolory 1
 
IBM8514 IBM8514LO 0 640 x 480 256 kolorów ?
  IBM8514HI 1 1024 x 768 256 kolorów ?

Liczba kolorów nie jest istotna, ponieważ obecna implementacja BGI w Windows zawiera możliwość rysowania w dowolnym kolorze.

pathtodriver ścieżka do pliku sterownika graficznego na dysku. Parametr ten nie jest używany w Windows i może być dowolnym tekstem.
int initwindow(int width, int height, const char* title="Windows BGI", int left=0, int top=0, bool dbflag=false, closeflag=true);

Funkcja dostępna w wersji BGI dla systemu Windows, nie było jej w takiej postaci w oryginalnej bibliotece Borlanda. Inicjuje bibliotekę BGI i otwiera ona okno graficzne o wybranych parametrach. Funkcja initwindow() wymaga tylko dwóch pierwszych parametrów, pozostałe są opcjonalne. Jeśli je pominiesz w wywołaniu, to przyjmą standardowe wartości. Zalecamy stosowanie tej funkcji zamiast initgraph(). Funkcja zwraca numer otwartego okna. Użytkownik może otwierać wiele okien, a numer służy do wyboru aktywnego okna. W oryginalnej bibliotece BGI można było otworzyć tylko jedno okno.

width szerokość obszaru rysunkowego okna w pikselach.
height wysokość obszaru rysunkowego okna w pikselach.
title tytuł tworzonego okna.
left, top współrzędne lewego górnego narożnika okna
dbflag wartość true włącza podwójne buforowanie.
closeflag wartość true umożliwia użytkownikowi zamknięcie okna przez kliknięcie myszką w ikonę [x] na pasku tytułowym.
void closegraph(int wid=ALL_WINDOWS);

W oryginalnej bibliotece BGI funkcja closegraph() zamykała system graficzny, zwalniała pamięć i powodowała powrót do trybu tekstowego. W wersji dla systemu Windows funkcja posiada dodatkowy parametr, który może przyjąć wartość numeru otwartego okna. W takim przypadku zostaje zamknięte okno o tym numerze. Numer okna otrzymujemy jako wynik funkcji initwindow(). Jeśli w programie będzie otwierane kilka okien, to numer ten należy zapamiętać.

wid numer okna do zamknięcia. Brak tego parametru spowoduje zamknięcie wszystkich okien BGI.
void setcurrentwindow(int window);
Funkcja setcuurentwindow() jest dostępna tylko w implementacji biblioteki BGI dla systemu Windows. Wybiera ona okno do wykonywania w nim wszystkich operacji graficznych. Takie okno staje się oknem aktualnym. Funkcje initwindow() oraz initgraph() automatycznie tworzą i ustawiają bieżące okno. Jeśli twoja aplikacja wykorzystuje tylko jedno okno, to nie ma potrzeby wywoływać po nich funkcji setcurrentwindow().
window numer okna, które ma się stać oknem bieżącym. Numer ten jest wynikiem wywołania funkcji initwindow()
int getcurrentwindow();
Funkcja jest dostępna tylko w implementacji biblioteki BGI dla Windows. Zwraca numer bieżącego okna. Bieżące okno jest tym, w którym są wykonywane wszystkie operacje graficzne.

Poniższy program otwiera małe okno graficzne, oczekuje na klawisz, po czym zamyka to okno. Aby go uruchomić wykorzystaj szablon aplikacji bgi.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Test biblioteki BGI
//----------------------------

#include <iostream>
#include <graphics.h>

using namespace std;

int main()
{
   initwindow(240,120,"Test BGI");
   getch();
   closegraph();
   return 0;
}

Jeśli nie chcesz okna konsoli, to z menu wybierz opcję Project/Properties... Pojawi się okno dialogowe z własnościami projektu. Wybierz zakładkę Build targets i na liście Type zmień Console application na GUI application:

Na początek:  podrozdziału   strony 

Kolory w BGI

Gdy mamy już okno graficzne, to możemy w nim wykonywać różne operacje graficzne. Poniżej opisujemy podstawowe funkcje graficzne – pełny opis biblioteki BGI znajdziesz w sieci.

Kolory w oryginalnej bibliotece BGI były ograniczone do kolorów dostępnych na karcie graficznej komputera. Dla kart wyświetlających grafikę kolorową było to zwykle 16 następujących kolorów:

Nazwa Wartość Kolor
BLACK 0  
BLUE 1  
GREEN 2  
CYAN 3  
RED 4  
MAGENTA 5  
BROWN 6  
LIGHTGRAY 7  
DARKGRAY 8  
LIGHTBLUE 9  
LIGHTGREEN 10  
LIGHTCYAN 11  
LIGHTRED 12  
LIGHTMAGENTA 13  
YELLOW 14  
WHITE 15  

Podane powyżej nazwy stałych oraz ich wartości liczbowe można wciąż używać w implementacji biblioteki BGI dla Windows, jednakże nowoczesne karty graficzne nie są już ograniczone do 16 kolorów. Dlatego w BGI dla Windows kolory w operacjach graficznych można również określać za pomocą  składowych kolorów R (ang. red – składowa czerwona), G (ang. green – składowa zielona), B (ang. blue – składowa niebieska). Jeśli popatrzysz na ekran swojego monitora przez mocne szkło powiększające, to zobaczysz, że na jego powierzchni znajdują się punkty świecące tylko jednym z trzech kolorów składowych:

Pojedynczy piksel składa się z trzech takich punktów. Kolor piksela zależy od natężenia barw składowych. Do określania tego koloru w bibliotece BGI mamy makro COLOR(R,G,B). Zamienia ono wartości natężenia składowych koloru na kolor wynikowy. Składowe R, G i B mogą przyjmować wartości od 0 do 255:

R G B Kolor
0 0 0  
0 0 204  
0 204 0  
0 204 204  
204 0 0  
204 0 204  
204 204 0  
204 204 204  
64 64 64  
0 0 255  
0 255 0  
0 255 255  
255 0 0  
255 0 255  
255 255 0  
255 255 255  
void setcolor(int color);

Ustawia bieżący kolor rysowania dla operacji graficznych.

color wartość koloru może być podana jako liczba od 0 do 15, jako stała BLACK, BLUE, GREEN, ..., WHITE lub jako makro COLOR().
int getcolor(void);

Zwraca wartość bieżąco używanego koloru. Jest to ta sama wartość, którą przekazano w parametrze funkcji setcolor().

Na początek:  podrozdziału   strony 

Piksele w BGI

Słowo piksel pochodzi z języka angielskiego (ang. pixel): pixel = picture element. Jest to najmniejszy, niepodzielny element obrazu, który przyjmuje jednolity kolor Powierzchnia robocza okna graficznego składa się z prostokątnej siatki pikseli, którą nazywamy rastrem (ang. raster):

W rastrze piksele ułożone są w poziome wiersze i pionowe kolumny. Ilość kolumn i wierszy określa rozmiar rastra (np.: 1024 x 768). Piksele są zdefiniowane w rastrze poprzez ich współrzędne: numer kolumny oraz numer wiersza:

Na przykład:

Piksel A ma współrzędne (0,0)
Piksel B ma współrzędne (2,4)
Piksel C ma współrzędne (3,1)

Jeśli przyrównamy to do osi układu współrzędnych, to numer kolumny będzie odpowiadał współrzędnej x, a numer wiersza będzie odpowiadał współrzędnej y. Oś OY jest skierowana w dół. Współrzędne nie przyjmują wartości ujemnych:

void putpixel(int x, int y, int color);

Na pozycji (x,y) rysuje piksel w podanym kolorze.

x,y współrzędne, na których ma zostać postawiony piksel
color wartość koloru może być podana jako liczba od 0 do 15, jako stała BLACK, BLUE, GREEN, ..., WHITE lub jako makro COLOR().
int getwindowheight(void);

Zwraca łączną wysokość w pikselach bieżącego okna.

int getwindowwidth(void);

Zwraca łączną szerokość w pikselach bieżącego okna.

int getmaxx(void);

Zwraca największą wartość współrzędnej x w bieżącym oknie.

int getmaxy(void);

Zwraca największą wartość współrzędnej y w bieżącym oknie.

Poniższy program wypełnia obszar graficzny okna pikselami o przypadkowych kolorach. Okno zamknij ikoną [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Piksele
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    int xmax,ymax;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(400,300,"Piksele");

    // Odczytujemy rozmiar obszaru roboczego okna
    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Pętla nieskończona
    while(1)
    {
        // Rysujemy piksel o przypadkowym kolorze
        putpixel(rand() % xmax,
                 rand() % ymax,
                 COLOR(rand() & 0xff,
                       rand() & 0xff,
                       rand() & 0xff));
    }
    closegraph();
    return 0;
}

Wynik:

Kolejny program uzależnia składowe koloru piksela od jego pozycji w oknie. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Piksele
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    int xmax,ymax;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(200,200,"Piksele");

    // Odczytujemy rozmiar obszaru roboczego okna
    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    int crs,cre,cgs,cge,cbs,cbe; // Kolory narożników

    int x,y;      // Pozycja piksela
    int cr,cg,cb; // Kolor na pozycji piksela

    int r,rmax;

    rmax = (xmax - 1) * (xmax - 1) + (ymax - 1) * (ymax - 1);

    // Pętla nieskończona
    while(1)
    {
        // Generujemy kolory dla dwóch narożników.
        // Lewy górny

        crs = rand() & 0xff;
        cgs = rand() & 0xff;
        cbs = rand() & 0xff;

        // Prawy dolny

        cre = 255 - crs;
        cge = 255 - cgs;
        cbe = 255 - cbe;

        // Rysujemy piksele

        for(y = 0; y < ymax; y++)
            for(x = 0; x < xmax; x++)
            {
                // Wyliczamy kolor w punkcie (x,y)

                r  = x * x + y * y;
                cr = crs + r * (cre - crs) / rmax;
                cg = cgs + r * (cge - cgs) / rmax;
                cb = cbs + r * (cbe - cbs) / rmax;

                // Stawiamy piksel

                putpixel(x,y,COLOR(cr,cg,cb));
            }
    }
    closegraph();
    return 0;
}

Wynik:

Na początek:  podrozdziału   strony 

Odcinki w BGI

Za pomocą pikseli można narysować dowolną figurę geometryczną, jednakże nie jest to wcale takie proste. Już narysowanie zgrabnego odcinka wymaga dosyć skomplikowanego algorytmu, dlatego każda szanująca się biblioteka graficzna posiada odpowiednie funkcje.

void line(int x1, int y1, int x2, int y2);

Rysuje odcinek od punktu (x1,y1) do punktu (x2,y2) za pomocą pikseli o bieżącym kolorze. Kolor ustawia się funkcją setcolor().

x1,y1 współrzędne początku odcinka
x2,y2 współrzędne końca odcinka

Poniższy program wypełnia okno przypadkowymi odcinkami. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Odcinki
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    int xmax,ymax;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(400,400,"Odcinki");

    // Odczytujemy rozmiar obszaru roboczego okna
    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Pętla nieskończona
    while(1)
    {
        // Ustawiamy przypadkowy kolor rysowania
        setcolor(COLOR(rand() & 0xff, rand() & 0xff, rand() & 0xff));

        // Rysujemy odcinek w oknie
        line(rand() % xmax, rand() % ymax,
             rand() % xmax, rand() % ymax);

    }
    closegraph();
    return 0;
}

Wynik:

Następny program jest ciekawszy. Za pomocą odcinków tworzy prostą grafikę.  Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Odcinki
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    int xmax,ymax,x,cr,cg,cb,er,eg,eb;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(400,400,"Odcinki");

    // Odczytujemy rozmiar obszaru roboczego okna
    xmax = getmaxx();
    ymax = getmaxy();

    // Generujemy kolor startowy
    cr = rand() & 0xff;
    cg = rand() & 0xff;
    cb = rand() & 0xff;

    // Generujemy kolor docelowy
    er = rand() & 0xff;
    eg = rand() & 0xff;
    eb = rand() & 0xff;

    // Pętla nieskończona
    while(1)
    {
       // Ustawiamy kolor
       setcolor(COLOR(cr,cg,cb));

       // Modyfikujemy składowe kolorów
       if(cr > er) cr--;
       if(cr < er) cr++;
       if(cg > eg) cg--;
       if(cg < eg) cg++;
       if(cb > eb) cb--;
       if(cb < eb) cb++;

       if(cr == er) er = rand() & 0xff;
       if(cg == eg) eg = rand() & 0xff;
       if(cb == eb) eb = rand() & 0xff;

       // Rysujemy figurę

       x = 0;
       while(x <= xmax)
       {
           line(0,0,x,ymax);
           line(0,ymax,x,0);
           line(xmax,0,x,ymax);
           line(xmax,ymax,x,0);
           x += 10;
       }
    }
    closegraph();
    return 0;
}

Wynik:

Łamana jest figurą zbudowaną z ciągu odcinków. W łamanej punkt końcowy jednego odcinka jest punktem startowym następnego. Łamaną można narysować przy pomocy wywołań funkcji line(), lecz w bibliotece BGI istnieje prostszy sposób.

void moveto(int x, int y);

Ustawia bieżącą pozycję graficzną w punkcie (x,y).  Funkcja nie rysuje nic na obszarze graficznym.

x,y współrzędne pozycji, od której rozpocznie się rysowanie
void lineto(int x, int y)

Rysuje odcinek od bieżącej pozycji graficznej do punktu (x,y). Po narysowaniu odcinka punkt (x,y) staje się nową pozycją bieżącą.

x,y współrzędne końca odcinka

Poniższy program wykorzystuje podane funkcje moveto() i lineto() do narysowania ciekawej figury geometrycznej. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Łamana
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    int xmax,ymax,cr,cg,cb,er,eg,eb;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(600,400,"Łamana");

    // Odczytujemy rozmiar obszaru roboczego okna
    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Generujemy kolor startowy
    cr = rand() & 0xff;
    cg = rand() & 0xff;
    cb = rand() & 0xff;

    // Generujemy kolor docelowy
    er = rand() & 0xff;
    eg = rand() & 0xff;
    eb = rand() & 0xff;

    // Tworzymy N punktów na powierzchni graficznej
    const int N = 50;  // Liczba punktów na obwodzie elipsy
    int x[N],y[N];

    for(int i = 0; i < N; i++)
    {
        x[i] = rand() % xmax;
        y[i] = rand() % ymax;
    }

    // Pętla nieskończona
    while(1)
    {
        // Ustawiamy kolor
        setcolor(COLOR(cr,cg,cb));

        // Modyfikujemy składowe kolorów
        if(cr > er) cr--;
        if(cr < er) cr++;
        if(cg > eg) cg--;
        if(cg < eg) cg++;
        if(cb > eb) cb--;
        if(cb < eb) cb++;

        if(cr == er) er = rand() & 0xff;
        if(cg == eg) eg = rand() & 0xff;
        if(cb == eb) eb = rand() & 0xff;

        // Rysujemy figurę

        moveto(x[0],y[0]);
        for(int i = 1; i < N; i++) lineto(x[i],y[i]);
    }
    closegraph();
    return 0;
}

Wynik:

Kolejne funkcje umożliwiają rysowanie tych samych figur poczynając od wybranego punktu, ponieważ posługują się one współrzędnymi względnymi:

void moverel(int dx, int dy);

Ustawia bieżącą pozycję graficzną w punkcie w odległości dx (w poziomie) i dy (w pionie) od poprzednio ustawionej pozycji graficznej.  Funkcja nie rysuje nic na obszarze graficznym.

dx,dy odległości w poziomie i w pionie od bieżącej pozycji graficznej
void linerel(int dx, int dy);

Rysuje odcinek od bieżącej pozycji graficznej do punktu odległego w poziomie o dx i w pionie o dy. Po narysowaniu odcinka punkt końcowy staje się nową pozycją bieżącą.

dx,dy odległości w poziomie i w pionie od bieżącej pozycji graficznej

Dodatkowo opiszmy kilka przydatnych funkcji biblioteki BGI:

void setbkcolor(int color);

Ustawia kolor tła okna.

color wartość koloru może być podana jako liczba od 0 do 15, jako stała BLACK, BLUE, GREEN, ..., WHITE lub jako makro COLOR().
int getbkcolor(void);

Zwraca wartość bieżącego koloru tła.

void cleardevice(void);

Zamalowuje całe okno kolorem tła i ustawia bieżącą pozycję graficzną w lewym górnym narożniku okna na współrzędnych (0,0).

color wartość koloru może być podana jako liczba od 0 do 15, jako stała BLACK, BLUE, GREEN, ..., WHITE lub jako makro COLOR().
void delay(int millisec);

Wstrzymuje wykonywanie programu na zadany okres czasu w milisekundach (tysięcznych częściach sekundy). Funkcja umożliwia tworzenie prostych animacji.

millisec wartość opóźnienia.

Poniższy program rysuje trójkąty w różnych miejscach okna graficznego. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Łamana
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

const int N = 50; // Liczba trójkątów

int main()
{
    int xmax,ymax,x[3],y[3],i,j;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(600,400,"Trójkąty");

    // Odczytujemy rozmiar obszaru roboczego okna
    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Pętla nieskończona
    while(1)
    {
        // Generujemy wierzchołki trójkąta
        for(i = 0; i < 2; i++)
        {
            x[i] = rand() % 200 - 100;
            y[i] = rand() % 200 - 100;
        }
        x[2] = -x[0] - x[1];
        y[2] = -y[0] - y[1];

        // Czyścimy treść okna
        cleardevice();

        // Na przypadkowych pozycjach rysujemy N trójkątów
        for(i = 0; i < N; i++)
        {
            // Kolor trójkąta
            setcolor(COLOR(rand() & 0xff,rand() & 0xff,rand() & 0xff));

            // Pozycja startowa
            moveto(rand() % xmax, rand() % ymax);

            // Rysujemy 3 odcinki
            for(j = 0; j < 3; j++) linerel(x[j],y[j]);

        }

        // Czekamy pół sekundy
        delay(500);
    }
    closegraph();
    return 0;
}

Wynik:

Na początek:  podrozdziału   strony 

Klawiatura i mysz w BGI

Biblioteka BGI umożliwia odczyt naciśniętych klawiszy oraz pozycji i stanu przycisków myszki.

int kbhit(void);

Funkcja zwraca wartość różną od zera, jeśli w buforze klawiatury oczekuje kod naciśniętego klawisza. Okno graficzne musi posiadać skupienie, inaczej biblioteka BGI nie ma kontroli nad klawiaturą. Funkcja przydaje się wtedy, gdy twoja aplikacja wyświetla jakąś animację, której nie chcesz przerywać oczekiwaniem na naciśnięcie klawisza przez użytkownika. Przykład użycia znajdziesz w programie poniżej.

int getch(void);

Funkcja odczytuje kod naciśniętego klawisza i zwraca go jako swój wynik. Jeśli w buforze klawiatury nie oczekuje kod, to funkcja wstrzymuje działanie programu do momentu, aż użytkownik naciśnie klawisz. W pewnych wypadkach może to być niepożądane, ponieważ następuje zatrzymanie wykonywania programu. Rozwiązaniem jest użycie funkcji getch() wspólnie z funkcją kbhit():

    ...
    if(kbhit()) // Sprawdzamy, czy naciśnięto klawisz
    {
        key = getch(); // Odczytujemy kod naciśniętego klawisza
        ... // Przetwarzamy ten kod
    }
    ...

Ten sposób nie powoduje zatrzymania programu, można go zatem stosować w prostych grach.

Jeśli naciśniętym klawiszem jest klawisz specjalny, to funkcja getch() zwróci wartość zero. W takim przypadku ponowne wywołanie getch() da nam kod naciśniętego klawisza specjalnego. Kody te są następujące:

#define KEY_HOME       71
#define KEY_UP         72
#define KEY_PGUP       73
#define KEY_LEFT       75
#define KEY_CENTER     76
#define KEY_RIGHT      77
#define KEY_END        79
#define KEY_DOWN       80
#define KEY_PGDN       81
#define KEY_INSERT     82
#define KEY_DELETE     83
#define KEY_F1         59
#define KEY_F2         60
#define KEY_F3         61
#define KEY_F4         62
#define KEY_F5         63
#define KEY_F6         64
#define KEY_F7         65
#define KEY_F8         66
#define KEY_F9         67
Sposób postępowania jest następujący:
    ...
    key = getch(); // Odczytujemy kod klawisza
    if(!key)       // Klawisz specjalny?
    {
        key = getch(); // Odczytujemy kod klawisza specjalnego
        ...        // Przetwarzamy klawisz specjalny
    }
    else
    {
        ...        // Przetwarzamy klawisz normalny
    }
    ...

Jeśli naciśnięto klawisz normalny, to funkcja zwraca jego kod ASCII.

void getmouseclick(int kind, int& x, int& y);

Funkcja odczytuje stan myszki dla zdarzenia, którego kod przekazujemy w parametrze kind. Jeśli dane zdarzenie wystąpiło i nie zostało jeszcze przetworzone, to w zmiennych x  i y  funkcja umieści współrzędne kursora myszki w chwili zdarzenia. Jeśli zdarzenie nie wystąpiło, to w x  i y  umieszczone zostają wartości -1. Funkcja nie czeka na wystąpienie zdarzenia. Rodzaje zdarzeń zdefiniowane są za pomocą stałych:

WM_MOUSEMOVE
Jeśli chcesz wykryć ruch myszki
WM_LBUTTONDBLCLK
Jeśli chcesz wykryć podwójne kliknięcie lewym przyciskiem myszki
WM_LBUTTONDOWN
Jeśli chcesz wykryć wciśnięcie lewego przycisku myszki
WM_LBUTTONUP
Jeśli chcesz wykryć zwolnienie lewego przycisku myszki
WM_MBUTTONDBLCLK
Jeśli chcesz wykryć podwójne kliknięcie środkowego przycisku myszki
WM_MBUTTONDOWN
Jeśli chcesz wykryć wciśnięcie środkowego przycisku myszki
WM_MBUTTONUP
Jeśli chcesz wykryć zwolnienie środkowego przycisku myszki
WM_RBUTTONDBLCLK
Jeśli chcesz wykryć podwójne kliknięcie prawego przycisku myszki
WM_RBUTTONDOWN
Jeśli chcesz wykryć wciśnięcie prawego przycisku myszki
WM_RBUTTONUP
Jeśli chcesz wykryć zwolnienie prawego przycisku myszki
bool ismouseclick(int kind);

Funkcja zwraca wartość true, jeśli wystąpiło zdarzenie myszki podanego typu (patrz powyżej). Współrzędne x,y położenia kursora myszki w momencie zdarzenia można następnie odczytać za pomocą funkcji getmouseclick().

Poniższy program jest prostym edytorem graficznym. Umożliwia on rysowanie myszką w oknie. Kolor rysowanych linii wybieramy klawiszami: R (czerwony), G (zielony), B (niebieski) i W (biały). Zawartość okna czyścimy naciśnięciem prawego przycisku myszki. Linie rysujemy naciskając lewy przycisk myszki.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Klawiatura i myszka
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Otwieramy okno graficzne
    initwindow(600,600,"Klawiatura/myszka");

    // Zmienne
    int key;            // klawisz
    int x,y;            // Współrzędne kursora myszki
    bool drawing = FALSE; // Rysowanie

    setcolor(WHITE);

    // Pętla nieskończona
    while(1)
    {
        if(kbhit()) // Sprawdzamy, czy naciśnięto klawisz
        {
            key = getch(); // Tak, pobieramy kod klawisza
            switch(toupper(key))
            {
                case 'W': setcolor(WHITE);      break;
                case 'R': setcolor(LIGHTRED);   break;
                case 'G': setcolor(LIGHTGREEN); break;
                case 'B': setcolor(LIGHTBLUE);  break;
                default: break;
            }
        }

        // Sprawdzamy, czy wciśnieto prawy przycisk myszki
        getmouseclick(WM_RBUTTONDOWN,x,y);
        if(x != -1)
        {
            drawing = FALSE;
            cleardevice();
        }

        // Sprawdzamy, czy wciśnięto lewy przycisk myszki
        getmouseclick(WM_LBUTTONDOWN,x,y);
        if(x != -1)
        {
            drawing = TRUE;
            moveto(x,y);
        }

        // Sprawdzamy, czy zwolniono lewy przycisk myszki
        getmouseclick(WM_LBUTTONUP,x,y);
        if(x != -1)
        {
            drawing = FALSE;
            lineto(x,y);
        }

        // Sprawdzamy, czy należy rysować
        if(drawing)
        {
            // Sprawdzamy, czy myszka wykonała ruch
            getmouseclick(WM_MOUSEMOVE,x,y);
            if(x != -1) lineto(x,y);
        }
    }
    closegraph();
    return 0;
}

Wynik:

Na początek:  podrozdziału   strony 

Tekst w BGI

Często na utworzonej grafice będziesz chciał umieszczać jakieś napisy. Do tego celu biblioteka BGI posiada kilka funkcji. W języku C++ jesteśmy przyzwyczajeni do używania strumieni przy wyprowadzaniu tekstu. W BGI zdefiniowany jest globalny strumień wyjścia bgiout, który pracuje podobnie do strumienia cout. Jednakże nie wyświetla on wprowadzonego tekstu od razu w oknie graficznym, jak robi to strumień wyjścia konsoli cout, lecz umieszcza go w swojej wewnętrznej pamięci. Do wyświetlenia zawartości strumienia bgiout mamy dwie funkcje:

extern ostringstream bgiout;

void outstream(ostringstream& out=bgiout);

void outstreamxy(int x, int y, ostringstream& out=bgiout);

Funkcje wyświetlają w oknie graficznym zawartość strumienia out typu ostringstream. Jeśli pominiesz strumień out na ich liście parametrów, to zostanie standardowo użyty strumień bgiout. Różnica pomiędzy outstream() a outstreamxy() jest taka, iż pierwsza funkcja wyświetla zawartość strumienia out na bieżącej pozycji graficznej, a druga robi to na pozycji (x,y). Obie funkcje czyszczą zawartość strumienia po jej wyświetleniu.

out strumień typu ostringstream. Brak tego parametru spowoduje użycie strumienia bgiout.
x,y pozycja w oknie, na której zostanie wyświetlona zawartość strumienia out.

Poniższy program tworzy przykładową grafikę z tekstem. Po naciśnięciu klawisza następuje zmiana. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Grafika i tekst
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

extern ostringstream bgiout;

int main(void)
{
    // Zmienne
    int xmax,ymax,x1,y1,x2,y2;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Tworzymy okno graficzne
    initwindow(600, 400,"Tekst");

    xmax = getmaxx();
    ymax = getmaxy();

    // Pętla nieskończona
    while(1)
    {
        // Czyścimy okno
        cleardevice();

        // Generujemy początek odcinka
        x1 = xmax / 4 + rand() % 100;
        y1 = ymax / 4 + rand() % 100;

        // Generujemy koniec odcinka
        x2 = (3 * xmax / 4) - rand() % 100;
        y2 = (3 * ymax / 4) - rand() % 100;

        // Rysujemy odcinek w kolorze żółtym
        setcolor(YELLOW);
        line(x1,y1,x2,y2);

        // Kolor tekstu jasnozielony
        setcolor(LIGHTGREEN);

        // Współrzędne początku
        bgiout << "początek:" << endl
               << "(" << x1 << "," << y1 << ")";
        outstreamxy(x1 - 36,y1 - 36);

        // Kolor tekstu jasnoczerwony
        setcolor(LIGHTRED);

        // Współrzędne końca
        bgiout << "koniec:" << endl
               << "(" << x2 << "," << y2 << ")";
        outstreamxy(x2 - 24,y2 + 4);

        // Kolor tekstu biały
        setcolor(WHITE);

        // Czekamy na klawisz
        bgiout << "Naciśnij dowolny klawisz...";
        outstreamxy(0,0);
        getch();
    }

    closegraph( );
    return 0;

}

Wynik:

Do wyświetlania łańcuchów znakowych mamy w bibliotece BGI dwie funkcje:

void outtext(char *textstring);
void outtextxy(int x, int y, char *textstring);

Funkcje wyświetlają podany łańcuch tekstowy textstring w oknie graficznym. Funkcja outtext() wyświetla tekst od bieżącej pozycji graficznej. Funkcja outtextxy() wyświetla tekst od pozycji (x,y).

textstring łańcuch tekstu do wyświetlenia
x,y pozycja w oknie, na której zostanie wyświetlony tekst.

Poniższy program wypełnia treść okna przypadkowymi literami od A do Z. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Tekst
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

extern ostringstream bgiout;

int main(void)
{
    // Zmienne
    int xmax,ymax;

    char t[2];

    t[1] = 0; // Znak EOT, czyli koniec tekstu

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Tworzymy okno graficzne
    initwindow(600, 400,"Tekst");

    xmax = getmaxx();
    ymax = getmaxy();

    // Pętla nieskończona
    while(1)
    {
        // Generujemy znak od A do Z

        t[0] = 'A' + rand() % ('Z' - 'A' + 1);

        // Kolor znaku
        setcolor(1 + rand() % 15);

        // Piszemy znak
        outtextxy(rand() % xmax, rand() % ymax, t);
    }

    closegraph( );

    return 0;

}

Wynik:

Opisane funkcje tekstowe współdziałają z funkcjami, które w bibliotece BGI ustawiają różne parametry tekstu, takie jak kolor liter, pozycja w oknie, krój czcionki, rozmiar, kierunek, długość i wysokość w pikselach oraz sposób wyrównywania.

void setcolor(int color);

Ustawia bieżący kolor liter.

color wartość koloru może być podana jako liczba od 0 do 15, jako stała BLACK, BLUE, GREEN, ..., WHITE lub jako makro COLOR().
void setbkcolor(int color);

Ustawia kolor tła liter.

color wartość koloru może być podana jako liczba od 0 do 15, jako stała BLACK, BLUE, GREEN, ..., WHITE lub jako makro COLOR().
void moveto(int x, int y);

Ustawia początkową pozycję do wyświetlenia tekstu dla funkcji, które nie ustawiają tej pozycji samodzielnie.

x,y współrzędne pozycji, od której rozpocznie się rysowanie tekstu
void moverel(int dx, int dy);

Ustawia bieżącą pozycję graficzną w punkcie w odległości dx (w poziomie) i dy (w pionie) od poprzednio ustawionej pozycji graficznej.  Funkcja nie rysuje nic na obszarze graficznym.

dx,dy odległości w poziomie i w pionie od bieżącej pozycji graficznej
void settextstyle(int font, int direction, int charsize);

Funkcja ustawia krój czcionki, kierunek wypisywania tekstu oraz rozmiar znaków.

font stała określająca krój czcionki, którą użyją funkcje wyświetlające tekst. Ustawienie nowego kroju działa przy następnym wyświetleniu tekstu. Tekst już wyświetlony w oknie nie zmienia się. W Windows kroje są pobierane z zestawu czcionek systemowych. Rozpoznawane stałe mają wartości od 0 do 10:
Nazwa stałej Wartość Opis
DEFAULT_FONT 0 systemowa czcionka bitmapowa
TRIPLEX_FONT 1 Czcionka wektorowa triplex
SMALL_FONT 2 Czcionka wektorowa small
SANS_SERIF_FONT 3 Czcionka wektorowa sans-serif
GOTHIC_FONT 4 Czcionka wektorowa gothic
SCRIPT_FONT 5 Czcionka wektorowa script
SIMPLEX_FONT 6 Czcionka wektorowa simplex
TRIPLEX_SCR_FONT    7 Czcionka wektorowa triplex script
COMPLEX_FONT 8 Czcionka wektorowa complex
EUROPEAN_FONT 9 Czcionka wektorowa European
BOLD_FONT 10 Czcionka wektorowa bold
direction kierunek wypisywania liter. Dostępne są dwie opcje:
Nazwa stałej Wartość Opis
HORIZ_DIR 0 tekst będzie wypisywany poziomo
VERT_DIR 1 tekst będzie wypisywany pionowo
Nie działa z każdą czcionką z powodu błędów implementacji biblioteki BGI w Windows.
charsize określa wielkość czcionek. Dozwolone wartości są od 0 do 10, gdzie 0 oznacza rozmiar użytkownika, 1 oznacza wielkość standardową, 2 oznacza wielkość podwójną, itd.
void setusercharsize(int multx, int divx, int multy, int divy);

Funkcja pozwala skalować czcionki wektorowe. Ponieważ biblioteka BGI używa tylko liczb całkowitych, to skalowanie definiowane jest przez dwie liczby: mnożnik i dzielnik. Na przykład, jeśli chcesz uzyskać czcionkę o szerokości w osi x 1/3 normalnej i wysokości w osi y 4/5 normalnej, to stosujesz wywołanie:

settextstyle(xxx,HORIZ_DIR,0);
setusercharsize(1,3,4,5);

Szczerze mówiąc nie jest to poprawnie zaimplementowane w Windows, działa tylko w kierunku poziomym. W kierunku pionowym nie ma zmian.

multx,divx mnożnik i dzielnik do skalowania w osi x
multy,divy mnożnik i dzielnik do skalowania w osi y
int textwidth(char *textstring);
int textheight(char *textstring);

Z uwagi na skalowanie czcionek tekst może zajmować różne miejsce w obszarze okna. Te funkcje zwracają długość (textwidth()) lub wysokość (textheight()) tekstu w pikselach przy bieżących parametrach wyświetlania tekstu,

textstring łańcuch tekstu, którego długość lub wysokość zostanie zwrócona
void settextjustify(int horiz, int vert);

Funkcja określa sposób pozycjonowania tekstu przez funkcje wyświetlające tekst w oknie graficznym. Pozycjonowanie wykonywane jest względem bieżącej pozycji graficznej.

horiz określa pozycjonowanie tekstu w poziomie względem bieżącej pozycji graficznej. Może przyjmować następujące wartości:
Nazwa stałej Wartość Opis
LEFT_TEXT 0 tekst zostanie wyświetlony z wyrównaniem do lewej
CENTER_TEXT 1 tekst zostanie wyśrodkowany w poziomie
RIGHT_TEXT 2 tekst zostanie wyświetlony z wyrównaniem do prawej
Jeśli kierunek tekstu jest poziomy i parametr horiz ma wartość LEFT_TEXT, to funkcja outtext() zwiększa w poziomie bieżącą pozycję graficzną o szerokość tekstu.
vert określa sposób pozycjonowania tekstu w pionie względem bieżącej pozycji graficznej:
Nazwa stałej Wartość Opis
BOTTOM_TEXT 0 tekst zostanie wyświetlony z wyrównaniem do spodu
CENTER_TEXT 1 tekst zostanie wyśrodkowany w pionie
TOP_TEXT 2 tekst zostanie wyświetlony z wyrównaniem do góry

Poniższy program wyświetla w oknie graficznym teksty o różnych ustawieniach. Prześledź go dokładnie. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym. Program oczekuje na dowolny klawisz przy zmianach wyświetlanych treści.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Tekst
//----------------------------

#include <iostream>
#include <graphics.h>

using namespace std;

int main(void)
{
    // Zmienne
    char * f[] = {(char *)"Standard",
                  (char *)"Triplex",
                  (char *)"Small",
                  (char *)"Sans Serif",
                  (char *)"Gothic",
                  (char *)"Script",
                  (char *)"Simplex",
                  (char *)"Triplex Script",
                  (char *)"Complex",
                  (char *)"European",
                  (char *)"Bold"};

    int i,x,y,s = 0;

    // Tworzymy okno graficzne
    initwindow(600, 500,"Tekst");

    // Pętla nieskończona
    while(1)
    {
        switch(s++)
        {
            case 0: setbkcolor(BLUE);
                    cleardevice();
                    setcolor(YELLOW);
                    x = getmaxx() / 2;
                    y = 64;
                    for(i = DEFAULT_FONT; i <= BOLD_FONT; i++)
                    {
                        if(i == SMALL_FONT) settextstyle(i,HORIZ_DIR,4);
                        else                settextstyle(i,HORIZ_DIR,1);
                        settextjustify(CENTER_TEXT,TOP_TEXT);
                        outtextxy(x,y,f[i]);
                        y += 16 + textheight(f[i]);
                    }
                    break;
            case 1: setbkcolor(RED);
                    cleardevice();
                    setcolor(WHITE);
                    x = 120;
                    y = getmaxy() / 2;
                    for(i = DEFAULT_FONT; i <= BOLD_FONT; i++)
                    {
                        if(i == SMALL_FONT) settextstyle(i,VERT_DIR,4);
                        else                settextstyle(i,VERT_DIR,1);
                        settextjustify(LEFT_TEXT,CENTER_TEXT);
                        outtextxy(x,y,f[i]);
                        x += 16 + textheight(f[i]);
                    }
                    break;
            case 2: setbkcolor(BLACK);
                    cleardevice();
                    setcolor(LIGHTRED);
                    y = 16;
                    for(i = DEFAULT_FONT; i <= BOLD_FONT; i++)
                    {
                        x = 16;
                        settextstyle(i,HORIZ_DIR,0);
                        settextjustify(LEFT_TEXT,TOP_TEXT);
                        setusercharsize(1,1,1,1);
                        moveto(x,y);
                        outtext(f[i]);
                        setusercharsize(2,3,1,1);
                        outtext((char *)" : A");
                        setusercharsize(1,1,1,1);
                        outtext((char *)"A");
                        setusercharsize(2,1,1,1);
                        outtext((char *)"A");
                        setusercharsize(3,1,1,1);
                        outtext((char *)"A");
                        setusercharsize(4,1,1,1);
                        outtext((char *)"A");
                        y += 16 + textheight("Ay");
                    }
                    break;
        }

        if(s == 3) s = 0;

        // Czekamy na klawisz
        getch();
    }

    closegraph( );

    return 0;

}

Wyniki:

Uwagi: implementacja wyświetlania tekstów w bibliotece BGI dla Windows (Windows 10 64-bitowe) nie jest najlepsza. Czcionka Small jest normalnie wyświetlana jako zbyt mała i napisy stają się zupełnie nieczytelne. Dlatego w programie wybrałem dla niej wielkość 4. Czcionki Script i Triplex Script drukowane są identycznie. Tak samo czcionki Triplex, Simplex i European. Nie sprawdzałem działania tego programu w innych systemach Windows, bo nie mam do nich teraz dostępu.

Uwagi: przy druku pionowym w bibliotece BGI są błędy przy czcionce Small i Sans Serif. Small nie jest wcale drukowana, a Sans Serif drukowana jest poziomo.

Uwagi: przy rozmiarze użytkownika czcionka standardowa nie zmienia się wcale, czcionki Smal i Sans Serif drukowane są źle.

Na początek:  podrozdziału   strony 

Obiekty w BGI

Oprócz pikseli i odcinków biblioteka BGI zawiera funkcje rysujące różne figury geometryczne. Tutaj krótko opiszemy kilka z nich.

void drawpoly(int numpoints, int *polypoints);

Funkcja rysuje łamaną zbudowaną zbudowaną z odcinków łączących podane wierzchołki.

numpoints liczba wierzchołków łamanej
polypoints wskazanie tablicy liczb całkowitych, która zawiera pary współrzędnych wierzchołków łamanej.

Poniższy program jest przykładem prostej animacji łamanej. Program działa w nieskończonej pętli, zamknij go kliknięciem w ikonę [x] na pasku tytułowym.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Obiekty
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

const int N = 20; // Liczba wierzchołków łamanej

int main(void)
{
    // Zmienne
    int xy[2 * N],dxy[2 * N],xmax,ymax,i,j;
    int cr,cg,cb,dr,dg,db;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Tworzymy okno graficzne
    initwindow(500, 400,"Łamane");

    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Inicjujemy tablice wierzchołków
    for(i = 0; i < N; i++)
    {
        j = i + i;
        xy[j] = rand() % xmax;
        do dxy[j] = 3 - rand() % 7; while(!dxy[j]);
        j++;
        xy[j] = rand() % ymax;
        do dxy[j] = 3 - rand() % 7; while(!dxy[j]);
    }
    // inicjujemy kolory składowe
    cr = rand() & 0xff;
    cg = rand() & 0xff;
    cb = rand() & 0xff;
    do dr = 3 - rand() % 7; while(!dr);
    do dg = 3 - rand() % 7; while(!dg);
    do db = 3 - rand() % 7; while(!db);

    // Pętla nieskończona
    while(1)
    {
        // Ustawiamy kolor
        setcolor(COLOR(cr,cg,cb));

        // Rysujemy łamaną
        drawpoly(N,xy);

        // modyfikujemy kolory
        cr += dr;
        if((cr < 0) || (cr > 255))
        {
            dr = -dr;
            cr += dr;
        }
        cg += dg;
        if((cg < 0) || (cg > 255))
        {
            dg = -dg;
            cg += dg;
        }
        cb += dr;
        if((cb < 0) || (cb > 255))
        {
            db = -db;
            cb += db;
        }

        // Modyfikujemy współrzędne wierzchołków
        for(i = 0; i < N; i++)
        {
            j = i + i;
            xy[j] += dxy[j];
            if((xy[j] < 0) || (xy[j] >= xmax)) dxy[j] = -dxy[j];
            j++;
            xy[j] += dxy[j];
            if((xy[j] < 0) || (xy[j] >= ymax)) dxy[j] = -dxy[j];
        }

        // Opóźnienie 1/20 sekundy
        delay(20);
    }

    closegraph( );

    return 0;
}

Wynik:

Jeśli łamana ma tworzyć figurę zamkniętą, to ostatni wierzchołek w tablicy musi być równy pierwszemu wierzchołkowi. Wynika z tego, iż tablica musi zawierać o jeden wierzchołek więcej. Prosta modyfikacja powyższego programu tworzy trójkąty:

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Obiekty
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

const int N = 3; // Liczba wierzchołków łamanej

int main(void)
{
    // Zmienne
    int xy[2 * (N + 1)],dxy[2 * N],xmax,ymax,i,j;
    int cr,cg,cb,dr,dg,db;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Tworzymy okno graficzne
    initwindow(500, 400,"Trójkąty");

    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Inicjujemy tablice wierzchołków
    for(i = 0; i < N; i++)
    {
        j = i + i;
        xy[j] = rand() % xmax;
        do dxy[j] = 3 - rand() % 7; while(!dxy[j]);
        j++;
        xy[j] = rand() % ymax;
        do dxy[j] = 3 - rand() % 7; while(!dxy[j]);
    }
    xy[6] = xy[0];
    xy[7] = xy[1];

    // inicjujemy kolory składowe
    cr = rand() & 0xff;
    cg = rand() & 0xff;
    cb = rand() & 0xff;
    do dr = 3 - rand() % 7; while(!dr);
    do dg = 3 - rand() % 7; while(!dg);
    do db = 3 - rand() % 7; while(!db);

    // Pętla nieskończona
    while(1)
    {
        // Ustawiamy kolor
        setcolor(COLOR(cr,cg,cb));

        // Rysujemy łamaną
        drawpoly(N + 1,xy);

        // modyfikujemy kolory
        cr += dr;
        if((cr < 0) || (cr > 255))
        {
            dr = -dr;
            cr += dr;
        }
        cg += dg;
        if((cg < 0) || (cg > 255))
        {
            dg = -dg;
            cg += dg;
        }
        cb += dr;
        if((cb < 0) || (cb > 255))
        {
            db = -db;
            cb += db;
        }

        // Modyfikujemy współrzędne wierzchołków
        for(i = 0; i < N; i++)
        {
            j = i + i;
            xy[j] += dxy[j];
            if((xy[j] < 0) || (xy[j] >= xmax)) dxy[j] = -dxy[j];
            j++;
            xy[j] += dxy[j];
            if((xy[j] < 0) || (xy[j] >= ymax)) dxy[j] = -dxy[j];
        }

        xy[6] = xy[0];
        xy[7] = xy[1];

        // Opóźnienie 1/20 sekundy
        delay(20);
    }

    closegraph( );

    return 0;

}

Wynik:

void setfillstyle(int pattern, int color);

Funkcja ustawia sposób wypełniania figur oraz kolor wypełnienia.

patern stała określająca sposób wypełniania obszaru figury. Dozwolone są następujące wartości:
Nazwa stałej Wartość  Opis
EMPTY_FILL 0 Wypełnienie kolorem tła
SOLID_FILL 1 Pełny kolor wypełnienia
LINE_FILL 2 Wypełnienie liniami poziomymi
LTSLASH_FILL 3 Wypełnienie cienkimi liniami pochyłymi w prawo
SLASH_FILL 4 Wypełnienie grubymi liniami pochyłymi w prawo
BKSLASH_FILL 5 Wypełnienie grubymi liniami pochyłymi w lewo
LTBKSLASH_FILL 6 Wypełnienie cienkimi liniami pochyłymi w lewo
HATCH_FILL 7 Wypełnienie cienką kratą
XHATCH_FILL 8 Wypełnienie kratą pod kątem
INTERLEAVE_FILL 9 Wypełnienie przeplatane
WIDE_DOT_FILL 10 Wypełnienie rozsuniętymi szeroko kropkami
CLOSE_DOT_FILL 11 Wypełnienie blisko leżącymi kropkami
USER_FILL 12 Wypełnienie zdefiniowane przez użytkownika
Uwaga: nie używaj wartości USER_FILL, zamiast tego wywołuj funkcję setfillpattern().
color kolor wypełnienia jako stała 0...15, BLACK...WHITE lub jako kolor RGB ustawiany przez makro COLOR().
void setfillpattern(char *upattern, int color);

Funkcja ustawia wypełnienie zdefiniowane przez użytkownika oraz jego kolor.

upattern jest wskaźnikiem tablicy 8-bajtowej, która określa matrycę 8 × 8 bitów z wzorem wypełnienia. Każdy bajt tablicy jest jednym, 8-bitowym wierszem matrycy wypełnienia.
color kolor wypełnienia jako stała 0...15, BLACK...WHITE lub jako kolor RGB ustawiany przez makro COLOR().
void fillpoly(int numpoints, int *polypoints);

Funkcja rysuje wielokąt zdefiniowany przez numpoints wierzchołków (wielokąt jest automatycznie zamykany) wykorzystując bieżący kolor rysowania. Następnie wypełnia go zgodnie z bieżącym sposobem wypełniania.

upattern jest wskaźnikiem tablicy 8-bajtowej, która określa matrycę 8 × 8 bitów z wzorem wypełnienia. Każdy bajt tablicy jest jednym, 8-bitowym wierszem matrycy wypełnienia.
color kolor wypełnienia jako stała 0...15, BLACK...WHITE lub jako kolor RGB ustawiany przez makro COLOR().

Poniższy program generuje wielokąt zbudowany z zadanej liczby wierzchołków, po czym wypełnia go poszczególnymi rodzajami wypełnienia. Poszczególne etapy są wyzwalane naciśnięciami klawiszy.

Przykładowy program graficzny w języku C++
// BGI
// (C)2020 mgr Jerzy Wałaszek
// Metody numeryczne
// Obiekty
//----------------------------

#include <iostream>
#include <graphics.h>
#include <cstdlib>
#include <ctime>

using namespace std;

const int N = 10; // Liczba wierzchołków wielokąta

int main(void)
{
    // Zmienne
    char * s[] = {(char *)"EMPTY_FILL",
                  (char *)"SOLID_FILL",
                  (char *)"LINE_FILL",
                  (char *)"LTSLASH_FILL",
                  (char *)"SLASH_FILL",
                  (char *)"BKSLASH_FILL ",
                  (char *)"LTBKSLASH_FILL",
                  (char *)"HATCH_FILL",
                  (char *)"XHATCH_FILL",
                  (char *)"INTERLEAVE_FILL",
                  (char *)"WIDE_DOT_FILL",
                  (char *)"CLOSE_DOT_FILL",
                  (char *)"USER_FILL"};

    char f[] = { 0x00,  // 00000000
                 0x7E,  // 01111110
                 0x42,  // 01000010
                 0x5A,  // 01011010
                 0x5A,  // 01011010
                 0x42,  // 01000010
                 0x7E,  // 01111110
                 0x00}; // 00000000

    int p[2 * N];
    int i,j,xmax,ymax;

    // Inicjujemy generator pseudolosowy
    srand(time(NULL));

    // Tworzymy okno graficzne
    initwindow(600, 400,"Wieloboki");

    xmax = getmaxx() + 1;
    ymax = getmaxy() + 1;

    // Generujemy wierzchołki
    for(i = 0; i < N; i++)
    {
        j = i + i;
        p[j++] = rand() % xmax;
        p[j]   = 32 + rand() % (ymax - 32);
    }

    // Wyświetlamy wielobok z kolejnymi wypełnieniami

    for(i = EMPTY_FILL; i <= USER_FILL; i++)
    {
        // Czyścimy okno
        cleardevice();

        // Kolor tła
        setbkcolor(BLUE);

        // Kolor Linii
        setcolor(WHITE);

        // Rodzaj i kolor wypełnienia
        if(i != USER_FILL) setfillstyle(i,YELLOW);
        else               setfillpattern(f,LIGHTRED);

        // Rysujemy wielobok
        fillpoly(N,p);

        // Wyświetlamy nazwę wypełnienia
        setcolor(LIGHTCYAN);
        setbkcolor(BLACK);
        settextstyle(TRIPLEX_FONT,HORIZ_DIR,2);
        settextjustify(CENTER_TEXT,TOP_TEXT);
        moveto(xmax / 2, 5);
        outtext(s[i]);

        // Czekamy na klawisz
        getch();
    }

    closegraph( );

    return 0;
}

Wynik:

void setlinestyle(int linestyle, unsigned upattern, int thickness);

Funkcja ustawia sposób rysowania linii w bibliotece BGI.

linestyle parametr określa styl linii. Może przyjąć następujące wartości:
Nazwa stałej >Wartość Opis
SOLID_LINE 0 Linia ciągła
DOTTED_LINE 1 Linia kropkowana
CENTER_LINE 2 Linia przerywana
DASHED_LINE 3 Linia kreskowana
USERBIT_LINE    4 Linia o wzorze użytkownika
Uwaga, styl linii nie wpływa na rysowanie łuków, okręgów, elips, czy wycinków elips. Korzystają one jedynie z grubości linii.
upattern jeśli styl linii został określony jako USERBIT_LINE, to parametr ten jest traktowany jako 16 bitowy wzorzec do rysowania linii Bit ustawiony na 1 jest rysowany w aktualnym kolorze rysowania, bit ustawiony na 0 rysowany jest w kolorze tła. Jeśli styl linii jest inny od USERBIT_LINE, to wartość parametru upattern jest ignorowana.
thickness parametr określa grubość linii. Przyjmuje tylko dwie wartości:
Nazwa stałej Wartość    Opis
NORM_WIDTH 1 Szerokość na 1 piksel
THICK_WIDTH    3 Szerokość na 3 piksele
void rectangle(int left, int top, int right, int bottom);

Funkcja rysuje czworokąt wykorzystując bieżący kolor oraz bieżący styl linii.

left,top współrzędne lewego górnego narożnika prostokąta.
right,bottom współrzędne prawego dolnego narożnika prostokąta.
void bar(int left, int top, int right, int bottom);

Funkcja wypełnia prostokątny obszar za pomocą bieżącego stylu i koloru wypełnienia. Funkcja nie rysuje linii brzegowej.

left,top współrzędne lewego górnego narożnika obszaru.
right,bottom współrzędne prawego dolnego narożnika obszaru.
void circle(int x, int y, int radius);

Funkcja rysuje okrąg. Używa aktualnego koloru oraz grubości linii. Styl linii nie jest używany.

x,y współrzędne środka okręgu
radius promień okręgu.
void fillellipse(int x, int y, int xradius, int yradius);

Funkcja  rysuje elipsę wykorzystując bieżący kolor linii oraz grubość linii (styl linii nie jest używany), po czym wypełnia ją wg bieżącego stylu i koloru wypełnienia.

x,y współrzędne środka elipsy
xradius promień elipsy w osi x.
yradius promień elipsy w osi y.

Na tym kończymy opis biblioteki BGI. Mamy nadzieję, iż podane tutaj informacje pozwolą skutecznie wykorzystywać to proste narzędzie we własnych programach.

Na początek:  podrozdziału   strony 

Podsumowanie

Poniżej umieściliśmy alfabetyczne zestawienie funkcji biblioteki BGI opisanych w tym rozdziale. Z funkcji tych będziemy korzystać w następnych rozdziałach w tym artykule. W bibliotece BGI jest dużo więcej różnych funkcji, a jeśli cię to zainteresowało, to ich opis znajdziesz w witrynie (w języku angielskim):

Borland Graphics Interface (BGI) for Windows

Biblioteka BGI dla Windows nie jest w pełni dopracowana (szczególnie jeśli chodzi o wyświetlanie tekstów) i nie stanowi konkurencji dla profesjonalnych bibliotek graficznych, np. SDL2, OpenGL lub DirectX. Jednak jej zaletą jest prostota instalacji i stosowania, dlatego nadaje się szczególnie dobrze do naszych celów. Dzięki niej możesz łatwo wyposażać swoje programy w prosty interfejs graficzny do celów prezentacji wyników obliczeń. W następnym rozdziale opisujemy sposoby tworzenia wykresów funkcji matematycznych za pomocą biblioteki BGI, które wykorzystamy do prezentacji wyników obliczeń.

void bar(int left, int top, int right, int bottom);
void circle(int x, int y, int radius);
void cleardevice(void);
void closegraph(int wid=ALL_WINDOWS);
void delay(int millisec);
void drawpoly(int numpoints, int *polypoints);
void fillpoly(int numpoints, int *polypoints);
int  getbkcolor(void);
int  getch(void);
int  getcolor(void);
int  getcurrentwindow();
int  getmaxx(void);
int  getmaxy(void);
void getmouseclick(int kind, int& x, int& y);
int  getwindowheight(void);void initgraph(int *graphdriver, int *graphmode, char *pathtodriver);
int  getwindowwidth(void);
int  initwindow(int width, int height, const char* title="Windows BGI", int left=0, int top=0, bool dbflag=false, closeflag=true);
bool ismouseclick(int kind);
int  kbhit(void);
void line(int x1, int y1, int x2, int y2);
void linerel(int dx, int dy);
void lineto(int x, int y);
void moverel(int dx, int dy);
void moveto(int x, int y);
void outstream(ostringstream& out=bgiout);
void outstreamxy(int x, int y, ostringstream& out=bgiout);
void outtext(char *textstring);
void outtextxy(int x, int y, char *textstring);
void putpixel(int x, int y, int color);
void rectangle(int left, int top, int right, int bottom);
void setbkcolor(int color);
void setcolor(int color);
void setcurrentwindow(int window);
void setfillstyle(int pattern, int color);
void setlinestyle(int linestyle, unsigned upattern, int thickness);
void settextjustify(int horiz, int vert);
void setfillpattern(char *upattern, int color);
void settextstyle(int font, int direction, int charsize);
void setusercharsize(int multx, int divx, int multy, int divy);
int  textheight(char *textstring);
int  textwidth(char *textstring);
Na początek:  podrozdziału   strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2020 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.