Hlavní navigace

2D grafika s využitím knihovny OpenVG (nejenom) na Raspberry Pi: cesty

21. 6. 2016
Doba čtení: 40 minut

Sdílet

Ve čtvrté části článku o grafické knihovně OpenVG si na několika demonstračních příkladech ukážeme, jak je možné vykreslit složitější dvourozměrné objekty s využitím takzvaných „cest“.

Obsah

1. Práce s cestami v knihovně OpenVG

2. Základní funkce určené pro práci s cestami

3. Funkce vgCreatePath

4. Funkce vgDestroyPath

5. Funkce vgClearPath

6. Funkce vgDrawPath

7. Funkce vgAppendPathData

8. První demonstrační příklad (šestý v celkovém pořadí): vykreslení cesty obsahující jediný segment – úsečku

9. Druhý demonstrační příklad (sedmý v celkovém pořadí): vykreslení uzavřené cesty složené z úseček

10. Třetí demonstrační příklad (osmý v celkovém pořadí): použití příkazů pro vykreslení vodorovných a svislých úseček

11. Čtvrtý demonstrační příklad (devátý v celkovém pořadí): vykreslení Bézierovy křivky

12. Vysokoúrovňové funkce vguLine, vguRect, vguRoundRect a vguPolygon

13. Repositář s demonstračními příklady

14. Odkazy na Internetu

1. Práce s cestami v knihovně OpenVG

V předchozí části článku o grafické knihovně OpenVG jsme si vysvětlili koncept takzvaných cest (paths), protože právě s využitím cest jsou v této knihovně vykreslovány prakticky všechny složitější dvourozměrné objekty, ať již se jedná o objekty otevřené (úsečky, lomené čáry – polyčáry, oblouky, křivky) či objekty uzavřené (kruhy, vyplněné mnohoúhelníky apod.). Připomeňme si, že každá cesta se skládá z prakticky libovolného množství segmentů (segments), přičemž je zajímavé a pro některé účely i velmi důležité, že jednotlivé segmenty na sebe nutně nemusí graficky navazovat, ale mohou být mezi nimi mezery. Minule jsme si taktéž řekli, že použití konceptu cest není v oblasti 2D grafiky samozřejmě nic nového, protože jsme se s nimi mohli setkat například v PostScriptu či v grafickém formátu SVG (PostScript lze přitom podle jeho konkrétního způsobu použití chápat jako souborový formát, programovací jazyk a současně i renderovací/vykreslovací knihovnu).

2. Základní funkce určené pro práci s cestami

Pro práci s cestami je v grafické knihovně OpenVG připraveno několik funkcí, ovšem pro začátek si vystačíme s pouhými pěti funkcemi, jejichž jména a stručný popis je vypsán v následující tabulce:

# Funkce Stručný popis funkce
1 vgCreatePath() vytvoření datové struktury obsahující (prozatím) prázdnou cestu
2 vgDestroyPath() odstranění cesty z aktuálního kontextu a uvolnění operační paměti
3 vgAppendPathData() přidání dalších segmentů do existující cesty (původně je cesta bez segmentů)
4 vgClearPath() odstranění všech segmentů z existující cesty (lze použít i pro právě vytvořenou cestu bez segmentů)
5 vgDrawPath() vykreslení cesty s využitím aktuálního kontextu a tedy i nastaveného stylu vykreslování

Můžeme se však setkat i s dalšími funkcemi, které souvisí s cestami, například:

# Funkce Stručný popis funkce
1 vgGetPathCapabilities() získání aktuálního nastavení parametrů cesty
2 vgRemovePathCapabilities() odstranění některého nastavení cesty (zadává se bitovým polem)
3 vgAppendPath() spojení dvou cest do cesty jediné
4 vgTransformPath() aplikace lineární transformace na vybranou cestu (posun, změna měřítka, …)
5 vgPathLength() výpočet délky cesty
6 vgPathBounds() výpočet obalového obdélníku pro zadanou cestu

Další zajímavou (ale ne vždy intuitivně použitelnou) funkcí je vgInterpolatePath, kterou si popíšeme příště:

VGboolean vgInterpolatePath(
    VGPath    dstPath,
    VGPath    startPath,
    VGPath    endPath,
    VGfloat   amount)

3. Funkce vgCreatePath

Z předchozí kapitoly již víme, že se prázdná cesta vytváří s využitím funkce vgCreatePath(). Tato funkce má následující hlavičku:

VGPath vgCreatePath(
    VGint          pathFormat,
    VGPathDatatype datatype,
    VGfloat        scale,
    VGfloat        bias,
    VGint          segmentCapacityHint,
    VGint          coordCapacityHint,
    VGbitfield     capabilities);

Funkce vgCreatePath sice vyžaduje předání sedmi parametrů, ale ve skutečnosti se do mnoha parametrů většinou předává stále stejná hodnota. To je případ prvního parametru, který bývá nastaven na konstantu se jménem VG_PATH_FORMAT_STANDARD. Ve druhém parametru se specifikuje formát hodnot použitých pro uložení vrcholů jednotlivých segmentů (určuje se tím způsob zpracování pole s vrcholy segmentů):

datatype Význam
VG_PATH_DATATYPE_S8 osmibitové hodnoty se znaménkem
VG_PATH_DATATYPE_S16 16bitové hodnoty se znaménkem
VG_PATH_DATATYPE_S32 32bitové hodnoty se znaménkem
VG_PATH_DATATYPE_F formát s plovoucí řádovou čárkou podle IEEE 754 (float)

Následuje dvojice parametrů scale a bias, které slouží pro jednoduchou transformaci všech souřadnic podle vzorce scale*x+bias. Typicky se předává scale=1.0 a bias=0.0, pokud je ovšem vstupní formát souřadnic nějak specifický, můžete hodnoty těchto parametrů pochopitelně změnit, a to právě na tomto jediném místě (nemusí se zdlouhavě přepočítávat jednotlivé souřadnice). Parametry segmentCapacityHint a coordCapacityHint slouží pouze pro optimalizaci alokátoru paměti – předává se zde předpokládaná velikost cesty (počet segmentů, celkový počet souřadnic). Pokud tyto hodnoty dopředu neznáte, nebo je nechcete počítat, předává se 0 značící unknown.

Poslední formát určuje možnosti a povolené operace, které budeme chtít s cestou provádět. Jedná se o celočíselnou konstantu získanou operací OR či + nad následujícími konstantami:

VG_PATH_CAPABILITY_APPEND_FROM
VG_PATH_CAPABILITY_APPEND_TO
VG_PATH_CAPABILITY_MODIFY
VG_PATH_CAPABILITY_TRANSFORM_FROM
VG_PATH_CAPABILITY_TRANSFORM_TO
VG_PATH_CAPABILITY_INTERPOLATE_FROM
VG_PATH_CAPABILITY_INTERPOLATE_TO
VG_PATH_CAPABILITY_PATH_LENGTH
VG_PATH_CAPABILITY_POINT_ALONG_PATH
VG_PATH_CAPABILITY_TANGENT_ALONG_PATH
VG_PATH_CAPABILITY_PATH_BOUNDS
VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS
VG_PATH_CAPABILITY_ALL

Důležitá je především konstanta nazvaná VG_PATH_CAPABILITY_APPEND_TO, protože právě ta povoluje použití funkce vgAppendPathData() popsané v dalších kapitolách.

4. Funkce vgDestroyPath

Druhou důležitou funkcí při práci s cestami je funkce nazvaná vgDestroyPath(). Tato funkce, která je vlastně opakem výše popsané funkce vgCreatePath(), cestu z aktuálního kontextu odstraní a uvolní paměť (buď na grafickém akcelerátoru nebo „obyčejnou“ operační paměť). V aplikacích je vhodné tuto funkci zavolat co nejdříve a nenechávat v paměti uloženo zbytečně velké množství cest (paměť pro cesty totiž může být alokována v paměťovém prostoru grafického akcelerátoru, záleží ovšem na konkrétní implementaci):

void vgDestroyPath(
    VGPath path);

Povšimněte si návratového typu, který naznačuje, že tato funkce nevrací žádnou hodnotu, ovšem případná chyba může být nahlášena: VG_BAD_HANDLE_ERROR.

5. Funkce vgClearPath

Segmenty se z vybrané cesty dají kdykoli odstranit s využitím funkce vgClearPath(), jejíž hlavička je velmi jednoduchá:

void vgClearPath(
    VGPath     path,
    VGbitfield capabilities);

Tuto funkci je možné zavolat i v případě, že se jedná o novou cestu bez segmentů.

U hlavičky této funkce si povšimněte toho, že se kromě odstranění všech segmentů, z nichž se cesta skládá, mohou nastavit nové vlastnosti cesty, a to díky druhému parametru pojmenovanému capabilities.

Tato funkce má význam ve chvíli, kdy je zapotřebí vykreslit větší množství cest. V takovém okamžiku je neustálé používání dvojice funkcí vgCreatePath() a vgDestroyPath() neefektivní; lepší je jednu cestu vykreslit, smazat její data pomocí vgClearPath() a nadefinovat cestu novou.

6. Funkce vgDrawPath

Čtvrtá funkce důležitá při práci s cestami se jmenuje vgDrawPath a její hlavička vypadá následovně:

void vgDrawPath(
    VGPath     path,
    VGbitfield paintModes)

Prvním parametrem této funkce je reference na již vytvořenou a inicializovanou cestu (ideálně obsahující nějaké segmenty, které se mají vykreslit, ve skutečnosti to však není nutné – vykreslit lze i prázdnou cestu, ovšem s pochopitelným výsledkem). Zajímavý je druhý parametr, kterým se určuje styl vykreslení cesty:

paintModes Operace
VG_STROKE_PATH vykreslí se obrys cesty
VG_FILL_PATH vyplní se vnitřek cesty
VG_STROKE_PATH | VG_FILL_PATH kombinace vykreslení a současného vyplnění

Poznámka: styl vykreslení a styl výplně se může odlišovat, což znamená, že obrys může mít jinou barvu, než samotná výplň.

7. Funkce vgAppendPathData

Poslední důležitou funkcí, s níž se dnes musíme seznámit, je funkce nazvaná vgAppendPathData. Tato funkce slouží k připojení dalších segmentů ke specifikované cestě. Funkce vgAppendPathData má následující hlavičku:

void vgAppendPathData(
    VGPath         dstPath,
    VGint          numSeg,
    const VGubyte *pathSeg,
    const void    *pathData)

Význam prvního argumentu je zřejmý – jde o referenci na vytvořenou cestu, k níž se mají připojit další segmenty. Ve druhém parametru je předán počet připojovaných segmentů, protože ze samotných dat není možné tuto informaci zjistit. Zajímavý je třetí argument. Jedná se o pole obsahující jednotlivé příkazy pro tvorbu segmentů (jejich význam jsme si vysvětlili minule):

# Symbolická konstanta Hodnota Význam
1 VG_CLOSE_PATH 0 uzavření cesty
2 VG_MOVE_TO 2 přesun aktivního bodu bez kreslení
3 VG_LINE_TO 4 lineární segment (úsečka)
4 VG_HLINE_TO 6 horizontální úsečka
5 VG_VLINE_TO 8 vertikální úsečka
6 VG_QUAD_TO 10 kvadratická Bézierova křivka
7 VG_CUBIC_TO 12 kubická Bézierova křivka
8 VG_SQUAD_TO 14 segment s G1 spojitostí tvořený kvadratickou křivkou
9 VG_SCUBIC_TO 16 segment s G1 spojitostí tvořený kubickou křivkou
10 VG_SCCWARC_TO 18 kratší segment tvořený eliptickým obloukem
11 VG_SCWARC_TO 20 kratší segment tvořený eliptickým obloukem
12 VG_LCCWARC_TO 22 delší segment tvořený eliptickým obloukem
13 VG_LCWARC_TO 24 delší segment tvořený eliptickým obloukem

Každý příkaz může používat absolutní souřadnice (vztažené vůči počátku souřadného systému) či souřadnice relativní (vztažené vůči poslední zadané či vypočtené souřadnici). Rozhodnutí o použití relativních či absolutních souřadnicích se provádí na základě nejnižšího bitu příkazu, který může nabývat hodnot:

# Symbolická konstanta Hodnota Význam
1 VG_ABSOLUTE 0 příznak použití absolutních souřadnic
2 VG_RELATIVE 1 příznak použití relativních souřadnic

Výsledkem jsou následující kombinace:

# Symbolická konstanta Vypočteno z
1 VG_MOVE_TO_ABS VG_MOVE_TO | VG_ABSOLUTE
2 VG_MOVE_TO_REL VG_MOVE_TO | VG_RELATIVE
3 VG_LINE_TO_ABS VG_LINE_TO | VG_ABSOLUTE
4 VG_LINE_TO_REL VG_LINE_TO | VG_RELATIVE
5 VG_HLINE_TO_ABS VG_HLINE_TO | VG_ABSOLUTE
6 VG_HLINE_TO_REL VG_HLINE_TO | VG_RELATIVE
7 VG_VLINE_TO_ABS VG_VLINE_TO | VG_ABSOLUTE
8 VG_VLINE_TO_REL VG_VLINE_TO | VG_RELATIVE
9 VG_QUAD_TO_ABS VG_QUAD_TO | VG_ABSOLUTE
10 VG_QUAD_TO_REL VG_QUAD_TO | VG_RELATIVE
11 VG_CUBIC_TO_ABS VG_CUBIC_TO | VG_ABSOLUTE
12 VG_CUBIC_TO_REL VG_CUBIC_TO | VG_RELATIVE
13 VG_SQUAD_TO_ABS VG_SQUAD_TO | VG_ABSOLUTE
14 VG_SQUAD_TO_REL VG_SQUAD_TO | VG_RELATIVE
15 VG_SCUBIC_TO_ABS VG_SCUBIC_TO | VG_ABSOLUTE
16 VG_SCUBIC_TO_REL VG_SCUBIC_TO | VG_RELATIVE
17 VG_SCCWARC_TO_ABS VG_SCCWARC_TO | VG_ABSOLUTE
18 VG_SCCWARC_TO_REL VG_SCCWARC_TO | VG_RELATIVE
19 VG_SCWARC_TO_ABS VG_SCWARC_TO | VG_ABSOLUTE
20 VG_SCWARC_TO_REL VG_SCWARC_TO | VG_RELATIVE
21 VG_LCCWARC_TO_ABS VG_LCCWARC_TO | VG_ABSOLUTE
22 VG_LCCWARC_TO_REL VG_LCCWARC_TO | VG_RELATIVE
23 VG_LCWARC_TO_ABS VG_LCWARC_TO | VG_ABSOLUTE
24 VG_LCWARC_TO_REL VG_LCWARC_TO | VG_RELATIVE

Poslední parametr obsahuje pole souřadnic pro jednotlivé segmenty. Formát souřadnic (celé číslo, float…) byl určen již při vytváření cesty funkcí vgCreatePath(). Souřadnice jsou v poli uloženy za sebou: x1, y1, x2, y2, …

8. První demonstrační příklad (šestý v celkovém pořadí): vykreslení cesty obsahující jediný segment – úsečku

Všech pět funkcí důležitých pro tvorbu cest jsme si již popsali, takže nám již zbývá si ukázat jejich použití v demonstračních příkladech. Dnešní první demonstrační příklad (který je celkově již osmým příkladem na OpenVG) je sice poměrně dlouhý, ovšem jeho základem je vykreslení jednoduché úsečky. Po inicializaci EGL apod. (viz též předchozí části tohoto seriálu) se zavolá funkce draw, která:

  1. Vymaže obrazovku černou barvou
  2. Nastaví barvu štětce pro vykreslovanou úsečku
  3. Nastaví šířku štětce i styl zakončení (zde konkrétně kulaté konce)
  4. Vytvoří cestu
  5. Přidá do cesty segment dvěma příkazy: VG_MOVE_TO_ABS, VG_LINE_TO_REL
  6. Cestu zruší
  7. Prohodí přední a zadní buffer

Podívejme se na kód této funkce:

/*
 * Vykresleni usecky sestrojene pomoci "cesty" (path).
 */
void draw(EGL_STATE_T *state)
{
    /* vymazani pozadi cernou barvou */
    VGfloat color1[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    vgSetfv(VG_CLEAR_COLOR, 4, color1);
    vgClear(0, 0, state->window_width, state->window_height);
 
    /* barva stetce vykreslovane usecky */
    VGfloat color2[4] = {0.75f, 0.25f, 0.25f, 1.0f};
    VGPaint strokePaint = vgCreatePaint();
    vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
    vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
    vgSetPaint(strokePaint, VG_STROKE_PATH);
    vgDestroyPaint(strokePaint);
 
    /* sirka a styl stetce pouziteho pro kresbu usecky */
    vgSetf(VG_STROKE_LINE_WIDTH, 10);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
 
    /* vykresleni prvni usecky */
    VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
    /* deklarace useckoveho segmentu */
    VGubyte commands[] = {VG_MOVE_TO_ABS, VG_LINE_TO_REL};
    VGfloat coordinates[] = {state->window_width >> 1, state->window_height >> 1, 100, 50};
 
    /* pridani useckoveho segmentu */
    vgAppendPathData(path, 2, commands, coordinates);
 
    /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
    vgDrawPath(path, VG_STROKE_PATH);
    vgDestroyPath(path);
 
    /* prohozeni predniho a zadniho bufferu (pokud je to zapotrebi) */
    eglSwapBuffers(state->display, state->surface);
}

Úplný zdrojový kód demonstračního příkladu je vypsán pod tímto odstavcem:

/* OpenVG (nejenom) na Raspberry Pi - sesty demonstracni priklad */
/* Vykresleni usecky s vyuzitim jednoho "segmentu" cesty. */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
    EGLint     num_config;
    EGLConfig  config;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    static EGL_DISPMANX_WINDOW_T nativewindow;
 
    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;
 
    static VC_DISPMANX_ALPHA_T alpha = {
        DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
        255, 0
    };
 
    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_NONE
    };
 
    /* vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
 
    /* navazani EGL na OpenVG */
    eglBindAPI(EGL_OPENVG_API);
 
    /* ziskani konfigurace framebufferu */
    result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL choose config failed");
        exit(1);
    }
 
    /* vytvoreni kontextu */
    state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->context == EGL_NO_CONTEXT) {
        puts("EGL create context failed");
        exit(1);
    }
 
    /* vytvoreni surface */
    int32_t success = graphics_get_display_size(0, &state->screen_width, &state->screen_height);
 
    /* kontrola, zda operace probehla v poradku */
    if (success < 0) {
        puts("get display size failed");
        exit(1);
    }
 
    if ((state->window_width == 0) || (state->window_width > state->screen_width))
        state->window_width = state->screen_width;
    if ((state->window_height == 0) || (state->window_height > state->screen_height))
        state->window_height = state->screen_height;
 
    dispman_display = vc_dispmanx_display_open(0);
    dispman_update = vc_dispmanx_update_start(0);
 
    dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer */ , &dst_rect, 0 /*src */ ,
                          &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp */ ,
                          0 /*transform */ );
 
    nativewindow.element = dispman_element;
    nativewindow.width = state->window_width;
    nativewindow.height = state->window_height;
    vc_dispmanx_update_submit_sync(dispman_update);
 
    /* vytvoreni surface */
    state->surface = eglCreateWindowSurface(state->display, config, &nativewindow, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->surface == EGL_NO_SURFACE) {
        puts("no surface!");
        exit(1);
    }
 
    /* nastaveni chovani bufferu pri operaci swap */
    result = eglSurfaceAttrib(state->display, state->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not set surface attributes!");
        exit(1);
    }
 
    /* propojeni kontextu se surface */
    result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not connect context with the surface!");
        exit(1);
    }
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vykresleni usecky sestrojene pomoci "cesty" (path).
 */
