1. Pohled pod kapotu JVM – kreslicí funkce dostupné ve třídě sdljavax.gfx.SDLGfx (2.část)
V předchozí části tohoto seriálu jsme si ukázali, jakým způsobem je možné využít funkce (tj. veřejné statické metody) nabízené třídou sdljavax.gfx.SDLGfx pro vykreslování základních grafických entit do vybrané plochy typu SDL_Surface, tj. mj. i do předního či zadního bufferu. Připomeňme si, že jsme si na pětici demonstračních příkladů ukázali využití funkcí sdljavax.gfx.SDLGfx.pixelRGBA(), sdljavax.gfx.SDLGfx.pixelColor(), sdljavax.gfx.SDLGfx.lineColor(), sdljavax.gfx.SDLGfx.lineRGBA(), sdljavax.gfx.SDLGfx.aalineColor() a konečně sdljavax.gfx.SDLGfx.aalineRGBA(). V knihovně SDLJava ovšem můžeme najít i mnoho dalších funkcí využitelných při kreslení složitějších grafických entit.
Obrázek 1: Vzorek vykreslený s využitím funkce pixelRGBA().
Dnes si ukážeme, jakým způsobem je možné vykreslovat kružnice, kruhy, trojúhelníky, ale i obecné polygony či Bézierovy křivky využívané v mnoha vektorových grafických editorech i například v PostScriptu či ve vektorovém formátu SVG. Vykreslování pixelů, úseček, kružnic či trojúhelníků vyžaduje předání konstantního počtu parametrů příslušným funkcím, ovšem v případě obecných polygonů a Bézierových křivek je situace poněkud složitější, neboť těmto funkcím se předává větší (proměnný) počet vrcholů. V knihovně SDLJava se tento problém řeší na první pohled poněkud nešikovným způsobem – použitím možností nabízených třídou java.nio.ShortBuffer. Podrobnosti si popíšeme v závěrečných kapitolách dnešního článku.
Obrázek 2: Vzorek vykreslený s využitím funkce aalineRGBA().
2. Kreslení kružnic a kruhů
Pro kreslení kružnic popř. kruhů je možné využít osm funkcí, které jsou vypsány v následující tabulce:
| # | Název funkce | Parametry | Stručný popis |
|---|---|---|---|
| 1 | circleColor | SDLSurface dst, int x, int y, int r, long color | kružnice |
| 2 | circleRGBA | SDLSurface dst, int x, int y, int rad, int r, int g, int b, int a | kružnice |
| 3 | aacircleColor | SDLSurface dst, int x, int y, int r, long color | kružnice s vyhlazeným okrajem |
| 4 | aacircleRGBA | SDLSurface dst, int x, int y, int rad, int r, int g, int b, int a | kružnice s vyhlazeným okrajem |
| 5 | filledCircleColor | SDLSurface dst, int x, int y, int r, long color | kruh |
| 6 | filledCircleRGBA | SDLSurface dst, int x, int y, int rad, int r, int g, int b, int a | kruh |
Povšimněte si, že první čtyři parametry těchto funkcí jsou vždy shodné – jedná se o objekt představující plochu, do níž se má kružnice či kruh vykreslit, souřadnice středu této grafické entity a konečně poloměr kruhu popř. kružnice. Poté již následuje určení barvy, která může být specifikována buď jediným 32bitovým číslem ve formátu 0×rrggbbaa, nebo alternativně čtveřicí osmibitových celočíselných parametrů představujících hodnoty barvových složek red, green, blue následované průhledností (alpha).
Určení barvy použitím 32bitové hodnoty je využito ve funkcích circleColor(), aacircleColor() a filledCircleColor(), zatímco trojice barvových složek a hodnota průhlednosti je použita ve funkcích circleRGBA(), aacircleRGBA() a filledCircleRGBA(). Kružnice lze vykreslit buď rychlým celočíselným Brehsemanovým algoritmem (funkce circleColor() a circleRGBA()) nebo naopak pomalejším algoritmem s antialiasingem (funkce aacircleColor() a aacircleRGBA()). Při kresbě kruhů není antialiasing (kupodivu) použit.

