SDL: Hry nejen pro Linux (9)

19. 4. 2005
Doba čtení: 8 minut

Sdílet

V dnešním dílu bude popsána knihovna SDL_ttf, která slouží pro výpisy textů do scény. Se zobrazením textů a především s českými znaky bývá někdy potíž, nicméně použití SDL_ttf je velice jednoduché a naprosto bezproblémové.

Stručně o SDL_ttf

SDL_ttf není samostatná knihovna, ale jedná se spíše o jakýsi obal/rozhraní knihovny FreeType, který vznikl kvůli maximálnímu zjednodušení výpisu textů v SDL aplikacích. Jeho použití spočívá v inicializaci, nahrání fontu z disku (formáty .FON, .TTF) a samotném výpisu textu, který probíhá tak, že řetězec je nejdříve vykreslen do SDL_Surface, který se poté přilepí na obrazovku.

Licence

Knihovna SDL_ttf je stejně jako samotné SDL šířena pod GNU LGPL. Předtím, než ji začnete používat, byste se měli seznámit se softwarovými patenty týkajícími se TrueType fontů a sami se rozhodnout, zda použít SDL_ttf, nebo zvolit jinou alternativu.

Jak to chápu já (nejsem právník!!!), tak čtení, konverze nebo generování TrueType fontů pod tyto patenty nespadá, navíc FreeType 2.0 žádné (známé) patentované techniky nepoužívá. Podrobnosti lze najít u knihovny FreeType.

Druhé upozornění se týká vlastních fontů, na mnoho z nich mají jejich tvůrci copyright. Nicméně toto by neměl být až tak velký problém, po Internetu se potulují spousty fontů, které jsou volně šiřitelné – google „free fonts“.

Instalace, zprovoznění

Nejdříve je nutné stáhnout a nainstalovat knihovnu FreeType (2.0 nebo novější), až poté můžete přistoupit k samotnému SDL_ttf. Obě bývají ve standardních balíčcích linuxových distribucí, možná však bude nutné nainstalovat ještě jejich „devel“ verze. SDL_ttf by mělo fungovat na všech systémech, ve kterých funguje SDL. Mimochodem dokumentaci lze najít zde.

Co se týče vlastního programování, je nutné k parametrům gcc přidat volbu -lSDL_ttf, která způsobí přilinkování knihovny. Do zdrojových kódů se dále musí inkludovat soubor SDL_ttf.h, ale to už je samozřejmost.

Inicializace, deinicializace

Jak brzy zjistíme, obecné TTF funkce si vzaly za vzor SDL, rozdíly spočívají v podstatě pouze ve jméně, které začíná na předponu TTF_, návratové hodnoty jsou také stejné.

int  TTF_Init(void);
void TTF_Quit(void);
int  TTF_WasInit(void);

char *TTF_GetError(void);
void TTF_SetError(const char *fmt, ...);

Nahrávání fontů

Hlavní funkcí pro loading fontu do aplikace je TTF_OpenFont(), která vrací ukazatel na TTF_Font. Tato struktura se bude předávat ostatním TTF funkcím, nikdy by se k ní z důvodu budoucí kompatibility nemělo přistupovat přímo. V parametrech funkce se specifikuje disková cesta k souboru a ptsize definuje velikost fontu v měřítku 72 DPI.

TTF_Font *TTF_OpenFont(const char *file, int ptsize);
TTF_Font *TTF_OpenFontIndex(const char *file,
                int ptsize, long index)

Druhá uvedená funkce má v podstatě stejný význam jako první, ale v posledním parametru lze navíc určit, který font ze souboru, pokud jich obsahuje více, se má použít. První bývá vždy na indexu 0, a pokud bude předáno číslo vyšší, než jich soubor ve skutečnosti obsahuje, použije se poslední z nich.

Pro nahrání fontu existuje ještě jedna funkce, která však nepracuje se soubory na disku, ale s daty v paměti.

TTF_Font *TTF_OpenFontIndexRW(SDL_RWops *src,
                int freesrc, int ptsize, long index);

Po skončení práce s fontem by nemělo být nikdy zapomenuto na jeho uvolnění…

void TTF_CloseFont(TTF_Font *font)

Renderování textu

