Obsah
1. Pohled pod kapotu JVM – blending a textury s alfa kanálem v knihovně SDLJava
2. Průhlednost a poloprůhlednost fragmentů, alfa kanál a alfa blending
3. Tvar míchací funkce (blending function) využívané při vykreslování
4. Význam konstant předávaných do metody GL.glBlendFunc()
5. Alfa blending prováděný při vykreslování trojrozměrných scén
6. Demonstrační příklad SDLTest23 – alfa blending u textury načtené ze souboru
7. Demonstrační příklad SDLTest24 – nastavení poloprůhlednosti při vykreslování
8. Demonstrační příklad SDLTest25 – ukázka dalších možností blendingu
9. Repositář se zdrojovými kódy všech čtyř dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – blending a textury s alfa kanálem v knihovně SDLJava
Texturování popsané v předchozí části tohoto seriálu lze využít pro pokrytí stěn trojrozměrných těles nějakým (bitmapovým) vzorkem, ovšem stejná technologie se v současnosti používá například i u stále populárních 2D her, zejména pro vyobrazení scrollujícího pozadí hry nebo pro vykreslení pohybujících se spritů. V těchto oblastech však již nevystačíme se zcela neprůhlednými texturami, ale je nutné nějakým způsobem umět pracovat s texturami, v nichž jsou některé texely průhledné či dokonce poloprůhledné. Samotné grafické akcelerátory, grafická knihovna OpenGL a zprostředkovaně i javovská knihovna SDLJava samozřejmě práci s texturami majícími (polo)průhledné texely podporuje; celá tato funkcionalita je součástí obecnější technologie – blendingu – při němž dochází k míchání barev pixelů již uložených do framebufferu s právě vykreslovanými fragmenty. Podrobnosti o blendingu a především pak o blendingu využívajícího alfa kanál si popíšeme v navazujících kapitolách.
V předchozích částech tohoto seriálu jsme se již několikrát zmínili o barvovém prostoru používaném při práci s barvami v knihovně OpenGL. Barvy jsou v tomto barvovém prostoru popsány pomocí tří barvových složek R (Red), G (Green) a B (Blue). K těmto třem složkám se často přidává ještě složka čtvrtá, nazývaná A (Alfa). Výsledný barvový prostor se proto označuje zkratkou RGBA. Pomocí alfa složky (někdy také nazývané alfa-kanál) lze specifikovat míru průhlednosti, resp. naopak neprůhlednosti vybraných objektů nebo jejich plošek. Alfa složku lze také nastavit samostatně pro každý texel ve vykreslované textuře, čehož se poměrně často využívá při programování mnoha grafických efektů, například výbuchů. A právě tuto vlastnost OpenGL využijeme v dnešních demonstračních příkladech. Při spuštění programu, který používá pro vykreslování grafickou knihovnu OpenGL, je vliv alfa složky na vykreslovanou plošku zakázán. Proto, pokud chceme programovat některé grafické efekty, musíme před vykreslením vhodně nastavit režim míchání již nakreslené části scény s nově vykreslovanými tělesy.
2. Průhlednost a poloprůhlednost fragmentů, alfa kanál a alfa blending
Nejprve si připomeňme, že takzvaný fragment je velmi jednoduchá datová struktura (popisující diskrétní část plochy) složená z barvy pixelu, jeho průhlednosti, vzdálenosti od pozorovatele (popř. převrácené hodnoty vzdálenosti od pozorovatele) a případných dalších podpůrných informací. Framebuffer je v podstatě pravidelně uspořádaná matice (rastr) fragmentů, i když většinou o framebufferu přemýšlíme spíše jako o množině několika specializovaných bufferů (color-buffer, paměť hloubky neboli Z-buffer, stencil buffer, accumulation buffer jakožto zobecněná forma color-bufferu atd.). Barvy fragmentů tvoří ve framebufferu samostatný color-buffer, který se posléze – po vykreslení celé scény – zobrazuje na obrazovce. Rasterizace je proces, kterým se matematický model plošky (polygonu) převádí na jednotlivé fragmenty. Při použití blendingu (tj. míchání barev) musíme nejdříve specifikovat, jakým způsobem se budou kombinovat právě vykreslované fragmenty s hodnotami uloženými ve framebufferu. Způsob míchání barvy uložené ve framebufferu a barvy aktuálně vykreslovaného fragmentu se řídí uživatelem definovanou míchací funkci (blending function). V této (velmi jednoduché) funkci vystupují následující členy:
- Zdroj (source) je fragment vzniklý rasterizací v právě běžícím rasterizačním procesu (můžeme si představit například vykreslení trojúhelníku postupnou rasterizací/diskretizací plochy trojúhelníku na jednotlivé fragmenty).
- Cíl (destination) je hodnota již dříve zapsaná do framebufferu, tj. barva fragmentu, který již byl do framebufferu vykreslen dříve. Tato hodnota bude v závislosti na aktuálně nastavené blending funkci přepsána nebo jinak ovlivněna.
V knihovně OpenGL lze stanovit koeficienty míchání pro každou barvovou složku zvlášť. Tak lze jednoduše dosáhnout na první pohled složitých efektů, například maskování jedné barvy apod.
3. Tvar míchací funkce (blending function) využívané při vykreslování
Míchací rovnici (původně ve vektorovém tvaru), která se při blendingu používá pro výpočet nové barvy fragmentu, je možné rozepsat do čtyř rovnic odpovídajících barvovému modelu RGBA:
Rn=RsSr+RdDr |
Gn=GsSg+GdDg |
Bn=BsSb+BdDb |
An=AsSa+AdDa |
Význam jednotlivých členů použitých v rovnicích je následující:
# | Člen | Význam |
---|---|---|
1 | Rn | nově vypočtená červená barvová složka |
2 | Gn | nově vypočtená zelená barvová složka |
3 | Bn | nově vypočtená modrá barvová složka |
4 | An | nová hodnota alfa složky |
5 | Rs | červená barvová složka zdrojového fragmentu |
6 | Gs | zelená barvová složka zdrojového fragmentu |
7 | Bs | modrá barvová složka zdrojového fragmentu |
8 | As | alfa složka zdrojového fragmentu |
9 | Rd | červená barvová složka cílového fragmentu |
10 | Gd | zelená barvová složka cílového fragmentu |
11 | Bd | modrá barvová složka cílového fragmentu |
12 | Ad | alfa složka cílového fragmentu |
13 | Sr | míchací faktor pro červenou barvu zdrojového fragmentu |
14 | Sg | míchací faktor pro zelenou barvu zdrojového fragmentu |
15 | Sb | míchací faktor pro modrou barvu zdrojového fragmentu |
16 | Sa | míchací faktor pro alfa složku zdrojového fragmentu |
17 | Dr | míchací faktor pro červenou barvu cílového fragmentu |
18 | Dg | míchací faktor pro zelenou barvu cílového fragmentu |
19 | Db | míchací faktor pro modrou barvu cílového fragmentu |
20 | Da | míchací faktor pro alfa složku cílového fragmentu |
Pro praktické použití si však stačí zapamatovat význam jednotlivých písmen: R-red, G-green, B-blue, A-alpha, n-new fragment, s-source fragment, d-destination fragment.
Ve výše uvedených rovnicích je nutné specifikovat míchací faktory (koeficienty) Sr, Sg, Sb, Sa, Dr, Dg, Db a Da, ostatní hodnoty odpovídají barvám a alfa-složkám zdrojových a cílových fragmentů. Koeficienty S a D se nezadávají přímo číselnou hodnotou, protože se mohou měnit v závislosti na barvách zdrojových a cílových fragmentů. Místo toho se používají symboly (symbolické konstanty), jejichž konkrétní hodnota se vypočte automaticky při rasterizaci.
4. Význam konstant předávaných do metody GL.glBlendFunc()
Pro zadání míchacích koeficientů se používá metoda:
org.gljava.opengl.GL.glBlendFunc(long sFactor, long dFactor);
První parametr sFactor určuje způsob výpočtu míchacích faktorů Sr, Sg, Sb a Sa, druhý parametr dFactor pak způsob výpočtu faktorů Dr, Dg, Db a Da.
Pro hodnoty, které lze do těchto parametrů dosadit, platí základní pravidla:
- Za sFactor popř. dFactor lze dosadit některou z konstant, které jsou předdefinovány v hlavičkovém souboru gl.h (nativní rozhraní OpenGL) či jako konstanty v rozhraní org.gljava.opengl.GL (knihovna SDLJava).
- Některé z těchto konstant lze zadat do obou parametrů. Jedná se například o konstanty GL_ZERO, GL_ONE apod. Význam těchto konstant se samozřejmě liší podle toho, do kterého parametru jsou dosazeny.
- Některé konstanty lze použít pouze pro parametr sFactor. Jedná se například o konstanty GL_DST_COLOR nebo GL_ONE_MINUS_DST_COLOR.
- Některé konstanty lze naopak použít pouze pro parametrdFactor. Jde o konstanty GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR apod.
V následující tabulce je vypsán význam míchacích faktorů, které můžeme použít pro specifikaci koeficientů míchací rovnice. Ve sloupci Název je jméno faktoru, tj. konstanta definovaná v rozhraní GL. Ve sloupci Použití je označeno, zda se může symbolická konstanta použít pro dosazení do parametru sFactor (S), dFactor (D) nebo do obou parametrů. Ve sloupci Význam jsou ve vektorovém tvaru naznačeny hodnoty zdrojových či cílových koeficientů.
# | Název | Použití | Význam |
---|---|---|---|
1 | GL_ZERO | S nebo D | (0, 0, 0, 0) |
2 | GL_ONE | S nebo D | (1, 1, 1, 1) |
3 | GL_DST_COLOR | S | (Rd, Gd, Bd, Ad) |
4 | GL_SRC_COLOR | D | (Rs, Gs, Bs, As) |
5 | GL_ONE_MINUS_DST_COLOR | S | (1, 1, 1, 1)-(Rd, Gd, Bd, Ad) |
6 | GL_ONE_MINUS_SRC_COLOR | D | (1, 1, 1, 1)-(Rs, Gs, Bs, As) |
7 | GL_SRC_ALPHA | S nebo D | (As, As, As, As) |
8 | GL_ONE_MINUS_SRC_ALPHA | S nebo D | (1, 1, 1, 1)-(As, As, As, As) |
9 | GL_DST_ALPHA | S nebo D | (Ad, Ad, Ad, Ad) |
10 | GL_ONE_MINUS_DST_ALPHA | S nebo D | (1, 1, 1, 1)-(Ad, Ad, Ad, Ad) |
11 | GL_SRC_ALPHA_SATURATE | S | (f, f, f, 1) f=min(As, 1-Ad) |
5. Alfa blending prováděný při vykreslování trojrozměrných scén
Při vykreslování průhledných či poloprůhledných trojrozměrných těles záleží vizuální vzhled výsledné scény na zvoleném pořadí renderovaných objektů, na rozdíl od neprůhledných těles, kde jsou neviditelné (plně či částečně překryté) stěny automaticky odstraněny díky testu na hloubku fragmentů prováděnou při renderingu s využitím paměti hloubky (nezávisle na pořadí vykreslování). Jako první by se proto při práci s průhlednými tělesy měly vykreslit nejvzdálenější objekty (resp. přesněji řečeno jejich stěny). Zejména proto, že řazení stěn podle vzdálenosti od pozorovatele je časově náročné a nejednoznačné, je nutno metodu pro praktické využití nepatrně vylepšit. Doporučuje se dodržovat následující postup:
- Nejprve je zapotřebí při startu aplikace alokovat společně s barvovými buffery i paměť hloubky (Z-buffer). V případě použití knihovnySDLJava se tato inicializace může provést automaticky při nastavování grafického režimu.
- Paměť hloubky (Z-buffer) se musí nastavit do režimu čtení i zápisu (read-write) hloubek fragmentů. Toho dosáhneme zavoláním příkazuGL.glDepthMask(true).
- Po nastavení a povolení paměti hloubky se vykreslí všechny neprůhledné objekty, resp. přesněji řečeno všechny neprůhledné stěny. Tyto objekty se vzhledem k testu hloubky každého vykreslovaného fragmentu vykreslí korektně, tj. vzdálenější stěny budou korektně překryty bližšími stěnami. To je zapříčiněno funkcí paměti hloubky a komparátoru, který pro každý vykreslovaný fragment testuje, zda je umístěn před nebo za již vykresleným fragmentem, jehož hloubka je v hloubkovém bufferu uložena. Po vykreslení všech neprůhledných objektů je tedy v paměti hloubky zapsána „výšková mapa“ nejbližších vykreslených fragmentů v každé buňce framebufferu (formát zde uložených vzdáleností je většinou reprezentován číslem 1/z, takže by bylo přesnější mluvit o tzn. W-bufferu a ne o Z-bufferu, to je však pouze implementační detail).
- Před vykreslením průhledných objektů se musí funkce paměti hloubky nastavit do režimu read-only, tj. hloubky fragmentů jsou z hloubkového bufferu pouze čteny při komparaci (a tyto fragmenty jsou popř. odstraněny z dalšího vykreslování). Zápis hodnot do hloubkového bufferu je zakázán, protože průhledné objekty se musí vykreslit i tehdy, pokud jsou schovány za dalším průhledným objektem a neprůhledné objekty se za objekty průhlednými nesmí vymazat. Nastavení hloubkového bufferu do režimu read-only provedeme příkazem/metodou GL.glDepthMask(false).
- Dalším krokem je programové seřazení průhledných objektů podle jejich hloubky (vzdálenosti) od pozorovatele. Objekty se poté vykreslí v tomto pořadí, nejdříve samozřejmě objekt nejvzdálenější.
- Složité objekty, tj. objekty, jejichž plošky jsou složeny z mnohoúhelníků, je někdy nutné takzvanou tesselací rozdělit na jednotlivé trojúhelníky, jinak by mohly nastat vizuální chyby při překrývání objektů. K tesselaci je možné použít již existující knihovny (v případě céčka například knihovnu GLU).
- Po vykreslení všech průhledných objektů se hloubkový buffer nastaví opět do režimu read-write (GL.glDepthMask(true)), aby se v příštím průchodu (snímku) neprůhledné objekty vykreslily korektně.
6. Demonstrační příklad SDLTest23 – alfa blending u textury načtené ze souboru
V dnešním prvním demonstračním příkladu nazvaném SDLTest23 je ukázáno, jakým způsobem je možné použít externí rastrový obrázek s (polo)průhlednými pixely jako texturu použitou při vykreslení vyplněného čtyřúhelníku. Obrázek, který je zde použitý, byl získán z Wikipedie a obsahuje jak zcela neprůhledné pixely, tak i částečně či zcela průhledné pixely. Aby bylo možné korektně uložit celý alfa kanál s osmibitovou hloubkou, byl vybrán formát PNG. Originální obrázek použitý ve funkci textury vypadá takto:
Alfa kanál lze zobrazit následujícím způsobem (průhlednost určuje úroveň šedé, šachovnice značí zcela průhledné pixely):
Na detailu hrany písmena C je patrné, že obrázek skutečně obsahuje i poloprůhledné pixely:
Povšimněte si, že i přesto, že načtená textura obsahuje alfa kanál, je nutné při texturování povolit blending, jinak by se výpočet průhlednosti neprovedl korektně (ostatně sami si můžete vyzkoušet, co se stane, když se následující příkazy zakomentují):
// nastaveni blendingu gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
Následuje výpis zdrojového kódu demonstračního příkladu SDLTest23:
import java.nio.ByteBuffer; import java.nio.ByteOrder; import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; import org.gljava.opengl.Texture; import org.gljava.opengl.TextureFactory; /** * Dvacaty treti demonstracni priklad vyuzivajici knihovnu SDLjava. * * Texturovani, objekt typu Texture a alfa blending. * * @author Pavel Tisnovsky */ public class SDLTest23 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 600; /** * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_HEIGHT = 600; /** * 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_OPENGL | SDLVideo.SDL_DOUBLEBUF; return SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, flags); } /** * Nastaveni transformacnich matic a barvy pozadi framebufferu. */ private static void initScene(GL gl, int width, int height) { // nastaveni projekcni matice gl.glMatrixMode(gl.GL_PROJECTION); // jednotkova matice gl.glLoadIdentity(); // mapovani abstraktnich souradnic do souradnic okna ci cele obrazovky gl.glOrtho(0, width, height, 0, -1, 1); // nastaveni modelview matice gl.glMatrixMode(gl.GL_MODELVIEW); gl.glLoadIdentity(); // viditelna oblast gl.glViewport(0, 0, width, height); // vypnuti pameti hloubky pri vykreslovani gl.glDisable(gl.GL_DEPTH_TEST); // opakovani textury gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT); gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT); // volba filtru gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST); gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST); // vylepseni zobrazovani v pripade pouziti perspektivni projekce gl.glHint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_NICEST); // barva pozadi framebufferu pro volani glClear() gl.glClearColor (0.0f, 0.0f, 0.0f, 0.0f); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl, Texture texture) { // vymazani framebufferu gl.glClear(GL.GL_COLOR_BUFFER_BIT); // zakaz prace s texturami gl.glDisable(gl.GL_TEXTURE_2D); gl.glBegin(GL.GL_LINES); gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex2i(0, 0); gl.glColor3f(1.0f, 0.0f, 1.0f); gl.glVertex2i(600, 600); gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex2i(600, 0); gl.glColor3f(1.0f, 1.0f, 0.0f); gl.glVertex2i(0, 600); gl.glEnd(); // povoleni prace s texturami gl.glEnable(GL.GL_TEXTURE_2D); // nastaveni blendingu gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); texture.bind(gl); // vykresleni ctyruhelniku gl.glBegin(GL.GL_QUADS); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex2i(100, 100); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex2i(500, 100); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex2i(500, 500); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex2i(100, 500); gl.glEnd(); gl.glFlush(); // provedeni a vykresleni vsech zmen } /** * Spusteni osmeho demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani SDLSurface screen = initVideo(); // inicializace celoobrazovkoveho grafickeho rezimu GL gl = screen.getGL(); // nastaveni transformacnich matic a barvy pozadi framebufferu initScene(gl, GFX_WIDTH, GFX_HEIGHT); // nacteni textury Texture texture = TextureFactory.getFactory().loadTexture(gl, "c.png"); // vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL drawScene(gl, texture); // prepnuti predniho a zadniho bufferu screen.glSwapBuffers(); // ukonceni cele aplikace po peti sekundach Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } // zobrazit ziskane informace } }
Skript pro překlad na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest23.java
Dávkový soubor pro překlad na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest23.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 SDLTest23
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% SDLTest23
Obrázek 1: Scéna vykreslená po spuštění demonstračního příkladu SDLTest23.
7. Demonstrační příklad SDLTest24 – nastavení poloprůhlednosti při vykreslování
Jak jsme si již řekli v úvodních kapitolách, netýká se nastavení průhlednosti pouze texelů, z nichž se skládají textury, ale průhlednost je možné nastavit i při vykreslování různých geometrických primitiv podporovaných knihovnou SDLJava. V dnešním druhém demonstračním příkladu je ukázáno využití metody GL.glColor4f() pro specifikaci barvy a současně i průhlednosti při vykreslování čtverců. V programové smyčce umístěné do uživatelské metody drawScene() je postupně vykreslen čtverec vyplněný různými barvami, jehož neprůhlednost je postupně nastavována na hodnoty 0%, 20%, 40%, 60%, 80% a 100%:
// nastaveni blendingu gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); float[][] colors = { {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, }; // vykresleni serie nekolika ctvercu ruznou barvou // s ruznou pruhlednosti float alpha; int x, y; for (y = 0; y < colors.length; y++) { for (x = 0, alpha = 0.0f; x <= 500; x += 100, alpha += 0.2f) { drawSquare(gl, x, y*100, colors[y][0], colors[y][1], colors[y][2], alpha); } }
Následuje výpis zdrojového kódu příkladu SDLTest24:
import java.nio.ByteBuffer; import java.nio.ByteOrder; import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; import org.gljava.opengl.Texture; import org.gljava.opengl.TextureFactory; /** * Dvacaty ctvrty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Alfa blending pri vykreslovani. * * @author Pavel Tisnovsky */ public class SDLTest24 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 600; /** * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_HEIGHT = 600; /** * 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_OPENGL | SDLVideo.SDL_DOUBLEBUF; return SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, flags); } /** * Nastaveni transformacnich matic a barvy pozadi framebufferu. */ private static void initScene(GL gl, int width, int height) { // nastaveni projekcni matice gl.glMatrixMode(gl.GL_PROJECTION); // jednotkova matice gl.glLoadIdentity(); // mapovani abstraktnich souradnic do souradnic okna ci cele obrazovky gl.glOrtho(0, width, height, 0, -1, 1); // nastaveni modelview matice gl.glMatrixMode(gl.GL_MODELVIEW); gl.glLoadIdentity(); // viditelna oblast gl.glViewport(0, 0, width, height); // vypnuti pameti hloubky pri vykreslovani gl.glDisable(gl.GL_DEPTH_TEST); // barva pozadi framebufferu pro volani glClear() gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); } /** * Vykresleni ctverce. */ private static void drawSquare(GL gl, int x, int y, float r, float g, float b, float a) { // vykresleni ctyruhelniku gl.glColor4f(r, g, b, a); gl.glBegin(GL.GL_QUADS); gl.glVertex2i(x+10, y+10); gl.glVertex2i(x+90, y+10); gl.glVertex2i(x+90, y+90); gl.glVertex2i(x+10, y+90); gl.glEnd(); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu (bile pozadi) gl.glClear(GL.GL_COLOR_BUFFER_BIT); // zakaz blendingu gl.glDisable(GL.GL_BLEND); // vykresleni mrizky gl.glColor3f(0.0f, 0.0f, 0.0f); gl.glBegin(GL.GL_LINES); for (int i=0; i < GFX_WIDTH; i+=20) { gl.glVertex2i(i, 0); gl.glVertex2i(i, GFX_HEIGHT); } for (int i=0; i < GFX_HEIGHT; i+=20) { gl.glVertex2i(0, i); gl.glVertex2i(GFX_WIDTH, i); } gl.glEnd(); // nastaveni blendingu gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); float[][] colors = { {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, }; // vykresleni serie nekolika ctvercu ruznou barvou // s ruznou pruhlednosti float alpha; int x, y; for (y = 0; y < colors.length; y++) { for (x = 0, alpha = 0.0f; x <= 500; x += 100, alpha += 0.2f) { drawSquare(gl, x, y*100, colors[y][0], colors[y][1], colors[y][2], alpha); } } gl.glFlush(); // provedeni a vykresleni vsech zmen } /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani SDLSurface screen = initVideo(); // inicializace celoobrazovkoveho grafickeho rezimu GL gl = screen.getGL(); // nastaveni transformacnich matic a barvy pozadi framebufferu initScene(gl, GFX_WIDTH, GFX_HEIGHT); // vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL drawScene(gl); // prepnuti predniho a zadniho bufferu screen.glSwapBuffers(); // ukonceni cele aplikace po peti sekundach Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } // zobrazit ziskane informace } }
Skript pro překlad na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest24.java
Dávkový soubor pro překlad na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest24.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 SDLTest24
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% SDLTest24
Obrázek 1: Scéna vykreslená po spuštění demonstračního příkladu SDLTest24.
8. Demonstrační příklad SDLTest25 – ukázka dalších možností blendingu
Dnešní třetí a současně i poslední demonstrační příklad je implementován ve třídě s názvem SDLTest25. V tomto příkladu je ukázán efekt většiny kombinací operátorů předávaných do metody GL.glBlendFunc(). Celočíselné konstanty odpovídající operátorům zdrojových fragmentů i fragmentů cílových jsou uloženy ve dvojici polí nazvaných sourceOperators a destOperators:
long[] sourceOperators = { GL.GL_ZERO, GL.GL_ONE, GL.GL_DST_COLOR, GL.GL_ONE_MINUS_DST_COLOR, GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA, GL.GL_DST_ALPHA, GL.GL_ONE_MINUS_DST_ALPHA };
long[] destOperators = { GL.GL_ZERO, GL.GL_ONE, GL.GL_SRC_COLOR, GL.GL_ONE_MINUS_SRC_COLOR, GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA, GL.GL_DST_ALPHA, GL.GL_ONE_MINUS_DST_ALPHA };
Vzájemné kombinace těchto operátorů jsou nastavovány ve vnořené programové smyčce:
// vykresleni serie nekolika ctvercu ruznou barvou // s ruznou pruhlednosti float alpha; int x, y; for (y = 0; y < destOperators.length; y++) { for (x = 0; x < sourceOperators.length; x++) { // nastaveni blendingu gl.glBlendFunc(sourceOperators[x], destOperators[y]); drawSquare(gl, x*100, y*100, 0.0f, 0.0f, 1.0f, 0.5f); } }
Za povšimnutí stojí i způsob nastavení barvy pozadí framebufferu:
// barva pozadi framebufferu pro volani glClear() gl.glClearColor(1.0f, 1.0f, 1.0f, 0.5f);
Úplný zdrojový kód demonstračního příkladu SDLTest25 má tvar:
import java.nio.ByteBuffer; import java.nio.ByteOrder; import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; import org.gljava.opengl.Texture; import org.gljava.opengl.TextureFactory; /** * Dvacaty paty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Alfa blending pri vykreslovani. * * @author Pavel Tisnovsky */ public class SDLTest25 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna. */ private static final int GFX_HEIGHT = 800; /** * 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_OPENGL | SDLVideo.SDL_DOUBLEBUF; return SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, flags); } /** * Nastaveni transformacnich matic a barvy pozadi framebufferu. */ private static void initScene(GL gl, int width, int height) { // nastaveni projekcni matice gl.glMatrixMode(gl.GL_PROJECTION); // jednotkova matice gl.glLoadIdentity(); // mapovani abstraktnich souradnic do souradnic okna ci cele obrazovky gl.glOrtho(0, width, height, 0, -1, 1); // nastaveni modelview matice gl.glMatrixMode(gl.GL_MODELVIEW); gl.glLoadIdentity(); // viditelna oblast gl.glViewport(0, 0, width, height); // vypnuti pameti hloubky pri vykreslovani gl.glDisable(gl.GL_DEPTH_TEST); // barva pozadi framebufferu pro volani glClear() gl.glClearColor(1.0f, 1.0f, 1.0f, 0.5f); } /** * Vykresleni ctverce. */ private static void drawSquare(GL gl, int x, int y, float r, float g, float b, float a) { // vykresleni ctyruhelniku gl.glColor4f(r, g, b, a); gl.glBegin(GL.GL_QUADS); gl.glVertex2i(x+10, y+10); gl.glVertex2i(x+90, y+10); gl.glVertex2i(x+90, y+90); gl.glVertex2i(x+10, y+90); gl.glEnd(); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu (bile pozadi) gl.glClear(GL.GL_COLOR_BUFFER_BIT); // zakaz blendingu gl.glDisable(GL.GL_BLEND); // vykresleni mrizky gl.glColor3f(0.0f, 0.0f, 0.0f); gl.glBegin(GL.GL_LINES); for (int i=0; i < GFX_WIDTH; i+=20) { gl.glVertex2i(i, 0); gl.glVertex2i(i, GFX_HEIGHT); } for (int i=0; i < GFX_HEIGHT; i+=20) { gl.glVertex2i(0, i); gl.glVertex2i(GFX_WIDTH, i); } gl.glEnd(); // povoleni blendingu gl.glEnable(GL.GL_BLEND); long[] sourceOperators = { GL.GL_ZERO, GL.GL_ONE, GL.GL_DST_COLOR, GL.GL_ONE_MINUS_DST_COLOR, GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA, GL.GL_DST_ALPHA, GL.GL_ONE_MINUS_DST_ALPHA }; long[] destOperators = { GL.GL_ZERO, GL.GL_ONE, GL.GL_SRC_COLOR, GL.GL_ONE_MINUS_SRC_COLOR, GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA, GL.GL_DST_ALPHA, GL.GL_ONE_MINUS_DST_ALPHA }; // vykresleni serie nekolika ctvercu ruznou barvou // s ruznou pruhlednosti float alpha; int x, y; for (y = 0; y < destOperators.length; y++) { for (x = 0; x < sourceOperators.length; x++) { // nastaveni blendingu gl.glBlendFunc(sourceOperators[x], destOperators[y]); drawSquare(gl, x*100, y*100, 0.0f, 0.0f, 1.0f, 0.5f); } } gl.glFlush(); // provedeni a vykresleni vsech zmen } /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace grafickeho rezimu ci otevreni okna pro vykreslovani SDLSurface screen = initVideo(); // inicializace celoobrazovkoveho grafickeho rezimu GL gl = screen.getGL(); // nastaveni transformacnich matic a barvy pozadi framebufferu initScene(gl, GFX_WIDTH, GFX_HEIGHT); // vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL drawScene(gl); // prepnuti predniho a zadniho bufferu screen.glSwapBuffers(); // ukonceni cele aplikace po peti sekundach Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim // i v tom pripade, ze nastane nejaka vyjimka SDLMain.quit(); } // zobrazit ziskane informace } }
Skript pro překlad na Linuxu:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest25.java
Dávkový soubor pro překlad na Windows:
set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest25.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 SDLTest25
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% SDLTest25
Obrázek 1: Scéna vykreslená po spuštění demonstračního příkladu SDLTest25.
9. Repositář se zdrojovými kódy všech čtyř dnešních demonstračních příkladů
Všechny čtyř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 šesti 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:
10. Odkazy na Internetu
- 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 - 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 - 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