Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package glapp;
- import java.util.*;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import java.lang.reflect.Method;
- import java.nio.*;
- import java.io.*;
- import java.net.URL;
- import org.lwjgl.*;
- import org.lwjgl.opengl.*;
- import org.lwjgl.input.*;
- import org.lwjgl.util.glu.*;
- /**
- * Collection of functions to init and run an OpenGL app using LWJGL.
- * <P>
- * Includes functions to handle: <BR>
- * Setup display mode, keyboard, mouse, handle events<BR>
- * Run main loop of application <BR>
- * Buffer allocation -- manage IntBuffer, ByteBuffer calls. <BR>
- * OpenGL functions -- convert screen/world coords, set modes, lights, etc. <BR>
- * Utility functions -- load images, convert pixels, getTimeInMillis, etc. <BR>
- * <P>
- * Has a main() function to run as an application, though this class has only
- * minimal placeholder functionality. It is meant to be subclassed,
- * and the subclass will define setup() draw() mouseMove() functions, etc.
- * <P>
- * GLApp initializes the LWJGL environment for OpenGL rendering,
- * ie. creates a window, sets the display mode, inits mouse and keyboard,
- * then runs a loop.
- * <P>
- * Uses GLImage to load and hold image pixels.
- * <P>
- * napier -at- potatoland -dot- org
- *
- * @see GLImage
- */
- public class GLApp {
- // Just for reference
- public static final String GLAPP_VERSION = ".5";
- // Byte size of data types: Used when allocating native buffers
- public static final int SIZE_DOUBLE = 8;
- public static final int SIZE_FLOAT = 4;
- public static final int SIZE_INT = 4;
- public static final int SIZE_BYTE = 1;
- // Application settings
- // These can be tweaked in main() before calling app.run()
- // to customize app behavior.
- public static int finishedKey = Keyboard.KEY_ESCAPE; // App will exit when this key is hit (set to 0 for no key exit)
- public static String window_title = "OpenGL Window"; // window title, set in initDisplay()
- public static String configFilename = "GLApp.cfg"; // init() calls loadSettings() to load initial settings from this file (OPTIONAL)
- public static boolean hideNativeCursor = false; // hide the operating system cursor, see hideNativeCursor()
- public static boolean disableNativeCursor = false; // turn completely off the operating system cursor, see disableNativeCursor()
- public static boolean VSyncEnabled = true; // if true, synchronize screen updates with video refresh rate
- public static boolean useCurrentDisplay = false; // when initing display, use the settings of the desktop (whatever the PC was using before app was started)
- public static boolean fullScreen = false; // full screen or floating window
- public static boolean showMessages = true; // if true, show debug messages, if false show only error messages (see msg() err())
- public static float aspectRatio = 0; // aspect ratio of OpenGL context (if 0, default to displayWidth/displayHeight)
- // Display settings (settings in glapp.cfg will override these)
- // initDisplay() will pick a Display that best matches displayWidth,
- // displayHeight, displayColorBits, displayFrequency. If these values
- // are -1, initDisplay() will use the desktop screen settings.
- public static int displayWidth = -1;
- public static int displayHeight = -1;
- public static int displayColorBits = -1;
- public static int displayFrequency = -1;
- public static int depthBufferBits = 24; // bits per pixel in the depth buffer
- public static int viewportX, viewportY; // viewport position (will default to 0,0)
- public static int viewportW, viewportH; // viewport size (will default to screen width, height)
- //private static int orthoWidth = 0;
- //private static int orthoHeight = 0;
- // DisplayMode chosen by initDisplay()
- // DM and displayMode are the same thing.
- public static DisplayMode DM, origDM; // hold display mode we set, and the display mode when app first executes
- public static DisplayMode displayMode; // hold display mode we set (same as DM)
- // Application variables
- // These are set internally but can be read by the
- // subclass application.
- public static Properties settings=new Properties(); // holds settings from file GLApp.cfg (see loadSettings())
- public static boolean finished; // App will exit when finished is true (when finishedKey is hit: see run())
- public static int cursorX, cursorY; // mouse position (see handleEvents())
- public static double lastFrameTime = 0; // ticks since last frame was drawn (see run() and updateTimer())
- public static double secondsSinceLastFrame = 0; // seconds elapsed since last frame was drawn (see updateTimer())
- public static long ticksPerSecond = 0; // used to calc time in millis
- public static int frameCount = 0; // count frames per sec (just to track performance)
- // For copying screen image to a texture
- public static int screenTextureSize = 1024; // how large should texture be to hold screen (see makeTextureForScreen())
- // NIO Buffers to retrieve OpenGL settings.
- // For memory efficiency and performance, instantiate these once, and reuse.
- // see getSetingInt(), getModelviewMatrix(), project(), unProject()
- public static IntBuffer bufferViewport = allocInts(16);
- public static FloatBuffer bufferModelviewMatrix = allocFloats(16);
- public static FloatBuffer bufferProjectionMatrix = allocFloats(16);
- public static FloatBuffer tmpResult = allocFloats(16); // temp var to hold project/unproject results
- public static FloatBuffer tmpFloats = allocFloats(4); // temp var used by setLightPos(), setFog()
- public static ByteBuffer tmpFloat = allocBytes(SIZE_FLOAT); // temp var used by getZDepth()
- public static IntBuffer tmpInts = allocInts(16); // temp var used by getSettingInt()
- public static ByteBuffer tmpByte = allocBytes(SIZE_BYTE); // temp var used by getStencilValue()
- public static ByteBuffer tmpInt = allocBytes(GLApp.SIZE_INT); // temp var used by getPixelColor()
- // Material colors (see setMaterial())
- public static FloatBuffer mtldiffuse = allocFloats(4); // color of the lit surface
- public static FloatBuffer mtlambient = allocFloats(4); // color of the shadowed surface
- public static FloatBuffer mtlspecular = allocFloats(4); // reflection color (typically this is a shade of gray)
- public static FloatBuffer mtlemissive = allocFloats(4); // glow color
- public static FloatBuffer mtlshininess = allocFloats(4); // size of the reflection highlight
- // Misc.
- public static float rotation = 0f; // to rotate cubes (just to put something on screen)
- public static final float PIOVER180 = 0.0174532925f; // A constant used in navigation: PI/180
- public static final float PIUNDER180 = 57.2957795130f; // A constant used in navigation: 180/PI;
- static Hashtable OpenGLextensions; // will be populated by extensionExists()
- static double avgSecsPerFrame=.01; // to smooth out motion, keep a moving average of frame render times
- //========================================================================
- // Run main loop of application. Handle mouse and keyboard input.
- //
- // The functions main(), run() and init() start and run the application.
- // The run() function starts a loop that handles mouse and keyboard events
- // and calls draw() repeatedly.
- //
- //========================================================================
- public static void main(String args[]) {
- GLApp demo = new GLApp();
- demo.run();
- }
- /**
- * Runs the application. Calls init() function to setup OpenGL,
- * input and display. Runs the main loop of the application, which handles
- * mouse and keyboard input.
- * <P>
- * Calls init(), handleEvents(), update() and draw(). <BR>
- * handleEvents() calls: mouseMove(), mouseDown(), mouseUp(), keyDown(), keyUp()
- */
- public void run() {
- // hold onto application class in case we need to load images from jar (see getInputStream())
- setRootClass();
- try {
- // Init Display, Keyboard, Mouse, OpenGL, load config file
- init();
- // Main loop
- while (!finished) {
- if (!Display.isVisible()) { // window is minimized
- Thread.sleep(200L);
- }
- else if (Display.isCloseRequested()) { // window X button clicked
- finished = true;
- }
- else { // yield a little so other threads can work
- Thread.sleep(1);
- }
- updateTimer(); // track when frame was drawn (see secondsSinceLastFrame)
- handleEvents(); // call key...() and mouse...() functions based on input events
- update(); // do program logic here (subclass may override this)
- draw(); // redraw the screen (subclass overrides this)
- Display.update();
- }
- }
- catch (Exception e) {
- err("GLApp.run(): " + e);
- e.printStackTrace(System.out);
- }
- // prepare to exit
- cleanup();
- System.exit(0);
- }
- /**
- * Called only once when app is first started, init() prepares the display,
- * mouse and OpenGL context for use. Override init() only if you want to
- * substantially alter the app startup behavior. Otherwise just override
- * initGL() to tweak the OpenGL context and setup() to load textures,
- * models, etc..
- */
- public void init()
- {
- // load settings from config file (display size, resolution, etc.)
- loadSettings(configFilename);
- initDisplay();
- initInput();
- initGL();
- setup(); // subclass usually overrides this
- updateTimer(); // Do this once to init time values to something sane, otherwise the first game loop will report a huge secondsElapsedPerFrame
- }
- /**
- * Called by the run() loop. Handles animation and input for each frame.
- */
- public void handleEvents() {
- int mouseDX = Mouse.getDX();
- int mouseDY = Mouse.getDY();
- int mouseDW = Mouse.getDWheel();
- // handle mouse motion
- if (mouseDX != 0 || mouseDY != 0 || mouseDW != 0) {
- cursorX += mouseDX;
- cursorY += mouseDY;
- if (cursorX < 0) {
- cursorX = 0;
- }
- else if (cursorX > displayMode.getWidth()) {
- cursorX = displayMode.getWidth();
- }
- if (cursorY < 0) {
- cursorY = 0;
- }
- else if (cursorY > displayMode.getHeight()) {
- cursorY = displayMode.getHeight();
- }
- mouseMove(cursorX,cursorY);
- //msg("DX=" + mouseDX + " DY=" + mouseDY + " cursorX=" + cursorX);
- }
- // handle mouse wheel event
- if (mouseDW != 0) {
- mouseWheel(mouseDW);
- }
- // handle mouse clicks
- while ( Mouse.next() ) {
- if(Mouse.getEventButton() == 0 && Mouse.getEventButtonState() == true) {
- mouseDown(cursorX, cursorY);
- }
- if(Mouse.getEventButton() == 0 && Mouse.getEventButtonState() == false) {
- mouseUp(cursorX, cursorY);
- }
- if(Mouse.getEventButton() == 1 && Mouse.getEventButtonState() == true) {
- mouseDown(cursorX, cursorY);
- }
- if(Mouse.getEventButton() == 1 && Mouse.getEventButtonState() == false) {
- mouseUp(cursorX, cursorY);
- }
- }
- // Handle key hits
- while ( Keyboard.next() ) {
- // check for exit key
- if (Keyboard.getEventKey() == finishedKey) {
- finished = true;
- }
- // pass key event to handler
- if (Keyboard.getEventKeyState()) { // key was just pressed, trigger keyDown()
- keyDown(Keyboard.getEventKey());
- }
- else {
- keyUp(Keyboard.getEventKey()); // key was released
- }
- }
- // Count frames
- frameCount++;
- if ((Sys.getTime()-lastFrameTime) > ticksPerSecond) {
- //msg("==============> FramesPerSec=" + (frameCount/1) + " timeinsecs=" + getTimeInSeconds() + " timeinmillis=" + getTimeInMillis());
- frameCount = 0;
- }
- }
- /**
- * Load configuration settings from optional properties file.
- * File format is:<BR>
- * <PRE>
- * # Comment
- * displayWidth=1024
- * displayHeight=768
- * </PRE>
- *
- * @param configFilename
- */
- public void loadSettings(String configFilename)
- {
- if (configFilename == null || configFilename.equals("")) {
- return;
- }
- InputStream configFileIn = getInputStream(configFilename);
- settings = new Properties();
- if (configFileIn == null) {
- msg("GLApp.loadSettings() warning: config file " + configFilename + " not found, will use default settings.");
- return;
- }
- else {
- try { settings.load(configFileIn); }
- catch (Exception e) {
- msg("GLApp.loadSettings() warning: " + e);
- return;
- }
- }
- // Debug: show the settings
- settings.list(System.out);
- // Check for available settings
- if (settings.getProperty("displayWidth") != null) {
- displayWidth = Integer.parseInt(settings.getProperty("displayWidth"));
- }
- if (settings.getProperty("displayHeight") != null) {
- displayHeight = Integer.parseInt(settings.getProperty("displayHeight"));
- }
- if (settings.getProperty("displayColorBits") != null) {
- displayColorBits = Integer.parseInt(settings.getProperty("displayColorBits"));
- }
- if (settings.getProperty("displayFrequency") != null) {
- displayFrequency = Integer.parseInt(settings.getProperty("displayFrequency"));
- }
- if (settings.getProperty("depthBufferBits") != null) {
- depthBufferBits = Integer.parseInt(settings.getProperty("depthBufferBits"));
- }
- if (settings.getProperty("aspectRatio") != null) {
- aspectRatio = Float.parseFloat(settings.getProperty("aspectRatio"));
- }
- if (settings.getProperty("fullScreen") != null) {
- fullScreen = settings.getProperty("fullScreen").toUpperCase().equals("YES");
- }
- if (settings.getProperty("useCurrentDisplay") != null) {
- useCurrentDisplay = settings.getProperty("useCurrentDisplay").toUpperCase().equals("YES");
- }
- if (settings.getProperty("finishedKey") != null) { // key codes are defined in the lwjgl Keyboard class
- finishedKey = Integer.parseInt(settings.getProperty("finishedKey"));
- }
- if (settings.getProperty("window_title") != null) {
- window_title = settings.getProperty("window_title");
- }
- if (settings.getProperty("VSyncEnabled") != null) {
- VSyncEnabled = settings.getProperty("VSyncEnabled").toUpperCase().equals("YES");
- }
- }
- //========================================================================
- // Setup display mode
- //
- // Initialize Display, Mouse, Keyboard.
- //
- //========================================================================
- /**
- * Initialize the Display mode, viewport size, and open a Window.
- * By default the window is fullscreen, the viewport is the same dimensions
- * as the window.
- */
- public boolean initDisplay() {
- origDM = Display.getDisplayMode(); // current display settings
- msg("GLApp.initDisplay(): Current display mode is " + origDM);
- // for display properties that have not been specified, default to current display value
- if (displayHeight == -1) displayHeight = origDM.getHeight();
- if (displayWidth == -1) displayWidth = origDM.getWidth();
- if (displayColorBits == -1) displayColorBits = origDM.getBitsPerPixel();
- if (displayFrequency == -1) displayFrequency = origDM.getFrequency();
- // Set display mode
- try {
- if (useCurrentDisplay) {
- // use current display settings (ignore properties file)
- DM = origDM;
- }
- else {
- // find a display mode that matches the specified settings (or use a sane alternative)
- if ( (DM = getDisplayMode(displayWidth, displayHeight, displayColorBits, displayFrequency)) == null) {
- if ( (DM = getDisplayMode(1024, 768, 32, 60)) == null) {
- if ( (DM = getDisplayMode(1024, 768, 16, 60)) == null) {
- if ( (DM = getDisplayMode(origDM.getWidth(), origDM.getHeight(), origDM.getBitsPerPixel(), origDM.getFrequency())) == null) {
- err("GLApp.initDisplay(): Can't find a compatible Display Mode!!!");
- }
- }
- }
- }
- }
- msg("GLApp.initDisplay(): Setting display mode to " + DM + " with pixel depth = " + depthBufferBits);
- Display.setDisplayMode(DM);
- displayMode = DM;
- displayWidth = DM.getWidth();
- displayHeight = DM.getHeight();
- displayColorBits = DM.getBitsPerPixel();
- displayFrequency = DM.getFrequency();
- }
- catch (Exception exception) {
- System.err.println("GLApp.initDisplay(): Failed to create display: " + exception);
- System.exit(1); //!!!!new
- }
- // Initialize the Window
- try {
- Display.create(new PixelFormat(0, depthBufferBits, 8)); // set bits per buffer: alpha, depth, stencil
- Display.setTitle(window_title);
- Display.setFullscreen(fullScreen);
- Display.setVSyncEnabled(VSyncEnabled);
- //msg("GLApp.initDisplay(): Created OpenGL window.");
- }
- catch (Exception exception1) {
- System.err.println("GLApp.initDisplay(): Failed to create OpenGL window: " + exception1);
- System.exit(1);
- }
- // Set viewport width/height and Aspect ratio.
- if (aspectRatio == 0f) {
- // no aspect ratio was set in GLApp.cfg: default to full screen.
- aspectRatio = (float)DM.getWidth() / (float)DM.getHeight(); // calc aspect ratio of display
- }
- // viewport may not match shape of screen. Adjust to fit.
- viewportH = DM.getHeight(); // viewport Height
- viewportW = (int) (DM.getHeight() * aspectRatio); // Width
- if (viewportW > DM.getWidth()) {
- viewportW = DM.getWidth();
- viewportH = (int) (DM.getWidth() * (1 / aspectRatio));
- }
- // center viewport in screen
- viewportX = (int) ((DM.getWidth()-viewportW) / 2);
- viewportY = (int) ((DM.getHeight()-viewportH) / 2);
- return true;
- }
- /**
- * Retrieve a DisplayMode object with the given params
- */
- public static DisplayMode getDisplayMode(int w, int h, int colorBits, int freq) {
- try {
- DisplayMode allDisplayModes[] = Display.getAvailableDisplayModes();
- DisplayMode dm = null;
- for (int j = 0; j < allDisplayModes.length; j++) {
- dm = allDisplayModes[j];
- if (dm.getWidth() == w && dm.getHeight() == h && dm.getBitsPerPixel() == colorBits &&
- dm.getFrequency() == freq) {
- return dm;
- }
- }
- }
- catch (LWJGLException lwjgle) {
- err("GLApp.getDisplayMode() error:" + lwjgle);
- }
- return null;
- }
- /**
- * Initialize the Keyboard and Mouse.
- * <P>
- * Disable or hide the native cursor. Set the initial cursor position. Get
- * the timer resolution (ticks per second).
- *
- * @see handleEvents()
- */
- public void initInput() {
- try {
- // init keyboard
- Keyboard.create();
- // Turn off native cursor?
- if (disableNativeCursor) {
- // Mouse.setGrabbed(true) will turn off the native cursor
- disableNativeCursor(true);
- // set initial cursor pos to center screen
- cursorX = (int) DM.getWidth() / 2;
- cursorY = (int) DM.getHeight() / 2;
- }
- // Hide native cursor when inside application window?
- if (hideNativeCursor) {
- hideNativeCursor(true);
- }
- // Init hi-res timer (see time functions)
- ticksPerSecond = Sys.getTimerResolution();
- }
- catch (Exception e) {
- err("GLApp.initInput(): " + e);
- }
- }
- //========================================================================
- // Custom Application functionality: can be overriden by subclass.
- //
- // Functions to initialize OpenGL, set the viewing mode, render the scene,
- // respond to mouse actions, and initialize the app. These functions
- // are overridden in the subclass to create custom behavior.
- //
- //========================================================================
- /**
- * Initialize the OpenGL context. The subclass can override this function
- * to customize the OpenGL settings. This function is called by init()
- * once when app starts, but may be called again to restore settings to a
- * default state, or to initialize a PBuffer object to the exact same
- * state as the display.
- */
- public void initGL() {
- try {
- // Depth test setup
- GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
- GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do
- // Some basic settings
- GL11.glClearColor(0f, 0f, 0f, 1f); // Black Background
- GL11.glEnable(GL11.GL_NORMALIZE); // force normal lengths to 1
- GL11.glEnable(GL11.GL_CULL_FACE); // don't render hidden faces
- GL11.glEnable(GL11.GL_TEXTURE_2D); // use textures
- GL11.glEnable(GL11.GL_BLEND); // enable transparency
- // How to handle transparency: average colors together
- GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- // Enable alpha test so the transparent backgrounds in texture images don't draw.
- // This prevents transparent areas from affecting the depth or stencil buffer.
- // alpha func will accept only fragments with alpha greater than 0
- GL11.glEnable(GL11.GL_ALPHA_TEST);
- GL11.glAlphaFunc(GL11.GL_GREATER, 0f);
- // Draw specular highlghts on top of textures
- GL11.glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SEPARATE_SPECULAR_COLOR );
- // Perspective quality
- GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
- // Set the size and shape of the screen area
- GL11.glViewport(viewportX, viewportY, viewportW, viewportH);
- // setup perspective (see setOrtho() for 2D)
- setPerspective();
- // select model view for subsequent transformations
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- GL11.glLoadIdentity();
- }
- catch (Exception e) {
- err("GLApp.initOpenGL(): " + e);
- }
- }
- /**
- * Setup can be overridden by the subclass to initialize the application
- * ie load textures, models, and create data structures used by the app.
- *
- * This function is called only once, when application starts. It is
- * called after initDisplay and initOpenGL(), so the OpenGL context is
- * already created.
- *
- * @see init()
- */
- public void setup() {
- }
- /**
- * Update can be overridden by the subclass
- *
- * @see run()
- */
- public void update() {
- }
- /**
- * Called by run() to draw one frame. Subclass will override this.
- * This is an alias function just to be follow Processing and OpenFrameworks
- * function naming conventions.
- */
- public void draw() {
- render();
- }
- /**
- * Same as draw(). Subclass can override render() instead of draw().
- * Same thing, just a matter of taste.
- */
- public void render() {
- // rotate 90 degrees per second
- rotation += secondsSinceLastFrame * 90f;
- // clear depth buffer and color
- GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
- // select model view for subsequent transforms
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- GL11.glLoadIdentity();
- // set viewpoint 10 units from origin, looking at origin
- GLU.gluLookAt(0,0,10, 0,0,0, 0,1,0);
- // rotate, scale and draw cube
- GL11.glPushMatrix();
- {
- GL11.glRotatef(rotation, 0, 1, 0);
- GL11.glColor4f(0f, .5f, 1f, 1f);
- renderCube();
- }
- GL11.glPopMatrix();
- // draw another overlapping cube
- GL11.glPushMatrix();
- {
- GL11.glRotatef(rotation, 1, 1, 1);
- GL11.glColor4f(.7f, .5f, 0f, 1f);
- renderCube();
- }
- GL11.glPopMatrix();
- }
- /**
- * Run() calls this right before exit. Free up allocated resources (display lists)
- * and gracefully shut down OpenGL context.
- */
- public void cleanup() {
- destroyFont();
- destroyDisplayLists();
- Keyboard.destroy();
- Display.destroy(); // will call Mouse.destroy()
- }
- /**
- * Shutdown the application. This will call cleanup() before exiting from the
- * application.
- * @see cleanup()
- */
- public void exit() {
- finished = true;
- }
- //========================================================================
- // Mouse events, called by handleEvents()
- //========================================================================
- /**
- * Called by handleEvents() when mouse moves
- */
- public void mouseMove(int x, int y) {
- }
- public void mouseDown(int x, int y) {
- }
- public void mouseUp(int x, int y) {
- }
- public void mouseWheel(int wheelMoved) {
- }
- /**
- * Return true if the given mousebutton is down. Typically mouse buttons
- * are 0=left, 1=right. This function can be called inside mouse events such
- * as mouseDown() and mouseMove() to see which button is activated.
- * @param whichButton number of mouse button (0=left button)
- */
- public boolean mouseButtonDown(int whichButton) {
- return Mouse.isButtonDown(whichButton);
- }
- /**
- * Called when key is pressed. Keycode will be the key ID value as
- * defined in the LWJGL Keyboard class.
- *
- * @see Keyboard class in the LWJGL documentation
- * @param keycode
- */
- public void keyDown(int keycode) {
- }
- /**
- * Called when key is released. Keycode will be the key ID value as
- * defined in the LWJGL Keyboard class.
- *
- * @see Keyboard class in the LWJGL documentation
- * @param keycode
- */
- public void keyUp(int keycode) {
- }
- /**
- * Return the character associatated with the last key event. When
- * called inside keyDown() or keyUp() this function will return the
- * character equivalent of the keycode that was passed to keyDown()
- * or keyUp().
- */
- public char keyChar() {
- return Keyboard.getEventCharacter();
- }
- //========================================================================
- // functions to get values from a Properties object. Properties can be
- // loaded from a text file containing name=value pairs.
- //========================================================================
- /**
- * Load configuration settings from a properties file.
- * File format is:<BR>
- * <PRE>
- * # Comment
- * displayWidth=1024
- * displayHeight=768
- * </PRE>
- *
- * @param configFilename
- */
- public static Properties loadPropertiesFile(String configFilename)
- {
- Properties props = new Properties();
- try { settings.load(getInputStream(configFilename)); }
- catch (Exception e) {
- msg("GLApp.loadPropertiesFile() warning: " + e);
- return null;
- }
- return props;
- }
- public static String getProperty(Properties props, String propName) {
- String s = null;
- if (propName != null && propName.length() > 0) {
- s = props.getProperty(propName);
- }
- return s;
- }
- public static int getPropertyInt(Properties props, String propName) {
- String s = getProperty(props,propName);
- int v = -1;
- if (s != null) {
- v = Integer.parseInt(s);
- }
- return v;
- }
- public static float getPropertyFloat(Properties props, String propName) {
- String s = getProperty(props,propName);
- float v = -1f;
- if (s != null) {
- v = Float.parseFloat(s);
- }
- return v;
- }
- public static boolean getPropertyBool(Properties props, String propName) {
- String s = getProperty(props,propName);
- boolean v = false;
- if (s != null) {
- v = (s.toUpperCase().equals("YES") || s.toUpperCase().equals("TRUE") || s.equals("1"));
- }
- return v;
- }
- /**
- * Return a property from the application configuration file (the filename given
- * in the configFilename variable). This file is optional, so properties may be empty.
- * @see loadSettings()
- */
- public static String getProperty(String propertyName) {
- return settings.getProperty(propertyName);
- }
- /**
- * return the width of the Viewport (the screen area that OpenGL will draw into).
- * By default the viewport is the same size as the Display (see getWidthWindow()),
- * however the setViewport() function can set the viewport to a sub-region of the screen.
- * <P>
- * This function is only valid after app is running and Display has been initialized.
- *
- * @see setViewport(int,int,int,int)
- */
- public static int getWidth() {
- return viewportW;
- }
- /**
- * return the height of the Viewport (the screen area that OpenGL will draw into).
- * By default the viewport is the same size as the Display (see getHeightWindow()),
- * however the setViewport() function can set the viewport to a sub-region of the screen.
- * <P>
- * This function is only valid after app is running and Display has been initialized.
- *
- * @see setViewport(int,int,int,int)
- */
- public static int getHeight() {
- return viewportH;
- }
- /**
- * return the Display width (the width of the full window). Only valid after app
- * is running and Display has been initialized.
- */
- public static int getWidthWindow() {
- return displayWidth;
- }
- /**
- * return the Display height (the height of the full window). Only valid after
- * app is running and Display has been initialized.
- */
- public static int getHeightWindow() {
- return displayHeight;
- }
- //========================================================================
- // functions to set basic application behavior
- //========================================================================
- /**
- * Set the background color of the screen. The red,green,blue
- * color components are floats in the range 0-1. Black is 0,0,0
- * and white is 1,1,1. Color will take effect the next time the
- * screen is cleared.
- */
- public static void setBackgroundColor(float R, float G, float B) {
- GL11.glClearColor(R,G,B,1);
- }
- /**
- * If the param is true, turn off the hardware cursor. The application can
- * decide how to respond to mouse events and whether to draw a position indicator on
- * screen or not. If running in a window (not fullscreen), there will be no hardware
- * cursor visible and the user cannot move or click outside the window area.
- * <P>
- * If the param is false, the hardware cursor will behave normally. Use
- * hideHardwareCursor() to show or hide the hardware cursor.
- *
- * @see hideHardwareCursor()
- */
- public static void disableNativeCursor(boolean off) {
- disableNativeCursor = off;
- Mouse.setGrabbed(off);
- }
- /**
- * If param is true, make the native cursor transparent. Cursor will be hidden
- * in the window area, but will be visible outside the window (assuming you're not in
- * fullscreen mode). I also used this approach with touch screens because the touch
- * screen drivers needed to read the hardware mouse position, so I
- * couldn't disable the hardware cursor, but I wanted to hide it.
- * <P>
- * If param is false, reset the cursor to the default.
- *
- * @see disableHardwareCursor()
- */
- public static void hideNativeCursor(boolean hide) {
- hideNativeCursor = hide;
- if ( (Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) == 0) {
- err("GLApp.hideHardwareCursor(): No hardwared cursor support!");
- return;
- }
- try {
- if (hide) {
- Cursor cursor = null;
- int cursorImageCount = 1;
- int cursorWidth = Cursor.getMaxCursorSize();
- int cursorHeight = cursorWidth;
- IntBuffer cursorImages;
- IntBuffer cursorDelays = null;
- // Create a single cursor, completely transparent
- cursorImages = ByteBuffer.allocateDirect(cursorWidth * cursorHeight * cursorImageCount * SIZE_INT).order(ByteOrder.nativeOrder()).asIntBuffer();
- for (int j = 0; j < cursorWidth; j++) {
- for (int l = 0; l < cursorHeight; l++) {
- cursorImages.put(0x00000000);
- }
- }
- cursorImages.flip();
- cursor = new Cursor(Cursor.getMaxCursorSize(), Cursor.getMaxCursorSize(), Cursor.getMaxCursorSize() / 2, Cursor.getMaxCursorSize() / 2, cursorImageCount, cursorImages, cursorDelays);
- // turn it on
- Mouse.setNativeCursor(cursor);
- }
- else {
- Mouse.setNativeCursor(null);
- }
- }
- catch (Exception e) {
- err("GLApp.hideHardwareCursor(): error " + e);
- }
- }
- /**
- * Set the cursorX,cursorY position. This will set the screen position of the native
- * cursor also, unless hideCursor() was called.
- *
- * @param screenX
- * @param screenY
- */
- public static void setCursorPosition(int screenX, int screenY) {
- Mouse.setCursorPosition(screenX,screenY);
- cursorX = screenX;
- cursorY = screenY;
- }
- //========================================================================
- // Matrix functions: get settings, get matrices, convert
- // screen to world coords.
- //========================================================================
- /**
- * retrieve a setting from OpenGL (calls glGetInteger())
- * @param whichSetting the id number of the value to be returned (same constants as for glGetInteger())
- */
- public static int getSettingInt(int whichSetting)
- {
- tmpInts.clear();
- GL11.glGetInteger(whichSetting, tmpInts);
- return tmpInt.get(0);
- }
- public static FloatBuffer getModelviewMatrix()
- {
- bufferModelviewMatrix.clear();
- GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, bufferModelviewMatrix);
- return bufferModelviewMatrix;
- }
- public static FloatBuffer getProjectionMatrix()
- {
- bufferProjectionMatrix.clear();
- GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, bufferProjectionMatrix);
- return bufferProjectionMatrix;
- }
- public static IntBuffer getViewport()
- {
- bufferViewport.clear();
- GL11.glGetInteger(GL11.GL_VIEWPORT, bufferViewport);
- return bufferViewport;
- }
- /**
- * Convert a FloatBuffer matrix to a 4x4 float array.
- * @param fb FloatBuffer containing 16 values of 4x4 matrix
- * @return 2 dimensional float array
- */
- public static float[][] getMatrixAsArray(FloatBuffer fb) {
- float[][] fa = new float[4][4];
- fa[0][0] = fb.get();
- fa[0][1] = fb.get();
- fa[0][2] = fb.get();
- fa[0][3] = fb.get();
- fa[1][0] = fb.get();
- fa[1][1] = fb.get();
- fa[1][2] = fb.get();
- fa[1][3] = fb.get();
- fa[2][0] = fb.get();
- fa[2][1] = fb.get();
- fa[2][2] = fb.get();
- fa[2][3] = fb.get();
- fa[3][0] = fb.get();
- fa[3][1] = fb.get();
- fa[3][2] = fb.get();
- fa[3][3] = fb.get();
- return fa;
- }
- /**
- * Return the Z depth of the single pixel at the given screen position.
- */
- public static float getZDepth(int x, int y)
- {
- tmpFloat.clear();
- GL11.glReadPixels(x, y, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, tmpFloat);
- return ( (float) (tmpFloat.getFloat(0)));
- }
- /**
- * Find the Z depth of the origin in the projected world view. Used by getWorldCoordsAtScreen()
- * Projection matrix must be active for this to return correct results (GL.glMatrixMode(GL.GL_PROJECTION)).
- * For some reason I have to chop this to four decimals or I get bizarre
- * results when I use the value in project().
- */
- public static float getZDepthAtOrigin()
- {
- float[] resultf = new float[3];
- project( 0, 0, 0, resultf);
- return ((int)(resultf[2] * 10000F)) / 10000f; // truncate to 4 decimals
- }
- /**
- * Return screen coordinates for a given point in world space. The world
- * point xyz is 'projected' into screen coordinates using the current model
- * and projection matrices, and the current viewport settings.
- *
- * @param x world coordinates
- * @param y
- * @param z
- * @param resultf the screen coordinate as an array of 3 floats
- */
- public static void project(float x, float y, float z, float[] resultf)
- {
- // lwjgl 2.0 altered params for GLU funcs
- GLU.gluProject( x, y, z, getModelviewMatrix(), getProjectionMatrix(), getViewport(), tmpResult);
- resultf[0] = tmpResult.get(0);
- resultf[1] = tmpResult.get(1);
- resultf[2] = tmpResult.get(2);
- }
- /**
- * Return world coordinates for a given point on the screen. The screen
- * point xyz is 'un-projected' back into world coordinates using the
- * current model and projection matrices, and the current viewport settings.
- *
- * @param x screen x position
- * @param y screen y position
- * @param z z-buffer depth position
- * @param resultf the world coordinate as an array of 3 floats
- * @see getWorldCoordsAtScreen()
- */
- public static void unProject(float x, float y, float z, float[] resultf)
- {
- GLU.gluUnProject( x, y, z, getModelviewMatrix(), getProjectionMatrix(), getViewport(), tmpResult);
- resultf[0] = tmpResult.get(0);
- resultf[1] = tmpResult.get(1);
- resultf[2] = tmpResult.get(2);
- }
- /**
- * For given screen xy, return the world xyz coords in a float array. Assume
- * Z position is 0.
- */
- public static float[] getWorldCoordsAtScreen(int x, int y) {
- float z = getZDepthAtOrigin();
- float[] resultf = new float[3];
- unProject( (float)x, (float)y, (float)z, resultf);
- return resultf;
- }
- /**
- * For given screen xy and z depth, return the world xyz coords in a float array.
- */
- public static float[] getWorldCoordsAtScreen(int x, int y, float z) {
- float[] resultf = new float[3];
- unProject( (float)x, (float)y, (float)z, resultf);
- return resultf;
- }
- //========================================================================
- // Texture functions
- //========================================================================
- /**
- * Allocate a texture (glGenTextures) and return the handle to it.
- */
- public static int allocateTexture()
- {
- IntBuffer textureHandle = allocInts(1);
- GL11.glGenTextures(textureHandle);
- return textureHandle.get(0);
- }
- /**
- * "Select" the given texture for further texture operations.
- */
- public static void activateTexture(int textureHandle)
- {
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- }
- /**
- * Create a texture and mipmap from the given image file.
- */
- public static int makeTexture(String textureImagePath)
- {
- int textureHandle = 0;
- GLImage textureImg = loadImage(textureImagePath);
- if (textureImg != null) {
- textureHandle = makeTexture(textureImg);
- makeTextureMipMap(textureHandle,textureImg);
- }
- return textureHandle;
- }
- /**
- * Create a texture and optional mipmap with the given parameters.
- *
- * @param mipmap: if true, create mipmaps for the texture
- * @param anisotropic: if true, enable anisotropic filtering
- */
- public static int makeTexture(String textureImagePath, boolean mipmap, boolean anisotropic)
- {
- int textureHandle = 0;
- GLImage textureImg = loadImage(textureImagePath);
- if (textureImg != null) {
- textureHandle = makeTexture(textureImg.pixelBuffer, textureImg.w, textureImg.h, anisotropic);
- if (mipmap) {
- makeTextureMipMap(textureHandle,textureImg);
- }
- }
- return textureHandle;
- }
- /**
- * Create a texture from the given image.
- */
- public static int makeTexture(GLImage textureImg)
- {
- if ( textureImg != null ) {
- if (isPowerOf2(textureImg.w) && isPowerOf2(textureImg.h)) {
- return makeTexture(textureImg.pixelBuffer, textureImg.w, textureImg.h, false);
- }
- else {
- msg("GLApp.makeTexture(GLImage) Warning: not a power of two: " + textureImg.w + "," + textureImg.h);
- textureImg.convertToPowerOf2();
- return makeTexture(textureImg.pixelBuffer, textureImg.w, textureImg.h, false);
- }
- }
- return 0;
- }
- /**
- * De-allocate the given texture (glDeleteTextures()).
- */
- public static void deleteTexture(int textureHandle)
- {
- IntBuffer bufferTxtr = allocInts(1).put(textureHandle);;
- GL11.glDeleteTextures(bufferTxtr);
- }
- /**
- * Returns true if n is a power of 2. If n is 0 return zero.
- */
- public static boolean isPowerOf2(int n) {
- if (n == 0) { return false; }
- return (n & (n - 1)) == 0;
- }
- /**
- * Create a blank square texture with the given size.
- * @return the texture handle
- */
- public static int makeTexture(int w)
- {
- ByteBuffer pixels = allocBytes(w*w*SIZE_INT); // allocate 4 bytes per pixel
- return makeTexture(pixels, w, w, false);
- }
- /**
- * Create a texture from the given pixels in the default Java ARGB int format.<BR>
- * Configure the texture to repeat in both directions and use LINEAR for magnification.
- * <P>
- * @return the texture handle
- */
- public static int makeTexture(int[] pixelsARGB, int w, int h, boolean anisotropic)
- {
- if (pixelsARGB != null) {
- ByteBuffer pixelsRGBA = GLImage.convertImagePixelsRGBA(pixelsARGB,w,h,true);
- return makeTexture(pixelsRGBA, w, h, anisotropic);
- }
- return 0;
- }
- /**
- * Create a texture from the given pixels in the default OpenGL RGBA pixel format.
- * Configure the texture to repeat in both directions and use LINEAR for magnification.
- * <P>
- * @return the texture handle
- */
- public static int makeTexture(ByteBuffer pixels, int w, int h, boolean anisotropic)
- {
- // get a new empty texture
- int textureHandle = allocateTexture();
- // preserve currently bound texture, so glBindTexture() below won't affect anything)
- GL11.glPushAttrib(GL11.GL_TEXTURE_BIT);
- // 'select' the new texture by it's handle
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- // set texture parameters
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); //GL11.GL_NEAREST);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); //GL11.GL_NEAREST);
- // make texture "anisotropic" so it will minify more gracefully
- if (anisotropic && extensionExists("GL_EXT_texture_filter_anisotropic")) {
- // Due to LWJGL buffer check, you can't use smaller sized buffers (min_size = 16 for glGetFloat()).
- FloatBuffer max_a = allocFloats(16);
- // Grab the maximum anisotropic filter.
- GL11.glGetFloat(EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_a);
- // Set up the anisotropic filter.
- GL11.glTexParameterf(GL11.GL_TEXTURE_2D, EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, max_a.get(0));
- }
- // Create the texture from pixels
- GL11.glTexImage2D(GL11.GL_TEXTURE_2D,
- 0, // level of detail
- GL11.GL_RGBA8, // internal format for texture is RGB with Alpha
- w, h, // size of texture image
- 0, // no border
- GL11.GL_RGBA, // incoming pixel format: 4 bytes in RGBA order
- GL11.GL_UNSIGNED_BYTE, // incoming pixel data type: unsigned bytes
- pixels); // incoming pixels
- // restore previous texture settings
- GL11.glPopAttrib();
- return textureHandle;
- }
- /**
- * Create a texture from the given pixels in ARGB format. The pixels buffer contains
- * 4 bytes per pixel, in ARGB order. ByteBuffers are created with native hardware byte
- * orders, so the pixels can be in big-endian (ARGB) order, or little-endian (BGRA) order.
- * Set the pixel_byte_order accordingly when creating the texture.
- * <P>
- * Configure the texture to repeat in both directions and use LINEAR for magnification.
- * <P>
- * NOTE: I'm having problems creating mipmaps when image pixel data is in GL_BGRA format.
- * Looks like GLU type param doesn't recognize GL_UNSIGNED_INT_8_8_8_8 and
- * GL_UNSIGNED_INT_8_8_8_8_REV so I can't specify endian byte order. Mipmaps look
- * right on PC but colors are reversed on Mac. Have to stick with GL_RGBA
- * byte order for now.
- * <P>
- * @return the texture handle
- */
- public static int makeTextureARGB(ByteBuffer pixels, int w, int h)
- {
- // byte buffer has ARGB ints in little endian or big endian byte order
- int pixel_byte_order = (pixels.order() == ByteOrder.BIG_ENDIAN)?
- GL12.GL_UNSIGNED_INT_8_8_8_8 :
- GL12.GL_UNSIGNED_INT_8_8_8_8_REV;
- // get a new empty texture
- int textureHandle = allocateTexture();
- // 'select' the new texture by it's handle
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- // set texture parameters
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); //GL11.GL_NEAREST);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); //GL11.GL_NEAREST);
- // Create the texture from pixels
- GL11.glTexImage2D(GL11.GL_TEXTURE_2D,
- 0, // level of detail
- GL11.GL_RGBA8, // internal format for texture is RGB with Alpha
- w, h, // size of texture image
- 0, // no border
- GL12.GL_BGRA, // incoming pixel format: 4 bytes in ARGB order
- pixel_byte_order, // incoming pixel data type: little or big endian ints
- pixels); // incoming pixels
- return textureHandle;
- }
- /**
- * Build Mipmaps for currently bound texture (builds a set of textures at various
- * levels of detail so that texture will scale up and down gracefully)
- *
- * @param textureImg the texture image
- * @return error code of buildMipMap call
- */
- public static int makeTextureMipMap(int textureHandle, GLImage textureImg)
- {
- int ret = 0;
- if (textureImg != null && textureImg.isLoaded()) {
- GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureHandle);
- ret = GLU.gluBuild2DMipmaps(GL11.GL_TEXTURE_2D, GL11.GL_RGBA8,
- textureImg.w, textureImg.h,
- GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, textureImg.getPixelBytes());
- if (ret != 0) {
- err("GLApp.makeTextureMipMap(): Error occured while building mip map, ret=" + ret + " error=" + GLU.gluErrorString(ret) );
- }
- // Assign the mip map levels and texture info
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_NEAREST);
- GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
- }
- return ret;
- }
- /**
- * Create a texture large enough to hold the screen image. Use RGBA8 format
- * to insure colors are copied exactly. Use GL_NEAREST for magnification
- * to prevent slight blurring of image when screen is drawn back.
- *
- * @see frameCopy()
- * @see frameDraw()
- */
- public static int makeTextureForScreen(int screenSize)
- {
- // get a texture size big enough to hold screen (512, 1024, 2048 etc.)
- screenTextureSize = getPowerOfTwoBiggerThan(screenSize);
- msg("GLApp.makeTextureForScreen(): made texture for screen with size " + screenTextureSize);
- // get a new empty texture
- int textureHandle = allocateTexture();
- ByteBuffer pixels = allocBytes(screenTextureSize*screenTextureSize*SIZE_INT);
- // 'select' the new texture by it's handle
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- // set texture parameters
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
- // use GL_NEAREST to prevent blurring during frequent screen restores
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
- // Create the texture from pixels: use GL_RGBA8 to insure exact color copy
- GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, screenTextureSize, screenTextureSize, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
- return textureHandle;
- }
- /**
- * Find a power of two equal to or greater than the given value.
- * Ie. getPowerOfTwoBiggerThan(800) will return 1024.
- * <P>
- * @see makeTextureForScreen()
- * @param dimension
- * @return a power of two equal to or bigger than the given dimension
- */
- public static int getPowerOfTwoBiggerThan(int n) {
- if (n < 0)
- return 0;
- --n;
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- return n+1;
- }
- /**
- * Copy pixels from a ByteBuffer to a texture. The buffer pixels are integers in ARGB format
- * (this is the Java default format you get from a BufferedImage) or BGRA format (this is the
- * native order of Intel systems.
- *
- * The glTexSubImage2D() call treats the incoming pixels as integers
- * in either big-endian (ARGB) or little-endian (BGRA) formats based on the setting
- * of the bytebuffer (pixel_byte_order).
- *
- * @param bb ByteBuffer of pixels stored as ARGB or BGRA integers
- * @param w width of source image
- * @param h height of source image
- * @param textureHandle texture to copy pixels into
- */
- public static void copyPixelsToTexture(ByteBuffer bb, int w, int h, int textureHandle) {
- int pixel_byte_order = (bb.order() == ByteOrder.BIG_ENDIAN)?
- GL12.GL_UNSIGNED_INT_8_8_8_8 :
- GL12.GL_UNSIGNED_INT_8_8_8_8_REV;
- // "select" the texture that we'll write into
- GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureHandle);
- // Copy pixels to texture
- GL11.glTexSubImage2D(
- GL11.GL_TEXTURE_2D, // always GL_TEXTURE_2D
- 0, // texture detail level: always 0
- 0, 0, // x,y offset into texture
- w, h, // dimensions of image pixel data
- GL12.GL_BGRA, // format of pixels in texture (little_endian - native for PC)
- pixel_byte_order, // format of pixels in bytebuffer (big or little endian ARGB integers)
- bb // image pixel data
- );
- }
- /**
- * Calls glTexSubImage2D() to copy pixels from an image into a texture.
- */
- public static void copyImageToTexture(GLImage img, int textureHandle) {
- copyPixelsToTexture(img.pixelBuffer, img.w, img.h, textureHandle);
- }
- //========================================================================
- // functions to set projection
- //========================================================================
- /**
- * Set OpenGL to render in 3D perspective. Set the projection matrix using
- * GLU.gluPerspective(). The projection matrix controls how the scene is
- * "projected" onto the screen. Think of it as the lens on a camera, which
- * defines how wide the field of vision is, how deep the scene is, and how
- * what the aspect ratio will be.
- */
- public static void setPerspective()
- {
- // select projection matrix (controls perspective)
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glLoadIdentity();
- GLU.gluPerspective(40f, aspectRatio, 1f, 1000f);
- // return to modelview matrix
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- }
- /**
- * Set OpenGL to render in flat 2D (no perspective) with a one-to-one
- * relation between screen pixels and world coordinates, ie. if
- * you draw a 10x10 quad at 100,100 it will appear as a 10x10 pixel
- * square on screen at pixel position 100,100.
- * <P>
- * <B>ABOUT Ortho and Viewport:</B><br>
- * Let's say we're drawing in 2D and want to have a cinema proportioned
- * viewport (16x9), and want to bound our 2D rendering into that area ie.
- * <PRE>
- ___________1024,576
- | |
- | Scene | Set the bounds on the scene geometry
- |___________| to the viewport size and shape
- 0,0
- ___________1024,576
- | |
- | Ortho | Set the projection to cover the same
- |___________| area as the scene
- 0,0
- ___________ 1024,768
- |___________|
- | |1024,672
- | Viewport | Set the viewport to the same shape
- 0,96|___________| as scene and ortho, but centered on
- |___________| screen.
- 0,0
- *</PRE>
- */
- public static void setOrtho()
- {
- // select projection matrix (controls view on screen)
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glLoadIdentity();
- // set ortho to same size as viewport, positioned at 0,0
- GL11.glOrtho(
- 0,viewportW, // left,right
- 0,viewportH, // bottom,top
- -500,500); // Zfar, Znear
- // return to modelview matrix
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- }
- public static void setOrtho(int width, int height)
- {
- // select projection matrix (controls view on screen)
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glLoadIdentity();
- // set ortho to same size as viewport, positioned at 0,0
- GL11.glOrtho(
- 0,width, // left,right
- 0,height, // bottom,top
- -500,500); // Zfar, Znear
- // return to modelview matrix
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- }
- /**
- * Set OpenGL to render in flat 2D (no perspective) on top of current scene.
- * Preserve current projection and model views, and disable depth testing.
- * Ortho world size will be same as viewport size, so any ortho drawing
- * (drawQuad(), drawImageFullscreen(), etc.) will be scaled to fit viewport.
- * <P>
- * NOTE: if the viewport is the same size as the window (by default it is),
- * then setOrtho() will make the world coordinates exactly match the screen
- * pixel positions. This is convenient for mouse interaction, but be warned:
- * if you setViewport() to something other than fullscreen, then you need
- * to use getWorldCoordsAtScreen() to convert screen xy to world xy.
- * <P>
- * Once Ortho is on, glTranslate() will take pixel coords as arguments,
- * with the lower left corner 0,0 and the upper right corner 1024,768 (or
- * whatever your screen size is). !!!
- *
- * @see setOrthoOff()
- * @see setViewport(int,int,int,int)
- */
- public static void setOrthoOn()
- {
- // prepare projection matrix to render in 2D
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glPushMatrix(); // preserve perspective view
- GL11.glLoadIdentity(); // clear the perspective matrix
- GL11.glOrtho( // turn on 2D mode
- ////viewportX,viewportX+viewportW, // left, right
- ////viewportY,viewportY+viewportH, // bottom, top !!!
- 0,viewportW, // left, right
- 0,viewportH, // bottom, top
- -500,500); // Zfar, Znear
- // clear the modelview matrix
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- GL11.glPushMatrix(); // Preserve the Modelview Matrix
- GL11.glLoadIdentity(); // clear the Modelview Matrix
- // disable depth test so further drawing will go over the current scene
- GL11.glDisable(GL11.GL_DEPTH_TEST);
- }
- /**
- * Set the width and height of the Ortho scene. By default GLApp will use
- * viewportWidth and viewportHeight for the width and height of ortho mode.
- * You can override this behavior by setting a specific size with setOrthoDimensions().
- * <P>
- * By default ortho mode (setOrtho(), setOrthoOn()) will set the world width
- * and height to exactly match the screen pixel width and height (it uses
- * the viewport size, which is typically the exact same size as the opengl window).
- * This makes it easy to map screen positions to the world space. Text positions,
- * images and mouse coordinates map pixel-for-pixel to the screen.
- * <P>
- * The drawback is that the ortho world space will change size on different
- * resolution screens. In low-res screens the ortho world may be 800x600 while
- * in a hi-res screen it could be 1920x1200, which means that anything drawn
- * in ortho mode may shift on different screens.
- * <P>
- * setOrthoDimensions() assigns a fixed size for ortho scenes, independent of
- * the viewport size. OpenGL will project the ortho world into the
- * viewport just as it does with a perspective projection. Things drawn in
- * ortho will stay in the right place on any resolution screen.
- * <P>
- * The drawback with this method is that screen coordinates don't necessarily
- * map exactly to the ortho world. To translate a screen xy to the ortho
- * world coordinates, use getWorldCoordsAtScreen(x,y) just as with perspective
- * worlds.
- *
- * @param width width of ortho scene
- * @param height height of ortho scene
- *
- * @see setOrtho()
- * @see setOrthoOn()
- * @see setPerspective()
- *//*
- public static void setOrthoDimensions(int width, int height)
- {
- orthoWidth = width;
- orthoHeight = height;
- }
- */
- /**
- * Turn 2D mode off. Return the projection and model views to their
- * preserved state that was saved when setOrthoOn() was called, and
- * re-enable depth testing.
- *
- * @see setOrthoOn()
- */
- public static void setOrthoOff()
- {
- // restore the original positions and views
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glPopMatrix();
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- GL11.glPopMatrix();
- // turn Depth Testing back on
- GL11.glEnable(GL11.GL_DEPTH_TEST);
- }
- /**
- * Define the position and size of the screen area in which the
- * OpenGL context will draw. Position and size of the area are given
- * in exact pixel sizes. By default the viewport is the same size as
- * the window (displayWidth,displayHeight).
- * <P>
- * NOTE: by default the window size, viewport size and setOrtho() size are all
- * the same, so in ortho mode screen pixel positions exactly match to world
- * coordinates. THIS IS NO LONGER TRUE if you setViewport() to some other
- * size. With a custom viewport you need to use getWorldCoordsAtScreen()
- * to convert screen xy to world xy.
- * <P>
- * @param x position of the lower left of viewport area, in pixels
- * @param y
- * @param width size of the viewport area, in pixels
- * @param height
- *
- * @see setPerspective()
- * @see setOrtho()
- * @see setOrthoDimensions(int,int)
- */
- public static void setViewport(int x, int y, int width, int height)
- {
- viewportX = x;
- viewportY = y;
- viewportW = width;
- viewportH = height;
- aspectRatio = (float)width / (float)height;
- GL11.glViewport(x,y,width,height);
- }
- /**
- * Reset the viewport to full screen (displayWidth x displayHeight).
- *
- * @see setViewport(int,int,int,int)
- */
- public static void resetViewport()
- {
- setViewport(0,0,displayWidth,displayHeight);
- }
- /**
- * A simple way to set eye position. Calls gluLookat() to place
- * the viewpoint <distance> units up the Z axis from the given target position,
- * looking at the target position. The camera is oriented vertically (Y axis is up).
- * away.
- */
- public static void lookAt(float lookatX, float lookatY, float lookatZ, float distance)
- {
- // set viewpoint
- GLU.gluLookAt(
- lookatX,lookatY,lookatZ+distance, // eye is at the same XY as the target, <distance> units up the Z axis
- lookatX,lookatY,lookatZ, // look at the target position
- 0,1,0); // the Y axis is up
- }
- //========================================================================
- // Functions to push/pop OpenGL settings
- //========================================================================
- /**
- * preserve all OpenGL settings that can be preserved. Use this
- * function to isolate settings changes. Call pushAttrib() before
- * calling glEnable(), glDisable(), glMatrixMode() etc. After
- * your code executes, call popAttrib() to return to the
- * previous settings.
- *
- * For better performance, call pushAttrib() with specific settings
- * flags to preserve only specific settings.
- *
- * @see popAttrib()
- */
- public static void pushAttrib()
- {
- GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
- }
- /**
- * preserve the specified OpenGL setting. Call popAttrib() to return to
- * the preserved state.
- *
- * @see popAttrib()
- */
- public static void pushAttrib(int attribute_bits)
- {
- GL11.glPushAttrib(attribute_bits);
- }
- /**
- * preserve the OpenGL settings that will be affected when we draw in ortho
- * mode over the scene. For example if we're drawing an interface layer,
- * buttons, popup menus, cursor, text, etc. we need to turn off lighting,
- * turn on blending, set color to white and turn off depth test.
- * <P>
- * call pushAttribOverlay(), enable settings that you need, when done call popAttrib()
- *
- * @see popAttrib()
- */
- public static void pushAttribOrtho()
- {
- GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_TEXTURE_BIT | GL11.GL_LIGHTING_BIT | GL11.GL_DEPTH_BUFFER_BIT);
- }
- /**
- * preserve the OpenGL viewport settings.
- * <pre>
- * pushAttribViewport();
- * setViewport(0,0,displaymode.getWidth(),displaymode.getHeight());
- * ... do some drawing outside of previous viewport area
- * popAttrib();
- * </pre>
- *
- * @see popAttrib()
- */
- public static void pushAttribViewport()
- {
- GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT);
- }
- /**
- * return to the OpenGL settings that were preserved by the previous pushAttrib() call.
- *
- * @see pushAttrib()
- */
- public static void popAttrib()
- {
- GL11.glPopAttrib();
- }
- //========================================================================
- // Lighting functions
- //========================================================================
- /**
- * Set the color of a 'positional' light (a light that has a specific
- * position within the scene). <BR>
- *
- * Pass in an OpenGL light number (GL11.GL_LIGHT1),
- * the 'Diffuse' and 'Ambient' colors (direct light and reflected light),
- * and the position.<BR>
- *
- * @param GLLightHandle
- * @param diffuseLightColor
- * @param ambientLightColor
- * @param position
- */
- public static void setLight( int GLLightHandle,
- float[] diffuseLightColor, float[] ambientLightColor, float[] specularLightColor, float[] position )
- {
- FloatBuffer ltDiffuse = allocFloats(diffuseLightColor);
- FloatBuffer ltAmbient = allocFloats(ambientLightColor);
- FloatBuffer ltSpecular = allocFloats(specularLightColor);
- FloatBuffer ltPosition = allocFloats(position);
- GL11.glLight(GLLightHandle, GL11.GL_DIFFUSE, ltDiffuse); // color of the direct illumination
- GL11.glLight(GLLightHandle, GL11.GL_SPECULAR, ltSpecular); // color of the highlight
- GL11.glLight(GLLightHandle, GL11.GL_AMBIENT, ltAmbient); // color of the reflected light
- GL11.glLight(GLLightHandle, GL11.GL_POSITION, ltPosition);
- GL11.glEnable(GLLightHandle); // Enable the light (GL_LIGHT1 - 7)
- //GL11.glLightf(GLLightHandle, GL11.GL_QUADRATIC_ATTENUATION, .005F); // how light beam drops off
- }
- public static void setSpotLight( int GLLightHandle,
- float[] diffuseLightColor, float[] ambientLightColor,
- float[] position, float[] direction, float cutoffAngle )
- {
- FloatBuffer ltDirection = allocFloats(direction);
- setLight(GLLightHandle, diffuseLightColor, ambientLightColor, diffuseLightColor, position);
- GL11.glLightf(GLLightHandle, GL11.GL_SPOT_CUTOFF, cutoffAngle); // width of the beam
- GL11.glLight(GLLightHandle, GL11.GL_SPOT_DIRECTION, ltDirection); // which way it points
- GL11.glLightf(GLLightHandle, GL11.GL_CONSTANT_ATTENUATION, 2F); // how light beam drops off
- //GL11.glLightf(GLLightHandle, GL11.GL_LINEAR_ATTENUATION, .5F); // how light beam drops off
- //GL11.glLightf(GLLightHandle, GL11.GL_QUADRATIC_ATTENUATION, .5F); // how light beam drops off
- }
- /**
- * Set the color of the Global Ambient Light. Affects all objects in
- * scene regardless of their placement.
- */
- public static void setAmbientLight(float[] ambientLightColor)
- {
- put(tmpFloats,ambientLightColor);
- GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, tmpFloats);
- }
- /**
- * Set the position of a light to the given xyz. NOTE: Positional light only,
- * not directional.
- */
- public static void setLightPosition(int GLLightHandle, float x, float y, float z)
- {
- put(tmpFloats, new float[] {x,y,z,1});
- GL11.glLight(GLLightHandle, GL11.GL_POSITION, tmpFloats);
- }
- /**
- * Set the position (or direction) of a light to the given xyz.
- */
- public static void setLightPosition(int GLLightHandle, float[] position)
- {
- put(tmpFloats,position);
- GL11.glLight(GLLightHandle, GL11.GL_POSITION, tmpFloats);
- }
- /**
- * enable/disable the given light. The light handle parameter is one of
- * the predefined OpenGL light handle numbers (GL_LIGHT1, GL_LIGHT2 ... GL_LIGHT7).
- */
- public static void setLight(int GLLightHandle, boolean on)
- {
- if (on) {
- GL11.glEnable(GLLightHandle);
- }
- else {
- GL11.glDisable(GLLightHandle);
- }
- }
- /**
- * Enable/disable lighting. If parameter value is false, this will turn off all
- * lights and ambient lighting.
- *
- * NOTE: When lighting is disabled, material colors are disabled as well. Use
- * glColor() to set color properties when ligthing is off.
- */
- public static void setLighting(boolean on) {
- if (on) {
- GL11.glEnable(GL11.GL_LIGHTING);
- }
- else {
- GL11.glDisable(GL11.GL_LIGHTING);
- }
- }
- //========================================================================
- // Material functions
- //========================================================================
- public static final float[] colorClear = { 0f, 0f, 0f, 0f}; // alpha is 0
- public static final float[] colorBlack = { 0f, 0f, 0f, 1f};
- public static final float[] colorWhite = { 1f, 1f, 1f, 1f};
- public static final float[] colorGray = { .5f, .5f, .5f, 1f};
- public static final float[] colorRed = { 1f, 0f, 0f, 1f};
- public static final float[] colorGreen = { 0f, 1f, 0f, 1f};
- public static final float[] colorBlue = { 0f, 0f, 1f, 1f};
- /**
- * A simple way to set the current material properties to approximate a
- * "real" surface. Provide the surface color (float[4]]) and shininess
- * value (range 0-1).
- * <P>
- * Sets diffuse material color to the surfaceColor and ambient material color
- * to surfaceColor/2. Based on the shiny value (0-1), sets the specular
- * property to a color between black (0) and white (1), and sets the
- * shininess property to a value between 0 and 127.
- * <P>
- * Lighting must be enabled for material colors to take effect.
- * <P>
- * @param surfaceColor - must be float[4] {R,G,B,A}
- * @param reflection - a float from 0-1 (0=very matte, 1=very shiny)
- */
- public static void setMaterial(float[] surfaceColor, float shiny) {
- float[] reflect = {shiny,shiny,shiny,1}; // make a shade of gray
- float[] ambient = {surfaceColor[0]*.5f,surfaceColor[1]*.5f,surfaceColor[2]*.5f,1}; // darker surface color
- mtldiffuse.put(surfaceColor).flip(); // surface directly lit
- mtlambient.put(ambient).flip(); // surface in shadow
- mtlspecular.put(reflect).flip(); // reflected light
- mtlemissive.put(colorBlack).flip(); // no emissive light
- // size of reflection
- int openglShininess = ((int)(shiny*127f)); // convert 0-1 to 0-127
- if (openglShininess >= 0 && openglShininess <= 127) {
- mtlshininess.put(new float[] {openglShininess,0,0,0}).flip();
- }
- applyMaterial();
- }
- /**
- * Set the four material colors and calls glMaterial() to change the current
- * material color in OpenGL. Lighting must be enabled for material colors to take effect.
- *
- * @param shininess: size of reflection (0 is matte, 127 is pinpoint reflection)
- */
- public static void setMaterial(float[] diffuseColor, float[] ambientColor, float[] specularColor, float[] emissiveColor, float shininess) {
- mtldiffuse.put(diffuseColor).flip(); // surface directly lit
- mtlambient.put(ambientColor).flip(); // surface in shadow
- mtlspecular.put(specularColor).flip(); // reflection color
- mtlemissive.put(emissiveColor).flip(); // glow color
- if (shininess >= 0 && shininess <= 127) {
- mtlshininess.put(new float[] {shininess,0,0,0}).flip(); // size of reflection 0=broad 127=pinpoint
- }
- applyMaterial();
- }
- /**
- * Alter the material opacity by setting the diffuse material color
- * alpha value to the given value
- * @para alpha 0=transparent 1=opaque
- */
- public static void setMaterialAlpha(float alpha) {
- if (alpha < 0) alpha = 0;
- if (alpha > 1) alpha = 1;
- mtldiffuse.put(3,alpha).flip(); // alpha value of diffuse color
- applyMaterial();
- }
- /**
- * Call glMaterial() to activate these material properties in the OpenGL environment.
- * These properties will stay in effect until you change them or disable lighting.
- */
- public static void applyMaterial() {
- GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE, mtldiffuse);
- GL11.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, mtlambient);
- GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, mtlspecular);
- GL11.glMaterial(GL11.GL_FRONT, GL11.GL_EMISSION, mtlemissive);
- GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SHININESS, mtlshininess);
- }
- //========================================================================
- // Fog
- //========================================================================
- /**
- * Enable atmospheric fog effect, with the given color and density.
- * <PRE>
- * setFog(new float[] {.5f,.5f,.5f,1f}, .3f);
- * </PRE>
- *
- * @param fogColor float[4] specifies the RGB fog color value
- * @param fogDensity float in range 0-1 specifies how opaque the fog will be
- */
- public static void setFog(float[] fogColor, float fogdensity) {
- put(tmpFloats,fogColor);
- // turn fog on
- GL11.glEnable(GL11.GL_FOG);
- // mode: GL_EXP2 is dense fog, GL_EXP is thinner, GL_LINEAR is very thin
- GL11.glFogi(GL11.GL_FOG_MODE, GL11.GL_EXP2);
- // start and end (only apply when fog mode=GL_LINEAR
- //GL11.glFogf(GL11.GL_FOG_START, 100f);
- //GL11.glFogf(GL11.GL_FOG_END, 1000f);
- // color
- GL11.glFog(GL11.GL_FOG_COLOR, tmpFloats);
- // density
- GL11.glFogf(GL11.GL_FOG_DENSITY, fogdensity);
- // quality
- GL11.glHint(GL11.GL_FOG_HINT, GL11.GL_NICEST);
- }
- /**
- * Enable/disable fog effect. Does not change the fog settings.
- */
- public static void setFog(boolean on) {
- if (on) {
- GL11.glEnable(GL11.GL_FOG);
- }
- else {
- GL11.glDisable(GL11.GL_FOG);
- }
- }
- //========================================================================
- // Time functions
- //========================================================================
- public static double getTimeInSeconds()
- {
- if (ticksPerSecond == 0) {
- ticksPerSecond = Sys.getTimerResolution();
- }
- return (((double)Sys.getTime())/(double)ticksPerSecond);
- }
- public static double getTimeInMillis()
- {
- if (ticksPerSecond == 0) {
- ticksPerSecond = Sys.getTimerResolution();
- }
- return (double) ((((double)Sys.getTime())/(double)ticksPerSecond) * 1000.0);
- }
- /**
- * Calculate time since we last called updateTimer(). Updates secondsSinceLastFrame and
- * sets lastFrameTime to the current Sys.getTime().
- * <P>
- * Called by run() at the beginning of each loop.
- *
- * @see run()
- * @see getSecondsPerFrame()
- */
- public static void updateTimer()
- {
- // number of frames to average (about one second)
- double numToAvg = 50;
- // calc time elapsed since we last rendered
- secondsSinceLastFrame = (double)(Sys.getTime() - lastFrameTime) / (double)ticksPerSecond;
- lastFrameTime = Sys.getTime();
- // keep a moving average of frame elapsed times
- if (secondsSinceLastFrame < 1) {
- avgSecsPerFrame = (double) ((avgSecsPerFrame*numToAvg)+secondsSinceLastFrame) / (numToAvg+1D);
- }
- }
- /**
- * Return the moving average of the seconds per frame for the last 50 frames.
- * Useful when animating in real time. Will provide smoother time deltas
- * than the secondsSinceLastFrame variable, which holds the exact time elapsed
- * during the last frame (but may jump or lag as processor load varies).
- *
- * @see updateTimer()
- */
- public static double getSecondsPerFrame() {
- return avgSecsPerFrame;
- }
- /**
- * Return the moving average of the frames per second for the last 50 frames.
- *
- * @see updateTimer()
- */
- public static double getFramesPerSecond() {
- return 1d/avgSecsPerFrame;
- }
- //========================================================================
- // Load images
- //========================================================================
- /**
- * Make a blank image of the given size.
- * @return the new GLImage
- */
- public static GLImage makeImage(int w, int h) {
- ByteBuffer pixels = allocBytes(w*h*SIZE_INT);
- return new GLImage(pixels,w,h);
- }
- /**
- * Load an image from the given file and return a GLImage object.
- * @param image filename
- * @return the loaded GLImage
- */
- public static GLImage loadImage(String imgFilename) {
- GLImage img = new GLImage(imgFilename);
- if (img.isLoaded()) {
- return img;
- }
- return null;
- }
- /**
- * Load an image from the given file and return a ByteBuffer containing ARGB pixels.<BR>
- * Can be used to create textures. <BR>
- * @param imgFilename
- * @return
- */
- public static ByteBuffer loadImagePixels(String imgFilename) {
- GLImage img = new GLImage(imgFilename);
- return img.pixelBuffer;
- }
- /**
- * Draw a cursor image textured onto a quad at cursorX,cursorY. The cursor
- * image must be loaded into a 32x32 texture. This function can be called
- * after scene is drawn to place a cursor on top of scene.
- * <P>
- * NOTE: the cursor is drawn in screen space, at an absolute screen pixel location
- * without regard for viewport (temporarily zets viewport to entire screen).
- * <P>
- * See handleEvents() for cursorX cursorY and mouse motion handling.
- * <P>
- * Example:
- * <PRE>
- * int cursorTxtr;
- *
- * public void setup() {
- * cursorTxtr = makeTexture("images/cursorCrosshair32.gif"); // image must be 32x32
- * }
- *
- * public void draw() {
- * // render scene
- * ...
- * drawCursor(cursorTxtr);
- * }
- * </PRE>
- *
- * @param cursorTextureHandle handle to texture containing 32x32 cursor image
- */
- public static void drawCursor(int cursorTextureHandle) {
- // set projection matrix to 2D fullscreen
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glPushMatrix(); // preserve perspective view
- GL11.glLoadIdentity(); // clear the perspective matrix
- GL11.glOrtho( // set ortho to exactly match screen size
- 0,displayWidth, // left, right
- 0,displayHeight, // bottom, top
- -1,1); // Zfar, Znear
- // clear the modelview matrix
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- GL11.glPushMatrix(); // preserve current modelview matrix
- GL11.glLoadIdentity(); // clear the modelview matrix
- // preserve current settings then draw cursor
- GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_TEXTURE_BIT | GL11.GL_LIGHTING_BIT | GL11.GL_VIEWPORT_BIT);
- {
- // set viewport to full screen
- GL11.glViewport(0,0,displayWidth,displayHeight);
- // tweak settings
- GL11.glEnable(GL11.GL_TEXTURE_2D); // be sure textures are on
- GL11.glColor4f(1,1,1,1); // no color
- GL11.glDisable(GL11.GL_LIGHTING); // no lighting
- GL11.glDisable(GL11.GL_DEPTH_TEST); // no depth test
- GL11.glEnable(GL11.GL_BLEND); // enable transparency
- GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- // draw 32x32 cursor image
- drawQuadZ(cursorTextureHandle, cursorX-15, cursorY-15, 0, 32, 32);
- }
- GL11.glPopAttrib();
- // restore the previous matrix settings
- GL11.glMatrixMode(GL11.GL_PROJECTION);
- GL11.glPopMatrix();
- GL11.glMatrixMode(GL11.GL_MODELVIEW);
- GL11.glPopMatrix();
- }
- /**
- * OLD function: this drew the cursor only into the current viewport, and
- * could not handle difffent ortho coordinate systems (ortho had to be
- * exactly mapped to screen size).
- *
- * Draw a cursor image textured onto a quad at cursor position. The cursor
- * image must be loaded into a texture, then this function can be called
- * after scene is drawn. Uses glPushAttrib() to preserve the current
- * drawing state. glPushAttrib() may slow performance down, so in your
- * app you may want to set the states yourself before calling drawCursor()
- * and take the push/pop out of here.
- * <P>
- * See handleEvents() for cursorX cursorY and mouse motion handling.
- * <P>
- * Example:
- * <PRE>
- * int cursorTxtr;
- *
- * public void setup() {
- * cursorTxtr = makeTexture("images/cursorCrosshair32.gif"); // image must be 32x32
- * }
- *
- * public void draw() {
- * // render scene
- * ...
- * drawCursor(cursorTxtr);
- * }
- * </PRE>
- *
- * @param cursorTextureHandle handle to texture containing 32x32 cursor image
- */
- public static void drawCursorOLD(int cursorTextureHandle) {
- setOrthoOn();
- GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_TEXTURE_BIT | GL11.GL_LIGHTING_BIT);
- {
- // tweak settings
- GL11.glEnable(GL11.GL_TEXTURE_2D); // be sure textures are on
- GL11.glColor4f(1,1,1,1); // no color
- GL11.glDisable(GL11.GL_LIGHTING); // no lighting
- GL11.glDisable(GL11.GL_DEPTH_TEST); // no depth test
- GL11.glEnable(GL11.GL_BLEND); // enable transparency
- GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- drawQuad(cursorTextureHandle, cursorX-15, cursorY-15, 32, 32); // assumes 32x32 pixels
- }
- GL11.glPopAttrib();
- setOrthoOff();
- }
- /**
- * Draw an image in ortho mode (2D) over the entire viewport area.
- * Converts the image to a texture and maps onto a viewport-sized quad.
- * Depth test is turned off, lighting is off, color is set to white.
- * Alpha blending is on, so transparent areas will be respected.
- * <P>
- * NOTE: By default the viewport is the same size as the window so this function
- * will draw the image over the entire window. If you setViewport() to a
- * custom size the image will be drawn into the custom viewport area. To
- * insure that the image is drawn truly full screen, call resetViewport()
- * before drawImageFullScreen().
- * <P>
- * @see loadImage(String)
- * @see setViewport(int,int,int,int)
- * @see resetViewport()
- */
- public static void drawImageFullScreen(GLImage img) {
- if (img == null || img.isLoaded() == false) {
- return;
- }
- // if image has no texture, convert the image to a texture
- if (img.textureHandle <= 0) {
- img.textureHandle = makeTexture(img);
- }
- // Calculate the UV dimensions of the image in the texture
- float maxU = (float)img.w / (float)img.textureW;
- float maxV = (float)img.h / (float)img.textureH;
- // preserve settings
- pushAttribOrtho();
- // switch to 2D projection
- setOrthoOn();
- // tweak settings
- GL11.glEnable(GL11.GL_TEXTURE_2D); // be sure textures are on
- GL11.glColor4f(1,1,1,1); // no color
- GL11.glDisable(GL11.GL_LIGHTING); // no lighting
- GL11.glDisable(GL11.GL_DEPTH_TEST); // no depth test
- GL11.glEnable(GL11.GL_BLEND); // enable transparency
- GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- // activate the image texture
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,img.textureHandle);
- // draw a textured quad
- GL11.glBegin(GL11.GL_QUADS);
- {
- GL11.glTexCoord2f(0, 0);
- GL11.glVertex3f(0f, 0f, 0f); // Bottom Left
- GL11.glTexCoord2f(maxU, 0);
- GL11.glVertex3f(getWidth(), 0f, 0f); // Bottom Right
- GL11.glTexCoord2f(maxU, maxV);
- GL11.glVertex3f(getWidth(), getHeight(), 0f); // Top Right
- GL11.glTexCoord2f(0, maxV);
- GL11.glVertex3f(0f, getHeight(), 0f); // Top left
- }
- GL11.glEnd();
- // return to previous projection mode
- setOrthoOff();
- // return to previous settings
- popAttrib();
- }
- /**
- * Draw an image in whichever projection mode is current (does not switch to ortho mode).
- * Convert the image to a texture and draw onto quad. Will draw with current settings
- * (light, material, depth, blend, etc.)
- * <BR>
- * @see loadImage()
- * @see drawQuad()
- * @see drawImageFullScreen()
- */
- public static void drawImage(GLImage img, int x, int y, float w, float h) {
- // if image has no texture, convert the image to a texture
- if (img.textureHandle <= 0) {
- img.textureHandle = makeTexture(img);
- }
- // preserve settings
- pushAttribOrtho();
- // set color to white
- //GL11.glColor4f(1,1,1,1); // don't force color to white (may want to tint image)
- // activate the image texture
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,img.textureHandle);
- // draw a textured quad
- GL11.glNormal3f(0.0f, 0.0f, 1.0f); // normal faces positive Z
- GL11.glBegin(GL11.GL_QUADS);
- {
- GL11.glTexCoord2f(0f, 0f);
- GL11.glVertex3f( (float)x, (float)y, (float)0);
- GL11.glTexCoord2f(1f, 0f);
- GL11.glVertex3f( (float)x+w, (float)y, (float)0);
- GL11.glTexCoord2f(1f, 1f);
- GL11.glVertex3f( (float)x+w, (float)y+h, (float)0);
- GL11.glTexCoord2f(0f, 1f);
- GL11.glVertex3f( (float)x, (float)y+h, (float)0);
- }
- GL11.glEnd();
- // return to previous settings
- popAttrib();
- }
- /**
- * Draw a textured quad in Ortho mode (2D) at the given xy, scaled to
- * the given width and height. Depth test is turned off so quad will
- * be drawn on top of the current scene. Quad will be drawn
- * with current light and material if any are active.
- * <BR>
- * @ee loadImage()
- */
- public static void drawQuad(int textureHandle, int x, int y, float w, float h) {
- // activate the specified texture
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- // prepare to render in 2D
- setOrthoOn();
- // draw the textured quad
- GL11.glNormal3f(0.0f, 0.0f, 1.0f); // normal faces positive Z
- GL11.glBegin(GL11.GL_QUADS);
- {
- GL11.glTexCoord2f(0f, 0f);
- GL11.glVertex3f( (float)x, (float)y, (float)0);
- GL11.glTexCoord2f(1f, 0f);
- GL11.glVertex3f( (float)x+w, (float)y, (float)0);
- GL11.glTexCoord2f(1f, 1f);
- GL11.glVertex3f( (float)x+w, (float)y+h, (float)0);
- GL11.glTexCoord2f(0f, 1f);
- GL11.glVertex3f( (float)x, (float)y+h, (float)0);
- }
- GL11.glEnd();
- // restore the previous perspective and model views
- setOrthoOff();
- }
- /**
- * Draw a textured quad at the given xyz position in 3D space. Quad will be drawn
- * with current settings (ie. light, material, depth test, projection, etc.)
- */
- public static void drawQuadZ(int textureHandle, float x, float y, float z, float w, float h) {
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- // draw textured quad
- GL11.glNormal3f(0.0f, 0.0f, 1.0f); // normal faces positive Z
- GL11.glBegin(GL11.GL_QUADS);
- {
- GL11.glTexCoord2f(0f, 0f);
- GL11.glVertex3f( x, y, z);
- GL11.glTexCoord2f(1f, 0f);
- GL11.glVertex3f( x+w, y, z);
- GL11.glTexCoord2f(1f, 1f);
- GL11.glVertex3f( x+w, y+h, z);
- GL11.glTexCoord2f(0f, 1f);
- GL11.glVertex3f( x, y+h, z);
- }
- GL11.glEnd();
- }
- //========================================================================
- // Functions to get and set framebuffer pixels
- //========================================================================
- /**
- * Return a ByteBuffer containing ARGB pixels of the entire screen area.
- */
- public static ByteBuffer framePixels() {
- return framePixels(0,0,displayMode.getWidth(),displayMode.getHeight());
- }
- /**
- * Return a ByteBuffer containing ARGB pixels from the given screen area.
- */
- public static ByteBuffer framePixels(int x, int y, int w, int h) {
- // allocate 4 bytes per pixel
- ByteBuffer pixels = allocBytes(w*h*4);
- // Get pixels from frame buffer in ARGB format.
- GL11.glReadPixels(x,y,w,h, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
- return pixels;
- }
- /**
- * Return an int array containing ARGB pixels from the given screen area.
- */
- public static int[] framePixelsInt(int x, int y, int w, int h) {
- int[] pixels = new int[w * h];
- ByteBuffer pixelsBB = framePixels(x, y, w, h);
- get(pixelsBB,pixels);
- return pixels;
- }
- /**
- * Return the color buffer RGB value at the given screen position as byte[3].
- *
- * @param x screen position
- * @param y
- * @return rgb byte array
- */
- public static byte[] getPixelColor(int x, int y)
- {
- // color value will be stored in an integer
- tmpInt.clear();
- // read the framebuffer color value at the given position, as bytes
- GL11.glReadPixels(x, y, 1, 1, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, tmpInt);
- byte[] rgb = new byte[] {tmpInt.get(0), tmpInt.get(1), tmpInt.get(2)};
- return rgb;
- }
- /**
- * Return the depth buffer value at the given screen position.
- *
- * @param x screen position
- * @param y
- * @return float Z depth value
- */
- public static float getPixelDepth(int x, int y)
- {
- return getZDepth(x,y);
- }
- /**
- * Return the stencil buffer value at the given screen position. Stencil values are
- * typically bytes (0-255). The value will be returned as an integer.
- *
- * @param x screen position
- * @param y
- * @return int stencil value
- */
- public static int getPixelStencil(int x, int y)
- {
- return getMaskValue(x,y);
- }
- /**
- * Save entire screen image to a texture. Will copy entire screen even
- * if a viewport is in use. Texture param must be large enough to hold
- * screen image (see makeTextureForScreen()).
- *
- * @param txtrHandle texture where screen image will be stored
- * @see frameDraw()
- * @see makeTextureForScreen()
- */
- public static void frameCopy(int txtrHandle)
- {
- frameCopy(txtrHandle, 0,0, DM.getWidth(),DM.getHeight()); // entire screen
- }
- /**
- * Save a region of the screen to a texture. Texture must be large enough to hold
- * screen image.
- *
- * @param txtrHandle texture where screen region will be stored
- * @see frameDraw()
- * @see makeTextureForScreen()
- */
- public static void frameCopy(int txtrHandle, int x, int y, int w, int h)
- {
- GL11.glColor4f(1,1,1,1); // turn off alpha and color tints
- GL11.glReadBuffer(GL11.GL_BACK);
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,txtrHandle);
- // Copy screen to texture
- GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0,0, x,y,w,h);
- }
- /**
- * Draw the screen-sized image over entire screen area. The screen image
- * is stored in the given texture at 0,0 (see frameCopy()) and has the
- * same dimensions as the current display mode (DM.getWidth(), DM.getHeight()).
- * <P>
- * Reset the viewport and ortho mode to full screen (viewport may be
- * different proportion than screen if custom aspectRatio is set). Draw the
- * quad the same size as texture so no stretching or compression of image.
- *
- * @param txtrHandle
- */
- public static void frameDraw(int txtrHandle)
- {
- // keep it opaque
- GL11.glDisable(GL11.GL_BLEND);
- // set viewport to full screen
- GL11.glViewport(0, 0, DM.getWidth(), DM.getHeight());
- // draw square quad that covers entire screen
- drawQuad(txtrHandle, 0, 0, screenTextureSize, screenTextureSize); // draw the full screen image
- // restore viewport to custom aspect ratio
- GL11.glViewport(viewportX, viewportY, viewportW, viewportH);
- }
- /**
- * Save the current frame buffer to a PNG image. Exactly the same as screenShot().
- * @see screenShot()
- */
- public static void frameSave() {
- screenShot();
- }
- //========================================================================
- // Functions to render shapes.
- //========================================================================
- /**
- * Draw a rectangle outline in ortho mode (draws in 2D over the scene).
- * <BR>
- * @see setLineWidth()
- * @see drawRectZ()
- */
- public static void drawRect(int x, int y, float w, float h) {
- // switch projection to 2D mode
- setOrthoOn();
- // draw rectangle at Z=0
- drawRectZ(x,y,0,w,h);
- // restore the previous perspective and model views
- setOrthoOff();
- }
- /**
- * Draw a rectangle outline in world space. Uses opengl line_strip to make
- * the rectangle.
- * <BR>
- * @see setLineWidth()
- * @see drawRect()
- */
- public static void drawRectZ(int x, int y, int z, float w, float h) {
- // preserve current settings
- GL11.glPushAttrib(GL11.GL_TEXTURE_BIT | GL11.GL_LIGHTING_BIT);
- // de-activate texture and light
- GL11.glDisable(GL11.GL_TEXTURE_2D);
- GL11.glDisable(GL11.GL_LIGHTING);
- // draw the rectangle
- GL11.glBegin(GL11.GL_LINE_STRIP);
- {
- GL11.glVertex3f( (float)x, (float)y, (float)z);
- GL11.glVertex3f( (float)x+w, (float)y, (float)z);
- GL11.glVertex3f( (float)x+w, (float)y+h, (float)z);
- GL11.glVertex3f( (float)x, (float)y+h, (float)z);
- GL11.glVertex3f( (float)x, (float)y, (float)z);
- }
- GL11.glEnd();
- // draw points at the corners
- GL11.glBegin(GL11.GL_POINTS);
- {
- GL11.glVertex3f( (float)x, (float)y, (float)z);
- GL11.glVertex3f( (float)x+w, (float)y, (float)z);
- GL11.glVertex3f( (float)x+w, (float)y+h, (float)z);
- GL11.glVertex3f( (float)x, (float)y+h, (float)z);
- }
- GL11.glEnd();
- // re-enable settings
- popAttrib();
- }
- /**
- * Draws a circle with the given radius centered at the given world position.
- */
- public static void drawCircle(int x, int y, int radius, int linewidth) {
- // switch projection to 2D mode
- setOrthoOn();
- // draw circle at x,y with z=0
- GL11.glPushMatrix();
- {
- GL11.glTranslatef(x,y,0);
- drawCircle(radius-linewidth, radius, 180);
- }
- GL11.glPopMatrix();
- // restore the previous perspective and model views
- setOrthoOff();
- }
- /**
- * Draws a circle with the given radius centered at the given world position.
- */
- public static void drawCircleZ(int x, int y, int z, int radius, int linewidth) {
- GL11.glPushMatrix();
- {
- GL11.glTranslatef(x,y,z);
- drawCircle(radius-linewidth, radius, 180);
- }
- GL11.glPopMatrix();
- }
- /**
- * Draws a circle centered at 0,0,0. Use translate() to place circle at desired coords.
- * Inner and outer radius specify width, stepsize is number of degrees for each segment.
- */
- public static void drawCircle(float innerRadius, float outerRadius, int numSegments) {
- int s = 0; // start
- int e = 360; // end
- int stepSize = 360/numSegments; // degrees per segment
- GL11.glBegin(GL11.GL_QUAD_STRIP);
- {
- // add first 2 vertices
- float ts = (float) Math.sin(Math.toRadians(s));
- float tc = (float) Math.cos(Math.toRadians(s));
- GL11.glVertex2f(tc * innerRadius, ts * innerRadius);
- GL11.glVertex2f(tc * outerRadius, ts * outerRadius);
- // add intermediate vertices, snap to {step} degrees
- while ( (s = ( (s + stepSize) / stepSize) * stepSize) < e) {
- ts = (float) Math.sin(Math.toRadians(s));
- tc = (float) Math.cos(Math.toRadians(s));
- GL11.glVertex2f(tc * innerRadius, ts * innerRadius);
- GL11.glVertex2f(tc * outerRadius, ts * outerRadius);
- }
- // add last 2 vertices at end angle
- ts = (float) Math.sin(Math.toRadians(e));
- tc = (float) Math.cos(Math.toRadians(e));
- GL11.glVertex2f(tc * innerRadius, ts * innerRadius);
- GL11.glVertex2f(tc * outerRadius, ts * outerRadius);
- }
- GL11.glEnd();
- }
- /**
- * Render a 2 unit cube centered at origin. Includes texture coordinates
- * and normals.
- */
- public static void renderCube()
- {
- GL11.glBegin(GL11.GL_QUADS);
- // Front Face
- GL11.glNormal3f( 0.0f, 0.0f, 1.0f);
- GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left
- GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right
- GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right
- GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left
- // Back Face
- GL11.glNormal3f( 0.0f, 0.0f, -1.0f);
- GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right
- GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right
- GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left
- GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Left
- // Top Face
- GL11.glNormal3f( 0.0f, 1.0f, 0.0f);
- GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left
- GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left
- GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right
- GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right
- // Bottom Face
- GL11.glNormal3f( 0.0f, -1.0f, 0.0f);
- GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Top Right
- GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 1.0f, -1.0f, -1.0f); // Top Left
- GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left
- GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right
- // Right face
- GL11.glNormal3f( 1.0f, 0.0f, 0.0f);
- GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Right
- GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right
- GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left
- GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left
- // Left Face
- GL11.glNormal3f( -1.0f, 0.0f, 0.0f);
- GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left
- GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right
- GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right
- GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left
- GL11.glEnd();
- }
- /**
- * draw a cube with the given size, centered at origin. Include texture coordinates.
- * @param size length of each side
- * @param segments # segments to divide each side into
- */
- public static void renderCube(float size, int segments) {
- float halfsize = size/2f;
- GL11.glPushMatrix();
- {
- GL11.glPushMatrix();
- {
- GL11.glTranslatef(0,0,halfsize);
- renderPlane(size,segments);// front
- }
- GL11.glPopMatrix();
- GL11.glPushMatrix();
- {
- GL11.glRotatef(90,0,1,0);
- GL11.glTranslatef(0,0,halfsize);
- renderPlane(size,segments);// right
- }
- GL11.glPopMatrix();
- GL11.glPushMatrix();
- {
- GL11.glRotatef(180,0,1,0);
- GL11.glTranslatef(0,0,halfsize);
- renderPlane(size,segments);// back
- }
- GL11.glPopMatrix();
- GL11.glPushMatrix();
- {
- GL11.glRotatef(270,0,1,0);
- GL11.glTranslatef(0,0,halfsize);
- renderPlane(size,segments);// left
- }
- GL11.glPopMatrix();
- GL11.glPushMatrix();
- {
- GL11.glRotatef(90,1,0,0);
- GL11.glTranslatef(0,0,halfsize);
- renderPlane(size,segments);// bottom
- }
- GL11.glPopMatrix();
- GL11.glPushMatrix();
- {
- GL11.glRotatef(-90,1,0,0);
- GL11.glTranslatef(0,0,halfsize);
- renderPlane(size,segments);// top
- }
- GL11.glPopMatrix();
- }
- GL11.glPopMatrix();
- }
- /**
- * draw a square plane in the X,Y axis, centered at origin. Include texture coordinates.
- * @param size length of each side
- * @param segments number of segments to divide each side into
- */
- public static void renderPlane(float size, int segments) {
- renderPlane(size,size,segments,segments);
- }
- /**
- * draw a rectangular plane in the X,Y axis, centered at origin, with the specified size and
- * number of divisions. Texture will cover entire rectangle without repeating.
- * @param length length of X axis side
- * @param height length of Y axis side
- * @param segments number of segments to divide each side into
- */
- public static void renderPlane(float length, float height, int length_segments, int height_segments) {
- renderPlane(length, height, length_segments, height_segments, 1, 1);
- }
- /**
- * draw a rectangular plane in the X,Y axis, centered at origin. Include texture coordinates.
- * Scale the UV coordinates to same proportion as plane dimensions. Texture will repeat as
- * specified by the tilefactorU and tilefactorV values. If tilefactor values are 1, the texture
- * will cover the rectangle without tiling.
- * @param length length on X axis
- * @param depth length on Y axis
- * @param segments number of segments to divide each side into
- */
- public static void renderPlane(float length, float height, int length_segments, int height_segments, float tilefactorU, float tilefactorV) {
- float xpos = - length/2f;
- float ypos = - height/2f;
- float segsizeL = length/(float)length_segments;
- float segsizeH = height/(float)height_segments;
- float maxDimension = (length > height)? length : height;
- float uvsegsizeL = (length/maxDimension) / (float)length_segments;
- float uvsegsizeH = (height/maxDimension) / (float)height_segments;
- GL11.glBegin(GL11.GL_QUADS); {
- GL11.glNormal3f(0f, 0f, 1f); // plane is facing up the Z axis
- for (int x=0; x < length_segments; x++, xpos+=segsizeL) {
- for (int y=0; y < height_segments; y++, ypos+=segsizeH) {
- // bottom left
- GL11.glTexCoord2f((x*uvsegsizeL)*tilefactorU, (y*uvsegsizeH)*tilefactorV);
- GL11.glVertex3f( xpos, ypos, 0f);
- // bottom rite
- GL11.glTexCoord2f(((x*uvsegsizeL)+uvsegsizeL)*tilefactorU, (y*uvsegsizeH)*tilefactorV);
- GL11.glVertex3f( xpos+segsizeL, ypos, 0f);
- // top rite
- GL11.glTexCoord2f(((x*uvsegsizeL)+uvsegsizeL)*tilefactorU, ((y*uvsegsizeH)+uvsegsizeH)*tilefactorV);
- GL11.glVertex3f( xpos+segsizeL, ypos+segsizeH, 0f);
- // top left
- GL11.glTexCoord2f((x*uvsegsizeL)*tilefactorU, ((y*uvsegsizeH)+uvsegsizeH)*tilefactorV);
- GL11.glVertex3f( xpos, ypos+segsizeH, 0f);
- }
- ypos = - height/2f; // reset column position
- }
- }
- GL11.glEnd();
- }
- /**
- * draw a rectangular plane in the X,Y axis, centered at origin. Include texture coordinates.
- * Scale the UV coordinates to same proportion as plane dimensions.
- * @param length length on X axis
- * @param depth length on Y axis
- * @param segments number of segments to divide each side into
- */
- public static void renderPlaneORIG(float length, float height, int length_segments, int height_segments) {
- float xpos = - length/2f;
- float ypos = - height/2f;
- float segsizeL = length/(float)length_segments;
- float segsizeH = height/(float)height_segments;
- float maxDimension = (length > height)? length : height;
- float uvsegsizeL = (length/maxDimension) / (float)length_segments;
- float uvsegsizeH = (height/maxDimension) / (float)height_segments;
- GL11.glBegin(GL11.GL_QUADS); {
- GL11.glNormal3f(0f, 0f, 1f); // plane is facing up the Z axis
- for (int x=0; x < length_segments; x++, xpos+=segsizeL) {
- for (int y=0; y < height_segments; y++, ypos+=segsizeH) {
- // bottom left
- GL11.glTexCoord2f(x*uvsegsizeL, y*uvsegsizeH);
- GL11.glVertex3f( xpos, ypos, 0f);
- // bottom rite
- GL11.glTexCoord2f((x*uvsegsizeL)+uvsegsizeL, y*uvsegsizeH);
- GL11.glVertex3f( xpos+segsizeL, ypos, 0f);
- // top rite
- GL11.glTexCoord2f((x*uvsegsizeL)+uvsegsizeL, (y*uvsegsizeH)+uvsegsizeH);
- GL11.glVertex3f( xpos+segsizeL, ypos+segsizeH, 0f);
- // top left
- GL11.glTexCoord2f(x*uvsegsizeL, (y*uvsegsizeH)+uvsegsizeH);
- GL11.glVertex3f( xpos, ypos+segsizeH, 0f);
- }
- ypos = - height/2f; // reset column position
- }
- }
- GL11.glEnd();
- }
- /**
- * call the LWJGL Sphere class to draw sphere geometry
- * with texture coordinates and normals
- * @param facets number of divisions around longitude and latitude
- */
- public static void renderSphere(int facets) {
- Sphere s = new Sphere(); // an LWJGL class
- s.setOrientation(GLU.GLU_OUTSIDE); // normals point outwards
- s.setTextureFlag(true); // generate texture coords
- GL11.glPushMatrix();
- {
- GL11.glRotatef(-90f, 1,0,0); // rotate the sphere to align the axis vertically
- s.draw(1, facets, facets); // run GL commands to draw sphere
- }
- GL11.glPopMatrix();
- }
- /**
- * draw a sphere with 48 facets (pretty smooth) with normals and texture coords
- */
- public static void renderSphere() {
- renderSphere(48);
- }
- /**
- * Sets glLineWidth() and glPointSize() to the given width. This will
- * affect geometry drawn using glBegin(GL_LINES), GL_LINE_STRIP, and GL_POINTS.
- * May only work with widths up to 10 (depends on hardware).
- */
- public static void setLineWidth(int width)
- {
- GL11.glLineWidth(width);
- GL11.glPointSize(width);
- //GL11.glEnable(GL11.GL_POINT_SMOOTH);
- //GL11.glEnable(GL11.GL_LINE_SMOOTH);
- }
- /**
- * Set the current color with RGBA floats in range 0-1. The current color
- * is disabled when lighting is enabled. When lighting is enabled (glEnable(GL_LIGHTING))
- * then material colors are in effect and the current color is ignored.
- */
- public static void setColor(float R, float G, float B, float A)
- {
- GL11.glColor4f(R,G,B,A);
- }
- /**
- * Set the current color with RGBA bytes in range 0-255. The current color
- * is disabled when lighting is enabled. When lighting is enabled (glEnable(GL_LIGHTING))
- * then material colors are in effect and the current color is ignored.
- */
- public static void setColorB(int R, int G, int B, int A)
- {
- GL11.glColor4ub((byte)R,(byte)G,(byte)B,(byte)A);
- }
- /**
- * Set the current color to the given RGB or RGBA float array. Floats are
- * in range 0-1. The current color is disabled when lighting is enabled.
- * When lighting is enabled (glEnable(GL_LIGHTING)) then
- * material colors are in effect and the current color is ignored.
- */
- public static void setColor(float[] rgba)
- {
- if (rgba != null) {
- if (rgba.length == 4) {
- GL11.glColor4f(rgba[0],rgba[1],rgba[2],rgba[3]);
- }
- else if (rgba.length == 3) {
- GL11.glColor4f(rgba[0],rgba[1],rgba[2],1);
- }
- }
- }
- /**
- * Enable/disable the color-material setting. When enabled, the glColor() command
- * will change the current material color. This provides a convenient and
- * efficient way to change material colors without having to call glMaterial().
- * When disabled, the glColor() command functions normally (has no affect on
- * material colors).
- *
- * @param on when true, glColor() will set the current material color
- */
- public static void setColorMaterial(boolean on)
- {
- if (on) {
- // glColor() will change the diffuse and ambient material colors
- GL11.glColorMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT_AND_DIFFUSE);
- GL11.glEnable(GL11.GL_COLOR_MATERIAL);
- }
- else {
- // glColor() behaves normally
- GL11.glDisable(GL11.GL_COLOR_MATERIAL);
- }
- }
- //========================================================================
- // Functions to build a character set and draw text strings.
- //
- // Example:
- // buildFont("Font_tahoma.png");
- // ...
- // glPrint(100, 100, 0, "Here's some text");
- // ...
- // destroyFont(); // cleanup
- //========================================================================
- static int fontListBase = -1; // Base Display List For The character set
- static int fontTextureHandle = -1; // Texture handle for character set image
- /**
- * Build a character set from the given texture image.
- *
- * @param charSetImage texture image containing 256 characters in a 16x16 grid
- * @param fontWidth how many pixels to allow per character on screen
- *
- * @see destroyFont()
- */
- public static boolean buildFont(String charSetImage, int fontWidth)
- {
- // make texture from image
- GLImage textureImg = loadImage(charSetImage);
- if (textureImg == null) {
- return false; // image not found
- }
- //pushAttrib();
- fontTextureHandle = makeTexture(textureImg);
- // build character set as call list of 256 textured quads
- buildFont(fontTextureHandle, fontWidth);
- //popAttrib();
- return true;
- }
- /**
- * Build the character set display list from the given texture. Creates
- * one quad for each character, with one letter textured onto each quad.
- * Assumes the texture is a 256x256 image containing every
- * character of the charset arranged in a 16x16 grid. Each character
- * is 16x16 pixels. Call destroyFont() to release the display list memory.
- *
- * Should be in ORTHO (2D) mode to render text (see setOrtho()).
- *
- * Special thanks to NeHe and Giuseppe D'Agata for the "2D Texture Font"
- * tutorial (http://nehe.gamedev.net).
- *
- * @param charSetImage texture image containing 256 characters in a 16x16 grid
- * @param fontWidth how many pixels to allow per character on screen
- *
- * @see destroyFont()
- */
- public static void buildFont(int fontTxtrHandle, int fontWidth)
- {
- float factor = 1f/16f;
- float cx, cy;
- fontListBase = GL11.glGenLists(256); // Creating 256 Display Lists
- for (int i = 0; i < 256; i++) {
- cx = (float) (i % 16) / 16f; // X Texture Coord Of Character (0 - 1.0)
- cy = (float) (i / 16) / 16f; // Y Texture Coord Of Character (0 - 1.0)
- GL11.glNewList(fontListBase + i, GL11.GL_COMPILE); // Start Building A List
- GL11.glBegin(GL11.GL_QUADS); // Use A 16x16 pixel Quad For Each Character
- GL11.glTexCoord2f(cx, 1 - cy - factor); // Texture Coord (Bottom Left)
- GL11.glVertex2i(0, 0);
- GL11.glTexCoord2f(cx + factor, 1 - cy - factor); // Texture Coord (Bottom Right)
- GL11.glVertex2i(16, 0);
- GL11.glTexCoord2f(cx + factor, 1 - cy); // Texture Coord (Top Right)
- GL11.glVertex2i(16, 16);
- GL11.glTexCoord2f(cx, 1 - cy); // Texture Coord (Top Left)
- GL11.glVertex2i(0, 16);
- GL11.glEnd(); // Done Building Our Quad (Character)
- GL11.glTranslatef(fontWidth, 0, 0); // Move To The Right Of The Character
- GL11.glEndList(); // Done Building The Display List
- } // Loop Until All 256 Are Built
- }
- /**
- * Clean up the allocated display lists for the character set.
- */
- public static void destroyFont()
- {
- if (fontListBase != -1) {
- GL11.glDeleteLists(fontListBase,256);
- fontListBase = -1;
- }
- }
- /**
- * Render a text string in 2D over the scene, using the character set created
- * by buildFont().
- *
- * @param x screen pixel position of the string
- * @param y
- * @param msg text string to draw
- */
- public static void print(int x, int y, String msg)
- {
- print(x,y,msg,0);
- }
- /**
- * Render a text string in 2D over the scene, using the character set created
- * by buildFont().
- *
- * @param x screen pixel position of the string
- * @param y
- * @param msg text string to draw
- * @param set which of the two character sets: 0 or 1
- */
- public static void print(int x, int y, String msg, int set)
- {
- // if font is not initiallized, try loading default font
- if (fontListBase == -1 || fontTextureHandle == -1) {
- if (!buildFont("images/font_tahoma.png", 12)) {
- err("GLApp.print(): character set has not been created -- see buildFont()");
- return;
- }
- }
- if (msg != null) {
- int offset = fontListBase - 32 + (128 * set);
- // preserve current GL settings
- pushAttribOrtho();
- // turn off lighting
- GL11.glDisable(GL11.GL_LIGHTING);
- // enable alpha blending, so character background is transparent
- GL11.glEnable(GL11.GL_BLEND);
- GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- // enable the charset texture
- GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureHandle);
- // prepare to render in 2D
- setOrthoOn();
- // draw the text
- GL11.glTranslatef(x, y, 0); // Position The Text (in pixel coords)
- for(int i=0; i<msg.length(); i++) {
- GL11.glCallList(offset + msg.charAt(i));
- }
- // restore the original positions and views
- setOrthoOff();
- // restore previous settings
- popAttrib();
- }
- }
- /**
- * Render a text string in model space, using the character set created
- * by buildFont().
- */
- public static void printZ(float x, float y, float z, int set, float scale, String msg)
- {
- int offset;
- if (fontListBase == -1 || fontTextureHandle == -1) {
- // font is not initiallized, try this default
- if (!buildFont("images/font_tahoma.png", 12)) {
- err("GLApp.printZ(): character set has not been created -- see buildFont()");
- return;
- }
- }
- offset = fontListBase - 32 + (128 * set);
- if (msg != null) {
- // enable the charset texture
- GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureHandle);
- // draw the text
- GL11.glPushMatrix();
- {
- GL11.glTranslatef(x, y, z); // Position The Text (in pixels coords)
- GL11.glScalef(scale,scale,scale); // make it smaller (arbitrary kludge!!!!)
- for (int i = 0; i < msg.length(); i++) {
- GL11.glCallList(offset + msg.charAt(i));
- }
- }
- GL11.glPopMatrix();
- }
- }
- //========================================================================
- // PBuffer functions
- //
- // Pbuffers are offscreen buffers that can be rendered into just like
- // the regular framebuffer. A pbuffer can be larger than the screen,
- // which allows for the creation of higher resolution images.
- //
- //========================================================================
- /**
- * Create a Pbuffer for use as an offscreen buffer, with the given
- * width and height. Use selectPbuffer() to make the pbuffer the
- * context for all subsequent opengl commands. Use selectDisplay() to
- * make the Display the context for opengl commands.
- * <P>
- * @param width
- * @param height
- * @return Pbuffer
- * @see selectPbuffer(), selectDisplay()
- */
- public static Pbuffer makePbuffer(final int width, final int height) {
- Pbuffer pbuffer = null;
- try {
- pbuffer = new Pbuffer(width, height,
- new PixelFormat(24, //bitsperpixel
- 8, //alpha
- 24, //depth
- 8, //stencil
- 0), //samples
- null,
- null);
- } catch (LWJGLException e) {
- err("GLApp.makePbuffer(): exception " + e);
- }
- return pbuffer;
- }
- /**
- * Make the pbuffer the current context for opengl commands. All following
- * gl functions will operate on this buffer instead of the display.
- * <P>
- * NOTE: the Pbuffer may be recreated if it was lost since last used. It's
- * a good idea to use:
- * <PRE>
- * pbuff = selectPbuffer(pbuff);
- * </PRE>
- * to hold onto the new Pbuffer reference if Pbuffer was recreated.
- *
- * @param pb pbuffer to make current
- * @return Pbuffer
- * @see selectDisplay(), makePbuffer()
- */
- public static Pbuffer selectPbuffer(Pbuffer pb) {
- if (pb != null) {
- try {
- // re-create the buffer if necessary
- if (pb.isBufferLost()) {
- int w = pb.getWidth();
- int h = pb.getHeight();
- msg("GLApp.selectPbuffer(): Buffer contents lost - recreating the pbuffer");
- pb.destroy();
- pb = makePbuffer(w, h);
- }
- // select the pbuffer for rendering
- pb.makeCurrent();
- }
- catch (LWJGLException e) {
- err("GLApp.selectPbuffer(): exception " + e);
- }
- }
- return pb;
- }
- /**
- * Make the Display the current context for OpenGL commands. Subsequent
- * gl functions will operate on the Display.
- *
- * @see selectPbuffer()
- */
- public static void selectDisplay()
- {
- try {
- Display.makeCurrent();
- } catch (LWJGLException e) {
- err("GLApp.selectDisplay(): exception " + e);
- }
- }
- /**
- * Copy the pbuffer contents to a texture. (Should this use glCopyTexSubImage2D()?
- * Is RGB the fastest format?)
- */
- public static void frameCopy(Pbuffer pbuff, int textureHandle) {
- GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
- GL11.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, 0, 0, pbuff.getWidth(), pbuff.getHeight(), 0);
- }
- /**
- * Save the current frame buffer to a PNG image. Same as
- * screenShot(filename) but the screenshot filename will be automatically
- * set to <applicationClassName>-<timestamp>.png
- */
- public static void screenShot() {
- screenShot(0, 0, displayMode.getWidth(), displayMode.getHeight(), rootClass.getName() + "-" + makeTimestamp() + ".png");
- }
- /**
- * Save the current frame buffer to a PNG image. Can also
- * be used with the PBuffer class to copy large images or textures that
- * have been rendered into the offscreen pbuffer.
- */
- public static void screenShot(String imageFilename) {
- screenShot(0, 0, displayMode.getWidth(), displayMode.getHeight(), imageFilename);
- }
- /**
- * Save the current Pbuffer to a PNG image. Same as screenShot(filename)
- * but the Pbuffer will be saved instead of the framebuffer, and the
- * screenshot filename will be set to <applicationClassName>-<timestamp>.png
- * NOTE: Have to call selectPbuffer() before calling this function.
- */
- public static void screenShot(Pbuffer pb) {
- screenShot(0, 0, pb.getWidth(), pb.getHeight(), rootClass.getName() + "_" + makeTimestamp() + ".png");
- }
- /**
- * Save a region of the current render buffer to a PNG image. If the current
- * buffer is the framebuffer then this will work as a screen capture. Can
- * also be used with the PBuffer class to copy large images or textures that
- * have been rendered into the offscreen pbuffer.
- * <P>
- * WARNING: this function hogs memory! Call java with more memory
- * (java -Xms128m -Xmx128m)
- * <P>
- * @see selectPbuffer(Pbuffer)
- * @see selectDisplay()
- * @see savePixelsToPNG()
- */
- public static void screenShot(int x, int y, int width, int height, String imageFilename) {
- // allocate space for ARBG pixels
- ByteBuffer framebytes = allocBytes(width * height * SIZE_INT);
- int[] pixels = new int[width * height];
- // grab the current frame contents as ARGB ints (BGRA ints reversed)
- GL11.glReadPixels(x, y, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, framebytes);
- // copy ARGB data from ByteBuffer to integer array
- framebytes.asIntBuffer().get(pixels, 0, pixels.length);
- // free up this memory
- framebytes = null;
- // flip the pixels vertically and save to file
- GLImage.savePixelsToPNG(pixels, width, height, imageFilename, true);
- }
- /**
- * Save a ByteBuffer of ARGB pixels to a PNG file.
- * If flipY is true, flip the pixels on the Y axis before saving.
- */
- public static void savePixelsToPNG(ByteBuffer framebytes, int width, int height, String imageFilename, boolean flipY) {
- if (framebytes != null && imageFilename != null) {
- // copy ARGB data from ByteBuffer to integer array
- int[] pixels = new int[width * height];
- framebytes.asIntBuffer().get(pixels, 0, pixels.length);
- // save pixels to file
- GLImage.savePixelsToPNG(pixels, width, height, imageFilename, flipY);
- }
- }
- /**
- * Save the contents of the current render buffer to a PNG image. This is
- * an older version of screenShot() that used the default OpenGL GL_RGBA
- * pixel format which had to be swizzled into an ARGB format. I'm
- * keeping the function here for reference.
- * <P>
- * If the current buffer is the framebuffer then this will work as a screen capture.
- * Can also be used with the PBuffer class to copy large images or textures that
- * have been rendered into the offscreen pbuffer.
- * <P>
- * WARNING: this function hogs memory! Call java with more memory
- * (java -Xms128m -Xmx128)
- * <P>
- * @see selectPbuffer(), selectDisplay()
- */
- public static void screenShotRGB(int width, int height, String saveFilename) {
- // allocate space for RBG pixels
- ByteBuffer framebytes = GLApp.allocBytes(width * height * 3);
- int[] pixels = new int[width * height];
- int bindex;
- // grab a copy of the current frame contents as RGB (has to be UNSIGNED_BYTE or colors come out too dark)
- GL11.glReadPixels(0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, framebytes);
- // copy RGB data from ByteBuffer to integer array
- for (int i = 0; i < pixels.length; i++) {
- bindex = i * 3;
- pixels[i] =
- 0xFF000000 // A
- | ((framebytes.get(bindex) & 0x000000FF) << 16) // R
- | ((framebytes.get(bindex+1) & 0x000000FF) << 8) // G
- | ((framebytes.get(bindex+2) & 0x000000FF) << 0); // B
- }
- // free up some memory
- framebytes = null;
- // save to file (flip Y axis before saving)
- GLImage.savePixelsToPNG(pixels, width, height, saveFilename, true);
- }
- //========================================================================
- // Stencil functions
- //========================================================================
- /**
- * clear the stencil buffer
- */
- public static void clearMask() {
- GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
- }
- /**
- * Begin creating a mask. This function turns off the color and depth buffers
- * so all subsequent drawing will go only into the stencil buffer.
- * To use:
- * beginMask(1);
- * renderModel(); // draw some geometry
- * endMask();
- */
- public static void beginMask(int maskvalue) {
- // turn off writing to the color buffer and depth buffer
- GL11.glColorMask(false, false, false, false);
- GL11.glDepthMask(false);
- // enable stencil buffer
- GL11.glEnable(GL11.GL_STENCIL_TEST);
- // set the stencil test to ALWAYS pass
- GL11.glStencilFunc(GL11.GL_ALWAYS, maskvalue, 0xFFFFFFFF);
- // REPLACE the stencil buffer value with maskvalue whereever we draw
- GL11.glStencilOp(GL11.GL_REPLACE, GL11.GL_REPLACE, GL11.GL_REPLACE);
- }
- /**
- * End the mask. Freeze the stencil buffer and activate the color and depth buffers.
- */
- public static void endMask() {
- // don't let future drawing modify the contents of the stencil buffer
- GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
- // turn the color and depth buffers back on
- GL11.glColorMask(true, true, true, true);
- GL11.glDepthMask(true);
- }
- /**
- * Restrict rendering to the masked area.
- * To use:
- * GLStencil.beginMask(1);
- * renderModel();
- * GLStencil.endMask();
- */
- public static void activateMask(int maskvalue) {
- // enable stencil buffer
- GL11.glEnable(GL11.GL_STENCIL_TEST);
- // until stencil test is disabled, only write to areas where the
- // stencil buffer equals the mask value
- GL11.glStencilFunc(GL11.GL_EQUAL, maskvalue, 0xFFFFFFFF);
- }
- /**
- * turn off the stencil test so stencil has no further affect on rendering.
- */
- public static void disableMask() {
- GL11.glDisable(GL11.GL_STENCIL_TEST);
- }
- /**
- * Return the stencil buffer value at the given screen position.
- */
- public static int getMaskValue(int x, int y)
- {
- tmpByte.clear();
- // read the stencil value at the given position, as an unsigned byte, store it in tmpByte
- GL11.glReadPixels(x, y, 1, 1, GL11.GL_STENCIL_INDEX, GL11.GL_UNSIGNED_BYTE, tmpByte);
- return (int) tmpByte.get(0);
- }
- //========================================================================
- // Display list functions
- //
- // Display lists are OpenGL commands that have been optimized and stored
- // into memory on the graphics card. They greatly improve rendering
- // performance but also "freeze" the geometry, so are not suitable in cases
- // where the geometry has to change dynamically.
- //
- // Display lists have to be deleted from the graphics card when
- // the program exits, or they can accumulate and consume memory. The
- // function destroyDisplayLists() is called by cleanup() to de-allocate
- // any display lists that were created by these functions.
- //
- //========================================================================
- public static ArrayList displayLists = new ArrayList(); // will hold display list IDs created by beginDisplayList()
- /**
- * Begin a display list. All following OpenGL geometry commands (up to endDisplayList())
- * will be stored in a display list, not drawn to screen.
- * <P>
- * To use, create a display list in setup():
- * <PRE>
- * int teapotID = beginDisplayList();
- * ... // run teapot render code here
- * endDisplayList();
- * </PRE>
- *
- * Then call the display list later in render():
- * <PRE>
- * callDisplayList(teapotID);
- * </PRE>
- *
- * @return integer display list id
- * @see endDisplayList(), callDisplayList(), destroyDisplayList()
- */
- public static int beginDisplayList() {
- int DL_ID = GL11.glGenLists(1); // Allocate 1 new Display List
- GL11.glNewList(DL_ID, GL11.GL_COMPILE); // Start Building A List
- displayLists.add( new Integer(DL_ID) ); // save the list ID so we can delete it later (see destroyDisplayLists())
- return DL_ID;
- }
- /**
- * Finish display list creation. Use this function only after calling
- * beginDisplayList()
- *
- * @see beginDisplayList()
- */
- public static void endDisplayList() {
- GL11.glEndList();
- }
- /**
- * Render the geometry stored in a display list. Use this function after
- * calling beginDisplayList() and endDisplayList() to create a display list.
- *
- * @see beginDisplayList()
- * @see endDisplayList()
- */
- public static void callDisplayList(int displayListID) {
- GL11.glCallList(displayListID);
- }
- /**
- * Delete the given display list ID. Frees up resources on the graphics card.
- */
- public static void destroyDisplayList(int DL_ID)
- {
- GL11.glDeleteLists(DL_ID,1);
- }
- /**
- * Clean up the allocated display lists. Called by cleanUp() when app exits.
- *
- * @see cleanUp();
- */
- public static void destroyDisplayLists()
- {
- while (displayLists.size() > 0) {
- int displaylistID = ((Integer)displayLists.get(0)).intValue();
- GL11.glDeleteLists(displaylistID,1);
- displayLists.remove(0);
- }
- }
- //========================================================================
- // Native IO Buffer allocation functions
- //
- // These functions create and populate the native buffers used by LWJGL.
- //========================================================================
- public static ByteBuffer allocBytes(int howmany) {
- return ByteBuffer.allocateDirect(howmany * SIZE_BYTE).order(ByteOrder.nativeOrder());
- }
- public static IntBuffer allocInts(int howmany) {
- return ByteBuffer.allocateDirect(howmany * SIZE_INT).order(ByteOrder.nativeOrder()).asIntBuffer();
- }
- public static FloatBuffer allocFloats(int howmany) {
- return ByteBuffer.allocateDirect(howmany * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
- }
- public static DoubleBuffer allocDoubles(int howmany) {
- return ByteBuffer.allocateDirect(howmany * SIZE_DOUBLE).order(ByteOrder.nativeOrder()).asDoubleBuffer();
- }
- public static ByteBuffer allocBytes(byte[] bytearray) {
- ByteBuffer bb = ByteBuffer.allocateDirect(bytearray.length * SIZE_BYTE).order(ByteOrder.nativeOrder());
- bb.put(bytearray).flip();
- return bb;
- }
- public static IntBuffer allocInts(int[] intarray) {
- IntBuffer ib = ByteBuffer.allocateDirect(intarray.length * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asIntBuffer();
- ib.put(intarray).flip();
- return ib;
- }
- public static FloatBuffer allocFloats(float[] floatarray) {
- FloatBuffer fb = ByteBuffer.allocateDirect(floatarray.length * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
- fb.put(floatarray).flip();
- return fb;
- }
- public static DoubleBuffer allocDoubles(double[] darray) {
- DoubleBuffer fb = ByteBuffer.allocateDirect(darray.length * SIZE_DOUBLE).order(ByteOrder.nativeOrder()).asDoubleBuffer();
- fb.put(darray).flip();
- return fb;
- }
- public static void put(ByteBuffer b, byte[] values) {
- b.clear();
- b.put(values).flip();
- }
- public static void put(IntBuffer b, int[] values) {
- b.clear();
- b.put(values).flip();
- }
- public static void put(FloatBuffer b, float[] values) {
- b.clear();
- b.put(values).flip();
- }
- public static void put(DoubleBuffer b, double[] values) {
- b.clear();
- b.put(values).flip();
- }
- /**
- * copy ints from the given byteBuffer into the given int array.
- * @param b source ByteBuffer
- * @param values target integer array, must be same length as ByteBuffer capacity/4
- */
- public static void get(ByteBuffer b, int[] values) {
- b.asIntBuffer().get(values, 0, values.length);
- }
- /**
- * copy ints from the given IntBuffer into the given int array.
- * @param b source IntBuffer
- * @param values target integer array, must be same length as IntBuffer
- */
- public static void get(IntBuffer b, int[] values) {
- b.get(values, 0, values.length);
- }
- /**
- * return the contents of the byteBuffer as an array of ints.
- * @param b source ByteBuffer
- */
- public static int[] getInts(ByteBuffer b) {
- int[] values = new int[b.capacity()/SIZE_INT];
- b.asIntBuffer().get(values, 0, values.length);
- return values;
- }
- //========================================================================
- // Misc functions
- //========================================================================
- public static URL appletBaseURL = null;
- public static Class rootClass = GLApp.class;
- /**
- * Open the given file and return the InputStream. This function assumes
- * 1) that we're running an application and the file is in the local filesystem. If not found, then assume
- * 2) we're in a jar file and look for the file in the current jar. If not found, then assume
- * 3) we're running an applet and look for the file relative to the applet code base.
- * @param filename to open
- */
- public static InputStream getInputStream(String filename) {
- InputStream in = null;
- // 1) look for file in local filesystem
- try {
- in = new FileInputStream(filename);
- }
- catch (IOException ioe) {
- msg("GLApp.getInputStream (" + filename + "): " + ioe);
- if (in != null) {
- try {
- in.close();
- }
- catch (Exception e) {}
- in = null;
- }
- }
- catch (Exception e) {
- msg("GLApp.getInputStream (" + filename + "): " + e);
- }
- // 2) if couldn't open file, look in jar
- if (in == null && rootClass != null) {
- // NOTE: class.getResource() looks for files relative to the folder that the class is in.
- // ideally the class will be an application in the root of the installation, see setRootClass().
- URL u = null;
- if (filename.startsWith(".")) { // remove leading . ie. "./file"
- filename = filename.substring(1);
- }
- try {u = rootClass.getResource(filename);}
- catch (Exception ue) {msg("GLApp.getInputStream(): Can't find resource: " + ue);}
- //msg("GLApp.getInputStream (" +filename+ "): try jar resource url=" + u);
- if (u != null) {
- try {
- in = u.openStream();
- }
- catch (Exception e) {
- msg("GLApp.getInputStream (" +filename+ "): Can't load from jar: " + e);
- }
- }
- // 3) try loading file from applet base url
- if (in == null && appletBaseURL != null) {
- try {u = new URL(appletBaseURL,filename);}
- catch (Exception ue) {msg("GLApp.getInputStream(): Can't make applet base url: " + ue);}
- //msg("GLApp.getInputStream (" +filename+ "): try applet base url=" + u);
- try {
- in = u.openStream();
- }
- catch (Exception e) {
- msg("GLApp.getInputStream (" +filename+ "): Can't load from applet base URL: " + e);
- }
- }
- }
- return in;
- }
- /**
- * Return an array of bytes read from an InputStream. Reads all bytes
- * until the end of stream. Can read an arbitrary number of bytes.
- * NOTE: Does not close the inputStream!
- */
- public static byte[] getBytesFromStream(InputStream is) {
- int chunkSize = 1024;
- int totalRead = 0;
- int num = 0;
- byte[] bytes = new byte[chunkSize];
- ArrayList byteChunks = new ArrayList();
- // Read the bytes in chunks of 1024
- try {
- while ( (num=is.read(bytes)) >= 0) {
- byteChunks.add(bytes);
- bytes = new byte[chunkSize];
- totalRead += num;
- }
- }
- catch (IOException ioe) {
- err("GLApp.getBytesFromStream(): IOException " + ioe);
- }
- int numCopied = 0;
- bytes = new byte[totalRead];
- // copy byte chunks to byte array (last chunk may be partial)
- while (byteChunks.size() > 0) {
- byte[] byteChunk = (byte[]) byteChunks.get(0);
- int copylen = (totalRead - numCopied > chunkSize)? chunkSize : (totalRead - numCopied);
- System.arraycopy(byteChunk, 0, bytes, numCopied, copylen);
- byteChunks.remove(0);
- numCopied += copylen;
- }
- msg("getBytesFromStream() read " + numCopied + " bytes.");
- return bytes;
- }
- /**
- * Return an array of bytes read from a file.
- */
- public static byte[] getBytesFromFile(String filename) {
- InputStream is = getInputStream(filename);
- byte[] bytes = getBytesFromStream(is);
- try {
- is.close();
- }
- catch (IOException ioe) {
- err("GLApp.getBytesFromFile(): IOException " + ioe);
- }
- return bytes;
- }
- /**
- * Return a String array containing the path portion of a filename (result[0]),
- * and the fileame (result[1]). If there is no path, then result[0] will be ""
- * and result[1] will be the full filename.
- */
- public static String[] getPathAndFile(String filename) {
- String[] pathAndFile = new String[2];
- Matcher matcher = Pattern.compile("^.*/").matcher(filename);
- if (matcher.find()) {
- pathAndFile[0] = matcher.group();
- pathAndFile[1] = filename.substring(matcher.end());
- }
- else {
- pathAndFile[0] = "";
- pathAndFile[1] = filename;
- }
- return pathAndFile;
- }
- /**
- * Hold onto this Class for later class.getResource() calls (to load
- * resources from JAR files, see getInputStream()) and also to get class
- * name for use in screenshot filenames (see screenShot()).
- * <P>
- * To load files from a jar we need to access a class in the root folder
- * of the installation. It's not good to use GLApp.class because that
- * class is in the glapp package folder, and the getResource() function will not
- * find model, image and sound files because they're a level higher in
- * the folder tree. Below we call this.getClass() to record the class of the
- * application that subclasses GLApp, ie. assume we create an app MyGame that
- * extends GLApp, and MyGame.class is in the root folder of the installation:
- * <PRE>
- * MyGame.class
- * models (folder)
- * images (folder)
- * sounds (folder)
- * </PRE>
- * In this case setRootClass() will set the rootClass to MyGame. If MyGame
- * and subfolders are packaged in a jar file, then getInputStream() should
- * be able to do a rootClass.getResource("models/some_model.obj") and correctly
- * retrieve the file from the JAR.
- * <P>
- * @see getInputStream()
- */
- public void setRootClass() {
- rootClass = this.getClass();
- }
- /**
- * make a time stamp for filename
- * @return a string with format "YYYYMMDD-hhmmss"
- */
- public static String makeTimestamp()
- {
- Calendar now = Calendar.getInstance();
- int year = now.get(Calendar.YEAR);
- int month = now.get(Calendar.MONTH) + 1;
- int day = now.get(Calendar.DAY_OF_MONTH);
- int hours = now.get(Calendar.HOUR_OF_DAY);
- int minutes = now.get(Calendar.MINUTE);
- int seconds = now.get(Calendar.SECOND);
- String datetime = ""
- + year
- + (month < 10 ? "0" : "") + month
- + (day < 10 ? "0" : "") + day
- + "-"
- + (hours < 10 ? "0" : "") + hours
- + (minutes < 10 ? "0" : "") + minutes
- + (seconds < 10 ? "0" : "") + seconds;
- return datetime;
- }
- /**
- * Return a random floating point value between 0 and 1
- */
- public static float random() {
- return (float)Math.random();
- }
- /**
- * Return a random floating point value between 0 and upperbound (not including upperbound)
- */
- public static float random(float upperbound) {
- return (float)(Math.random()*(double)upperbound);
- }
- /**
- * Return a random integer value between 0 and upperbound (not including upperbound)
- */
- public static int random(int upperbound) {
- return (int)(Math.random()*(double)upperbound);
- }
- /**
- * Round a float value to the nearest int.
- */
- public static int round(float f) {
- return Math.round(f);
- }
- /**
- * Return true if the OpenGL context supports the given OpenGL extension.
- */
- public static boolean extensionExists(String extensionName) {
- if (OpenGLextensions == null) {
- String[] GLExtensions = GL11.glGetString(GL11.GL_EXTENSIONS).split(" ");
- OpenGLextensions = new Hashtable();
- for (int i=0; i < GLExtensions.length; i++) {
- OpenGLextensions.put(GLExtensions[i].toUpperCase(),"");
- }
- }
- return (OpenGLextensions.get(extensionName.toUpperCase()) != null);
- }
- /**
- * Show a debug message on the system console (calls System.out.println()). If
- * showMessages flag is false, does nothing.
- * @param text
- */
- public static void msg(String text) {
- if (showMessages) {
- System.out.println(text);
- }
- }
- /**
- * Show an error message on the system console (calls System.out.println()).
- * Does not check showMessages flag.
- * @param text
- */
- public static void err(String text) {
- System.out.println(text);
- }
- /**
- * Find a method in the given class with the given method name. Assumes the method
- * takes no parameters. The returned Method can be executed later using invoke()
- * (similar to a callback function in C/C++).
- * <P>
- * NOTE: method invocation is very fast for methods that take no parameters. If
- * the method takes parameters then invoking is much slower than calling the function
- * directly through code. For this reason and for simplicity I assume there are
- * no parameters on the function.
- *
- * @param object object that has the method we want to invoke
- * @param methodName name of function that we want to invoke
- * @return the Method object
- * @see invoke()
- */
- public static Method method(Object object, String methodName) {
- Method M = null;
- try {
- // Look for a method with the given name and no parameters
- M = object.getClass().getMethod(methodName, null);
- } catch (Exception e) {
- err("GLApp.method(): Can't find method (" +methodName+ "). " + e);
- }
- return M;
- }
- /**
- * Similar to the static method() function, this looks for the method in the
- * GLApp class (or it's subclass).
- *
- * @param methodName name of function that we want to invoke
- * @return the Method object
- * @see invoke()
- */
- public Method method(String methodName) {
- return method(this,methodName);
- }
- /**
- * Execute a method on the given object. Assumes the method
- * takes no parameters. Useful as a callback function.
- *
- * @param object (the object to call the method on)
- * @param method (the method that will be executed)
- * @see method()
- */
- public static void invoke(Object object, Method method) {
- if (object != null && method != null){
- try {
- // Call the method with this object as the argument!
- method.invoke(object, null);
- } catch (Exception e) {
- // Error handling
- System.err.println("GLApp.invoke(): couldn't invoke method " + method.getName() + " on object " + object.getClass().getName());
- }
- }
- }
- /**
- * Similar to the static invoke() function, this execute a method on the
- * GLApp class or subclass. Assumes the method takes no parameters.
- * Useful as a callback function.
- *
- * @param method (the method that will be executed)
- * @see method()
- */
- public void invoke(Method method) {
- if (method != null){
- try {
- // Call the method with this object as the argument!
- method.invoke(this, null);
- } catch (Exception e) {
- // Error handling
- System.err.println("GLApp.invoke(): couldn't invoke method " + method.getName() + " on object " + this.getClass().getName());
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement