Obsah
1. Pohled pod kapotu JVM – základní koncepty, na nichž je postavena knihovna SDLJava
2. Třída sdljava.video.SDLRect
3. Třída sdljava.video.SDLSurface
4. Načtení bitmapy s využitím metody sdljava.video.SDLVideo.loadBMP()
5. Podpora dalších grafických formátů
6. Operace typu BitBLT realizovaná mezi dvěma objekty typu sdljava.video.SDLSurface
7. Demonstrační příklad SDLTest4 – načtení bitmapy typu BMP a provedení operace BitBLT
8. Demonstrační příklad SDLTest5 – určení pozice, kde se má bitmapa vykreslit
9. Demonstrační příklad SDLTest6 – ořez bitmapy při provádění operace typu BitBLT
10. Demonstrační příklad SDLTest7 – načtení bitmapy uložené ve formátu PNG
11. Repositář se zdrojovými kódy všech čtyř dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – základní koncepty, na nichž je postavena knihovna SDLJava
V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji tohoto jazyka budeme pokračovat v popisu možností knihovny SDLJava. V předchozím díle jsme si řekli základní informace o této knihovně; víme tedy, že se jedná o „objektové“ rozhraní ke známé nativní knihovně SDL. Taktéž jsme si na trojici demonstračních příkladů ukázali, jak lze knihovnu SDLJava využít ve vlastních aplikacích. Dnes se podrobněji seznámíme se základy vykreslování grafických scén s využitím SDLJava a tím pádem i SDL. Demonstrační příklady, s nimiž se seznámíme, budou využívat šestici tříd vypsaných v následující tabulce, ovšem popis bude zaměřen především na třídy sdljava.video.SDLRect, sdljava.video.SDLVideo a sdljava.video.SDLSurface, které tvoří základ grafického subsystému knihovny SDL a v posledním demonstračním příkladu bude využita i třída sdljava.image.SDLImage:
# | Třída | Stručný popis |
---|---|---|
1 | sdljava.SDLMain | tato třída obsahuje především metody pro inicializaci knihovny SDL a pro korektní ukončení činnosti aplikace |
2 | sdljava.SDLException | výjimka vyhazovaná při provedení některé neplatné operace v knihovně SDLJava či SDL |
3 | sdljava.video.SDLRect | jednoduchá třída obalující strukturu SDL_rect z knihovny SDL |
4 | sdljava.video.SDLVideo | třída se statickými metodami používanými při práci s grafikou |
5 | sdljava.video.SDLSurface | reprezentuje bitmapu či framebuffer, do něhož je možné provádět vykreslování |
6 | sdljava.image.SDLImage | třída obsahující jedinou přetíženou metodu load určenou pro načtení bitmap z různých zdrojů (souborů, bufferu, URL atd.) |
2. Třída sdljava.video.SDLRect
První třída z knihovny SDLJava, s níž se dnes podrobněji seznámíme, má plný název sdljava.video.SDLRect . Instance této třídy reprezentují obdélník se specifikovanými souřadnicemi jeho levého horního rohu i se zadanými rozměry (šířka, výška). Obdélníky jsou v knihovně SDLJava využity na několika místech; my se s nimi konkrétně setkáme v souvislosti s operací typu BitBLT, v níž mohou být obdélníky použity jak pro specifikaci umístění kopírované bitmapy, tak i pro nastavení ořezávání při kopiích bitmap. Jak jednotlivé souřadnice, tak i šířka a výška každého obdélníku jsou reprezentovány celými čísly typu int, zatímco v nativní knihovně SDL vypadá datový typ SDL_Rect následovně:
typedef struct SDL_Rect { Sint16 x, y; Uint16 w, h; } SDL_Rect;
Ve třídě sdljava.video.SDLRect mohou programátoři přímo přistupovat k atributům x, y, width a height, popř. mohou alternativně použít příslušné gettery a settery, které jsou navíc rozšířeny o metody setLocation() a setSize():
# | Metoda | Popis |
---|---|---|
1 | int getX() | getter pro atribut x |
2 | int getY() | getter pro atribut y |
3 | int getWidth() | getter pro atribut width |
4 | int getHeight() | getter pro atribut height |
5 | void setX(int x) | setter pro atribut x |
6 | void setY(int y) | setter pro atribut y |
7 | void setWidth(int width) | setter pro atribut width |
8 | void setHeight(int height) | setter pro atribut height |
9 | void setLocation(int x, int y) | nastavuje atributy x i y |
10 | void setSize(int width, int height) | nastavuje atributy width i height |
Velmi často se taktéž používá konstruktor public SDLRect(int x, int y, int width, int height).
3. Třída sdljava.video.SDLSurface
Zatímco třída sdljava.video.SDLRect popsaná v předchozí kapitole je velmi jednoduchá a jedná se vlastně jen o přímočaře navrženou obalovou třídu nad céčkovou datovou strukturou, je třída sdljava.video.SDLSurface již mnohem složitější, a to jak svojí vnitřní strukturou, tak i metodami, které tato třída nabízí. Objekty typu SDLSurface představují v knihovně SDLJava bitmapu, do níž je možné provádět vykreslování, popř. kterou lze s využitím operace typu BitBLT přenést do jiné bitmapy. SDLSurface však v SDL taktéž představuje i vlastní framebuffer, což znamená, že většinu operací, kterou lze provádět s bitmapami uloženými v operační paměti, je možné provádět i s framebufferem. Třída SDLSurface obaluje nativní datovou strukturu SDL_Surface, jejíž deklarace vypadá následovně:
typedef struct SDL_Surface { Uint32 flags; /** Read-only */ SDL_PixelFormat *format; /** Read-only */ int w, h; /** Read-only */ Uint16 pitch; /** Read-only */ void *pixels; /** Read-write */ int offset; /** Private */ /** Hardware-specific surface info */ struct private_hwdata *hwdata; /** clipping information */ SDL_Rect clip_rect; /** Read-only */ Uint32 unused1; /** for binary compatibility */ /** Allow recursive locks */ Uint32 locked; /** Private */ /** info for fast blit mapping to other surfaces */ struct SDL_BlitMap *map; /** Private */ /** format version, bumped at every change to invalidate blit maps */ unsigned int format_version; /** Private */ /** Reference count -- used when freeing surface */ int refcount; /** Read-mostly */ } SDL_Surface;
Programátory využívající knihovnu SDLJava však budou velmi pravděpodobně zajímat především metody, které jim třída SDLSurface nabízí. Stručně je možné říci, že se nabízené metody rozdělují do několika kategorií: vytvoření či načtení bitmapy/plochy, vyplnění plochy či její části barvou, přístup k jednotlivým pixelům a konečně přenos celé plochy či její části na jinou plochu či obrazovku. Důležitou metodou je SDLSurface.loadBMP() popsaná v navazující kapitole. Dále zde můžeme nalézt metodu SDLSurface.fillRect() sloužící buď pro vyplnění celé plochy/bitmapy jednou barvou, nebo pro vyplnění obdélníka specifikovaného pomocí SDLRect. Ukázku použití těchto metod jsme mohli vidět v předchozí části tohoto seriálu. Samostatnou kategorií je přetížená metoda SDLSurface.blitSurface() sloužící pro vykonání operace typu BitBLT.
4. Načtení bitmapy s využitím metody sdljava.video.SDLVideo.loadBMP()
Většina her, v nichž je použita knihovna SDL (resp. přeneseně i SDLJava) pro práci s 2D grafikou, musí nějakým způsobem načítat rastrové obrázky z externích souborů. Samotná základní varianta knihovny SDL se nesnaží pokrýt všechny dostupné grafické formáty ani suplovat další knihovny (giflib, libpng, libjpeg…) a z tohoto důvodu podporuje pouze načítání rastrových obrázků uložených v souborech typu BMP neboli (Windows) Bitmap. Tento formát byl navržen firmami IBM a Microsoft (každá firma navrhla jinou variantu) jako základní rastrový obrazový formát pro jejich operační systémy OS/2 a Microsoft Windows. Tím pádem je načítání i ukládání obrázků v tomto formátu podporováno přímo v aplikačním rozhraní daného operačního systému a tvůrci programů mohou toto rozhraní využít bez toho, aby daný formát detailně znali.
Zajímavý je také způsob ukládání obrazových řádků do souborů. Ty se totiž v původních verzích neukládaly směrem shora dolů, jak je to přirozené pro programátory, mikroprocesory, operační paměti i pro použité zobrazovací prostředky (grafické karty, tiskárny), ale přesně naopak – zespoda nahoru. Vzhledem k tomu, že i vykreslování obrázků pomocí WinAPI se provádí od spodního okraje, se vše výrazně komplikuje. Důvod, proč je směr vykreslování a ukládání u bitmap (přesněji řečeno obrázků typu BMP) opačný, spočívá v tom, že tuto orientaci původně používal operační systém OS/2, který je však v tomto ohledu alespoň konzistentní – souřadnice rostou směrem od levého spodního rohu směrem doprava a nahoru. Ve WinAPI se však používá „klasické“ a přirozenější orientace souřadnic, které rostou od levého horního rohu směrem doprava a dolů, a tak se opačný smysl vykreslování bitmap do tohoto systému vůbec nehodí a u několika API funkcí způsobuje zmatky v chápání směru.
Nicméně tyto implementační detaily nemusí programátory využívající SDL/SDLJava příliš zajímat. Praktičtější je informace, že pro načtení bitmapy se používá statická metoda static SDLSurface. loadBMP(java.lang.String path), které se předá cesta k bitmapě a výsledkem je přímo objekt typu SDLSurface, jenž lze buď zkonvertovat nebo přímo vykreslit na obrazovku. Povšimněte si, že se této metodě předává řetězec s cestou a nikoli objekt typu File, takže záleží jen na programátorovi, zda správně ošetří jména souborů s bitmapami takovým způsobem, aby byl program přenositelný (týká se to zejména oddělovačů adresářů). Příklad použití této metody si ukážeme v demonstračním příkladu SDLTest4, který je popsán v sedmé kapitole, nicméně základní idiom je jednoduchý:
// nacteni bitmapy z externiho souboru SDLSurface bitmap = SDLVideo.loadBMP("test.bmp");
5. Podpora dalších grafických formátů
Podpora grafického formátu BMP v jádru knihovny SDL nemusí být pro mnoho aplikací dostačující, zejména ve chvíli, kdy je například vyvíjena hra s velkým množstvím obrázků. V takovém případě by byly nároky na potřebnou kapacitu disku zbytečně velké; navíc má formát BMP jen omezené možnosti definice průhlednosti pixelů. Alternativním řešením je využití jednoho z přídavných modulů knihovny SDL, který se jmenuje SDL_image. I tento modul je v knihovně SDLJava dostupný a to konkrétně přes třídu sdljava.image.SDLImage. Tato třída obsahuje jen jedinou přetíženou statickou metodu load(), která vrací, podobně jako výše popsaná metoda SDLSurface.loadBMP(), objekt typu SDLSurface. Přes sdljava.image.SDLImage.load() je možné načíst bitmapy uložené do různých formátů, ovšem pro většinu programátorů budou pravděpodobně nejdůležitější formáty PNG a JPEG:
# | Metoda | Popis |
---|---|---|
1 | static SDLSurface load(java.nio.Buffer buf) | načtení bitmapy, která je uložena v bufferu |
2 | static SDLSurface load(byte[] data) | načtení bitmapy uložené v poli |
3 | static SDLSurface load(java.io.InputStream in) | načtení bitmapy ze vstupního proudu |
4 | static SDLSurface load(java.lang.String file) | načtení bitmapy ze souboru specifikovaného jménem |
5 | static SDLSurface load(java.net.URL url) | načtení bitmapy z místa specifikovaného pomocí URL |
V mnoha aplikacích se programátoři pravděpodobně spokojí s načtením každé bitmapy ze samostatného souboru, ovšem někdy může být výhodnější všechny bitmapy uložit do souboru jediného a pro jejich načtení následně využít vstupní proud popř. buffer. Knihovna SDLJava sama rozpozná hlavičku grafického formátu i ukončení obrázku.
6. Operace typu BitBLT realizovaná mezi dvěma objekty typu sdljava.video.SDLSurface
Jakmile jsou bitmapy načteny z externích souborů, je nutné je nějakým způsobem vykreslit. V knihovně SDLJava se tato operace provádí pomocí přetížené metody SDLSurface.blitSurface(). Tato metoda existuje ve třech variantách, které se od sebe liší počtem a významem parametrů. Základní operace však zůstává stejná – zdrojová bitmapa (tj. objekt typu SDLSurface) je přenesena do bitmapy cílové, která je vždy předána v prvním parametru metody SDLSurface.blitSurface(). V případě, že je zdrojová bitmapa menší než bitmapa cílová, je zdrojová bitmapa přenesena do levého horního rohu cílové bitmapy. Pokud je naopak zdrojová bitmapa větší, je při jejím přenosu provedeno její ořezání.
Pokud je nutné explicitně specifikovat pozici zdrojové bitmapy v bitmapě cílové, používá se druhá varianta metody SDLSurface.blitSurface(), kde se kýžená pozice specifikuje pomocí objektu typu SDLRect (význam má jen pozice jeho levého horního rohu). Ovšem při přenosu bitmapy je možné provést i její ořezání na základě informací uložených ve druhém objektu typu SDLRect. Souřadnice představované tímto objektem se vztahují vždy ke zdrojové bitmapě (k jejímu lokálnímu souřadnému systému):
# | Metoda | Popis |
---|---|---|
1 | int blitSurface(SDLSurface dstSurface) | přenos bitmapy do levého horního rohu cílové bitmapy |
2 | int blitSurface(SDLSurface dstSurface, SDLRect dst) | předchozí operace + možnost specifikace místa, na nějž bude bitmapa přenesena |
3 | int blitSurface(SDLRect src, SDLSurface dstSurface, SDLRect dst) | předchozí operace + možnost specifikace ořezového obdélníka |
Všechny tři varianty budou použity v demonstračních příkladech.
7. Demonstrační příklad SDLTest4 – načtení bitmapy typu BMP a provedení operace BitBLT
V prvním demonstračním příkladu si ukážeme způsob načtení bitmapy s jejím následným vykreslením na obrazovku. Nejprve je provedena inicializace knihovny SDL s využitím statické metody SDLMain.init(), které se pomocí konstanty SDLMain.SDL_INIT_VIDEO předá informace o tom, že se bude využívat pouze grafický subsystém SDL. Následně je s využitím taktéž statické metody SDLVideo.setVideoMode() provedeno přepnutí do celoobrazovkového grafického režimu s rozlišením 800×600 pixelů a s bitovou hloubkou 16 bitů na pixel. Všechny tyto operace jsme si již popsali v předchozí části tohoto seriálu. Následně se s využitím metody SDLVideo.loadBMP() načte bitmapa uložená ve formátu Microsoft Bitmap. Návratovou hodnotou této metody je instance třídy SDLSurface, v níž jsou uloženy jak hodnoty (barvy) jednotlivých pixelů, tak i rozměry bitmapy, její formát apod. Bitmapa je na obrazovku vykreslena pomocí metody SDLSurface.blitSurface(SDLSurface), přičemž plochou/bitmapou, do níž má být vykreslení provedeno, je samotný framebuffer.
Příklad má pořadové číslo 4, protože navazuje na demonstrační příklady vysvětlené minule:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLVideo; import sdljava.video.SDLSurface; /** * Ctvrty demonstracni priklad vyuzivajici knihovnu SDLjava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * Po inicializaci grafickeho rezimu se nacte bitmapa "xscorch.bmp", * ktera se nasledne vykresli na obrazovku operaci typu BitBLT. */ public class SDLTest4 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Nazev bitmapy, ktera se ma nacist a nasledne zobrazit. */ private static final String IMAGE_NAME = "xscorch.bmp"; /** * Vykresleni bitmapy na obrazovku. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery se ma na obrazovku vykreslit */ private static void drawOnScreen(SDLSurface screen, SDLSurface bitmap) throws SDLException { // provest operaci typu BitBLT bitmap.blitSurface(screen); // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu final SDLSurface screen = SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_FULLSCREEN); // nacteni bitmapy z externiho souboru final SDLSurface bitmap = SDLVideo.loadBMP(IMAGE_NAME); // vykresleni bitmapy na obrazovku drawOnScreen(screen, bitmap); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Skript pro překlad (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest4.java
Skript pro překlad (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest4.java
Skript pro spuštění (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest4.java
Skript pro spuštění (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest4
8. Demonstrační příklad SDLTest5 – určení pozice, kde se má bitmapa vykreslit
V dnešním druhém demonstračním příkladu pojmenovaném SDLTest5 si ukážeme další možnosti nabízené metodou SDLSurface.blitSurface. V předchozím příkladu se bitmapa načtená z externího souboru zobrazila v levém horním rohu obrazovky nastavené na grafický režim 800×600×16 bpp. V naprosté většině případů (snad až na vykreslení pozadí celé scény) však budeme potřebovat vykreslit bitmapu na jinou pozici na obrazovce. K tomuto účelu se musí namísto metody SDLSurface.blitSurface(SDLSurface dstSurface) použít její rozšířená varianta blitSurface(SDLSurface dstSurface, SDLRect dst). Této metodě se navíc předává obdélník, jehož počáteční souřadnice (x,y) určují, ve kterém místě na obrazovce (či na jiné bitmapě) se má zdrojová bitmapa začít vykreslovat, tj. kde bude ležet její horní levý roh. Šířka a výška obdélníku zde nemá prakticky žádný význam, v demonstračním příkladu se však pro úplnost nastaví i tyto dva atributy, a to konkrétně v metodě computePositionOnScreen.
Následuje výpis zdrojového kódu dnešního druhého demonstračního příkladu:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLRect; import sdljava.video.SDLVideo; import sdljava.video.SDLSurface; /** * Paty demonstracni priklad vyuzivajici knihovnu SDLjava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * Po inicializaci grafickeho rezimu se nacte bitmapa "xscorch.bmp", * ktera se nasledne vykresli na obrazovku operaci typu BitBLT, ovsem * se specifikaci presneho umisteni bitmapy na obrazovce. */ public class SDLTest5 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Nazev bitmapy, ktera se ma nacist a nasledne zobrazit. */ private static final String IMAGE_NAME = "xscorch.bmp"; /** * Vykresleni bitmapy na obrazovku. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery se ma na obrazovku vykreslit */ private static void drawOnScreen(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); // 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, ktery 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 demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu final SDLSurface screen = SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_FULLSCREEN); // nacteni bitmapy z externiho souboru final SDLSurface bitmap = SDLVideo.loadBMP(IMAGE_NAME); // vykresleni bitmapy na obrazovku drawOnScreen(screen, bitmap); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Skript pro překlad (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest5.java
Skript pro překlad (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest5.java
Skript pro spuštění (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest5.java
Skript pro spuštění (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest5
9. Demonstrační příklad SDLTest6 – ořez bitmapy při provádění operace typu BitBLT
V dalším demonstračním příkladu nazvaném SDLTest6 se taktéž vykresluje bitmapa načtená z externího souboru typu BMP (Windows Bitmap), ovšem souběžně s vykreslováním této bitmapy s využitím operace BitBLT se aplikuje i ořezávání rastrového obrázku na základě údajů předaných ve výše popsané datové struktuře typu SDLRect. Aby byl efekt ořezávání lépe viditelný, není bitmapa do framebufferu vykreslena pouze jedenkrát; namísto toho je na displeji zobrazena jednoduchá animace spočívající v plynulém posunování ořezového obdélníku přes vykreslovanou („blitovanou“) bitmapu. Celkem je zobrazeno tisíc snímků animace, přičemž minimální doba jednoho snímku je nastavena na deset milisekund. Způsobem přesnějšího časování se budeme zabývat později, v dnešním jednoduchém příkladu nám však bude dostačovat použití Thread.sleep(10). Zdrojový kód demonstračního příkladu vypadá následovně:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLRect; import sdljava.video.SDLVideo; import sdljava.video.SDLSurface; /** * Sesty demonstracni priklad vyuzivajici knihovnu SDLjava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * Po inicializaci grafickeho rezimu se nacte bitmapa "xscorch.bmp". * Nasledne se provede demonstrace moznosti metody * blitSurface(SDLRect src, SDLSurface dstSurface, SDLRect dst) */ public class SDLTest6 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Nazev bitmapy, ktera se ma nacist a nasledne zobrazit. */ private static final String IMAGE_NAME = "xscorch.bmp"; /** * Rozmery obdelniku pouziteho pri animaci. */ private static final int SOURCE_RECTANGLE_SIZE = 100; /** * Vykresleni jednoduche animace na obrazovku. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery se ma na obrazovku vykreslit * @throws InterruptedException */ private static void drawOnScreen(SDLSurface screen, SDLSurface bitmap) throws SDLException, InterruptedException { // vypocitat umisteni bitmapy na obrazovce. final SDLRect dstrect = computePositionOnScreen(screen, bitmap); // obdelnik urcujici orezani obrazku SDLRect srcrect = new SDLRect(0, 0, SOURCE_RECTANGLE_SIZE, SOURCE_RECTANGLE_SIZE); int x = 0, y = 0; int dx = 1, dy = 1; // jednoducha animace spocivajici v plynule zmene // pocatecniho bodu zdrojoveho obdelniku for (int i = 0; i < 1000; i++) { x += dx; y += dy; if (x >= bitmap.getWidth() - SOURCE_RECTANGLE_SIZE) { dx = -dx; } if (y >= bitmap.getHeight() - SOURCE_RECTANGLE_SIZE) { dy = -dy; } if (x <= 0) { dx = -dx; } if (y <= 0) { dy = -dy; } // vypocitat pocatecni bod zdrojoveho obdelniku srcrect.x = x; srcrect.y = y; // provest operaci typu BitBLT bitmap.blitSurface(srcrect, screen, dstrect); // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); Thread.sleep(10); } } /** * Vypocitat umisteni bitmapy na obrazovce. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery 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 demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu final SDLSurface screen = SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_FULLSCREEN); // nacteni bitmapy z externiho souboru final SDLSurface bitmap = SDLVideo.loadBMP(IMAGE_NAME); // vykresleni bitmapy na obrazovku drawOnScreen(screen, bitmap); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Skript pro překlad (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest6.java
Skript pro překlad (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest6.java
Skript pro spuštění (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest6.java
Skript pro spuštění (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest6
10. Demonstrační příklad SDLTest7 – načtení bitmapy uložené ve formátu PNG
V dnešním posledním demonstračním příkladu pojmenovaném SDLTest7 si ukážeme jeden z možných způsobů načtení bitmapy uložené ve formátu odlišném od poměrně primitivního a neúsporného formátu Microsoft Bitmap. Zde již není možné využít metodu sdljava.video.SDLVideo.loadBMP(), ale je nutné zavolat mnohem obecnější metodu sdljava.image.SDLImage.load(), která volá nativní funkce z libSDLJava_image.so popř. SDLJava_image.dll (ve skutečnosti jsou tyto nativní metody jen mezivrstvou ke knihovně libSDL_image.so/SDL_image.so). Důležité je, že je podporován například formát PNG, což je velmi užitečné, protože kromě (poměrně dobré) bezztrátové komprimace podporuje tento formát i různé metody uložení průhlednosti pixelů, takže do PNG je možné ukládat například sprity. S touto v oblasti 2D grafiky známou a již velmi dlouho využívanou technikou se seznámíme v následující části tohoto seriálu. Nyní se již podívejme na zdrojový kód demonstračního příkladu:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLVideo; import sdljava.video.SDLSurface; import sdljava.image.SDLImage; /** * Sedmy demonstracni priklad vyuzivajici knihovnu SDLjava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * Po inicializaci grafickeho rezimu se nacte bitmapa "xscorch.png", * ktera se nasledne vykresli na obrazovku operaci typu BitBLT. */ public class SDLTest7 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Nazev bitmapy, ktera se ma nacist a nasledne zobrazit. */ private static final String IMAGE_NAME = "xscorch.png"; /** * Vykresleni bitmapy na obrazovku. * * @param screen * framebuffer * @param bitmap * bitmapa, ktery se ma na obrazovku vykreslit */ private static void drawOnScreen(SDLSurface screen, SDLSurface bitmap) throws SDLException { // provest operaci typu BitBLT bitmap.blitSurface(screen); // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu final SDLSurface screen = SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_FULLSCREEN); // nacteni bitmapy z externiho souboru final SDLSurface bitmap = SDLImage.load(IMAGE_NAME); // vykresleni bitmapy na obrazovku drawOnScreen(screen, bitmap); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } } }
Skript pro překlad (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest7.java
Skript pro překlad (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest7.java
Skript pro spuštění (Linux):
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest7.java
Skript pro spuštění (Windows):
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest7
11. Repositář se zdrojovými kódy všech čtyř dnešních demonstračních příkladů
Všechny čtyři dnešní 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ím dí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:
Pro správnou činnost demonstračních příkladů je nutné mít v pracovním adresáři uloženu i dvojici obrázků xscorch.bmp a xscorch.png:
# | Bitmapa | Umístění souboru v repositáři |
---|---|---|
1 | xscorch.bmp | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/raw-file/6fe0d3a6edeb/sdljava/img/xscorch.bmp |
2 | xscorch.png | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/raw-file/6fe0d3a6edeb/sdljava/img/xscorch.png |
12. Odkazy na Internetu
- 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