1 of 42

A grafika programozás alapjai

Kunné Dr. Tamás Judit�

Dr. Dudás László diái alapján

2 of 42

Vázlat

  • A grafika programozás módozatai
  • A képernyő koordináta rendszere
  • A graphics.h header fájl fontosabb függvényei
  • Mintaprogramok
  • Síkbeli transzformációk

3 of 42

A grafika programozás módozatai

  • A ma már csak ablakban elérhető szöveges (text) üzemmód helyett a monitorokat grafikus üzemmódban használjuk
  • Szöveges üzemmód
    • 80 oszlop, 25 sor, minden blokk egy karaktert tartalmazhat
    • Beállított kódtábla karakterei
  • Grafikus üzemód
    • Képpontonkénti (pixelenkénti) rajzolás
    • Egy képernyőpont a színmélységtől függő számú szín egyikével gyújtható ki
    • Minden rajzi elem kapcsolódó képpontok együtteseként jelenik meg.

4 of 42

A C programozási nyelv használatával elérhető módozatok

  • Alapvetően 2D vonalas grafika DOS szinten, a graphics.h könyvtár függvényeivel

  • Alapvetően 2D vonalas grafika Windows ablakban, a graphics.h könyvtár függvényeivel

5 of 42

  • 2D grafika Windows környezetben a Canvas függvényeivel

  • 3D árnyalt grafika Windows környezetben, OpenGL, DirectX grafikus könyvtárakkal

6 of 42

Képernyőmemória

  • A grafika létrehozása a képernyőmemóriába való írást jelenti
  • A képernyőmemória tartalma alapján a videoelektorika a képernyőképet másodpercenként 60-130 alkalommal újrarajzolja, frissíti
  • A grafikának ilyen hardverközeli programozása helyett magasszintű C függvényeket is használhatunk
  • Mozgást, animációt a kettő, vagy több képernyőnyi képernyőmemóriák tartalmának váltva történő megjelenítésével valósíthatunk meg (Double Buffer)

7 of 42

A képernyő koordináta rendszere�(graphics.h használata esetén)

8 of 42

Monitortípusok, meghajtókártyák, meghajtóprogramok, módok

  • A monitornak, a meghajtókártyának (vezérlőkártya) és a meghajtószoftvernek (interfész) egymáshoz illeszkednie kell
    • Ennek a beállítását az operációs rendszer végzi
  • A C magasszintű grafikus függvényeit, melyek a graphics.h header fájlban találhatóak, a különféle monitorokhoz, illetve meghajtókártyákhoz a meghajtószoftverek illesztik
  • Mód van a monitor és a meghajtókártya alkotta grafikus hardver típusának automatikus meghatározására, detektálására
  • Egy adott grafikus hardver többféle módon beállítható a felbontás, a színek száma szempontjából
    • Ezt a beállítást a grafikus mód (Gm) változó mutatja

9 of 42

A graphics.h fájl fontosabb függvényei

  • Feladatuk szerint:
    • Grafikus rendszer vezérlése
    • Rajzolás
    • Kifestés, kitöltés
    • Szövegkiírás
    • Képernyőrész, illetve ablakkezelés
    • Lapozás
    • Színkezelés
    • Hibakezelés
    • Állapotlekérdezés

10 of 42

Grafikus rendszer vezérlése

  • detectgraph(int *graphdriver, int *graphmode) – Grafikus hardver detektálása (DOS)
    • graphdriver egy egész szám, amely specifikálja, hogy melyik vezérlőt kell használni (pl. VGA – 9, definiálva van enum is)
    • graphmode egy egész szám, amely specifikálja a legnagyobb használható felbontást (függ a vezérlőtől, pl VGA esetén 640x480 felbontás – 2, definiálva van enum is)
  • initgraph(int *graphdriver, int *graphmode, char *pathtodriver) – Grafikus mód beállítás (DOS)
    • Betölti a vezérlőt a lemezről, és a rendszert grafikus módba állítja
    • A detectgraph() eredményeit használja fel a legtöbb esetben

