Obsah
1. Pohled pod kapotu JVM – kreslicí funkce dostupné ve třídě sdljavax.gfx.SDLGfx
2. Seznam základních kreslicích funkcí
3. Kreslení na úrovni jednotlivých pixelů
7. Kreslení úseček, antialiasing a využití alfa kanálu
8. Demonstrační příklad SDLTest50: vykreslení obrazce složeného z úseček
9. Demonstrační příklad SDLTest51: využití antialiasingu
10. Repositář se zdrojovými kódy všech pěti dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – kreslicí funkce dostupné ve třídě sdljavax.gfx.SDLGfx
Při popisu knihovny SDLJava jsme se prozatím zmínili pouze o dvou způsobech používaných při vykreslování objektů do zvolené plochy typu SDL_Surface. Jedná se o metodu SDLSurface.fillRect(), které se předá objekt typu SDLRect obsahující informace o geometrii vyplňovaného obdélníku (pozice na obrazovce plus rozměry) a taktéž barva, kterou se má obdélník vyplnit. Barva je představována proměnnou typu long a pro získání skutečné hodnoty barvy se používá metoda SDLSurface.mapRGB(), která zajistí, že se výpočet barvy provede s ohledem na formát pixelů uložených v bitmapě nebo ve framebufferu. To mj. znamená, že v případě použití grafického režimu s jinou bitovou hloubkou vrátí tato metoda odlišnou hodnotu.
Druhý způsob vykreslování objektů, který nám knihovna SDLJava nabízí a který jsme si již také popsali, spočívá ve využití možností OpenGL – jakmile dojde k inicializaci kontextu OpenGL, je možné zahájit vykreslování do předního a/nebo zadního bufferu, a to samozřejmě s využitím schopností grafických akcelerátorů.
Existuje ovšem i mnoho případů, v nichž je zapotřebí provést vykreslení nějaké (základní) entity nikoli do framebufferu, ale do vybrané SDL_Surface uložené v operační paměti. V tomto případě nám již metoda SDLSurface.fillRect() nebude dostačovat a vykreslení přes OpenGL se zpětnou kopií bitmapy z framebufferu do vybrané SDL_Surface je zbytečně komplikované. Nicméně knihovna SDLJava nám i v této chvíli nabízí řešení spočívající ve využití funkcí uložených ve třídě sdljavax.gfx.SDLGfx. Termín „funkce“ je zde použit z toho důvodu, že v sdljavax.gfx.SDLGfx nalezneme pouze statické veřejné metody, což znamená, že tyto metody/funkce lze staticky importovat, což vede ke kratšímu zápisu algoritmů sloužících k vykreslení celé scény (a právě statický import sdljavax.gfx.SDLGfx bude použit i v dnešních demonstračních příkladech).
2. Seznam základních kreslicích funkcí
V následující tabulce jsou vypsány vybrané funkce ze třídy sdljavax.gfx.SDLGfx, které lze použít k vykreslení základních entit do zvolené plochy typu SDL_Surface. Povšimněte si, že mnoho funkcí se od sebe odlišuje pouze ve způsobu specifikace barvy:
# | Název funkce | Parametry | Stručný popis |
---|---|---|---|
1 | pixelColor | SDLSurface dst, int x, int y, long color | vykreslení pixelu |
2 | pixelRGBA | SDLSurface dst, int x, int y, int r, int g, int b, int a | vykreslení pixelu |
3 | lineColor | SDLSurface dst, int x1, int y1, int x2, int y2, long color | úsečka |
4 | lineRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int r, int g, int b, int a | úsečka |
5 | hlineColor | SDLSurface dst, int x1, int x2, int y, long color | vodorovná úsečka |
6 | hlineRGBA | SDLSurface dst, int x1, int x2, int y, int r, int g, int b, int a | vodorovná úsečka |
7 | vlineColor | SDLSurface dst, int x, int y1, int y2, long color | svislá úsečka |
8 | vlineRGBA | SDLSurface dst, int x, int y1, int y2, int r, int g, int b, int a | svislá úsečka |
9 | aalineColor | SDLSurface dst, int x1, int y1, int x2, int y2, long color | úsečka s vyhlazenou hranou |
10 | aalineRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int r, int g, int b, int a | úsečka s vyhlazenou hranou |
11 | circleColor | SDLSurface dst, int x, int y, int r, long color | kružnice |
12 | circleRGBA | SDLSurface dst, int x, int y, int rad, int r, int g, int b, int a | kružnice |
13 | aacircleColor | SDLSurface dst, int x, int y, int r, long color | kružnice s vyhlazeným okrajem |
14 | aacircleRGBA | SDLSurface dst, int x, int y, int rad, int r, int g, int b, int a | kružnice s vyhlazeným okrajem |
15 | filledCircleColor | SDLSurface dst, int x, int y, int r, long color | kruh |
16 | filledCircleRGBA | SDLSurface dst, int x, int y, int rad, int r, int g, int b, int a | kruh |
17 | ellipseColor | SDLSurface dst, int x, int y, int rx, int ry, long color | elipsa |
18 | ellipseRGBA | SDLSurface dst, int x, int y, int rx, int ry, int r, int g, int b, int a | elipsa |
19 | aaellipseColor | SDLSurface dst, int xc, int yc, int rx, int ry, long color | elipsa s vyhlazeným okrajem |
20 | aaellipseRGBA | SDLSurface dst, int x, int y, int rx, int ry, int r, int g, int b, int a | elipsa s vyhlazeným okrajem |
21 | filledEllipseColor | SDLSurface dst, int x, int y, int rx, int ry, long color | vyplněná elipsa |
22 | filledEllipseRGBA | SDLSurface dst, int x, int y, int rx, int ry, int r, int g, int b, int a | vyplněná elipsa |
3. Kreslení na úrovni jednotlivých pixelů
Z tabulky vypsané v předchozí kapitole lze mj. vyčíst, že knihovna SDLJava nabízí programátorům i dvojici funkcí určených pro zápis barvy jednoho pixelu do zvolené roviny typu SDL_Surface. Tyto funkce se jmenují pixelColor() a pixelRGBA(). Obě zmíněné funkce se od sebe odlišují pouze tím, jakým způsobem je reprezentována barva vykreslovaného pixelu. V případě použití funkce pixelRGBA() se barva zadává čtyřmi argumenty reprezentujícími barvové složky red, green a blue i průhlednost pixelu alfa. Funkce pixelColor() naproti tomu očekává, že barva i průhlednost pixelu bude reprezentována jedinou 32bitovou hodnotou, která musí mít formát 0×RRGGBBAA – to znamená, že v dolních osmi bitech je uložena průhlednost pixelu, v dalších osmi bitech červená barvová složka, následuje zelená barvová složka a konečně v nejvyšších osmi bitech je uložena červená barvová složka. Na tomto místě je zapotřebí upozornit na to, že v mnoha algoritmech, jejichž zápis lze najít na internetu, se naproti tomu předpokládá formát 0×AARRGGBB či dokonce 0×AABBGGRR!
4. Demonstrační příklad SDLTest47: vykreslení pixelů s využitím funkce sdljavax.gfx.SDLGfx.pixelRGBA()
V dnešním prvním demonstračním příkladu pojmenovaném SDLTest47 je ukázán způsob využití funkce sdljavax.gfx.SDLGfx.pixelRGBA() při nastavování barev jednotlivých pixelů uložených přímo ve framebufferu. V metodě drawOnScreen() je do zadního bufferu (back buffer) vykreslen vzorek známý pod jménem „circle (pattern)“, jenž je mj. použit i v programu Fractint. Každá barvová složka pixelu je nejprve uložena do lokální proměnné red, green, blue a následně je zavolána již zmíněná funkce sdljavax.gfx.SDLGfx.pixelRGBA(), která se postará o vykreslení pixelu do zadního bufferu. Povšimněte si posledního parametru této funkce – v něm je předána hodnota průhlednosti pixelu. Z tohoto důvodu zde používáme hodnotu 255, protože původně zadní buffer obsahoval pouze černé pixely:
// vykreslit vzorek s vyuzitim funkce pixelRGBA(). for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // vypocet barvovych slozek pixelu final int red = (x*x) + (y*y); final int green = ((x-1)*x) + (y*y); final int blue = (x*x) + ((y-1)*y); // vykresleni pixelu pixelRGBA(screen, x, y, red, green, blue, 255); } }
Obrázek 1: Vzorek vykreslený demonstračním příkladem SDLTest47.
Následuje výpis 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.SDLSurface; import sdljava.video.SDLVideo; import sdljava.x.swig.SDLPressedState; import static sdljavax.gfx.SDLGfx.*; /** * Ctyricaty sedmy demonstracni priklad vyuzivajici knihovnu SDLjava. * * Vykresleni vzorku s vyuzitim funkce sdljavax.gfx.SDLGfx.pixelRGBA(). * * @author Pavel Tisnovsky */ public class SDLTest47 { /** * 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; /** * 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 sceny na obrazovku ci do okna aplikace. * * @param screen * framebuffer */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // rozmery okna aplikace ci rozliseni obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vykreslit vzorek s vyuzitim funkce pixelRGBA(). for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // vypocet barvovych slozek pixelu final int red = (x*x) + (y*y); final int green = ((x-1)*x) + (y*y); final int blue = (x*x) + ((y-1)*y); // vykresleni pixelu pixelRGBA(screen, x, y, red, green, blue, 255); } } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni ctyricateho sedmeho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // vykresleni sceny na obrazovku drawOnScreen(screen); // smycka pro zpracovani udalosti eventLoop(); } 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 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 SDLTest47.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 SDLTest47.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 SDLTest47
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% SDLTest47
5. Demonstrační příklad SDLTest48: vykreslení pixelů s využitím funkce sdljavax.gfx.SDLGfx.pixelColor()
Ve druhém demonstračním příkladu pojmenovaném SDLTest48 je ukázáno použití funkce sdljavax.gfx.SDLGfx.pixelColor() pro vykreslení vzorku „circle pattern“, který by měl odpovídat vzorku vykresleného v předchozím demonstračním příkladu. Barvové složky jednotlivých pixelů jsou opět (v metodě drawOnScreen) vypočteny zvlášť a posléze jsou sloučeny do jediné 32bitové hodnoty, a to z toho důvodu, že funkce sdljavax.gfx.SDLGfx.pixelColor() akceptuje barvu a průhlednost pixelu zakódovanou do jediného 32bitového slova:
// vykreslit vzorek s vyuzitim funkce pixelColor(). for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // vypocet barvovych slozek pixelu final int red = (x*x) + (y*y); final int green = ((x-1)*x) + (y*y); final int blue = (x*x) + ((y-1)*y); // vypocet barvy final int color = (red << 24) | (green << 16) | (blue << 8) | 255; // vykresleni pixelu pixelColor(screen, x, y, color); } }
Při pohledu na vzorek vykreslený tímto demonstračním příkladem je však patrné, že ve skutečnosti při výpočtu barev jednotlivých pixelů došlo k chybě. Ta je způsobena tím, že hodnoty jednotlivých barvových složek mohou být vyšší než 255 a tím pádem hodnota dané barvové složky „přeteče“ do té části 32bitové hodnoty, která je již vyhrazena pro jinou barvovou složku:
Obrázek 2: Vzorek vykreslený demonstračním příkladem SDLTest48.
Opět se podívejme na výpis úplného zdrojového textu 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.SDLSurface; import sdljava.video.SDLVideo; import sdljava.x.swig.SDLPressedState; import static sdljavax.gfx.SDLGfx.*; /** * Ctyricaty osmy demonstracni priklad vyuzivajici knihovnu SDLjava. * * Vykresleni vzorku s vyuzitim funkce sdljavax.gfx.SDLGfx.pixelColor(). * * @author Pavel Tisnovsky */ public class SDLTest48 { /** * 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; /** * 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 sceny na obrazovku ci do okna aplikace. * * @param screen * framebuffer */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // rozmery okna aplikace ci rozliseni obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vykreslit vzorek s vyuzitim funkce pixelColor(). for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // vypocet barvovych slozek pixelu final int red = (x*x) + (y*y); final int green = ((x-1)*x) + (y*y); final int blue = (x*x) + ((y-1)*y); // vypocet barvy final int color = (red << 24) | (green << 16) | (blue << 8) | 255; // vykresleni pixelu pixelColor(screen, x, y, color); } } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni ctyricateho osmeho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // vykresleni sceny na obrazovku drawOnScreen(screen); // smycka pro zpracovani udalosti eventLoop(); } 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 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 SDLTest48.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 SDLTest48.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 SDLTest48
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% SDLTest48
6. Demonstrační příklad SDLTest49: korektní výpočet barev pro funkci sdljavax.gfx.SDLGfx.pixelColor()
Náprava chyby při výpočtu barvových složek jednotlivých pixelů, které jsme se dopustili v předchozím demonstračním příkladu, je ve skutečnosti velmi jednoduchá. Hodnoty barvových složek je nutné upravit s využitím masky 255 (0×ff) takovým způsobem, aby jejich výsledná hodnota ležela pouze v rozsahu 0 až 255. Poté lze již bez dalších problémů spojit jednotlivé barvové složky i průhlednost do jediného 32bitového slova předaného do funkce sdljavax.gfx.SDLGfx.pixelColor():
// vykreslit vzorek s vyuzitim funkce pixelColor(). for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // vypocet barvovych slozek pixelu final int red = 0xff & ((x*x) + (y*y)); final int green = 0xff & (((x-1)*x) + (y*y)); final int blue = 0xff & ((x*x) + ((y-1)*y)); // vypocet barvy final int color = (red << 24) | (green << 16) | (blue << 8) | 255; // vykresleni pixelu pixelColor(screen, x, y, color); } }
Obrázek 3: Vzorek vykreslený demonstračním příkladem SDLTest49.
Podívejme se nyní na úplný výpis opraveného 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.SDLSurface; import sdljava.video.SDLVideo; import sdljava.x.swig.SDLPressedState; import static sdljavax.gfx.SDLGfx.*; /** * Ctyricaty devaty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Vykresleni vzorku s vyuzitim funkce sdljavax.gfx.SDLGfx.pixelColor(). * * @author Pavel Tisnovsky */ public class SDLTest49 { /** * 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; /** * 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 sceny na obrazovku ci do okna aplikace. * * @param screen * framebuffer */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // rozmery okna aplikace ci rozliseni obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vykreslit vzorek s vyuzitim funkce pixelColor(). for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // vypocet barvovych slozek pixelu final int red = 0xff & ((x*x) + (y*y)); final int green = 0xff & (((x-1)*x) + (y*y)); final int blue = 0xff & ((x*x) + ((y-1)*y)); // vypocet barvy final int color = (red << 24) | (green << 16) | (blue << 8) | 255; // vykresleni pixelu pixelColor(screen, x, y, color); } } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni ctyricateho devateho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // vykresleni sceny na obrazovku drawOnScreen(screen); // smycka pro zpracovani udalosti eventLoop(); } 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 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 SDLTest49.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 SDLTest49.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 SDLTest49
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% SDLTest49
7. Kreslení úseček, antialiasing a využití alfa kanálu
V knihovně SDLJava nalezneme mj. i osm funkcí sloužících pro vykreslení úsečky o šířce jednoho pixelu vybranou barvou do zvolené SDL_Surface. Těchto osm funkcí lze rozdělit podle tří vlastností – jakým způsobem je zapsána barva úsečky (čtyři složky versus 32bitové slovo), o jaký typ úsečky se jedná (obecná úsečka, vodorovná úsečka, svislá úsečka) a konečně, zda se má či naopak nemá při vykreslování použít algoritmus pro vyhlazení hran (Bresenhamův algoritmus popř. při vyhlazování Xiaolin Wuův algoritmus). Všech osm zmíněných funkcí je vypsáno v následující tabulce, kde si můžete povšimnout, že algoritmus pro vyhlazení hran není použit pro vodorovné či svislé úsečky, což je ostatně logické, neboť by v tomto případě mohlo dojít k rozostření hrany:
# | Název funkce | Parametry | Stručný popis |
---|---|---|---|
1 | lineColor | SDLSurface dst, int x1, int y1, int x2, int y2, long color | úsečka |
2 | lineRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int r, int g, int b, int a | úsečka |
3 | hlineColor | SDLSurface dst, int x1, int x2, int y, long color | vodorovná úsečka |
4 | hlineRGBA | SDLSurface dst, int x1, int x2, int y, int r, int g, int b, int a | vodorovná úsečka |
5 | vlineColor | SDLSurface dst, int x, int y1, int y2, long color | svislá úsečka |
6 | vlineRGBA | SDLSurface dst, int x, int y1, int y2, int r, int g, int b, int a | svislá úsečka |
7 | aalineColor | SDLSurface dst, int x1, int y1, int x2, int y2, long color | úsečka s vyhlazenou hranou |
8 | aalineRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int r, int g, int b, int a | úsečka s vyhlazenou hranou |
8. Demonstrační příklad SDLTest50: vykreslení obrazce složeného z úseček
Podívejme se nyní na způsob, jak lze s využitím funkce lineRGBA() vykreslit obrazec složený z úseček (jedná se o tzv. „string art“). Při vykreslení se používá průhlednost nastavená na hodnotu 0×80 (tj. 128 v desítkové soustavě), což znamená, že úsečky jsou na černém pozadí vykresleny šedou barvou [127, 127, 127] a v místech překryvu úseček nalezneme pixely se světlejší barvou [191, 191, 191] popř. při vícenásobném překryvu i [223, 223, 223]. I přes použití průhlednosti je však při vykreslování použit Bresenhamův algoritmus, který úsečku vykreslí s ostrými hranami (což může a nemusí být očekávaný výsledek):
Obrázek 4: Vzorek vykreslený demonstračním příkladem SDLTest50.
Zdrojový kód demonstračního příkladu SDLTest50:
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.SDLSurface; import sdljava.video.SDLVideo; import sdljava.x.swig.SDLPressedState; import static sdljavax.gfx.SDLGfx.*; /** * Padesaty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Vykresleni vzorku s vyuzitim funkce sdljavax.gfx.SDLGfx.lineRGBA(). * * @author Pavel Tisnovsky */ public class SDLTest50 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 480; /** * 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; /** * 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 sceny na obrazovku ci do okna aplikace. * * @param screen * framebuffer */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // rozmery okna aplikace ci rozliseni obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vypocet barvovych slozek pixelu final int red = 0xff; final int green = 0xff; final int blue = 0xff; final int alpha = 0x80; // vykreslit vzorek s vyuzitim funkce lineRGBA(). for (int i = 0; i < Math.min(width, height); i += 10) { // vykresleni usecky lineRGBA(screen, 0, i, i, height-1, red, green, blue, alpha); // vykresleni usecky lineRGBA(screen, 10, 0, width-1, i, red, green, blue, alpha); } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni padesateho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // vykresleni sceny na obrazovku drawOnScreen(screen); // smycka pro zpracovani udalosti eventLoop(); } 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 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 SDLTest50.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 SDLTest50.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 SDLTest50
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% SDLTest50
9. Demonstrační příklad SDLTest51: využití antialiasingu
V případě nutnosti vykreslení úsečky s vyhlazenými hranami se musí namísto funkcí lineRGBA()/lineColor() použít funkce aalineRGBA() popř. aalineColor(). Při implementaci těchto funkcí již není použit rychlý Bresenhamův algoritmus, ale nepatrně pomalejší algoritmus navržený Xiaolin Wuem, který vykresluje úsečku širokou dva pixely, přičemž se však (poněkud zjednodušeně řečeno) barvy obou pixelů vypočítají ze vzdálenosti středů těchto pixelů od skutečného průběhu úsečky. Výsledkem jsou skutečně vyhlazené úsečky, ovšem jednou z nevýhod tohoto algoritmu může být vznik nepříjemného moaré patrného i z pátého screenshotu:
Obrázek 5: Vzorek vykreslený demonstračním příkladem SDLTest51.
Zdrojový kód demonstračního příkladu SDLTest51:
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.SDLSurface; import sdljava.video.SDLVideo; import sdljava.x.swig.SDLPressedState; import static sdljavax.gfx.SDLGfx.*; /** * Padesaty prvni demonstracni priklad vyuzivajici knihovnu SDLjava. * * Vykresleni vzorku s vyuzitim funkce sdljavax.gfx.SDLGfx.aalineRGBA(). * * @author Pavel Tisnovsky */ public class SDLTest51 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 480; /** * 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; /** * 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 sceny na obrazovku ci do okna aplikace. * * @param screen * framebuffer */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // rozmery okna aplikace ci rozliseni obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vypocet barvovych slozek pixelu final int red = 0xff; final int green = 0xff; final int blue = 0xff; final int alpha = 0x80; // vykreslit vzorek s vyuzitim funkce aalineRGBA(). for (int i = 0; i < Math.min(width, height); i += 10) { // vykresleni usecky aalineRGBA(screen, 0, i, i, height-1, red, green, blue, alpha); // vykresleni usecky aalineRGBA(screen, 10, 0, width-1, i, red, green, blue, alpha); } // nutno volat i v pripade, ze neni pouzit double buffering screen.updateRect(); screen.flip(); } /** * Spusteni padesateho prvniho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace knihovny SDLJava SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani final SDLSurface screen = initVideo(); // vykresleni sceny na obrazovku drawOnScreen(screen); // smycka pro zpracovani udalosti eventLoop(); } 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 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 SDLTest51.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 SDLTest51.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 SDLTest51
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% SDLTest51
10. Repositář se zdrojovými kódy všech pěti dnešních demonstračních příkladů
Všech pět dnes popsaných demonstračních příkladů bylo společně s podpůrnými skripty určenými pro jejich překlad a následné spuštění uloženo 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:
11. 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