package org.newdawn.slick.opengl; import org.lwjgl.opengl.GL11; import org.newdawn.slick.SlickException; import org.newdawn.slick.opengl.renderer.Renderer; /** * A utility to allow performing GL operations without contaminating the * Slick OpenGL state. Note this will not protect you from OpenGL programming errors * like a glBegin() without a glEnd(), or glPush() without glPop() etc. * * Expected usage: * * <code> * SlickCallable callable = new SlickCallable() { * public performGLOperations() throws SlickException { * GL.glTranslate(0,0,1); * glBegin(GL.GL_POLYGONS); * glVertex(..); * ... * glEnd(); * } * } * callable.call(); * </code> * * Alternatively you can use the static methods directly * * <code> * SlickCallable.enterSafeBlock(); * * GL.glTranslate(0,0,1); * glBegin(GL.GL_POLYGONS); * glVertex(..); * ... * glEnd(); * * SlickCallable.leaveSafeBlock(); * </code> * * @author kevin */ public abstract class SlickCallable { /** The last texture used */ private static Texture lastUsed; /** True if we're in a safe block */ private static boolean inSafe = false; /** * Enter a safe block ensuring that all the OpenGL state that slick * uses is safe before touching the GL state directly. */ public static void enterSafeBlock() { if (inSafe) { return; } Renderer.get().flush(); lastUsed = TextureImpl.getLastBind(); TextureImpl.bindNone(); GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glPushMatrix(); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); GL11.glMatrixMode(GL11.GL_MODELVIEW); inSafe = true; } /** * Leave a safe block ensuring that all of Slick's OpenGL state is * restored since the last enter. */ public static void leaveSafeBlock() { if (!inSafe) { return; } GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPopMatrix(); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glPopMatrix(); GL11.glPopClientAttrib(); GL11.glPopAttrib(); if (lastUsed != null) { lastUsed.bind(); } else { TextureImpl.bindNone(); } inSafe = false; } /** * Cause this callable to perform it's GL operations (@see performGLOperations()). This * method will block until the GL operations have been performed. * * @throws SlickException Indicates a failure while performing the GL operations or * maintaing SlickState */ public final void call() throws SlickException { enterSafeBlock(); performGLOperations(); leaveSafeBlock(); } /** * Perform the GL operations that this callable is intended to. This operations should * not effect the slick OpenGL state. * * @throws SlickException Indicates a failure of some sort. This is user exception */ protected abstract void performGLOperations() throws SlickException; }