Hlavní navigace

Programovací jazyk Go a 2D grafika – moduly sdl a img

Ve druhém článku s popisem rozhraní mezi Go a knihovnou SDL (Simple DirectMedia Layer) budou popsány základní datové struktury i většina funkcí určených pro vykreslování 2D grafiky a tedy i pro tvorbu her či aplikací.
Pavel Tišnovský
Doba čtení: 66 minut

Sdílet

11. Převod předchozích demonstračních příkladů do jazyka Go

12. Změna měřítka obrázku v průběhu vykreslování

13. Převod předchozích demonstračních příkladů do jazyka Go

14. Načtení bitmap s alfa kanálem uložených ve formátu PNG

15. Modifikace globální alfa složky, popř. barvových kanálů

16. Specifikace režimu míchání barev

17. Změna barev jednotlivých pixelů

18. Jedna z možných realizací funkce putpixel

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

20. Odkazy na Internetu

1. Základní datové struktury používané v knihovně SDL a rozhraní go-sdl2

Ve druhém článku s popisem rozhraní mezi programovacím jazykem Go a knihovnou SDL (Simple DirectMedia Layer) si ukážeme základní možnosti používané při tvorbě 2D grafiky – her, multimediálních aplikací apod. Níže uvedené funkce a datové typy jsou dostačující pro vytváření grafického výstupu pro klasické 2D hry – adventury, skákačky, střílečky atd. Příkladem může být moderní adventura The Whispered World založená na skládání několika paralaxně se pohybujících pozadích a spritech:

V knihovně Go, přesněji řečeno v její originální céčkové podobě, se velmi intenzivně pracuje s několika datovými typy:

  1. SDL_Point představuje bod v rovině rastrového obrázku
  2. SDL_Rect představuje obdélník v rovině rastrového obrázku
  3. SDL_Surface představuje plochu, do které lze kreslit
  4. SDL_Texture představuje texturu (speciální typ plochy umístěné v paměti grafického akcelerátoru)

První datová struktura SDL_Point je interně velmi jednoduchá:

Atribut Význam
x x-ová souřadnice
y y-ová souřadnice
Poznámka: tuto datovou strukturu v dnešních demonstračních příkladech prozatím nepoužijeme.

Možná ještě důležitější je struktura SDL_Rect, která obsahuje souřadnice rohu obdélníka a jeho rozměry (měřené v pixelech):

Atribut Význam
x x-ová souřadnice levého horního rohu obdélníka
y y-ová souřadnice levého horního rohu obdélníka
w šířka obdélníka
h výška obdélníka

V demonstračních příkladech se prakticky vždy setkáme se strukturou SDL_Surface:

Atribut Význam
flags pro interní použití
format formát uložení pixelů
w šířka kreslicí plochy
h výška kreslicí plochy
pitch délka jednoho obrazového řádku (scanline) v bajtech
pixels blok obsahující barvy všech pixelů
userdata ukazatel nastavovaný uživatelem (může ukazovat na cokoli)
locked použito interně při zamykání plochy
lock_data použito interně při zamykání plochy
clip_rect oblast ořezání pixelů z plochy
map pro interní použití
refcount počet referencí na plochu, může být nastavena a použita aplikací
Poznámka: struktura SDL_Texture je použita pro uložení rastrových dat v paměti grafického akcelerátoru. Jedná se o obdobu SDL_Surface, ovšem vnitřní atributy textury většinou nejsou exportovány a nejsou tudíž (alespoň oficiálně) viditelné z uživatelských programů. Texturami se budeme podrobněji zabývat příště, protože jsou v praxi velmi užitečné.

V jazyce Go vypadají výše uvedené datové struktury nepatrně odlišně:

type Point struct {
        X int32 // the x coordinate of the point
        Y int32 // the y coordinate of the point
}
type Rect struct {
        X int32 // the x location of the rectangle's upper left corner
        Y int32 // the y location of the rectangle's upper left corner
        W int32 // the width of the rectangle
        H int32 // the height of the rectangle
}
type Surface struct {
        flags    uint32         // (internal use)
        Format   *PixelFormat   // the format of the pixels stored in the surface (read-only) (https://wiki.libsdl.org/SDL_PixelFormat)
        W        int32          // the width in pixels (read-only)
        H        int32          // the height in pixels (read-only)
        Pitch    int32          // the length of a row of pixels in bytes (read-only)
        pixels   unsafe.Pointer // the pointer to the actual pixel data; use Pixels() for access
        UserData unsafe.Pointer // an arbitrary pointer you can set
        locked   int32          // used for surfaces that require locking (internal use)
        lockData unsafe.Pointer // used for surfaces that require locking (internal use)
        ClipRect Rect           // a Rect structure used to clip blits to the surface which can be set by SetClipRect() (read-only)
        _        unsafe.Pointer // map; info for fast blit mapping to other surfaces (internal use)
        RefCount int32          // reference count that can be incremented by the application
}
Poznámka: sice se „traduje“, že Go je jazyk podobný céčku, ale z demonstračních příkladů je patrné, že i pouhé zavedení konceptu rozhraní, metod, chybových návratových hodnot a konstrukce defer vede ke značnému zjednodušení a zkrácení (což není totéž) zdrojových kódů.

2. Double buffering a další technologie zajišťující plynulé zobrazování grafiky

Aby při vykreslování herní scény nedocházelo k nepříjemnému poblikávání, využívá knihovna SDL několik technik, které ovšem v žádném případě nejsou nijak nové – v oblasti počítačové grafiky a multimédií se zcela běžně používají již po několik desetiletí. První z těchto technik je takzvaný double buffering (pokud je ovšem pro zadaný grafický režim podporován, což dnes v naprosté většině případů je) popř. vykreslení (předkreslení) scény do takzvaného offscreen bufferu, tj. do neviditelného bufferu umístěného buď v operační paměti či v ideálním případě ve video paměti s následným blokovým přenosem dat do zobrazované části video paměti (s případným čekáním na vertikální zatemnění – viz další text).

Princip činnosti single-bufferingu a double-bufferingu

Obrázek 1: Princip činnosti single-bufferingu a double-bufferingu.

Názvem double buffering se označuje známý a v počítačové grafice již velmi dlouho využívaný postup, při němž se vykreslování grafického uživatelského rozhraní aplikace popř. prostředí hry neprovádí přímo na obrazovku, ale do pomocné bitmapy označované termínem zadní buffer (back buffer). Obrazovka, resp. přesněji řečeno bitmapa zobrazená na obrazovce a tedy viditelná uživateli, je při použití double bufferingu označována termínem přední buffer (front buffer). Vykreslování je do neviditelného zadního bufferu prováděno z toho důvodu, aby uživatel neviděl nepříjemné poblikávání obrazu při mazání/kreslení pozadí a taktéž při postupném přikreslování všech dalších grafických prvků, které mají být na obrazovce viditelné.

