Hlavní navigace

Programovací jazyk Go a 2D grafika

26. 3. 2020
Doba čtení: 51 minut

Sdílet

Dnes začneme zpracovávat nové téma, tentokrát věnované možnostem použití Go při vykreslování 2D i 3D grafiky. Začneme jednodušším tématem, tedy 2D grafikou, konkrétně použitím knihovny SDL2 dostupné přes rozhraní nazvané go-sdl2.

Obsah

1. Programovací jazyk Go a 2D grafika

2. Knihovna SDL

3. Allegro 4 a Allegro 5

4. EGL

5. Vazba mezi SDL a dalšími programovacími jazyky

6. Instalace vývojové verze SDL2 a balíčku go-sdl2

7. Inicializace SDL, otevření okna a vyplnění plochy realizované v céčku

8. První demonstrační příklad v jazyce C

9. Přepis prvního příkladu do jazyka Go

10. Vykreslení rastrového obrázku funkcí typu blit

11. Druhý demonstrační příklad v jazyce C

12. Přepis druhého příkladu do jazyka Go

13. Třetí příklad – vykreslení obrázku se změnou jeho měřítka

14. Přepis třetího příkladu do jazyka Go

15. Přesné umístění obrázku doprostřed okna

16. Přepis čtvrtého příkladu do jazyka Go

17. Interaktivní prohlížeč fraktálů naprogramovaný v C

18. Interaktivní prohlížeč fraktálů naprogramovaný v Go

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

20. Odkazy na Internetu

1. Programovací jazyk Go a 2D grafika

Programovací jazyk Go se v současnosti používá převážně pro tvorbu různých typů služeb popř. démonů, tj. pro takové aplikace, u nichž není vyžadován přímý grafický výstup. Ovšem to neznamená, že se situace nemůže změnit popř. že Go není vhodným jazykem pro tvorbu 2D či 3D grafiky. Dnes se zaměříme především na oblast dvourozměrné grafiky. Existuje pochopitelně mnoho různých způsobů, jakými mohou aplikace naprogramované v Go zobrazovat dvourozměrnou grafiku. Na nejnižší (resp. přesněji řečeno rozumně nízké) úrovni je možné otevřít framebuffer, zjistit jeho formát a zapisovat data do framebufferu přes sdílenou paměť. Ovšem toto řešení má celou řadu nevýhod, takže se hodí jen pro specifické případy, například pro práci s 2D grafikou na zařízeních typu Raspberry Pi. Tomuto tématu jsme se již na stránkách Roota věnovali v článcích Operace s framebufferem na Raspberry Pi, Operace s framebufferem na Raspberry Pi (vykreslování do framebufferu) a Framebuffer na Raspberry Pi: vykreslování složitějších objektů. Použít lze ovšem i OpenGL ES či některou z více či méně pokročilých herních knihoven.

Navíc vždycky existuje alternativní možnost spočívající v použití překladače do WASM (Web Assembly) a v provádění vykreslování přímo do canvasu v okně prohlížeče, což je téma, kterému jsme se v tomto seriálu ve stručnosti věnovali. Pro některé typy aplikací se nemusí jednat o špatné řešení, ovšem systémové nároky jsou vyšší, než v případě použití nativního kódu a nějaké nativní knihovny.

2. Knihovna SDL

U některých typů aplikací může být výhodnější se použití vysokoúrovňových knihoven zcela vyhnout a použít namísto nich nějakou nativní knihovnu, která bude požadované grafické operace nabízet. V případě 3D grafiky je tak možné využít OpenGL či Direct3D, ovšem pokud se jedná o 2D grafiku, nabízí se celkem zajímavá volba – využití nativní knihovny SDL, která je sama o sobě pouze relativně tenkou vrstvou mezi uživatelskými programy a multimediálními zařízeními (grafickou a zvukovou kartou, ale též klávesnicí, joysticky a myší či časovačem). Mezi přednosti SDL patří její jednoduchost (z toho se odvíjí i existence vazby mezi SDL a programovacími jazyky, i když její základní API je čistě céčkové), přenositelnost na různé platformy (včetně Androidu, minimálně v případě SDL 1.x) a v neposlední řadě taktéž existence několika doplňujících modulů, například modulu pro vykreslování TTF fontů, vytvoření grafického kontextu pro OpenGL, modulu pro komunikaci po síti atd. I díky těmto vlastnostem je SDL používána v mnoha úspěšných hrách, viz též http://en.wikipedia.org/wi­ki/List_of_games_using_SDL.

Poznámka: ve výše uvedeném seznamu je i slavné Factorio.

Tato knihovna programátorům nabízí jak vykreslování do okna v případě použití systému X Window, tak i vykreslování do framebufferu. Přitom se v případě SDL 1.2 jedná o poměrně úzkou vrstvu mezi framebufferem a aplikací, což mj. znamená, že z vykreslovacích (grafických) operací jsou k dispozici pouze operace určené pro vykreslení obdélníku konstantní barvou, přenosu obrázku operací bitblt a uzamčení obrazové paměti s vrácením ukazatele do framebufferu (v tento okamžik, tj. po uzamčení obrazové paměti, se vlastně programátor nachází v podobném stavu, jako my při otevření speciálního zařízení /dev/fb0 a jeho namapování do adresního prostoru aplikace). SDL2 je již pojata odlišným způsobem, protože využívá možností nabízených grafickými akcelerátory, zejména možnost uchovat vykreslované bitmapy ve formě textur v paměti grafického akcelerátoru s tím, že vykreslení takových bitmap je mnohem rychlejší a vůbec nezatěžuje CPU.

Všechny příklady, s nimiž se seznámíme, využívají SDL2. Kromě SDL2 se ještě stále můžete setkat s návody popř. i aplikacemi, které jsou založeny na SDL(1). Ovšem mezi původním SDL a SDL2 je, jak jsme si již naznačili v předchozím odstavci, celá řada rozdílů, které se týkají především grafického subsystému. Je to ostatně logické, protože původní knihovna SDL vznikala v době, kdy se používalo softwarové vykreslování (hry typu Doom atd.), takže programy měly přímý přístup ke všem používaným bitmapám a vykreslování spočívalo v přenosu dat mezi operační pamětí a video pamětí. Dnes je situace zcela odlišná, protože vykreslované objekty (i pro 2D grafiku) bývají uloženy přímo v paměti grafické karty a vykreslení se většinou provádí bez nutnosti opakovaného přenosu dat z operační paměti do video paměti. To mj. znamená, že například vykreslované sprity musí být uloženy ve formátu podporovaného grafickou kartou (ve formě textur). Tyto principiální rozdíly se projevily právě ve vydání knihovny SDL2, která není a vlastně ani nemůže být zpětně kompatibilní.

Poznámka: tvůrci SDL2 schválně nevytvářeli emulační vrstvu, aby byla SDL2 stále jen tenkou „slupkou“ nad grafickými i dalšími multimediálními zařízeními.

3. Allegro 4 a Allegro 5

Určitou alternativou (či možná lépe řečeno konkurencí, i když méně známou) ke knihovně SDL je knihovna nazvaná Allegro, která v současnosti existuje ve dvou variantách: „klasická“ varianta založená na softwarovém renderingu nese označení Allegro 4 a zcela přepracovaná varianta, která již dokáže využívat některé možnosti nabízené grafickými akcelerátory, se jmenuje Allegro 5 (zpětná kompatibilita zde není zachována, podobně jako je tomu u SDL 1.2 → SDL 2.0). Z hlediska tvorby grafiky jsou nejdůležitější funkce pro vykreslování různých grafických primitiv (od pixelů přes úsečky až po křivky), práci s rastrovými obrázky a sprity (včetně použití tzv. kompilovaných spritů), ale i například podpora pro práci s animacemi uloženými ve formátu FLI/FLC. Pro některé účely může být zajímavý i modul nabízející velmi snadno použitelné GUI, které sice neobsahuje všechny dnes očekávané widgety (chybí například strom), ale pro konfigurační dialogy s tlačítky, scrollbary, vstupními textovými poli, přepínači atd. je to někdy použitelná a přitom výkonnostně a především paměťově nenáročná alternativa k plnohodnotným GUI knihovnám.

4. EGL