11 of 42

  • initwindow(int width, int height, const char* title=„Windows BGI”, int left=0, int top=0, bool dbflag=false, closeflag=true) – Grafikus mód beállítás (Windows, CodeBlocks)
    • A szélesség és magasság paraméterek kötelezőek, a többi paraméternek van alapértelmezett értéke
    • A cím paraméter az ablak címe, lehetséges üres sztringet is megadni neki, de akkor nem lesz az ablaknak sem címsávja, sem kerete (hasznos felugró ablakoknál). Ha egy szóközt adunk be neki, akkor lesz címsáv és keret is, de nem lesz címe.
    • A bal és a jobb paraméterek az ablak képernyőhöz viszonyított helyzetét adja meg
    • A dbflag paraméter a Double Buffer automatikus használatát mondja meg az ablakra
    • A closeflag paraméter az ablak jobb felső sarkában található x bezárást állítja be
    • Visszatérési értéke a ablak azonosítója

12 of 42

  • closegraph(int wid=ALL_WINDOWS) – A grafikus mód lezárása
    • Felszabítja a grafikus rendszer által lefoglalt memóriát
    • A képernyő módot beállítja az initgraph() előtti állapotra
    • A wid paraméter a bezárandó ablak azonosítója, vagy két konstans érték: ALL_WINDOWS (összes grafikus ablak bezárása) vagy CURRENT_WINDOW (aktuális ablak bezárása)

A rajzolás így az initwindow() és a closegraph() között lehetséges

  • setcurrentwindow(int window) – Aktuális ablak beállítása az ablak azonosítója alapján
  • setgraphmode(int mode) – Más grafikus mód beállítása, ablaktörlés

13 of 42

Rajzolás

  • Grafikus kurzor pozícionálása
    • moveto(int x, int y) – Az x, y pozícióba helyezi a kurzort
    • moverel(int x, int y) – A kurzort relatív távolságba pozícionálja
  • Pont rajzolása
    • putpixel(int x, int y, int color) - Az x, y pozícióba adott színű pontot tesz
    • A szín a 16 BGI szín egyike, vagy számmal vagy szimbolikus névvel megadva (pl. GREEN vagy 2)
  • Szakasz rajzolása
    • line(int x1, int y1, int x2, int y2) – Az x1,y1 ponttól az x2,y2 pontig rajzol az aktuális színnel, a kurzor mozgatása nélkül
    • lineto(int x, int y) – A kurzortól rajzol egy szakaszt az x, y pontig, majd az x,y pontba mozgatja a kurzort
    • linerel(int dx, int dy) – A kurzortól a dx, dy relatív távolságra levő pontig rajzolja a szakaszt, majd oda is mozgatja a kurzort

14 of 42

  • Sokszög rajzolása
    • drawpoly(int numpoints, int *polypoints) – Adott számú sokszög rajzolása az aktuális vonalstílussal és színnel
      • A polypoints a pontok koordinátáit tartalmazza x, y sorrendben egy szekvenciában numpoints*2 számú elemmel (pl x1,y1,x2,y2)
      • Ahhoz, hogy zárt legyen a sokszögünk, n+1 pontot kell felvenni úgy, hogy az utolsó és az első pont koordinátái megegyeznek (Ötszög esetén numpoints=6, és 10. elem = 0. elem, és 11.elem=1.elem)
  • Kör, körív rajzolása
    • circle(int x, int y, int radius) –Aktuális színű körvonallal rendelkező kör rajzolása x,y középponttal, és radius sugárral, a vonalstílus nincs rá hatással
    • arc(int x, int y, int stangle, int endangle, int radius)- Aktuális színű körív rajzolása x,y középponttal, stangle kezdőszöggel, endangle végszöggel, és radius sugárral, a vonalstílus nincs rá hatással
      • Ha a stangle 0, és az endangle 360, akkor egy egész kört rajzol
      • A szög az óra járásával ellentétes irányú, tehát a 0 fok az 3 óra, a 90 fok pedig 12 óra.