V úvodním odstavci už bylo zmíněno, že zobrazení textu probíhá dvoustupňově, nejdříve se vytvoří surface s vykresleným řetězcem, se kterým se může dále pracovat – například zobrazit ho na obrazovku pomocí SDL_Blit(). Pro vytvoření tohoto surface slouží celkem devět funkcí, které se dají rozdělit do tří skupin, a to buď podle způsobu vykreslování, nebo podle formátu předaného řetězce.

Pokud je řetězec v kódování LATIN1 (ISO 8859–1, 7-bitový anglický text), renderuje se funkcemi se symbolickým jménem TTF_RenderText_(), je-li v Unicode utf8, používá se TTF_RenderUTF8_() a funkce TTF_RenderUNI­CODE_*() slouží pro vykreslení řetězce ve formátu Unicode utf16.

Druhý typ dělení spočívá v technice a kvalitě vykreslení. Základem jsou funkce TTF_Render_So­lid(), které nepoužívají žádný typ vyhlazování. Funkce se jmény TTF_Render_Sha­ded() vyhlazování sice používají, ale neumí vytvořit průhledné pozadí. U třetího typu, TTF_Render*_Blen­ded(), je text vyhlazený a pozadí průhledné.

Na uvedeném obrázku jsou názorně vidět definované rozdíly. Řetězce byly vykresleny bílou barvou na modré pozadí okna, u druhého z nich je navíc definováno černé pozadí.

Ukázka módů solid, shaded, blended

Jak už bylo řečeno, všech devět funkcí si je velmi podobných. Všechny vracejí ukazatel na vytvořený surface s textem. Za první parametr se předává ukazatel na strukturu fontu, v druhém se specifikuje řetězec a třetí slouží k definování barvy textu. U druhého typu, Shaded, se navíc předává ještě barva pozadí.

SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
                const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
                const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
                const Uint16 *text, SDL_Color fg);

SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
                const char *text, SDL_Color fg,
                SDL_Color bg);
SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
                const char *text, SDL_Color fg,
                SDL_Color bg);
SDL_Surface *TTF_RenderUNICODE_Shaded(TTF_Font *font,
                const Uint16 *text, SDL_Color fg,
                SDL_Color bg);

SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
                const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
                const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
                const Uint16 *text, SDL_Color fg);

Funkce typu Solid generují osmibitový paletový surface, u kterého první (resp. nultý) pixel specifikuje barvu pozadí a druhý barvu textu. U funkcí Shaded je zvláštním pixelem pouze ten první, protože kvůli barevným přechodům na okrajích znaků nemůže být barva textu určena jednoznačně. Blended funkce vytvářejí třicetidvoubitový surface ve formátu ARGB. Text se tedy renderuje ve vysoké kvalitě s alfa blendingem, na druhou stranu je tato metoda o něco pomalejší.

SDL_ttf dále definuje funkce pro vykreslení jednoho (Unicode) znaku.

SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font,
                Uint16 ch, SDL_Color fg);
SDL_Surface *TTF_RenderGlyph_Shaded(TTF_Font *font,
                Uint16 ch, SDL_Color fg, SDL_Color bg);
SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font,
                Uint16 ch, SDL_Color fg);

Příklad na výpis textu

Kompletní příklad vykreslení textu včetně inicializace, nahrání fontu a deinicializace by mohl vypadat následovně.

// Globální proměnná
TTF_Font *g_font;

// Inicializace (za SDL_Init())
if(TTF_Init() == -1)
{
  printf("Unable to initialize SDL_ttf: %s\n",
    TTF_GetError());
  return false;
}

g_font = TTF_OpenFont("font.ttf", 12);
if(!g_font)
{
  printf("Unable to open font: %s\n",
    TTF_GetError());
  return false;
}

// Vykreslování
SDL_Color col = { 255, 255, 255, 0 };
SDL_Rect rect = { 20, 20, 0, 0 };
SDL_Surface *text;

text = TTF_RenderText_Solid(g_font, "Text", fg_col);
if(text != NULL)
{
  SDL_BlitSurface(text, NULL, g_screen, &rect);
  SDL_FreeSurface(text);
}

// Deinicializace
if(g_font != NULL)
{
  TTF_CloseFont(g_font);
  g_font = NULL;
}
TTF_Quit();

