/* GL.java * * Copyright (c) 2001-2002, Tuomas J. Lukka * * You may use and distribute under the terms of either the GNU Lesser * General Public License, either version 2 of the license or, * at your choice, any later version. Alternatively, you may use and * distribute under the terms of the XPL. * * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of * the licenses. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README * file for more details. * */ /* * Written by Tuomas Lukka */ package gzz.gfx.gl; import java.awt.Rectangle; import gzz.client.GraphicsAPI; /** The interface to the native OpenGL library. * Note: here we must be VERY careful, as this is one of the places * where foreign code is not sandboxed automatically for us. * * All parameters that go to C level must be checked either here * or at the C level, otherwise -- BOOM. */ public class GL { public static boolean dbg = false; private static void p(String s) { if(dbg) System.out.println(s); } private static void pa(String s) { System.err.println(s); } private static native int init(int debug); // Necessary to allow debug to be set before // init. private static boolean libLoaded = false; public static void loadLib() { if(!libLoaded) { System.loadLibrary("GZZGL"); libLoaded = true; } } public static void init() { loadLib(); init(1); } public interface EventHandler { int PRESS = 1; int MOTION = 2; int RELEASE = 3; void repaint(); /** Receive a keystroke event. */ void keystroke(String s); void mouse(int x, int y, int button, int type); void timeout(int id); } public interface Ticker { boolean tick(); } public static final int RENDERABLE0 = 0x0800000; public static final int RENDERABLE1 = 0x1000000; public static final int RENDERABLE2 = 0x2000000; /** The Java proxy for a C++ object. */ static public abstract class JavaObject extends gzz.vob.Vob { private int id = 0; JavaObject(int id) { super(); this.id = id; } public void finalize() { if(this.dbg) pa("Finalizing "+this+" "+id); if(id != 0) throw new Error("Zero id object!"); deleteObj(); id = 0; } public void render(java.awt.Graphics g, boolean fast, RenderInfo info1, RenderInfo info2 ) { } protected abstract void deleteObj(); protected int getId() { return id; } } static public abstract class NonRenderableJavaObject extends JavaObject { NonRenderableJavaObject(int id) { super(id); } public int addToListGL(GraphicsAPI.Window win, int[] list, int cur, int cs1, int cs2) { throw new Error("Not right to try to add me to a display list"); } } /** The Java proxy representing a Renderable object. */ static public abstract class Renderable0JavaObject extends JavaObject { public Renderable0JavaObject(int id) { super(id); } /** Add this object to the given list with the given coordinate system. * Usage: *
	 * 	int[] list;
	 * 	int curs;
	 * 	curs = obj.addToListGL(list, curs, coordsys);
	 * 
* @param list The display list to add this to. * @param cur The current index, to which the first int goes * @param coordsys The number of the coordinate system. * @return The new current index after adding these. */ public int addToList(int[] list, int cur) { list[cur++] = (RENDERABLE0 | getId()); return cur; } public int addToListGL(GraphicsAPI.Window win, int[] list, int cur, int cs1, int cs2) { return addToList(list, cur); } protected void deleteObj() { deleteRenderable1(getId()); } } static private native void deleteRenderable0(int id); /** The Java proxy representing a Renderable object. */ static public abstract class Renderable1JavaObject extends JavaObject { public Renderable1JavaObject(int id) { super(id); } /** Add this object to the given list with the given coordinate system. * Usage: *
	 * 	int[] list;
	 * 	int curs;
	 * 	curs = obj.addToList(list, curs, coordsys);
	 * 
* @param list The display list to add this to. * @param cur The current index, to which the first int goes * @param coordsys The number of the coordinate system. * @return The new current index after adding these. */ public int addToList(int[] list, int cur, int coordsys) { list[cur++] = (RENDERABLE1 | getId()); list[cur++] = coordsys; return cur; } public int addToListGL(GraphicsAPI.Window win, int[] list, int cur, int cs1, int cs2) { return addToList(list, cur, cs1); } protected void deleteObj() { deleteRenderable1(getId()); } } static private native void deleteRenderable1(int id); /** The Java proxy representing a Renderable2 object. */ static public abstract class Renderable2JavaObject extends JavaObject { public Renderable2JavaObject(int id) { super(id); } /** Add this object to the given list with the given coordinate * systems. * Usage: *
	 * 	int[] list;
	 * 	int curs;
	 * 	curs = obj.addToList(list, curs, coordsys1, coordsys2);
	 * 
* @param list The display list to add this to. * @param cur The current index, to which the first int goes * @param coordsys1 The number of the first system. * @param coordsys2 The number of the second system. * @return The new current index after adding these. */ public int addToListGL(GraphicsAPI.Window win, int[] list, int cur, int coordsys1, int coordsys2) { list[cur++] = (RENDERABLE2 | getId()); list[cur++] = coordsys1; list[cur++] = coordsys2; return cur; } protected void deleteObj() { deleteRenderable2(getId()); } } static private native void deleteRenderable2(int id); //--------- Window final static public class Window extends NonRenderableJavaObject { private Window(int id) { super(id); } protected void deleteObj() { deleteWindow(getId()); } public void repaint() { GL.repaintWindow(getId()); } public void addTimeout(int ms, int id) { addTimeoutWindow(getId(), ms, id); } public Rectangle getBounds() { Rectangle rect = new Rectangle(); getWindowSize(getId(), rect); return rect; } public void setCurrent() { impl_Window_setCurrent(getId()); } public void release() { impl_Window_release(getId()); } public void move(int x, int y) { impl_Window_move(getId(), x, y); } public void resize(int w, int h) { impl_Window_resize(getId(), w, h); } } final private static Window defaultWindow = new Window(-1); static public Window createWindow(int x, int y, int w, int h, EventHandler eh) { return new Window(createWindowImpl(x, y, w, h, eh)); } static private native int createWindowImpl(int x, int y, int w, int h, EventHandler eh); static private native void deleteWindow(int i); static private native void repaintWindow(int id); static private native void getWindowSize(int id, Rectangle into); static private native void addTimeoutWindow(int id, int ms, int tid); static private native void impl_Window_setCurrent(int id); static private native void impl_Window_release(int id); static private native void impl_Window_move(int id, int x, int y); static private native void impl_Window_resize(int id, int w, int h); //--------- Image static public class Image extends NonRenderableJavaObject { private Image(int id) { super(id); } protected void deleteObj() { deleteImage(getId()); } int getSize(int dimNo) { return getImageSize(getId(), dimNo); } } /** THIS METHOD IS A SEVERE SECURITY HOLE AND WILL BE REMOVED. * Exploit: load something that the image loader library doesn't like... * Need to work out how this should properly interact with mediaserver. */ static public Image createImage(String filename) { return new Image(createImageImpl(filename)); } static private native int createImageImpl(String filename); static private native void deleteImage(int i); static private native int getImageSize(int id, int dimNo); //--------- ImageCache static public class ImageCache { public static void get(String uri, int lod) { getFromImageCache(uri, lod); } public static void write(String uri, char buf[], int len) { writeToImageCache(uri, buf, len); } } static private native void getFromImageCache(String uri, int lod); static private native void writeToImageCache(String uri, char buf[], int len); static public void startBackgroundImageLoader(String uri) { gzz.gfx.gl.GLBackgroundImageLoader.startLoading(uri); } //--------- TexRect /** A rectangular region of an image, loaded into a texture. */ static public class TexRect extends NonRenderableJavaObject { private TexRect(int id) { super(id); } protected void deleteObj() { deleteImage(getId()); } public int getTexId() { return getTexRectTexID(getId()); } public double getTexCoord(int coordInd, double c) { return getTexRectTexCoord(getId(), coordInd, c); } } static public TexRect createTexRect(Image img) { return new TexRect(createTexRectImpl(img.getId())); } static private native int createTexRectImpl(int img); static private native void deleteTexRect(int i); static private native int getTexRectTexID(int i); static private native double getTexRectTexCoord(int i, int coordInd, double c); //--------- Texture /** A texture object. * Here, id == directly the texture id. */ static public class Texture extends NonRenderableJavaObject { private Texture(int id) { super(id); } protected void deleteObj() { impl_deleteTexture(getId()); } public int getTexId() { return getId(); } public int shade(int w, int h, int d, int comps, String internalFormat, String format, String shaderName, String[] params) { return impl_Texture_shade(getId(), w, h, d, comps, internalFormat, format, shaderName, params); } public void loadNull2D(int level, String internalFormat, int w, int h, int border, String format, String type) { impl_Texture_loadNull2D(getId(), level, internalFormat, w, h, border, format, type); } public void loadSubImage(int level, Image img, int xoffs, int yoffs) { impl_Texture_loadSubImage(getId(), level, img.getId(), xoffs, yoffs); } public void downsampleInto(Texture into, String target, int level, String internalFormat, String transferformat) { impl_Texture_downsampleInto(getId(), into.getId(), target, level, internalFormat, transferformat); } } static public Texture createTexture() { return new Texture(impl_createTexture()); } static private native int impl_createTexture(); static private native void impl_deleteTexture(int id); static private native int impl_Texture_shade(int id, int w, int h, int d, int comps, String internalFormat, String format, String shaderName, String[] params); static private native void impl_Texture_loadNull2D(int id, int level, String internalFormat, int w, int h, int border, String format, String type) ; static private native void impl_Texture_loadSubImage(int id, int level, int imgid, int xoffs, int yoffs) ; static private native void impl_Texture_downsampleInto(int id, int intoid, String target, int level, String internalFormat, String transferformat); //--------- VertexProgramNV /** A vertex program object. * Like Texture, id = directly VP id */ static public class VertexProgramNV extends NonRenderableJavaObject { private VertexProgramNV(int id) { super(id); } protected void deleteObj() { impl_deleteVertexProgramNV(getId()); } public int getVPId() { return getId(); } public int load(String program) { return impl_VertexProgramNV_load(getId(), program); } } static public VertexProgramNV createVertexProgramNV() { return new VertexProgramNV(impl_createVertexProgramNV()); } static public VertexProgramNV createVertexProgramNV(String program) { VertexProgramNV vp = new VertexProgramNV(impl_createVertexProgramNV()); vp.load(program); return vp; } static private native int impl_createVertexProgramNV(); static private native void impl_deleteVertexProgramNV(int id); static private native int impl_VertexProgramNV_load(int id, String program); //--------- ShaderRect /** 3D/2D shader image data, loaded into textures. */ static public class ShaderRect extends NonRenderableJavaObject { private ShaderRect(int id) { super(id); } protected void deleteObj() { deleteImage(getId()); } } static public ShaderRect createShaderRect(String turb, String col, String spots, String cell) { return new ShaderRect(createShaderRectImpl(turb, col, spots, cell)); } static private native int createShaderRectImpl(String turb, String col, String spots, String cell); static private native void deleteShaderRect(int i); //--------- Font static public class Font extends NonRenderableJavaObject{ float height; float yoffs; private Font(int id) { super(id); height = getFontHeight(getId()); yoffs = getFontYOffs(getId()); } protected void deleteObj() { deleteFont(getId()); } public float getHeight() { return height; } public float getYOffs() { return yoffs; } public void getWidths(short[] w) { putFontWidths(getId(), w); } } static public Font createFont(String name, int loadPt) { return new Font(createFontImpl(name, loadPt)); } static private native float getFontHeight(int id); static private native float getFontYOffs(int id); static private native int createFontImpl(String name, int loadPt); static private native void deleteFont(int id); static private native void putFontWidths(int id, short[] w); //--------- DisplayList static public class DisplayList extends NonRenderableJavaObject{ private DisplayList(int id) { super(id); } protected void deleteObj() { deleteDisplayList(getId()); } public void startCompile(Window w) { GL.startCompile(getId(), w.getId()); } public void endCompile(Window w) { GL.endCompile(getId(), w.getId()); } public void compileCallGL(String s) { GL.compileCallGL(getId(), s); } } static public DisplayList createDisplayList() { return new DisplayList(createDisplayListImpl()); } static public DisplayList createDisplayList(String s) { DisplayList d = new DisplayList(createDisplayListImpl()); d.compileCallGL(s); return d; } static private native int createDisplayListImpl(); static private native void startCompile(int id, int wid); static private native void endCompile(int id, int wid); static private native void compileCallGL(int id, String s); static private native void deleteDisplayList(int id); //---------- ByteVector static public class ByteVector extends NonRenderableJavaObject { private ByteVector(int id) { super(id); } protected void deleteObj() { deleteByteVector(getId()); } public int get(int ind) { return impl_ByteVector_get(getId(), ind); } public void readFromBuffer_ubytes(Window win, String buffer, int x, int y, int width, int height, String format) { impl_ByteVector_readFromBuffer_ubytes(getId(), win.getId(), buffer, x, y, width, height, format); } } static public ByteVector createByteVector() { return createByteVector(0); } static public ByteVector createByteVector(int size) { return new ByteVector(createByteVectorImpl(size)); } static private native int createByteVectorImpl(int size); static private native void deleteByteVector(int id); static private native void impl_ByteVector_readFromBuffer_ubytes( int id, int winid, String buffer, int x, int y, int width, int height, String format) ; static private native int impl_ByteVector_get(int id, int ind); //----------Misc public static void render( Window win, int[] codes, float[] pts1, float[] pts2, int numpts, float fract, boolean standardcoords, boolean showFinal) { renderImpl(win.getId(), codes, pts1, null, pts2, numpts, fract, standardcoords, showFinal); } public static void render( Window win, int[] codes, float[] pts1, int[] indices2, float[] pts2, int numpts, float fract, boolean standardcoords, boolean showFinal) { renderImpl(win.getId(), codes, pts1, indices2, pts2, numpts, fract, standardcoords, showFinal); } private static native void renderImpl( int window, int[] codes, float[] pts1, int[] indices2, float[] pts2, int numpts, float fract, boolean standardcoords, boolean showFinal); public static float timeRender( Window win, int[] codes, float[] pts1, int numpts, boolean standardcoords, int iters) { return timeRenderImpl(win.getId(), codes, pts1, numpts, standardcoords, iters); } private static native float timeRenderImpl( int window, int[] codes, float[] pts1, int numpts, boolean standardcoords, int iters); public static void eventLoop(Ticker t) { while(true) { p("TICK"); boolean ret = t.tick(); p("GOING TO EVENTLOOP"); eventLoop(!ret); } } /** Process native events. * @param wait If false, this function will return once there are no more * native events to process. If true, this function will wait * for the next native event. */ public static native void eventLoop(boolean wait); public static native void setDebugVar(String name, int value); public static native int getDebugVar(String name); public static native String[] getDebugVarNames(); public static native String getGLString(String name); public static native float[] getGLFloat(String name); public static native float[] getGLTexParameterFloat(String target, int tex, String name); public static native float[] getGLTexLevelParameterFloat(String target, int tex, int level, String name); public static native String getGLTokenString(int value); // Clear stencil buffer: on some NVIDIA drivers, there // seems to be a bug. public static native void reallyClearStencilBuffer(int w, int h); }