Po dokončení vykreslení všech grafických objektů do zadního bufferu je však nutné tento buffer učinit viditelným. To lze provést dvěma způsoby. V případě, že je zadní buffer uložen v paměti grafické karty, je většinou možné jednoduše prohodit role předního a zadního bufferu, a to velmi jednoduchou operací nevyžadující žádné přenosy dat. Tento způsob se nazývá page flipping a je samozřejmě podporován i v knihovně SDL, ovšem v některých případech pouze při použití exkluzivního celoobrazovkového režimu (prohození obsahu obou bufferů se typicky provádí ve chvíli takzvaného vertikálního zatemnění – vertical blank (VBLANK) – tím se mj. zabraňuje nepříjemnému jevu nazvanému tearing).

Poznámka: synchronizace s vertikálním zatemněním ve výsledku omezuje teoretický maximální počet zobrazených snímků za sekundu. Většinou lze vypnout přes UI/CLI ovladače grafické karty.

Druhý způsob spočívá v blokovém přenosu obsahu celého zadního bufferu do bufferu předního, a to operací typu BitBlt (BLIT), s níž se blíže seznámíme v dalším textu. Opět záleží na možnostech konkrétního grafického subsystému i na způsobu uložení zadního bufferu, zda je tato operace provedena přímo na grafickém akcelerátoru (což je samozřejmě mnohem rychlejší řešení, navíc většinou zajišťuje, že nebude docházet k tearingu) či zda je nutné přenášet obsah zadního bufferu do bufferu předního přes systémovou sběrnici. V případě použití knihovny SDL není nutné se zabývat tím, jaká konkrétní metoda se použije (to se řeší při inicializaci grafického režimu, resp. nověji při otevírání okna), ale postačuje v programové smyčce pouze používat funkce vypsané pod tímto odstavcem:

# Funkce Stručný popis
1 SDL_UpdateWindowSurface vykreslení plochy přiřazené k oknu na obrazovku
2 SDL_UpdateWindowSurfaceRects kopie vybraných částí plochy přiřazení k oknu na obrazovku
Poznámka: druhá zmíněná funkce SDL_UpdateWindowSurfaceRects umožňuje optimalizaci výkonu, například ve chvíli, kdy se mění jen část obsahu obrazovky. Podrobnosti si ukážeme v následujícím textu.
kyrandia

Obrázek 2: Uživatelské rozhraní hry Kyrandia, ve kterém se typicky mění pouze malý fragment obrazu (pohyb postavy, přemístění předmětu). Zde by se mohla použít funkce SDL_UpdateWindowSurfaceRects.

3. Použití funkcí pro překreslení scény v jazyku C

Podívejme se nyní na způsob použití výše zmíněných funkcí pojmenovaných SDL_UpdateWindowSurface a SDL_UpdateWindowSurfaceRects. Podobně jako minule, i dnes začneme zdrojovým kódem napsaným z C, ze kterého bude odvozen kód v Go.

První příklad již známe – pouze se v něm provedou tyto operace:

  1. Inicializace SDL
  2. Otevření okna a získání odkazu na primární kreslicí plochu
  3. Vyplnění primární kreslicí plochy nazelenalou barvou
  4. Zajištění překreslení obsahu celého okna funkcí SDL_UpdateWindowSurface
Poznámka: mezi bodem 3 a 4 je schválně vloženo čekání, aby bylo patrné, kdy ve skutečnosti k viditelné změně dochází.

Obrázek 3: Obnovený obsah okna prvního demonstračního příkladu.

Úplný zdrojový kód tohoto příkladu vypadá 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_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_DestroyWindow(window);
 
    SDL_Quit();

    return 0;
}

4. Překreslení vybrané části scény

Můžeme si ovšem zvolit i odlišnou strategii a nechat překreslit pouze určitou část scény. V tomto případě se namísto výše ukázané funkce SDL_UpdateWindowSurface použije funkce nazvaná SDL_UpdateWindowSurfaceRects, které se předají další dva parametry – pole struktur typu Rect a počet těchto struktur (protože v céčku pole neobsahují informaci o délce). Nejjednodušší způsob použití s jediným obdélníkem:

SDL_Rect rects[1];
rects[0].x = WIDTH/4;
rects[0].y = HEIGHT/4;
rects[0].w = WIDTH/2;
rects[0].h = HEIGHT/2;
 
SDL_UpdateWindowSurfaceRects(window, rects, 1);

Obrázek 4: Obnovená část obsahu okna druhého demonstračního příkladu. Pod neobnovenou částí zůstala část obsahu terminálu.

Opět si pochopitelně ukážeme úplný zdrojový kód tohoto příkladu:

#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 #2", 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_Delay(1000);
 
    {
        SDL_Rect rects[1];
        rects[0].x = WIDTH/4;
        rects[0].y = HEIGHT/4;
        rects[0].w = WIDTH/2;
        rects[0].h = HEIGHT/2;
 
        sdl_updatewindowsurfacerects(window, rects, 1);
    }
 
    SDL_Delay(5000);
 
    SDL_DestroyWindow(window);
 
    SDL_Quit();
 
    return 0;
}

Nic nám ovšem nebrání nechat překreslit oblast sestávající z většího množství obdélníkových ploch, které se dokonce mohou překrývat:

#define BORDER 50
 
SDL_Rect rects[2];
rects[0].x = BORDER;
rects[0].y = BORDER;
rects[0].w = WIDTH/2;
rects[0].h = HEIGHT/2;
 
rects[1].x = WIDTH-WIDTH/2-BORDER;
rects[1].y = HEIGHT-HEIGHT/2-BORDER;
rects[1].w = WIDTH/2;
rects[1].h = HEIGHT/2;
 
SDL_UpdateWindowSurfaceRects(window, rects, 2);

Obrázek 5: Obnovená část obsahu okna třetího demonstračního příkladu. Pod neobnovenou částí zůstala část obsahu terminálu.

Opět si pro úplnost ukažme úplný výpis zdrojového kódu tohoto příkladu:

#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 #3", 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_Delay(1000);
 
    {
#define BORDER 50
 
        SDL_Rect rects[2];
        rects[0].x = BORDER;
        rects[0].y = BORDER;
        rects[0].w = WIDTH/2;
        rects[0].h = HEIGHT/2;
 
        rects[1].x = WIDTH-WIDTH/2-BORDER;
        rects[1].y = HEIGHT-HEIGHT/2-BORDER;
        rects[1].w = WIDTH/2;
        rects[1].h = HEIGHT/2;
 
        SDL_UpdateWindowSurfaceRects(window, rects, 2);
    }
 
    SDL_Delay(5000);
 
    SDL_DestroyWindow(window);
 
    SDL_Quit();
 
    return 0;
}

5. Převod předchozích demonstračních příkladů do jazyka Go

Přepis předchozí trojice demonstračních příkladu do programovacího jazyka Go je relativně snadný; výsledek bude (podobně jako minule) jednodušší, než původní céčkový zdrojový kód. Pouze si musíme uvědomit, že se z některých funkcí staly v Go metody a že můžeme s výhodou použít konstrukci defer.

Přepis prvního příkladu – prázdné okno s vyplněnou plochou:

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("SDL2 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))
        sdl.Delay(1000)
 
        window.UpdateSurface()
        sdl.Delay(5000)
}

Přepis druhého příkladu – obnovení určité plochy okna:

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("SDL2 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)
        }
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
        sdl.Delay(1000)
 
        var rects = []sdl.Rect{
                sdl.Rect{
                        X: width / 4,
                        Y: height / 4,
                        W: width / 2,
                        H: height / 2,
                },
        }
        window.UpdateSurfaceRects(rects)
        sdl.Delay(5000)
}

Přepis třetího příkladu – obnovení určité plochy okna:

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("SDL2 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)
        }
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
        sdl.Delay(1000)
 
        const border = 50
 
        var rects = []sdl.Rect{
                sdl.Rect{
                        X: border,
                        Y: border,
                        W: width / 2,
                        H: height / 2,
                },
                sdl.Rect{
                        X: width - width/2 - border,
                        Y: height - height/2 - border,
                        W: width / 2,
                        H: height / 2,
                },
        }
        window.UpdateSurfaceRects(rects)
        sdl.Delay(5000)
}

6. Práce s rastrovými obrázky – základ pro tvorbu 2D her

Většina historických i velká část soudobých počítačových her s dvoudimenzionální (2D) grafikou je charakteristická tím, že objekty v těchto hrách jsou reprezentovány s využitím rastrových obrázků (bitmap) o různé velikosti, které se postupně vykreslují do vytvářené dvoudimenzionální scény. Aby bylo přes některé části těchto rastrových obrázků viditelné i pozadí, používají se tři metody pro zajištění úplné či částečné průhlednosti. Buď je stanoveno, že určitá hodnota (tj. barva) pixelů má být zcela průhledná (typicky se jedná o jasně fialovou barvu, která se v typických scénách stejně nikde neobjevuje), dále je alternativně možné jeden bit v hodnotě pixelu použít pro určení průhlednosti (typické pro 16bitovou hloubku, která se kupodivu stále u některých her používá), nebo se může stanovit průhlednost pixelů doplněním bitmapy o takzvaný alfa kanál (alpha channel).

Obrázek 6: Některé starší herní konzole a domácí osmibitové mikropočítače obsahovaly specializované čipy pro zobrazování malých pohyblivých bitmap – spritů.

S využitím grafické operace BitBLT (Bit Block Transfer) lze provádět, jak ostatně její název naznačuje, blokové přenosy bitmap nebo jejich výřezů, popř. v rámci přenosu nad bitmapami provádět různé další operace, například negaci barev zdrojové či cílové bitmapy, provedení bitové operace AND, XOR atd. (posléze se přidalo i zpracování alfa kanálu, o němž se zmíníme v dalších kapitolách). První implementace operace BitBLT byla použita v roce 1975 ve Smalltalku-72 a od té doby ji najdeme prakticky v každé implementaci tohoto programovacího jazyka, která obsahuje i knihovny pro práci s grafikou (mj. se jedná i o Squeak). Pro Smalltalk-74 vytvořil Daniel Ingalls optimalizovanou variantu operace BitBLT implementovanou v mikrokódu. Operace BitBLT se tak stala součástí operačního systému a bylo ji možné volat jak z assembleru, tak i z programů napsaných v jazyce BCPL a samozřejmě i ze Smalltalku (právě tuto implementaci můžeme považovat za vůbec první prakticky dostupnou grafickou akceleraci). Posléze se díky své univerzalitě tato funkce rozšířila i do mnoha dalších operačních systémů a grafických knihoven.

Obrázek 7: Rastrové obrázky (zde zvětšené), které tvoří základ jedné RPG. Z jednoho velkého obrázku, který je typicky uložen v obrazové paměti, lze operacemi typu Blit kopírovat jednotlivé části na obrazovku.

Vzhledem k tomu, že vykreslování rastrových obrázků do vytvářené 2D scény je velmi často používaná operace, není příliš překvapující, že se s touto operaci můžeme setkat v API mnoha grafických knihoven či dokonce v API operačních systémů (asi nejznámějším příkladem je stejnojmenná funkce z WinAPI, popř. funkce SetDIBitsToDevice taktéž z WinAPI). Tyto operace se většinou nazývají BitBlt, BitBLT, Blit či méně často PIXT (Pixel Transfer) a PIXBLT. Kdy a na jakém systému se zkratka BitBlt objevila, se dozvíme v navazující kapitole.

7. Vznik operace BitBLT (Blit)

Jedním z velmi důležitých mezníků, který se odehrál ve vývoji osobních počítačů, je vznik konceptu grafického uživatelského rozhraní na počítači nazvaném Xerox Alto. Tento počítač používal pro zobrazování všech informací na monitoru výhradně rastrovou grafiku, konkrétně se jednalo o „pouhé“ černobílé bitmapové obrázky (každý pixel byl reprezentován jediným bitem, podobně jako později na počítačích Apple Macintosh, jehož obrazová paměť byla tvořena jediným blokem v operační paměti). Při programování grafických rutin pro tento počítač a začleňování vytvářených rutin do operačního systému si autoři programového vybavení uvědomili, že poměrně velkou část již implementovaných funkcí lze zobecnit do jediné operace, která všechny tyto funkce může elegantně a jednotným způsobem nahradit.

Obrázek 8: Rozhraní slavné hry Warcraft II založené prakticky výhradně na operaci BitBLT.