void draw(EGL_STATE_T *state)
{
    /* vymazani pozadi cernou barvou */
    VGfloat color1[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    vgSetfv(VG_CLEAR_COLOR, 4, color1);
    vgClear(0, 0, state->window_width, state->window_height);
 
    /* barva stetce vykreslovane usecky */
    VGfloat color2[4] = {0.75f, 0.25f, 0.25f, 1.0f};
    VGPaint strokePaint = vgCreatePaint();
    vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
    vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
    vgSetPaint(strokePaint, VG_STROKE_PATH);
    vgDestroyPaint(strokePaint);
 
    /* sirka a styl stetce pouziteho pro kresbu usecky */
    vgSetf(VG_STROKE_LINE_WIDTH, 10);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
 
    /* vykresleni prvni usecky */
    VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
    /* deklarace useckoveho segmentu */
    VGubyte commands[] = {VG_MOVE_TO_ABS, VG_LINE_TO_REL};
    VGfloat coordinates[] = {state->window_width >> 1, state->window_height >> 1, 100, 50};
 
    /* pridani useckoveho segmentu */
    vgAppendPathData(path, 2, commands, coordinates);
 
    /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
    vgDrawPath(path, VG_STROKE_PATH);
    vgDestroyPath(path);
 
    /* prohozeni predniho a zadniho bufferu (pokud je to zapotrebi) */
    eglSwapBuffers(state->display, state->surface);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    draw(&egl_state);
    getchar();
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Soubor Makefile určený pro překlad tohoto příkladu:

# Makefile pro preklad sesteho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example6
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
    rm -f *.o
    rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
    $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

9. Druhý demonstrační příklad (sedmý v celkovém pořadí): vykreslení uzavřené cesty složené z úseček

V dnešním druhém demonstračním příkladu je ukázána tvorba uzavřené cesty. Okolo celé obrazovky je vykreslen široký žlutý okraj se zkosenými hranami. Nastavení stylu vykreslování je provedeno následovně:

/* barva stetce druhe cesty */
VGfloat color2[4] = {0.75f, 0.75f, 0.25f, 1.0f};
VGPaint strokePaint = vgCreatePaint();
vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
vgSetPaint(strokePaint, VG_STROKE_PATH);
vgDestroyPaint(strokePaint);
 
/* sirka a styl stetce druhe cesty */
vgSetf(VG_STROKE_LINE_WIDTH, 20);
vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);    /* siroke stopy konci presne na stanovenych souradnicich */
vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); /* vnejsi okraje spoju jsou "oseknute" */

Pro uzavřenou cestu bylo zvoleno pět příkazů (povšimněte si způsobu uzavření – to je důležité, aby byly správně zkoseny všechny okraje cesty):

/* deklarace useckoveho segmentu */
VGubyte commands[] = {VG_MOVE_TO_ABS,                  /* pocatecni bod */
                      VG_LINE_TO_REL,                  /* prvni usecka (vodorovna) */
                      VG_LINE_TO_REL,                  /* druha usecka (svisla) */
                      VG_LINE_TO_REL,                  /* treti usecka (vodorovna) */
                      VG_CLOSE_PATH};                  /* uzavreni cesty */

se souřadnicemi jednotlivých vrcholů:

VGfloat coordinates[] = {20, 20,                       /* pocatecni bod */
                         state->window_width-40, 0,    /* prvni usecka (vodorovna) */
                         0, state->window_height-40,   /* druha usecka (svisla) */
                         -state->window_width+40, 0};  /* treti usecka (vodorovna) */

Úplný zdrojový kód tohoto příkladu vypadá následovně:

/* OpenVG (nejenom) na Raspberry Pi - sedmy demonstracni priklad */
/* Vykresleni uzavreneho segmentu slozeneho z usecek. */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
    EGLint     num_config;
    EGLConfig  config;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    static EGL_DISPMANX_WINDOW_T nativewindow;
 
    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;
 
    static VC_DISPMANX_ALPHA_T alpha = {
        DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
        255, 0
    };
 
    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_NONE
    };
 
    /* vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
 
    /* navazani EGL na OpenVG */
    eglBindAPI(EGL_OPENVG_API);
 
    /* ziskani konfigurace framebufferu */
    result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL choose config failed");
        exit(1);
    }
 
    /* vytvoreni kontextu */
    state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->context == EGL_NO_CONTEXT) {
        puts("EGL create context failed");
        exit(1);
    }
 
    /* vytvoreni surface */
    int32_t success = graphics_get_display_size(0, &state->screen_width, &state->screen_height);
 
    /* kontrola, zda operace probehla v poradku */
    if (success < 0) {
        puts("get display size failed");
        exit(1);
    }
 
    if ((state->window_width == 0) || (state->window_width > state->screen_width))
        state->window_width = state->screen_width;
    if ((state->window_height == 0) || (state->window_height > state->screen_height))
        state->window_height = state->screen_height;
 
    dispman_display = vc_dispmanx_display_open(0);
    dispman_update = vc_dispmanx_update_start(0);
 
    dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer */ , &dst_rect, 0 /*src */ ,
                          &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp */ ,
                          0 /*transform */ );
 
    nativewindow.element = dispman_element;
    nativewindow.width = state->window_width;
    nativewindow.height = state->window_height;
    vc_dispmanx_update_submit_sync(dispman_update);
 
    /* vytvoreni surface */
    state->surface = eglCreateWindowSurface(state->display, config, &nativewindow, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->surface == EGL_NO_SURFACE) {
        puts("no surface!");
        exit(1);
    }
 
    /* nastaveni chovani bufferu pri operaci swap */
    result = eglSurfaceAttrib(state->display, state->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not set surface attributes!");
        exit(1);
    }
 
    /* propojeni kontextu se surface */
    result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not connect context with the surface!");
        exit(1);
    }
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vykresleni nekolika usecek.
 */