15 of 42

  • Ellipszis, elliptikus ív rajzolása
    • ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius) – Elliptikus ív rajzolása aktuális színnel, x, y középponttal, stangle kezdőszöggel, endangle végszöggel, xradius horizontális sugárral és yradius vertikális sugárral
      • Ha a stangle 0, és az endangle 360, akkor egy egész ellipszist rajzol
      • A szög az óra járásával ellentétes irányú, tehát a 0 fok az 3 óra, a 90 fok pedig 12 óra.
  • Téglalap rajzolása
    • Rectangle(int left, int top, int right, int bottom) – Az aktuális vonalstílusú és színű téglalap rajzolása
      • A left, top a felső bal pont koordinátája, míg a rigth, bottom a jobb alsó sarokpont koordinátája
  • Rajzolási stílusok beállítása
    • setlinestyle(int linestyle, unsigned upattern, int thickness) –Vonalstílus beállítása
      • linestyle: pl. tömör vonal, pontozott vonal, szaggatott vonal
      • Van lehetőség egyénileg megadott mintára is, amelyet az upattern paraméter értékeként kell megadni (ekkor a linestyle USERBIT_LINE vagy 4). A minta formátuma 0xFFFF (tömör vonal), 0x3333 (pontozott vonal) alakban írható le
      • thickness: a vonal vastagsága, értékei NORM_WIDTH 1 értékkel(1 pixel széles), illetve THICK_WIDTH 3 értékkel (3 pixel széles)

16 of 42

Kifestés, kitöltés

  • Kitöltőminta és szín beállítása
    • Setfillstyle(int pattern, int color)- Előre definiált minta beállítása
      • Minta lehet például az EMPTY_FILL (a háttérszínnel tölti ki), SOLID_FILL (aktuális színnel tölti ki), stb
      • A color a BGI színek egyike

    • Setfillpattern(char *upattern, int color) – Egyedi minta beállítása
      • A color a BGI színek egyike
      • Az upattern 8x8as minta (8 byte szekvenciája, ahol mindegyik byte 8 pixelnek felel meg), ahol 1-es van, az lesz kirajzolva
        • Például a sakktábla mintája: char checkboard[8] = { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};

17 of 42

  • Kitöltött téglalap rajzolása
    • Bar(int left, int top, int right, int bottom) – Átló végpontokkal megadott kitöltött, 2D-s téglalap, melynek nincs körvonala, és az aktuális mintával és színnel van kitöltve
    • Bar3d(int left, int top, int right, int bottom, int depth, int topflag) – Átló végpontokkal megadott, 3D-s téglalap
      • A depth paraméter adja meg a mélységét pixelben
      • A topflag ha nem nulla, akkor lesz teteje, ha nulla, akkor nem lesz teteje és egymásra lehet őket rakni
  • Kitöltött sokszög rajzolása
    • fillpoly(int numpoints, int *polypoints) – Adott oldalszámú kitöltött sokszög rajzolása, amely az aktuális mintával és színnel van kitöltve
      • A drawpoly()-val ellentétben itt az első és az utolsó pontnak nem kell megegyeznie, automatikusan bezárja
  • Kitöltött ellipszis rajzolása
    • fillellipse(int x, int y, int xradius, int yradius) – Adott középpontú, és tengelyű kitöltött ellipszis rajzolása, amely az aktuális mintával és színnel van kitöltve

18 of 42

  • Kitöltött cikk rajzolása
    • pieslice(int x, int y, int stangle, int endangle, int radius) – Adott középpontú és sugarú tortaszelet rajzolása a stangle kezdőszög és az endangle végszög között, amely az aktuális mintával és színnel van kitöltve
      • Ha a stangle 0, és az endangle 360, akkor egy egész kitöltött kört rajzol
      • A szög az óra járásával ellentétes irányú, tehát a 0 fok az 3 óra, a 90 fok pedig 12 óra.
    • sector(int x, int y, int stangle, int endangle, int xradius, int yradius) – Elliptikus szektor aktuális színnel és mintával kitöltve, x, y középponttal, stangle kezdőszöggel, endangle végszöggel, xradius horizontális sugárral és yradius vertikális sugárral
      • Ha a stangle 0, és az endangle 360, akkor egy egész ellipszist rajzol
      • A szög az óra járásával ellentétes irányú, tehát a 0 fok az 3 óra, a 90 fok pedig 12 óra.
  • Kitöltés
    • floodfill(int x, int y, int border) – Zárt részek kitöltése az aktuális színnel és mintával
      • x,y pont a magpont, ami körül kitölti a zárt részt.
      • Ha a magpont zárt részben található akkor azt tölti ki, ha nem, akkor külső rész lesz kitöltve