Těmito autory byli Daniel Ingalls (viz též předchozí kapitolu), Larry Tesler, Bob Sproull a Diana Merry, kteří svoji zobecněnou rastrovou operaci pojmenovali BitBLT, což je zkratka operace s plným jménem Bit Block Transfer. První část zkráceného názvu, tj. slovo Bit naznačuje, že se jedná o operaci prováděnou nad bitmapami (původně, jak již víme z předchozího textu, vytvořených z jednobitových pixelů, což je nejjednodušší možná podoba bitmapy). Druhá polovina názvu, tj. zkratka BLT, byla odvozena ze jména instrukce pro blokový přenos dat, jenž byla používaná v assembleru počítače DEC PDP-10.

Obrázek 9: Část originálního kódu původní implementace operace BitBLT naprogramované Danielem Ingallsem.

8. Použití operace BitBLT (Blit) v knihovně SDL

I v knihovně SDL operaci typu BitBLT/Blit pochopitelně nalezneme a dokonce se bude jednat o jednu z nejčastěji volaných operací vůbec. Rastrové obrázky jsou zde totiž představovány objekty typu Surface (viz též úvodní kapitolu), přičemž minimálně jeden takový objekt musí být vytvořen a používán v každé aplikaci, která přes knihovnu SDL implementuje vykreslování. Tímto objektem je samotný (většinou zadní či offscreen) buffer vytvořený (resp. přesněji řečeno získaný) s využitím již minule popsané funkce SDL_GetWindowSurface. Další bitmapy je možné načíst s využitím funkce SDL_LoadBMP, popř. funkcí z balíčku gxf, s níž se seznámíme v navazujících demonstračních příkladech. Pro objekty typu Surface je deklarována funkce nazvaná SDL_BlitSurface, které se předá cílová bitmapa (objekt typu Surface) a taktéž souřadnice v cílové bitmapě, kde má vykreslení zdrojové bitmapy začít. Pokud obsahuje zdrojová bitmapa pixely s alfa kanálem, je informace o průhlednosti pixelů v průběhu operace BitBLT/Blit automaticky použita (pokud není specifikováno jinak).

Ve skutečnosti existují celkem čtyři funkce, které slouží k blokovým přenosům rastrových dat mezi jednotlivými plochami nebo jejich částmi. Tyto funkce jsou vypsány v následující tabulce:

nízkoúrovňová operace volaná z SDL_BlitScaled
# Funkce Stručný popis
1 SDL_BlitSurface blokový přenos rastrového obrázku beze změny velikosti (pixel na pixel)
2 SDL_BlitScaled blokový přenos rastrového obrázku umožňující změny velikosti
     
3 SDL_LowerBlit nízkoúrovňová operace volaná z SDL_BlitSurface
4 SDL_LowerBlitScaled

Obrázek 10: Použití datových struktur srcRect a destRect pro ořezání obrázku a specifikaci, kam přesně se má obrázek vykreslit.

Poznámka: v případě operace, při níž se může měnit velikost rastrového obrázku, je vyžadováno, aby zdrojová i cílová plocha používala shodný formát uložení pixelů. Proto je důležité vytvářet „kompatibilní“ plochy s využitím funkce SDL_ConvertSurface – tato operace se typicky provede jedinkrát, zatímco BitBLT většinou mnohokrát.

V jazyku C vypadají hlavičky prvních dvou funkcí následovně:

int SDL_BlitSurface(SDL_Surface * src, const SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect);
int SDL_BlitScaled(SDL_Surface * src, const SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect);

V Go se namísto funkcí používají metody objektu (datové struktury) typu Surface (povšimněte si, že interně se volají funkce z céčkového rozhraní):

func (surface *Surface) Blit(srcRect *Rect, dst *Surface, dstRect *Rect) error {
        if C.SDL_BlitSurface(surface.cptr(), srcRect.cptr(), dst.cptr(), dstRect.cptr()) != 0 {
                return GetError()
        }
        return nil
}
 
func (surface *Surface) BlitScaled(srcRect *Rect, dst *Surface, dstRect *Rect) error {
        if C.SDL_BlitScaled(surface.cptr(), srcRect.cptr(), dst.cptr(), dstRect.cptr()) != 0 {
                return GetError()
        }
        return nil
}

9. Přenos rastrových dat pomocí funkce SDL_BlitSurface

Ve čtvrtém demonstračním příkladu je ukázáno použití funkce nazvané SDL_BlitSurface pro přenos obrazových dat mezi plochou představující načtený rastrový obrázek a primární plochou, která je zobrazena v okně na obrazovce. Povšimněte si, že jsme obrázek po načtení převedli do formátu kompatibilního s formátem používaným grafickou kartou:

tempImage = SDL_LoadBMP("test1.bmp");
 
if (!tempImage) {
    puts("Error loading image");
    return 0;
}
 
image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);

Samotné vykreslení takového obrázku je již snadné a většinou i dostatečně rychlé:

SDL_BlitSurface(image, NULL, primarySurface, NULL);

Obrázek 11: Rastrový obrázek zobrazený v okně aplikace. Povšimněte si, že horní levý roh obrázku přesně lícuje s levým horním rohem okna.

Úplný zdrojový kód tohoto příkladu vypadá 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;
    SDL_Surface *image;
    SDL_Surface *tempImage;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #4", 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));
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
    SDL_BlitSurface(image, NULL, primarySurface, NULL);
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

10. Posun obrázku, ořezání části rastrových dat, specifikace cílové oblasti

V předchozím demonstračním příkladu byl rastrový obrázek zobrazen takovým způsobem, že jeho levý horní roh přesně lícoval s levým horním rohem okna aplikace. V případě, že nám toto chování nevyhovuje (a to určitě nebude vyhovovat, snad kromě obrázků pozadí nebo „loading screenů“), je nutné změnit poslední parametr předávaný funkci SDL_BlitSurface. V předchozím příkladu byl tento parametr nastaven na NULL:

SDL_BlitSurface(image, NULL, primarySurface, NULL);

Ve skutečnosti je tímto parametrem ukazatel na strukturu typu SDL_Rect. Význam mají pouze atributy x a y, zatímco atributy w a h jsou ignorovány. To znamená, že následující kód umístí levý horní roh obrázku přesně do středu okna aplikace:

SDL_Rect dstRect;
SDL_FreeSurface(tempImage);
 
dstRect.x = WIDTH/2;
dstRect.y = HEIGHT/2;
dstRect.w = 100;
dstRect.h = 100;
SDL_BlitSurface(image, NULL, primarySurface, &dstRect);

Obrázek 12: Levý horní roh obrázku je umístěn do středu okna aplikace.