void draw(EGL_STATE_T *state)
{
    /* vymazani pozadi cernou barvou */
    VGfloat color1[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    vgSetfv(VG_CLEAR_COLOR, 4, color1);
    vgClear(0, 0, state->window_width, state->window_height);
 
    /* barva stetce prvni cesty */
    {
        VGfloat color2[4] = {0.75f, 0.25f, 0.25f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    /* sirka a styl stetce */
    vgSetf(VG_STROKE_LINE_WIDTH, 10);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
 
    {
        /* vykresleni prvni cesty */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,        /* pocatecni bod */
                              VG_LINE_TO_REL};       /* vodorovna usecka */
 
        VGfloat coordinates[] = {(state->window_width >> 1) - 100, state->window_height >> 1, 200, 0};
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 2, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* barva stetce druhe cesty */
    {
        VGfloat color2[4] = {0.75f, 0.75f, 0.25f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    /* sirka a styl stetce druhe cesty */
    vgSetf(VG_STROKE_LINE_WIDTH, 20);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);    /* siroke stopy konci presne na stanovenych souradnicich */
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); /* vnejsi okraje spoju jsou "oseknute" */
 
    {
        /* vykresleni polycary */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,                  /* pocatecni bod */
                              VG_LINE_TO_REL,                  /* prvni usecka (vodorovna) */
                              VG_LINE_TO_REL,                  /* druha usecka (svisla) */
                              VG_LINE_TO_REL,                  /* treti usecka (vodorovna) */
                              VG_CLOSE_PATH};                  /* uzavreni cesty */
 
        VGfloat coordinates[] = {20, 20,                       /* pocatecni bod */
                                 state->window_width-40, 0,    /* prvni usecka (vodorovna) */
                                 0, state->window_height-40,   /* druha usecka (svisla) */
                                 -state->window_width+40, 0};  /* treti usecka (vodorovna) */
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 5, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* prohozeni predniho a zadniho bufferu (pokud je to zapotrebi) */
    eglSwapBuffers(state->display, state->surface);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    draw(&egl_state);
    getchar();
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Soubor Makefile určený pro překlad tohoto příkladu se vlastně nijak neliší od předchozího Makefile:

# Makefile pro preklad sedmeho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example7
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
    rm -f *.o
    rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
    $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

10. Třetí demonstrační příklad (osmý v celkovém pořadí): použití příkazů pro vykreslení vodorovných a svislých úseček

Pokud si ještě pamatujete, že jsme v třetí části tohoto seriálku hovořili o možnosti jednoduché kresby vodorovných a svislých úseček, pak vás nepřekvapí, že příkazy z předchozího příkladu:

/* deklarace useckoveho segmentu */
VGubyte commands[] = {VG_MOVE_TO_ABS,                  /* pocatecni bod */
                      VG_LINE_TO_REL,                  /* prvni usecka (vodorovna) */
                      VG_LINE_TO_REL,                  /* druha usecka (svisla) */
                      VG_LINE_TO_REL,                  /* treti usecka (vodorovna) */
                      VG_CLOSE_PATH};                  /* uzavreni cesty */

je možné převést na příkazy pro vykreslení vodorovných čar (horizontal line) a čar vertikálních (vertical line):

/* deklarace useckoveho segmentu */
VGubyte commands[] = {VG_MOVE_TO_ABS,                  /* pocatecni bod */
                      VG_HLINE_TO_REL,                 /* prvni usecka (vodorovna) */
                      VG_VLINE_TO_REL,                 /* druha usecka (svisla) */
                      VG_HLINE_TO_REL,                 /* treti usecka (vodorovna) */
                      VG_CLOSE_PATH};                  /* uzavreni cesty */

Změní se především pole se souřadnicemi (resp. se toto pole zmenší, což je jeden z účelů použití horizontálních a vertikálních čar, který se projeví zejména u komplikovaných cest). Staré pole:

VGfloat coordinates[] = {20, 20,                       /* pocatecni bod */
                         state->window_width-40, 0,    /* prvni usecka (vodorovna) */
                         0, state->window_height-40,   /* druha usecka (svisla) */
                         -state->window_width+40, 0};  /* treti usecka (vodorovna) */

Nové pole (chybí zde nuly na druhém, třetím i čtvrtém řádku):

VGfloat coordinates[] = {20, 20,                       /* pocatecni bod */
                         state->window_width-40,       /* prvni usecka (vodorovna) */
                         state->window_height-40,      /* druha usecka (svisla) */
                         -state->window_width+40};     /* treti usecka (vodorovna) */

Úplný zdrojový kód tohoto příkladu vypadá následovně:

/* OpenVG (nejenom) na Raspberry Pi - osmy demonstracni priklad */
/* Vykresleni uzavreneho segmentu slozeneho z vodorovnych a svislych usecek. */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
    EGLint     num_config;
    EGLConfig  config;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    static EGL_DISPMANX_WINDOW_T nativewindow;
 
    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;
 
    static VC_DISPMANX_ALPHA_T alpha = {
        DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
        255, 0
    };
 
    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_NONE
    };
 
    /* vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
 
    /* navazani EGL na OpenVG */
    eglBindAPI(EGL_OPENVG_API);
 
    /* ziskani konfigurace framebufferu */
    result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL choose config failed");
        exit(1);
    }
 
    /* vytvoreni kontextu */
    state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->context == EGL_NO_CONTEXT) {
        puts("EGL create context failed");
        exit(1);
    }
 
    /* vytvoreni surface */
    int32_t success = graphics_get_display_size(0, &state->screen_width, &state->screen_height);
 
    /* kontrola, zda operace probehla v poradku */
    if (success < 0) {
        puts("get display size failed");
        exit(1);
    }
 
    if ((state->window_width == 0) || (state->window_width > state->screen_width))
        state->window_width = state->screen_width;
    if ((state->window_height == 0) || (state->window_height > state->screen_height))
        state->window_height = state->screen_height;
 
    dispman_display = vc_dispmanx_display_open(0);
    dispman_update = vc_dispmanx_update_start(0);
 
    dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer */ , &dst_rect, 0 /*src */ ,
                          &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp */ ,
                          0 /*transform */ );
 
    nativewindow.element = dispman_element;
    nativewindow.width = state->window_width;
    nativewindow.height = state->window_height;
    vc_dispmanx_update_submit_sync(dispman_update);
 
    /* vytvoreni surface */
    state->surface = eglCreateWindowSurface(state->display, config, &nativewindow, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->surface == EGL_NO_SURFACE) {
        puts("no surface!");
        exit(1);
    }
 
    /* nastaveni chovani bufferu pri operaci swap */
    result = eglSurfaceAttrib(state->display, state->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not set surface attributes!");
        exit(1);
    }
 
    /* propojeni kontextu se surface */
    result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not connect context with the surface!");
        exit(1);
    }
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vykresleni nekolika usecek.
 */