19 of 42

Szövegkiírás

  • Szövegkiírás
    • outtext(char *string) – Adott szöveg kiírása a kurzor pozícióhoz az aktuális karaktertípus, irány és méret szerint
      • Abban az esetben ha balra igazított szöveg van, és az irány horizontális, akkor frissíti a kurzor x koordinátáját
    • outtextxy(int x, int y, char *textstring) - Adott szöveg kiírása az adott koordinátákhoz az aktuális karaktertípus, irány és méret szerint
  • Szövegigazítás beállítása
    • settextjustify(int horiz, int vert) – Horizontális és vertikális szövegigazítás beállítása
      • horiz lehetséges értékei: LEFT_TEXT (0) balra igazítás, CENTER_TEXT (1) középre igazítás, RIGHT_TEXT (2) jobbra igazítás
      • vert lehetséges értékei: BOTTOM_TEXT (0) alulra igazítás, CENTER_TEXT (1) középre igazítás, TOP_TEXT (2) felülre igazítás

20 of 42

  • Karaktertípus, irány, méret beállítása
    • settextstyle(int font, int direction, int charsize) – Karaktertípus, irány, méret beállítása
      • font paraméter néhány lehetséges értéke: DEFAULT_FONT (0) 8x8-as bittérkép font, SANS_SERIF_FONT (3) simogatott sans serif, BOLD_FONT (10) simogatott félkövér.
      • direction paraméter lehet horizontális (balról jobbra) vagy vertikális (az óramutató járásával ellentétes irányban 90 fokos elforgatással)
      • charsize paraméter a karakterek nagyításáért felel
        • Nulla érték csak a simogatott betűtípusokra érvényes, és vagy az alapértelmezett nagyítási faktort (4) használja, vagy a setusercharsize() függvény segítségével megadott más értéket
        • A nullánál nagyobb érték a nagyítási faktort mondja meg, így 1 esetén a 8x8as bittérkép egy 8x8as pixel téglalapnak felel meg, míg 2 esetén egy 16x16os pixel téglalapnak. Ez a szám 10ig mehet.
    • setusercharsize(int multx, int divx, int multy, int divy) – Beállítja az egyedi nagyítási faktort
      • A szélességet és a magasságot beállító faktorok
      • Az alap szélesség skálázva van a multx : divx hányadossal
      • Az alap magasság skálázva van a multy: divy hányadossal

21 of 42

22 of 42

Képernyőrész, illetve ablakkezelés

  • Képernyőrész helyfoglalása
    • imagesize(int left, int top, int right, int bottom) –A kép tárolásához szükséges memória terület mérete
  • Képernyőrész mentése, kirakása
    • getimage(int left, int top, int right, int bottom, void *bitmap) – Lemásolja a képet a képernyőről a memóriába
      • A left, top illetve a right, bottom téglalapnyi képernyő került lementésre
      • A bitmap mutat a memóriaterületre
    • putimage(int left, int top, void *bitmap, int op) – A memóriából kirakja a képet a képernyőre a left, top ponttól kezdve
      • Bitmap mutat a képet tároló memóriaterületre
      • Az op a másolás kombinációs operátorát mondja meg, hogy hogyan kezelje a már meglévő és a memóriából másolandó pixelt
        • Lehetséges értékei: COPY_PUT (0) másolás, XOR_PUT (1) kizáró vagy, OR_PUT (2) vagy, AND_PUT (3) és, illetve NOT_PUT (4) a forrás inverzét másolja

23 of 42

  • Nézetablak létrehozás + vágás
    • setviewport(int left, int top, int right, int bottom, int clip) – Adott átlóval megadott téglalap alakú nézetablak létrehozása
      • A kurzort a nézetablak 0,0 koordinátájába rakja
      • clip paraméter megadja, hogy a nézetablakon túlnyúló alakzatok le legyenek-e vágva
  • Nézetablak törlése háttérszínre
    • clearviewport() – Kitörli a nézetablakot, és visszarakja a kurzort a 0,0 pozícióba

24 of 42