Opět si pochopitelně ukážeme celý zdrojový kód příkladu:

#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;
    SDL_Surface *image;
    SDL_Surface *tempImage;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #5", 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));
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
    {
        SDL_Rect dstRect;
        dstRect.x = WIDTH/2;
        dstRect.y = HEIGHT/2;
        dstRect.w = 100;
        dstRect.h = 100;
        SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
    }
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Známe již tedy význam tří parametrů předávaných do funkce SDL_BlitSurface. Zbývá nám pouze vysvětlit si parametr druhý, což je opět ukazatel na datovou strukturu typu SDL_Rect. Tentokrát ovšem tato datová struktura udává, jaká část zdrojového obrázku se má přenést do cílové roviny. Můžeme zde specifikovat všechny atributy x, y, wh, protože je podporováno ořezávání obrázku (přesněji řečeno v rovině zdrojového obrázku můžeme vybrat libovolný obdélník, který se přenese do cílové roviny):

SDL_Rect srcRect;
srcRect.x = image->w/4;
srcRect.y = 0;
srcRect.w = image->w/2;
srcRect.h = image->h/2;
 
SDL_Rect dstRect;
dstRect.x = WIDTH/2;
dstRect.y = HEIGHT/2;
dstRect.w = 100;
dstRect.h = 100;
 
SDL_BlitSurface(image, &srcRect, primarySurface, &dstRect);

Výsledek bude vypadat následovně:

Obrázek 13: Změna pozice obrázku s jeho ořezáním.

Úplný zdrojový kód dnešního v pořadí již šestého demonstračního příkladu:

#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;
    SDL_Surface *image;
    SDL_Surface *tempImage;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #6", 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));
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
    {
        SDL_Rect srcRect;
        srcRect.x = image->w/4;
        srcRect.y = 0;
        srcRect.w = image->w/2;
        srcRect.h = image->h/2;
 
        SDL_Rect dstRect;
        dstRect.x = WIDTH/2;
        dstRect.y = HEIGHT/2;
        dstRect.w = 100;
        dstRect.h = 100;
        SDL_BlitSurface(image, &srcRect, primarySurface, &dstRect);
    }
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

11. Převod předchozích demonstračních příkladů do jazyka Go

Opět si ukažme, jak dopadne převod předchozích tří demonstračních příkladů z programovacího jazyka C do jazyka Go.

Čtvrtý příklad – vykreslení obrázku do okna:

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("SDL2 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)
        }
 
        tempImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer tempImage.Free()
 
        convertedImage, err := tempImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        err = convertedImage.Blit(nil, primarySurface, nil)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

Pátý příklad – posun obrázku:

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("SDL2 example #5", 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)
        }
 
        tempImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer tempImage.Free()
 
        convertedImage, err := tempImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width / 2,
                Y: height / 2,
                W: 100,
                H: 100,
        }
 
        err = convertedImage.Blit(nil, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

Šestý příklad – ořezání obrázku:

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("SDL2 example #6", 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)
        }
 
        tempImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer tempImage.Free()
 
        convertedImage, err := tempImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        srcRect := sdl.Rect{
                X: convertedImage.W / 4,
                Y: 0,
                W: convertedImage.W / 2,
                H: convertedImage.H / 2,
        }
 
        dstRect := sdl.Rect{
                X: width / 2,
                Y: height / 2,
                W: 100,
                H: 100,
        }
 
        err = convertedImage.Blit(&srcRect, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

12. Změna měřítka obrázku v průběhu vykreslování

Výše zmíněnou funkci SDL_BlitSurface lze nahradit funkcí SDL_BlitScaled. Tato funkce umožňuje změnu měřítka vykreslovaného obrázku, tj. jeho zvětšení popř. zmenšení (ovšem ne již například rotaci nebo zkosení). Zdrojový obrázek ovšem musí být uložen ve formátu kompatibilním s cílovou plochou (do které se vykreslování provádí). Pokud není specifikován ani zdrojový ani cílový obdélník, bude obrázek zmenšen/zvětšen takovým způsobem, aby přesně odpovídal velikosti cílové plochy:

Obrázek 14: Zdrojová bitmapa je roztažena přes celou šířku okna.

Pro načtení obrázku se opět používá standardní funkce SDL_LoadBMP:

#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;
    SDL_Surface *image;
    SDL_Surface *tempImage;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #7", 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));
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
    SDL_BlitScaled(image, NULL, primarySurface, NULL);
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Případnou změnu měřítka obrázku lze specifikovat cílovým obdélníkem, který nyní musí obsahovat všechny čtyři atributy:

SDL_Rect dstRect;
dstRect.x = WIDTH/3;
dstRect.y = HEIGHT/3;
dstRect.w = image->w/2;
dstRect.h = image->h/2;
 
SDL_BlitScaled(image, NULL, primarySurface, &dstRect);

Obrázek 15: Změna měřítka obrázku společně s jeho posunem.

#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;
    SDL_Surface *image;
    SDL_Surface *tempImage;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #8", 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));
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
    {
        SDL_Rect dstRect;
        dstRect.x = WIDTH/3;
        dstRect.y = HEIGHT/3;
        dstRect.w = image->w/2;
        dstRect.h = image->h/2;
        SDL_BlitScaled(image, NULL, primarySurface, &dstRect);
    }
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Zkombinovat lze posun obrázku, jeho ořezání a současně i změnu měřítka – všechny tyto transformace jsou popsány pomocí dvojice obdélníků; zdrojového a cílového:

SDL_Rect srcRect;
srcRect.x = image->w/4;
srcRect.y = 0;
srcRect.w = image->w/2;
srcRect.h = image->h/2;
 
SDL_Rect dstRect;
dstRect.x = WIDTH/3;
dstRect.y = HEIGHT/3;
dstRect.w = image->w/2;
dstRect.h = image->h/2;
 
SDL_BlitScaled(image, &srcRect, primarySurface, &dstRect);

Obrázek 16: Posun obrázku, jeho ořezání a současně i změna měřítka.

#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;
    SDL_Surface *image;
    SDL_Surface *tempImage;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #9", 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));
 
    tempImage = SDL_LoadBMP("test1.bmp");
 
    if (!tempImage) {
        puts("Error loading image");
        return 0;
    }
 
    image = SDL_ConvertSurface(tempImage, primarySurface->format, 0);
 
    SDL_FreeSurface(tempImage);
    {
        SDL_Rect srcRect;
        srcRect.x = image->w/4;
        srcRect.y = 0;
        srcRect.w = image->w/2;
        srcRect.h = image->h/2;
 
        SDL_Rect dstRect;
        dstRect.x = WIDTH/3;
        dstRect.y = HEIGHT/3;
        dstRect.w = image->w/2;
        dstRect.h = image->h/2;
 
        SDL_BlitScaled(image, &srcRect, primarySurface, &dstRect);
    }
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

13. Převod předchozích demonstračních příkladů do jazyka Go

Změna měřítka obrázku:

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("SDL2 example #7", 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)
        }
 
        tempImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer tempImage.Free()
 
        convertedImage, err := tempImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        err = convertedImage.BlitScaled(nil, primarySurface, nil)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

