1. Pohled pod kapotu JVM – volání funkcí OpenGL s využitím knihovny SDLJava
2. Inicializace knihovny SDLJava a získání kontextu OpenGL
3. Inicializace stavového stroje OpenGL a vykreslení jednoduché scény
4. Demonstrační příklad SDLTest12 – použití OpenGL pro vykreslování
5. Geometrické entity v OpenGL 1.x a OpenGL 2.x
6. Demonstrační příklad SDLTest13 – vykreslení geometrických primitiv
7. Nastavení základních vlastností vykreslovaných objektů
8. Demonstrační příklad SDLTest14 – nastavení základních vlastností vykreslovaných bodů
9. Demonstrační příklad SDLTest15 – nastavení základních vlastností vykreslovaných úseček
10. Demonstrační příklad SDLTest16 – nastavení vlastností uzavřených plošných objektů
11. Repositář se zdrojovými kódy všech pěti dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – volání funkcí OpenGL s využitím knihovny SDLJava
V předchozích částech seriálu o programovacím jazyku Java i o virtuálním stroji Javy jsme si ukázali využití metod nabízených knihovnou SDLJava při vykreslování bitmap do framebufferu i způsoby, jakými je možné číst či zapisovat hodnoty jednotlivých pixelů v libovolném objektu typu SDLSurface. Tyto možnosti nabízené třídami z balíčků SDLJava přesně odpovídají grafickým schopnostem nativní knihovny SDL 1.x, která kromě práce s bitmapami, vyplnění obdélníku a blokového přenosu jedné bitmapy do bitmapy jiné žádné další specializovanější funkce nepodporuje. To znamená, že například algoritmus pro vykreslení úsečky či vyplněného polygonu si buď musí vývojář sám naprogramovat, popř. může alternativně využít některé rozšiřující moduly, které byly ke knihovně SDL vyvinuty. Ovšem existuje ještě jedna možnost, která může být pro mnoho aplikací velmi užitečná – využití možností knihovny OpenGL a tím pádem i schopností nabízených staršími i moderními grafickými akcelerátory.
Vzhledem k tomu, že knihovna OpenGL byla navržena takovým způsobem, že její API je kompatibilní s jazyky C a Fortran, je nutné pro použití této knihovny z jiných programovacích jazyků vytvořit nějaké vhodné rozhraní. Týká se to i Javy, kde je toto rozhraní komplikováno mj. i nutností volat všechny funkce OpenGL přes JNI (Java Native Interface). V současnosti existuje hned několik podpůrných knihoven i celých enginů pro Javu, které javovským programátorům možnosti grafické knihovny OpenGL více či méně přímočarým způsobem zpřístupňují; my se v tomto článku budeme věnovat rozhraní, které je nabízené přímo v knihovně SDLJava. Toto rozhraní se nesnaží žádným způsobem možnosti OpenGL „obalovat“ další funkcionalitou, takže zde například nenalezneme třídy ani metody pro vytvoření grafu scény, načítání 3D formátů, tvorbu obalových těles atd. Namísto toho se při využití SDLJava setkáme s metodami, které jsou pojmenovány stejně jako funkce v nativní knihovně OpenGL a případné změny jsou provedeny jen kvůli rozdílům mezi C a Javou (bezznaménkové datové typy atd.).
2. Inicializace knihovny SDLJava a získání kontextu OpenGL
Funkce, které jsou nabízeny API grafické knihovny OpenGL, slouží pro nastavení parametrů vykreslovací pipeline a pro zahájení vykreslování těles složených z jednoduchých geometrických prvků typu bod, úsečka, trojúhelník, pruh trojúhelníků atd. V tomto API však nenajdeme žádné funkce pro vytvoření okna, nastavení grafického režimu, konfiguraci framebufferu či pro prohození funkcí předního a zadního bufferu. Tvůrci OpenGL rozumně předpokládali, že tyto funkce jsou zcela závislé na konkrétním operačním systému a tudíž je žádným způsobem do standardu(ů) OpenGL nezařadili. Z tohoto důvodu je nutné, aby se vytvoření okna pro vykreslování popř. nastavení celoobrazovkového grafického režimu řešilo s využitím jiných knihoven (SDL, GLUT/freeglut, GLFW, EGL apod.), popř. s využitím API podporovaného operačním systémem (příkladem může být WGL). Podobnou funkcionalitu nám samozřejmě nabízí i knihovna SDLJava.
Inicializace a získání takzvaného grafického kontextu OpenGL se skládá ze dvou kroků. Nejprve je nutné inicializovat celoobrazovkový grafický režim či otevřít okno pro vykreslování s uvedením bitového příznaku SDLVideo.SDL_OPENGL:
/** * 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); }
Následně je nutné nad získaným objektem typu SDLSurface, který představuje framebuffer, zavolat metodu getGL() vracející instanci třídy implementující rozhraní org.gljava.opengl.GL:
// inicializace grafickeho rezimu ci otevreni okna pro vykreslovani SDLSurface screen = initVideo(); // inicializace celoobrazovkoveho grafickeho rezimu GL gl = screen.getGL();
Přes metody předepsané rozhraním org.gljava.opengl.GL je již možné volat všechny funkce OpenGL, což si ukážeme v navazujících kapitolách na pětici demonstračních příkladů.
3. Inicializace stavového stroje OpenGL a vykreslení jednoduché scény
Jakmile máme k dispozici instanci třídy implementující rozhraní org.gljava.opengl.GL, je již možné přes tuto instanci volat nativní funkce knihovny OpenGL. Nejprve se podívejme, jak se nastavují transformační matice (projekční matice a modelview matice). Nejprve se přes Gl.glMatrixMode() určí, obsah jaké matice se má nastavit a posléze se přes Gl.glLoadIdentity() načte jednotková matice, což pro naše účely (jednoduchá 2D scéna) plně postačuje. Následně se přes Gl.glOrtho() nastaví ortogonální promítání (bez perspektivy). Metoda Gl.glDisable(gl.GL_DEPTH_TEST) zakáže provádění testů na hloubku (vzdálenost) jednotlivých fragmentů vytvářených v procesu rasterizace objektů a metoda Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f) specifikuje barvu, kterou se vymaže pozadí okna, přesněji řečeno zadní buffer uložený ve framebufferu. Při jejím volání se zadávají čtyři barvové složky (Red, Green, Blue a Alpha), z nichž každá je v rozsahu 0.0–1.0 (0.0 znamená nepřítomnost příslušné barvové složky ve výsledné barvě, 1.0 maximální vysvícení):
/** * 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, 0, height, -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 (0.0f, 0.0f, 0.0f, 0.0f); }
Při vykreslování budeme používat takzvaný přímý režim (direct mode), který byl specifikován již v OpenGL verze 1.x a dodnes je dodržována zpětná kompatibilita s tímto režimem. Teoreticky se sice přímý režim stal v OpenGL 3.1 oficiálně nepodporovaným, ovšem například ovladače karet nVidia ho stále podporují a podle tvrzení firmy i podporovat budou (nový a obecně i rychlejší způsob vykreslování si přiblížíme v některé navazující části tohoto seriálu).
Metoda Gl.glBegin(Gl.GL_QUADS) zahájí vykreslování čtyřúhelníků, z nichž každý je specifikován čtyřmi vrcholy. Tyto vrcholy se zadávají například příkazem Gl.glVertex2i(), kterému předáme 2D souřadnice vrcholu čtyřúhelníku. Ukončení zadávání vrcholů zajistí příkaz Gl.glEnd(), který tvoří takzvané „příkazové závorky“ společně s voláním Gl.glBegin(). Tyto příkazy tedy vždy musí tvořit pár. Posledním příkazem je Gl.glFlush(), jenž zajistí provedení všech operací na grafické kartě. Bez uvedení tohoto příkazu by se mohlo stát, že některé objekty by nebyly zobrazeny, protože by zůstaly v nedokončeném stavu v grafické pipeline akcelerátoru:
/** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu gl.glClear(gl.GL_COLOR_BUFFER_BIT); // vykresleni ctverce gl.glBegin(gl.GL_QUADS); gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex2i(200, 100); gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex2i(600, 100); gl.glColor3f(1.0f, 0.0f, 1.0f); gl.glVertex2i(600, 500); gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex2i(200, 500); gl.glEnd(); }
4. Demonstrační příklad SDLTest12 – použití OpenGL pro vykreslování
V dnešním prvním demonstračním příkladu si ukážeme jak inicializaci knihovny SDLJava, tak i způsob získání kontextu OpenGL. Ve chvíli, kdy je tento kontext získán, je již možné provést inicializaci stavového stroje OpenGL a následně vykreslit jednoduchou scénu způsobem, který jsme si popsali v předchozích dvou kapitolách:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; /** * Dvanacty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Ukazka vyuziti zakladnich moznosti graficke knihovny OpenGL - * vykresleni ctyruhelniku a vypocet barvy s vyuzitim * Gouraudova stinovani. * * @author Pavel Tisnovsky */ public class SDLTest12 { /** * 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 = 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, 0, height, -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 (0.0f, 0.0f, 0.0f, 0.0f); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu gl.glClear(gl.GL_COLOR_BUFFER_BIT); // vykresleni ctverce gl.glBegin(gl.GL_QUADS); gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex2i(200, 100); gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex2i(600, 100); gl.glColor3f(1.0f, 0.0f, 1.0f); gl.glVertex2i(600, 500); gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex2i(200, 500); gl.glEnd(); } /** * 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); // vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL drawScene(gl); // prepnuti predniho a zadniho bufferu screen.glSwapBuffers(); // ukonceni 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 SDLTest12.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 SDLTest12.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 SDLTest12
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% SDLTest12
Obrázek 1: Screenshot demonstračního příkladu SDLTest12.java.
5. Geometrické entity v OpenGL 1.x a OpenGL 2.x
Pomocí příkazů OpenGL lze při použití přímého režimu vykreslovat pouze základní geometrické prvky, které nazýváme primitiva. Z těchto primitiv se potom skládají složitější tělesa a celé rozsáhlé 3D scény. Existuje celkem deset typů primitiv, mezi než patří: izolovaný bod, úsečka zadaná dvěma koncovými body, řetězec úseček (polyčára), uzavřená smyčka vytvořená z úseček (uzavřená polyčára), trojúhelník, trs trojúhelníků, pás trojúhelníků, rovinný čtyřúhelník, pás rovinných čtyřúhelníků a rovinný konvexní polygon.
Při vykreslování každého primitiva musíme nejdříve zadat příkaz Gl.glBegin(typ primitiva), kterým knihovně OpenGL sdělujeme, že se začínají zadávat jednotlivé vrcholy primitiva popř. i vlastnosti těchto vrcholů. Vykreslování se ukončí párovým příkazem Gl.glEnd(), který nemá žádné parametry. Mezi příkazy Gl.glBegin() a Gl.glEnd() lze zadat libovolný počet vrcholů primitiva příkazem Gl.glVertex*(). Vrcholy jsou zadané svými souřadnicemi, a to buď dvěma (x, y), třemi (x, y, z) nebo čtyřmi (x, y, z, w).
Pro dvourozměrné scény zadáváme pouze souřadnice (x, y) a vrcholy se zadávají příkazem Gl.glVertex2*(), kde se za znak * dosadí příznak udávající datový typ (i-int, f-float apod.) parametrů. Souřadnice (z) se automaticky nastaví na nulu a souřadnice (w) na jedničku.
Pro 3D scény zadáváme buď souřadnice (x, y, z) nebo celou čtveřici (x, y, z, w). Pro trojici souřadnic se pro zadání vrcholů používá příkaz Gl.glVertex3*(), pro čtveřici souřadnic potom Gl.glVertex4*(). Pokud je zadána pouze trojice souřadnic, dosadí se za souřadnici w automaticky jednička. Souřadnice w je použita při perspektivní projekci, a udává váhu vrcholu (weight). Pro běžné použití vždy tuto souřadnici nastavujeme na jedničku, protože touto souřadnicí se dělí zbylé tři souřadnice, tedy x'=x/w, y'=y/w a z'=z/w.
6. Demonstrační příklad SDLTest13 – vykreslení geometrických primitiv
Po překladu a spuštění dnešního druhého demonstračního příkladu se do okna vykreslí všechna grafická primitiva podporovaná knihovnou OpenGL v případě, že se pro vykreslování využívá přímý režim (direct mode). Ve spodní části okna jsou postupně vykresleny body, jednotlivé úsečky, polyčára a uzavřená polyčára, ve druhé řadě pak trojúhelník, pruh trojúhelníků a trs trojúhelníků. V horní řadě je zobrazen čtyřúhelník, pruh sestavený ze čtyřúhelníků a obecný konvexní mnohostěn:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; /** * Trinacty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Ukazka vyuziti zakladnich moznosti graficke knihovny OpenGL - * vykresleni nekolika bodu a linearnich geometrickych tvaru. * * @author Pavel Tisnovsky */ public class SDLTest13 { /** * 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 = 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*2/3, 0, height*2/3, -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 (0.0f, 0.0f, 0.0f, 0.0f); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu gl.glClear(gl.GL_COLOR_BUFFER_BIT); // nastaveni barvy pro vykreslovani gl.glColor3f(1.0f, 1.0f, 1.0f); gl.glBegin(gl.GL_POINTS); // nyni zacneme vykreslovat body gl.glVertex2i( 50, 50); gl.glVertex2i(100, 50); gl.glVertex2i(100, 100); gl.glVertex2i( 50, 100); gl.glEnd(); gl.glColor3f(1.0f, 0.0f, 1.0f); gl.glBegin(gl.GL_LINES); // nyni zacneme vykreslovat usecky gl.glVertex2i(150, 50); gl.glVertex2i(200, 50); gl.glVertex2i(200, 100); gl.glVertex2i(150, 100); gl.glEnd(); gl.glColor3f(0.0f, 1.0f, 1.0f); gl.glBegin(gl.GL_LINE_STRIP); // nyni vykreslime polycaru gl.glVertex2i(250, 50); gl.glVertex2i(300, 50); gl.glVertex2i(300, 100); gl.glVertex2i(250, 100); gl.glEnd(); gl.glColor3f(1.0f, 1.0f, 0.0f); gl.glBegin(gl.GL_LINE_LOOP); // nyni vykreslime uzavrenou polycaru gl.glVertex2i(350, 50); gl.glVertex2i(400, 50); gl.glVertex2i(400, 100); gl.glVertex2i(350, 100); gl.glEnd(); gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glBegin(gl.GL_TRIANGLES); // vykresleni trojuhelniku gl.glVertex2i( 50, 150); gl.glVertex2i(100, 150); gl.glVertex2i(100, 200); gl.glVertex2i( 50, 200); gl.glEnd(); gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glBegin(gl.GL_TRIANGLE_STRIP); // vykresleni pruhu trojuhelniku gl.glVertex2i(150, 150); gl.glVertex2i(150, 200); gl.glVertex2i(200, 200); gl.glVertex2i(200, 150); gl.glEnd(); gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glBegin(gl.GL_TRIANGLE_FAN); // vykresleni trsu trojuhelniku gl.glVertex2i(300, 150); gl.glVertex2i(250, 160); gl.glVertex2i(270, 190); gl.glVertex2i(290, 200); gl.glVertex2i(310, 200); gl.glVertex2i(330, 190); gl.glVertex2i(350, 160); gl.glEnd(); gl.glColor3f(1.0f, 0.5f, 0.5f); gl.glBegin(gl.GL_QUADS); // vykresleni ctyruhelniku gl.glVertex2i( 50, 250); gl.glVertex2i(100, 250); gl.glVertex2i(100, 300); gl.glVertex2i( 50, 300); gl.glEnd(); gl.glColor3f(0.5f, 0.5f, 1.0f); gl.glBegin(gl.GL_QUAD_STRIP); // vykresleni pruhu ctyruhleniku gl.glVertex2i(150, 250); gl.glVertex2i(150, 300); gl.glVertex2i(200, 240); gl.glVertex2i(200, 310); gl.glVertex2i(250, 260); gl.glVertex2i(250, 290); gl.glVertex2i(300, 250); gl.glVertex2i(300, 300); gl.glEnd(); gl.glColor3f(0.5f, 1.0f, 0.5f); gl.glBegin(gl.GL_POLYGON); // vykresleni konvexniho polygonu gl.glVertex2i(350, 260); gl.glVertex2i(370, 240); gl.glVertex2i(390, 240); gl.glVertex2i(410, 260); gl.glVertex2i(410, 280); gl.glVertex2i(390, 300); gl.glVertex2i(370, 300); gl.glVertex2i(350, 280); gl.glEnd(); } /** * 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); // 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 SDLTest13.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 SDLTest13.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 SDLTest13
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% SDLTest13
Obrázek 2: Screenshot demonstračního příkladu SDLTest13.java.
7. Nastavení základních vlastností vykreslovaných objektů
Při vykreslování lze velmi jednoduše měnit mnoho vlastností primitiv/objektů. První vlastností, kterou lze měnit u všech typů primitiv, je barva vrcholu. Jelikož je bod zadán pouze jedním vrcholem (příkazem Gl.glVertex*()), je zadaná barva pro celý bod konstantní, pro úsečky a plošné útvary je tomu však jinak. Barva se zadává příkazem Gl.glColor*(). Formát barvy je definován v barvovém modelu RGB (Red, Green, Blue – tedy tři barevné složky) nebo RGBA (Red, Green, Blue, Alpha – tři barevné složky a průhlednost). Jako typ dat lze pro specifikaci jednotlivých barevných složek zadat libovolný datový typ OpenGL; my se budeme v demonstračních příkladech držet typu float.
Druhou vlastností je velikost bodu. Velikost se zadává příkazem Gl.glPointSize(float size), kde parametr size musí být větší než nula. Implicitní velikost bodu je nastavena na 1.0 což odpovídá jednomu pixelu na obrazovce. Velikost bodu nelze měnit uvnitř „závorkových příkazů“ glBegin() a glEnd().
Třetí vlastností, kterou lze vypnout nebo zapnout je antialiasing bodů. Antialiasing se zapíná příkazem Gl.glEnable(Gl.GL_POINT_SMOOTH) a vypíná příkazem Gl.glDisable(Gl.GL_POINT_SMOOTH). Pokud je antialiasing vypnutý, body se zobrazují jako čtverce, pokud je zapnutý, tak by se body měly zobrazit jako kruhy s rozmazanými okraji. Zde je zapotřebí zdůraznit, že ne všechny grafické akcelerátory podporují kruhové body. Antialiasing nelze zapnout a vypnout uvnitř závorkových příkazů glBegin() a glEnd(). Při vypnutém antialiasingu se velikost bodů zaokrouhluje na celé pixely, pokud je však antialiasing zapnutý, velikost může být neceločíselná.
Podobně jako u bodů, i u úseček lze měnit jejich barvu. Pokud se barva specifikuje před „závorkovým příkazem“ Gl.glBegin(), je celá úsečka vykreslena konstantní barvou. Pokud se barva specifikuje mezi příkazy Gl.glBegin() a Gl.glEnd(), může se měnit barva jednotlivých vrcholů. Na grafické kartě se potom automaticky provede lineární interpolace barev mezi vrcholy. Druhou vlastností je tloušťka úsečky. Ta se nastavuje příkazem Gl.glLineWidth(float width), kde width musí být větší než nula. Implicitní tloušťka úseček je nastavena na hodnotu 1.0 což odpovídá jednomu pixelu na obrazovce.
Při vykreslování úseček lze, podobně jako u bodů, povolit nebo zakázat antialiasing. Pro tento účel se používají příkazy Gl.glEnable(Gl.GL_LINE_SMOOTH) a Gl.glDisable(Gl.GL_LINE_SMOOTH). Pokud je antialiasing úseček vypnutý, úsečka se vykreslí s ostrými hranami a konce úseček budou zarovnány s nejbližší souřadnou osou (konce jsou tedy horizontální nebo vertikální). Pokud je antialiasing úseček zapnutý, úsečka se vykreslí s rozmazanými hranami a konce úseček budou vždy kolmé na směrnici úsečky.
Poslední vlastností úseček je maska, která se používá při vykreslování jednotlivých pixelů úsečky. Maska je šestnáctibitová hodnota, kde jednotlivé bity určují, zda se má některá část úsečky vykreslit. Maska tedy specifikuje vzorek, kterým je úsečka vykreslena. Pokud je například maska nastavena na hodnotu 0×fff0 (binárně 1111111111110000), bude vždy dvanáct pixelů vykresleno a čtyři pixely nevykresleny. Maska se zadává příkazem Gl.glLineStipple(factor, pastrongern), kde factor je faktor zvětšení masky ve směru úsečky (vzorek lze tedy na úsečce „natahovat“) a pastrongern je bitová maska. Pro povolení maskování se musí zavolat příkaz Gl.glEnable(Gl.GL_LINE_STIPPLE), pro zakázání Gl.glDisable(Gl.GL_LINE_STIPPLE). Implicitně je maskování zakázáno.
U plošných útvarů lze, podobně jako u bodů a úseček, měnit jejich barvu. Pokud se barva specifikuje před příkazem Gl.glBegin(), je celý útvar vykreslen jednou konstantní barvou (pokud nepoužijeme texturování a osvětlení – viz další díly). Pokud barvu specifikujeme mezi „závorkovými příkazy“ Gl.glBegin() a Gl.glEnd(), lze měnit barvu jednotlivých vrcholů. Grafická karta nebo softwarová implementace OpenGL potom provede interpolaci barvy. Tímto jednoduchým způsobem lze v OpenGL dosáhnout Gouraudova stínování.
Každý plošný útvar má dvě strany (faces) – rub a líc (back a front). Tyto strany (orientace se zjistí z normálového vektoru) mohou být vykresleny odlišně. Toho se dá využít například při řezu objektů, kdy je jasné, která strana leží uvnitř a která vně tělesa. Odvrácené strany úplně uzavřených těles lze ořezat (operace culling).
Pro rub a/nebo líc lze zadat mód vykreslování. Jsou možné tři varianty:
- vykreslí se pouze vrcholy polygonu (plošného útvaru)
- vykreslí se hrany polygonu
- vykreslí se vyplněný polygon
Mód vykreslování plošných útvarů se změní příkazem Gl.glPolygonMode(face, mode), kde parametr face může nabývat hodnot Gl.GL_FRONT_AND_BACK (obě strany), Gl.GL_FRONT (přední strana) a Gl.GL_BACK (zadní strana). Parametr mode může nabývat hodnot Gl.GL_POINT (vykreslují se vrcholy), Gl.GL_LINE (vykreslují se hrany) a Gl.GL_FILL (vyplněný polygon).
8. Demonstrační příklad SDLTest14 – nastavení základních vlastností vykreslovaných bodů
V demonstračním příkladu SDLTest14 je ukázáno, jakým způsobem lze nastavit základní vlastnosti vykreslovaných bodů. Na obrazovce (resp. ve vytvořeném okně) se ve spodní části vykreslí několik bodů s různou barvou (tyto body mají velikost jednoho pixelu), nad nimi jsou nakresleny čtvercové body o různé velikosti (antialiasing je zakázaný) a v horní řadě pak kulaté body, opět s různou velikostí (zde je naopak antialiasing povolený):
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; /** * Ctrnacty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Nastaveni vlastnosti zakladnich geometrickych tvaru (zde konkretne bodu) * vykreslovanych pres OpenGL. * * @author Pavel Tisnovsky */ public class SDLTest14 { /** * 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 = 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/2, 0, height/2, -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 (0.0f, 0.0f, 0.0f, 0.0f); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu gl.glClear(gl.GL_COLOR_BUFFER_BIT); gl.glDisable(gl.GL_POINT_SMOOTH); // zakazani antialiasingu bodu gl.glPointSize(1.0f); // velikost vykreslovanych bodu je jeden pixel gl.glBegin(gl.GL_POINTS); for (float loop=0.0f; loop<=1.0f; loop+=0.1f) {// vykresleni prvni rady bodu ruzne barvy gl.glColor3f(loop, 0.5f, 1.0f-loop); // zmena barvy uvnitr prikazovych "zavorek" glBegin()/glEnd() gl.glVertex2f(50.0f+300.0f*loop, 50.0f); } gl.glEnd(); for (float loop=0.0f; loop<=1.0f; loop+=0.1f) {// vykresleni druhe rady bodu ruzne velikosti a barvy gl.glColor3f(loop, 0.5f, 1.0f-loop); // zmena barvy vne prikazovych "zavorek" glBegin()/glEnd() gl.glPointSize(loop*20.0f+1.0f); // zmena velikosti vykreslovanych bodu gl.glBegin(gl.GL_POINTS); gl.glVertex2f(50.0f+300.0f*loop, 100.0f); gl.glEnd(); } gl.glEnable(gl.GL_POINT_SMOOTH); // povoleni antialiasingu bodu for (float loop=0.0f; loop<=1.0f; loop+=0.1f) {// vykresleni treti rady bodu ruzne velikosti a barvy gl.glColor3f(loop, 0.5f, 1.0f-loop); // zmena barvy vne prikazovych "zavorek" glBegin()/glEnd() gl.glPointSize(loop*20.0f+1.0f); // zmena velikosti vykreslovanych bodu gl.glBegin(gl.GL_POINTS); gl.glVertex2f(50.0f+300.0f*loop, 150.0f); 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); // 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 SDLTest14.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 SDLTest14.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 SDLTest14
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% SDLTest14
Obrázek 3: Screenshot demonstračního příkladu SDLTest14.java.
9. Demonstrační příklad SDLTest15 – nastavení základních vlastností vykreslovaných úseček
Dnešní předposlední příklad, jehož název je SDLTest15, slouží pro ukázku, jak je možné nastavit vlastnosti vykreslovaných úseček. Do vytvořeného okna jsou vykresleny úsečky, u nichž je barva počátečního a koncového vrcholu odlišná, což znamená, že grafický akcelerátor musí použít lineární stínování. Dále je u úseček nastavena rozdílná tloušťka, antialiasing (zapnutý/vypnutý) a v horní části okna můžeme vidět několik úseček, u nichž se postupně mění jejich vzorek:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; /** * Patnacty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Nastaveni vlastnosti zakladnich geometrickych tvaru vykreslovanych * pres OpenGL. * * @author Pavel Tisnovsky */ public class SDLTest15 { /** * 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 = 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/2, 0, height/2, -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 (0.0f, 0.0f, 0.0f, 0.0f); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { int patterns[]={0xff00, 0xf0f0, 0xcccc, 0x5555, 0xfe10, 0x5e32}; // vymazani framebufferu gl.glClear(gl.GL_COLOR_BUFFER_BIT); gl.glDisable(gl.GL_LINE_SMOOTH); // zakazani antialiasingu usecek gl.glDisable(gl.GL_LINE_STIPPLE); // zakazani maskovani pixelu na care gl.glLineWidth(1.0f); // tloustka usecky je jeden pixel gl.glBegin(gl.GL_LINES); for (float loop=0.0f; loop<=1.0f; loop+=0.1f) { // vykresleni prvni rady usecek ruzne barvy gl.glColor3f(loop, 0.0f, 1.0f-loop); // zmena barvy uvnitr prikazovych "zavorek" glBegin()/glEnd() gl.glVertex2f(50.0f+300.0f*loop, 20.0f); gl.glColor3f(loop, 1.0f, 1.0f-loop); gl.glVertex2f(100.0f+300.0f*loop, 70.0f); } gl.glEnd(); for (float loop=0.0f; loop<=1.0f; loop+=0.1f) {// vykresleni druhe rady usecek ruzne tloustky gl.glLineWidth(loop*10.0f+0.1f); // zmena tloustky usecky gl.glBegin(gl.GL_LINES); gl.glColor3f(loop, 0.0f, 1.0f-loop); // zmena barvy uvnitr prikazovych "zavorek" glBegin()/glEnd() gl.glVertex2f(50.0f+300.0f*loop, 90.0f); gl.glColor3f(loop, 1.0f, 1.0f-loop); gl.glVertex2f(100.0f+300.0f*loop, 140.0f); gl.glEnd(); } gl.glEnable(gl.GL_LINE_SMOOTH); // povoleni antialiasingu usecek for (float loop=0.0f; loop<=1.0f; loop+=0.1f) {// vykresleni treti rady usecek ruzne tloustky gl.glLineWidth(loop*10.0f+0.1f); // zmena tloustky usecky gl.glBegin(gl.GL_LINES); gl.glColor3f(loop, 0.0f, 1.0f-loop); // zmena barvy uvnitr prikazovych "zavorek" glBegin()/glEnd() gl.glVertex2f(50.0f+300.0f*loop, 160.0f); gl.glColor3f(loop, 1.0f, 1.0f-loop); gl.glVertex2f(100.0f+300.0f*loop, 210.0f); gl.glEnd(); } gl.glDisable(gl.GL_LINE_SMOOTH); // zakazani antialiasingu usecek gl.glEnable(gl.GL_LINE_STIPPLE); // povoleni maskovani pixelu na care gl.glLineWidth(1.0f); // tloustka usecky je jeden pixel gl.glColor3f(1.0f, 1.0f, 1.0f); // zmena barvy vne prikazovych "zavorek" glBegin()/glEnd() for (int i=0; i<6; i++) { gl.glLineStipple(2, patterns[i]); // nastaveni masky pri kresleni usecek gl.glBegin(gl.GL_LINES); gl.glVertex2i(50, 230+i*15); // vykresleni usecky gl.glVertex2i(350, 230+i*15); 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); // 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 SDLTest15.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 SDLTest15.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 SDLTest15
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% SDLTest15
Obrázek 4: Screenshot demonstračního příkladu SDLTest15.java.
10. Demonstrační příklad SDLTest16 – nastavení vlastností uzavřených plošných objektů
V posledním demonstračním příkladu s názvem SDLTest16 je ukázán způsob nastavení vlastností uzavřených plošných objektů, v tomto konkrétním případě trojúhelníků. Trojúhelníky jsou vykresleny různým způsobem: s výplní (Gouraudovo stínování), pouze hrany a pouze vrcholy:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLPixelFormat; import sdljava.video.SDLSurface; import sdljava.video.SDLVideo; import org.gljava.opengl.GL; /** * Sestnacty demonstracni priklad vyuzivajici knihovnu SDLjava. * * Nastaveni vlastnosti zakladnich geometrickych tvaru vykreslovanych * pres OpenGL. * * @author Pavel Tisnovsky */ public class SDLTest16 { /** * 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 = 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*2/3, 0, height*2/3, -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 (0.0f, 0.0f, 0.0f, 0.0f); } /** * Vykresleni trojuhelniku na urcenou pozici. */ private static void drawTriangle(GL gl, int x, int y) { gl.glBegin(gl.GL_TRIANGLES); gl.glColor3f(1.0f, 0.0f, 0.0f); // kazdy vertex bude vykresleny jinou barvou gl.glVertex2i(x, y); gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex2i(x+100, y); gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex2i(x+50, y+80); gl.glEnd(); } /** * Vykresleni velmi jednoduche sceny s vyuzitim funkci OpenGL. */ private static void drawScene(GL gl) { // vymazani framebufferu gl.glClear(gl.GL_COLOR_BUFFER_BIT); gl.glPointSize(5.0f); // velikost bodu je rovna peti pixelum gl.glLineWidth(2.0f); // tloustka usecek je rovna dvema pixelum gl.glEnable(gl.GL_POINT_SMOOTH); // povoleni antialiasingu bodu gl.glEnable(gl.GL_LINE_SMOOTH); // povoleni antialiasingu usecek gl.glDisable(gl.GL_POLYGON_STIPPLE); // zakazat vzorek gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL); // vykreslovani vyplnenych trojuhelniku drawTriangle(gl, 50, 50); gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE); // vykreslovani pouze hran trojuhelniku drawTriangle(gl, 180, 50); gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_POINT); // vykreslovani pouze vrcholu trojuhelniku drawTriangle(gl, 310, 50); gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL); // vykreslovani vyplnenych trojuhelniku 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); // 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 SDLTest16.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 SDLTest16.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 SDLTest16
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% SDLTest16
Obrázek 5: Screenshot demonstračního příkladu SDLTest16.java.
11. 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 třech 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:
12. Odkazy na Internetu
- 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/ - 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