void draw(EGL_STATE_T *state)
{
    /* vymazani pozadi cernou barvou */
    VGfloat color1[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    vgSetfv(VG_CLEAR_COLOR, 4, color1);
    vgClear(0, 0, state->window_width, state->window_height);
 
    /* barva stetce prvni cesty */
    {
        VGfloat color2[4] = {0.75f, 0.25f, 0.25f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    /* sirka a styl stetce */
    vgSetf(VG_STROKE_LINE_WIDTH, 10);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
 
    {
        /* vykresleni prvni cesty */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,        /* pocatecni bod */
                              VG_HLINE_TO_REL};      /* vodorovna usecka */
 
        VGfloat coordinates[] = {(state->window_width >> 1) - 100, state->window_height >> 1,
                                 200}; /* delka vodorovne usecky */
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 2, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* barva stetce druhe cesty */
    {
        VGfloat color2[4] = {0.75f, 0.75f, 0.25f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    /* sirka a styl stetce druhe cesty */
    vgSetf(VG_STROKE_LINE_WIDTH, 20);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);    /* siroke stopy konci presne na stanovenych souradnicich */
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); /* vnejsi okraje spoju jsou "oseknute" */
 
    {
        /* vykresleni polycary */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,                  /* pocatecni bod */
                              VG_HLINE_TO_REL,                 /* prvni usecka (vodorovna) */
                              VG_VLINE_TO_REL,                 /* druha usecka (svisla) */
                              VG_HLINE_TO_REL,                 /* treti usecka (vodorovna) */
                              VG_CLOSE_PATH};                  /* uzavreni cesty */
 
        VGfloat coordinates[] = {20, 20,                       /* pocatecni bod */
                                 state->window_width-40,       /* prvni usecka (vodorovna) */
                                 state->window_height-40,      /* druha usecka (svisla) */
                                 -state->window_width+40};     /* treti usecka (vodorovna) */
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 5, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* prohozeni predniho a zadniho bufferu (pokud je to zapotrebi) */
    eglSwapBuffers(state->display, state->surface);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    draw(&egl_state);
    getchar();
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Soubor Makefile určený pro překlad tohoto příkladu se opět nijak neliší od předchozího Makefile:

# Makefile pro preklad osmeho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example8
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
    rm -f *.o
    rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
    $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

11. Čtvrtý demonstrační příklad (devátý v celkovém pořadí): vykreslení Bézierovy křivky

Kubické Bézierovy křivky většina uživatelů používajících vektorové grafické editory již velmi dobře zná (ale nalezneme je i v rastrových grafických editorech, například v GIMPu). Připomeňme si tedy, že tyto křivky jsou definovány počátečním bodem, koncovým bodem a dvojicí řídicích bodů. Větší množství řídicích bodů dává uživatelům i větší možnosti tvarování křivky, protože je možné vytvořit i esíčko atd. V knihovně OpenVG se tyto křivky (resp. segmenty složené z kubických Bézierových křivek) specifikují příkazy VG_CUBIC_TO_ABS a VG_CUBIC_TO_REL, přičemž se očekávají tři body (tedy šest souřadnic), protože počáteční bod již známe – je jím dočasný poslední bod aktuálně vytvářené cesty. Pozor je zapotřebí dávat na to, že i relativně zadané souřadnice jsou vždy vztaženy k tomu bodu, kde křivka začíná, nikoli k poslednímu zadanému bodu:

/* deklarace useckoveho segmentu */
VGubyte commands[] = {VG_MOVE_TO_ABS,        /* pocatecni bod */
                      VG_CUBIC_TO_REL};      /* Bezierova kubicka krivka */
 
VGfloat coordinates[] = {(state->window_width >> 1) - 400, state->window_height >> 1,
                         200,  250,
                         400, -250,
                         600,  0};           /* koncovy bod Bezierovy kubicke krivky */

Kromě samotné kubické Bézierovy křivky je do 2D scény vykreslena i polyčára spojující koncové body křivky s jejími řídicími body. Zde jsou samozřejmě relativní souřadnice vztaženy vždy k poslední vykreslené úsečce:

/* deklarace useckoveho segmentu */
VGubyte commands[] = {VG_MOVE_TO_ABS,        /* pocatecni bod */
                      VG_LINE_TO_REL,
                      VG_LINE_TO_REL,
                      VG_LINE_TO_REL};
 
VGfloat coordinates[] = {(state->window_width >> 1) - 400, state->window_height >> 1,
                         200,  250,
                         200, -500,
                         200,  250};

Úplný zdrojový kód tohoto příkladu vypadá takto:

/* OpenVG (nejenom) na Raspberry Pi - devaty demonstracni priklad */
/* Segmenty slozene z Berierovych krivek. */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
    EGLint     num_config;
    EGLConfig  config;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    static EGL_DISPMANX_WINDOW_T nativewindow;
 
    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;
 
    static VC_DISPMANX_ALPHA_T alpha = {
        DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
        255, 0
    };
 
    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_NONE
    };
 
    /* vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
 
    /* navazani EGL na OpenVG */
    eglBindAPI(EGL_OPENVG_API);
 
    /* ziskani konfigurace framebufferu */
    result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL choose config failed");
        exit(1);
    }
 
    /* vytvoreni kontextu */
    state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->context == EGL_NO_CONTEXT) {
        puts("EGL create context failed");
        exit(1);
    }
 
    /* vytvoreni surface */
    int32_t success = graphics_get_display_size(0, &state->screen_width, &state->screen_height);
 
    /* kontrola, zda operace probehla v poradku */
    if (success < 0) {
        puts("get display size failed");
        exit(1);
    }
 
    if ((state->window_width == 0) || (state->window_width > state->screen_width))
        state->window_width = state->screen_width;
    if ((state->window_height == 0) || (state->window_height > state->screen_height))
        state->window_height = state->screen_height;
 
    dispman_display = vc_dispmanx_display_open(0);
    dispman_update = vc_dispmanx_update_start(0);
 
    dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer */ , &dst_rect, 0 /*src */ ,
                          &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp */ ,
                          0 /*transform */ );
 
    nativewindow.element = dispman_element;
    nativewindow.width = state->window_width;
    nativewindow.height = state->window_height;
    vc_dispmanx_update_submit_sync(dispman_update);
 
    /* vytvoreni surface */
    state->surface = eglCreateWindowSurface(state->display, config, &nativewindow, NULL);
 
    /* kontrola, zda operace probehla v poradku */
    if (state->surface == EGL_NO_SURFACE) {
        puts("no surface!");
        exit(1);
    }
 
    /* nastaveni chovani bufferu pri operaci swap */
    result = eglSurfaceAttrib(state->display, state->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not set surface attributes!");
        exit(1);
    }
 
    /* propojeni kontextu se surface */
    result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
 
    /* kontrola, zda operace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("can not connect context with the surface!");
        exit(1);
    }
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vykresleni nekolika usecek a Bezierovych krivek.
 */