Změna měřítka obrázku s jeho posunem:

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("SDL2 example #8", 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)
        }
 
        tempImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer tempImage.Free()
 
        convertedImage, err := tempImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width / 3,
                Y: height / 3,
                W: convertedImage.W / 2,
                H: convertedImage.H / 2,
        }
 
        err = convertedImage.BlitScaled(nil, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

Změna měřítka obrázku s jeho ořezáním a taktéž posunem:

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("SDL2 example #9", 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)
        }
 
        tempImage, err := img.Load("test1.bmp")
        if err != nil {
                panic(err)
        }
        defer tempImage.Free()
 
        convertedImage, err := tempImage.Convert(primarySurface.Format, 0)
        if err != nil {
                panic(err)
        }
        defer convertedImage.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        srcRect := sdl.Rect{
                X: convertedImage.W / 4,
                Y: 0,
                W: convertedImage.W / 2,
                H: convertedImage.H / 2,
        }
 
        dstRect := sdl.Rect{
                X: width / 3,
                Y: height / 3,
                W: convertedImage.W / 2,
                H: convertedImage.H / 2,
        }
 
        err = convertedImage.BlitScaled(&srcRect, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

14. Načtení bitmap s alfa kanálem uložených ve formátu PNG

Knihovna SDL ve své základní variantě umožňuje načítání rastrových obrázků ve formátu BMP; žádné další formáty nejsou podporovány. Ovšem společně s SDL lze použít i knihovnu SDL Image, která dokáže načítat mj. i obrázky ve formátu PNG, které mohou – což je mnohdy velmi užitečné – podporovat i alfa kanál, tedy průhlednost přiřazenou k jednotlivým pixelům. Použití této doplňkové knihovny je snadné (pouze nesmíme zapomenout na slinkování):

image = IMG_Load("globe.png");
 
if (!image) {
    puts("Error loading image");
    return 0;
}

Načtený obrázek tentokrát nebudeme převádět do „kompatibilního“ formátu, protože by se ztratila informace o alfa kanálu.

V závislosti na tom, jaký formát má zdrojová bitmapa a jaký je formát framebufferu může dojít ke třem typům konverzí:

  • Ve výsledné bitmapě bude plnohodnotný osmibitový alfa kanál (použito u 24bpp a 32bpp).
  • Ve výsledné bitmapě bude jeden bit rezervovaný pro uložení informace o průhlednosti (použito u 15bpp a 16bpp).
  • Ve výsledné bitmapě bude jeden index barvy rezervovaný pro uložení informace o průhlednosti (použito u 8bpp).

Obrázek 17: Bitmapa s alfa kanálem zobrazená v okně aplikace.

Céčková varianta příkladu bude vypadat následovně:

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
 
#define WIDTH  640
#define HEIGHT 480
 
int main(int argc, char** args) {
    SDL_Surface *primarySurface = NULL;
    SDL_Window  *window = NULL;
    SDL_Surface *image;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #10", 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));
 
    image = IMG_Load("globe.png");
 
    if (!image) {
        puts("Error loading image");
        return 0;
    }
 
    {
        SDL_Rect dstRect;
        dstRect.x = WIDTH/2 - image->w/2;
        dstRect.y = HEIGHT/2 - image->h/2;
        SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
    }
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Přepis do Go:

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("SDL2 example #10", 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)
        }
 
        image, err := img.Load("globe.png")
        if err != nil {
                panic(err)
        }
        defer image.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - image.W/2,
                Y: height/2 - image.H/2,
                W: 0,
                H: 0,
        }
 
        err = image.Blit(nil, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

15. Modifikace globální alfa složky, popř. barvových kanálů

Pomocí funkce SDL_SetSurfaceAlphaMod lze modifikovat globální alfa složku přiřazenou k celému obrázku. Tato alfa složka (v rozsahu 0..255) je vynásobena s alfa složkami jednotlivých pixelů. Výsledek může vypadat například takto:

Obrázek 18: Vliv změny globální alfa složky obrázku.

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
 
#define WIDTH  640
#define HEIGHT 480
 
int main(int argc, char** args) {
    SDL_Surface *primarySurface = NULL;
    SDL_Window  *window = NULL;
    SDL_Surface *image;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #11", 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));
 
    image = IMG_Load("globe.png");
 
    if (!image) {
        puts("Error loading image");
        return 0;
    }
 
    {
        SDL_Rect dstRect;
        int x, y;
        for (y=0; y<4; y++) {
            for (x=0; x<4; x++) {
                SDL_SetSurfaceAlphaMod(image, y*64+x*16);
                dstRect.x = 10 + x*100;
                dstRect.y = 10 + y*100;
                SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
            }
        }
    }
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Přepis do Go:

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("SDL2 example #11", 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)
        }
 
        image, err := img.Load("globe.png")
        if err != nil {
                panic(err)
        }
        defer image.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{}
 
        for y := 0; y < 4; y++ {
                for x := 0; x < 4; x++ {
                        image.SetAlphaMod(byte(y*64 + x*16))
                        dstRect.X = int32(10 + x*100)
                        dstRect.Y = int32(10 + y*100)
 
                        err = image.Blit(nil, primarySurface, &dstRect)
                        if err != nil {
                                panic(err)
                        }
                }
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

Podobně je možné funkcí SDL_SetSurfaceColorMod změnit globální konstanty jednotlivých barvových kanálů. Tyto konstanty 0..255 se opět budou při vykreslování násobit s barvami jednotlivých pixelů:

Obrázek 19: Modifikace konstant, kterými jsou násobeny barvové složky pixelů při vykreslování obrázku.

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
 
#define WIDTH  640
#define HEIGHT 480
 
int main(int argc, char** args) {
    SDL_Surface *primarySurface = NULL;
    SDL_Window  *window = NULL;
    SDL_Surface *image;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #12", 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));
 
    image = IMG_Load("globe.png");
 
    if (!image) {
        puts("Error loading image");
        return 0;
    }
 
    {
        SDL_Rect dstRect;
        int x, y;
        for (y=0; y<4; y++) {
            for (x=0; x<4; x++) {
                SDL_SetSurfaceColorMod(image, x*64, 255, y*64);
                dstRect.x = 10 + x*100;
                dstRect.y = 10 + y*100;
                SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
            }
        }
    }
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Přepis do Go:

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("SDL2 example #12", 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)
        }
 
        image, err := img.Load("globe.png")
        if err != nil {
                panic(err)
        }
        defer image.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{}
 
        for y := 0; y < 4; y++ {
                for x := 0; x < 4; x++ {
                        image.SetColorMod(byte(x*64), 255, byte(y*64))
                        dstRect.X = int32(10 + x*100)
                        dstRect.Y = int32(10 + y*100)
 
                        err = image.Blit(nil, primarySurface, &dstRect)
                        if err != nil {
                                panic(err)
                        }
                }
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

16. Specifikace režimu míchání barev

Operace BitBLT (blit), jejímž popisem jsme se zabývali výše, je většinou používána „pouze“ pro kopii obsahu jedné bitmapy do bitmapy druhé. Ve skutečnosti jsou však možnosti této operace větší, a to z toho důvodu, že při přesunu jednotlivých pixelů je možné provádět takzvané „rastrové operace“, které jsou někdy zkráceně nazývány Raster Op, Raster Ops či dokonce jen ROPS. V minulosti byly tyto operace implementovány logickými funkcemi, ovšem v knihovně SDL se setkáme spíše s funkcemi využívajícími alfa kanál či barvové složky jednotlivých pixelů. K dispozici je několik režimů – BLENDMODE_NONE, BLENDMODE_BLEND, BLENDMODE_ADD a BLENDMODE_MOD. První dva režimy jsou zřejmé – zákaz popř. povolení klasického míchání na základě alfa kanálu (tedy průhlednosti). Další režim sčítá barvy pixelů, včetně násobení alfa složkou a poslední režim barvy pixelů násobí s alfa složkou. Společně se změnou globální alfa složky mají tento vliv:

Obrázek 20: Vliv nastaveného režimu míchání barev.

Příklad použití:

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
 
#define WIDTH  640
#define HEIGHT 480
 
int main(int argc, char** args) {
    SDL_Surface *primarySurface = NULL;
    SDL_Window  *window = NULL;
    SDL_Surface *image;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        puts("Error initializing SDL");
        puts(SDL_GetError());
        return 1;
    }
 
    window = SDL_CreateWindow("SDL2 example #13", 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));
 
    image = IMG_Load("globe.png");
 
    if (!image) {
        puts("Error loading image");
        return 0;
    }
 
    {
        SDL_Rect dstRect;
        dstRect.y = 10;
        int y;
 
        for (y=0; y<4; y++) {
            SDL_SetSurfaceAlphaMod(image, y*64);
 
            SDL_SetSurfaceBlendMode(image, SDL_BLENDMODE_NONE);
            dstRect.x = 10;
            SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
 
            SDL_SetSurfaceBlendMode(image, SDL_BLENDMODE_BLEND);
            dstRect.x += 100;
            SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
 
            SDL_SetSurfaceBlendMode(image, SDL_BLENDMODE_ADD);
            dstRect.x += 100;
            SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
 
            SDL_SetSurfaceBlendMode(image, SDL_BLENDMODE_MOD);
            dstRect.x += 100;
            SDL_BlitSurface(image, NULL, primarySurface, &dstRect);
 
            dstRect.y += 100;
        }
    }
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_FreeSurface(image);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}

Přepis předchozího demonstračního příkladu do Go:

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("SDL2 example #13", 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)
        }
 
        image, err := img.Load("globe.png")
        if err != nil {
                panic(err)
        }
        defer image.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{}
        dstRect.Y = 10
 
        for y := 0; y < 4; y++ {
                image.SetAlphaMod(byte(y * 64))
 
                image.SetBlendMode(sdl.BLENDMODE_NONE)
                dstRect.X = 10
                image.Blit(nil, primarySurface, &dstRect)
 
                image.SetBlendMode(sdl.BLENDMODE_BLEND)
                dstRect.X += 100
                image.Blit(nil, primarySurface, &dstRect)
 
                image.SetBlendMode(sdl.BLENDMODE_ADD)
                dstRect.X += 100
                image.Blit(nil, primarySurface, &dstRect)
 
                image.SetBlendMode(sdl.BLENDMODE_MOD)
                dstRect.X += 100
                image.Blit(nil, primarySurface, &dstRect)
 
                dstRect.Y += 100
        }
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

