diff --git a/src/java/org/lwjgl/Window.java b/src/java/org/lwjgl/Window.java index 13d8123c..06117fe5 100644 --- a/src/java/org/lwjgl/Window.java +++ b/src/java/org/lwjgl/Window.java @@ -71,15 +71,15 @@ public abstract class Window { * * Only one Window can be created() at a time; to create another Window you must * first destroy() the first window. - * - * The dimensions may be ignored if the window cannot be made non- - * fullscreen. The position may be ignored in either case. + * + * The dimensions may be ignored if the window cannot be made non- + * fullscreen. The position may be ignored in either case. * * @param title The window's title * @param x Position on x axis of top left corner of window. - * @param y Position on y axis of top left corner of window. - * @param width Width of window - * @param height Height of window + * @param y Position on y axis of top left corner of window. + * @param width Width of window + * @param height Height of window * @throws RuntimeException if you attempt to create more than one window at the same time */ protected Window(String title, int x, int y, int width, int height) { diff --git a/src/java/org/lwjgl/input/Cursor.java b/src/java/org/lwjgl/input/Cursor.java index 5319d4b8..4f793509 100644 --- a/src/java/org/lwjgl/input/Cursor.java +++ b/src/java/org/lwjgl/input/Cursor.java @@ -64,12 +64,14 @@ public class Cursor { * @param height cursor image height * @param xHotspot the x coordinate of the cursor hotspot * @param yHotspot the y coordinate of the cursor hotspot + * @param numImages number of cursor images specified. Must be 1 if animations are not supported. * @param cursorAddress the address of an int array containing the cursor image + * @param delayAddresses the address of animation frame delays, if numImages is greater than 1, else Sys.NULL * @throws Exception if the cursor could not be created for any reason */ - public Cursor(int width, int height, int xHotspot, int yHotspot, int imageAddress) throws Exception { + public Cursor(int width, int height, int xHotspot, int yHotspot, int numImages, int imageAddress, int delayAddresses) throws Exception { assert Mouse.isCreated(); - nativeHandle = nCreateCursor(width, height, xHotspot, yHotspot, imageAddress); + nativeHandle = nCreateCursor(width, height, xHotspot, yHotspot, numImages, imageAddress, delayAddresses); } /** @@ -89,7 +91,7 @@ public class Cursor { /** * Native method to create a native cursor */ - private static native int nCreateCursor(int width, int height, int xHotspot, int yHotspot, int imageAddresses); + private static native int nCreateCursor(int width, int height, int xHotspot, int yHotspot, int numImages, int imageAddresses, int delayAddresses); /** * Native method to destroy a native cursor diff --git a/src/java/org/lwjgl/input/Mouse.java b/src/java/org/lwjgl/input/Mouse.java index 2e346a5b..3c38042e 100644 --- a/src/java/org/lwjgl/input/Mouse.java +++ b/src/java/org/lwjgl/input/Mouse.java @@ -48,6 +48,9 @@ import org.lwjgl.*; * @version $Revision$ */ public class Mouse { + public final static int CURSOR_ONE_BIT_TRANSPARANCY = 1; + public final static int CURSOR_8_BIT_ALPHA = 2; + public final static int CURSOR_ANIMATION = 4; /** Has the mouse been created? */ private static boolean created; @@ -92,17 +95,21 @@ public class Mouse { } /** - * Check native cursor support - * @return true if native cursors are supported + * Get the capabilities of the native cursor. Return a bit mask of the native cursor capabilities. + * The CURSOR_ONE_BIT_TRANSPARANCY indicates support for cursors with one bit transparancy, + * the CURSOR_8_BIT_ALPHA indicates support for 8 bit alpha and CURSOR_ANIMATION indicates + * support for cursor animations. + * + * @return A bit mask with native cursor capabilities. */ - public static boolean isNativeCursorSupported() { - return nIsNativeCursorSupported(); + public static int getNativeCursorCaps() { + return nGetNativeCursorCaps(); } /** * Native function to determine native cursor support */ - private static native boolean nIsNativeCursorSupported(); + private static native int nGetNativeCursorCaps(); /** * Binds a native cursor. If the cursor argument is null, the @@ -120,7 +127,7 @@ public class Mouse { * @throws Exception if the cursor could not be set for any reason */ public static Cursor setNativeCursor(Cursor cursor) throws Exception { - assert created && isNativeCursorSupported(); + assert created && ((getNativeCursorCaps() | CURSOR_ONE_BIT_TRANSPARANCY) != 0); Cursor oldCursor = currentCursor; currentCursor = cursor; if (currentCursor != null) { @@ -136,7 +143,8 @@ public class Mouse { /** * Gets the minimum size of a native cursor. Can only be called if - * The Mouse is created and isNativeCursorSupported() returns true + * The Mouse is created and cursor caps includes at least + * CURSOR_ONE_BIT_TRANSPARANCY. * * @return the maximum size of a native cursor */ @@ -149,7 +157,8 @@ public class Mouse { /** * Gets the maximum size of a native cursor. Can only be called if - * The Mouse is created and isNativeCursorSupported() returns true + * The Mouse is created and cursor caps includes at least + * CURSOR_ONE_BIT_TRANSPARANCY. * * @return the maximum size of a native cursor */ diff --git a/src/java/org/lwjgl/opengl/BaseGL.java b/src/java/org/lwjgl/opengl/BaseGL.java index 6263a4eb..4982a016 100644 --- a/src/java/org/lwjgl/opengl/BaseGL.java +++ b/src/java/org/lwjgl/opengl/BaseGL.java @@ -88,12 +88,12 @@ public class BaseGL extends Window { * support windowed mode, then the width and height must match the current * display resolution, or an Exception will be thrown. Otherwise a fullscreen * window will be created. - * + * * @param title The title of the window * @param x The position of the window on the x axis. May be ignored. - * @param y The position of the window on the y axis. May be ignored. + * @param y The position of the window on the y axis. May be ignored. * @param width The width of the window's client area - * @param height The height of the window's client area + * @param height The height of the window's client area * @param bpp Require colour bits * @param alpha Required alpha bits * @param depth Required depth bits diff --git a/src/java/org/lwjgl/opengl/Pbuffer.java b/src/java/org/lwjgl/opengl/Pbuffer.java new file mode 100644 index 00000000..f261926c --- /dev/null +++ b/src/java/org/lwjgl/opengl/Pbuffer.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.lwjgl.opengl; + +import org.lwjgl.*; +import org.lwjgl.Window; + +/** + * $Id$ + * + * Pbuffer encapsulates an OpenGL pbuffer. + * + * Each instance of GL is only valid in the thread that creates it. + * In addition, only one instance of an OpenGL window or Pbuffer may be + * the current GL context in any one thread. To make a GL instance the + * current context, use makeCurrent(). + * + * @author elias_naur + * @version $Revision$ + */ +public class Pbuffer { + public final static int PBUFFER_SUPPORTED = 1; + + static { + System.loadLibrary(Sys.getLibraryName()); + } + + /** Handle to the native GL rendering context */ + protected final int handle; + + /** Current Pbuffer */ + private static Pbuffer currentBuffer = null; + + /** + * Construct an instance of a Pbuffer. If this fails then an Exception will be thrown. + * The buffer is single-buffered. + * + * NOTE: An OpenGL window must be created before a Pbuffer can be created. The Pbuffer will + * have its own context that shares display lists and textures with the OpenGL window context, + * but it will have its own OpenGL state. Therefore, state changes to a pbuffer will not be seen + * in the window context and vice versa. + * + * NOTE: Some OpenGL implementations requires the shared contexts to use the same pixel format. + * So if possible, use the same bpp, alpha, depth and stencil values used to create the main window. + * + * @param width Pbuffer width + * @param height Pbuffer height + * @param bpp Minimum bits per pixel + * @param alpha Minimum bits per pixel in alpha buffer + * @param depth Minimum bits per pixel in depth buffer + * @param stencil Minimum bits per pixel in stencil buffer + */ + public Pbuffer(int width, int height, int bpp, int alpha, int depth, int stencil) throws Exception { + handle = nCreate(width, height, bpp, alpha, depth, stencil); + } + + /** + * Method to release the current Pbuffer context and make the OpenGL window current. + */ + public static void releaseContext() { + currentBuffer = null; + nReleaseContext(); + } + + /** + * Method to test for validity of the buffer. If this function returns true, + * the buffer contents is lost. The buffer can still be used, but the results are undefined. + * The application is expected to release the buffer if needed, destroy it and recreate a new + * buffer. + * + * @return true if the buffer is lost and destroyed, false if the buffer is valid. + */ + public boolean isBufferLost() { + return nIsBufferLost(handle); + } + + /** + * Native method to test for buffer integrity + */ + private native static boolean nIsBufferLost(int handle); + + /** + * Native method to release the context. + */ + private native static void nReleaseContext(); + + /** + * Method to make the Pbuffer context current. All subsequent OpenGL + * calls will go to this buffer. + */ + public void makeCurrent() { + currentBuffer = this; + nMakeCurrent(handle); + } + + /** + * Native method to make a pbuffer current. + */ + private native static void nMakeCurrent(int handle); + + /** + * Gets the Pbuffer capabilities. Only the flag PBUFFER_SUPPORTED is + * available, and indicates that Pbuffers can be created. + * + * @return a bitmask of Pbuffer capabilities. + */ + public static native int getPbufferCaps(); + + /** + * Native method to create a Pbuffer + */ + private native static int nCreate( + int width, + int height, + int bpp, + int alpha, + int depth, + int stencil) throws Exception; + + /** + * Destroys the Pbuffer. The buffer must not be current. + */ + public void destroy() { + assert currentBuffer != this : "Pbuffers must not be current when releasing it"; + nDestroy(handle); + } + + /** + * Natively destroy any GL-related stuff + */ + private native static void nDestroy(int handle); +} diff --git a/src/java/org/lwjgl/test/input/HWCursorTest.java b/src/java/org/lwjgl/test/input/HWCursorTest.java index 3ba059d8..e7e48717 100644 --- a/src/java/org/lwjgl/test/input/HWCursorTest.java +++ b/src/java/org/lwjgl/test/input/HWCursorTest.java @@ -104,19 +104,19 @@ public class HWCursorTest { } catch (Exception e) { e.printStackTrace(); } - if (!Mouse.isNativeCursorSupported()) { + if ((Mouse.getNativeCursorCaps() & Mouse.CURSOR_ONE_BIT_TRANSPARANCY) == 0) { System.out.println("No HW cursor support!"); System.exit(0); } System.out.println("Maximum native cursor size: " + Mouse.getMaxCursorSize() + ", min size: " + Mouse.getMinCursorSize()); mouse_x = mouse_y = 0; -// int num_images = 3; + int num_images = 3; int image_size = Mouse.getMaxCursorSize()*Mouse.getMaxCursorSize(); - IntBuffer cursor_images = ByteBuffer.allocateDirect(/*num_images**/image_size*4).order(ByteOrder.nativeOrder()).asIntBuffer(); -/* IntBuffer delays = ByteBuffer.allocateDirect(num_images*4).order(ByteOrder.nativeOrder()).asIntBuffer(); + IntBuffer cursor_images = ByteBuffer.allocateDirect(num_images*image_size*4).order(ByteOrder.nativeOrder()).asIntBuffer(); + IntBuffer delays = ByteBuffer.allocateDirect(num_images*4).order(ByteOrder.nativeOrder()).asIntBuffer(); delays.put(0, 500); delays.put(1, 500); - delays.put(2, 500);*/ + delays.put(2, 500); int color_scale = 255/Mouse.getMaxCursorSize(); int bit_mask = 0x81000000; for (int j = 0; j < image_size; j++) { @@ -125,16 +125,22 @@ public class HWCursorTest { int color = (j*color_scale/Mouse.getMaxCursorSize()) << 16; cursor_images.put(0*image_size + j, 0x00000020 | color | bit_mask); } -/* for (int j = 0; j < image_size; j++) { + for (int j = 0; j < image_size; j++) { + if (j % 4 == 0) + bit_mask = (~bit_mask) & 0x81000000; int color = (j*color_scale/Mouse.getMaxCursorSize()) << 8; - cursor_images.put(1*image_size + j, 0x80000000 | color); + cursor_images.put(1*image_size + j, 0x00000020 | color | bit_mask); } for (int j = 0; j < image_size; j++) { - int color = j*color_scale/Mouse.getMaxCursorSize(); - cursor_images.put(2*image_size + j, 0x80000000 | color); - }*/ + if (j % 4 == 0) + bit_mask = (~bit_mask) & 0x81000000; + int color = (j*color_scale/Mouse.getMaxCursorSize()); + cursor_images.put(2*image_size + j, 0x00000020 | color | bit_mask); + } try { - cursor = new Cursor(Mouse.getMaxCursorSize(), Mouse.getMaxCursorSize(), Mouse.getMaxCursorSize()/2, Mouse.getMaxCursorSize()/2/*, num_images*/, Sys.getDirectBufferAddress(cursor_images)/*, Sys.getDirectBufferAddress(delays)*/); + if ((Mouse.getNativeCursorCaps() | Mouse.CURSOR_ANIMATION) == 0) + num_images = 1; + cursor = new Cursor(Mouse.getMaxCursorSize(), Mouse.getMaxCursorSize(), Mouse.getMaxCursorSize()/2, Mouse.getMaxCursorSize()/2, num_images, Sys.getDirectBufferAddress(cursor_images), Sys.getDirectBufferAddress(delays)); Mouse.setNativeCursor(cursor); } catch (Exception e) { e.printStackTrace(); diff --git a/src/java/org/lwjgl/test/opengl/PbufferTest.java b/src/java/org/lwjgl/test/opengl/PbufferTest.java new file mode 100644 index 00000000..111d46ad --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/PbufferTest.java @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2003 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Lightweight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl.test.opengl; + +import org.lwjgl.*; +import org.lwjgl.input.*; +import org.lwjgl.opengl.*; +import org.lwjgl.vector.Vector2f; + +import java.nio.*; + +/** + * $Id$ + * + * Tests Pbuffers + * + * @author elias_naur + * @version $Revision$ + */ +public class PbufferTest { + + /** Intended deiplay mode */ + private DisplayMode mode; + + /** GL instance */ + private GL gl; + + /** GLU instance */ + private GLU glu; + + /** our quad moving around */ + private Vector2f quadPosition; + + /** our quadVelocity */ + private Vector2f quadVelocity; + + /** angle of quad */ + private float angle; + + /** degrees to rotate per frame */ + private float angleRotation = 1.0f; + + /** Max speed of all changable attributes */ + private static final float MAX_SPEED = 20.0f; + + /** Pbuffer instance */ + private static Pbuffer pbuffer; + + /** The shared texture */ + private static int tex_handle; + + /** + * Executes the test + */ + public void execute() { + initialize(); + + mainLoop(); + + cleanup(); + } + + /** + * Initializes the test + */ + private void initialize() { + try { + //find displaymode + mode = findDisplayMode(800, 600, 16); + + // start of in windowed mode + gl = new GL("Test", 50, 50, mode.width, mode.height, mode.bpp, 0, 0, 0); +// gl = new GL("Test", 50, 50, mode.width, mode.height, mode.bpp, 0, 0, 0); + gl.create(); + glu = new GLU(gl); + if ((Pbuffer.getPbufferCaps() & Pbuffer.PBUFFER_SUPPORTED) == 0) { + System.out.println("No Pbuffer support!"); + System.exit(1); + } + System.out.println("Pbuffer support detected"); + + glInit(); + initPbuffer(); + + Keyboard.create(); + + quadPosition = new Vector2f(100f, 100f); + quadVelocity = new Vector2f(1.0f, 1.0f); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Runs the main loop of the "test" + */ + private void mainLoop() { + while (!Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) + && !gl.isCloseRequested()) { + // allow subsystem to get a chance to run too + gl.tick(); + + if (!gl.isMinimized()) { + // check keyboard input + processKeyboard(); + + // do "game" logic, and render it + logic(); + render(); + + // paint window + gl.paint(); + } else { + + // no need to render/paint if nothing has changed (ie. window dragged over) + if (gl.isDirty()) { + render(); + gl.paint(); + } + + // don't waste cpu time, sleep more + try { + Thread.sleep(100); + } catch (InterruptedException inte) { + } + } + } + } + + /** + * Performs the logic + */ + private void logic() { + angle += angleRotation; + if (angle > 90.0f) { + angle = 0.0f; + } + + quadPosition.x += quadVelocity.x; + quadPosition.y += quadVelocity.y; + + //check colision with vertical border border + if (quadPosition.x + 50 >= mode.width || quadPosition.x - 50 <= 0) { + quadVelocity.x *= -1; + } + + //check collision with horizontal border + if (quadPosition.y + 50 >= mode.height || quadPosition.y - 50 <= 0) { + quadVelocity.y *= -1; + } + } + + private void render() { + if (pbuffer.isBufferLost()) { + System.out.println("Buffer contents lost - will recreate the buffer"); + Pbuffer.releaseContext(); + pbuffer.destroy(); + initPbuffer(); + } + pbuffer.makeCurrent(); + // Pbuffer rendering + //clear background + gl.clear(GL.COLOR_BUFFER_BIT); + + // draw white quad + gl.pushMatrix(); + { + gl.translatef(quadPosition.x, quadPosition.y, 0); + gl.rotated(angle, 0.0f, 0.0f, 1.0f); + gl.color3f(1.0f, 1.0f, 1.0f); + gl.begin(GL.QUADS); + { + gl.vertex2i(-50, -50); + gl.vertex2i(50, -50); + gl.vertex2i(50, 50); + gl.vertex2i(-50, 50); + } + gl.end(); + } + gl.popMatrix(); + gl.copyTexImage2D(GL.TEXTURE_2D, 0, GL.RGB, 0, 0, 256, 256, 0); + Pbuffer.releaseContext(); + + // OpenGL window rendering + gl.clear(GL.COLOR_BUFFER_BIT); + // draw white quad + gl.pushMatrix(); + { + gl.translatef(quadPosition.x, quadPosition.y, 0); + gl.rotated(angle, 0.0f, 0.0f, 1.0f); + gl.color3f(1.0f, 1.0f, 0.0f); + gl.begin(GL.QUADS); + { + gl.texCoord2f(0f, 0f); + gl.vertex2i(-50, -50); + gl.texCoord2f(1f, 0f); + gl.vertex2i(50, -50); + gl.texCoord2f(1f, 1f); + gl.vertex2i(50, 50); + gl.texCoord2f(0f, 1f); + gl.vertex2i(-50, 50); + } + gl.end(); + } + gl.popMatrix(); + } + + private void initPbuffer() { + try { + pbuffer = new Pbuffer(256, 256, mode.bpp, 0, 0, 0); + pbuffer.makeCurrent(); + initGLState(256, 256, 0.5f); + gl.bindTexture(GL.TEXTURE_2D, tex_handle); + Pbuffer.releaseContext(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Processes keyboard input + */ + private void processKeyboard() { + Keyboard.poll(); + + //check for fullscreen key + if (Keyboard.isKeyDown(Keyboard.KEY_F)) { + + try { + destroyTexture(); + Keyboard.destroy(); + Pbuffer.releaseContext(); + pbuffer.destroy(); + gl.destroy(); + + Display.setDisplayMode(mode); + gl = new GL("Test", mode.bpp, 0, 0, 0); + gl.create(); + glInit(); + initPbuffer(); + glu = new GLU(gl); + + Keyboard.create(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + //check for window key + if (Keyboard.isKeyDown(Keyboard.KEY_W)) { + try { + destroyTexture(); + Keyboard.destroy(); + Pbuffer.releaseContext(); + pbuffer.destroy(); + gl.destroy(); + + Display.resetDisplayMode(); + gl = new GL("Test", 50, 50, mode.width, mode.height, mode.bpp, 0, 0, 0); + gl.create(); + glInit(); + initPbuffer(); + glu = new GLU(gl); + + + Keyboard.create(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + //check for speed changes + if (Keyboard.isKeyDown(Keyboard.KEY_UP)) { + quadVelocity.y += 0.1f; + } + if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) { + quadVelocity.y -= 0.1f; + } + if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) { + quadVelocity.x += 0.1f; + } + if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) { + quadVelocity.x -= 0.1f; + } + + if (Keyboard.isKeyDown(Keyboard.KEY_ADD)) { + angleRotation += 0.1f; + } + if (Keyboard.isKeyDown(Keyboard.KEY_SUBTRACT)) { + angleRotation -= 0.1f; + } + + //throttle + if (quadVelocity.x < -MAX_SPEED) { + quadVelocity.x = -MAX_SPEED; + } + if (quadVelocity.x > MAX_SPEED) { + quadVelocity.x = MAX_SPEED; + } + if (quadVelocity.y < -MAX_SPEED) { + quadVelocity.y = -MAX_SPEED; + } + if (quadVelocity.y > MAX_SPEED) { + quadVelocity.y = MAX_SPEED; + } + + if (angleRotation < 0.0f) { + angleRotation = 0.0f; + } + if (angleRotation > MAX_SPEED) { + angleRotation = MAX_SPEED; + } + } + + private void destroyTexture() { + IntBuffer buffer = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer(); + buffer.put(0, tex_handle); + gl.deleteTextures(1, Sys.getDirectBufferAddress(buffer)); + } + + /** + * Cleans up the test + */ + private void cleanup() { + destroyTexture(); + Keyboard.destroy(); + Pbuffer.releaseContext(); + pbuffer.destroy(); + gl.destroy(); + } + + /** + * Retrieves a displaymode, if one such is available + * + * @param width Required width + * @param height Required height + * @param bpp Minimum required bits per pixel + * @return + */ + private DisplayMode findDisplayMode(int width, int height, int bpp) { + DisplayMode[] modes = Display.getAvailableDisplayModes(); + for (int i = 0; i < modes.length; i++) { + if (modes[i].width == width + && modes[i].height == height + && modes[i].bpp >= bpp) { + return modes[i]; + } + } + return null; + } + + private void initGLState(int width, int height, float color) { + gl.matrixMode(GL.PROJECTION); + gl.loadIdentity(); + glu.ortho2D(0, mode.width, 0, mode.height); + gl.matrixMode(GL.MODELVIEW); + gl.loadIdentity(); + gl.viewport(0, 0, width, height); + + //set clear color to black + gl.clearColor(color, color, color, 0.0f); + } + + /** + * Initializes OGL + */ + private void glInit() { + // Go into orthographic projection mode. + gl.determineAvailableExtensions(); + //sync frame (only works on windows) + if (GL.WGL_EXT_swap_control) { + GL.wglSwapIntervalEXT(1); + } + gl.texEnvf(GL.TEXTURE_ENV, GL.TEXTURE_ENV_MODE, GL.REPLACE); + gl.enable(GL.TEXTURE_2D); + // Create shared texture + IntBuffer buffer = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer(); + gl.genTextures(1, Sys.getDirectBufferAddress(buffer)); + tex_handle = buffer.get(0); + gl.bindTexture(GL.TEXTURE_2D, tex_handle); + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP); + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP); + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR); + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR); + initGLState(mode.width, mode.height, 0f); + } + + /** + * Test entry point + */ + public static void main(String[] args) { + System.out.println( + "Change between fullscreen and windowed mode, by pressing F and W respectively"); + System.out.println("Move quad using arrowkeys, and change rotation using +/-"); + PbufferTest fswTest = new PbufferTest(); + fswTest.execute(); + } +} diff --git a/src/native/common/org_lwjgl_input_Cursor.h b/src/native/common/org_lwjgl_input_Cursor.h index 645b1efc..56b3c8ff 100644 --- a/src/native/common/org_lwjgl_input_Cursor.h +++ b/src/native/common/org_lwjgl_input_Cursor.h @@ -12,10 +12,10 @@ extern "C" { /* * Class: org_lwjgl_input_Cursor * Method: nCreateCursor - * Signature: (IIIII)I + * Signature: (IIIIIII)I */ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor - (JNIEnv *, jclass, jint, jint, jint, jint, jint); + (JNIEnv *, jclass, jint, jint, jint, jint, jint, jint, jint); /* * Class: org_lwjgl_input_Cursor diff --git a/src/native/common/org_lwjgl_input_Mouse.h b/src/native/common/org_lwjgl_input_Mouse.h index d5dc07ca..17f6939f 100644 --- a/src/native/common/org_lwjgl_input_Mouse.h +++ b/src/native/common/org_lwjgl_input_Mouse.h @@ -8,6 +8,12 @@ extern "C" { #endif /* Inaccessible static: _00024assertionsDisabled */ +#undef org_lwjgl_input_Mouse_CURSOR_ONE_BIT_TRANSPARANCY +#define org_lwjgl_input_Mouse_CURSOR_ONE_BIT_TRANSPARANCY 1L +#undef org_lwjgl_input_Mouse_CURSOR_8_BIT_ALPHA +#define org_lwjgl_input_Mouse_CURSOR_8_BIT_ALPHA 2L +#undef org_lwjgl_input_Mouse_CURSOR_ANIMATION +#define org_lwjgl_input_Mouse_CURSOR_ANIMATION 4L /* Inaccessible static: created */ /* Inaccessible static: buttons */ /* Inaccessible static: dx */ @@ -19,10 +25,10 @@ extern "C" { /* Inaccessible static: class_00024org_00024lwjgl_00024input_00024Mouse */ /* * Class: org_lwjgl_input_Mouse - * Method: nIsNativeCursorSupported - * Signature: ()Z + * Method: nGetNativeCursorCaps + * Signature: ()I */ -JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nIsNativeCursorSupported +JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetNativeCursorCaps (JNIEnv *, jclass); /* diff --git a/src/native/common/org_lwjgl_opengl_Pbuffer.h b/src/native/common/org_lwjgl_opengl_Pbuffer.h new file mode 100644 index 00000000..182e1f9a --- /dev/null +++ b/src/native/common/org_lwjgl_opengl_Pbuffer.h @@ -0,0 +1,66 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_lwjgl_opengl_Pbuffer */ + +#ifndef _Included_org_lwjgl_opengl_Pbuffer +#define _Included_org_lwjgl_opengl_Pbuffer +#ifdef __cplusplus +extern "C" { +#endif +/* Inaccessible static: _00024assertionsDisabled */ +#undef org_lwjgl_opengl_Pbuffer_PBUFFER_SUPPORTED +#define org_lwjgl_opengl_Pbuffer_PBUFFER_SUPPORTED 1L +/* Inaccessible static: currentBuffer */ +/* Inaccessible static: class_00024org_00024lwjgl_00024opengl_00024Pbuffer */ +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nIsBufferLost + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Pbuffer_nIsBufferLost + (JNIEnv *, jclass, jint); + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nReleaseContext + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nReleaseContext + (JNIEnv *, jclass); + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nMakeCurrent + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nMakeCurrent + (JNIEnv *, jclass, jint); + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: getPbufferCaps + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Pbuffer_getPbufferCaps + (JNIEnv *, jclass); + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nCreate + * Signature: (IIIIII)I + */ +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Pbuffer_nCreate + (JNIEnv *, jclass, jint, jint, jint, jint, jint, jint); + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nDestroy + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nDestroy + (JNIEnv *, jclass, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/native/linux/Makefile.am b/src/native/linux/Makefile.am index e9908814..d939b297 100644 --- a/src/native/linux/Makefile.am +++ b/src/native/linux/Makefile.am @@ -11,6 +11,7 @@ NATIVE = \ org_lwjgl_input_Mouse.cpp \ org_lwjgl_input_Cursor.cpp \ org_lwjgl_opengl_BaseGL.cpp \ + org_lwjgl_opengl_Pbuffer.cpp \ org_lwjgl_Window.cpp \ extxcursor.cpp diff --git a/src/native/linux/Window.h b/src/native/linux/Window.h index d898ba23..a46dc1bb 100644 --- a/src/native/linux/Window.h +++ b/src/native/linux/Window.h @@ -46,6 +46,7 @@ #include #include #include + #include "extgl.h" /* * update input grabbing(keyboard, mouse) @@ -124,4 +125,19 @@ */ extern void throwRuntimeException(JNIEnv * env, const char * err); + /* + * convert bit-per-pixel to bits-per-element + */ + extern int convertToBPE(int bpp); + + /* + * Return the context to the OpenGL window + */ + void makeCurrent(void); + + /* + * Return the current OpenGL window context + */ + GLXContext getCurrentContext(void); + #endif /* _LWJGL_WINDOW_H_INCLUDED_ */ diff --git a/src/native/linux/org_lwjgl_input_Cursor.cpp b/src/native/linux/org_lwjgl_input_Cursor.cpp index 2a1d483e..bd2bf5f3 100644 --- a/src/native/linux/org_lwjgl_input_Cursor.cpp +++ b/src/native/linux/org_lwjgl_input_Cursor.cpp @@ -8,25 +8,24 @@ * Signature: (IIIIIII)I */ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor - (JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, /*jint num_cursors,*/ jint image_address/*, jint delay_addresses*/) + (JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jint image_addresses, jint delay_addresses) { - XcursorPixel *pixels = (XcursorPixel *)image_address; -/* int *delays = (int *)delay_addresses; - int stride = width*height;*/ - int num_cursors = 1; - XcursorImages *cursor_images = XcursorImagesCreate(num_cursors); + XcursorPixel *pixels = (XcursorPixel *)image_addresses; + int *delays = (int *)delay_addresses; + int stride = width*height; + XcursorImages *cursor_images = XcursorImagesCreate(num_images); if (cursor_images == NULL) throwException(env, "Could not allocate cursor."); - cursor_images->nimage = num_cursors; -// for (int i = 0; i < num_cursors; i++) { + cursor_images->nimage = num_images; + for (int i = 0; i < num_images; i++) { XcursorImage *cursor_image = XcursorImageCreate(width, height); cursor_image->xhot = x_hotspot; cursor_image->yhot = y_hotspot; - cursor_image->pixels = pixels; -// cursor_image->pixels = &(pixels[stride*i]); - cursor_image->delay = 0/*delays[i]*/; - cursor_images->images[0] = cursor_image; -// } + cursor_image->pixels = &(pixels[stride*i]); + if (num_images > 1) + cursor_image->delay = delays[i]; + cursor_images->images[i] = cursor_image; + } Cursor cursor = XcursorImagesLoadCursor(getCurrentDisplay(), cursor_images); XcursorImagesDestroy(cursor_images); return (jint)cursor; diff --git a/src/native/linux/org_lwjgl_input_Mouse.cpp b/src/native/linux/org_lwjgl_input_Mouse.cpp index 23da46bd..4ceb91ed 100644 --- a/src/native/linux/org_lwjgl_input_Mouse.cpp +++ b/src/native/linux/org_lwjgl_input_Mouse.cpp @@ -174,13 +174,18 @@ void releasePointer(void) { * Method: nIsNativeCursorSupported * Signature: ()Z */ -JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nIsNativeCursorSupported +JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetNativeCursorCaps (JNIEnv *env, jclass clazz) { + int caps = 0; if (!isXcursorLoaded()) - return false; + return caps; XcursorBool argb_supported = XcursorSupportsARGB(getCurrentDisplay()); XcursorBool anim_supported = XcursorSupportsAnim(getCurrentDisplay()); - return argb_supported && anim_supported ? JNI_TRUE : JNI_FALSE; + if (argb_supported) + caps |= org_lwjgl_input_Mouse_CURSOR_8_BIT_ALPHA | org_lwjgl_input_Mouse_CURSOR_ONE_BIT_TRANSPARANCY; + if (anim_supported) + caps |= org_lwjgl_input_Mouse_CURSOR_ANIMATION; + return caps; } /* diff --git a/src/native/linux/org_lwjgl_opengl_BaseGL.cpp b/src/native/linux/org_lwjgl_opengl_BaseGL.cpp index ebe5ba0c..edb6050e 100644 --- a/src/native/linux/org_lwjgl_opengl_BaseGL.cpp +++ b/src/native/linux/org_lwjgl_opengl_BaseGL.cpp @@ -44,38 +44,67 @@ #include "org_lwjgl_opengl_BaseGL.h" static GLXContext context = NULL; // OpenGL rendering context +static GLXWindow glx_window; -static void makeCurrent(void) { - glXMakeCurrent(getCurrentDisplay(), getCurrentWindow(), context); +void makeCurrent(void) { + if (extgl_Extensions.glx.GLX13) + glXMakeContextCurrent(getCurrentDisplay(), glx_window, glx_window, context); + else + glXMakeCurrent(getCurrentDisplay(), getCurrentWindow(), context); } static void releaseContext(void) { - glXMakeCurrent(getCurrentDisplay(), None, NULL); + if (extgl_Extensions.glx.GLX13) + glXMakeContextCurrent(getCurrentDisplay(), None, None, NULL); + else + glXMakeCurrent(getCurrentDisplay(), None, NULL); } -static XVisualInfo *chooseVisual(Display *disp, int screen, int bpp, int depth, int alpha, int stencil) { - int bpe; +int convertToBPE(int bpp) { + int bpe = 4; switch (bpp) { case 32: case 24: bpe = 8; break; - case 16: - bpe = 4; - break; + case 16: /* Fall through */ default: - return JNI_FALSE; + break; } + return bpe; +} - int attriblist[] = { GLX_RGBA, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, depth, - GLX_RED_SIZE, bpe, - GLX_GREEN_SIZE, bpe, - GLX_BLUE_SIZE, bpe, - GLX_ALPHA_SIZE, alpha, - GLX_STENCIL_SIZE, stencil, - None }; +GLXContext getCurrentContext(void) { + return context; +} + +static GLXFBConfig *chooseVisualGLX13(Display *disp, int screen, int bpp, int depth, int alpha, int stencil) { + int bpe = convertToBPE(bpp); + int attriblist[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, True, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DEPTH_SIZE, depth, + GLX_RED_SIZE, bpe, + GLX_GREEN_SIZE, bpe, + GLX_BLUE_SIZE, bpe, + GLX_ALPHA_SIZE, alpha, + GLX_STENCIL_SIZE, stencil, + None}; + int num_formats; + return glXChooseFBConfig(disp, screen, attriblist, &num_formats); +} + +static XVisualInfo *chooseVisual(Display *disp, int screen, int bpp, int depth, int alpha, int stencil) { + int bpe = convertToBPE(bpp); + int attriblist[] = {GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, depth, + GLX_RED_SIZE, bpe, + GLX_GREEN_SIZE, bpe, + GLX_BLUE_SIZE, bpe, + GLX_ALPHA_SIZE, alpha, + GLX_STENCIL_SIZE, stencil, + None}; return glXChooseVisual(disp, screen, attriblist); } @@ -92,6 +121,8 @@ static void dumpVisualInfo(Display *disp, XVisualInfo *vis_info) { static void destroy(void) { releaseContext(); + if (extgl_Extensions.glx.GLX13) + glXDestroyWindow(getCurrentDisplay(), glx_window); glXDestroyContext(getCurrentDisplay(), context); context = NULL; Display *disp = getCurrentDisplay(); @@ -100,6 +131,63 @@ static void destroy(void) { extgl_Close(); } +static bool initWindowGLX13(JNIEnv *env, Display *disp, int screen, jstring title, int x, int y, int width, int height, int bpp, int depth, int alpha, int stencil, bool fscreen) { + GLXFBConfig *configs = chooseVisualGLX13(disp, screen, bpp, depth, alpha, stencil); + if (configs == NULL) { + throwException(env, "Could not find a matching pixel format"); + return false; + } + context = glXCreateNewContext(disp, configs[0], GLX_RGBA_TYPE, NULL, True); + if (context == NULL) { + XFree(configs); + throwException(env, "Could not create a GLX context"); + return false; + } + if (glXIsDirect(disp, context) == False) { + glXDestroyContext(disp, context); + XFree(configs); + throwException(env, "Could not create a GLX context"); + return false; + } + XVisualInfo * vis_info = glXGetVisualFromFBConfig(disp, configs[0]); +#ifdef _DEBUG + dumpVisualInfo(disp, vis_info); +#endif + createWindow(env, disp, screen, vis_info, title, x, y, width, height, fscreen); + glx_window = glXCreateWindow(disp, configs[0], getCurrentWindow(), NULL); + makeCurrent(); + XFree(configs); + XFree(vis_info); + return true; +} + +static bool initWindowGLX(JNIEnv *env, Display *disp, int screen, jstring title, int x, int y, int width, int height, int bpp, int depth, int alpha, int stencil, bool fscreen) { + XVisualInfo *vis_info = chooseVisual(disp, screen, bpp, depth, alpha, stencil); + if (vis_info == NULL) { + throwException(env, "Could not find a matching pixel format"); + return false; + } +#ifdef _DEBUG + dumpVisualInfo(disp, vis_info); +#endif + context = glXCreateContext(disp, vis_info, NULL, True); + if (context == NULL) { + XFree(vis_info); + throwException(env, "Could not create a GLX context"); + return false; + } + if (glXIsDirect(disp, context) == False) { + glXDestroyContext(disp, context); + XFree(vis_info); + throwException(env, "Could not create a GLX context"); + return false; + } + createWindow(env, disp, screen, vis_info, title, x, y, width, height, fscreen); + makeCurrent(); + XFree(vis_info); + return true; +} + /* * Class: org_lwjgl_opengl_BaseGL * Method: nCreate @@ -110,7 +198,6 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_nCreate { int screen; Display *disp; - XVisualInfo *vis_info; bool fscreen = false; if (fullscreen == JNI_TRUE) fscreen = true; @@ -131,27 +218,17 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_nCreate throwException(env, "Could not init GLX"); return; } - vis_info = chooseVisual(disp, screen, bpp, depth, alpha, stencil); - if (vis_info == NULL) { + bool create_success; + if (extgl_Extensions.glx.GLX13) { + create_success = initWindowGLX13(env, disp, screen, title, x, y, width, height, bpp, depth, alpha, stencil, fscreen); + } else { + create_success = initWindowGLX(env, disp, screen, title, x, y, width, height, bpp, depth, alpha, stencil, fscreen); + } + if (!create_success) { XCloseDisplay(disp); extgl_Close(); - throwException(env, "Could not find a matching pixel format"); return; } -#ifdef _DEBUG - dumpVisualInfo(disp, vis_info); -#endif - context = glXCreateContext(disp, vis_info, NULL, True); - if (context == NULL) { - XFree(vis_info); - XCloseDisplay(disp); - extgl_Close(); - throwException(env, "Could not create a GLX context"); - return; - } - createWindow(env, disp, screen, vis_info, title, x, y, width, height, fscreen); - XFree(vis_info); - makeCurrent(); if (extgl_Initialize() != 0) { destroy(); throwException(env, "Could not init gl function pointers"); @@ -163,6 +240,17 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_nCreate #endif } +/* + * Class: org_lwjgl_opengl_BaseGL + * Method: makeCurrent + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_makeCurrent + (JNIEnv *env, jobject obj) +{ + makeCurrent(); +} + /* * Class: org_lwjgl_opengl_BaseGL * Method: nDestroy @@ -181,5 +269,8 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_nDestroyGL */ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_swapBuffers(JNIEnv * env, jobject obj) { - glXSwapBuffers(getCurrentDisplay(), getCurrentWindow()); + if (extgl_Extensions.glx.GLX13) + glXSwapBuffers(getCurrentDisplay(), glx_window); + else + glXSwapBuffers(getCurrentDisplay(), getCurrentWindow()); } diff --git a/src/native/linux/org_lwjgl_opengl_Pbuffer.cpp b/src/native/linux/org_lwjgl_opengl_Pbuffer.cpp new file mode 100644 index 00000000..c102510f --- /dev/null +++ b/src/native/linux/org_lwjgl_opengl_Pbuffer.cpp @@ -0,0 +1,142 @@ +#include +#include "org_lwjgl_opengl_Pbuffer.h" +#include "extgl.h" +#include "Window.h" + +typedef struct _PbufferInfo { + GLXPbuffer buffer; + GLXContext context; +} PbufferInfo; + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nIsBufferLost + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Pbuffer_nIsBufferLost + (JNIEnv *env, jclass clazz, jint handle) +{ + // The buffer is never lost, because of the GLX_PRESERVED_CONTENTS flag + return JNI_FALSE; +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: isPbufferSupported + * Signature: ()Z + */ +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Pbuffer_getPbufferCaps + (JNIEnv *env, jclass clazz) +{ + // Only support thw GLX 1.3 Pbuffers and ignore the GLX_SGIX_pbuffer extension + return extgl_Extensions.glx.GLX13 ? org_lwjgl_opengl_Pbuffer_PBUFFER_SUPPORTED : 0; +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nCreate + * Signature: (IIII)I + */ +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Pbuffer_nCreate + (JNIEnv *env, jclass clazz, jint width, jint height, jint bpp, jint alpha, jint depth, jint stencil) +{ + int bpe = convertToBPE(bpp); + const int attrib_list[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, False, + GLX_RED_SIZE, bpe, + GLX_GREEN_SIZE, bpe, + GLX_BLUE_SIZE, bpe, + GLX_ALPHA_SIZE, alpha, + GLX_DEPTH_SIZE, depth, + GLX_STENCIL_SIZE, stencil, + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + None}; + int num_configs; + GLXFBConfig *configs = glXChooseFBConfig(getCurrentDisplay(), getCurrentScreen(), attrib_list, &num_configs); + if (num_configs == 0) { + XFree(configs); + throwException(env, "No matching pixel format"); + return -1; + } + int max; + glXGetFBConfigAttrib(getCurrentDisplay(), configs[0], GLX_MAX_PBUFFER_WIDTH, &max); + if (max < width) { + XFree(configs); + throwException(env, "Width too large"); + return -1; + } + glXGetFBConfigAttrib(getCurrentDisplay(), configs[0], GLX_MAX_PBUFFER_HEIGHT, &max); + if (max < height) { + XFree(configs); + throwException(env, "Height too large"); + return -1; + } + GLXContext context = glXCreateNewContext(getCurrentDisplay(), configs[0], GLX_RGBA_TYPE, getCurrentContext(), True); + if (context == NULL) { + XFree(configs); + throwException(env, "Could not create a GLX context"); + return false; + } + if (glXIsDirect(getCurrentDisplay(), context) == False) { + glXDestroyContext(getCurrentDisplay(), context); + XFree(configs); + throwException(env, "Could not create a direct GLX context"); + return false; + } + const int buffer_attribs[] = {GLX_PBUFFER_WIDTH, width, + GLX_PBUFFER_HEIGHT, height, + GLX_PRESERVED_CONTENTS, True, + GLX_LARGEST_PBUFFER, False}; + + GLXPbuffer buffer = glXCreatePbuffer(getCurrentDisplay(), configs[0], buffer_attribs); + XFree(configs); + PbufferInfo *buffer_info = (PbufferInfo *)malloc(sizeof(PbufferInfo)); + buffer_info->buffer = buffer; + buffer_info->context = context; + return (jint)buffer_info; +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nReleaseContext + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nReleaseContext + (JNIEnv *env, jclass clazz) +{ + makeCurrent(); +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nMakeCurrent + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nMakeCurrent + (JNIEnv *env, jclass clazz, jint handle) +{ + PbufferInfo *buffer_info = (PbufferInfo *)handle; + GLXPbuffer buffer = buffer_info->buffer; + GLXContext context = buffer_info->context; + if (glXMakeContextCurrent(getCurrentDisplay(), buffer, buffer, context) == False) { +#ifdef _DEBUG + printf("Could not make pbuffer current"); +#endif + } +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nDestroyGL + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nDestroy + (JNIEnv *env, jclass clazz, jint handle) +{ + PbufferInfo *buffer_info = (PbufferInfo *)handle; + GLXPbuffer buffer = buffer_info->buffer; + GLXContext context = buffer_info->context; + glXDestroyPbuffer(getCurrentDisplay(), buffer); + glXDestroyContext(getCurrentDisplay(), context); + free(buffer_info); +} diff --git a/src/native/win32/Window.h b/src/native/win32/Window.h index 64df0c10..9231e455 100644 --- a/src/native/win32/Window.h +++ b/src/native/win32/Window.h @@ -48,6 +48,7 @@ #undef DIRECTINPUT_VERSION #define DIRECTINPUT_VERSION 0x0300 #include + #include "extgl.h" #ifdef _PRIVATE_WINDOW_H_ #define WINDOW_H_API @@ -60,6 +61,7 @@ extern bool isFullScreen; // Whether we're fullscreen or not extern bool isMinimized; // Whether we're minimized or not extern RECT clientSize; + extern HGLRC hglrc; #endif /* _PRIVATE_WINDOW_H_ */ /* diff --git a/src/native/win32/org_lwjgl_Window.cpp b/src/native/win32/org_lwjgl_Window.cpp index 510f6f68..178e3a69 100644 --- a/src/native/win32/org_lwjgl_Window.cpp +++ b/src/native/win32/org_lwjgl_Window.cpp @@ -139,9 +139,6 @@ void closeWindow() #endif hwnd = NULL; } - - // Show the mouse - ShowCursor(TRUE); } /* @@ -239,7 +236,7 @@ bool registerWindow() windowClass.cbWndExtra = 0; windowClass.hInstance = dll_handle; windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); - windowClass.hCursor = NULL/*LoadCursor(NULL, IDC_ARROW)*/; + windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); windowClass.lpszMenuName = NULL; windowClass.lpszClassName = WINDOWCLASSNAME; @@ -328,7 +325,6 @@ bool createWindow(const char * title, int x, int y, int width, int height, bool // 3. Hide the mouse if necessary isFullScreen = fullscreen == JNI_TRUE; - ShowCursor(FALSE); // 4. Create DirectInput if (!createDirectInput()) { diff --git a/src/native/win32/org_lwjgl_input_Cursor.cpp b/src/native/win32/org_lwjgl_input_Cursor.cpp index 5047d0e3..ea30b51b 100755 --- a/src/native/win32/org_lwjgl_input_Cursor.cpp +++ b/src/native/win32/org_lwjgl_input_Cursor.cpp @@ -5,10 +5,10 @@ /* * Class: org_lwjgl_input_Cursor * Method: nCreateCursor - * Signature: (IIIIIII)I + * Signature: (IIIIIIIII)I */ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor - (JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint image_address) + (JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jint image_address, jint delay_addresses) { int *pixels = (int *)image_address; diff --git a/src/native/win32/org_lwjgl_input_Mouse.cpp b/src/native/win32/org_lwjgl_input_Mouse.cpp index f155c65c..2b3c4198 100644 --- a/src/native/win32/org_lwjgl_input_Mouse.cpp +++ b/src/native/win32/org_lwjgl_input_Mouse.cpp @@ -108,6 +108,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nCreate(JNIEnv *env, jclas mEnvironment = env; clsMouse = clazz; + ShowCursor(FALSE); CacheMouseFields(); /* skip enumeration, since we only want system mouse */ @@ -149,12 +150,12 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nCreate(JNIEnv *env, jclas /* * Class: org_lwjgl_input_Mouse * Method: nIsNativeCursorSupported - * Signature: ()Z + * Signature: ()I */ -JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nIsNativeCursorSupported +JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetNativeCursorCaps (JNIEnv *env, jclass clazz) { - return JNI_TRUE; + return org_lwjgl_input_Mouse_CURSOR_ONE_BIT_TRANSPARANCY; } /* @@ -187,24 +188,24 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nSetNativeCursor SetCursorPos(clientRect.left, clientRect.top); cursorPos.x = clientRect.left; cursorPos.y = clientRect.top; - while (ShowCursor(TRUE) < 0) - ; + ShowCursor(TRUE); usingNativeCursor = true; } } else { - while (ShowCursor(FALSE) >= 0) - ; - SetClassLong(hwnd, GCL_HCURSOR, (LONG)NULL); - SetCursor(NULL); - mDIDevice->Unacquire(); - if(mDIDevice->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) { + if (usingNativeCursor) { + SetClassLong(hwnd, GCL_HCURSOR, (LONG)NULL); + SetCursor(NULL); + mDIDevice->Unacquire(); + if(mDIDevice->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) { #if _DEBUG - printf("SetCooperativeLevel failed\n"); + printf("SetCooperativeLevel failed\n"); #endif - throwException(env, "Could not set the CooperativeLevel."); - return; + throwException(env, "Could not set the CooperativeLevel."); + return; + } + ShowCursor(FALSE); + usingNativeCursor = false; } - usingNativeCursor = false; } } @@ -236,9 +237,10 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMinCursorSize * Signature: ()V */ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nDestroy(JNIEnv *env, jclass clazz) { - mEnvironment = env; - clsMouse = clazz; - ShutdownMouse(); + mEnvironment = env; + clsMouse = clazz; + ShowCursor(FALSE); + ShutdownMouse(); } /* diff --git a/src/native/win32/org_lwjgl_opengl_BaseGL.cpp b/src/native/win32/org_lwjgl_opengl_BaseGL.cpp index 07a8ee9c..0fa8d599 100644 --- a/src/native/win32/org_lwjgl_opengl_BaseGL.cpp +++ b/src/native/win32/org_lwjgl_opengl_BaseGL.cpp @@ -47,6 +47,89 @@ HGLRC hglrc = NULL; // OpenGL rendering context +static int findPixelFormat(JNIEnv *env, unsigned int flags, int bpp, int alpha, int depth, int stencil) { + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + flags, // RGBA type + PFD_TYPE_RGBA, + (BYTE)bpp, + 0, 0, 0, 0, 0, 0, // color bits ignored + (BYTE)alpha, + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + (BYTE)depth, + (BYTE)stencil, + 0, // No auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + + // get the best available match of pixel format for the device context + int iPixelFormat = ChoosePixelFormat(hdc, &pfd); + if (iPixelFormat == 0) { + throwException(env, "Failed to choose pixel format"); + return -1; + } + +#ifdef _DEBUG + printf("Pixel format is %d\n", iPixelFormat); +#endif + + // make that the pixel format of the device context + if (SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE) { + printf("Failed to set pixel format\n"); + throwException(env, "Failed to choose pixel format"); + return -1; + } + + // 3. Check the chosen format matches or exceeds our specifications + PIXELFORMATDESCRIPTOR desc; + if (DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &desc) == 0) { + throwException(env, "Could not describe pixel format"); + return -1; + } + + if (desc.cColorBits < bpp) { + throwException(env, "This application requires a greater colour depth"); + return -1; + } + + if (desc.cAlphaBits < alpha) { + throwException(env, "This application requires a greater alpha depth"); + return -1; + } + + if (desc.cStencilBits < stencil) { + throwException(env, "This application requires a greater stencil depth"); + return -1; + } + + if (desc.cDepthBits < depth) { + throwException(env, "This application requires a greater depth buffer depth"); + return -1; + } + + if ((desc.dwFlags & PFD_GENERIC_FORMAT) != 0 || (desc.dwFlags & PFD_GENERIC_ACCELERATED) != 0) { + throwException(env, "Mode not supported by hardware"); + return -1; + } + + if ((desc.dwFlags & flags) != flags) { + throwException(env, "Capabilities not supported"); + return -1; + } + + // 4. Initialise other things now + if (extgl_Open() != 0) { + throwException(env, "Failed to open extgl"); + return -1; + } + return iPixelFormat; +} + /* * Class: org_lwjgl_opengl_BaseGL * Method: nCreate @@ -73,96 +156,11 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_BaseGL_nCreate PFD_SUPPORT_OPENGL | // support OpenGL PFD_DOUBLEBUFFER; // double buffered - PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd - 1, // version number - flags, // RGBA type - PFD_TYPE_RGBA, - (BYTE)bpp, - 0, 0, 0, 0, 0, 0, // color bits ignored - (BYTE)alpha, - 0, // shift bit ignored - 0, // no accumulation buffer - 0, 0, 0, 0, // accum bits ignored - (BYTE)depth, - (BYTE)stencil, - 0, // No auxiliary buffer - PFD_MAIN_PLANE, // main layer - 0, // reserved - 0, 0, 0 // layer masks ignored - }; - - // get the best available match of pixel format for the device context - int iPixelFormat = ChoosePixelFormat(hdc, &pfd); - if (iPixelFormat == 0) { - throwException(env, "Failed to choose pixel format"); + int iPixelFormat = findPixelFormat(env, flags, bpp, alpha, depth, stencil); + if (iPixelFormat == -1) { closeWindow(); return; } - -#ifdef _DEBUG - printf("Pixel format is %d\n", iPixelFormat); -#endif - - // make that the pixel format of the device context - if (SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE) { - printf("Failed to set pixel format\n"); - throwException(env, "Failed to choose pixel format"); - closeWindow(); - return; - } - - // 3. Check the chosen format matches or exceeds our specifications - PIXELFORMATDESCRIPTOR desc; - if (DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &desc) == 0) { - throwException(env, "Could not describe pixel format"); - closeWindow(); - return; - } - - if (desc.cColorBits < bpp) { - throwException(env, "This application requires a greater colour depth"); - closeWindow(); - return; - } - - if (desc.cAlphaBits < alpha) { - throwException(env, "This application requires a greater alpha depth"); - closeWindow(); - return; - } - - if (desc.cStencilBits < stencil) { - throwException(env, "This application requires a greater stencil depth"); - closeWindow(); - return; - } - - if (desc.cDepthBits < depth) { - throwException(env, "This application requires a greater depth buffer depth"); - closeWindow(); - return; - } - - if ((desc.dwFlags & PFD_GENERIC_FORMAT) != 0 || (desc.dwFlags & PFD_GENERIC_ACCELERATED) != 0) { - throwException(env, "Mode not supported by hardware"); - closeWindow(); - return; - } - - if ((desc.dwFlags & flags) != flags) { - throwException(env, "Capabilities not supported"); - closeWindow(); - return; - } - - // 4. Initialise other things now - if (extgl_Open() != 0) { - throwException(env, "Failed to open extgl"); - closeWindow(); - return; - } - // Create a rendering context hglrc = wglCreateContext(hdc); if (hglrc == NULL) { diff --git a/src/native/win32/org_lwjgl_opengl_Pbuffer.cpp b/src/native/win32/org_lwjgl_opengl_Pbuffer.cpp new file mode 100755 index 00000000..f9b3dbe6 --- /dev/null +++ b/src/native/win32/org_lwjgl_opengl_Pbuffer.cpp @@ -0,0 +1,131 @@ +#include +#include "org_lwjgl_opengl_Pbuffer.h" +#include "Window.h" +#include "extgl.h" + +typedef struct _PbufferInfo { + HGLRC Pbuffer_context; + HPBUFFERARB Pbuffer; + HDC Pbuffer_dc; +} PbufferInfo; + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: isPbufferSupported + * Signature: ()Z + */ +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Pbuffer_getPbufferCaps + (JNIEnv *env, jclass clazz) +{ + return extgl_Extensions.wgl.ARB_pbuffer ? org_lwjgl_opengl_Pbuffer_PBUFFER_SUPPORTED : 0; +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nCreate + * Signature: (IIII)I + */ +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Pbuffer_nCreate + (JNIEnv *env, jclass clazz, jint width, jint height, jint bpp, jint alpha, jint depth, jint stencil) +{ + int iPixelFormat; + unsigned int num_formats_returned; + int attrib_list[] = {WGL_DRAW_TO_PBUFFER_ARB, TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_DOUBLE_BUFFER_ARB, FALSE, + WGL_SUPPORT_OPENGL_ARB, TRUE, + WGL_COLOR_BITS_ARB, bpp, + WGL_ALPHA_BITS_ARB, alpha, + WGL_DEPTH_BITS_ARB, depth, + WGL_STENCIL_BITS_ARB, stencil, + 0}; + BOOL result = wglChoosePixelFormatARB(hdc, attrib_list, NULL, 1, &iPixelFormat, &num_formats_returned); + if (result == FALSE) { + throwException(env, "Could not choose pixel formats."); + return (jint)NULL; + } + HPBUFFERARB Pbuffer = wglCreatePbufferARB(hdc, iPixelFormat, width, height, NULL); + if (Pbuffer == NULL) { + throwException(env, "Could not create Pbuffer."); + return (jint)NULL; + } + HDC Pbuffer_dc = wglGetPbufferDCARB(Pbuffer); + if (Pbuffer_dc == NULL) { + wglDestroyPbufferARB(Pbuffer); + throwException(env, "Could not get Pbuffer dc."); + return (jint)NULL; + } + // Create a rendering context + HGLRC Pbuffer_context = wglCreateContext(Pbuffer_dc); + if (Pbuffer_context == NULL) { + wglReleasePbufferDCARB(Pbuffer, Pbuffer_dc); + wglDestroyPbufferARB(Pbuffer); + throwException(env, "Failed to create Pbuffer rendering context"); + return (jint)NULL; + } + if (!wglShareLists(hglrc, Pbuffer_context)) { + wglDeleteContext(Pbuffer_context); + wglReleasePbufferDCARB(Pbuffer, Pbuffer_dc); + wglDestroyPbufferARB(Pbuffer); + throwException(env, "Could not share buffer context."); + return (jint)NULL; + } + PbufferInfo *Pbuffer_info = (PbufferInfo *)malloc(sizeof(PbufferInfo)); + Pbuffer_info->Pbuffer = Pbuffer; + Pbuffer_info->Pbuffer_context = Pbuffer_context; + Pbuffer_info->Pbuffer_dc = Pbuffer_dc; + return (jint)Pbuffer_info; +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nReleaseContext + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nReleaseContext + (JNIEnv *env, jclass clazz) +{ + wglMakeCurrent(hdc, hglrc); +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nIsBufferLost + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Pbuffer_nIsBufferLost + (JNIEnv *env, jclass clazz, jint handle) +{ + PbufferInfo *Pbuffer_info = (PbufferInfo *)handle; + BOOL buffer_lost; + wglQueryPbufferARB(Pbuffer_info->Pbuffer, WGL_PBUFFER_LOST_ARB, &buffer_lost); + return buffer_lost ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nMakeCurrent + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nMakeCurrent + (JNIEnv *env, jclass clazz, jint handle) +{ + PbufferInfo *Pbuffer_info = (PbufferInfo *)handle; + wglMakeCurrent(Pbuffer_info->Pbuffer_dc, Pbuffer_info->Pbuffer_context); +} + +/* + * Class: org_lwjgl_opengl_Pbuffer + * Method: nDestroyGL + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Pbuffer_nDestroy + (JNIEnv *env, jclass clazz, jint handle) +{ + PbufferInfo *Pbuffer_info = (PbufferInfo *)handle; + wglDeleteContext(Pbuffer_info->Pbuffer_context); + wglReleasePbufferDCARB(Pbuffer_info->Pbuffer, Pbuffer_info->Pbuffer_dc); + wglDestroyPbufferARB(Pbuffer_info->Pbuffer); + free(Pbuffer_info); +}