Taktéž je možné využít technologii, která je přímo navržena pro práci s grafickým procesorem. Jedná se o EGL neboli též Native Platform Interface používané jako mezivrstva mezi grafickým procesorem (přičemž každý grafický procesor může mít zcela odlišný způsob ovládání) na jedné straně a knihovnou OpenVG či OpenGL ES na straně druhé (alternativně je samozřejmě možné volat funkce poskytované EGL přímo. Za vývojem EGL stojí sdružení Khronos, které kromě toho „pečuje“ i o specifikace a implementace OpenGL, OpenGL ES, OpenVG atd. Jedním ze základních úkolů EGL je vytvoření a správa grafického kontextu, ploch (surface), do kterých je možné přes knihovny OpenGL ES a OpenVG provádět vykreslování atd. Mimochodem – plochy (surface) mohou být vytvořeny tak, aby aplikace běžela v systému X Window (i v okně), přes framebuffer nebo lze vykreslování provádět do takzvaného zadního bufferu. Další důležitou funkcí nabízenou EGL je kopie obsahu bitmap mezi jednotlivými plochami, tj. operace typu bitblt.

5. Vazba mezi SDL a dalšími programovacími jazyky

Jak jsme se již řekli v úvodních kapitolách, pro většinu dnes používaných programovacích jazyků existuje rozhraní umožňující volat funkce knihovny SDL. Mezi podporované jazyky patří (pochopitelně kromě nativního céčka) zejména Ada, C++, C#, D, Fortran, Genie, Go, Haskell, Julia, Lua, Nim, OCaml, Pascal, Perl, PHP, Python, Rust, Vala a dokonce i Common Lisp. SDL lze použít i z jazyka Java (a tím pádem z jakéhokoli jazyka postaveného nad JVM), což je téma, kterým jsme se opět již zabývali:

  1. Pohled pod kapotu JVM – využití knihovny SDLJava v graficky náročných aplikacích
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-vyuziti-knihovny-sdljava-v-graficky-narocnych-aplikacich/
  2. Pohled pod kapotu JVM – základní koncepty, na nichž je postavena knihovna SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-zakladni-koncepty-na-nichz-je-postavena-knihovna-sdljava/
  3. Pohled pod kapotu JVM – nízkoúrovňový přístup k framebufferu i bitmapám s využitím knihovny SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-nizkourovnovy-pristup-k-framebufferu-i-bitmapam-s-vyuzitim-knihovny-sdljava/
  4. Pohled pod kapotu JVM – volání funkcí OpenGL s využitím knihovny SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-volani-funkci-opengl-s-vyuzitim-knihovny-sdljava/
  5. Pohled pod kapotu JVM – složitější tělesa, textury a sprity v knihovně SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-slozitejsi-telesa-textury-a-sprity-v-knihovne-sdljava/
  6. Pohled pod kapotu JVM – práce s texturami v knihovně SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-prace-s-texturami-v-knihovne-sdljava/
  7. Pohled pod kapotu JVM – blending a textury s alfa kanálem v knihovně SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-blending-a-textury-s-alfa-kanalem-v-knihovne-sdljava/
  8. Pohled pod kapotu JVM – zpracování událostí v knihovně SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-zpracovani-udalosti-v-knihovne-sdljava/
  9. Pohled pod kapotu JVM – zpracování událostí v knihovně SDLJava (klávesnice a myš)
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-zpracovani-udalosti-v-knihovne-sdljava-klavesnice-a-mys/
  10. Pohled pod kapotu JVM – zpracování událostí v knihovně SDLJava (dokončení)
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-zpracovani-udalosti-v-knihovne-sdljava-dokonceni/
  11. Pohled pod kapotu JVM – práce s TTF fonty v knihovně SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-prace-s-ttf-fonty-v-knihovne-sdljava/
  12. Pohled pod kapotu JVM – práce s TTF fonty v knihovně SDLJava (dokončení)
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-prace-s-ttf-fonty-v-knihovne-sdljava-dokonceni/
  13. Pohled pod kapotu JVM – kreslicí funkce dostupné ve třídě sdljavax.gfx.SDLGfx
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-kreslici-funkce-dostupne-ve-tride-sdljavax-gfx-sdlgfx/
  14. Pohled pod kapotu JVM – kreslicí funkce dostupné ve třídě sdljavax.gfx.SDLGfx (2.část)
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-kreslici-funkce-dostupne-ve-tride-sdljavax-gfx-sdlgfx-2-cast/
  15. Pohled pod kapotu JVM – kreslicí funkce ve třídě sdljavax.gfx.SDLGfx (3.část) a zvukový subsystém SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-kreslici-funkce-ve-tride-sdljavax-gfx-sdlgfx-3-cast-a-zvukovy-subsystem-sdljava/
  16. Pohled pod kapotu JVM – přehrávání hudby s využitím knihovny SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-prehravani-hudby-s-vyuzitim-knihovny-sdljava/
  17. Pohled pod kapotu JVM – přehrávání a mixování zvuků s využitím knihovny SDLJava
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-prehravani-a-mixovani-zvuku-s-vyuzitim-knihovny-sdljava/
  18. Pohled pod kapotu JVM – výkonnost aplikací vytvořených s využitím SDLJava v porovnání s nativními aplikacemi
    https://www.root.cz/clanky/pohled-pod-kapotu-jvm-vykonnost-aplikaci-vytvorenych-s-vyuzitim-sdljava-v-porovnani-s-nativnimi-aplikacemi/

Dnes si popíšeme způsob použití SDL z jazyka Go s využitím balíčků go-sdl2.

6. Instalace vývojové verze SDL2 a balíčku go-sdl2

Před instalací rozhraní mezi knihovnou SDL2 a programovacím jazykem Go je nutné nainstalovat vývojové verze knihovny (přesněji řečeno knihoven) SDL2. To je ve skutečnosti velmi snadné a celá operace se provede (v distribuci založené na RPM, zde konkrétně na poněkud obstarožní Fedoře 27) následovně:

$ sudo yum install SDL2{,_image,_mixer,_ttf,_gfx}-devel
 
Last metadata expiration check: 0:47:05 ago on Sun 22 Mar 2020 08:15:23 AM CET.
Dependencies resolved.
================================================================================
 Package                   Arch        Version               Repository    Size
================================================================================
Installing:
 SDL2-devel                x86_64      2.0.7-3.fc27          updates      252 k
 SDL2_gfx-devel            x86_64      1.0.3-1.fc27          updates       40 k
 SDL2_image-devel          x86_64      2.0.2-2.fc27          updates       12 k
 SDL2_mixer-devel          x86_64      2.0.2-1.fc27          updates       19 k
 SDL2_ttf-devel            x86_64      2.0.14-5.fc27         fedora        12 k
Installing dependencies:
 SDL2_gfx                  x86_64      1.0.3-1.fc27          updates       39 k
 SDL2_image                x86_64      2.0.2-2.fc27          updates       80 k
 SDL2_mixer                x86_64      2.0.2-1.fc27          updates       76 k
 SDL2_ttf                  x86_64      2.0.14-5.fc27         fedora        24 k
 libX11-devel              x86_64      1.6.5-4.fc27          fedora       984 k
 libXau-devel              x86_64      1.0.8-9.fc27          fedora        18 k
 libXdamage-devel          x86_64      1.1.4-11.fc27         fedora        14 k
 libXext-devel             x86_64      1.3.3-7.fc27          fedora        79 k
 libXfixes-devel           x86_64      5.0.3-4.fc27          fedora        17 k
 libXxf86vm-devel          x86_64      1.1.4-6.fc27          fedora        22 k
 libdrm-devel              x86_64      2.4.91-1.fc27         updates      138 k
 libglvnd-core-devel       x86_64      1:1.0.0-1.fc27        updates       22 k
 libglvnd-devel            x86_64      1:1.0.0-1.fc27        updates       13 k
 libglvnd-opengl           x86_64      1:1.0.0-1.fc27        updates       45 k
 libxcb-devel              x86_64      1.12-5.fc27           fedora       1.0 M
 mesa-libEGL-devel         x86_64      17.3.9-1.fc27         updates       45 k
 mesa-libGLES-devel        x86_64      17.3.9-1.fc27         updates       70 k
 xorg-x11-proto-devel      noarch      7.7-23.fc27           fedora       287 k
 
Transaction Summary
================================================================================
Install  23 Packages
 
Total download size: 3.3 M
Installed size: 8.7 M
Is this ok [y/N]:
Poznámka: my sice dnes budeme reálně používat pouze SDL2-devel a SDL2_gfx-devel, ovšem překlad balíčku pro Go by neproběhl korektně, kdyby nebyly k dispozici i další vyžadované knihovny. Nicméně naprostou většinu funkcí volanou z Go najdeme v balíčku github.com/veandco/go-sdl2/sdl.

V distribucích založených na Debianích balíčcích se instalace spustí velmi podobným způsobem (otestováno na Mintu):

$ apt-get install libsdl2{,-image,-mixer,-ttf,-gfx}-dev

Ve druhém kroku je nutné nainstalovat rozhraní mezi SDL2 a programovacím jazykem Go představované balíčkem nazvaným příznačně go-sdl2. Celý postup je v tomto případě zcela jednoduchý:

$ go get github.com/veandco/go-sdl2/sdl
Poznámka: pokud předchozí příklad selže, nejsou pravděpodobně správně nastaveny cesty k vývojové verzi knihovny SDL2 nainstalované v předchozím kroku. Ovšem tuto skutečnost si otestujeme na překladu a slinkování demonstračních příkladů naprogramovaných v céčku.

7. Inicializace SDL, otevření okna a vyplnění plochy realizované v céčku

Vlastnosti a možnosti nabízené knihovnou SDL si nejlépe ukážeme na demonstračních příkladech. Všechny dnes uvedené demonstrační příklady – ty psané v C i v Go – budou velmi jednoduché a současně budou využívat jen základní grafické možnosti knihovny SDL, zatímco dalšími možnostmi (zvuky, čtení stavů klávesnice a myši atd.) se budeme zabývat v navazujících částech tohoto seriálu. První demonstrační příklad uvedený v této kapitole je velmi jednoduchý a využívá pouze několik funkcí SDL určené pro inicializaci okna, kreslicí plochy (surface), základní vykreslení a uvolnění všech zdrojů – ukazuje tedy základní typy objektů, s nimiž se v SDL dříve či později setkáme.

Inicializace knihovny SDL, resp. jejích vybraných subsystémů:

if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    puts("Error initializing SDL");
    puts(SDL_GetError());
    return 1;
}

Vytvoření okna zadané velikosti (lze otevřít i fullscreen okno bez okrajů):