Další užitečné funkce

Pomocí následujících dvou funkcí lze specifikovat/do­tázat se, zda má být font vykreslován normálně, tučně, kurzívou nebo podtržený. Za parametr style lze předat binárně ORovanou kombinaci symbolických konstant TTF_STYLE_NORMAL, TTF_STYLE_BOLD, TTF_STYLE_ITALIC a TTF_STYLE_UNDER­LINE.

void TTF_SetFontStyle(TTF_Font *font, int style);
int TTF_GetFontStyle(TTF_Font *font);

Pixelové rozměry řetězce po vykreslení, které lze použít například při zarovnávání (doleva/na střed/doprava), lze získat funkcemi

int TTF_SizeText(TTF_Font *font,
                const char *text,
                int *w, int *h);
int TTF_SizeUTF8(TTF_Font *font,
                const char *text,
                int *w, int *h);
int TTF_SizeUNICODE(TTF_Font *font,
                const Uint16 *text,
                int *w, int *h);

Funkce TTF_FontHeight() vrátí maximální výšku předaného fontu v pixelech. Tato hodnota však není moc vhodná pro posun na další řádek, protože by byly moc blízko u sebe. K tomu slouží TTF_FontLineSkip(). Mimochodem SDL_ttf neposkytuje žádné funkce pro víceřádkové výpisy textu, programátor si je musí implementovat sám.

int TTF_FontHeight(TTF_Font *font);
int TTF_FontLineSkip(TTF_Font *font);

Hodnota vrácená funkcí TTF_FontAscent() označuje vzdálenost od horního okraje fontu k jeho základní lince, která se dá použít při vykreslování znaků relativně k hornímu okraji. TTF_FontDescent() se naopak vztahuje k okraji dolnímu.

int TTF_FontAscent(TTF_Font *font);
int TTF_FontDescent(TTF_Font *font);

Kompletní informace o rozměrech určitého znaku lze získat pomocí funkce TTF_GlyphMetrics(). Jednotlivé parametry vysvětluje obrázek níže (byl převzat ze SDL_ttf dokumentace a předtím z FreeType dokumentace). Velice rozsáhlý článek o GlyphMetrics lze najít v dokumentaci knihovny FreeType.

int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
                int *minx, int *maxx,
                int *miny, int *maxy,
                int *advance);
Význam parametrů funkce TTF_GlyphMetrics()

Při práci s širokými Unicode znaky může nastat situace, že budou byty ve znaku vzhledem k procesoru prohozené (little/big endian). Pomocí funkce TTF_ByteSwappe­dUNICODE() lze tento stav změnit. Při předání nenulové hodnoty (UNICODE_BOM_SWAP­PED) se budou byty prohazovat, s nulou (UNICODE_BOM_NA­TIVE) nebudou.

void TTF_ByteSwappedUNICODE(int swapped);

Poslední funkce, které budou probrány, poskytují spíše informativní hodnoty. Jsou jimi jméno rodiny fontu, jeho typ, jestli je font proporcionální, nebo ne, a počet faců.

bitcoin školení listopad 24

char *TTF_FontFaceFamilyName(TTF_Font *font);
char *TTF_FontFaceStyleName(TTF_Font *font);
int  TTF_FontFaceIsFixedWidth(TTF_Font *font);
long TTF_FontFaces(TTF_Font *font);

Ukázkové programy

Výpis textu pomocí SDL_ttf

Ukázkový program je dnes relativně jednoduchý, na modrém pozadí je zobrazeno několik řádek textu. Každá řádka se kreslí jinou technikou a je ukázán i výpis českých znaků. V levém dolním rohu se zobrazují i informace o použitém fontu. (Zdrojový kód se zvýrazněním syntaxe.)

Výpis textu pomocí SDL_ttf

Download

Pokračování

V příštím dílu bude probrána komunikace se správcem oken (změna titulku a ikony, přepínání do fullscreenu atd.), na konci nakousneme zpracování událostí.

Autor článku

Backend programátor ve společnosti Avast, kde vyvíjí a spravuje BigData systém pro příjem a analýzu událostí odesílaných z klientských aplikací založený na Apache Kafka a Apache Hadoop.