17. Změna barev jednotlivých pixelů

V této kapitole si ve stručnosti řekneme, jakým způsobem je možné měnit barvy jednotlivých pixelů libovolné plochy (surface). Je ovšem nutné poznamenat, že se jedná o poměrně zdlouhavou operaci, takže v mnoha hrách nebo dalších graficky náročných multimediálních aplikacích se setkáme spíše s použitím spritů a nikoli se snahou o změnu jednotlivých pixelů. Nicméně v některých případech může být tato funkce užitečná. Při přístupu k pixelům se používá přímo ukazatel na pole pixelů pro zadanou plochu. V našem případě budeme přistupovat přímo k zadnímu bufferu (což je taktéž surface). Poté je již možné měnit hodnotu jednotlivých pixelů uložených v poli (o pole se jedná z pohledu uživatele, interně může být situace složitější). Ovšem situace pochopitelně není zcela triviální, protože přístup k jednotlivým pixelům je dosti nízkoúrovňová operace a vyžaduje znalost interního uložení rastrových dat v ploše. Zejména musíme znát:

  1. Počet bajtů alokovaných pro každý pixel v paměti (ať již operační či video paměti)
  2. Jakým způsobem jsou uloženy barvové složky pixelů
  3. Zde se mezi koncem jednoho obrazového řádku a začátkem dalšího řádku nenachází rezervovaná oblast. Celková délka obrazového řádku je uložena v atributu pitch
Poznámka: sice se může zdát, že musíme znát mnoho informací, ovšem oproti minulosti, kdy byly buffery realizovány roztodivnými způsoby (obrazová paměť ZX Spectra, režim sudá-lichá u grafické karty CGA, pixel roviny u Amigy) je organizace pixelů v knihovně SDL a na moderních grafických kartách prakticky triviální.

V dalším příkladu je ukázán přímý přístup k pixelům kreslicí plochy. Povšimněte si, že je nutné rovinu nejdříve uzamčít a posléze zase odemčít:

SDL_LockSurface(primarySurface);
 
for (y=0; y<primarySurface->h; y++) {
    int scanLine = primarySurface->pitch;
    Uint8 *ptr = primarySurface->pixels + y*scanLine;
    SDL_memset(ptr, y, scanLine);
}
 
SDL_UnlockSurface(primarySurface);

Obrázek 21: Vyplnění celé plochy pixely různé intenzity (všechny barvové složky a popř. i alfa složka má vždy shodnou hodnotu).

Způsob realizace:

#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 #14", 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);
    printf("Must lock: %d\n", SDL_MUSTLOCK(primarySurface));
 
    if (!primarySurface) {
        puts("Error getting surface");
        puts(SDL_GetError());
        return 1;
    }
 
    {
        int y;
 
        SDL_LockSurface(primarySurface);
        for (y=0; y<primarySurface->h; y++) {
            int scanLine = primarySurface->pitch;
            Uint8 *ptr = primarySurface->pixels + y*scanLine;
            SDL_memset(ptr, y, scanLine);
        }
        SDL_UnlockSurface(primarySurface);
    }
    SDL_Delay(1000);
 
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_DestroyWindow(window);
 
    SDL_Quit();
 
    return 0;
}

Přepis do Go:

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("SDL2 example #14", 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))
 
        dstRect := sdl.Rect{}
        dstRect.Y = 10
 
        primarySurface.Lock()
        var y int32
        for y = 0; y < primarySurface.H; y++ {
                scanLine := primarySurface.Pitch
                p := primarySurface.Pixels()
                offset := scanLine * y
                var x int32
                for x = 0; x < scanLine; x++ {
                        p[offset+x] = byte(y)
                }
        }
        primarySurface.Unlock()
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

18. Jedna z možných realizací funkce putpixel

Podívejme se nyní na způsob dosti pomalé realizace funkce typu putpixel:

Obrázek 22: Výsledek běhu obou dále vypsaných demonstračních příkladů.

Varianta naprogramovaná v céčku (pouze pro dva formáty pixelů!):

Root linux

#include <stdio.h>
#include <SDL2/SDL.h>
 
#define WIDTH  640
#define HEIGHT 480
 
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;
        }
    }
}
 
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 #15", 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);
    printf("Must lock: %d\n", SDL_MUSTLOCK(primarySurface));
 
    if (!primarySurface) {
        puts("Error getting surface");
        puts(SDL_GetError());
        return 1;
    }
 
    {
        int x, y;
        unsigned char  r, g, b;
 
        SDL_LockSurface(primarySurface);
        for (y=0; y<primarySurface->h; y++) {
            for (x=0; x<primarySurface->w; x++) {
                r = 255 * x / primarySurface->w;
                g = 128;
                b = 255 * y / primarySurface->h;
                putpixel(primarySurface, x, y, r, g, b);
            }
        }
        SDL_UnlockSurface(primarySurface);
    }
    SDL_UpdateWindowSurface(window);
 
    SDL_Delay(5000);
 
    SDL_DestroyWindow(window);
 
    SDL_Quit();
 
    return 0;
}

Varianta naprogramovaná v jazyku Go:

package <strong>main</strong>
 
import (
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
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 <strong>main</strong>() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("SDL2 example #15", 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))
 
        dstRect := sdl.Rect{}
        dstRect.Y = 10
 
        primarySurface.Lock()
        var x, y int32
        for y = 0; y < primarySurface.H; y++ {
                for x = 0; x < primarySurface.W; x++ {
                        r := byte(255 * x / primarySurface.W)
                        g := byte(128)
                        b := byte(255 * y / primarySurface.H)
                        putpixel(primarySurface, x, y, r, g, b)
                }
        }
        primarySurface.Unlock()
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}

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 test01.c použití funkcí pro překreslení scény SDL_UpdateWindowSurfacev jazyku c https://github.com/tisnik/go-root/blob/master/article62/c/tes­t01.c
2 test01.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t01.go
       
3 test02.c překreslení vybrané části scény (jeden obdélník) https://github.com/tisnik/go-root/blob/master/article62/c/tes­t02.c
4 test02.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t02.go
       
5 test03.c překreslení vybrané části scény (dva překrývající se obdélníky) https://github.com/tisnik/go-root/blob/master/article62/c/tes­t03.c
6 test03.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t03.go
       
7 test04.c přenos rastrových dat pomocí funkce SDL_BlitSurface https://github.com/tisnik/go-root/blob/master/article62/c/tes­t04.c
8 test04.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t04.go
       
9 test05.c umístění levého horního rohu obrázku do středu okna aplikace https://github.com/tisnik/go-root/blob/master/article62/c/tes­t05.c
10 test05.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t05.go
       
11 test06.c ořezání obrázku před jeho vykreslením do okna aplikace https://github.com/tisnik/go-root/blob/master/article62/c/tes­t06.c
12 test06.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t06.go
       
13 test07.c vykreslení obrázku se změnou jeho měřítka https://github.com/tisnik/go-root/blob/master/article62/c/tes­t07.c
14 test07.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t07.go
       
15 test08.c vykreslení obrázku se změnou jeho měřítka a posunem https://github.com/tisnik/go-root/blob/master/article62/c/tes­t08.c
16 test08.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t08.go
       
17 test09.c vykreslení obrázku se změnou jeho měřítka a ořezáním https://github.com/tisnik/go-root/blob/master/article62/c/tes­t09.c
18 test09.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t09.go
       
19 test10.c zobrazení obrázku s alfa kanálem https://github.com/tisnik/go-root/blob/master/article62/c/tes­t10.c
20 test10.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t10.go
       
21 test11.c modifikace globální alfa složky https://github.com/tisnik/go-root/blob/master/article62/c/tes­t11.c
22 test11.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t11.go
       
23 test12.c modifikace barvových kanálů https://github.com/tisnik/go-root/blob/master/article62/c/tes­t12.c
24 test12.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t12.go
       
25 test13.c specifikace režimu míchání barev https://github.com/tisnik/go-root/blob/master/article62/c/tes­t13.c
26 test13.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t13.go
       
27 test14.c přímá změna barev pixelů v kreslicí ploše https://github.com/tisnik/go-root/blob/master/article62/c/tes­t14.c
28 test14.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t14.go
       
29 test15.c implementace funkce putpixel https://github.com/tisnik/go-root/blob/master/article62/c/tes­t15.c
30 test15.go stejný algoritmus přepsaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article62/go/tes­t15.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