window = SDL_CreateWindow("SDL2 example #1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
 
if (!window) {
    puts("Error creating window");
    puts(SDL_GetError());
    return 1;
}

Důležitý je koncept kreslicí plochy – surface. Tu lze získat i pro existující otevřené okno. Jakmile je získána kreslicí plocha, můžeme ji či její část vyplnit zadanou barvou a vynutit si překreslení obsahu okna:

primarySurface = SDL_GetWindowSurface(window);
 
if (!primarySurface) {
    puts("Error getting surface");
    puts(SDL_GetError());
    return 1;
}
 
SDL_FillRect(primarySurface, NULL, SDL_MapRGB(primarySurface->format, 192, 255, 192));
 
SDL_UpdateWindowSurface(window);

Nakonec bychom neměli zapomenout na uvolnění všech prostředků (objektů) a ukončení běhu knihovny SDL:

SDL_DestroyWindow(window);
 
SDL_Quit();
Poznámka: zcela korektní by bylo kontrolovat návratové kódy i těchto dvou funkcí.

8. První demonstrační příklad v jazyce C

Úplný zdrojový kód prvního příkladu zapsaného v jazyce C může vypadat následovně:

#include <stdio.h>
#include <SDL2/SDL.h>
 
#define WIDTH  640
#define HEIGHT 480
 
int main(int argc, char** args) {
    SDL_Surface *primarySurface = NULL;
    SDL_Window  *window = NULL;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
 
    if (!window) {
        puts("Error creating window");
        puts(SDL_GetError());
        return 1;
    }
 
    primarySurface = SDL_GetWindowSurface(window);
 
    if (!primarySurface) {
        puts("Error getting surface");
        puts(SDL_GetError());
        return 1;
    }
 
    SDL_FillRect(primarySurface, NULL, SDL_MapRGB(primarySurface->format, 192, 255, 192));
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_DestroyWindow(window);
 
    SDL_Quit();
 
    return 0;
}

9. Přepis prvního příkladu do jazyka Go

Nyní se můžeme pokusit přepsat tento demonstrační příklad do jazyka Go. Kostra a základní myšlenka zůstane pochopitelně stejná, budou se jen lišit jména funkcí, namísto některých funkcí použijeme metody a navíc s výhodou využijeme konstrukci defer.

package main
 
import "github.com/veandco/go-sdl2/sdl"
 
const (
        width  = 640
        height = 480
)
 
func main() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("Example #1", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
        defer window.Destroy()
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
        window.UpdateSurface()
 
        sdl.Delay(5000)
}
Poznámka: povšimněte si, že jména funkcí jsou zkrácena, protože na rozdíl od céčka nemusíme používat jediný jmenný prostor. Datový typ surface je navíc objektem (s předepsaným rozhraním), podobně i typ window. To znamená, že se z některých funkcí staly metody a celý příklad se poměrně radikálním způsobem zpřehlednil.

10. Vykreslení rastrového obrázku funkcí typu blit

Ve druhém demonstračním příkladu se pokusíme o načtení rastrového obrázku uloženého ve formátu BMP. Tento formát nebyl v žádném případě zvolen proto, že by byl snadno zpracovatelný nebo dokonce úsporný, ale z toho prostého důvodu, že jeho podpora je přímo součástí základní knihovny SDL/SDL2 bez nutnosti používat sdl-image. Další formáty (PNG apod.) lze sice načítat také, ale nepatrně složitějším způsobem. Vraťme se však k demonstračnímu příkladu. Načtení obrázku v programovacím jazyce C a kontrola, zda se načtení podařilo, se provede následujícím způsobem:

SDL_Surface *tempImage;
 
tempImage = SDL_LoadBMP("test1.bmp");
 
if (!tempImage) {
    puts("Error loading image");
    return 0;
}

Následně je vhodné (i když ne vždy nutné) obrázek zkonvertovat do takového formátu, který je přímo zobrazitelný na obrazovce. K tomuto účelu se používá funkce SDL_ConvertSurface, které se předá jak původní kreslicí plocha (načtený obrázek), tak i požadovaný formát:

image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
Poznámka: v tomto konkrétním příkladu by se mohlo zdát, že konverze není zapotřebí provádět (a budete mít pravdu), ale pro operaci typu „StretchBlit“ je nutné mít kompatibilní obrázek.

Zkonvertovaný obrázek se zobrazí funkcí nazvanou SDL_BlitSurface, které pro jednoduchost předáme pouze obrázek a primární kreslicí plochu. Obrázek tedy bude umístěn do souřadnic (0,0):

SDL_BlitSurface(image, NULL, primarySurface, NULL);

11. Druhý demonstrační příklad v jazyce C

Úplný zdrojový kód takto navrženého druhého demonstračního příkladu vypadá následovně:

#include <stdio.h>
#include <SDL2/SDL.h>
 
#define WIDTH  640
#define HEIGHT 480
 
SDL_Window  *window;
SDL_Surface *primarySurface;
SDL_Surface *image;
 
int load() {
    SDL_Surface *tempImage;
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
 
    if (!image) {
        puts("Error converting surface");
        return 0;
    }
    return 1;
}
 
int init() {
    if (SDL_Init(SDL_INIT_VIDEO ) < 0) {
        puts("Error initializing SDL");
        return 0;
    }
 
    window = SDL_CreateWindow("SDL2 example #2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
    if (!window) {
        puts("Error creating window");
        return 0;
    }
 
    primarySurface = SDL_GetWindowSurface(window);
    if (!primarySurface) {
        puts("Error getting surface");
        return 0;
    }
    return 1;
}
 
void destroy() {
    SDL_FreeSurface(image);
 
    SDL_DestroyWindow(window);
    SDL_Quit();
}
 
int main(int argc, char** args) {
    if (!init()) {
        return 1;
    }
    if (!load()) {
        return 1;
    }
 
    SDL_BlitSurface(image, NULL, primarySurface, NULL);
 
    SDL_UpdateWindowSurface(window);
    SDL_Delay(5000);
 
    destroy();
    return 0;
}

12. Přepis druhého příkladu do jazyka Go

Následuje přepis předchozího céčkového příkladu do Go. Opět zde můžeme vidět určitá zjednodušení; například načtení rastrového obrázku je triviální:

surfaceImage, err := img.Load("test1.bmp")
if err != nil {
        panic(err)
}
defer surfaceImage.Free()

Výsledek:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
func main() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("Example #2", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
        defer window.Destroy()
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        surfaceImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer surfaceImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        err = surfaceImage.Blit(nil, primarySurface, nil)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

Jak jsme si již řekli výše, je užitečnější a korektnější převést obrázek na „kompatibilní formát“, což je provedeno v dalším zdrojovém kódu, který mj. obsahuje:

convertedImage, err := surfaceImage.Convert(primarySurface.Format, 0)
if err != nil {
        panic(err)
}
defer convertedImage.Free()

Úplný zdrojový kód:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
func main() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("Example #2", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
        defer window.Destroy()
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        surfaceImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer surfaceImage.Free()
 
        convertedImage, err := surfaceImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(convertedImage.Format, 192, 255, 192))
 
        err = convertedImage.Blit(nil, primarySurface, nil)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}
Poznámka: povšimněte si, že jsou příklady přepsané do Go skutečně kratší a současně i přehlednější.

13. Třetí příklad – vykreslení obrázku se změnou jeho měřítka

Ve třetím příkladu zobrazíme stejný obrázek, jako v příkladu předchozím, ovšem s odlišným měřítkem. Pro tento účel se v céčku používá funkce nazvaná SDL_BlitScaled, která ovšem pracuje korektně jen za předpokladu, že je obrázek uložen ve formátu kompatibilním s cílovou kreslicí plochou, tj. v našem případě s plochou představující obrazovku. Rozměry a umístění obrázku jsou představovány datovou strukturou Rect (obdélník):

dest.x = 160;
dest.y = 120;
dest.w = 250;
dest.h = 250;
 
SDL_BlitScaled(image, NULL, primarySurface, &dest);

Úplný zdrojový kód třetího příkladu v céčkové variantě:

#include <stdio.h>
#include <SDL2/SDL.h>
 
#define WIDTH  640
#define HEIGHT 480
 
SDL_Window  *window;
SDL_Surface *primarySurface;
SDL_Surface *image;
 
int load() {
    SDL_Surface *tempImage;
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
 
    if (!image) {
        puts("Error converting surface");
        return 0;
    }
    return 1;
}
 
int init() {
    if (SDL_Init(SDL_INIT_VIDEO ) < 0) {
        puts("Error initializing SDL");
        return 0;
    }
 
    window = SDL_CreateWindow("SDL2 example #3", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN );
    if (!window) {
        puts("Error creating window");
        return 0;
    }
 
    primarySurface = SDL_GetWindowSurface(window);
    if (!primarySurface) {
        puts("Error getting surface");
        return 0;
    }
    return 1;
}
 
void destroy() {
    SDL_FreeSurface(image);
 
    SDL_DestroyWindow(window);
    SDL_Quit();
}
 
int main(int argc, char** args) {
    SDL_Rect dest;
 
    if (!init()) {
        return 1;
    }
    if (!load()) {
        return 1;
    }
 
    SDL_FillRect(primarySurface, NULL, SDL_MapRGB(primarySurface->format, 192, 255, 192));
 
    dest.x = 160;
    dest.y = 120;
    dest.w = 250;
    dest.h = 250;
    SDL_BlitScaled(image, NULL, primarySurface, &dest);
 
    SDL_UpdateWindowSurface(window);
    SDL_Delay(5000);
 
    destroy();
    return 0;
}

14. Přepis třetího příkladu do jazyka Go

Přepis předchozího příkladu do idiomatického Go je relativně snadný a příliš se neliší od obou příkladů předchozích:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
func main() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("Example #3", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
        defer window.Destroy()
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        surfaceImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer surfaceImage.Free()
 
        convertedImage, err := surfaceImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(convertedImage.Format, 192, 255, 192))
 
        var destRect sdl.Rect
        destRect.X = 160
        destRect.Y = 120
        destRect.W = 250
        destRect.H = 250
 
        err = convertedImage.BlitScaled(nil, primarySurface, &destRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

15. Přesné umístění obrázku doprostřed okna

Ve čtvrtém demonstračním příkladu se seznámíme s dalšími vlastnostmi kreslicí plochy. Týká se to zejména informace o její šířce a výšce, která je v jazyku C reprezentovaná položkami nazvanými h a w. Vzhledem k tomu, že k ploše přistupujeme přes ukazatel, bude se pro přístup k položkám datové struktury používat opererátor ->. Vycentrování obrázku na střed okna a současně jeho zmenšení na polovinu zajistí následující úryvek kódu:

dest.x = primarySurface->w/2 - image->w/4;
dest.y = primarySurface->h/2 - image->h/4;
dest.w = image->w/2;
dest.h = image->h/2;
 
printf("%d %d %d %d\n", dest.x, dest.y, dest.w, dest.h);
 
SDL_BlitScaled(image, NULL, primarySurface, &dest);

Opět pochopitelně následuje výpis úplného zdrojového kódu tohoto příkladu:

#include <stdio.h>
#include <SDL2/SDL.h>
 
#define WIDTH  640
#define HEIGHT 480
 
SDL_Window  *window;
SDL_Surface *primarySurface;
SDL_Surface *image;
 
int load() {
    SDL_Surface *tempImage;
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
 
    if (!image) {
        puts("Error converting surface");
        return 0;
    }
    return 1;
}
 
int init() {
    if (SDL_Init(SDL_INIT_VIDEO ) < 0) {
        puts("Error initializing SDL");
        return 0;
    }
 
    window = SDL_CreateWindow("SDL2 example #4", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
    if (!window) {
        puts("Error creating window");
        return 0;
    }
 
    primarySurface = SDL_GetWindowSurface(window);
    if (!primarySurface) {
        puts("Error getting surface");
        return 0;
    }
    return 1;
}
 
void destroy() {
    SDL_FreeSurface(image);
 
    SDL_DestroyWindow(window);
    SDL_Quit();
}
 
int main(int argc, char** args) {
    SDL_Rect dest;
 
    if (!init()) {
        return 1;
    }
    if (!load()) {
        return 1;
    }
 
    SDL_FillRect(primarySurface, NULL, SDL_MapRGB(primarySurface->format, 192, 255, 192));
 
    dest.x = primarySurface->w/2 - image->w/4;
    dest.y = primarySurface->h/2 - image->h/4;
    dest.w = image->w/2;
    dest.h = image->h/2;
    printf("%d %d %d %d\n", dest.x, dest.y, dest.w, dest.h);
    SDL_BlitScaled(image, NULL, primarySurface, &dest);
 
    SDL_UpdateWindowSurface(window);
    SDL_Delay(5000);
 
    destroy();
    return 0;
}

16. Přepis čtvrtého příkladu do jazyka Go

Převod do idiomatického Go pravděpodobně není zapotřebí podrobně komentovat, protože se jedná jen o variantu na třetí demonstrační příklad:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
func main() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("Example #4", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
        defer window.Destroy()
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        surfaceImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer surfaceImage.Free()
 
        convertedImage, err := surfaceImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(convertedImage.Format, 192, 255, 192))
 
        var destRect sdl.Rect
        destRect.X = primarySurface.W/2 - convertedImage.W/4
        destRect.Y = primarySurface.H/2 - convertedImage.H/4
        destRect.W = convertedImage.W / 2
        destRect.H = convertedImage.H / 2
 
        err = convertedImage.BlitScaled(nil, primarySurface, &destRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

17. Interaktivní prohlížeč fraktálů naprogramovaný v C

Knihovnou SDL se budeme zabývat i příště, takže si již dopředu ukažme relativně složitý zdrojový kód, v němž je realizován výpočet a vykreslení fraktálů (mix mezi Mandelbrotovou a Juliovou množinou). V tomto příkladu se používá přímý přístup do paměti kreslicí plochy, zpracování událostí (smyčka událostí) atd. Podrobnosti si řekneme v navazujícím článku:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <SDL2/SDL.h>
 
#define WIDTH 320
#define HEIGHT 240
 
#define nil NULL
 
#define MAX(a,b) ((a)>(b) ? (a) : (b))
#define MIN(a,b) ((a)<(b) ? (a) : (b))
 
SDL_Surface *pixmap;
SDL_Surface *screen_surface = NULL;
SDL_Surface *bitmap_font_surface = NULL;
SDL_Window *window = NULL;
 
double xpos = -0.75;
double ypos = 0.0;
double scale = 150.0;
double  uhel = 45.0;
 
int gfx_initialize(int fullscreen, int width, int height, int bpp) {
    window = NULL;
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError());
        return 1;
    } else {
        puts("SDL_Init ok");
    }
 
    window = SDL_CreateWindow( "Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN );
    if (!window) {
        puts("Error creating window");
        puts(SDL_GetError());
        return 1;
    } else {
        puts("SDL_CreateWindow ok");
    }
 
    screen_surface = SDL_GetWindowSurface(window);
 
    if (!screen_surface) {
        fprintf(stderr, "Error setting video mode: %s\n", SDL_GetError());
        return 1;
    } else {
        puts("SDL_GetWindowSurface ok");
    }
    return 0;
}
 
void gfx_finalize(void) {
    SDL_FreeSurface(screen_surface);
    SDL_DestroyWindow(window);
}
 
SDL_Surface* gfx_create_surface(int width, int height) {
    return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000);
}
 
void putpixel(SDL_Surface *surface, int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
    if (x>=0 && x< surface->w && y>=0 && y < surface->h) {
        if (surface->format->BitsPerPixel == 24) {
            Uint8 *pixel = (Uint8 *)surface->pixels;
            pixel += x*3;
            pixel += y*surface->pitch;
            *pixel++ = b;
            *pixel++ = g;
            *pixel   = r;
        }
        if (surface->format->BitsPerPixel == 32) {
            Uint8 *pixel = (Uint8 *)surface->pixels;
            pixel += x*4;
            pixel += y*surface->pitch;
            *pixel++ = b;
            *pixel++ = g;
            *pixel   = r;
        }
    }
}
 
void hline(SDL_Surface *surface, int x1, int x2, int y, unsigned char r, unsigned char g, unsigned char b) {
    int x;
    int fromX = MIN(x1, x2);
    int toX = MAX(x1, x2);
    for (x = fromX; x <= toX; x++) {
        putpixel(surface, x, y, r, g, b);
    }
}
 
void vline(SDL_Surface *surface, int x,  int y1, int y2, unsigned char r, unsigned char g, unsigned char b) {
    int y;
    int fromY = MIN(y1, y2);
    int toY = MAX(y1, y2);
    for (y = fromY; y <= toY; y++) {
        putpixel(surface, x, y, r, g, b);
    }
}
 
static void show_fractal(SDL_Surface *surface) {
    SDL_BlitSurface(surface, NULL, screen_surface, NULL);
    SDL_UpdateWindowSurface(window);
}
 
void calcCorner(double xpos, double ypos, double scale,
                double *xmin,  double *ymin,  double *xmax, double *ymax) {
    *xmin=xpos-WIDTH/scale;
    *ymin=ypos-HEIGHT/scale;
    *xmax=xpos+WIDTH/scale;
    *ymax=ypos+HEIGHT/scale;
}
 
void draw_grid(SDL_Surface *surface) {
    int width = surface->w;
    int height = surface->h;
    int x, y;
    SDL_FillRect(surface, NULL, 0xffffffff);
 
    for (x=0; x<width; x+=20) {
        vline(surface, x, 0, height-1, 191, 191, 255);
    }
    for (y=0; y<height; y+=20) {
        hline(surface, 0, width-1, y, 191, 191, 255);
    }
}
 
void draw_mandeljulia(SDL_Surface *surface) {
    double  zx,zy,zx2,zy2,cx,cy;
    double  cosu,sinu,ccxc,ccyc;
    int     x,y,i;
    Uint8 *pixel = nil;
 
    double ccx = 0.0;
    double ccy = 0.0;
 
    double xmin, ymin, xmax, ymax;
    double u;
 
    calcCorner(xpos, ypos, scale, &xmin, &ymin, &xmax, &ymax);
 
    u=uhel*3.1415/180.0;
    cosu=cos(u);
    sinu=sin(u);
    ccxc=ccx*cosu;
    ccyc=ccy*cosu;
 
    cy = ymin;
 
    for (y=0;y<240;y++) {
        cx=xmin;
        pixel = (Uint8 *)surface->pixels + (y + 128) * surface->pitch + 160*4;
        for (x=0;x<320;x++) {
            i=0;
            zx=cx*cosu;
            zy=cy*cosu;
            do {
                zx2=zx*zx;
                zy2=zy*zy;
                zy=2.0*zx*zy+ccyc+cy*sinu;
                zx=zx2-zy2+ccxc+cx*sinu;
                i++;
            } while (i<64 && zx2+zy2<4.0);
            {
                int r = i*2;
                int g = i*3;
                int b = i*5;
 
                *pixel++ = r;
                *pixel++ = g;
                *pixel++ = b;
                pixel++;
            }
            cx += (xmax-xmin)/WIDTH;
        }
        cy += (ymax-ymin)/HEIGHT;
    }
}
 
void redraw(SDL_Surface *pixmap) {
    draw_grid(pixmap);
    draw_mandeljulia(pixmap);
    show_fractal(pixmap);
}
 
static void main_event_loop(void) {
    SDL_Event event;
    int done = 0;
    int left = 0, right = 0, up = 0, down = 0;
    int zoomin = 0, zoomout = 0;
    int perform_redraw;
    int angle_1 = 0, angle_2 = 0;
 
    do {
        /*SDL_WaitEvent(&event);*/
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    done = 1;
                    break;
                case SDL_KEYDOWN:
                    switch (event.key.keysym.sym) {
                        case SDLK_ESCAPE:
                        case SDLK_q:
                            done = 1;
                            break;
                        case SDLK_LEFT:
                            left = 1;
                            break;
                        case SDLK_RIGHT:
                            right = 1;
                            break;
                        case SDLK_UP:
                            up = 1;
                            break;
                        case SDLK_DOWN:
                            down = 1;
                            break;
                        case SDLK_PAGEDOWN:
                            zoomin = 1;
                            break;
                        case SDLK_PAGEUP:
                            zoomout = 1;
                            break;
                        case SDLK_z:
                            angle_1 = 1;
                            break;
                        case SDLK_x:
                            angle_2 = 1;
                            break;
                        default:
                            break;
                    }
                    break;
                case SDL_KEYUP:
                    switch (event.key.keysym.sym) {
                        case SDLK_LEFT:
                            left = 0;
                            break;
                        case SDLK_RIGHT:
                            right = 0;
                            break;
                        case SDLK_UP:
                            up = 0;
                            break;
                        case SDLK_DOWN:
                            down = 0;
                            break;
                        case SDLK_PAGEDOWN:
                            zoomin = 0;
                            break;
                        case SDLK_PAGEUP:
                            zoomout = 0;
                            break;
                        case SDLK_z:
                            angle_1 = 0;
                            break;
                        case SDLK_x:
                            angle_2 = 0;
                            break;
                        default:
                            break;
                    }
                default:
                    break;
            }
        }
        perform_redraw = 0;
        if (left) {
            xpos -= 10.0/scale;
            perform_redraw=1;
        }
        if (right) {
            xpos += 10.0/scale;
            perform_redraw=1;
        }
        if (up) {
            ypos -= 10.0/scale;
            perform_redraw=1;
        }
        if (down) {
            ypos += 10.0/scale;
            perform_redraw=1;
        }
        if (zoomin) {
            scale *= 0.9;
            perform_redraw=1;
        }
        if (zoomout) {
            scale *= 1.1;
            perform_redraw=1;
        }
        if (angle_1) {
            uhel--;
            perform_redraw=1;
        }
        if (angle_2) {
            uhel++;
            perform_redraw=1;
        }
        if (perform_redraw) {
            redraw(pixmap);
        }
    } while (!done);
}
 
int main(int argc, char **argv) {
    if (gfx_initialize(0, 640, 480, 32)) {
        return 1;
    }
 
    pixmap = gfx_create_surface(screen_surface->w, screen_surface->h);
 
    draw_grid(pixmap);
    draw_mandeljulia(pixmap);
    show_fractal(pixmap);
    main_event_loop();
 
    gfx_finalize();
    SDL_Quit();
    return 0;
}

18. Interaktivní prohlížeč fraktálů naprogramovaný v Go

Přepis předchozího příkladu do programovacího jazyka Go může vypadat následovně:

package main
 
import (
        "math"
 
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 320
        height = 240
)
 
var pixmap *sdl.Surface = nil
var primarySurface *sdl.Surface = nil
var window *sdl.Window = nil
 
var xpos float64 = -0.75
var ypos float64 = 0.0
var scale float64 = 150.0
var uhel float64 = 45.0
 
func min(a, b int32) int32 {
        if a > b {
                return b
        }
        return a
}
 
func max(a, b int32) int32 {
        if a > b {
                return a
        }
        return b
}
 
func gfxInitialize(width int32, height int32, bpp int) {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        window, err = sdl.CreateWindow("Fractals", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        primarySurface, err = window.GetSurface()
        if err != nil {
                panic(err)
        }
}
 
func gfxFinalize() {
        primarySurface.Free()
        window.Destroy()
        sdl.Quit()
}
 
func createSurface(width int32, height int32) *sdl.Surface {
        surface, err := sdl.CreateRGBSurface(sdl.SWSURFACE, width, height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000)
        if err != nil {
                panic(err)
        }
        return surface
}
 
func putpixel(surface *sdl.Surface, x int32, y int32, r byte, g byte, b byte) {
        if x >= 0 && x < surface.W && y >= 0 && y < surface.H {
                switch surface.Format.BitsPerPixel {
                case 24:
                        index := x*3 + y*surface.Pitch
                        pixels := surface.Pixels()
                        pixels[index] = b
                        pixels[index+1] = g
                        pixels[index+2] = r
                case 32:
                        index := x*4 + y*surface.Pitch
                        pixels := surface.Pixels()
                        pixels[index] = b
                        pixels[index+1] = g
                        pixels[index+2] = r
                }
        }
}
 
func hline(surface *sdl.Surface, x1 int32, x2 int32, y int32, r byte, g byte, b byte) {
        fromX := min(x1, x2)
        toX := max(x1, x2)
 
        for x := fromX; x <= toX; x++ {
                putpixel(surface, x, y, r, g, b)
        }
}
 
func vline(surface *sdl.Surface, x int32, y1 int32, y2 int32, r byte, g byte, b byte) {
        fromY := min(y1, y2)
        toY := max(y1, y2)
 
        for y := fromY; y <= toY; y++ {
                putpixel(surface, x, y, r, g, b)
        }
}
 
func drawGrid(surface *sdl.Surface) {
        width := surface.W
        height := surface.H
        var x, y int32
 
        surface.FillRect(nil, 0xffffffff)
 
        for x = 0; x < width; x += 20 {
                vline(surface, x, 0, height-1, 191, 191, 255)
        }
 
        for y = 0; y < height; y += 20 {
                hline(surface, 0, width-1, y, 191, 191, 255)
        }
}
 
func showFractal(surface *sdl.Surface) {
        err := surface.Blit(nil, primarySurface, nil)
        if err != nil {
                panic(err)
        }
        window.UpdateSurface()
}
 
func calcCorner(xpos, ypos, scale float64) (xmin, ymin, xmax, ymax float64) {
        xmin = xpos - width/scale
        ymin = ypos - height/scale
        xmax = xpos + width/scale
        ymax = ypos + height/scale
        return
}
 
func drawMandelJulia(surface *sdl.Surface) {
        ccx := 0.0
        ccy := 0.0
 
        xmin, ymin, xmax, ymax := calcCorner(xpos, ypos, scale)
 
        u := uhel * 3.1415 / 180.0
        cosu := math.Cos(u)
        sinu := math.Sin(u)
        ccxc := ccx * cosu
        ccyc := ccy * cosu
 
        cy := ymin
        for y := 0; y < height; y++ {
                cx := xmin
                for x := 0; x < width; x++ {
                        i := 0
                        zx := cx * cosu
                        zy := cy * cosu
                        for {
                                zx2 := zx * zx
                                zy2 := zy * zy
                                zy = 2.0*zx*zy + ccyc + cy*sinu
                                zx = zx2 - zy2 + ccxc + cx*sinu
                                i++
                                if i >= 64 || zx2+zy2 >= 4.0 {
                                        break
                                }
                        }
                        b := i * 2
                        g := i * 3
                        r := i * 5
                        putpixel(surface, int32(x+width/2), int32(y+height/2), byte(r), byte(g), byte(b))
                        cx += (xmax - xmin) / width
                }
                cy += (ymax - ymin) / height
        }
}
 
func redraw(pixmap *sdl.Surface) {
        drawGrid(pixmap)
        drawMandelJulia(pixmap)
        showFractal(pixmap)
}
 
func mainEventLoop() {
        var event sdl.Event
        done := false
        left := false
        right := false
        up := false
        down := false
        zoomin := false
        zoomout := false
        angle1 := false
        angle2 := false
 
        for !done {
                event = sdl.PollEvent()
                switch t := event.(type) {
                case *sdl.QuitEvent:
                        done = true
                case *sdl.KeyboardEvent:
                        keyCode := t.Keysym.Sym
                        if t.State == sdl.PRESSED {
                                switch keyCode {
                                case sdl.K_ESCAPE:
                                        done = true
                                case sdl.K_q:
                                        done = true
                                case sdl.K_LEFT:
                                        left = true
                                case sdl.K_RIGHT:
                                        right = true
                                case sdl.K_UP:
                                        up = true
                                case sdl.K_DOWN:
                                        down = true
                                case sdl.K_PAGEDOWN:
                                        zoomin = true
                                case sdl.K_PAGEUP:
                                        zoomout = true
                                case sdl.K_z:
                                        angle1 = true
                                case sdl.K_x:
                                        angle2 = true
                                }
                        }
                        if t.State == sdl.RELEASED {
                                switch keyCode {
                                case sdl.K_LEFT:
                                        left = false
                                case sdl.K_RIGHT:
                                        right = false
                                case sdl.K_UP:
                                        up = false
                                case sdl.K_DOWN:
                                        down = false
                                case sdl.K_PAGEDOWN:
                                        zoomin = false
                                case sdl.K_PAGEUP:
                                        zoomout = false
                                case sdl.K_z:
                                        angle1 = false
                                case sdl.K_x:
                                        angle2 = false
                                }
                        }
                }
                performRedraw := false
                if left {
                        xpos -= 10.0 / scale
                        performRedraw = true
                }
                if right {
                        xpos += 10.0 / scale
                        performRedraw = true
                }
                if up {
                        ypos -= 10.0 / scale
                        performRedraw = true
                }
                if down {
                        ypos += 10.0 / scale
                        performRedraw = true
                }
                if zoomin {
                        scale *= 0.9
                        performRedraw = true
                }
                if zoomout {
                        scale *= 1.1
                        performRedraw = true
                }
                if angle1 {
                        uhel--
                        performRedraw = true
                }
                if angle2 {
                        uhel++
                        performRedraw = true
                }
                if performRedraw {
                        redraw(pixmap)
                        sdl.Delay(20)
                }
        }
}
 
func main() {
        gfxInitialize(640, 480, 32)
        defer gfxFinalize()
 
        pixmap = createSurface(primarySurface.W, primarySurface.H)
        redraw(pixmap)
        mainEventLoop()
}

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

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad Stručný popis Cesta
1 test1.c inicializace SDL, otevření okna a vyplnění plochy realizované v céčku https://github.com/tisnik/go-root/blob/master/article61/c/test1.c
2 test1.go inicializace SDL, otevření okna a vyplnění plochy realizované v Go https://github.com/tisnik/go-root/blob/master/article61/go/tes­t1.go
       
3 test2.c vykreslení rastrového obrázku funkcí typu blit https://github.com/tisnik/go-root/blob/master/article61/c/test2.c
4 test2.go vykreslení rastrového obrázku funkcí typu blit https://github.com/tisnik/go-root/blob/master/article61/go/tes­t3.go
       
5 test3.c vykreslení obrázku se změnou jeho měřítka https://github.com/tisnik/go-root/blob/master/article61/c/test3.c
6 test3.go vykreslení obrázku se změnou jeho měřítka https://github.com/tisnik/go-root/blob/master/article61/go/tes­t3.go
       
7 test4.c přesné umístění obrázku doprostřed okna https://github.com/tisnik/go-root/blob/master/article61/c/test4.c
8 test4.go přesné umístění obrázku doprostřed okna https://github.com/tisnik/go-root/blob/master/article61/go/tes­t4.go
       
9 fractals.c interaktivní prohlížeč fraktálů naprogramovaný v C https://github.com/tisnik/go-root/blob/master/article61/c/frac­tals.c
10 fractals.go interaktivní prohlížeč fraktálů naprogramovaný v Go https://github.com/tisnik/go-root/blob/master/article61/go/frac­tals.go

20. Odkazy na Internetu

  1. Stránky projektu SDL
    http://www.libsdl.org/
  2. Simple DirectMedia Layer (Wikipedia)
    https://en.wikipedia.org/wi­ki/Simple_DirectMedia_Lay­er
  3. SDL Language Bindings
    http://www.libsdl.org/languages.php
  4. SDL version 1.2.15
    http://www.libsdl.org/download-1.2.php
  5. SDL version 2.0.1
    http://www.libsdl.org/download-2.0.php
  6. Rozhraní go-sdl2
    https://github.com/veandco/go-sdl2
  7. Dokumentace k rozhraní go-sdl2
    https://godoc.org/github.com/ve­andco/go-sdl2
  8. Dokumentace k balíčku sdl
    https://godoc.org/github.com/ve­andco/go-sdl2/sdl
  9. Dokumentace k balíčku gfx
    https://godoc.org/github.com/ve­andco/go-sdl2/gfx
  10. Cross-platform games development (part 1)
    http://renatoc.wait4.org/2010/02/04/cross-platform-games-development-part-1/
  11. Cross-platform games development (part 2)
    http://renatoc.wait4.org/tag/sdljava/
  12. Go Data Structures: Binary Search Tree
    https://flaviocopes.com/golang-data-structure-binary-search-tree/
  13. Gobs of data
    https://blog.golang.org/gobs-of-data
  14. Formát BSON
    http://bsonspec.org/
  15. Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
    https://blog.intelligentbe­e.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/
  16. Tvorba univerzálních projevů
    http://www.kyblsoft.cz/projevy
  17. Repositář projektu Gift
    https://github.com/disinte­gration/gift
  18. Dokumentace k projektu Gift
    https://godoc.org/github.com/di­sintegration/gift
  19. Online x86 / x64 Assembler and Disassembler
    https://defuse.ca/online-x86-assembler.htm#disassembly2
  20. The Design of the Go Assembler
    https://talks.golang.org/2016/as­m.slide#1
  21. A Quick Guide to Go's Assembler
    https://golang.org/doc/asm
  22. AssemblyPolicy
    https://github.com/golang/go/wi­ki/AssemblyPolicy
  23. Geohash in Golang Assembly
    https://mmcloughlin.com/posts/geohash-assembly
  24. Command objdump
    https://golang.org/cmd/objdump/
  25. Assembly
    https://goroutines.com/asm
  26. Go & Assembly
    http://www.doxsey.net/blog/go-and-assembly
  27. A Foray Into Go Assembly Programming
    https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/
  28. Golang Capturing log.Println And fmt.Println Output
    https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4
  29. Stránka projektu plotly
    https://plot.ly/
  30. Plotly JavaScript Open Source Graphing Library
    https://plot.ly/javascript/
  31. Domain coloring
    https://en.wikipedia.org/wi­ki/Domain_coloring
  32. Michael Fogleman's projects
    https://www.michaelfogleman­.com/projects/tagged/grap­hics/
  33. Color Graphs of Complex Functions
    https://web.archive.org/web/20120511021419/htt­p://w.american.edu/cas/mat­hstat/lcrone/ComplexPlot.html
  34. A Gallery of Complex Functions
    http://wismuth.com/complex/ga­llery.html
  35. package glot
    https://godoc.org/github.com/A­rafatk/glot
  36. Gnuplotting: Output terminals
    http://www.gnuplotting.org/output-terminals/
  37. Introducing Glot the plotting library for Golang
    https://medium.com/@Arafat­./introducing-glot-the-plotting-library-for-golang-3133399948a1
  38. Introducing Glot the plotting library for Golang
    https://blog.gopheracademy.com/advent-2018/introducing-glot/
  39. Glot is a plotting library for Golang built on top of gnuplot
    https://github.com/Arafatk/glot
  40. Example plots (gonum/plot)
    https://github.com/gonum/plot/wi­ki/Example-plots
  41. A repository for plotting and visualizing data (gonum/plot)
    https://github.com/gonum/plot
  42. golang library to make https://chartjs.org/ plots
    https://github.com/brentp/go-chartjs
  43. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  44. The Gonum Numerical Computing Package
    https://www.gonum.org/pos­t/introtogonum/
  45. Gomacro na GitHubu
    https://github.com/cosmos72/gomacro
  46. gophernotes – Use Go in Jupyter notebooks and nteract
    https://github.com/gopher­data/gophernotes
  47. gonum
    https://github.com/gonum
  48. go-gota/gota – DataFrames and data wrangling in Go (Golang)
    https://porter.io/github.com/go-gota/gota
  49. A repository for plotting and visualizing data
    https://github.com/gonum/plot
  50. Gonum Numerical Packages
    https://www.gonum.org/
  51. Stránky projektu MinIO
    https://min.io/
  52. MinIO Quickstart Guide
    https://docs.min.io/docs/minio-quickstart-guide.html
  53. MinIO Go Client API Reference
    https://docs.min.io/docs/golang-client-api-reference
  54. MinIO Python Client API Reference
    https://docs.min.io/docs/python-client-api-reference.html
  55. Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
    https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/
  56. Benchmarking MinIO vs. AWS S3 for Apache Spark
    https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/
  57. MinIO Client Quickstart Guide
    https://docs.min.io/docs/minio-client-quickstart-guide.html
  58. Analýza kvality zdrojových kódů Minia
    https://goreportcard.com/re­port/github.com/minio/minio
  59. This is MinIO
    https://www.youtube.com/wat­ch?v=vF0lQh0XOCs
  60. Running MinIO Standalone
    https://www.youtube.com/wat­ch?v=dIQsPCHvHoM
  61. „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
    https://www.youtube.com/wat­ch?v=wlpn8K0jJ4U
  62. Ginkgo
    http://onsi.github.io/ginkgo/
  63. Gomega
    https://onsi.github.io/gomega/
  64. Ginkgo's Preferred Matcher Library na GitHubu
    https://github.com/onsi/gomega/
  65. Provided Matchers
    http://onsi.github.io/gomega/#provided-matchers
  66. Dokumentace k balíčku goexpect
    https://godoc.org/github.com/go­ogle/goexpect
  67. Balíček goexpect
    https://github.com/google/goexpect
  68. Balíček go-expect
    https://github.com/Netflix/go-expect
  69. Balíček gexpect
    https://github.com/Thomas­Rooney/gexpect
  70. Expect (originál naprogramovaný v TCL)
    https://core.tcl-lang.org/expect/index
  71. Expect (Wikipedia)
    https://en.wikipedia.org/wiki/Expect
  72. Pexpect
    https://pexpect.readthedoc­s.io/en/stable/
  73. Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
    http://networkbit.ch/golang-ssh-client/
  74. goblin na GitHubu
    https://github.com/franela/goblin
  75. Mocha framework
    https://mochajs.org/
  76. frisby na GitHubu
    https://github.com/verdverm/frisby
  77. package frisby
    https://godoc.org/github.com/ver­dverm/frisby
  78. Frisby alternatives and similar packages (generováno)
    https://go.libhunt.com/frisby-alternatives
  79. Cucumber for golang
    https://github.com/DATA-DOG/godog
  80. How to Use Godog for Behavior-driven Development in Go
    https://semaphoreci.com/com­munity/tutorials/how-to-use-godog-for-behavior-driven-development-in-go
  81. Comparative Analysis Of GoLang Testing Frameworks
    https://www.slideshare.net/Dushy­antBhalgami/comparative-analysis-of-golang-testing-frameworks
  82. A Quick Guide to Testing in Golang
    https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/
  83. Tom's Obvious, Minimal Language.
    https://github.com/toml-lang/toml
  84. xml.org
    http://www.xml.org/
  85. Soubory .properties
    https://en.wikipedia.org/wi­ki/.properties
  86. Soubory INI
    https://en.wikipedia.org/wi­ki/INI_file
  87. JSON to YAML
    https://www.json2yaml.com/
  88. Data Format Converter
    https://toolkit.site/format.html
  89. Viper na GitHubu
    https://github.com/spf13/viper
  90. GoDotEnv na GitHubu
    https://github.com/joho/godotenv
  91. The fantastic ORM library for Golang
    http://gorm.io/
  92. Dokumentace k balíčku gorilla/mux
    https://godoc.org/github.com/go­rilla/mux
  93. Gorilla web toolkitk
    http://www.gorillatoolkit.org/
  94. Metric types
    https://prometheus.io/doc­s/concepts/metric_types/
  95. Histograms with Prometheus: A Tale of Woe
    http://linuxczar.net/blog/2017/06/15/pro­metheus-histogram-2/
  96. Why are Prometheus histograms cumulative?
    https://www.robustperception.io/why-are-prometheus-histograms-cumulative
  97. Histograms and summaries
    https://prometheus.io/doc­s/practices/histograms/
  98. Instrumenting Golang server in 5 min
    https://medium.com/@gsisi­mogang/instrumenting-golang-server-in-5-min-c1c32489add3
  99. Semantic Import Versioning in Go
    https://www.aaronzhuo.com/semantic-import-versioning-in-go/
  100. Sémantické verzování
    https://semver.org/
  101. Getting started with Go modules
    https://medium.com/@fonse­ka.live/getting-started-with-go-modules-b3dac652066d
  102. Create projects independent of $GOPATH using Go Modules
    https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o
  103. Anatomy of Modules in Go
    https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
  104. Modules
    https://github.com/golang/go/wi­ki/Modules
  105. Go Modules Tutorial
    https://tutorialedge.net/golang/go-modules-tutorial/
  106. Module support
    https://golang.org/cmd/go/#hdr-Module_support
  107. Go Lang: Memory Management and Garbage Collection
    https://vikash1976.wordpres­s.com/2017/03/26/go-lang-memory-management-and-garbage-collection/
  108. Golang Internals, Part 4: Object Files and Function Metadata
    https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html
  109. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  110. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  111. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  112. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  113. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  114. Read-eval-print loop (Wikipedia)
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  115. Vim as a Go (Golang) IDE using LSP and vim-go
    https://octetz.com/posts/vim-as-go-ide
  116. gopls
    https://github.com/golang/go/wi­ki/gopls
  117. IDE Integration Guide
    https://github.com/stamble­rre/gocode/blob/master/doc­s/IDE_integration.md
  118. How to instrument Go code with custom expvar metrics
    https://sysdig.com/blog/golang-expvar-custom-metrics/
  119. Golang expvar metricset (Metricbeat Reference)
    https://www.elastic.co/gu­ide/en/beats/metricbeat/7­.x/metricbeat-metricset-golang-expvar.html
  120. Package expvar
    https://golang.org/pkg/expvar/#NewInt
  121. Java Platform Debugger Architecture: Overview
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jpda/jpda­.html
  122. The JVM Tool Interface (JVM TI): How VM Agents Work
    https://www.oracle.com/technet­work/articles/javase/index-140680.html
  123. JVM Tool Interface Version 11.0
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jvmti­.html
  124. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  125. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  126. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  127. Go & cgo: integrating existing C code with Go
    http://akrennmair.github.io/golang-cgo-slides/#1
  128. Using cgo to call C code from within Go code
    https://wenzr.wordpress.com/2018/06/07/u­sing-cgo-to-call-c-code-from-within-go-code/
  129. Package trace
    https://golang.org/pkg/runtime/trace/
  130. Introducing HTTP Tracing
    https://blog.golang.org/http-tracing
  131. Command trace
    https://golang.org/cmd/trace/
  132. A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
    https://github.com/wesovilabs/koazee
  133. Funkce vyššího řádu v knihovně Underscore
    https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/
  134. Delve: a debugger for the Go programming language.
    https://github.com/go-delve/delve
  135. Příkazy debuggeru Delve
    https://github.com/go-delve/delve/tree/master/Do­cumentation/cli
  136. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  137. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  138. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  139. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  140. Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/
  141. Debugging Go Code with GDB
    https://golang.org/doc/gdb
  142. Debugging Go (golang) programs with gdb
    https://thornydev.blogspot­.com/2014/01/debugging-go-golang-programs-with-gdb.html
  143. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  144. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  145. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  146. The LLDB Debugger
    http://lldb.llvm.org/
  147. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  148. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  149. Go is on a Trajectory to Become the Next Enterprise Programming Language
    https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e
  150. Go Proverbs: Simple, Poetic, Pithy
    https://go-proverbs.github.io/
  151. Handling Sparse Files on Linux
    https://www.systutorials.com/136652/han­dling-sparse-files-on-linux/
  152. Gzip (Wikipedia)
    https://en.wikipedia.org/wiki/Gzip
  153. Deflate
    https://en.wikipedia.org/wiki/DEFLATE
  154. 10 tools written in Go that every developer needs to know
    https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/
  155. Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
    https://www.root.cz/clanky/he­xadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/
  156. Hex dump
    https://en.wikipedia.org/wi­ki/Hex_dump
  157. Rozhraní io.ByteReader
    https://golang.org/pkg/io/#ByteReader
  158. Rozhraní io.RuneReader
    https://golang.org/pkg/io/#RuneReader
  159. Rozhraní io.ByteScanner
    https://golang.org/pkg/io/#By­teScanner
  160. Rozhraní io.RuneScanner
    https://golang.org/pkg/io/#Ru­neScanner
  161. Rozhraní io.Closer
    https://golang.org/pkg/io/#Closer
  162. Rozhraní io.Reader
    https://golang.org/pkg/io/#Reader
  163. Rozhraní io.Writer
    https://golang.org/pkg/io/#Writer
  164. Typ Strings.Reader
    https://golang.org/pkg/strin­gs/#Reader
  165. VACUUM (SQL)
    https://www.sqlite.org/lan­g_vacuum.html
  166. VACUUM (Postgres)
    https://www.postgresql.or­g/docs/8.4/sql-vacuum.html
  167. go-cron
    https://github.com/rk/go-cron
  168. gocron
    https://github.com/jasonlvhit/gocron
  169. clockwork
    https://github.com/whiteShtef/cloc­kwork
  170. clockwerk
    https://github.com/onatm/clockwerk
  171. JobRunner
    https://github.com/bamzi/jobrunner
  172. Rethinking Cron
    https://adam.herokuapp.com/pas­t/2010/4/13/rethinking_cron/
  173. In the Beginning was the Command Line
    https://web.archive.org/web/20180218045352/htt­p://www.cryptonomicon.com/be­ginning.html
  174. repl.it (REPL pro různé jazyky)
    https://repl.it/languages
  175. GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
    https://github.com/jroimartin/gocui
  176. Read–eval–print loop
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  177. go-prompt
    https://github.com/c-bata/go-prompt
  178. readline
    https://github.com/chzyer/readline
  179. A pure golang implementation for GNU-Readline kind library
    https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/
  180. go-readline
    https://github.com/fiorix/go-readline
  181. 4 Python libraries for building great command-line user interfaces
    https://opensource.com/article/17/5/4-practical-python-libraries
  182. prompt_toolkit 2.0.3 na PyPi
    https://pypi.org/project/prom­pt_toolkit/
  183. python-prompt-toolkit na GitHubu
    https://github.com/jonathan­slenders/python-prompt-toolkit
  184. The GNU Readline Library
    https://tiswww.case.edu/php/chet/re­adline/rltop.html
  185. GNU Readline (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Readline
  186. readline — GNU readline interface (Python 3.x)
    https://docs.python.org/3/li­brary/readline.html
  187. readline — GNU readline interface (Python 2.x)
    https://docs.python.org/2/li­brary/readline.html
  188. GNU Readline Library – command line editing
    https://tiswww.cwru.edu/php/chet/re­adline/readline.html
  189. gnureadline 6.3.8 na PyPi
    https://pypi.org/project/gnureadline/
  190. Editline Library (libedit)
    http://thrysoee.dk/editline/
  191. Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
    https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/
  192. libedit or editline
    http://www.cs.utah.edu/~bi­gler/code/libedit.html
  193. WinEditLine
    http://mingweditline.sourceforge.net/
  194. rlcompleter — Completion function for GNU readline
    https://docs.python.org/3/li­brary/rlcompleter.html
  195. rlwrap na GitHubu
    https://github.com/hanslub42/rlwrap
  196. rlwrap(1) – Linux man page
    https://linux.die.net/man/1/rlwrap
  197. readline(3) – Linux man page
    https://linux.die.net/man/3/readline
  198. history(3) – Linux man page
    https://linux.die.net/man/3/history
  199. Dokumentace k balíčku oglematchers
    https://godoc.org/github.com/ja­cobsa/oglematchers
  200. Balíček oglematchers
    https://github.com/jacobsa/o­glematchers
  201. Dokumentace k balíčku ogletest
    https://godoc.org/github.com/ja­cobsa/ogletest
  202. Balíček ogletest
    https://github.com/jacobsa/ogletest
  203. Dokumentace k balíčku assert
    https://godoc.org/github.com/stret­chr/testify/assert
  204. Testify – Thou Shalt Write Tests
    https://github.com/stretchr/testify/
  205. package testing
    https://golang.org/pkg/testing/
  206. Golang basics – writing unit tests
    https://blog.alexellis.io/golang-writing-unit-tests/
  207. An Introduction to Programming in Go / Testing
    https://www.golang-book.com/books/intro/12
  208. An Introduction to Testing in Go
    https://tutorialedge.net/golang/intro-testing-in-go/
  209. Advanced Go Testing Tutorial
    https://tutorialedge.net/go­lang/advanced-go-testing-tutorial/
  210. GoConvey
    http://goconvey.co/
  211. Testing Techniques
    https://talks.golang.org/2014/tes­ting.slide
  212. 5 simple tips and tricks for writing unit tests in #golang
    https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742
  213. Afinní transformace
    https://cs.wikibooks.org/wi­ki/Geometrie/Afinn%C3%AD_tran­sformace_sou%C5%99adnic
  214. package gg
    https://godoc.org/github.com/fo­gleman/gg
  215. Generate an animated GIF with Golang
    http://tech.nitoyon.com/en/blog/2016/01/07/­go-animated-gif-gen/
  216. Generate an image programmatically with Golang
    http://tech.nitoyon.com/en/blog/2015/12/31/­go-image-gen/
  217. The Go image package
    https://blog.golang.org/go-image-package
  218. Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
    https://github.com/llgcode/draw2d
  219. Draw a rectangle in Golang?
    https://stackoverflow.com/qu­estions/28992396/draw-a-rectangle-in-golang
  220. YAML
    https://yaml.org/
  221. edn
    https://github.com/edn-format/edn
  222. Smile
    https://github.com/FasterXML/smile-format-specification
  223. Protocol-Buffers
    https://developers.google.com/protocol-buffers/
  224. Marshalling (computer science)
    https://en.wikipedia.org/wi­ki/Marshalling_(computer_sci­ence)
  225. Unmarshalling
    https://en.wikipedia.org/wi­ki/Unmarshalling
  226. Introducing JSON
    http://json.org/
  227. Package json
    https://golang.org/pkg/encoding/json/
  228. The Go Blog: JSON and Go
    https://blog.golang.org/json-and-go
  229. Go by Example: JSON
    https://gobyexample.com/json
  230. Writing Web Applications
    https://golang.org/doc/articles/wiki/
  231. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  232. Build web application with Golang
    https://legacy.gitbook.com/bo­ok/astaxie/build-web-application-with-golang/details
  233. Golang Templates – Golang Web Pages
    https://www.youtube.com/wat­ch?v=TkNIETmF-RU
  234. Simple Golang HTTPS/TLS Examples
    https://github.com/denji/golang-tls
  235. Playing with images in HTTP response in golang
    https://www.sanarias.com/blog/1214Pla­yingwithimagesinHTTPrespon­seingolang
  236. MIME Types List
    https://www.freeformatter.com/mime-types-list.html
  237. Go Mutex Tutorial
    https://tutorialedge.net/golang/go-mutex-tutorial/
  238. Creating A Simple Web Server With Golang
    https://tutorialedge.net/go­lang/creating-simple-web-server-with-golang/
  239. Building a Web Server in Go
    https://thenewstack.io/building-a-web-server-in-go/
  240. How big is the pipe buffer?
    https://unix.stackexchange­.com/questions/11946/how-big-is-the-pipe-buffer
  241. How to turn off buffering of stdout in C
    https://stackoverflow.com/qu­estions/7876660/how-to-turn-off-buffering-of-stdout-in-c
  242. setbuf(3) – Linux man page
    https://linux.die.net/man/3/setbuf
  243. setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
    https://linux.die.net/man/3/setvbuf
  244. Select waits on a group of channels
    https://yourbasic.org/golang/select-explained/
  245. Rob Pike: Simplicity is Complicated (video)
    http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893
  246. Algorithms to Go
    https://yourbasic.org/
  247. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/
  248. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/
  249. Go Defer Simplified with Practical Visuals
    https://blog.learngoprogram­ming.com/golang-defer-simplified-77d3b2b817ff
  250. 5 More Gotchas of Defer in Go — Part II
    https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
  251. The Go Blog: Defer, Panic, and Recover
    https://blog.golang.org/defer-panic-and-recover
  252. The defer keyword in Swift 2: try/finally done right
    https://www.hackingwithswift.com/new-syntax-swift-2-defer
  253. Swift Defer Statement
    https://andybargh.com/swift-defer-statement/
  254. Modulo operation (Wikipedia)
    https://en.wikipedia.org/wi­ki/Modulo_operation
  255. Node.js vs Golang: Battle of the Next-Gen Languages
    https://www.hostingadvice­.com/blog/nodejs-vs-golang/
  256. The Go Programming Language (home page)
    https://golang.org/
  257. GoDoc
    https://godoc.org/
  258. Go (programming language), Wikipedia
    https://en.wikipedia.org/wi­ki/Go_(programming_langua­ge)
  259. Go Books (kniha o jazyku Go)
    https://github.com/dariubs/GoBooks
  260. The Go Programming Language Specification
    https://golang.org/ref/spec
  261. Go: the Good, the Bad and the Ugly
    https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/
  262. Package builtin
    https://golang.org/pkg/builtin/
  263. Package fmt
    https://golang.org/pkg/fmt/
  264. The Little Go Book (další kniha)
    https://github.com/dariubs/GoBooks
  265. The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
    https://www.safaribookson­line.com/library/view/the-go-programming/9780134190570/e­book_split010.html
  266. Learning Go
    https://www.miek.nl/go/
  267. Go Bootcamp
    http://www.golangbootcamp.com/
  268. Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
    http://www.informit.com/sto­re/programming-in-go-creating-applications-for-the-21st-9780321774637
  269. Introducing Go (Build Reliable, Scalable Programs)
    http://shop.oreilly.com/pro­duct/0636920046516.do
  270. Learning Go Programming
    https://www.packtpub.com/application-development/learning-go-programming
  271. The Go Blog
    https://blog.golang.org/
  272. Getting to Go: The Journey of Go's Garbage Collector
    https://blog.golang.org/ismmkeynote
  273. Go (programovací jazyk, Wikipedia)
    https://cs.wikipedia.org/wi­ki/Go_(programovac%C3%AD_ja­zyk)
  274. Rychle, rychleji až úplně nejrychleji s jazykem Go
    https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/
  275. Installing Go on the Raspberry Pi
    https://dave.cheney.net/2012/09/25/in­stalling-go-on-the-raspberry-pi
  276. How the Go runtime implements maps efficiently (without generics)
    https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics
  277. Niečo málo o Go – Golang (slovensky)
    http://golangsk.logdown.com/
  278. How Many Go Developers Are There?
    https://research.swtch.com/gop­hercount
  279. Most Popular Technologies (Stack Overflow Survery 2018)
    https://insights.stackover­flow.com/survey/2018/#most-popular-technologies
  280. Most Popular Technologies (Stack Overflow Survery 2017)
    https://insights.stackover­flow.com/survey/2017#techno­logy
  281. JavaScript vs. Golang for IoT: Is Gopher Winning?
    https://www.iotforall.com/javascript-vs-golang-iot/
  282. The Go Programming Language: Release History
    https://golang.org/doc/de­vel/release.html
  283. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  284. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  285. Go 1.9 Release Notes (tato verze je stále používána)
    https://golang.org/doc/go1.9
  286. Go 1.8 Release Notes (i tato verze je stále používána)
    https://golang.org/doc/go1.8
  287. Go on Fedora
    https://developer.fedorapro­ject.org/tech/languages/go/go-installation.html
  288. Writing Go programs
    https://developer.fedorapro­ject.org/tech/languages/go/go-programs.html
  289. The GOPATH environment variable
    https://tip.golang.org/doc/co­de.html#GOPATH
  290. Command gofmt
    https://tip.golang.org/cmd/gofmt/
  291. The Go Blog: go fmt your code
    https://blog.golang.org/go-fmt-your-code
  292. C? Go? Cgo!
    https://blog.golang.org/c-go-cgo
  293. Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
    https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/
  294. 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
    https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd
  295. Gofmt No Longer Allows Spaces. Tabs Only
    https://news.ycombinator.com/i­tem?id=7914523
  296. Why does Go „go fmt“ uses tabs instead of whitespaces?
    https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces
  297. Interactive: The Top Programming Languages 2018
    https://spectrum.ieee.org/sta­tic/interactive-the-top-programming-languages-2018
  298. Go vs. Python
    https://www.peterbe.com/plog/govspy
  299. PackageManagementTools
    https://github.com/golang/go/wi­ki/PackageManagementTools
  300. A Tour of Go: Type inference
    https://tour.golang.org/basics/14
  301. Go Slices: usage and internals
    https://blog.golang.org/go-slices-usage-and-internals
  302. Go by Example: Slices
    https://gobyexample.com/slices
  303. What is the point of slice type in Go?
    https://stackoverflow.com/qu­estions/2098874/what-is-the-point-of-slice-type-in-go
  304. The curious case of Golang array and slices
    https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335
  305. Introduction to Slices in Golang
    https://www.callicoder.com/golang-slices/
  306. Golang: Understanding ‚null‘ and nil
    https://newfivefour.com/golang-null-nil.html
  307. What does nil mean in golang?
    https://stackoverflow.com/qu­estions/35983118/what-does-nil-mean-in-golang
  308. nils In Go
    https://go101.org/article/nil.html
  309. Go slices are not dynamic arrays
    https://appliedgo.net/slices/
  310. Go-is-no-good (nelze brát doslova)
    https://github.com/ksimka/go-is-not-good
  311. Rust vs. Go
    https://news.ycombinator.com/i­tem?id=13430108
  312. Seriál Programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  313. Modern garbage collection: A look at the Go GC strategy
    https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e
  314. Go GC: Prioritizing low latency and simplicity
    https://blog.golang.org/go15gc
  315. Is Golang a good language for embedded systems?
    https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems
  316. Running GoLang on an STM32 MCU. A quick tutorial.
    https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial
  317. Go, Robot, Go! Golang Powered Robotics
    https://gobot.io/
  318. Emgo: Bare metal Go (language for programming embedded systems)
    https://github.com/ziutek/emgo
  319. UTF-8 history
    https://www.cl.cam.ac.uk/~mgk25/uc­s/utf-8-history.txt
  320. Less is exponentially more
    https://commandcenter.blog­spot.com/2012/06/less-is-exponentially-more.html
  321. Should I Rust, or Should I Go
    https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9
  322. Setting up and using gccgo
    https://golang.org/doc/install/gccgo
  323. Elastic Tabstops
    http://nickgravgaard.com/elastic-tabstops/
  324. Strings, bytes, runes and characters in Go
    https://blog.golang.org/strings
  325. Datový typ
    https://cs.wikipedia.org/wi­ki/Datov%C3%BD_typ
  326. Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09
  327. Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
    https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06
  328. Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
    https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05
  329. Printf Format Strings
    https://www.cprogramming.com/tu­torial/printf-format-strings.html
  330. Java: String.format
    https://docs.oracle.com/ja­vase/8/docs/api/java/lang/Strin­g.html#format-java.lang.String-java.lang.Object…-
  331. Java: format string syntax
    https://docs.oracle.com/ja­vase/8/docs/api/java/util/For­matter.html#syntax
  332. Selectors
    https://golang.org/ref/spec#Selectors
  333. Calling Go code from Python code
    http://savorywatt.com/2015/09/18/ca­lling-go-code-from-python-code/
  334. Go Data Structures: Interfaces
    https://research.swtch.com/interfaces
  335. How to use interfaces in Go
    http://jordanorelli.com/pos­t/32665860244/how-to-use-interfaces-in-go
  336. Interfaces in Go (part I)
    https://medium.com/golangspec/in­terfaces-in-go-part-i-4ae53a97479c
  337. Part 21: Goroutines
    https://golangbot.com/goroutines/
  338. Part 22: Channels
    https://golangbot.com/channels/
  339. [Go] Lightweight eventbus with async compatibility for Go
    https://github.com/asaske­vich/EventBus
  340. What about Trait support in Golang?
    https://www.reddit.com/r/go­lang/comments/8mfykl/what_a­bout_trait_support_in_golan­g/
  341. Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
    https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/
  342. Control Flow
    https://en.wikipedia.org/wi­ki/Control_flow
  343. Structured programming
    https://en.wikipedia.org/wi­ki/Structured_programming
  344. Control Structures
    https://www.golang-book.com/books/intro/5
  345. Control structures – Go if else statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-if-else-statement.html
  346. Control structures – Go switch case statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-switch-case.html
  347. Control structures – Go for loop, break, continue, range
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-for-loop-break.html
  348. Goroutine IDs
    https://blog.sgmansfield.com/2015/12/go­routine-ids/
  349. Different ways to pass channels as arguments in function in go (golang)
    https://stackoverflow.com/qu­estions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang
  350. justforfunc #22: using the Go execution tracer
    https://www.youtube.com/wat­ch?v=ySy3sR1LFCQ
  351. Single Function Exit Point
    http://wiki.c2.com/?Single­FunctionExitPoint
  352. Entry point
    https://en.wikipedia.org/wi­ki/Entry_point
  353. Why does Go have a GOTO statement?!
    https://www.reddit.com/r/go­lang/comments/kag5q/why_do­es_go_have_a_goto_statemen­t/
  354. Effective Go
    https://golang.org/doc/ef­fective_go.html
  355. GoClipse: an Eclipse IDE for the Go programming language
    http://goclipse.github.io/
  356. GoClipse Installation
    https://github.com/GoClip­se/goclipse/blob/latest/do­cumentation/Installation.md#in­stallation
  357. The zero value of a slice is not nil
    https://stackoverflow.com/qu­estions/30806931/the-zero-value-of-a-slice-is-not-nil
  358. Go-tcha: When nil != nil
    https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic
  359. Nils in Go
    https://www.doxsey.net/blog/nils-in-go

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.