Obrázek 3: Čtyřikrát zvětšený detail obrazovky s kružnicemi vykreslenými rychlým Bresenhamovým celočíselným algoritmem.
Obrázek 4: Čtyřikrát zvětšený detail obrazovky s kružnicemi vykreslenými algoritmem s antialiasingem.
3. Demonstrační příklad SDLTest52: vykreslení jednoduchého vzorku s využitím funkce circleColor()
Dnešní první demonstrační příklad nazvaný SDLTest52 využívá funkci circleColor() pro vykreslení vzorku složeného z většího množství poloprůhledných kružnic se shodnou barvou. Barva je nejdříve uložena do čtveřice konstant pojmenovaných red, green, blue a alpha, z nichž je následně vypočtena 32bitová hodnota uložená do konstanty pojmenované color. Tato konstanta je následně použita v programové smyčce, v níž je celý vzorek vykreslen přímo do framebufferu a tedy i na obrazovku:
// vypocet barvovych slozek pixelu
final int red = 0xff;
final int green = 0xff;
final int blue = 0xff;
final int alpha = 0x80;
// vypocet barvy
final int color = (red << 24) | (green << 16) | (blue << 8) | alpha;
// vykreslit vzorek s vyuzitim funkce circleColor()
for (int i = 0; i < 90; i++) {
final int radius = 90 - i;
final int x = (width >> 1) + (int)((i * 2 + 70) * Math.cos(i/10.0));
final int y = (height >> 1) + (int)((i * 2 + 70) * Math.sin(i/10.0));
circleColor(screen, x, y, radius, color);
}
Obrázek 5: Vzorek vykreslený demonstračním příkladem SDLTest52.
Obrázek 6: Detail, na němž je patrný výpočet průhlednosti a překryvu kružnic.
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.*;
/**
* Padesaty druhy demonstracni priklad vyuzivajici knihovnu SDLjava.
*
* Vykresleni jednoducheho vzorku s vyuzitim funkce circleColor().
*
* @author Pavel Tisnovsky
*/
public class SDLTest52 {
/**
* 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;
// vypocet barvy
final int color = (red << 24) | (green << 16) | (blue << 8) | alpha;
// vykreslit vzorek s vyuzitim funkce circleColor()
for (int i = 0; i < 90; i++) {
final int radius = 90 - i;
final int x = (width >> 1) + (int)((i * 2 + 70) * Math.cos(i/10.0));
final int y = (height >> 1) + (int)((i * 2 + 70) * Math.sin(i/10.0));
circleColor(screen, x, y, radius, color);
}
// nutno volat i v pripade, ze neni pouzit double buffering
screen.updateRect();
screen.flip();
}
/**
* Spusteni padesateho druheho 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 SDLTest52.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 SDLTest52.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 SDLTest52
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% SDLTest52
4. Demonstrační příklad SDLTest53: vykreslení jednoduchého vzorku s využitím funkce circleRGBA()
Při vykreslování kružnic (či jiných grafických entit), u nichž se programově mění jejich barva popř. průhlednost, je výhodnější namísto 32bitové hodnoty předávané do funkcí *Color() použít čtveřici hodnot předávaných do funkcí *RGBA(). V tomto případě ani není nutné kontrolovat, zda každá hodnota leží v předpokládaném rozsahu 0 až 255. Právě funkce circleRGBA() je použita v dnešním druhém demonstračním příkladu pojmenovaném SDLTest53 jehož vykreslovací „jádro“ vypadá následovně:
// vypocet barvovych slozek pixelu
int red = 0xff;
int green = 0xff;
int blue = 0x00;
final int alpha = 0x80;
// vykreslit vzorek s vyuzitim funkce circleRGBA()
for (int i = 0; i < 90; i++) {
final int radius = 90 - i;
final int x = (width >> 1) + (int)((i * 2 + 70) * Math.cos(i/10.0));
final int y = (height >> 1) + (int)((i * 2 + 70) * Math.sin(i/10.0));
circleRGBA(screen, x, y, radius, red, green, blue, alpha);
red-=2;
blue+=2;
}
Obrázek 7: Vzorek vykreslený demonstračním příkladem SDLTest53.
Obrázek 8: Detail, na němž je patrný výpočet průhlednosti a překryvu kružnic.
Celý zdrojový kód demonstračního příkladu SDLTest53:
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 treti demonstracni priklad vyuzivajici knihovnu SDLjava.
*
* Vykresleni jednoducheho vzorku s vyuzitim funkce circleRGBA().
*
* @author Pavel Tisnovsky
*/
public class SDLTest53 {
/**
* 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
int red = 0xff;
int green = 0xff;
int blue = 0x00;
final int alpha = 0x80;
// vykreslit vzorek s vyuzitim funkce circleRGBA()
for (int i = 0; i < 90; i++) {
final int radius = 90 - i;
final int x = (width >> 1) + (int)((i * 2 + 70) * Math.cos(i/10.0));
final int y = (height >> 1) + (int)((i * 2 + 70) * Math.sin(i/10.0));
circleRGBA(screen, x, y, radius, red, green, blue, alpha);
red-=2;
blue+=2;
}
// nutno volat i v pripade, ze neni pouzit double buffering
screen.updateRect();
screen.flip();
}
/**
* Spusteni padesateho tretiho 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 SDLTest53.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 SDLTest53.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 SDLTest53
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% SDLTest53
5. Demonstrační příklad SDLTest54: vykreslení jednoduchého vzorku s využitím funkce aacircleColor()
Ve třetím demonstračním příkladu SDLTest54 se opět vykreslují kružnice, tentokrát však již s využitím algoritmu aplikujícího jednoduchý antialiasing, tj. namísto funkcí circleColor() popř. circleRGBA() se používají funkce aacircleColor() popř. aacircleRGBA(). Výsledkem použití vykreslovacího algoritmu s antialiasingem je následující scéna:
Obrázek 9: Vzorek vykreslený demonstračním příkladem SDLTest54.
Obrázek 10: Detail, na němž je vidět funkce algoritmu pro antialiasing.
Podobně jako tomu bylo i v případě úseček, je i zde dobré mít na paměti, že současné použití antialiasingu a poloprůhledných objektů může zapříčinit vznik nežádoucích moaré:
Obrázek 11: Vznik moaré při vykreslení poloprůhledných kružnic.
Obrázek 12: Detail, na němž je vidět funkce algoritmu pro antialiasing.
Zdrojový kód příkladu SDLTest54:
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 ctvrty demonstracni priklad vyuzivajici knihovnu SDLjava.
*
* Vykresleni jednoducheho vzorku s vyuzitim funkce aacircleColor().
*
* @author Pavel Tisnovsky
*/
public class SDLTest54 {
/**
* 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 = 0xff;
// vypocet barvy
final int color = (red << 24) | (green << 16) | (blue << 8) | alpha;
// vykreslit vzorek s vyuzitim funkce aacircleColor()
for (int i = 0; i < 140; i++) {
final int radius = 140 - i;
final int x = (width >> 1) + (int)((i + 80) * Math.cos(i/12.0));
final int y = (height >> 1) + (int)((i + 80) * Math.sin(i/12.0));
aacircleColor(screen, x, y, radius, color);
}
// nutno volat i v pripade, ze neni pouzit double buffering
screen.updateRect();
screen.flip();
}
/**
* Spusteni padesateho ctvrteho 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 SDLTest54.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 SDLTest54.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 SDLTest54
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% SDLTest54
6. Demonstrační příklad SDLTest55: vykreslení jednoduchého vzorku s využitím funkce filledCircleRGBA()
Poslední příklad, v němž se používají funkce pro vykreslení kružnic a kruhů, nese pojmenování SDLTest55. V tomto příkladu se v jediné programové smyčce nejdříve vykreslí barevný kruh a přes něj černá kružnice, která zvýrazní hranice kruhu. Jádro vykreslovacího algoritmu se v mnoha ohledech podobá jádru použitému v předchozí trojici příkladů:
// vykreslit vzorek s vyuzitim funkce filledCircleRGBA()
for (int i = 0; i < 140; i++) {
final int radius = 140 - i;
final int x = (width >> 1) + (int)((i + 80) * Math.cos(i/12.0));
final int y = (height >> 1) + (int)((i + 80) * Math.sin(i/12.0));
filledCircleRGBA(screen, x, y, radius, red, green, blue, alpha);
aacircleColor(screen, x, y, radius, 0xff); // cerna nepruhledna barva
red-=2;
blue+=2;
}
Povšimněte si, že černá neprůhledná barva je reprezentována 32bitovou konstantou 0×000000ff.
Obrázek 13: Vzorek vykreslený demonstračním příkladem SDLTest55.
Zdrojový kód příkladu SDLTest55 má tvar:
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 paty demonstracni priklad vyuzivajici knihovnu SDLjava.
*
* Vykresleni jednoducheho vzorku s vyuzitim funkce filledCircleRGBA().
*
* @author Pavel Tisnovsky
*/
public class SDLTest55 {
/**
* 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
int red = 0xff;
int green = 0xff;
int blue = 0x00;
final int alpha = 0x10;
// vykreslit vzorek s vyuzitim funkce filledCircleRGBA()
for (int i = 0; i < 140; i++) {
final int radius = 140 - i;
final int x = (width >> 1) + (int)((i + 80) * Math.cos(i/12.0));
final int y = (height >> 1) + (int)((i + 80) * Math.sin(i/12.0));
filledCircleRGBA(screen, x, y, radius, red, green, blue, alpha);
aacircleColor(screen, x, y, radius, 0xff); // cerna nepruhledna barva
red-=2;
blue+=2;
}
// nutno volat i v pripade, ze neni pouzit double buffering
screen.updateRect();
screen.flip();
}
/**
* Spusteni padesateho pateho 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 SDLTest55.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 SDLTest55.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 SDLTest55
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% SDLTest55
7. Kreslení trojúhelníků a obdélníků
Pro kreslení trojúhelníků a obdélníků je možné využít několika funkcí, které jsou vypsány v následující tabulce:
| # | Název funkce | Parametry | Stručný popis |
|---|---|---|---|
| 1 | rectangleColor | SDLSurface dst, int x1, int y1, int x2, int y2, long color | obdélník |
| 2 | rectangleRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int r, int g, int b, int a | obdélník |
| 3 | boxColor | SDLSurface dst, int x1, int y1, int x2, int y2, long color | vyplněný obdélník |
| 4 | boxRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int r, int g, int b, int a | vyplněný obdélník |
| 5 | trigonColor | SDLSurface dst, int x1, int y1, int x2, int y2, int x3, int y3, long color | trojúhelník |
| 6 | trigonRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int x3, int y3, int r, int g, int b, int a | trojúhelník |
| 7 | aatrigonColor | SDLSurface dst, int x1, int y1, int x2, int y2, int x3, int y3, long color | trojúhelník (antialiasing hran) |
| 8 | aatrigonRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int x3, int y3, int r, int g, int b, int a | trojúhelník (antialiasing hran) |
| 9 | filledTrigonColor | SDLSurface dst, int x1, int y1, int x2, int y2, int x3, int y3, int color | vyplněný trojúhelník |
| 10 | filledTrigonRGBA | SDLSurface dst, int x1, int y1, int x2, int y2, int x3, int y3, int r, int g, int b, int a | vyplněný trojúhelník |
Pravděpodobně není překvapující, že pro osově orientované obdélníky neexistují varianty funkcí pro vykreslování s využitím antialiasingu.
8. Demonstrační příklad SDLTest56: využití kreslicí funkce filledTrigonColor()
V dnešním posledním příkladu pojmenovaném SDLTest56 je ukázáno využití výše zmíněné funkce filledTrigonColor() při tvorbě vzorku složeného z vyplněných trojúhelníků. Z výpisu zdrojového kódu je patrné, že se této funkci musí předat osm parametrů – plocha typu SDL_Surface, do níž se má trojúhelník vykreslit, za ní následuje trojice souřadnic vrcholů trojúhelníku a posledním parametrem je barva, kterou je trojúhelník vyplněn:
// vykresleni vzorku funkci filledTrigonColor()
for (int y = 0; y < height + width/3; y += 20) {
for (int x = 0; x < width; x += 20) {
final int off = x/3;
filledTrigonColor(screen, x, y - off, x + 16, y - off, x + 8, y - 12 - off, 0xffff00ff);
filledTrigonColor(screen, x + 7, y - off + 1, x + 23, y - off + 1, x + 15, y + 13 - off, 0xff0000ff);
}
}
Obrázek 14: Vzorek vykreslený pomocí funkce filledTrigonColor().
Zdrojový kód demonstračního příkladu SDLTest56 má tvar:
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 paty demonstracni priklad vyuzivajici knihovnu SDLjava.
*
* Vykresleni jednoducheho vzorku s vyuzitim funkce filledTrigonColor().
*
* @author Pavel Tisnovsky
*/
public class SDLTest56 {
/**
* 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();
// vykresleni vzorku funkci filledTrigonColor()
for (int y = 0; y < height + width/3; y += 20) {
for (int x = 0; x < width; x += 20) {
final int off = x/3;
filledTrigonColor(screen, x, y - off, x + 16, y - off, x + 8, y - 12 - off, 0xffff00ff);
filledTrigonColor(screen, x + 7, y - off + 1, x + 23, y - off + 1, x + 15, y + 13 - off, 0xff0000ff);
}
}
// nutno volat i v pripade, ze neni pouzit double buffering
screen.updateRect();
screen.flip();
}
/**
* Spusteni padesateho sesteho 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 SDLTest56.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 SDLTest56.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 SDLTest56
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% SDLTest56
9. Kreslicí funkce pro grafické entity s proměnným počtem vrcholů a/nebo řídicích bodů
V knihovně SDLJava nalezneme i několik funkcí určených pro vykreslení složitějších grafických entit, konkrétně entit s proměnným počtem vrcholů. Jedná se jak o polygony, tak i o Bézierovy křivky. Programátoři využívající Javu by mohli předpokládat, že se v tomto případě použijí statické metody/funkce s proměnným počtem parametrů, ovšem vzhledem k tomu, že je SDLJava nízkoúrovňová knihovna, je implementováno poněkud překvapivé řešení – souřadnice vrcholů jsou předávány přes objekty typu java.nio.ShortBuffer, což sice není příliš elegantní řešení, ovšem je efektivní při přenosu většího množství dat mezi Javovskou částí aplikace a nativním kódem. Příklady použití při vykreslování obecných polygonů a Bézierových křivek si ukážeme v navazující části tohoto seriálu.
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