Obsah
1. Pohled pod kapotu JVM – práce s TTF fonty v knihovně SDLJava (dokončení)
2. Volba stylu vykreslování textu
3. Demonstrační příklad SDLTest44: vykreslení textu čtyřmi různými styly
4. Výška textu a doporučená vzdálenost mezi obrazovými řádky
5. Demonstrační příklad SDLTest45: vykreslení několika řádků textu
6. Získání informací o dalších základních charakteristikách vybraného fontu
7. Demonstrační příklad SDLTest46: výpis dalších charakteristik vybraného fontu
8. Repositář se zdrojovými kódy všech tří dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – práce s TTF fonty v knihovně SDLJava (dokončení)
V předchozí části tohoto seriálu jsme se seznámili se způsobem vykreslování textů s využitím knihovny SDLJava. Připomeňme si, že texty se v této knihovně vykreslují do samostatných bitmap, které je nutné s využitím metody sdljava.video.SDLSurface.blitSurface() přenést na obrazovku (resp. přesněji řečeno na plochu odpovídající přednímu či zadnímu bufferu, v závislosti na nastavení double bufferingu). Tvary znaků jsou získány z externích TTF fontů – původní obrys jednotlivých znaků je automaticky převeden do rastrové podoby (rasterizace) a následně vykreslen do zmíněné bitmapy. Při vykreslování textů si vývojář může zvolit mezi trojicí renderovacích metod, které se od sebe liší v kvalitě výsledku a taktéž v náročnosti renderingu a paměťové náročnosti:
# | Metoda | Stručný popis metody |
---|---|---|
1 | SDLTrueTypeFont.renderTextSolid() | vytvoření bitmapy s 8bpp, pozadí znaků je průhledné |
2 | SDLTrueTypeFont.renderTextShaded() | vytvoření bitmapy s 8bpp, pozadí znaků má zvolenou barvu |
3 | SDLTrueTypeFont.renderTextBlended() | vytvoření bitmapy s 32bpp, využívá se zde antialiasing |
Dnes téma vykreslování textů s využitím knihovny SDLJava dokončíme – popíšeme si, jakým způsobem je možné nastavit styl vykreslovaných textů a jak lze zjistit základní informace o metrikách použitého fontu. To je poměrně důležité v případě, že se má například vykreslit víceřádkové menu či nápověda. Možnosti knihovny SDLJava sice v této oblasti nejsou na tak propracované úrovni, jako je tomu například v knihovně AWT (viz popis třídy java.awt.FontMatrics, nicméně to ani není cílem knihovny SDLJava. V SDLJava nejsou podporovány ani další složitější manipulace s fonty (práce s ligaturami, umístění znaků se subpixelovou přesností, psaní zprava doleva atd.), což by však při tvorbě her nemělo příliš vadit.
2. Volba stylu vykreslování textu
Minule jsme si taktéž řekli a na čtveřici demonstračních příkladů i prakticky ukázali, že font typu TTF se do spuštěné aplikace může načíst s využitím metody sdljava.ttf.SDLTTF.openFont(jméno_souboru_s_fontem, velikost_písma_v_bodech). Pokud tato metoda nevyhodí výjimku (což se může stát v mnoha případech, například pokud není font nalezen), vrátí instanci třídy sdljava.ttf.SDLTrueTypeFont. Tato třída kromě výše zmíněné trojice metod určených pro rasterizaci textu obsahuje mj. i metodu nazvanou sdljava.ttf.SDLTrueTypeFont.setFontStyle(), jenž je určena pro změnu řezu písma, tloušťky písmových tahů (duktu) popř. pro zapnutí podtrhávání celého textu. Metoda setFontStyle() akceptuje teoreticky libovolnou kombinaci čtyř celočíselných konstant vypsaných v následující tabulce:
# | Parametr metody SDLTrueTypeFont.setFontStyle | Význam parametru |
---|---|---|
1 | TTF_STYLE_NORMAL | základní řez písma |
2 | TTF_STYLE_ITALIC | kurzíva (ať již pravá či nepravá) |
3 | TTF_STYLE_BOLD | polotučné písmo |
4 | TTF_STYLE_UNDERLINE | podtržení celého textu (ne pouze jednotlivých znaků) |
Současná verze knihovny SDLJava však obsahuje prozatím neopravenou chybu způsobující, že při použití některých kombinací (polotučné písmo+kurzíva) může při vykreslování textů dojít k pádu celého virtuálního stroje Javy. Z tohoto důvodu je bezpečnější se tomuto způsobu úpravy řezu písma vyhnout a používat každou ze zmíněných konstant samostatně, tj. bez kombinace s dalšími třemi konstantami.
Obrázek 1: Různé řezy a styly textů vykreslených demonstračním příkladem SDLTest44.
3. Demonstrační příklad SDLTest44: vykreslení textu čtyřmi různými styly
Způsob změny stylu vykreslovaných textů je ukázán v dnešním prvním demonstračním příkladu, který je nazván SDLTest44. Po spuštění tohoto příkladu je načten vybraný font (příslušný soubor „freesans.ttf“ by měl být uložen v aktuálním adresáři) a následně se na obrazovku vypíšou čtyři řádky s textem – první řádek je vykreslen základním řezem písma, druhý řádek pravou či nepravou kurzívou, třetí řádek polotučným písmem a konečně řádek čtvrtý je podtržený). Ještě před vykreslením všech čtyř textových řádků je do bufferu vykreslen rastrový obrázek, takže lze snadno demonstrovat výpočet průhlednosti těch pixelů, které nepřísluší do žádného znaku. Demonstrační příklad samozřejmě podporuje použití libovolného fontu typu TTF, postačuje pouze příslušný font překopírovat do aktuálního adresáře a změnit hodnotu konstanty FONT_NAME. Následuje výpis zdrojového kódu celého demonstračního příkladu SDLTest44:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.event.SDLEvent; import sdljava.event.SDLKeyboardEvent; import sdljava.event.SDLKey; import sdljava.event.SDLQuitEvent; import sdljava.video.SDLColor; import sdljava.video.SDLRect; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import sdljava.ttf.SDLTTF; import sdljava.ttf.SDLTrueTypeFont; import sdljava.x.swig.SDLPressedState; /** * Ctyricaty ctvrty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Ukazka vyuziti zakladnich moznosti tridy sdljava.ttf.SDLTTF: * zmena stylu fontu. * * @author Pavel Tisnovsky */ public class SDLTest44 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 640; /** * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_HEIGHT = 480; /** * Bitova hloubka vybraneho grafickeho rezimu. * (0 znamena automaticky vyber, ovsem lze samozrejme pouzit * i hodnoty 8, 16, 24 ci 32, podle vlastnosti graficke karty) */ private static final int GFX_BPP = 0; /** * Jmeno souboru s fontem. */ private static final String FONT_NAME = "freesans.ttf"; //private static final String FONT_NAME = "mcgf.ttf"; //private static final String FONT_NAME = "aescr5b.ttf"; /** * Velikost pisma udavana v bodech. */ private static final int FONT_SIZE = 72; /** * Barvy vykresleneho textu. */ private static final SDLColor[] FONT_COLORS = new SDLColor[] { new SDLColor(255, 95, 95), new SDLColor(255, 255, 95), new SDLColor(95, 255, 95), new SDLColor(95, 95, 255) }; /** * Styly vykresleneho textu. */ private static final int[] FONT_STYLES = new int[] { SDLTrueTypeFont.TTF_STYLE_NORMAL, SDLTrueTypeFont.TTF_STYLE_ITALIC, SDLTrueTypeFont.TTF_STYLE_BOLD, SDLTrueTypeFont.TTF_STYLE_UNDERLINE, }; /** * Nazev bitmapy, ktera se ma nacist a nasledne zobrazit. */ private static final String INPUT_IMAGE_NAME = "xscorch.bmp"; /** * Inicializace grafickeho rezimu ci otevreni okna pro vykreslovani. */ private static SDLSurface initVideo() throws SDLException { final long flags = SDLVideo.SDL_DOUBLEBUF; return SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, flags); } /** * Smycka pro zpracovani udalosti. */ private static void eventLoop() throws SDLException { while (true) { // precist udalost z fronty SDLEvent event = SDLEvent.waitEvent(); // vyskok ze smycky pro zpracovani udalosti pri vyskytu // udalosti typu SDLQuitEvent if (event instanceof SDLQuitEvent) { return; } // stisk ci pusteni klavesy if (event instanceof SDLKeyboardEvent) { // pretypovani final SDLKeyboardEvent keyEvent = (SDLKeyboardEvent)event; // symbol/kod klavesy final int symbol = keyEvent.getSym(); // ESC ukonci program if (symbol == SDLKey.SDLK_ESCAPE && keyEvent.getState() == SDLPressedState.PRESSED) { return; } } } } /** * Vykresleni bitmapy na obrazovku. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery se ma na obrazovku vykreslit */ private static void drawBitmap(SDLSurface screen, SDLSurface bitmap) throws SDLException { // vypocitat umisteni bitmapy na obrazovce. final SDLRect rect = computePositionOnScreen(screen, bitmap); // provest operaci typu BitBLT bitmap.blitSurface(screen, rect); } /** * Vykresleni bitmapy s textem na obrazovku (do okna aplikace). * * @param screen * framebuffer * @param font * font pouzity pri vykreslovani */ private static void drawOnScreen(SDLSurface screen, SDLTrueTypeFont font, SDLSurface bitmap) throws SDLException { // vykresleni podkladove bitmapy s obrazkem drawBitmap(screen, bitmap); // vykresleni textu s vyuzitim ctyr ruznych barev a stylu for (int i = 0; i < FONT_COLORS.length; i++) { // nastaveni stylu pisma font.setFontStyle(FONT_STYLES[i]); // vykreslit text do samostatne bitmapy SDLSurface textBitmap = font.renderTextSolid("www.root.cz", FONT_COLORS[i]); // vypocitat umisteni bitmapy na obrazovce. SDLRect rect = computePositionOnScreen(screen, textBitmap); rect.y += (i-2) * 70; // provest operaci typu BitBLT textBitmap.blitSurface(screen, rect); } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Vypocitat umisteni bitmapy na obrazovce. * * @param screen * framebuffer * @param bitmap * bitmapa s pismem, ktera se ma na obrazovku vykreslit * @return obdelnik predstavujici pozici bitmapy na obrazovce */ private static SDLRect computePositionOnScreen(SDLSurface screen, SDLSurface bitmap) { // ziskat rozmery obrazovky i bitmapy final int screenWidth = screen.getWidth(); final int screenHeight = screen.getHeight(); final int bitmapWidth = bitmap.getWidth(); final int bitmapHeight = bitmap.getHeight(); // vypocitat umisteni bitmapy na obrazovce final int x = (screenWidth - bitmapWidth)>>1; final int y = (screenHeight - bitmapHeight)>>1; return new SDLRect(x, y, bitmapWidth, bitmapHeight); } /** * Spusteni ctyricateho ctvrteho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace subsystemu SDL_ttf SDLTTF.init(); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // nacteni bitmapy z externiho souboru final SDLSurface bitmap = SDLVideo.loadBMP(INPUT_IMAGE_NAME); // instance tridy SDLTrueTypeFont nese jiz zpracovane informace fontu // vybrane velikosti final SDLTrueTypeFont font = SDLTTF.openFont(FONT_NAME, FONT_SIZE); // vykresleni sceny na obrazovku drawOnScreen(screen, font, bitmap); // smycka pro zpracovani udalosti eventLoop(); } catch (Exception e) { e.printStackTrace(); } finally { try { // uvolneni prostredku vyuzivanych subsytemem SDL_ttf. SDLTTF.quit(); } catch (SDLException e) { e.printStackTrace(); } // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Obrázek 2: Různé řezy a styly textů vykreslených demonstračním příkladem SDLTest44.
Skript pro překlad tohoto demonstračního příkladu na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest44.java
Dávkový soubor pro překlad tohoto demonstračního příkladu na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest44.java
Skript pro spuštění na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib java -cp .:$SDL_JAVA_LIBS/sdljava.jar -Djava.library.path=$SDL_JAVA_LIBS SDLTest44
Dávkový soubor pro spuštění na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest44
4. Výška textu a doporučená vzdálenost mezi obrazovými řádky
Při pohledu na zdrojový kód demonstračního příkladu SDLTest44 je možné si všimnout způsobu výpočtu umístění bitmapy s textem na obrazovku:
// vykreslit text do samostatne bitmapy SDLSurface textBitmap = font.renderTextSolid("www.root.cz", FONT_COLORS[i]); // vypocitat umisteni bitmapy na obrazovce. SDLRect rect = computePositionOnScreen(screen, textBitmap); rect.y += (i-2) * 70;
V žádném případě se nejedná o nijak čitelný výpočet, ovšem jeho největším záporem je to, že není přesný a navíc nebude pracovat korektně ve chvíli, kdy se změní velikost fontu, tj. v našem příkladu konkrétně hodnota konstanty FONT_SIZE. Jeden z problémů spočívá v tom, že se velikost textu určuje v typografických bodech, zatímco pozice bitmapy na obrazovce se udává v pixelech. Ovšem třída SDLTrueTypeFont obsahuje i metody, které dokážou na základě metrik uložených v souboru s fontem získat výšku řádků, popř. doporučovanou vzdálenost mezi obrazovými řádky. Důležité je, že tyto údaje již jsou skutečně uváděny v pixelech, takže je lze využít pro přesné polohování textů na obrazovce:
# | Metoda | Význam |
---|---|---|
1 | SDLTrueTypeFont.fontHeight() | Maximální výška znaku, který se může ve fontu vyskytnout |
2 | SDLTrueTypeFont.fontLineSkip() | Doporučená vertikální vzdálenost mezi po sobě jdoucími textovými řádky |
Hodnoty vrácené metodami fontHeight() a fontLineSkip() se od sebe budou lišit, protože mezi jednotlivými po sobě jdoucími textovými řádky by měl být alespoň minimální volný prostor, například o velikosti jeden či dva pixely (obrazové řádky). Při snaze o vykreslení co největšího množství řádků na obrazovku je však v naprosté většině případů možné použít i hodnotu vrácenou funkcí fontHeight(), protože je jen málo pravděpodobné, že dojde k dotyku dvou znaků pod sebou (horní znak by musel mít dolní dotažnici a spodní znak by například musel být kapitálkou).
Obrázek 3: Čtyři textové řádky (písmo velikosti 72) vykreslené demonstračním příkladem SDLTest45.
5. Demonstrační příklad SDLTest45: vykreslení několika řádků textu
Použití metody SDLTrueTypeFont.fontHeight() je ukázáno v dnešním druhém demonstračním příkladu nazvaném SDLTest45. I v tomto příkladu se na obrazovku vytisknou čtyři řádky textu, ovšem s korektně spočítanou vzdáleností mezi jednotlivými textovými řádky. Samotný výpočet probíhá velmi jednoduše v metodě drawOnScreen:
/** * Vykresleni bitmapy s textem na obrazovku (do okna aplikace). * * @param screen * framebuffer * @param font * font pouzity pri vykreslovani */ private static void drawOnScreen(SDLSurface screen, SDLTrueTypeFont font, SDLSurface bitmap) throws SDLException { // vykresleni podkladove bitmapy s obrazkem drawBitmap(screen, bitmap); // vypocitat umisteni bitmapy s textem na obrazovce. SDLRect rect = new SDLRect(100, 10); // vykresleni textu s vyuzitim ctyr ruznych barev for (int i = 0; i < FONT_COLORS.length; i++) { // vykreslit text do samostatne bitmapy SDLSurface textBitmap = font.renderTextSolid("www.root.cz", FONT_COLORS[i]); // presun na dalsi "radek" rect.y += font.fontHeight(); // provest operaci typu BitBLT textBitmap.blitSurface(screen, rect); } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); }
Následuje výpis úplného zdrojového kódu tohoto demonstračního příkladu:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.event.SDLEvent; import sdljava.event.SDLKeyboardEvent; import sdljava.event.SDLKey; import sdljava.event.SDLQuitEvent; import sdljava.video.SDLColor; import sdljava.video.SDLRect; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import sdljava.ttf.SDLTTF; import sdljava.ttf.SDLTrueTypeFont; import sdljava.x.swig.SDLPressedState; /** * Ctyricaty paty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Ukazka vyuziti zakladnich moznosti tridy sdljava.ttf.SDLTTF: * vyuziti metriky fontu pri zjistovani vysky textoveho radku. * * @author Pavel Tisnovsky */ public class SDLTest45 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 640; /** * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_HEIGHT = 480; /** * Bitova hloubka vybraneho grafickeho rezimu. * (0 znamena automaticky vyber, ovsem lze samozrejme pouzit * i hodnoty 8, 16, 24 ci 32, podle vlastnosti graficke karty) */ private static final int GFX_BPP = 0; /** * Jmeno souboru s fontem. */ private static final String FONT_NAME = "freesans.ttf"; //private static final String FONT_NAME = "mcgf.ttf"; //private static final String FONT_NAME = "aescr5b.ttf"; /** * Velikost pisma udavana v bodech. */ private static final int FONT_SIZE = 72; /** * Barvy vykresleneho textu. */ private static final SDLColor[] FONT_COLORS = new SDLColor[] { new SDLColor(255, 95, 95), new SDLColor(255, 255, 95), new SDLColor(95, 255, 95), new SDLColor(95, 95, 255) }; /** * Nazev bitmapy, ktera se ma nacist a nasledne zobrazit. */ private static final String INPUT_IMAGE_NAME = "xscorch.bmp"; /** * Inicializace grafickeho rezimu ci otevreni okna pro vykreslovani. */ private static SDLSurface initVideo() throws SDLException { final long flags = SDLVideo.SDL_DOUBLEBUF; return SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, flags); } /** * Smycka pro zpracovani udalosti. */ private static void eventLoop() throws SDLException { while (true) { // precist udalost z fronty SDLEvent event = SDLEvent.waitEvent(); // vyskok ze smycky pro zpracovani udalosti pri vyskytu // udalosti typu SDLQuitEvent if (event instanceof SDLQuitEvent) { return; } // stisk ci pusteni klavesy if (event instanceof SDLKeyboardEvent) { // pretypovani final SDLKeyboardEvent keyEvent = (SDLKeyboardEvent)event; // symbol/kod klavesy final int symbol = keyEvent.getSym(); // ESC ukonci program if (symbol == SDLKey.SDLK_ESCAPE && keyEvent.getState() == SDLPressedState.PRESSED) { return; } } } } /** * Vykresleni bitmapy na obrazovku. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery se ma na obrazovku vykreslit */ private static void drawBitmap(SDLSurface screen, SDLSurface bitmap) throws SDLException { // vypocitat umisteni bitmapy na obrazovce. final SDLRect rect = computePositionOnScreen(screen, bitmap); // provest operaci typu BitBLT bitmap.blitSurface(screen, rect); } /** * Vykresleni bitmapy s textem na obrazovku (do okna aplikace). * * @param screen * framebuffer * @param font * font pouzity pri vykreslovani */ private static void drawOnScreen(SDLSurface screen, SDLTrueTypeFont font, SDLSurface bitmap) throws SDLException { // vykresleni podkladove bitmapy s obrazkem drawBitmap(screen, bitmap); // vypocitat umisteni bitmapy s textem na obrazovce. SDLRect rect = new SDLRect(100, 10); // vykresleni textu s vyuzitim ctyr ruznych barev for (int i = 0; i < FONT_COLORS.length; i++) { // vykreslit text do samostatne bitmapy SDLSurface textBitmap = font.renderTextSolid("www.root.cz", FONT_COLORS[i]); // presun na dalsi "radek" rect.y += font.fontHeight(); // provest operaci typu BitBLT textBitmap.blitSurface(screen, rect); } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Vypocitat umisteni bitmapy na obrazovce. * * @param screen * framebuffer * @param bitmap * bitmapa s pismem, ktera se ma na obrazovku vykreslit * @return obdelnik predstavujici pozici bitmapy na obrazovce */ private static SDLRect computePositionOnScreen(SDLSurface screen, SDLSurface bitmap) { // ziskat rozmery obrazovky i bitmapy final int screenWidth = screen.getWidth(); final int screenHeight = screen.getHeight(); final int bitmapWidth = bitmap.getWidth(); final int bitmapHeight = bitmap.getHeight(); // vypocitat umisteni bitmapy na obrazovce final int x = (screenWidth - bitmapWidth)>>1; final int y = (screenHeight - bitmapHeight)>>1; return new SDLRect(x, y, bitmapWidth, bitmapHeight); } /** * Spusteni ctyricateho pateho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace subsystemu SDL_ttf SDLTTF.init(); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // nacteni bitmapy z externiho souboru final SDLSurface bitmap = SDLVideo.loadBMP(INPUT_IMAGE_NAME); // instance tridy SDLTrueTypeFont nese jiz zpracovane informace fontu // vybrane velikosti final SDLTrueTypeFont font = SDLTTF.openFont(FONT_NAME, FONT_SIZE); // vykresleni sceny na obrazovku drawOnScreen(screen, font, bitmap); // smycka pro zpracovani udalosti eventLoop(); } catch (Exception e) { e.printStackTrace(); } finally { try { // uvolneni prostredku vyuzivanych subsytemem SDL_ttf. SDLTTF.quit(); } catch (SDLException e) { e.printStackTrace(); } // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Obrázek 4: Čtyři textové řádky (písmo velikosti 10) vykreslené demonstračním příkladem SDLTest45.
Skript pro překlad tohoto demonstračního příkladu na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest45.java
Dávkový soubor pro překlad tohoto demonstračního příkladu na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest45.java
Skript pro spuštění na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib java -cp .:$SDL_JAVA_LIBS/sdljava.jar -Djava.library.path=$SDL_JAVA_LIBS SDLTest45
Dávkový soubor pro spuštění na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest45
6. Získání informací o dalších základních charakteristikách vybraného fontu
Ve třídě SDLTrueTypeFont najdeme kromě již popsaných metod fontHeight() a fontLineSkip() i další dvě metody nazvané fontAscent() a fontDescent() popisující přesněji metriku vybraného fontu, resp. parametry písmové osnovy. První z těchto metod vrací vzdálenost (udávanou v pixelech) mezi akcentovou dotažnicí (sem dosahují nejvyšší akcenty) a základní dotažnicí, tj. základem písmové osnovy (nejnižší místo, kam zasahují tvary kapitálek). Druhá metoda se jmenuje fontDescent() a vrací vzdálenost mezi základní dotažnicí a dolní dotažnicí, tj. spodní hranicí minusek g, j, p, q a y (tato hodnota je záporná):
# | Metoda | Význam |
---|---|---|
1 | SDLTrueTypeFont.fontHeight() | Maximální výška znaku, který se může ve fontu vyskytnout |
2 | SDLTrueTypeFont.fontLineSkip() | Doporučená vertikální vzdálenost mezi po sobě jdoucími textovými řádky |
3 | SDLTrueTypeFont.fontAscent() | Vrací vzdálenost mezi akcentovou dotažnicí a základní dotažnicí |
4 | SDLTrueTypeFont.fontDescent() | Vrací vzdálenost mezi základní dotažnicí a dolní dotažnicí |
Obrázek 5: Základní informace o načteném fontu.
Obrázek 6: Základní informace o načteném fontu (odlišná velikost písma).
7. Demonstrační příklad SDLTest46: výpis dalších charakteristik vybraného fontu
Všechny informace získané z načteného a inicializovaného fontu vypisuje do svého okna dnešní třetí a současně i poslední demonstrační příklad nazvaný SDLTest46. Výpis jména vlastnosti i její hodnoty je implementován v metodě drawText(), v níž se pro přesun vykreslování na další řádek používá hodnota získaná metodou SDLTrueTypeFont.fontLineSkip():
/** * Vykresleni textu na obrazovku. * * @param screen * framebuffer * @param font * font pouzity pri vykreslovani * @param property * text, ktery ma byt vypsany na obrazovku (vlastnost) * @param value * text, ktery ma byt vypsany na obrazovku (hodnota vlastnosti) */ private static void drawText(SDLSurface screen, SDLTrueTypeFont font, String property, int value) throws SDLException { // vykreslit text do samostatne bitmapy SDLSurface textBitmap1 = font.renderTextSolid(property, FONT_COLORS[0]); SDLSurface textBitmap2 = font.renderTextSolid(Integer.toString(value), FONT_COLORS[1]); // provest operaci typu BitBLT textBitmap1.blitSurface(screen, rect1); textBitmap2.blitSurface(screen, rect2); // presun na dalsi "radek" rect1.y += font.fontLineSkip(); rect2.y += font.fontLineSkip(); }
Výpis zdrojového kódu demonstračního příkladu SDLTest46:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.event.SDLEvent; import sdljava.event.SDLKeyboardEvent; import sdljava.event.SDLKey; import sdljava.event.SDLQuitEvent; import sdljava.video.SDLColor; import sdljava.video.SDLRect; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import sdljava.ttf.SDLTTF; import sdljava.ttf.SDLTrueTypeFont; import sdljava.x.swig.SDLPressedState; /** * Ctyricaty sesty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Ukazka vyuziti zakladnich moznosti tridy sdljava.ttf.SDLTTF: * vypis informaci o vlastnostech zvoleneho fontu. * * @author Pavel Tisnovsky */ public class SDLTest46 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 640; /** * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_HEIGHT = 480; /** * Bitova hloubka vybraneho grafickeho rezimu. * (0 znamena automaticky vyber, ovsem lze samozrejme pouzit * i hodnoty 8, 16, 24 ci 32, podle vlastnosti graficke karty) */ private static final int GFX_BPP = 0; /** * Jmeno souboru s fontem. */ private static final String FONT_NAME = "freesans.ttf"; //private static final String FONT_NAME = "mcgf.ttf"; //private static final String FONT_NAME = "aescr5b.ttf"; /** * Velikost pisma udavana v bodech. */ private static final int FONT_SIZE = 24; /** * Barvy vykresleneho textu. */ private static final SDLColor[] FONT_COLORS = new SDLColor[] { new SDLColor(255, 95, 95), new SDLColor(255, 255, 95), }; /** * Umisteni bitmapy s textem na obrazovce. */ private static SDLRect rect1 = new SDLRect(50, 10); private static SDLRect rect2 = new SDLRect(350, 10); /** * Inicializace grafickeho rezimu ci otevreni okna pro vykreslovani. */ private static SDLSurface initVideo() throws SDLException { final long flags = SDLVideo.SDL_DOUBLEBUF; return SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, flags); } /** * Smycka pro zpracovani udalosti. */ private static void eventLoop() throws SDLException { while (true) { // precist udalost z fronty SDLEvent event = SDLEvent.waitEvent(); // vyskok ze smycky pro zpracovani udalosti pri vyskytu // udalosti typu SDLQuitEvent if (event instanceof SDLQuitEvent) { return; } // stisk ci pusteni klavesy if (event instanceof SDLKeyboardEvent) { // pretypovani final SDLKeyboardEvent keyEvent = (SDLKeyboardEvent)event; // symbol/kod klavesy final int symbol = keyEvent.getSym(); // ESC ukonci program if (symbol == SDLKey.SDLK_ESCAPE && keyEvent.getState() == SDLPressedState.PRESSED) { return; } } } } /** * Vykresleni textu na obrazovku. * * @param screen * framebuffer * @param font * font pouzity pri vykreslovani * @param property * text, ktery ma byt vypsany na obrazovku (vlastnost) * @param value * text, ktery ma byt vypsany na obrazovku (hodnota vlastnosti) */ private static void drawText(SDLSurface screen, SDLTrueTypeFont font, String property, int value) throws SDLException { // vykreslit text do samostatne bitmapy SDLSurface textBitmap1 = font.renderTextSolid(property, FONT_COLORS[0]); SDLSurface textBitmap2 = font.renderTextSolid(Integer.toString(value), FONT_COLORS[1]); // provest operaci typu BitBLT textBitmap1.blitSurface(screen, rect1); textBitmap2.blitSurface(screen, rect2); // presun na dalsi "radek" rect1.y += font.fontLineSkip(); rect2.y += font.fontLineSkip(); } /** * Vykresleni bitmapy s textem na obrazovku (do okna aplikace). * * @param screen * framebuffer * @param font * font pouzity pri vykreslovani */ private static void drawOnScreen(SDLSurface screen, SDLTrueTypeFont font) throws SDLException { // vypis vsech vlastnosti fontu drawText(screen, font, "Font size (points): ", font.getPTSize()); drawText(screen, font, "Max. height (pixels):", font.fontHeight()); drawText(screen, font, "Ascent (points): ", font.fontAscent()); drawText(screen, font, "Descent (points): ", font.fontDescent()); drawText(screen, font, "Line skip (points): ", font.fontLineSkip()); // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni ctyricateho sesteho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace subsystemu SDL_ttf SDLTTF.init(); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // instance tridy SDLTrueTypeFont nese jiz zpracovane informace fontu // vybrane velikosti final SDLTrueTypeFont font = SDLTTF.openFont(FONT_NAME, FONT_SIZE); // vykresleni sceny na obrazovku drawOnScreen(screen, font); // smycka pro zpracovani udalosti eventLoop(); } catch (Exception e) { e.printStackTrace(); } finally { try { // uvolneni prostredku vyuzivanych subsytemem SDL_ttf. SDLTTF.quit(); } catch (SDLException e) { e.printStackTrace(); } // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Obrázek 7: Základní informace o načteném fontu (odlišná velikost písma).
Skript pro překlad tohoto demonstračního příkladu na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest46.java
Dávkový soubor pro překlad tohoto demonstračního příkladu na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest46.java
Skript pro spuštění na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib java -cp .:$SDL_JAVA_LIBS/sdljava.jar -Djava.library.path=$SDL_JAVA_LIBS SDLTest46
Dávkový soubor pro spuštění na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest46
8. Repositář se zdrojovými kódy všech tří dnešních demonstračních příkladů
Všechny tři dnes popsané demonstrační příklady byly společně s podpůrnými skripty určenými pro jejich překlad a následné spuštění uloženy do Mercurial repositáře dostupného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/. Podobně jako tomu bylo i v předchozích několika dílech tohoto seriálu, i ke dnešním příkladům jsou přiloženy skripty využitelné pro jejich překlad a spuštění. Navíc byly přidány i skripty využitelné ve Windows:
9. Odkazy na Internetu
- SDLJava: package sdljava.ttf
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/package-summary.html#package_description - SDLJava: class sdljava.ttf.SDLTTF
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTTF.html - SDLJava: class sdljava.ttf.SDLTrueTypeFont
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTrueTypeFont.html - SDL_ttf Documentation
http://www.libsdl.org/projects/SDL_ttf/docs/ - SDL_ttf 2.0 (není prozatím součástí SDLJava)
http://www.libsdl.org/projects/SDL_ttf/ - SDL_ttf doc
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html - SDL 1.2 Documentation: SDL_Surface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html - SDL 1.2 Documentation: SDL_PixelFormat
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html - SDL 1.2 Documentation: SDL_LockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html - SDL 1.2 Documentation: SDL_UnlockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html - SDL 1.2 Documentation: SDL_LoadBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html - SDL 1.2 Documentation: SDL_SaveBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html - SDL 1.2 Documentation: SDL_BlitSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html - SDL 1.2 Documentation: SDL_VideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html - SDL 1.2 Documentation: SDL_GetVideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html - glDrawArrays
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArrays.xml - glDrawElements
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElements.xml - glDrawArraysInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArraysInstanced.xml - glDrawElementsInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElementsInstanced.xml - Root.cz: Seriál Grafická knihovna OpenGL
http://www.root.cz/serialy/graficka-knihovna-opengl/ - Root.cz: Seriál Tvorba přenositelných grafických aplikací využívajících knihovnu GLUT
http://www.root.cz/serialy/tvorba-prenositelnych-grafickych-aplikaci-vyuzivajicich-knihovnu-glut/ - Best Practices for Working with Vertex Data
https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html - Class BufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class Graphics
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Graphics.html - Double Buffering and Page Flipping
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html - BufferStrategy and BufferCapabilities
http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html - Java:Tutorials:Double Buffering
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering - Double buffer in standard Java AWT
http://www.codeproject.com/Articles/2136/Double-buffer-in-standard-Java-AWT - Java 2D: Hardware Accelerating – Part 1 – Volatile Images
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0 - Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
http://www.javalobby.org/java/forums/t16867.html - How does paintComponent work?
http://stackoverflow.com/questions/15544549/how-does-paintcomponent-work - A Swing Architecture Overview
http://www.oracle.com/technetwork/java/architecture-142923.html - Class javax.swing.JComponent
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html - Class java.awt.Component
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html - Class java.awt.Component.BltBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.BltBufferStrategy.html - Class java.awt.Component.FlipBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.FlipBufferStrategy.html - Metoda java.awt.Component.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#isDoubleBuffered() - Metoda javax.swing.JComponent.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#isDoubleBuffered() - Metoda javax.swing.JComponent.setDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#setDoubleBuffered(boolean) - Javadoc – třída GraphicsDevice
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html - Javadoc – třída GraphicsEnvironment
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsEnvironment.html - Javadoc – třída GraphicsConfiguration
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsConfiguration.html - Javadoc – třída DisplayMode
http://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html - Lesson: Full-Screen Exclusive Mode API
http://docs.oracle.com/javase/tutorial/extra/fullscreen/ - Full-Screen Exclusive Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html - Display Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/displaymode.html - Using the Full-Screen Exclusive Mode API in Java
http://www.developer.com/java/other/article.php/3609776/Using-the-Full-Screen-Exclusive-Mode-API-in-Java.htm - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - GC safe-point (or safepoint) and safe-region
http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html - Safepoints in HotSpot JVM
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html - Java theory and practice: Synchronization optimizations in Mustang
http://www.ibm.com/developerworks/java/library/j-jtp10185/ - How to build hsdis
http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/tools/hsdis/README - Java SE 6 Performance White Paper
http://www.oracle.com/technetwork/java/6-performance-137236.html - Lukas Stadler's Blog
http://classparser.blogspot.cz/2010/03/hsdis-i386dll.html - How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
http://dropzone.nfshost.com/hsdis.htm - PrintAssembly
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly - The Java Virtual Machine Specification: 3.14. Synchronization
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.14 - The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4 - The Java Virtual Machine Specification: 17.4. Memory Model
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 - The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 - Open Source ByteCode Libraries in Java
http://java-source.net/open-source/bytecode-libraries - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - BCEL Home page
http://commons.apache.org/bcel/ - Byte Code Engineering Library (před verzí 5.0)
http://bcel.sourceforge.net/ - Byte Code Engineering Library (verze >= 5.0)
http://commons.apache.org/proper/commons-bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - Javassist
http://www.jboss.org/javassist/ - Byteman
http://www.jboss.org/byteman - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - jclasslib bytecode viewer
http://www.ej-technologies.com/products/jclasslib/overview.html