Lapozás

  • Aktív lap kijelölése
    • Setactivepage(int page) – A megadott azonosítójú lap lesz az aktív lap, amelyre rajzolunk
      • Ez nem feltétlenül a látható lap
  • Látható lap kijelölése
    • Setvisualpage(int page) – A megadott azonosítójú lap lesz a látható lap
  • Képernyő törlése
    • Cleardevice() - A háttérszínnel kitölti a képernyőt, és a kurzort a 0,0 pozícióba mozgatja

25 of 42

Színkezelés

  • setbkcolor(int color) – A BGI színek egyikét beállítja háttérszínként
  • setcolor(int color) – A BGI színek egyikét állítja be az aktuális színnek

26 of 42

Hibakezelés

  • Graphresult() – Visszaadja az utolsó hibát dobó grafikai művelet hibakódját, és visszaállítja a hibaszintet grOk-ra
    • Néhány lehetséges hiba:
      • grOk (0)– Nincs hiba ☺
      • grFileNotFound (-3) – Eszközvezérlő fájl nem található
      • grInvalidMode (-10) – Invalid grafikus mód
      • grError (-11) – Grafikus hiba
  • grapherrormsg(int errorcode) - Visszaadja a hibakódhoz tartozó üzenetet

27 of 42

Állapotlekérdezés

Minden beállítható érték lekérdezhető

  • getgraphmode() - Visszaadja grafikus mód kódszámát
  • getmaxmode() – Visszaadja a legnagyobb grafikus mód számát
  • getdrivername() – Visszaadja a grafikus hardver nevét
  • getx(), gety()- Visszaadja a kurzor aktuális pozícióját
  • getmaxx(), getmaxy() – Visszaadja képernyő méretét (felbontását)
  • getcolor() – Visszaadja az aktuális rajzolási színt
  • getpixel(int x, int y) – Visszaadja egy pont színét
  • getmaxcolor() – Visszaadja a legnagyobb használható színkódot
  • getbkcolor() – Visszaadja a háttérszínt

28 of 42

Mintaprogram 1

  • Készítsük el az alábbi ábrához hasonló ábrát rajzoló programot!

29 of 42

#include <stdio.h>

#include <graphics.h>

int main( ) /* a CodeBlocks C program főfüggvénye */

{

int i,R,MaxX,MaxY;

initwindow( 640 , 480 , " WinBGIm Demo " ); /* 1024 , 768 is mûködik */

setbkcolor(LIGHTGRAY); /* háttérszín elõválasztás: világosszürke*/

cleardevice(); /* háttér törlése háttérszínre */

setlinestyle(SOLID_LINE,0,THICK_WIDTH); /* vonalstílus beállítása */

MaxX= getmaxx(); MaxY= getmaxy(); /* ablakméret lekérdezése */

for (i=1; i<=10; i++) {

setcolor(i+5); /* aktuális vonalszín beállítása */

line(0,0,(MaxX / 10)*i, MaxY); /* szakaszrajzolás */

R= (MaxY-10) / (2*i); /* körsugár beállítása */

circle(MaxX-R, MaxY / 2, R); /* körrajzolás */

ellipse(MaxX / 2, MaxY / 8, 0, 360, MaxX / (4*i), MaxY / 8); /* ellipszis rajzolás */ }

while( !kbhit() ); /* várakozás billentyűlenyomásig */

closegraph( ); /* grafikus üzemmód/ablak bezárása */

return( 0 );

}

30 of 42

A CodeBlocks fejlesztőkörnyezetben futtatott program képe

Hogy oldjuk meg, hogy a háttérszínt ne vegye fel?

if(i+5 == getbkcolor()){

if(getbkcolor()==BLACK){

setcolor(WHITE);

}else{

setcolor(BLACK);}

}else{

setcolor(i+5); /* aktuális vonalszín beállítása */

}

31 of 42

Mintaprogram 2

  • Készítsük el az alábbi ábrához hasonló ábrát rajzoló programot!

32 of 42