void draw(EGL_STATE_T *state)
{
    /* vymazani pozadi cernou barvou */
    VGfloat color1[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    vgSetfv(VG_CLEAR_COLOR, 4, color1);
    vgClear(0, 0, state->window_width, state->window_height);
 
    /* sirka a styl stetce */
    vgSetf(VG_STROKE_LINE_WIDTH, 1);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
 
    /* barva stetce prvni polycary */
    {
        VGfloat color2[4] = {0.25f, 0.25f, 0.75f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    {
        /* vykresleni druhe cesty slozene z usecek */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,        /* pocatecni bod */
                              VG_LINE_TO_REL,
                              VG_LINE_TO_REL,
                              VG_LINE_TO_REL};
 
        VGfloat coordinates[] = {(state->window_width >> 1) - 400, state->window_height >> 1,
                                 200,  250,
                                 200, -500,
                                 200,  250};
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 4, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* sirka a styl stetce */
    vgSetf(VG_STROKE_LINE_WIDTH, 3);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
 
    /* barva stetce Bezierovych krivek */
    {
        VGfloat color2[4] = {0.75f, 0.25f, 0.25f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    {
        /* vykresleni prvni cesty slozene z Bezierovych krivek */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,        /* pocatecni bod */
                              VG_CUBIC_TO_REL};      /* Bezierova kubicka krivka */
 
        VGfloat coordinates[] = {(state->window_width >> 1) - 400, state->window_height >> 1,
                                 200,  250,
                                 400, -250,
                                 600,  0};           /* koncovy bod Bezierovy kubicke krivky */
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 2, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* barva stetce polycary */
    {
        VGfloat color2[4] = {0.75f, 0.75f, 0.25f, 1.0f};
        VGPaint strokePaint = vgCreatePaint();
        vgSetParameteri(strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameterfv(strokePaint, VG_PAINT_COLOR, 4, color2);
        vgSetPaint(strokePaint, VG_STROKE_PATH);
        vgDestroyPaint(strokePaint);
    }
 
    /* sirka a styl stetce */
    vgSetf(VG_STROKE_LINE_WIDTH, 20);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);    /* siroke stopy konci presne na stanovenych souradnicich */
    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); /* vnejsi okraje spoju jsou "oseknute" */
 
    {
        /* vykresleni polycary */
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
 
        /* deklarace useckoveho segmentu */
        VGubyte commands[] = {VG_MOVE_TO_ABS,                  /* pocatecni bod */
                              VG_LINE_TO_REL,                  /* prvni usecka (vodorovna) */
                              VG_LINE_TO_REL,                  /* druha usecka (svisla) */
                              VG_LINE_TO_REL,                  /* treti usecka (vodorovna) */
                              VG_CLOSE_PATH};                  /* uzavreni cesty */
 
        VGfloat coordinates[] = {20, 20,                       /* pocatecni bod */
                                 state->window_width-40, 0,    /* prvni usecka (vodorovna) */
                                 0, state->window_height-40,   /* druha usecka (svisla) */
                                 -state->window_width+40, 0};  /* treti usecka (vodorovna) */
 
        /* pridani useckoveho segmentu */
        vgAppendPathData(path, 5, commands, coordinates);
 
        /* usecka nema "vnitrek", proto se pouzije pouze VG_STROKE_PATH */
        vgDrawPath(path, VG_STROKE_PATH);
        vgDestroyPath(path);
    }
 
    /* prohozeni predniho a zadniho bufferu (pokud je to zapotrebi) */
    eglSwapBuffers(state->display, state->surface);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    draw(&egl_state);
    getchar();
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Soubor Makefile určený pro překlad tohoto příkladu se opět podle očekávání nijak neliší od předchozího Makefile:

# Makefile pro preklad devateho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example9
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
    rm -f *.o
    rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
    $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

12. Vysokoúrovňové funkce vguLine, vguRect, vguRoundRect a vguPolygon

V některých případech nemá příliš význam ručně tvořit cesty, pokud je vykreslovaný tvar podporovaný pomocnou knihovnou VGU (OpenVG Utility Library). Jedná se o samostatnou úsečku, osově orientovaný obdélník, osově orientovaný obdélník se zaoblenými rohy a obecný polygon:

vguErrorCode vguLine(VGPath path,
                     VGfloat x0, VGfloat y0,
                     VGfloat x1, VGfloat y1);
vguErrorCode vguRect(VGPath path,
                     VGfloat x, VGfloat y,
                     VGfloat width, VGfloat height);
vguErrorCode vguRoundRect(VGPath path,
                          VGfloat x, VGfloat y,
                          VGfloat width, VGfloat height,
                          VGfloat arcW, VGfloat arcH);
vguErrorCode vguPolygon(VGPath path,
                        const VGfloat * points, VGint count,
                        VGboolean closed);

Praktické příklady si ukážeme příště.

13. Repositář s demonstračními příklady

Všechny čtyři demonstrační příklady, které jsme si v dnešním článku popsali, byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/pre­sentations. V tabulce zobrazené pod tímto odstavcem naleznete na zdrojové kódy všech čtyř zmíněných demonstračních příkladů přímé odkazy:

ict ve školství 24

Poznámka1: pro zjednodušení překladu je ke každému demonstračnímu příkladu přiložen i příslušný soubor Makefile (otestovaný na Raspberry Pi).

Poznámka2: nenechte se prosím zmást číslováním – příklady example1 až example5 byly totiž popsány v předchozích třech částech tohoto seriálu.

14. Odkazy na Internetu

  1. EGL quick reference card
    https://www.khronos.org/files/egl-1–4-quick-reference-card.pdf
  2. EGL Reference Pages Index
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/in­dexflat.php
  3. Funkce eglInitialize
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glInitialize.xhtml
  4. Funkce eglGetDisplay
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glGetDisplay.xhtml
  5. Funkce eglGetConfigs
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glGetConfigs.xhtml
  6. Funkce eglGetConfigAttrib
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glGetConfigAttrib.xhtml
  7. Funkce eglDestroySurface
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glDestroySurface.xhtml
  8. Funkce eglDestroyContext
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glDestroyContext.xhtml
  9. Funkce eglTerminate
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glTerminate.xhtml
  10. Khronos Native Platform Graphics Interface
    https://www.khronos.org/re­gistry/egl/specs/eglspec.1­.4.pdf
  11. Khronos Group
    https://www.khronos.org/
  12. Khronos Group (Wikipedia)
    https://en.wikipedia.org/wi­ki/Khronos_Group
  13. Raspberry Pi VideoCore APIs
    http://elinux.org/Raspberry_Pi_Vi­deoCore_APIs
  14. Programming AudioVideo on the Raspberry Pi GPU
    https://jan.newmarch.name/RPi/in­dex.html
  15. The Standard for Vector Graphics Acceleration
    https://www.khronos.org/openvg/
  16. OpenVG (Wikipedia)
    https://en.wikipedia.org/wiki/OpenVG
  17. OpenVG Quick Reference Card
    https://www.khronos.org/files/openvg-quick-reference-card.pdf
  18. OpenVG on the Raspberry Pi
    http://mindchunk.blogspot­.cz/2012/09/openvg-on-raspberry-pi.html
  19. ShivaVG: open-source ANSI C OpenVG
    http://ivanleben.blogspot­.cz/2007/07/shivavg-open-source-ansi-c-openvg.html
  20. Testbed for exploring OpenVG on the Raspberry Pi
    https://github.com/ajstarks/openvg
  21. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: knihovna Pygame
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-knihovna-pygame/
  22. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: knihovna Pygame prakticky
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-knihovna-pygame-prakticky/
  23. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: práce s bitmapami a TrueType fonty
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-prace-s-bitmapami-a-truetype-fonty/
  24. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: sprity v knihovně Pygame
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-sprity-v-knihovne-pygame/
  25. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: detekce kolize spritů
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-detekce-kolize-spritu/
  26. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: transformace rastrových obrázků
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-transformace-rastrovych-obrazku/
  27. Seriál Grafické karty a grafické akcelerátory
    http://www.root.cz/serialy/graficke-karty-a-graficke-akceleratory/
  28. Grafika na osmibitových počítačích firmy Sinclair II
    http://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  29. Xiaolin_Wu's Line Algorithm
    https://en.wikipedia.org/wi­ki/Xiaolin_Wu's_line_algo­rithm
  30. Grafické čipy v osmibitových počítačích Atari
    http://www.root.cz/clanky/graficke-cipy-v-osmibitovych-pocitacich-atari/
  31. Osmibitové počítače Commodore a čip VIC-II
    http://www.root.cz/clanky/osmibitove-pocitace-commodore-a-cip-vic-ii/
  32. Grafika na osmibitových počítačích firmy Apple
    http://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-apple/
  33. Počátky grafiky na PC: grafické karty CGA a Hercules
    http://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/
  34. Karta EGA: první použitelná barevná grafika na PC
    http://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/
  35. Grafické karty MCGA a VGA
    http://www.root.cz/clanky/graficke-karty-mcga-a-vga/
  36. Grafický subsystém počítačů Amiga
    http://www.root.cz/clanky/graficky-subsystem-pocitacu-amiga/
  37. Grafický subsystém počítačů Amiga II
    http://www.root.cz/clanky/graficky-subsystem-pocitacu-amiga-ii/
  38. Raspberry Pi pages
    https://www.raspberrypi.org/
  39. BCM2835 registers
    http://elinux.org/BCM2835_registers
  40. VideoCore (archiv stránek společnosti Alphamosaic)
    http://web.archive.org/web/20030209213838/www­.alphamosaic.com/videocore/
  41. VideoCore (Wikipedia)
    https://en.wikipedia.org/wi­ki/Videocore
  42. RPi lessons: Lesson 6 Screen01
    http://www.cl.cam.ac.uk/pro­jects/raspberrypi/tutorial­s/os/screen01.html
  43. Raspberry Pi forum: Bare metal
    https://www.raspberrypi.or­g/forums/viewforum.php?f=72
  44. C library for Broadcom BCM 2835 as used in Raspberry Pi
    http://www.airspayce.com/mi­kem/bcm2835/
  45. Raspberry Pi Hardware Components
    http://elinux.org/RPi_Har­dware#Components
  46. (Linux) Framebuffer
    http://wiki.linuxquestion­s.org/wiki/Framebuffer
  47. (Linux) Framebuffer HOWTO
    http://tldp.org/HOWTO/Framebuffer-HOWTO/
  48. Linux framebuffer (Wikipedia)
    https://en.wikipedia.org/wi­ki/Linux_framebuffer
  49. RPi Framebuffer
    http://elinux.org/RPi_Framebuffer
  50. HOWTO: Boot your Raspberry Pi into a fullscreen browser kiosk
    http://blogs.wcode.org/2013/09/howto-boot-your-raspberry-pi-into-a-fullscreen-browser-kiosk/
  51. Zdrojový kód fb.c pro RPI
    https://github.com/jncronin/rpi-boot/blob/master/fb.c
  52. RPiconfig
    http://elinux.org/RPi_config.txt
  53. Mailbox framebuffer interface
    https://github.com/raspbe­rrypi/firmware/wiki/Mailbox-framebuffer-interface
  54. Seriál Grafické formáty
    http://www.root.cz/serialy/graficke-formaty/

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.