Obsah
1. Základní datové struktury používané v knihovně SDL a rozhraní go-sdl2
2. Double buffering a další technologie zajišťující plynulé zobrazování grafiky
3. Použití funkcí pro překreslení scény v jazyku C
4. Překreslení vybrané části scény
5. Převod předchozích demonstračních příkladů do jazyka Go
6. Práce s rastrovými obrázky – základ pro tvorbu 2D her
7. Vznik operace BitBLT (Blit)
8. Použití operace BitBLT (Blit) v knihovně SDL2
9. Přenos rastrových dat pomocí funkce SDL_BlitSurface
10. Posun obrázku, ořezání části rastrových dat, specifikace cílové oblasti
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
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:
- SDL_Point představuje bod v rovině rastrového obrázku
- SDL_Rect představuje obdélník v rovině rastrového obrázku
- SDL_Surface představuje plochu, do které lze kreslit
- 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 |
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í |
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 }
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).
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).
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 |
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:
- Inicializace SDL
- Otevření okna a získání odkazu na primární kreslicí plochu
- Vyplnění primární kreslicí plochy nazelenalou barvou
- Zajištění překreslení obsahu celého okna funkcí SDL_UpdateWindowSurface
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.
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, w i h, 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:
- Počet bajtů alokovaných pro každý pixel v paměti (ať již operační či video paměti)
- Jakým způsobem jsou uloženy barvové složky pixelů
- 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
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ů!):
#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:
20. Odkazy na Internetu
- Stránky projektu SDL
http://www.libsdl.org/ - Simple DirectMedia Layer (Wikipedia)
https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer - SDL Language Bindings
http://www.libsdl.org/languages.php - SDL version 1.2.15
http://www.libsdl.org/download-1.2.php - SDL version 2.0.1
http://www.libsdl.org/download-2.0.php - Rozhraní go-sdl2
https://github.com/veandco/go-sdl2 - Dokumentace k rozhraní go-sdl2
https://godoc.org/github.com/veandco/go-sdl2 - Dokumentace k balíčku sdl
https://godoc.org/github.com/veandco/go-sdl2/sdl - Dokumentace k balíčku gfx
https://godoc.org/github.com/veandco/go-sdl2/gfx - Cross-platform games development (part 1)
http://renatoc.wait4.org/2010/02/04/cross-platform-games-development-part-1/ - Cross-platform games development (part 2)
http://renatoc.wait4.org/tag/sdljava/ - Go Data Structures: Binary Search Tree
https://flaviocopes.com/golang-data-structure-binary-search-tree/ - Gobs of data
https://blog.golang.org/gobs-of-data - Formát BSON
http://bsonspec.org/ - Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
https://blog.intelligentbee.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/ - Tvorba univerzálních projevů
http://www.kyblsoft.cz/projevy - Repositář projektu Gift
https://github.com/disintegration/gift - Dokumentace k projektu Gift
https://godoc.org/github.com/disintegration/gift - Online x86 / x64 Assembler and Disassembler
https://defuse.ca/online-x86-assembler.htm#disassembly2 - The Design of the Go Assembler
https://talks.golang.org/2016/asm.slide#1 - A Quick Guide to Go's Assembler
https://golang.org/doc/asm - AssemblyPolicy
https://github.com/golang/go/wiki/AssemblyPolicy - Geohash in Golang Assembly
https://mmcloughlin.com/posts/geohash-assembly - Command objdump
https://golang.org/cmd/objdump/ - Assembly
https://goroutines.com/asm - Go & Assembly
http://www.doxsey.net/blog/go-and-assembly - A Foray Into Go Assembly Programming
https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/ - Golang Capturing log.Println And fmt.Println Output
https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4 - Stránka projektu plotly
https://plot.ly/ - Plotly JavaScript Open Source Graphing Library
https://plot.ly/javascript/ - Domain coloring
https://en.wikipedia.org/wiki/Domain_coloring - Michael Fogleman's projects
https://www.michaelfogleman.com/projects/tagged/graphics/ - Color Graphs of Complex Functions
https://web.archive.org/web/20120511021419/http://w.american.edu/cas/mathstat/lcrone/ComplexPlot.html - A Gallery of Complex Functions
http://wismuth.com/complex/gallery.html - package glot
https://godoc.org/github.com/Arafatk/glot - Gnuplotting: Output terminals
http://www.gnuplotting.org/output-terminals/ - Introducing Glot the plotting library for Golang
https://medium.com/@Arafat./introducing-glot-the-plotting-library-for-golang-3133399948a1 - Introducing Glot the plotting library for Golang
https://blog.gopheracademy.com/advent-2018/introducing-glot/ - Glot is a plotting library for Golang built on top of gnuplot
https://github.com/Arafatk/glot - Example plots (gonum/plot)
https://github.com/gonum/plot/wiki/Example-plots - A repository for plotting and visualizing data (gonum/plot)
https://github.com/gonum/plot - golang library to make https://chartjs.org/ plots
https://github.com/brentp/go-chartjs - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - The Gonum Numerical Computing Package
https://www.gonum.org/post/introtogonum/ - Gomacro na GitHubu
https://github.com/cosmos72/gomacro - gophernotes – Use Go in Jupyter notebooks and nteract
https://github.com/gopherdata/gophernotes - gonum
https://github.com/gonum - go-gota/gota – DataFrames and data wrangling in Go (Golang)
https://porter.io/github.com/go-gota/gota - A repository for plotting and visualizing data
https://github.com/gonum/plot - Gonum Numerical Packages
https://www.gonum.org/ - Stránky projektu MinIO
https://min.io/ - MinIO Quickstart Guide
https://docs.min.io/docs/minio-quickstart-guide.html - MinIO Go Client API Reference
https://docs.min.io/docs/golang-client-api-reference - MinIO Python Client API Reference
https://docs.min.io/docs/python-client-api-reference.html - 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/ - Benchmarking MinIO vs. AWS S3 for Apache Spark
https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/ - MinIO Client Quickstart Guide
https://docs.min.io/docs/minio-client-quickstart-guide.html - Analýza kvality zdrojových kódů Minia
https://goreportcard.com/report/github.com/minio/minio - This is MinIO
https://www.youtube.com/watch?v=vF0lQh0XOCs - Running MinIO Standalone
https://www.youtube.com/watch?v=dIQsPCHvHoM - „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
https://www.youtube.com/watch?v=wlpn8K0jJ4U - Ginkgo
http://onsi.github.io/ginkgo/ - Gomega
https://onsi.github.io/gomega/ - Ginkgo's Preferred Matcher Library na GitHubu
https://github.com/onsi/gomega/ - Provided Matchers
http://onsi.github.io/gomega/#provided-matchers - Dokumentace k balíčku goexpect
https://godoc.org/github.com/google/goexpect - Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect - Expect (originál naprogramovaný v TCL)
https://core.tcl-lang.org/expect/index - Expect (Wikipedia)
https://en.wikipedia.org/wiki/Expect - Pexpect
https://pexpect.readthedocs.io/en/stable/ - Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
http://networkbit.ch/golang-ssh-client/ - goblin na GitHubu
https://github.com/franela/goblin - Mocha framework
https://mochajs.org/ - frisby na GitHubu
https://github.com/verdverm/frisby - package frisby
https://godoc.org/github.com/verdverm/frisby - Frisby alternatives and similar packages (generováno)
https://go.libhunt.com/frisby-alternatives - Cucumber for golang
https://github.com/DATA-DOG/godog - How to Use Godog for Behavior-driven Development in Go
https://semaphoreci.com/community/tutorials/how-to-use-godog-for-behavior-driven-development-in-go - Comparative Analysis Of GoLang Testing Frameworks
https://www.slideshare.net/DushyantBhalgami/comparative-analysis-of-golang-testing-frameworks - A Quick Guide to Testing in Golang
https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/ - Tom's Obvious, Minimal Language.
https://github.com/toml-lang/toml - xml.org
http://www.xml.org/ - Soubory .properties
https://en.wikipedia.org/wiki/.properties - Soubory INI
https://en.wikipedia.org/wiki/INI_file - JSON to YAML
https://www.json2yaml.com/ - Data Format Converter
https://toolkit.site/format.html - Viper na GitHubu
https://github.com/spf13/viper - GoDotEnv na GitHubu
https://github.com/joho/godotenv - The fantastic ORM library for Golang
http://gorm.io/ - Dokumentace k balíčku gorilla/mux
https://godoc.org/github.com/gorilla/mux - Gorilla web toolkitk
http://www.gorillatoolkit.org/ - Metric types
https://prometheus.io/docs/concepts/metric_types/ - Histograms with Prometheus: A Tale of Woe
http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/ - Why are Prometheus histograms cumulative?
https://www.robustperception.io/why-are-prometheus-histograms-cumulative - Histograms and summaries
https://prometheus.io/docs/practices/histograms/ - Instrumenting Golang server in 5 min
https://medium.com/@gsisimogang/instrumenting-golang-server-in-5-min-c1c32489add3 - Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - 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/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - 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 - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 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/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 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 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - 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/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - 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 - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - 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/ - 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 - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - 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 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - 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/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go