int smile(){

int cx,cy;

initwindow( 640 , 480 , " Smile" );

cx = getmaxx()/2;

cy = getmaxy()/2;

setfillstyle(1,YELLOW);

fillellipse(cx-200,cy-40,80,80);

setcolor(BLACK);

setfillstyle(1,BLACK);

fillellipse(cx-230,cy-60,8,12);

fillellipse(cx-170,cy-60,8,12);

arc(cx-200,cy-30,200,340,30);

setcolor(CYAN);

setfillstyle(1,CYAN);

pieslice(cx,cy-40,0,180,50);

setfillstyle(1,BLUE);

sector(cx, cy-40, 180,360,50,80);

setcolor(LIGHTGREEN);

setfillstyle(SLASH_FILL,LIGHTGREEN);

bar(cx+120,cy-90,cx+260,cy+50);

setcolor(WHITE);

settextstyle(3,0,3);

outtextxy(cx-200,cy+100,"Sziasztok");

getch();

closegraph(CURRENT_WINDOW);

return 0;

}

33 of 42

Síkbeli transzformációk

34 of 42

Leképezés a Világ-koordinátarendszerről a Képernyő-koordinátarendszerre

  • Az ábrázolandó fizikai jelenségek, geometriai alakzatok általában a jelenségek leírására használt Világ-koordinátarendszerben állnak rendelkezésre, mely ritkán esik egybe a Képernyő-koordinátarendszerrel
  • Ezért egy leképezést kell végeznünk a Világ-koordinátarendszerről a Képernyő-koordinátarendszerre
    • Megadja a Világ-koordinátarendszer-beli (x,y) koordináták Képernyő-koordinátarendszer-beli megfelelőjét (XK, YK)

35 of 42

Lx = getmaxx()/(x2-x1)

Ly = getmaxy()/(y2-y1)

A képernyő-koordináták:

XK = Lx*(x-x1)

YK = getmaxy()-Ly*(y-y1) = Ly*(y2-y)

36 of 42

Ponttranszformációk a Világ-koordinátarendszerben

  • Az ábrázolandó fizikai jelenségek gyakran igénylik az alakzatok mozgásának leírását
  • Ezt célszerűen a Világ-koordinátarendszerben végezhetjük el az alakzatok jellemző pontjainak (például egy háromszög csúcspontjai) transzformálásával
    • Eltolással, nagyítással, elforgatással
  • Mindegyik síkbeli transzformáció leírható egy 3x3as mátrixszal
  • Az egymást követő transzformációs lépések mátrixainak összeszorzásával egyetlen mátrix formájában megkapjuk az összetett transzformáció leírását.
  • Egy pont transzformáltját megkapjuk, ha a mátrixot a pont helyvektorával megszorozzuk.

37 of 42

Eltolás (Transzláció)

  • Megadása transzformációs mátrixszal

r1 = MT * r0

A transzformációk mátrixszal való megadásának előnye az egymást követő transzformációk egyesített kezelésének egyszerűsége.

38 of 42

Nagyítás, kicsinyítés (Zoom-olás) az origóra vonatkozóan

  • Megadása transzformációs mátrixszal

r1 = MZ * r0

  • Aránytartó nagyítás esetén kx = ky.
  • A nagyítás, ill. a kicsinyítés megfelel ugyanazon koordinátatengelyeken más tengelybeosztás alkalmazásának.

39 of 42

Elforgatás az origó körül (Rotáció)

  • Megadása transzformációs mátrixszal

r1 = MR * r0

40 of 42

Példa�Egy háromszög elforgatása adott pont körül adott szöggel

Forgassuk el a C(7,9) pont körül 90 fokkal a (14,4),

(19,5) és (13,11) koordinátájú csúcsokkal adott

háromszöget!

  1. lépés: Áttranszformálás a C origójú K1 koordinátarendszerbe. (Eltolás)

A transzformáció mátrixa:

41 of 42

2. lépés: Áttranszformálás a 90 fokkal elforgatott K2 koordinátarendszerbe. (Elforgatás)

A transzformáció mátrixa:

3. lépés: Áttranszformálás a K2 koordináta-rendszerből a K3 koordinátarendszerbe. (Eltolás)

A transzformáció mátrixa:

42 of 42

  • A transzformációsorozatot leíró mátrix az elemi transzformációs mátrixok szorzataként adódik

  • Pl. a háromszög (13,11) koordinátájú csúcspontja a három transzformációs lépés után az

vektor által kijelölt (5,15) pontba kerül.