modes = new ArrayList<>();
+ while(m.hasRemaining()){
+ GLFWVidMode vidMode = m.get();
+ int bpp = vidMode.redBits() + vidMode.greenBits() + vidMode.blueBits();
+ modes.add(new DisplayMode(vidMode.width(), vidMode.height(), bpp, vidMode.refreshRate()));
+ }
+ return modes.toArray(new DisplayMode[modes.size()]);
+ }
+ public static DisplayMode getDesktopDisplayMode(){
+ GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
+ int bpp = vidMode.redBits() + vidMode.greenBits() + vidMode.blueBits();
+ return new DisplayMode(vidMode.width(), vidMode.height(), bpp, vidMode.refreshRate());
+ }
+ public static boolean isCreated(){
+ return created;
+ }
+ public static boolean isCloseRequested(){
+ return glfwWindowShouldClose(window);
+ }
+ public static void sync(int fps){
+ Sync.sync(fps);
+ }
+ public static void update(){
+ if(glfwGetWindowAttrib(window, GLFW_VISIBLE) == 1) {
+ resized = false;
+ glfwSwapBuffers(window);
+ Mouse.poll_scrollY = 0;
+ glfwPollEvents();
+ Mouse.createEvent();
+ }
+ }
+ public static boolean wasResized(){
+ return resized;
+ }
+ public static int getWidth(){
+ return current_mode.getWidth();
+ }
+ public static int getHeight(){
+ return current_mode.getHeight();
+ }
+ public static boolean isActive(){
+ return focused;
+ }
+
+ public static long getWindow() {
+ return window;
+ }
+
+ public static void releaseContext() {
+ glfwSetWindowShouldClose(window, true);
+ }
+
+ public static void create() throws LWJGLException {
+ create(new PixelFormat(), new ContextAttribs(3, 3).withProfileCore(true));
+ }
+
+ public static void create(PixelFormat pf) throws LWJGLException {
+ create(pf, new ContextAttribs(3, 3).withProfileCore(true));
+ }
+
+ public static void create(PixelFormat pf, ContextAttribs attributes) throws LWJGLException {
+ created = true;
+ try ( MemoryStack stack = MemoryStack.stackPush()) {
+ IntBuffer pWidth = stack.mallocInt(1); // int*
+ IntBuffer pHeight = stack.mallocInt(1); // int*
+
+ // Get the window size passed to glfwCreateWindow
+ glfwGetWindowSize(window, pWidth, pHeight);
+
+ // Center the window
+ glfwSetWindowPos(
+ window,
+ (initial_mode.getWidth() - pWidth.get(0)) / 2,
+ (initial_mode.getHeight() - pHeight.get(0)) / 2
+ );
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, attributes.getVersion_major());
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, attributes.getVersion_minor());
+ if(attributes.isProfileCore()) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+ glfwSetWindowSizeCallback(window, new GLFWWindowSizeCallback() {
+ @Override
+ public void invoke(long window, int width, int height) {
+ current_mode = new DisplayMode(width, height);
+ resized = true;
+ }
+ });
+ glfwSetWindowFocusCallback(window, new GLFWWindowFocusCallback() {
+ @Override
+ public void invoke(long l, boolean focused) {
+ Display.focused = focused;
+ Mouse.poll_xPos = Mouse.last_x;
+ Mouse.poll_yPos = Mouse.last_y;
+ }
+ });
+
+ Keyboard.create();
+ Keyboard.pollGLFW();
+ Mouse.create();
+ Mouse.pollGLFW();
+
+ //Use raw input, better for 3D camera
+ if (glfwRawMouseMotionSupported())
+ glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
+
+ glfwSwapInterval(vsync ? GLFW_TRUE : GLFW_FALSE);
+ glfwShowWindow(window);
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/display/DisplayMode.java b/src/de/verschwiegener/lwjgl3/display/DisplayMode.java
new file mode 100644
index 0000000..876e48f
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/display/DisplayMode.java
@@ -0,0 +1,41 @@
+package de.verschwiegener.lwjgl3.display;
+
+public class DisplayMode {
+
+ private int width, height, bpp, freq;
+
+ private final boolean fullscreen;
+
+ public DisplayMode(int width, int height) {
+ this(width, height, 0, 0, false);
+ }
+
+ DisplayMode(int width, int height, int bpp, int freq) {
+ this(width, height, bpp, freq, true);
+ }
+
+ private DisplayMode(int width, int height, int bpp, int freq, boolean fullscreen) {
+ this.width = width;
+ this.height = height;
+ this.bpp = bpp;
+ this.freq = freq;
+ this.fullscreen = fullscreen;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getBitsPerPixel() {
+ return bpp;
+ }
+
+ public int getFrequency() {
+ return freq;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/display/GlobalLock.java b/src/de/verschwiegener/lwjgl3/display/GlobalLock.java
new file mode 100644
index 0000000..b2d3ed0
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/display/GlobalLock.java
@@ -0,0 +1,5 @@
+package de.verschwiegener.lwjgl3.display;
+
+final class GlobalLock {
+ static final Object lock = new Object();
+}
diff --git a/src/de/verschwiegener/lwjgl3/display/PixelFormat.java b/src/de/verschwiegener/lwjgl3/display/PixelFormat.java
new file mode 100644
index 0000000..52fee73
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/display/PixelFormat.java
@@ -0,0 +1,381 @@
+package de.verschwiegener.lwjgl3.display;
+
+public class PixelFormat {
+
+ /**
+ * We probybly dont even need this class but so it is drop in place
+ */
+
+ /**
+ * The number of bits per pixel, exluding alpha.
+ * This parameter is ignored in Display.create().
+ */
+ private int bpp;
+ /** The number of alpha bits. */
+ private int alpha;
+ /** The number of depth buffer bits */
+ private int depth;
+ /** The number of stencil bits */
+ private int stencil;
+ /**
+ * The number of samples to use in anti-aliasing.
+ * 0 means that anti-aliasing is disabled.
+ */
+ private int samples;
+ /**
+ * The number of COLOR_SAMPLES_NV to use for Coverage Sample Anti-aliasing (CSAA).
+ * When this number is greater than 0, the {@code samples} property will be treated
+ * as if it were the COVERAGE_SAMPLES_NV property.
+ *
+ * This property is currently a no-op for the MacOS implementation.
+ */
+ private int colorSamples;
+ /** The number of auxiliary buffers */
+ private int num_aux_buffers;
+ /** The number of bits per pixel in the accumulation buffer */
+ private int accum_bpp;
+ /** The number of alpha bits in the accumulation buffer */
+ private int accum_alpha;
+ /** Whether this format requires a stereo buffer */
+ private boolean stereo;
+ /** Whether this format specifies a floating point format */
+ private boolean floating_point;
+ /**
+ * Whether this format specifies a packed floating point format (32 bit unsigned - R11F_G11F_B10F)
+ * This property is currently a no-op for the MacOS implementation.
+ */
+ private boolean floating_point_packed;
+ /**
+ * Whether this format specifies an sRGB format
+ * This property is currently a no-op for the MacOS implementation.
+ */
+ private boolean sRGB;
+
+ /**
+ * Default pixel format is minimum 8 bits depth, and no alpha
+ * nor stencil requirements.
+ */
+ public PixelFormat() {
+ this(0, 8, 0);
+ }
+
+ public PixelFormat(int alpha, int depth, int stencil) {
+ this(alpha, depth, stencil, 0);
+ }
+
+ public PixelFormat(int alpha, int depth, int stencil, int samples) {
+ this(0, alpha, depth, stencil, samples);
+ }
+
+ public PixelFormat(int bpp, int alpha, int depth, int stencil, int samples) {
+ this(bpp, alpha, depth, stencil, samples, 0, 0, 0, false);
+ }
+
+ public PixelFormat(int bpp, int alpha, int depth, int stencil, int samples, int num_aux_buffers, int accum_bpp, int accum_alpha, boolean stereo) {
+ this(bpp, alpha, depth, stencil, samples, num_aux_buffers, accum_bpp, accum_alpha, stereo, false);
+ }
+
+ public PixelFormat(int bpp, int alpha, int depth, int stencil, int samples, int num_aux_buffers, int accum_bpp, int accum_alpha, boolean stereo, boolean floating_point) {
+ this.bpp = bpp;
+ this.alpha = alpha;
+ this.depth = depth;
+ this.stencil = stencil;
+
+ this.samples = samples;
+
+ this.num_aux_buffers = num_aux_buffers;
+
+ this.accum_bpp = accum_bpp;
+ this.accum_alpha = accum_alpha;
+
+ this.stereo = stereo;
+
+ this.floating_point = floating_point;
+ this.floating_point_packed = false;
+ this.sRGB = false;
+ }
+
+ private PixelFormat(final PixelFormat pf) {
+ this.bpp = pf.bpp;
+ this.alpha = pf.alpha;
+ this.depth = pf.depth;
+ this.stencil = pf.stencil;
+
+ this.samples = pf.samples;
+ this.colorSamples = pf.colorSamples;
+
+ this.num_aux_buffers = pf.num_aux_buffers;
+
+ this.accum_bpp = pf.accum_bpp;
+ this.accum_alpha = pf.accum_alpha;
+
+ this.stereo = pf.stereo;
+
+ this.floating_point = pf.floating_point;
+ this.floating_point_packed = pf.floating_point_packed;
+ this.sRGB = pf.sRGB;
+ }
+
+ public int getBitsPerPixel() {
+ return bpp;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new bits per pixel value.
+ *
+ * @param bpp the new bits per pixel value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withBitsPerPixel(final int bpp) {
+ if ( bpp < 0 )
+ throw new IllegalArgumentException("Invalid number of bits per pixel specified: " + bpp);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.bpp = bpp;
+ return pf;
+ }
+
+ public int getAlphaBits() {
+ return alpha;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new alpha bits value.
+ *
+ * @param alpha the new alpha bits value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withAlphaBits(final int alpha) {
+ if ( alpha < 0 )
+ throw new IllegalArgumentException("Invalid number of alpha bits specified: " + alpha);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.alpha = alpha;
+ return pf;
+ }
+
+ public int getDepthBits() {
+ return depth;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new depth bits value.
+ *
+ * @param depth the new depth bits value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withDepthBits(final int depth) {
+ if ( depth < 0 )
+ throw new IllegalArgumentException("Invalid number of depth bits specified: " + depth);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.depth = depth;
+ return pf;
+ }
+
+ public int getStencilBits() {
+ return stencil;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new stencil bits value.
+ *
+ * @param stencil the new stencil bits value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withStencilBits(final int stencil) {
+ if ( stencil < 0 )
+ throw new IllegalArgumentException("Invalid number of stencil bits specified: " + stencil);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.stencil = stencil;
+ return pf;
+ }
+
+ public int getSamples() {
+ return samples;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new samples value.
+ *
+ * @param samples the new samples value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withSamples(final int samples) {
+ if ( samples < 0 )
+ throw new IllegalArgumentException("Invalid number of samples specified: " + samples);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.samples = samples;
+ return pf;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new color samples values.
+ * A value greater than 0 is valid only if the {@code samples} property is also greater than 0. Additionally, the
+ * color samples value needs to be lower than or equal to the {@code samples} property.
+ *
+ * @param colorSamples the new color samples value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withCoverageSamples(final int colorSamples) {
+ return withCoverageSamples(colorSamples, samples);
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new color samples
+ * and coverage samples values.
+ *
+ * @param colorSamples the new color samples value. This value must be lower than or equal to the coverage samples value.
+ * @param coverageSamples the new coverage samples value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withCoverageSamples(final int colorSamples, final int coverageSamples) {
+ if ( coverageSamples < 0 || colorSamples < 0 || (coverageSamples == 0 && 0 < colorSamples) || coverageSamples < colorSamples )
+ throw new IllegalArgumentException("Invalid number of coverage samples specified: " + coverageSamples + " - " + colorSamples);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.samples = coverageSamples;
+ pf.colorSamples = colorSamples;
+ return pf;
+ }
+
+ public int getAuxBuffers() {
+ return num_aux_buffers;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new auxiliary buffers value.
+ *
+ * @param num_aux_buffers the new auxiliary buffers value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withAuxBuffers(final int num_aux_buffers) {
+ if ( num_aux_buffers < 0 )
+ throw new IllegalArgumentException("Invalid number of auxiliary buffers specified: " + num_aux_buffers);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.num_aux_buffers = num_aux_buffers;
+ return pf;
+ }
+
+ public int getAccumulationBitsPerPixel() {
+ return accum_bpp;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new bits per pixel in the accumulation buffer value.
+ *
+ * @param accum_bpp the new bits per pixel in the accumulation buffer value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withAccumulationBitsPerPixel(final int accum_bpp) {
+ if ( accum_bpp < 0 )
+ throw new IllegalArgumentException("Invalid number of bits per pixel in the accumulation buffer specified: " + accum_bpp);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.accum_bpp = accum_bpp;
+ return pf;
+ }
+
+ public int getAccumulationAlpha() {
+ return accum_alpha;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new alpha bits in the accumulation buffer value.
+ *
+ * @param accum_alpha the new alpha bits in the accumulation buffer value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withAccumulationAlpha(final int accum_alpha) {
+ if ( accum_alpha < 0 )
+ throw new IllegalArgumentException("Invalid number of alpha bits in the accumulation buffer specified: " + accum_alpha);
+
+ final PixelFormat pf = new PixelFormat(this);
+ pf.accum_alpha = accum_alpha;
+ return pf;
+ }
+
+ public boolean isStereo() {
+ return stereo;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new stereo value.
+ *
+ * @param stereo the new stereo value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withStereo(final boolean stereo) {
+ final PixelFormat pf = new PixelFormat(this);
+ pf.stereo = stereo;
+ return pf;
+ }
+
+ public boolean isFloatingPoint() {
+ return floating_point;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new floating point value.
+ * If floating_point is true, floating_point_packed will be reset to false.
+ *
+ * @param floating_point the new floating point value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withFloatingPoint(final boolean floating_point) {
+ final PixelFormat pf = new PixelFormat(this);
+ pf.floating_point = floating_point;
+ if ( floating_point )
+ pf.floating_point_packed = false;
+ return pf;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new packed floating point value.
+ * If floating_point_packed is true, floating_point will be reset to false.
+ *
+ * @param floating_point_packed the new packed floating point value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withFloatingPointPacked(final boolean floating_point_packed) {
+ final PixelFormat pf = new PixelFormat(this);
+ pf.floating_point_packed = floating_point_packed;
+ if ( floating_point_packed )
+ pf.floating_point = false;
+ return pf;
+ }
+
+ public boolean isSRGB() {
+ return sRGB;
+ }
+
+ /**
+ * Returns a new PixelFormat object with the same properties as this PixelFormat and the new sRGB value.
+ *
+ * @param sRGB the new floating point value.
+ *
+ * @return the new PixelFormat
+ */
+ public PixelFormat withSRGB(final boolean sRGB) {
+ final PixelFormat pf = new PixelFormat(this);
+ pf.sRGB = sRGB;
+ return pf;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/display/Sync.java b/src/de/verschwiegener/lwjgl3/display/Sync.java
new file mode 100644
index 0000000..d916160
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/display/Sync.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2002-2012 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.display;
+
+import org.lwjgl.glfw.GLFW;
+
+/**
+ * A highly accurate sync method that continually adapts to the system
+ * it runs on to provide reliable results.
+ *
+ * @author Riven
+ * @author kappaOne
+ */
+class Sync {
+
+ /** number of nano seconds in a second */
+ private static final long NANOS_IN_SECOND = 1000L * 1000L * 1000L;
+
+ /** The time to sleep/yield until the next frame */
+ private static long nextFrame = 0;
+
+ /** whether the initialisation code has run */
+ private static boolean initialised = false;
+
+ /** for calculating the averages the previous sleep/yield times are stored */
+ private static RunningAvg sleepDurations = new RunningAvg(10);
+ private static RunningAvg yieldDurations = new RunningAvg(10);
+
+
+ /**
+ * An accurate sync method that will attempt to run at a constant frame rate.
+ * It should be called once every frame.
+ *
+ * @param fps - the desired frame rate, in frames per second
+ */
+ public static void sync(int fps) {
+ if (fps <= 0) return;
+ if (!initialised) initialise();
+ try {
+ // sleep until the average sleep time is greater than the time remaining till nextFrame
+ for (long t0 = getTime(), t1; (nextFrame - t0) > sleepDurations.avg(); t0 = t1) {
+ Thread.sleep(1);
+ sleepDurations.add((t1 = getTime()) - t0); // update average sleep time
+ }
+
+ // slowly dampen sleep average if too high to avoid yielding too much
+ sleepDurations.dampenForLowResTicker();
+
+ // yield until the average yield time is greater than the time remaining till nextFrame
+ for (long t0 = getTime(), t1; (nextFrame - t0) > yieldDurations.avg(); t0 = t1) {
+ Thread.yield();
+ yieldDurations.add((t1 = getTime()) - t0); // update average yield time
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ // schedule next frame, drop frame(s) if already too late for next frame
+ nextFrame = Math.max(nextFrame + NANOS_IN_SECOND / fps, getTime());
+ }
+
+ /**
+ * This method will initialise the sync method by setting initial
+ * values for sleepDurations/yieldDurations and nextFrame.
+ *
+ * If running on windows it will start the sleep timer fix.
+ */
+ private static void initialise() {
+ initialised = true;
+
+ sleepDurations.init(1000 * 1000);
+ yieldDurations.init((int) (-(getTime() - getTime()) * 1.333));
+
+ nextFrame = getTime();
+
+ String osName = System.getProperty("os.name");
+
+ if (osName.startsWith("Win")) {
+ // On windows the sleep functions can be highly inaccurate by
+ // over 10ms making in unusable. However it can be forced to
+ // be a bit more accurate by running a separate sleeping daemon
+ // thread.
+ Thread timerAccuracyThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(Long.MAX_VALUE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ timerAccuracyThread.setName("LWJGL Timer");
+ timerAccuracyThread.setDaemon(true);
+ timerAccuracyThread.start();
+ }
+ }
+
+ /**
+ * Get the system time in nano seconds
+ *
+ * @return will return the current time in nano's
+ */
+ private static long getTime() {
+ return (long) ((GLFW.glfwGetTime() * NANOS_IN_SECOND));
+ }
+
+ private static class RunningAvg {
+ private final long[] slots;
+ private int offset;
+
+ private static final long DAMPEN_THRESHOLD = 10 * 1000L * 1000L; // 10ms
+ private static final float DAMPEN_FACTOR = 0.9f; // don't change: 0.9f is exactly right!
+
+ public RunningAvg(int slotCount) {
+ this.slots = new long[slotCount];
+ this.offset = 0;
+ }
+
+ public void init(long value) {
+ while (this.offset < this.slots.length) {
+ this.slots[this.offset++] = value;
+ }
+ }
+
+ public void add(long value) {
+ this.slots[this.offset++ % this.slots.length] = value;
+ this.offset %= this.slots.length;
+ }
+
+ public long avg() {
+ long sum = 0;
+ for (int i = 0; i < this.slots.length; i++) {
+ sum += this.slots[i];
+ }
+ return sum / this.slots.length;
+ }
+
+ public void dampenForLowResTicker() {
+ if (this.avg() > DAMPEN_THRESHOLD) {
+ for (int i = 0; i < this.slots.length; i++) {
+ this.slots[i] *= DAMPEN_FACTOR;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/opengl/ARBDebugOutputCallback.java b/src/de/verschwiegener/lwjgl3/opengl/ARBDebugOutputCallback.java
new file mode 100644
index 0000000..a09d4a8
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/opengl/ARBDebugOutputCallback.java
@@ -0,0 +1,158 @@
+package de.verschwiegener.lwjgl3.opengl;
+
+public class ARBDebugOutputCallback extends PointerWrapperAbstract {
+ /** Severity levels. */
+ private static final int
+ GL_DEBUG_SEVERITY_HIGH_ARB = 0x9146,
+ GL_DEBUG_SEVERITY_MEDIUM_ARB = 0x9147,
+ GL_DEBUG_SEVERITY_LOW_ARB = 0x9148;
+
+ /** Sources. */
+ private static final int
+ GL_DEBUG_SOURCE_API_ARB = 0x8246,
+ GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB = 0x8247,
+ GL_DEBUG_SOURCE_SHADER_COMPILER_ARB = 0x8248,
+ GL_DEBUG_SOURCE_THIRD_PARTY_ARB = 0x8249,
+ GL_DEBUG_SOURCE_APPLICATION_ARB = 0x824A,
+ GL_DEBUG_SOURCE_OTHER_ARB = 0x824B;
+
+ /** Types. */
+ private static final int
+ GL_DEBUG_TYPE_ERROR_ARB = 0x824C,
+ GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB = 0x824D,
+ GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB = 0x824E,
+ GL_DEBUG_TYPE_PORTABILITY_ARB = 0x824F,
+ GL_DEBUG_TYPE_PERFORMANCE_ARB = 0x8250,
+ GL_DEBUG_TYPE_OTHER_ARB = 0x8251;
+
+ private static final long CALLBACK_POINTER;
+
+ static {
+ long pointer = 0;
+ try {
+ // Call reflectively so that we can compile this class for the Generator.
+ pointer = (Long)Class.forName("org.lwjgl.opengl.CallbackUtil").getDeclaredMethod("getDebugOutputCallbackARB").invoke(null);
+ } catch (Exception e) {
+ // ignore
+ }
+ CALLBACK_POINTER = pointer;
+ }
+
+ private final Handler handler;
+
+ /**
+ * Creates an ARBDebugOutputCallback with a default callback handler.
+ * The default handler will simply print the message on System.err.
+ */
+ public ARBDebugOutputCallback() {
+ this(new Handler() {
+ public void handleMessage(final int source, final int type, final int id, final int severity, final String message) {
+ System.err.println("[LWJGL] ARB_debug_output message");
+ System.err.println("\tID: " + id);
+
+ String description;
+ switch ( source ) {
+ case GL_DEBUG_SOURCE_API_ARB:
+ description = "API";
+ break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
+ description = "WINDOW SYSTEM";
+ break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
+ description = "SHADER COMPILER";
+ break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
+ description = "THIRD PARTY";
+ break;
+ case GL_DEBUG_SOURCE_APPLICATION_ARB:
+ description = "APPLICATION";
+ break;
+ case GL_DEBUG_SOURCE_OTHER_ARB:
+ description = "OTHER";
+ break;
+ default:
+ description = printUnknownToken(source);
+ }
+ System.err.println("\tSource: " + description);
+
+ switch ( type ) {
+ case GL_DEBUG_TYPE_ERROR_ARB:
+ description = "ERROR";
+ break;
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
+ description = "DEPRECATED BEHAVIOR";
+ break;
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
+ description = "UNDEFINED BEHAVIOR";
+ break;
+ case GL_DEBUG_TYPE_PORTABILITY_ARB:
+ description = "PORTABILITY";
+ break;
+ case GL_DEBUG_TYPE_PERFORMANCE_ARB:
+ description = "PERFORMANCE";
+ break;
+ case GL_DEBUG_TYPE_OTHER_ARB:
+ description = "OTHER";
+ break;
+ default:
+ description = printUnknownToken(type);
+ }
+ System.err.println("\tType: " + description);
+
+ switch ( severity ) {
+ case GL_DEBUG_SEVERITY_HIGH_ARB:
+ description = "HIGH";
+ break;
+ case GL_DEBUG_SEVERITY_MEDIUM_ARB:
+ description = "MEDIUM";
+ break;
+ case GL_DEBUG_SEVERITY_LOW_ARB:
+ description = "LOW";
+ break;
+ default:
+ description = printUnknownToken(severity);
+ }
+ System.err.println("\tSeverity: " + description);
+
+ System.err.println("\tMessage: " + message);
+ }
+
+ private String printUnknownToken(final int token) {
+ return "Unknown (0x" + Integer.toHexString(token).toUpperCase() + ")";
+ }
+ });
+ }
+
+ /**
+ * Creates an ARBDebugOutputCallback with the specified callback handler.
+ * The handler's {@code handleMessage} method will be called whenever
+ * debug output is generated by the GL.
+ *
+ * @param handler the callback handler
+ */
+ public ARBDebugOutputCallback(final Handler handler) {
+ super(CALLBACK_POINTER);
+
+ this.handler = handler;
+ }
+
+ Handler getHandler() {
+ return handler;
+ }
+
+ /** Implementations of this interface can be used to receive ARB_debug_output notifications. */
+ public interface Handler {
+
+ /**
+ * This method will be called when an ARB_debug_output message is generated.
+ *
+ * @param source the message source
+ * @param type the message type
+ * @param id the message ID
+ * @param severity the message severity
+ * @param message the string representation of the message.
+ */
+ void handleMessage(int source, int type, int id, int severity, String message);
+
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/opengl/GLContext.java b/src/de/verschwiegener/lwjgl3/opengl/GLContext.java
new file mode 100644
index 0000000..2b5153b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/opengl/GLContext.java
@@ -0,0 +1,11 @@
+package de.verschwiegener.lwjgl3.opengl;
+
+import org.lwjgl.opengl.GL;
+import org.lwjgl.opengl.GLCapabilities;
+
+public class GLContext {
+
+ public static GLCapabilities getCapabilities(){
+ return GL.getCapabilities();
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/opengl/PointerWrapper.java b/src/de/verschwiegener/lwjgl3/opengl/PointerWrapper.java
new file mode 100644
index 0000000..7e937ff
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/opengl/PointerWrapper.java
@@ -0,0 +1,5 @@
+package de.verschwiegener.lwjgl3.opengl;
+
+public interface PointerWrapper {
+ long getPointer();
+}
diff --git a/src/de/verschwiegener/lwjgl3/opengl/PointerWrapperAbstract.java b/src/de/verschwiegener/lwjgl3/opengl/PointerWrapperAbstract.java
new file mode 100644
index 0000000..e99b701
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/opengl/PointerWrapperAbstract.java
@@ -0,0 +1,58 @@
+package de.verschwiegener.lwjgl3.opengl;
+
+
+import de.verschwiegener.lwjgl3.LWJGLUtil;
+
+public class PointerWrapperAbstract implements PointerWrapper {
+ protected final long pointer;
+
+ protected PointerWrapperAbstract(final long pointer) {
+ this.pointer = pointer;
+ }
+
+ /**
+ * Returns true if this object represents a valid pointer.
+ * The pointer might be invalid because it is NULL or because
+ * some other action has deleted the object that this pointer
+ * represents.
+ *
+ * @return true if the pointer is valid
+ */
+ public boolean isValid() {
+ return pointer != 0;
+ }
+
+ /**
+ * Checks if the pointer is valid and throws an IllegalStateException if
+ * it is not. This method is a NO-OP, unless the org.lwjgl.util.Debug
+ * property has been set to true.
+ */
+ public final void checkValid() {
+ if ( LWJGLUtil.DEBUG && !isValid() )
+ throw new IllegalStateException("This " + getClass().getSimpleName() + " pointer is not valid.");
+ }
+
+ public final long getPointer() {
+ checkValid();
+ return pointer;
+ }
+
+ public boolean equals(final Object o) {
+ if ( this == o ) return true;
+ if ( !(o instanceof PointerWrapperAbstract) ) return false;
+
+ final PointerWrapperAbstract that = (PointerWrapperAbstract)o;
+
+ if ( pointer != that.pointer ) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (int)(pointer ^ (pointer >>> 32));
+ }
+
+ public String toString() {
+ return getClass().getSimpleName() + " pointer (0x" + Long.toHexString(pointer).toUpperCase() + ")";
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/Color.java b/src/de/verschwiegener/lwjgl3/util/Color.java
new file mode 100644
index 0000000..a807d01
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/Color.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+
+/**
+ * A mutable Color class
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public final class Color implements ReadableColor, Serializable, WritableColor {
+
+ static final long serialVersionUID = 1L;
+
+ /** Color components, publicly accessible */
+ private byte red, green, blue, alpha;
+
+ /**
+ * Constructor for Color.
+ */
+ public Color() {
+ this(0, 0, 0, 255);
+ }
+
+ /**
+ * Constructor for Color. Alpha defaults to 255.
+ */
+ public Color(int r, int g, int b) {
+ this(r, g, b, 255);
+ }
+
+ /**
+ * Constructor for Color. Alpha defaults to 255.
+ */
+ public Color(byte r, byte g, byte b) {
+ this(r, g, b, (byte) 255);
+ }
+
+ /**
+ * Constructor for Color.
+ */
+ public Color(int r, int g, int b, int a) {
+ set(r, g, b, a);
+ }
+
+ /**
+ * Constructor for Color.
+ */
+ public Color(byte r, byte g, byte b, byte a) {
+ set(r, g, b, a);
+ }
+
+ /**
+ * Constructor for Color
+ */
+ public Color(ReadableColor c) {
+ setColor(c);
+ }
+
+ /**
+ * Set a color
+ */
+ public void set(int r, int g, int b, int a) {
+ red = (byte) r;
+ green = (byte) g;
+ blue = (byte) b;
+ alpha = (byte) a;
+ }
+
+ /**
+ * Set a color
+ */
+ public void set(byte r, byte g, byte b, byte a) {
+ this.red = r;
+ this.green = g;
+ this.blue = b;
+ this.alpha = a;
+ }
+
+ /**
+ * Set a color
+ */
+ public void set(int r, int g, int b) {
+ set(r, g, b, 255);
+ }
+
+ /**
+ * Set a color
+ */
+ public void set(byte r, byte g, byte b) {
+ set(r, g, b, (byte) 255);
+ }
+
+ /**
+ * Accessor
+ */
+ public int getRed() {
+ return red & 0xFF;
+ }
+
+ /**
+ * Accessor
+ */
+ public int getGreen() {
+ return green & 0xFF;
+ }
+
+ /**
+ * Accessor
+ */
+ public int getBlue() {
+ return blue & 0xFF;
+ }
+
+ /**
+ * Accessor
+ */
+ public int getAlpha() {
+ return alpha & 0xFF;
+ }
+
+ /**
+ * Set the Red component
+ */
+ public void setRed(int red) {
+ this.red = (byte) red;
+ }
+
+ /**
+ * Set the Green component
+ */
+ public void setGreen(int green) {
+ this.green = (byte) green;
+ }
+
+ /**
+ * Set the Blue component
+ */
+ public void setBlue(int blue) {
+ this.blue = (byte) blue;
+ }
+
+ /**
+ * Set the Alpha component
+ */
+ public void setAlpha(int alpha) {
+ this.alpha = (byte) alpha;
+ }
+
+ /**
+ * Set the Red component
+ */
+ public void setRed(byte red) {
+ this.red = red;
+ }
+
+ /**
+ * Set the Green component
+ */
+ public void setGreen(byte green) {
+ this.green = green;
+ }
+
+ /**
+ * Set the Blue component
+ */
+ public void setBlue(byte blue) {
+ this.blue = blue;
+ }
+
+ /**
+ * Set the Alpha component
+ */
+ public void setAlpha(byte alpha) {
+ this.alpha = alpha;
+ }
+
+ /**
+ * Stringify
+ */
+ public String toString() {
+ return "Color [" + getRed() + ", " + getGreen() + ", " + getBlue() + ", " + getAlpha() + "]";
+ }
+
+ /**
+ * Equals
+ */
+ public boolean equals(Object o) {
+ return (o != null)
+ && (o instanceof ReadableColor)
+ && (((ReadableColor) o).getRed() == this.getRed())
+ && (((ReadableColor) o).getGreen() == this.getGreen())
+ && (((ReadableColor) o).getBlue() == this.getBlue())
+ && (((ReadableColor) o).getAlpha() == this.getAlpha());
+ }
+
+ /**
+ * Hashcode
+ */
+ public int hashCode() {
+ return (red << 24) | (green << 16) | (blue << 8) | alpha;
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#getAlphaByte()
+ */
+ public byte getAlphaByte() {
+ return alpha;
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#getBlueByte()
+ */
+ public byte getBlueByte() {
+ return blue;
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#getGreenByte()
+ */
+ public byte getGreenByte() {
+ return green;
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#getRedByte()
+ */
+ public byte getRedByte() {
+ return red;
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#writeRGBA(java.nio.ByteBuffer)
+ */
+ public void writeRGBA(ByteBuffer dest) {
+ dest.put(red);
+ dest.put(green);
+ dest.put(blue);
+ dest.put(alpha);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#writeRGB(java.nio.ByteBuffer)
+ */
+ public void writeRGB(ByteBuffer dest) {
+ dest.put(red);
+ dest.put(green);
+ dest.put(blue);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#writeABGR(java.nio.ByteBuffer)
+ */
+ public void writeABGR(ByteBuffer dest) {
+ dest.put(alpha);
+ dest.put(blue);
+ dest.put(green);
+ dest.put(red);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#writeARGB(java.nio.ByteBuffer)
+ */
+ public void writeARGB(ByteBuffer dest) {
+ dest.put(alpha);
+ dest.put(red);
+ dest.put(green);
+ dest.put(blue);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#writeBGR(java.nio.ByteBuffer)
+ */
+ public void writeBGR(ByteBuffer dest) {
+ dest.put(blue);
+ dest.put(green);
+ dest.put(red);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableColor#writeBGRA(java.nio.ByteBuffer)
+ */
+ public void writeBGRA(ByteBuffer dest) {
+ dest.put(blue);
+ dest.put(green);
+ dest.put(red);
+ dest.put(alpha);
+ }
+
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ public void readRGBA(ByteBuffer src) {
+ red = src.get();
+ green = src.get();
+ blue = src.get();
+ alpha = src.get();
+ }
+
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ public void readRGB(ByteBuffer src) {
+ red = src.get();
+ green = src.get();
+ blue = src.get();
+ }
+
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ public void readARGB(ByteBuffer src) {
+ alpha = src.get();
+ red = src.get();
+ green = src.get();
+ blue = src.get();
+ }
+
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ public void readBGRA(ByteBuffer src) {
+ blue = src.get();
+ green = src.get();
+ red = src.get();
+ alpha = src.get();
+ }
+
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ public void readBGR(ByteBuffer src) {
+ blue = src.get();
+ green = src.get();
+ red = src.get();
+ }
+
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ public void readABGR(ByteBuffer src) {
+ alpha = src.get();
+ blue = src.get();
+ green = src.get();
+ red = src.get();
+ }
+
+ /**
+ * Set this color's color by copying another color
+ * @param src The source color
+ */
+ public void setColor(ReadableColor src) {
+ red = src.getRedByte();
+ green = src.getGreenByte();
+ blue = src.getBlueByte();
+ alpha = src.getAlphaByte();
+ }
+
+ /**
+ * HSB to RGB conversion, pinched from java.awt.Color.
+ * @param hue (0..1.0f)
+ * @param saturation (0..1.0f)
+ * @param brightness (0..1.0f)
+ */
+ public void fromHSB(float hue, float saturation, float brightness) {
+ if (saturation == 0.0F) {
+ red = green = blue = (byte) (brightness * 255F + 0.5F);
+ } else {
+ float f3 = (hue - (float) Math.floor(hue)) * 6F;
+ float f4 = f3 - (float) Math.floor(f3);
+ float f5 = brightness * (1.0F - saturation);
+ float f6 = brightness * (1.0F - saturation * f4);
+ float f7 = brightness * (1.0F - saturation * (1.0F - f4));
+ switch ((int) f3) {
+ case 0 :
+ red = (byte) (brightness * 255F + 0.5F);
+ green = (byte) (f7 * 255F + 0.5F);
+ blue = (byte) (f5 * 255F + 0.5F);
+ break;
+ case 1 :
+ red = (byte) (f6 * 255F + 0.5F);
+ green = (byte) (brightness * 255F + 0.5F);
+ blue = (byte) (f5 * 255F + 0.5F);
+ break;
+ case 2 :
+ red = (byte) (f5 * 255F + 0.5F);
+ green = (byte) (brightness * 255F + 0.5F);
+ blue = (byte) (f7 * 255F + 0.5F);
+ break;
+ case 3 :
+ red = (byte) (f5 * 255F + 0.5F);
+ green = (byte) (f6 * 255F + 0.5F);
+ blue = (byte) (brightness * 255F + 0.5F);
+ break;
+ case 4 :
+ red = (byte) (f7 * 255F + 0.5F);
+ green = (byte) (f5 * 255F + 0.5F);
+ blue = (byte) (brightness * 255F + 0.5F);
+ break;
+ case 5 :
+ red = (byte) (brightness * 255F + 0.5F);
+ green = (byte) (f5 * 255F + 0.5F);
+ blue = (byte) (f6 * 255F + 0.5F);
+ break;
+ }
+ }
+ }
+
+ /**
+ * RGB to HSB conversion, pinched from java.awt.Color.
+ * The HSB value is returned in dest[] if dest[] is supplied.
+ * Values range from 0..1
+ * @param dest Destination floats, or null
+ * @return dest, or a new float array
+ */
+ public float[] toHSB(float dest[]) {
+ int r = getRed();
+ int g = getGreen();
+ int b = getBlue();
+ if (dest == null)
+ dest = new float[3];
+ int l = r <= g ? g : r;
+ if (b > l)
+ l = b;
+ int i1 = r >= g ? g : r;
+ if (b < i1)
+ i1 = b;
+ float brightness = l / 255F;
+ float saturation;
+ if (l != 0)
+ saturation = (float) (l - i1) / (float) l;
+ else
+ saturation = 0.0F;
+ float hue;
+ if (saturation == 0.0F) {
+ hue = 0.0F;
+ } else {
+ float f3 = (float) (l - r) / (float) (l - i1);
+ float f4 = (float) (l - g) / (float) (l - i1);
+ float f5 = (float) (l - b) / (float) (l - i1);
+ if (r == l)
+ hue = f5 - f4;
+ else if (g == l)
+ hue = (2.0F + f3) - f5;
+ else
+ hue = (4F + f4) - f3;
+ hue /= 6F;
+ if (hue < 0.0F)
+ hue++;
+ }
+ dest[0] = hue;
+ dest[1] = saturation;
+ dest[2] = brightness;
+ return dest;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/Dimension.java b/src/de/verschwiegener/lwjgl3/util/Dimension.java
new file mode 100644
index 0000000..7e8b7f3
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/Dimension.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import java.io.Serializable;
+
+/**
+ * A 2D integer Dimension class, which looks remarkably like an AWT one.
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public final class Dimension implements Serializable, ReadableDimension, WritableDimension {
+
+ static final long serialVersionUID = 1L;
+
+ /** The dimensions! */
+ private int width, height;
+
+ /**
+ * Constructor for Dimension.
+ */
+ public Dimension() {
+ super();
+ }
+
+ /**
+ * Constructor for Dimension.
+ */
+ public Dimension(int w, int h) {
+ this.width = w;
+ this.height = h;
+ }
+
+ /**
+ * Constructor for Dimension.
+ */
+ public Dimension(ReadableDimension d) {
+ setSize(d);
+ }
+
+ public void setSize(int w, int h) {
+ this.width = w;
+ this.height = h;
+ }
+
+ public void setSize(ReadableDimension d) {
+ this.width = d.getWidth();
+ this.height = d.getHeight();
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableDimension#getSize(com.shavenpuppy.jglib.Dimension)
+ */
+ public void getSize(WritableDimension dest) {
+ dest.setSize(this);
+ }
+
+ /**
+ * Checks whether two dimension objects have equal values.
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof ReadableDimension) {
+ ReadableDimension d = (ReadableDimension) obj;
+ return (width == d.getWidth()) && (height == d.getHeight());
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hash code for this Dimension
.
+ *
+ * @return a hash code for this Dimension
+ */
+ public int hashCode() {
+ int sum = width + height;
+ return sum * (sum + 1) / 2 + width;
+ }
+
+ /**
+ * Returns a string representation of the values of this
+ * Dimension
object's height
and
+ * width
fields. This method is intended to be used only
+ * for debugging purposes, and the content and format of the returned
+ * string may vary between implementations. The returned string may be
+ * empty but may not be null
.
+ *
+ * @return a string representation of this Dimension
+ * object
+ */
+ public String toString() {
+ return getClass().getName() + "[width=" + width + ",height=" + height + "]";
+ }
+
+ /**
+ * Gets the height.
+ * @return Returns a int
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the height.
+ * @param height The height to set
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ /**
+ * Gets the width.
+ * @return Returns a int
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the width.
+ * @param width The width to set
+ */
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/IOUtil.java b/src/de/verschwiegener/lwjgl3/util/IOUtil.java
new file mode 100644
index 0000000..1f2a08d
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/IOUtil.java
@@ -0,0 +1,68 @@
+package de.verschwiegener.lwjgl3.util;
+
+import org.lwjgl.*;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.*;
+
+import static org.lwjgl.BufferUtils.*;
+import static org.lwjgl.system.MemoryUtil.*;
+
+public class IOUtil {
+
+ private IOUtil() {
+ }
+
+ private static ByteBuffer resizeBuffer(ByteBuffer buffer, int newCapacity) {
+ ByteBuffer newBuffer = BufferUtils.createByteBuffer(newCapacity);
+ buffer.flip();
+ newBuffer.put(buffer);
+ return newBuffer;
+ }
+
+ /**
+ * Reads the specified resource and returns the raw data as a ByteBuffer.
+ *
+ * @param resource the resource to read
+ * @param bufferSize the initial buffer size
+ *
+ * @return the resource data
+ *
+ * @throws IOException if an IO error occurs
+ */
+ public static ByteBuffer ioResourceToByteBuffer(String resource, int bufferSize) throws IOException {
+ ByteBuffer buffer;
+
+ Path path = Paths.get(resource);
+ if (Files.isReadable(path)) {
+ try (SeekableByteChannel fc = Files.newByteChannel(path)) {
+ buffer = BufferUtils.createByteBuffer((int)fc.size() + 1);
+ while (fc.read(buffer) != -1) {
+ ;
+ }
+ }
+ } else {
+ try (
+ InputStream source = IOUtil.class.getClassLoader().getResourceAsStream(resource);
+ ReadableByteChannel rbc = Channels.newChannel(source)
+ ) {
+ buffer = createByteBuffer(bufferSize);
+
+ while (true) {
+ int bytes = rbc.read(buffer);
+ if (bytes == -1) {
+ break;
+ }
+ if (buffer.remaining() == 0) {
+ buffer = resizeBuffer(buffer, buffer.capacity() * 3 / 2); // 50%
+ }
+ }
+ }
+ }
+
+ buffer.flip();
+ return memSlice(buffer);
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/Point.java b/src/de/verschwiegener/lwjgl3/util/Point.java
new file mode 100644
index 0000000..0c8bb29
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/Point.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import java.io.Serializable;
+
+/**
+ * A 2D integer point class, which looks remarkably like an AWT one.
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public final class Point implements ReadablePoint, WritablePoint, Serializable {
+
+ static final long serialVersionUID = 1L;
+
+ /** The location */
+ private int x, y;
+
+ /**
+ * Constructor for Point.
+ */
+ public Point() {
+ super();
+ }
+
+ /**
+ * Constructor for Point.
+ */
+ public Point(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Constructor for Point.
+ */
+ public Point(ReadablePoint p) {
+ setLocation(p);
+ }
+
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public void setLocation(ReadablePoint p) {
+ this.x = p.getX();
+ this.y = p.getY();
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+
+ /**
+ * Translate a point.
+ * @param dx The translation to apply
+ * @param dy The translation to apply
+ */
+ public void translate(int dx, int dy) {
+ this.x += dx;
+ this.y += dy;
+ }
+
+ /**
+ * Translate a point.
+ * @param p The translation to apply
+ */
+ public void translate(ReadablePoint p) {
+ this.x += p.getX();
+ this.y += p.getY();
+ }
+
+ /**
+ * Un-translate a point.
+ * @param p The translation to apply
+ */
+ public void untranslate(ReadablePoint p) {
+ this.x -= p.getX();
+ this.y -= p.getY();
+ }
+
+ /**
+ * Determines whether an instance of Point2D
is equal
+ * to this point. Two instances of Point2D
are equal if
+ * the values of their x
and y
member
+ * fields, representing their position in the coordinate space, are
+ * the same.
+ * @param obj an object to be compared with this point
+ * @return true
if the object to be compared is
+ * an instance of Point
and has
+ * the same values; false
otherwise
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof Point) {
+ Point pt = (Point) obj;
+ return (x == pt.x) && (y == pt.y);
+ }
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns a string representation of this point and its location
+ * in the (x, y) coordinate space. This method is
+ * intended to be used only for debugging purposes, and the content
+ * and format of the returned string may vary between implementations.
+ * The returned string may be empty but may not be null
.
+ *
+ * @return a string representation of this point
+ */
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]";
+ }
+
+ /**
+ * Returns the hash code for this Point
.
+ *
+ * @return a hash code for this Point
+ */
+ public int hashCode() {
+ int sum = x + y;
+ return sum * (sum + 1) / 2 + x;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public void getLocation(WritablePoint dest) {
+ dest.setLocation(x, y);
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/ReadableColor.java b/src/de/verschwiegener/lwjgl3/util/ReadableColor.java
new file mode 100644
index 0000000..8da4930
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/ReadableColor.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Readonly interface for Colors
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface ReadableColor {
+
+ /**
+ * Return the red component (0..255)
+ * @return int
+ */
+ int getRed();
+
+ /**
+ * Return the red component (0..255)
+ * @return int
+ */
+ int getGreen();
+
+ /**
+ * Return the red component (0..255)
+ * @return int
+ */
+ int getBlue();
+
+ /**
+ * Return the red component (0..255)
+ * @return int
+ */
+ int getAlpha();
+
+ /**
+ * Return the red component
+ * @return int
+ */
+ byte getRedByte();
+
+ /**
+ * Return the red component
+ * @return int
+ */
+ byte getGreenByte();
+
+ /**
+ * Return the red component
+ * @return int
+ */
+ byte getBlueByte();
+
+ /**
+ * Return the red component
+ * @return int
+ */
+ byte getAlphaByte();
+
+ /**
+ * Write the RGBA color directly out to a ByteBuffer
+ * @param dest the buffer to write to
+ */
+ void writeRGBA(ByteBuffer dest);
+
+ /**
+ * Write the RGB color directly out to a ByteBuffer
+ * @param dest the buffer to write to
+ */
+ void writeRGB(ByteBuffer dest);
+
+ /**
+ * Write the ABGR color directly out to a ByteBuffer
+ * @param dest the buffer to write to
+ */
+ void writeABGR(ByteBuffer dest);
+
+ /**
+ * Write the BGR color directly out to a ByteBuffer
+ * @param dest the buffer to write to
+ */
+ void writeBGR(ByteBuffer dest);
+
+ /**
+ * Write the BGRA color directly out to a ByteBuffer
+ * @param dest the buffer to write to
+ */
+ void writeBGRA(ByteBuffer dest);
+
+ /**
+ * Write the ARGB color directly out to a ByteBuffer
+ * @param dest the buffer to write to
+ */
+ void writeARGB(ByteBuffer dest);
+
+ /*
+ * Some standard colors
+ */
+ ReadableColor RED = new Color(255, 0, 0);
+ ReadableColor ORANGE = new Color(255, 128, 0);
+ ReadableColor YELLOW = new Color(255, 255, 0);
+ ReadableColor GREEN = new Color(0, 255, 0);
+ ReadableColor CYAN = new Color(0, 255, 255);
+ ReadableColor BLUE = new Color(0, 0, 255);
+ ReadableColor PURPLE = new Color(255, 0, 255);
+ ReadableColor WHITE = new Color(255, 255, 255);
+ ReadableColor BLACK = new Color(0, 0, 0);
+ ReadableColor LTGREY = new Color(192, 192, 192);
+ ReadableColor DKGREY = new Color(64, 64, 64);
+ ReadableColor GREY = new Color(128, 128, 128);
+
+
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/ReadableDimension.java b/src/de/verschwiegener/lwjgl3/util/ReadableDimension.java
new file mode 100644
index 0000000..1978006
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/ReadableDimension.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ * Readonly interface for Dimensions
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface ReadableDimension {
+
+ /**
+ * Get the width
+ * @return int
+ */
+ int getWidth();
+
+ /**
+ * Get the height
+ * @return int
+ */
+ int getHeight();
+
+ /**
+ * Copy this ReadableDimension into a destination Dimension
+ * @param dest The destination
+ */
+ void getSize(WritableDimension dest);
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/ReadablePoint.java b/src/de/verschwiegener/lwjgl3/util/ReadablePoint.java
new file mode 100644
index 0000000..a09f00e
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/ReadablePoint.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ * Readonly interface for Points
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface ReadablePoint {
+
+ /**
+ * @return int
+ */
+ int getX();
+
+ /**
+ * @return int
+ */
+ int getY();
+
+ /**
+ * Copy this ReadablePoint into a destination Point
+ * @param dest The destination Point, or null, to create a new Point
+ */
+ void getLocation(WritablePoint dest);
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/ReadableRectangle.java b/src/de/verschwiegener/lwjgl3/util/ReadableRectangle.java
new file mode 100644
index 0000000..7e52d1f
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/ReadableRectangle.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ * Readonly interface for Rectangles
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface ReadableRectangle extends ReadableDimension, ReadablePoint {
+
+ /**
+ * Copy this readable rectangle's bounds into a destination Rectangle
+ * @param dest The destination Rectangle, or null, to create a new Rectangle
+ */
+ void getBounds(WritableRectangle dest);
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/Rectangle.java b/src/de/verschwiegener/lwjgl3/util/Rectangle.java
new file mode 100644
index 0000000..2ff576b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/Rectangle.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import java.io.Serializable;
+
+/**
+ * A 2D integer Rectangle class which looks remarkably like an AWT one.
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public final class Rectangle implements ReadableRectangle, WritableRectangle, Serializable {
+
+ static final long serialVersionUID = 1L;
+
+ /** Rectangle's bounds */
+ private int x, y, width, height;
+
+ /**
+ * Constructor for Rectangle.
+ */
+ public Rectangle() {
+ super();
+ }
+ /**
+ * Constructor for Rectangle.
+ */
+ public Rectangle(int x, int y, int w, int h) {
+ this.x = x;
+ this.y = y;
+ this.width = w;
+ this.height = h;
+ }
+ /**
+ * Constructor for Rectangle.
+ */
+ public Rectangle(ReadablePoint p, ReadableDimension d) {
+ x = p.getX();
+ y = p.getY();
+ width = d.getWidth();
+ height = d.getHeight();
+ }
+ /**
+ * Constructor for Rectangle.
+ */
+ public Rectangle(ReadableRectangle r) {
+ x = r.getX();
+ y = r.getY();
+ width = r.getWidth();
+ height = r.getHeight();
+ }
+
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public void setLocation(ReadablePoint p) {
+ this.x = p.getX();
+ this.y = p.getY();
+ }
+
+ public void setSize(int w, int h) {
+ this.width = w;
+ this.height = h;
+ }
+
+ public void setSize(ReadableDimension d) {
+ this.width = d.getWidth();
+ this.height = d.getHeight();
+ }
+
+ public void setBounds(int x, int y, int w, int h) {
+ this.x = x;
+ this.y = y;
+ this.width = w;
+ this.height = h;
+ }
+
+ public void setBounds(ReadablePoint p, ReadableDimension d) {
+ x = p.getX();
+ y = p.getY();
+ width = d.getWidth();
+ height = d.getHeight();
+ }
+
+ public void setBounds(ReadableRectangle r) {
+ x = r.getX();
+ y = r.getY();
+ width = r.getWidth();
+ height = r.getHeight();
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableRectangle#getBounds(com.shavenpuppy.jglib.Rectangle)
+ */
+ public void getBounds(WritableRectangle dest) {
+ dest.setBounds(x, y, width, height);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadablePoint#getLocation(com.shavenpuppy.jglib.Point)
+ */
+ public void getLocation(WritablePoint dest) {
+ dest.setLocation(x, y);
+ }
+
+ /* (Overrides)
+ * @see com.shavenpuppy.jglib.ReadableDimension#getSize(com.shavenpuppy.jglib.Dimension)
+ */
+ public void getSize(WritableDimension dest) {
+ dest.setSize(width, height);
+ }
+
+ /**
+ * Translate the rectangle by an amount.
+ * @param x The translation amount on the x axis
+ * @param y The translation amount on the y axis
+ */
+ public void translate(int x, int y) {
+ this.x += x;
+ this.y += y;
+ }
+
+ /**
+ * Translate the rectangle by an amount.
+ * @param point The translation amount
+ */
+ public void translate(ReadablePoint point) {
+ this.x += point.getX();
+ this.y += point.getY();
+ }
+
+ /**
+ * Un-translate the rectangle by an amount.
+ * @param point The translation amount
+ */
+ public void untranslate(ReadablePoint point) {
+ this.x -= point.getX();
+ this.y -= point.getY();
+ }
+
+ /**
+ * Checks whether or not this Rectangle
contains the
+ * specified Point
.
+ * @param p the Point
to test
+ * @return true
if the Point
+ * (x, y) is inside this
+ * Rectangle
;
+ * false
otherwise.
+ */
+ public boolean contains(ReadablePoint p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ /**
+ * Checks whether or not this Rectangle
contains the
+ * point at the specified location
+ * (x, y).
+ * @param X the specified x coordinate
+ * @param Y the specified y coordinate
+ * @return true
if the point
+ * (x, y) is inside this
+ * Rectangle
;
+ * false
otherwise.
+ */
+ public boolean contains(int X, int Y) {
+ int w = this.width;
+ int h = this.height;
+ if ((w | h) < 0) {
+ // At least one of the dimensions is negative...
+ return false;
+ }
+ // Note: if either dimension is zero, tests below must return false...
+ int x = this.x;
+ int y = this.y;
+ if (X < x || Y < y) {
+ return false;
+ }
+ w += x;
+ h += y;
+ // overflow || intersect
+ return ((w < x || w > X) && (h < y || h > Y));
+ }
+
+ /**
+ * Checks whether or not this Rectangle
entirely contains
+ * the specified Rectangle
.
+ * @param r the specified Rectangle
+ * @return true
if the Rectangle
+ * is contained entirely inside this Rectangle
;
+ * false
otherwise.
+ */
+ public boolean contains(ReadableRectangle r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ /**
+ * Checks whether this Rectangle
entirely contains
+ * the Rectangle
+ * at the specified location (X, Y) with the
+ * specified dimensions (W, H).
+ * @param X the specified x coordinate
+ * @param Y the specified y coordinate
+ * @param W the width of the Rectangle
+ * @param H the height of the Rectangle
+ * @return true
if the Rectangle
specified by
+ * (X, Y, W, H)
+ * is entirely enclosed inside this Rectangle
;
+ * false
otherwise.
+ */
+ public boolean contains(int X, int Y, int W, int H) {
+ int w = this.width;
+ int h = this.height;
+ if ((w | h | W | H) < 0) {
+ // At least one of the dimensions is negative...
+ return false;
+ }
+ // Note: if any dimension is zero, tests below must return false...
+ int x = this.x;
+ int y = this.y;
+ if (X < x || Y < y) {
+ return false;
+ }
+ w += x;
+ W += X;
+ if (W <= X) {
+ // X+W overflowed or W was zero, return false if...
+ // either original w or W was zero or
+ // x+w did not overflow or
+ // the overflowed x+w is smaller than the overflowed X+W
+ if (w >= x || W > w)
+ return false;
+ } else {
+ // X+W did not overflow and W was not zero, return false if...
+ // original w was zero or
+ // x+w did not overflow and x+w is smaller than X+W
+ if (w >= x && W > w)
+ return false;
+ }
+ h += y;
+ H += Y;
+ if (H <= Y) {
+ if (h >= y || H > h)
+ return false;
+ } else {
+ if (h >= y && H > h)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determines whether or not this Rectangle
and the specified
+ * Rectangle
intersect. Two rectangles intersect if
+ * their intersection is nonempty.
+ *
+ * @param r the specified Rectangle
+ * @return true
if the specified Rectangle
+ * and this Rectangle
intersect;
+ * false
otherwise.
+ */
+ public boolean intersects(ReadableRectangle r) {
+ int tw = this.width;
+ int th = this.height;
+ int rw = r.getWidth();
+ int rh = r.getHeight();
+ if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
+ return false;
+ }
+ int tx = this.x;
+ int ty = this.y;
+ int rx = r.getX();
+ int ry = r.getY();
+ rw += rx;
+ rh += ry;
+ tw += tx;
+ th += ty;
+ // overflow || intersect
+ return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry));
+ }
+
+ /**
+ * Computes the intersection of this Rectangle
with the
+ * specified Rectangle
. Returns a new Rectangle
+ * that represents the intersection of the two rectangles.
+ * If the two rectangles do not intersect, the result will be
+ * an empty rectangle.
+ *
+ * @param r the specified Rectangle
+ * @return the largest Rectangle
contained in both the
+ * specified Rectangle
and in
+ * this Rectangle
; or if the rectangles
+ * do not intersect, an empty rectangle.
+ */
+ public Rectangle intersection(ReadableRectangle r, Rectangle dest) {
+ int tx1 = this.x;
+ int ty1 = this.y;
+ int rx1 = r.getX();
+ int ry1 = r.getY();
+ long tx2 = tx1;
+ tx2 += this.width;
+ long ty2 = ty1;
+ ty2 += this.height;
+ long rx2 = rx1;
+ rx2 += r.getWidth();
+ long ry2 = ry1;
+ ry2 += r.getHeight();
+ if (tx1 < rx1)
+ tx1 = rx1;
+ if (ty1 < ry1)
+ ty1 = ry1;
+ if (tx2 > rx2)
+ tx2 = rx2;
+ if (ty2 > ry2)
+ ty2 = ry2;
+ tx2 -= tx1;
+ ty2 -= ty1;
+ // tx2,ty2 will never overflow (they will never be
+ // larger than the smallest of the two source w,h)
+ // they might underflow, though...
+ if (tx2 < Integer.MIN_VALUE)
+ tx2 = Integer.MIN_VALUE;
+ if (ty2 < Integer.MIN_VALUE)
+ ty2 = Integer.MIN_VALUE;
+ if (dest == null)
+ dest = new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
+ else
+ dest.setBounds(tx1, ty1, (int) tx2, (int) ty2);
+ return dest;
+
+ }
+
+ /**
+ * Computes the union of this Rectangle
with the
+ * specified Rectangle
. Returns a new
+ * Rectangle
that
+ * represents the union of the two rectangles
+ * @param r the specified Rectangle
+ * @return the smallest Rectangle
containing both
+ * the specified Rectangle
and this
+ * Rectangle
.
+ */
+ public WritableRectangle union(ReadableRectangle r, WritableRectangle dest) {
+ int x1 = Math.min(x, r.getX());
+ int x2 = Math.max(x + width, r.getX() + r.getWidth());
+ int y1 = Math.min(y, r.getY());
+ int y2 = Math.max(y + height, r.getY() + r.getHeight());
+ dest.setBounds(x1, y1, x2 - x1, y2 - y1);
+ return dest;
+ }
+
+ /**
+ * Adds a point, specified by the integer arguments newx
+ * and newy
, to this Rectangle
. The
+ * resulting Rectangle
is
+ * the smallest Rectangle
that contains both the
+ * original Rectangle
and the specified point.
+ *
+ * After adding a point, a call to contains
with the
+ * added point as an argument does not necessarily return
+ * true
. The contains
method does not
+ * return true
for points on the right or bottom
+ * edges of a Rectangle
. Therefore, if the added point
+ * falls on the right or bottom edge of the enlarged
+ * Rectangle
, contains
returns
+ * false
for that point.
+ * @param newx the x coordinates of the new point
+ * @param newy the y coordinates of the new point
+ */
+ public void add(int newx, int newy) {
+ int x1 = Math.min(x, newx);
+ int x2 = Math.max(x + width, newx);
+ int y1 = Math.min(y, newy);
+ int y2 = Math.max(y + height, newy);
+ x = x1;
+ y = y1;
+ width = x2 - x1;
+ height = y2 - y1;
+ }
+
+ /**
+ * Adds the specified Point
to this
+ * Rectangle
. The resulting Rectangle
+ * is the smallest Rectangle
that contains both the
+ * original Rectangle
and the specified
+ * Point
.
+ *
+ * After adding a Point
, a call to contains
+ * with the added Point
as an argument does not
+ * necessarily return true
. The contains
+ * method does not return true
for points on the right
+ * or bottom edges of a Rectangle
. Therefore if the added
+ * Point
falls on the right or bottom edge of the
+ * enlarged Rectangle
, contains
returns
+ * false
for that Point
.
+ * @param pt the new Point
to add to this
+ * Rectangle
+ */
+ public void add(ReadablePoint pt) {
+ add(pt.getX(), pt.getY());
+ }
+
+ /**
+ * Adds a Rectangle
to this Rectangle
.
+ * The resulting Rectangle
is the union of the two
+ * rectangles.
+ * @param r the specified Rectangle
+ */
+ public void add(ReadableRectangle r) {
+ int x1 = Math.min(x, r.getX());
+ int x2 = Math.max(x + width, r.getX() + r.getWidth());
+ int y1 = Math.min(y, r.getY());
+ int y2 = Math.max(y + height, r.getY() + r.getHeight());
+ x = x1;
+ y = y1;
+ width = x2 - x1;
+ height = y2 - y1;
+ }
+
+ /**
+ * Resizes the Rectangle
both horizontally and vertically.
+ *
+ * This method modifies the Rectangle
so that it is
+ * h
units larger on both the left and right side,
+ * and v
units larger at both the top and bottom.
+ *
+ * The new Rectangle
has (x - h
,
+ * y - v
) as its top-left corner, a
+ * width of
+ * width
+
2h
,
+ * and a height of
+ * height
+
2v
.
+ *
+ * If negative values are supplied for h
and
+ * v
, the size of the Rectangle
+ * decreases accordingly.
+ * The grow
method does not check whether the resulting
+ * values of width
and height
are
+ * non-negative.
+ * @param h the horizontal expansion
+ * @param v the vertical expansion
+ */
+ public void grow(int h, int v) {
+ x -= h;
+ y -= v;
+ width += h * 2;
+ height += v * 2;
+ }
+
+ /**
+ * Determines whether or not this Rectangle
is empty. A
+ * Rectangle
is empty if its width or its height is less
+ * than or equal to zero.
+ * @return true
if this Rectangle
is empty;
+ * false
otherwise.
+ */
+ public boolean isEmpty() {
+ return (width <= 0) || (height <= 0);
+ }
+ /**
+ * Checks whether two rectangles are equal.
+ *
+ * The result is true
if and only if the argument is not
+ * null
and is a Rectangle
object that has the
+ * same top-left corner, width, and height as this Rectangle
.
+ * @param obj the Object
to compare with
+ * this Rectangle
+ * @return true
if the objects are equal;
+ * false
otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof Rectangle) {
+ Rectangle r = (Rectangle) obj;
+ return ((x == r.x) && (y == r.y) && (width == r.width) && (height == r.height));
+ }
+ return super.equals(obj);
+ }
+
+ /**
+ * Debugging
+ * @return a String
+ */
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
+ }
+ /**
+ * Gets the height.
+ * @return Returns a int
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the height.
+ * @param height The height to set
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ /**
+ * Gets the width.
+ * @return Returns a int
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the width.
+ * @param width The width to set
+ */
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ /**
+ * Gets the x.
+ * @return Returns a int
+ */
+ public int getX() {
+ return x;
+ }
+
+ /**
+ * Sets the x.
+ * @param x The x to set
+ */
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ /**
+ * Gets the y.
+ * @return Returns a int
+ */
+ public int getY() {
+ return y;
+ }
+
+ /**
+ * Sets the y.
+ * @param y The y to set
+ */
+ public void setY(int y) {
+ this.y = y;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/Renderable.java b/src/de/verschwiegener/lwjgl3/util/Renderable.java
new file mode 100644
index 0000000..18dad98
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/Renderable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ *
+ * Simple interface to things that can be Rendered.
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface Renderable {
+
+ /**
+ * "Render" this thing. This will involve calls to the GL.
+ */
+ void render();
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/Timer.java b/src/de/verschwiegener/lwjgl3/util/Timer.java
new file mode 100644
index 0000000..b1f713a
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/Timer.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import de.verschwiegener.lwjgl3.Sys;
+
+/**
+ *
+ * A hires timer. This measures time in seconds as floating point values.
+ * All Timers created are updated simultaneously by calling the static method
+ * tick(). This ensures that within a single iteration of a game loop that
+ * all timers are updated consistently with each other.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+public class Timer {
+
+ // Record the timer resolution on classload
+ private static long resolution = Sys.getTimerResolution();
+
+ // Every so often we will re-query the timer resolution
+ private static final int QUERY_INTERVAL = 50; // in calls to tick()
+ private static int queryCount;
+
+ // Globally keeps track of time for all instances of Timer
+ private static long currentTime;
+
+ // When the timer was started
+ private long startTime;
+
+ // The last time recorded by getTime()
+ private long lastTime;
+
+ // Whether the timer is paused
+ private boolean paused;
+
+ static {
+ tick();
+ }
+
+ /**
+ * Constructs a timer. The timer will be reset to 0.0 and resumed immediately.
+ */
+ public Timer() {
+ reset();
+ resume();
+ }
+
+ /**
+ * @return the time in seconds, as a float
+ */
+ public float getTime() {
+ if (!paused) {
+ lastTime = currentTime - startTime;
+ }
+
+ return (float) ((double) lastTime / (double) resolution);
+ }
+ /**
+ * @return whether this timer is paused
+ */
+ public boolean isPaused() {
+ return paused;
+ }
+
+ /**
+ * Pause the timer. Whilst paused the time will not change for this timer
+ * when tick() is called.
+ *
+ * @see #resume()
+ */
+ public void pause() {
+ paused = true;
+ }
+
+ /**
+ * Reset the timer. Equivalent to set(0.0f);
+ * @see #set(float)
+ */
+ public void reset() {
+ set(0.0f);
+ }
+
+ /**
+ * Resume the timer.
+ * @see #pause()
+ */
+ public void resume() {
+ paused = false;
+ startTime = currentTime - lastTime;
+ }
+
+ /**
+ * Set the time of this timer
+ * @param newTime the new time, in seconds
+ */
+ public void set(float newTime) {
+ long newTimeInTicks = (long) ((double) newTime * (double) resolution);
+ startTime = currentTime - newTimeInTicks;
+ lastTime = newTimeInTicks;
+ }
+
+ /**
+ * Get the next time update from the system's hires timer. This method should
+ * be called once per main loop iteration; all timers are updated simultaneously
+ * from it.
+ */
+ public static void tick() {
+ currentTime = Sys.getTime();
+
+ // Periodically refresh the timer resolution:
+ queryCount ++;
+ if (queryCount > QUERY_INTERVAL) {
+ queryCount = 0;
+ resolution = Sys.getTimerResolution();
+ }
+ }
+
+ /**
+ * Debug output.
+ */
+ public String toString() {
+ return "Timer[Time=" + getTime() + ", Paused=" + paused + "]";
+ }
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/WritableColor.java b/src/de/verschwiegener/lwjgl3/util/WritableColor.java
new file mode 100644
index 0000000..4615532
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/WritableColor.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Write interface for Colors
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface WritableColor {
+ /**
+ * Set a color
+ */
+ void set(int r, int g, int b, int a);
+ /**
+ * Set a color
+ */
+ void set(byte r, byte g, byte b, byte a);
+ /**
+ * Set a color
+ */
+ void set(int r, int g, int b);
+ /**
+ * Set a color
+ */
+ void set(byte r, byte g, byte b);
+ /**
+ * Set the Red component
+ */
+ void setRed(int red);
+ /**
+ * Set the Green component
+ */
+ void setGreen(int green);
+ /**
+ * Set the Blue component
+ */
+ void setBlue(int blue);
+ /**
+ * Set the Alpha component
+ */
+ void setAlpha(int alpha);
+ /**
+ * Set the Red component
+ */
+ void setRed(byte red);
+ /**
+ * Set the Green component
+ */
+ void setGreen(byte green);
+ /**
+ * Set the Blue component
+ */
+ void setBlue(byte blue);
+ /**
+ * Set the Alpha component
+ */
+ void setAlpha(byte alpha);
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ void readRGBA(ByteBuffer src);
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ void readRGB(ByteBuffer src);
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ void readARGB(ByteBuffer src);
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ void readBGRA(ByteBuffer src);
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ void readBGR(ByteBuffer src);
+ /**
+ * Read a color from a byte buffer
+ * @param src The source buffer
+ */
+ void readABGR(ByteBuffer src);
+ /**
+ * Set this color's color by copying another color
+ * @param src The source color
+ */
+ void setColor(ReadableColor src);
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/WritableDimension.java b/src/de/verschwiegener/lwjgl3/util/WritableDimension.java
new file mode 100644
index 0000000..d69c24b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/WritableDimension.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ * Write interface for Dimensions
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+
+ */
+public interface WritableDimension {
+ void setSize(int w, int h);
+ void setSize(ReadableDimension d);
+ /**
+ * Sets the height.
+ * @param height The height to set
+ */
+ void setHeight(int height);
+ /**
+ * Sets the width.
+ * @param width The width to set
+ */
+ void setWidth(int width);
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/WritablePoint.java b/src/de/verschwiegener/lwjgl3/util/WritablePoint.java
new file mode 100644
index 0000000..795f4e2
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/WritablePoint.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ * Write interface for Points
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface WritablePoint {
+ void setLocation(int x, int y);
+ void setLocation(ReadablePoint p);
+ void setX(int x);
+ void setY(int y);
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/WritableRectangle.java b/src/de/verschwiegener/lwjgl3/util/WritableRectangle.java
new file mode 100644
index 0000000..e311598
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/WritableRectangle.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+/**
+ * Write interface for Rectangles
+ * @author $Author$
+ * @version $Revision$
+ * $Id$
+ */
+public interface WritableRectangle extends WritablePoint, WritableDimension {
+
+ /**
+ * Sets the bounds of the rectangle
+ * @param x Position of rectangle on x axis
+ * @param y Position of rectangle on y axis
+ * @param width Width of rectangle
+ * @param height Height of rectangle
+ */
+ void setBounds(int x, int y, int width, int height);
+
+ /**
+ * Sets the bounds of the rectangle
+ * @param location
+ * @param size
+ */
+ void setBounds(ReadablePoint location, ReadableDimension size);
+
+ /**
+ * Sets the bounds of the rectangle
+ * @param src
+ */
+ void setBounds(ReadableRectangle src);
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/XPMFile.java b/src/de/verschwiegener/lwjgl3/util/XPMFile.java
new file mode 100644
index 0000000..60f46e5
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/XPMFile.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+/**
+ *
+ * NOTE: This simple XPM reader does not support extensions nor hotspots
+ *
+ *
+ * @author Brian Matzon
+ * @author Jos Hirth
+ * @version $Revision$
+ * $Id$
+ */
+
+public class XPMFile {
+
+ /** Array of bytes (RGBA) */
+ private byte bytes[];
+
+ private static final int WIDTH = 0;
+
+ private static final int HEIGHT = 1;
+
+ private static final int NUMBER_OF_COLORS = 2;
+
+ private static final int CHARACTERS_PER_PIXEL = 3;
+
+ private static int[] format = new int[4];
+
+ /*
+ * Private constructor, use load(String filename)
+ */
+ private XPMFile() {
+ }
+
+ /**
+ * Loads the XPM file
+ *
+ * @param file
+ * path to file
+ * @return XPMFile loaded, or exception
+ * @throws IOException
+ * If any IO exceptions occurs while reading file
+ */
+ public static XPMFile load(String file) throws IOException {
+ return load(new FileInputStream(new File(file)));
+ }
+
+ /**
+ * Loads the XPM file
+ *
+ * @param is
+ * InputStream to read file from
+ * @return XPMFile loaded, or exception
+ */
+ public static XPMFile load(InputStream is) {
+ XPMFile xFile = new XPMFile();
+ xFile.readImage(is);
+ return xFile;
+ }
+
+ /**
+ * @return the height of the image.
+ */
+ public int getHeight() {
+ return format[HEIGHT];
+ }
+
+ /**
+ * @return the width of the image.
+ */
+ public int getWidth() {
+ return format[WIDTH];
+ }
+
+ /**
+ * @return The data of the image.
+ */
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ /**
+ * Read the image from the specified file.
+ */
+ private void readImage(InputStream is) {
+ try {
+ LineNumberReader reader = new LineNumberReader(
+ new InputStreamReader(is));
+ HashMap colors = new HashMap();
+
+ format = parseFormat(nextLineOfInterest(reader));
+
+ // setup color mapping
+ for (int i = 0; i < format[NUMBER_OF_COLORS]; i++) {
+ Object[] colorDefinition = parseColor(nextLineOfInterest(reader));
+ colors.put((String)colorDefinition[0], (Integer)colorDefinition[1]);
+ }
+
+ // read actual image (convert to RGBA)
+ bytes = new byte[format[WIDTH] * format[HEIGHT] * 4];
+ for (int i = 0; i < format[HEIGHT]; i++) {
+ parseImageLine(nextLineOfInterest(reader), format, colors, i);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("Unable to parse XPM File");
+ }
+ }
+
+ /**
+ * Finds the next interesting line of text.
+ *
+ * @param reader
+ * The LineNumberReader to read from
+ * @return The next interesting String (with stripped quotes)
+ * @throws IOException
+ * If any IO exceptions occurs while reading file
+ */
+ private static String nextLineOfInterest(LineNumberReader reader)
+ throws IOException {
+ String ret;
+ do {
+ ret = reader.readLine();
+ } while (!ret.startsWith("\""));
+ // lacks sanity check
+ return ret.substring(1, ret.lastIndexOf('\"'));
+ }
+
+ /**
+ * Parses the format of the xpm file given a format string
+ *
+ * @param format
+ * String to parse
+ * @return Array specifying width, height, colors, characters per pixel
+ */
+ private static int[] parseFormat(String format) {
+ // format should look like this:
+ // 16 16 122 2
+
+ // tokenize it
+ StringTokenizer st = new StringTokenizer(format);
+
+ return new int[] { Integer.parseInt(st.nextToken()), /* width */
+ Integer.parseInt(st.nextToken()), /* height */
+ Integer.parseInt(st.nextToken()), /* colors */
+ Integer.parseInt(st.nextToken()) /* chars per pixel */
+ };
+ }
+
+ /**
+ * Given a line defining a color/pixel, parses this into an array containing
+ * a key and a color
+ *
+ * @param line
+ * Line to parse
+ * @return Array containing a key (String) and a color (Integer)
+ */
+ private static Object[] parseColor(String line) {
+ // line should look like this:
+ // # c #0A0A0A
+
+ // NOTE: will break if the color is something like "black" or "gray50"
+ // etc (instead of #rrggbb).
+
+ String key = line.substring(0, format[CHARACTERS_PER_PIXEL]);
+ // since we always assume color as type we dont need to read it
+ // String type = line.substring(format[CHARACTERS_PER_PIXEL] + 1,
+ // format[CHARACTERS_PER_PIXEL] + 2);
+ String color = line.substring(format[CHARACTERS_PER_PIXEL] + 4);
+
+ // we always assume type is color, and supplied as #
+ return new Object[] { key, Integer.parseInt(color, 16) };
+ }
+
+ /**
+ * Parses an Image line into its byte values
+ *
+ * @param line
+ * Line of chars to parse
+ * @param format
+ * Format to expext it in
+ * @param colors
+ * Colors to lookup
+ * @param index
+ * current index into lines, we've reached
+ */
+ private void parseImageLine(String line, int[] format, HashMap colors,
+ int index) {
+ // offset for next line
+ int offset = index * 4 * format[WIDTH];
+
+ // read characters times,
+ // each iteration equals one pixel
+ for (int i = 0; i < format[WIDTH]; i++) {
+ String key = line
+ .substring(
+ i * format[CHARACTERS_PER_PIXEL],
+ (i * format[CHARACTERS_PER_PIXEL] + format[CHARACTERS_PER_PIXEL]));
+ int color = colors.get(key);
+ bytes[offset + (i * 4)] = (byte) ((color & 0x00ff0000) >> 16);
+ bytes[offset + ((i * 4) + 1)] = (byte) ((color & 0x0000ff00) >> 8);
+ bytes[offset + ((i * 4) + 2)] = (byte) ((color & 0x000000ff) >> 0); // looks
+ // better
+ // :)
+ bytes[offset + ((i * 4) + 3)] = (byte) 0xff; // always 0xff alpha
+ }
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ System.out.println("usage:\nXPMFile ");
+ }
+
+ try {
+ String out = args[0].substring(0, args[0].indexOf(".")) + ".raw";
+ XPMFile file = XPMFile.load(args[0]);
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(new File(out)));
+ bos.write(file.getBytes());
+ bos.close();
+
+ // showResult(file.getBytes());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ /*
+ private static void showResult(byte[] bytes) {
+ final BufferedImage i = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
+ int c = 0;
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 16; x++) {
+ i.setRGB(x, y, (bytes[c] << 16) + (bytes[c + 1] << 8) + (bytes[c + 2] << 0) + (bytes[c + 3] << 24));//+(128<<24));//
+ c += 4;
+ }
+ }
+
+ final Frame frame = new Frame("XPM Result");
+ frame.add(new Canvas() {
+
+ public void paint(Graphics g) {
+ g.drawImage(i, 0, 0, frame);
+ }
+ });
+
+ frame.addWindowListener(new WindowAdapter() {
+
+ public void windowClosing(WindowEvent e) {
+ frame.dispose();
+ }
+
+ });
+
+ frame.setSize(100, 100);
+ frame.setVisible(true);
+ }*/
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Cylinder.java b/src/de/verschwiegener/lwjgl3/util/glu/Cylinder.java
new file mode 100644
index 0000000..e1666bd
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Cylinder.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * Cylinder.java
+ *
+ *
+ * Created 23-dec-2003
+ * @author Erik Duijs
+ */
+public class Cylinder extends Quadric {
+
+ /**
+ * Constructor for Cylinder.
+ */
+ public Cylinder() {
+ super();
+ }
+
+ /**
+ * draws a cylinder oriented along the z axis. The base of the
+ * cylinder is placed at z = 0, and the top at z=height. Like a sphere, a
+ * cylinder is subdivided around the z axis into slices, and along the z axis
+ * into stacks.
+ *
+ * Note that if topRadius is set to zero, then this routine will generate a
+ * cone.
+ *
+ * If the orientation is set to GLU.OUTSIDE (with glu.quadricOrientation), then
+ * any generated normals point away from the z axis. Otherwise, they point
+ * toward the z axis.
+ *
+ * If texturing is turned on (with glu.quadricTexture), then texture
+ * coordinates are generated so that t ranges linearly from 0.0 at z = 0 to
+ * 1.0 at z = height, and s ranges from 0.0 at the +y axis, to 0.25 at the +x
+ * axis, to 0.5 at the -y axis, to 0.75 at the -x axis, and back to 1.0 at the
+ * +y axis.
+ *
+ * @param baseRadius Specifies the radius of the cylinder at z = 0.
+ * @param topRadius Specifies the radius of the cylinder at z = height.
+ * @param height Specifies the height of the cylinder.
+ * @param slices Specifies the number of subdivisions around the z axis.
+ * @param stacks Specifies the number of subdivisions along the z axis.
+ */
+ public void draw(float baseRadius, float topRadius, float height, int slices, int stacks) {
+
+ float da, r, dr, dz;
+ float x, y, z, nz, nsign;
+ int i, j;
+
+ if (super.orientation == GLU_INSIDE) {
+ nsign = -1.0f;
+ } else {
+ nsign = 1.0f;
+ }
+
+ da = 2.0f * PI / slices;
+ dr = (topRadius - baseRadius) / stacks;
+ dz = height / stacks;
+ nz = (baseRadius - topRadius) / height;
+ // Z component of normal vectors
+
+ if (super.drawStyle == GLU_POINT) {
+ glBegin(GL_POINTS);
+ for (i = 0; i < slices; i++) {
+ x = cos((i * da));
+ y = sin((i * da));
+ normal3f(x * nsign, y * nsign, nz * nsign);
+
+ z = 0.0f;
+ r = baseRadius;
+ for (j = 0; j <= stacks; j++) {
+ glVertex3f((x * r), (y * r), z);
+ z += dz;
+ r += dr;
+ }
+ }
+ glEnd();
+ } else if (super.drawStyle == GLU_LINE || super.drawStyle == GLU_SILHOUETTE) {
+ // Draw rings
+ if (super.drawStyle == GLU_LINE) {
+ z = 0.0f;
+ r = baseRadius;
+ for (j = 0; j <= stacks; j++) {
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < slices; i++) {
+ x = cos((i * da));
+ y = sin((i * da));
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f((x * r), (y * r), z);
+ }
+ glEnd();
+ z += dz;
+ r += dr;
+ }
+ } else {
+ // draw one ring at each end
+ if (baseRadius != 0.0) {
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < slices; i++) {
+ x = cos((i * da));
+ y = sin((i * da));
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f((x * baseRadius), (y * baseRadius), 0.0f);
+ }
+ glEnd();
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < slices; i++) {
+ x = cos((i * da));
+ y = sin((i * da));
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f((x * topRadius), (y * topRadius), height);
+ }
+ glEnd();
+ }
+ }
+ // draw length lines
+ glBegin(GL_LINES);
+ for (i = 0; i < slices; i++) {
+ x = cos((i * da));
+ y = sin((i * da));
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ glVertex3f((x * baseRadius), (y * baseRadius), 0.0f);
+ glVertex3f((x * topRadius), (y * topRadius), (height));
+ }
+ glEnd();
+ } else if (super.drawStyle == GLU_FILL) {
+ float ds = 1.0f / slices;
+ float dt = 1.0f / stacks;
+ float t = 0.0f;
+ z = 0.0f;
+ r = baseRadius;
+ for (j = 0; j < stacks; j++) {
+ float s = 0.0f;
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= slices; i++) {
+ if (i == slices) {
+ x = sin(0.0f);
+ y = cos(0.0f);
+ } else {
+ x = sin((i * da));
+ y = cos((i * da));
+ }
+ if (nsign == 1.0f) {
+ normal3f((x * nsign), (y * nsign), (nz * nsign));
+ TXTR_COORD(s, t);
+ glVertex3f((x * r), (y * r), z);
+ normal3f((x * nsign), (y * nsign), (nz * nsign));
+ TXTR_COORD(s, t + dt);
+ glVertex3f((x * (r + dr)), (y * (r + dr)), (z + dz));
+ } else {
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ TXTR_COORD(s, t);
+ glVertex3f((x * r), (y * r), z);
+ normal3f(x * nsign, y * nsign, nz * nsign);
+ TXTR_COORD(s, t + dt);
+ glVertex3f((x * (r + dr)), (y * (r + dr)), (z + dz));
+ }
+ s += ds;
+ } // for slices
+ glEnd();
+ r += dr;
+ t += dt;
+ z += dz;
+ } // for stacks
+ }
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Disk.java b/src/de/verschwiegener/lwjgl3/util/glu/Disk.java
new file mode 100644
index 0000000..7093762
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Disk.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * Disk.java
+ *
+ *
+ * Created 23-dec-2003
+ * @author Erik Duijs
+ */
+public class Disk extends Quadric {
+
+ /**
+ * Constructor for Disk.
+ */
+ public Disk() {
+ super();
+ }
+
+ /**
+ * renders a disk on the z = 0 plane. The disk has a radius of
+ * outerRadius, and contains a concentric circular hole with a radius of
+ * innerRadius. If innerRadius is 0, then no hole is generated. The disk is
+ * subdivided around the z axis into slices (like pizza slices), and also
+ * about the z axis into rings (as specified by slices and loops,
+ * respectively).
+ *
+ * With respect to orientation, the +z side of the disk is considered to be
+ * "outside" (see glu.quadricOrientation). This means that if the orientation
+ * is set to GLU.OUTSIDE, then any normals generated point along the +z axis.
+ * Otherwise, they point along the -z axis.
+ *
+ * If texturing is turned on (with glu.quadricTexture), texture coordinates are
+ * generated linearly such that where r=outerRadius, the value at (r, 0, 0) is
+ * (1, 0.5), at (0, r, 0) it is (0.5, 1), at (-r, 0, 0) it is (0, 0.5), and at
+ * (0, -r, 0) it is (0.5, 0).
+ */
+ public void draw(float innerRadius, float outerRadius, int slices, int loops)
+ {
+ float da, dr;
+
+ /* Normal vectors */
+ if (super.normals != GLU_NONE) {
+ if (super.orientation == GLU_OUTSIDE) {
+ glNormal3f(0.0f, 0.0f, +1.0f);
+ }
+ else {
+ glNormal3f(0.0f, 0.0f, -1.0f);
+ }
+ }
+
+ da = 2.0f * PI / slices;
+ dr = (outerRadius - innerRadius) / loops;
+
+ switch (super.drawStyle) {
+ case GLU_FILL:
+ {
+ /* texture of a gluDisk is a cut out of the texture unit square
+ * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
+ * (linear mapping)
+ */
+ float dtc = 2.0f * outerRadius;
+ float sa, ca;
+ float r1 = innerRadius;
+ int l;
+ for (l = 0; l < loops; l++) {
+ float r2 = r1 + dr;
+ if (super.orientation == GLU_OUTSIDE) {
+ int s;
+ glBegin(GL_QUAD_STRIP);
+ for (s = 0; s <= slices; s++) {
+ float a;
+ if (s == slices)
+ a = 0.0f;
+ else
+ a = s * da;
+ sa = sin(a);
+ ca = cos(a);
+ TXTR_COORD(0.5f + sa * r2 / dtc, 0.5f + ca * r2 / dtc);
+ glVertex2f(r2 * sa, r2 * ca);
+ TXTR_COORD(0.5f + sa * r1 / dtc, 0.5f + ca * r1 / dtc);
+ glVertex2f(r1 * sa, r1 * ca);
+ }
+ glEnd();
+ }
+ else {
+ int s;
+ glBegin(GL_QUAD_STRIP);
+ for (s = slices; s >= 0; s--) {
+ float a;
+ if (s == slices)
+ a = 0.0f;
+ else
+ a = s * da;
+ sa = sin(a);
+ ca = cos(a);
+ TXTR_COORD(0.5f - sa * r2 / dtc, 0.5f + ca * r2 / dtc);
+ glVertex2f(r2 * sa, r2 * ca);
+ TXTR_COORD(0.5f - sa * r1 / dtc, 0.5f + ca * r1 / dtc);
+ glVertex2f(r1 * sa, r1 * ca);
+ }
+ glEnd();
+ }
+ r1 = r2;
+ }
+ break;
+ }
+ case GLU_LINE:
+ {
+ int l, s;
+ /* draw loops */
+ for (l = 0; l <= loops; l++) {
+ float r = innerRadius + l * dr;
+ glBegin(GL_LINE_LOOP);
+ for (s = 0; s < slices; s++) {
+ float a = s * da;
+ glVertex2f(r * sin(a), r * cos(a));
+ }
+ glEnd();
+ }
+ /* draw spokes */
+ for (s = 0; s < slices; s++) {
+ float a = s * da;
+ float x = sin(a);
+ float y = cos(a);
+ glBegin(GL_LINE_STRIP);
+ for (l = 0; l <= loops; l++) {
+ float r = innerRadius + l * dr;
+ glVertex2f(r * x, r * y);
+ }
+ glEnd();
+ }
+ break;
+ }
+ case GLU_POINT:
+ {
+ int s;
+ glBegin(GL_POINTS);
+ for (s = 0; s < slices; s++) {
+ float a = s * da;
+ float x = sin(a);
+ float y = cos(a);
+ int l;
+ for (l = 0; l <= loops; l++) {
+ float r = innerRadius * l * dr;
+ glVertex2f(r * x, r * y);
+ }
+ }
+ glEnd();
+ break;
+ }
+ case GLU_SILHOUETTE:
+ {
+ if (innerRadius != 0.0) {
+ float a;
+ glBegin(GL_LINE_LOOP);
+ for (a = 0.0f; a < 2.0 * PI; a += da) {
+ float x = innerRadius * sin(a);
+ float y = innerRadius * cos(a);
+ glVertex2f(x, y);
+ }
+ glEnd();
+ }
+ {
+ float a;
+ glBegin(GL_LINE_LOOP);
+ for (a = 0; a < 2.0f * PI; a += da) {
+ float x = outerRadius * sin(a);
+ float y = outerRadius * cos(a);
+ glVertex2f(x, y);
+ }
+ glEnd();
+ }
+ break;
+ }
+ default:
+ return;
+ }
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/GLU.java b/src/de/verschwiegener/lwjgl3/util/glu/GLU.java
new file mode 100644
index 0000000..c463139
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/GLU.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import de.verschwiegener.lwjgl3.LWJGLUtil;
+import de.verschwiegener.lwjgl3.util.glu.tessellation.GLUtessellatorImpl;
+
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+
+import static org.lwjgl.opengl.GL11.*;
+
+/**
+ * GLU.java
+ *
+ *
+ * Created 23-dec-2003
+ * @author Erik Duijs
+ */
+public class GLU {
+ static final float PI = (float)Math.PI;
+
+ /* Errors: (return value 0 = no error) */
+ public static final int GLU_INVALID_ENUM = 100900;
+ public static final int GLU_INVALID_VALUE = 100901;
+ public static final int GLU_OUT_OF_MEMORY = 100902;
+ public static final int GLU_INCOMPATIBLE_GL_VERSION = 100903;
+
+ /* StringName */
+ public static final int GLU_VERSION = 100800;
+ public static final int GLU_EXTENSIONS = 100801;
+
+ /* Boolean */
+ public static final boolean GLU_TRUE = true;
+ public static final boolean GLU_FALSE = false;
+
+
+ /**** Quadric constants ****/
+
+ /* QuadricNormal */
+ public static final int GLU_SMOOTH = 100000;
+ public static final int GLU_FLAT = 100001;
+ public static final int GLU_NONE = 100002;
+
+ /* QuadricDrawStyle */
+ public static final int GLU_POINT = 100010;
+ public static final int GLU_LINE = 100011;
+ public static final int GLU_FILL = 100012;
+ public static final int GLU_SILHOUETTE = 100013;
+
+ /* QuadricOrientation */
+ public static final int GLU_OUTSIDE = 100020;
+ public static final int GLU_INSIDE = 100021;
+
+ /* Callback types: */
+ /* ERROR = 100103 */
+
+
+ /**** Tesselation constants ****/
+
+ public static final double GLU_TESS_MAX_COORD = 1.0e150;
+ public static final double TESS_MAX_COORD = 1.0e150;
+
+ /* TessProperty */
+ public static final int GLU_TESS_WINDING_RULE = 100140;
+ public static final int GLU_TESS_BOUNDARY_ONLY = 100141;
+ public static final int GLU_TESS_TOLERANCE = 100142;
+
+ /* TessWinding */
+ public static final int GLU_TESS_WINDING_ODD = 100130;
+ public static final int GLU_TESS_WINDING_NONZERO = 100131;
+ public static final int GLU_TESS_WINDING_POSITIVE = 100132;
+ public static final int GLU_TESS_WINDING_NEGATIVE = 100133;
+ public static final int GLU_TESS_WINDING_ABS_GEQ_TWO = 100134;
+
+ /* TessCallback */
+ public static final int GLU_TESS_BEGIN = 100100; /* void (CALLBACK*)(GLenum type) */
+ public static final int GLU_TESS_VERTEX = 100101; /* void (CALLBACK*)(void *data) */
+ public static final int GLU_TESS_END = 100102; /* void (CALLBACK*)(void) */
+ public static final int GLU_TESS_ERROR = 100103; /* void (CALLBACK*)(GLenum errno) */
+ public static final int GLU_TESS_EDGE_FLAG = 100104; /* void (CALLBACK*)(GLboolean boundaryEdge) */
+ public static final int GLU_TESS_COMBINE = 100105; /* void (CALLBACK*)(GLdouble coords[3],
+ void *data[4],
+ GLfloat weight[4],
+ void **dataOut) */
+ public static final int GLU_TESS_BEGIN_DATA = 100106; /* void (CALLBACK*)(GLenum type,
+ void *polygon_data) */
+ public static final int GLU_TESS_VERTEX_DATA = 100107; /* void (CALLBACK*)(void *data,
+ void *polygon_data) */
+ public static final int GLU_TESS_END_DATA = 100108; /* void (CALLBACK*)(void *polygon_data) */
+ public static final int GLU_TESS_ERROR_DATA = 100109; /* void (CALLBACK*)(GLenum errno,
+ void *polygon_data) */
+ public static final int GLU_TESS_EDGE_FLAG_DATA = 100110; /* void (CALLBACK*)(GLboolean boundaryEdge,
+ void *polygon_data) */
+ public static final int GLU_TESS_COMBINE_DATA = 100111; /* void (CALLBACK*)(GLdouble coords[3],
+ void *data[4],
+ GLfloat weight[4],
+ void **dataOut,
+ void *polygon_data) */
+
+ /* TessError */
+ public static final int GLU_TESS_ERROR1 = 100151;
+ public static final int GLU_TESS_ERROR2 = 100152;
+ public static final int GLU_TESS_ERROR3 = 100153;
+ public static final int GLU_TESS_ERROR4 = 100154;
+ public static final int GLU_TESS_ERROR5 = 100155;
+ public static final int GLU_TESS_ERROR6 = 100156;
+ public static final int GLU_TESS_ERROR7 = 100157;
+ public static final int GLU_TESS_ERROR8 = 100158;
+
+ public static final int GLU_TESS_MISSING_BEGIN_POLYGON = GLU_TESS_ERROR1;
+ public static final int GLU_TESS_MISSING_BEGIN_CONTOUR = GLU_TESS_ERROR2;
+ public static final int GLU_TESS_MISSING_END_POLYGON = GLU_TESS_ERROR3;
+ public static final int GLU_TESS_MISSING_END_CONTOUR = GLU_TESS_ERROR4;
+ public static final int GLU_TESS_COORD_TOO_LARGE = GLU_TESS_ERROR5;
+ public static final int GLU_TESS_NEED_COMBINE_CALLBACK = GLU_TESS_ERROR6;
+
+ /**** NURBS constants ****/
+
+ /* NurbsProperty */
+ public static final int GLU_AUTO_LOAD_MATRIX = 100200;
+ public static final int GLU_CULLING = 100201;
+ public static final int GLU_SAMPLING_TOLERANCE = 100203;
+ public static final int GLU_DISPLAY_MODE = 100204;
+ public static final int GLU_PARAMETRIC_TOLERANCE = 100202;
+ public static final int GLU_SAMPLING_METHOD = 100205;
+ public static final int GLU_U_STEP = 100206;
+ public static final int GLU_V_STEP = 100207;
+
+ /* NurbsSampling */
+ public static final int GLU_PATH_LENGTH = 100215;
+ public static final int GLU_PARAMETRIC_ERROR = 100216;
+ public static final int GLU_DOMAIN_DISTANCE = 100217;
+
+
+ /* NurbsTrim */
+ public static final int GLU_MAP1_TRIM_2 = 100210;
+ public static final int GLU_MAP1_TRIM_3 = 100211;
+
+ /* NurbsDisplay */
+ /* FILL = 100012 */
+ public static final int GLU_OUTLINE_POLYGON = 100240;
+ public static final int GLU_OUTLINE_PATCH = 100241;
+
+ /* NurbsCallback */
+ /* ERROR = 100103 */
+
+ /* NurbsErrors */
+ public static final int GLU_NURBS_ERROR1 = 100251;
+ public static final int GLU_NURBS_ERROR2 = 100252;
+ public static final int GLU_NURBS_ERROR3 = 100253;
+ public static final int GLU_NURBS_ERROR4 = 100254;
+ public static final int GLU_NURBS_ERROR5 = 100255;
+ public static final int GLU_NURBS_ERROR6 = 100256;
+ public static final int GLU_NURBS_ERROR7 = 100257;
+ public static final int GLU_NURBS_ERROR8 = 100258;
+ public static final int GLU_NURBS_ERROR9 = 100259;
+ public static final int GLU_NURBS_ERROR10 = 100260;
+ public static final int GLU_NURBS_ERROR11 = 100261;
+ public static final int GLU_NURBS_ERROR12 = 100262;
+ public static final int GLU_NURBS_ERROR13 = 100263;
+ public static final int GLU_NURBS_ERROR14 = 100264;
+ public static final int GLU_NURBS_ERROR15 = 100265;
+ public static final int GLU_NURBS_ERROR16 = 100266;
+ public static final int GLU_NURBS_ERROR17 = 100267;
+ public static final int GLU_NURBS_ERROR18 = 100268;
+ public static final int GLU_NURBS_ERROR19 = 100269;
+ public static final int GLU_NURBS_ERROR20 = 100270;
+ public static final int GLU_NURBS_ERROR21 = 100271;
+ public static final int GLU_NURBS_ERROR22 = 100272;
+ public static final int GLU_NURBS_ERROR23 = 100273;
+ public static final int GLU_NURBS_ERROR24 = 100274;
+ public static final int GLU_NURBS_ERROR25 = 100275;
+ public static final int GLU_NURBS_ERROR26 = 100276;
+ public static final int GLU_NURBS_ERROR27 = 100277;
+ public static final int GLU_NURBS_ERROR28 = 100278;
+ public static final int GLU_NURBS_ERROR29 = 100279;
+ public static final int GLU_NURBS_ERROR30 = 100280;
+ public static final int GLU_NURBS_ERROR31 = 100281;
+ public static final int GLU_NURBS_ERROR32 = 100282;
+ public static final int GLU_NURBS_ERROR33 = 100283;
+ public static final int GLU_NURBS_ERROR34 = 100284;
+ public static final int GLU_NURBS_ERROR35 = 100285;
+ public static final int GLU_NURBS_ERROR36 = 100286;
+ public static final int GLU_NURBS_ERROR37 = 100287;
+
+ /* Contours types -- obsolete! */
+ public static final int GLU_CW = 100120;
+ public static final int GLU_CCW = 100121;
+ public static final int GLU_INTERIOR = 100122;
+ public static final int GLU_EXTERIOR = 100123;
+ public static final int GLU_UNKNOWN = 100124;
+
+ /* Names without "TESS_" prefix */
+ public static final int GLU_BEGIN = GLU_TESS_BEGIN;
+ public static final int GLU_VERTEX = GLU_TESS_VERTEX;
+ public static final int GLU_END = GLU_TESS_END;
+ public static final int GLU_ERROR = GLU_TESS_ERROR;
+ public static final int GLU_EDGE_FLAG = GLU_TESS_EDGE_FLAG;
+
+ /**
+ * Method gluLookAt
+ * @param eyex
+ * @param eyey
+ * @param eyez
+ * @param centerx
+ * @param centery
+ * @param centerz
+ * @param upx
+ * @param upy
+ * @param upz
+ */
+ public static void gluLookAt(
+ float eyex,
+ float eyey,
+ float eyez,
+ float centerx,
+ float centery,
+ float centerz,
+ float upx,
+ float upy,
+ float upz) {
+
+ Project.gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
+ }
+
+ /**
+ * Method gluOrtho2D
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ */
+ public static void gluOrtho2D(
+ float left,
+ float right,
+ float bottom,
+ float top) {
+
+ glOrtho(left, right, bottom, top, -1.0, 1.0);
+ }
+
+ /**
+ * Method gluPerspective
+ * @param fovy
+ * @param aspect
+ * @param zNear
+ * @param zFar
+ */
+ public static void gluPerspective(
+ float fovy,
+ float aspect,
+ float zNear,
+ float zFar) {
+
+ Project.gluPerspective(fovy, aspect, zNear, zFar);
+ }
+
+ /**
+ * Method gluProject
+ * @param objx
+ * @param objy
+ * @param objz
+ * @param modelMatrix
+ * @param projMatrix
+ * @param viewport
+ * @param win_pos
+ */
+ public static boolean gluProject(float objx, float objy, float objz,
+ FloatBuffer modelMatrix,
+ FloatBuffer projMatrix,
+ IntBuffer viewport,
+ FloatBuffer win_pos)
+ {
+ return Project.gluProject(objx, objy, objz, modelMatrix, projMatrix, viewport, win_pos);
+ }
+
+ /**
+ * Method gluUnproject
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param modelMatrix
+ * @param projMatrix
+ * @param viewport
+ * @param obj_pos
+ */
+ public static boolean gluUnProject(float winx, float winy, float winz,
+ FloatBuffer modelMatrix,
+ FloatBuffer projMatrix,
+ IntBuffer viewport,
+ FloatBuffer obj_pos)
+ {
+ return Project.gluUnProject(winx, winy, winz, modelMatrix, projMatrix, viewport, obj_pos);
+ }
+
+ /**
+ * Method gluPickMatrix
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ * @param viewport
+ */
+ public static void gluPickMatrix(
+ float x,
+ float y,
+ float width,
+ float height,
+ IntBuffer viewport) {
+
+ Project.gluPickMatrix(x, y, width, height, viewport);
+ }
+
+ /**
+ * Method gluGetString.
+ * @param name
+ * @return String
+ */
+ public static String gluGetString(int name) {
+ return Registry.gluGetString(name);
+ }
+
+ /**
+ * Method gluCheckExtension.
+ * @param extName
+ * @param extString
+ * @return boolean
+ */
+ public static boolean gluCheckExtension(String extName, String extString) {
+ return Registry.gluCheckExtension(extName, extString);
+ }
+
+ /**
+ * Method gluBuild2DMipmaps
+ * @param target
+ * @param components
+ * @param width
+ * @param height
+ * @param format
+ * @param type
+ * @param data
+ * @return int
+ */
+ public static int gluBuild2DMipmaps(
+ int target,
+ int components,
+ int width,
+ int height,
+ int format,
+ int type,
+ ByteBuffer data) {
+
+ return MipMap.gluBuild2DMipmaps(target, components, width, height, format, type, data);
+ }
+
+ /**
+ * Method gluScaleImage.
+ * @param format
+ * @param widthIn
+ * @param heightIn
+ * @param typeIn
+ * @param dataIn
+ * @param widthOut
+ * @param heightOut
+ * @param typeOut
+ * @param dataOut
+ * @return int
+ */
+ public static int gluScaleImage(
+ int format,
+ int widthIn,
+ int heightIn,
+ int typeIn,
+ ByteBuffer dataIn,
+ int widthOut,
+ int heightOut,
+ int typeOut,
+ ByteBuffer dataOut) {
+
+ return MipMap.gluScaleImage(format, widthIn, heightIn, typeIn, dataIn, widthOut, heightOut, typeOut, dataOut);
+ }
+
+ public static String gluErrorString(int error_code) {
+ switch (error_code) {
+ case GLU_INVALID_ENUM:
+ return "Invalid enum (glu)";
+ case GLU_INVALID_VALUE:
+ return "Invalid value (glu)";
+ case GLU_OUT_OF_MEMORY:
+ return "Out of memory (glu)";
+ default:
+ return LWJGLUtil.translateGLErrorString(error_code);
+ }
+ }
+
+ public static GLUtessellator gluNewTess() {
+ return new GLUtessellatorImpl();
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellator.java b/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellator.java
new file mode 100644
index 0000000..666c260
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellator.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+public interface GLUtessellator {
+
+ void gluDeleteTess();
+
+ void gluTessProperty(int which, double value);
+
+ /* Returns tessellator property */
+ void gluGetTessProperty(int which, double[] value,
+ int value_offset); /* gluGetTessProperty() */
+
+ void gluTessNormal(double x, double y, double z);
+
+ void gluTessCallback(int which,
+ GLUtessellatorCallback aCallback);
+
+ void gluTessVertex(double[] coords, int coords_offset,
+ Object vertexData);
+
+ void gluTessBeginPolygon(Object data);
+
+ void gluTessBeginContour();
+
+ void gluTessEndContour();
+
+ void gluTessEndPolygon();
+
+ /*******************************************************/
+
+ /* Obsolete calls -- for backward compatibility */
+
+ void gluBeginPolygon();
+
+ /*ARGSUSED*/
+ void gluNextContour(int type);
+
+ void gluEndPolygon();
+
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellatorCallback.java b/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellatorCallback.java
new file mode 100644
index 0000000..3a78193
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellatorCallback.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu;
+
+/**
+ * GLUtessellatorCallback interface provides methods that the user will
+ * override to define the callbacks for a tessellation object.
+ *
+ * @author Eric Veach, July 1994
+ * @author Java Port: Pepijn Van Eeckhoudt, July 2003
+ * @author Java Port: Nathan Parker Burg, August 2003
+ */
+public interface GLUtessellatorCallback {
+
+ void begin(int type);
+
+
+ void beginData(int type, Object polygonData);
+
+
+
+ void edgeFlag(boolean boundaryEdge);
+
+
+
+ void edgeFlagData(boolean boundaryEdge, Object polygonData);
+
+
+
+ void vertex(Object vertexData);
+
+
+
+ void vertexData(Object vertexData, Object polygonData);
+
+
+
+ void end();
+
+
+
+ void endData(Object polygonData);
+
+
+
+ void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData);
+
+
+
+ void combineData(double[] coords, Object[] data,
+ float[] weight, Object[] outData,
+ Object polygonData);
+
+
+
+
+ void error(int errnum);
+
+
+ void errorData(int errnum, Object polygonData);
+
+ //void mesh(com.sun.opengl.impl.tessellator.GLUmesh mesh);
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellatorCallbackAdapter.java b/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellatorCallbackAdapter.java
new file mode 100644
index 0000000..059116a
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/GLUtessellatorCallbackAdapter.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu;
+
+/**
+ * The GLUtessellatorCallbackAdapter provides a default implementation of
+ * {@link GLUtessellatorCallback GLUtessellatorCallback}
+ * with empty callback methods. This class can be extended to provide user
+ * defined callback methods.
+ *
+ * @author Eric Veach, July 1994
+ * @author Java Port: Pepijn Van Eechhoudt, July 2003
+ * @author Java Port: Nathan Parker Burg, August 2003
+ */
+
+public class GLUtessellatorCallbackAdapter implements GLUtessellatorCallback {
+ public void begin(int type) {}
+ public void edgeFlag(boolean boundaryEdge) {}
+ public void vertex(Object vertexData) {}
+ public void end() {}
+// public void mesh(com.sun.opengl.impl.tessellator.GLUmesh mesh) {}
+ public void error(int errnum) {}
+ public void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData) {}
+ public void beginData(int type, Object polygonData) {}
+ public void edgeFlagData(boolean boundaryEdge,
+ Object polygonData) {}
+ public void vertexData(Object vertexData, Object polygonData) {}
+ public void endData(Object polygonData) {}
+ public void errorData(int errnum, Object polygonData) {}
+ public void combineData(double[] coords, Object[] data,
+ float[] weight, Object[] outData,
+ Object polygonData) {}
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/MipMap.java b/src/de/verschwiegener/lwjgl3/util/glu/MipMap.java
new file mode 100644
index 0000000..6d57e96
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/MipMap.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import java.nio.ByteBuffer;
+
+import org.lwjgl.BufferUtils;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * MipMap.java
+ *
+ *
+ * Created 11-jan-2004
+ * @author Erik Duijs
+ */
+public class MipMap extends Util {
+
+ /**
+ * Method gluBuild2DMipmaps
+ *
+ * @param target
+ * @param components
+ * @param width
+ * @param height
+ * @param format
+ * @param type
+ * @param data
+ * @return int
+ */
+ public static int gluBuild2DMipmaps(final int target,
+ final int components, final int width, final int height,
+ final int format, final int type, final ByteBuffer data) {
+ if ( width < 1 || height < 1 ) return GLU_INVALID_VALUE;
+
+ final int bpp = bytesPerPixel(format, type);
+ if ( bpp == 0 )
+ return GLU_INVALID_ENUM;
+
+ final int maxSize = glGetIntegerv(GL_MAX_TEXTURE_SIZE);
+
+ int w = nearestPower(width);
+ if ( w > maxSize )
+ w = maxSize;
+
+ int h = nearestPower(height);
+ if ( h > maxSize )
+ h = maxSize;
+
+ // Get current glPixelStore state
+ PixelStoreState pss = new PixelStoreState();
+
+ // set pixel packing
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+
+ ByteBuffer image;
+ int retVal = 0;
+ boolean done = false;
+
+ if ( w != width || h != height ) {
+ // must rescale image to get "top" mipmap texture image
+ image = BufferUtils.createByteBuffer((w + 4) * h * bpp);
+ int error = gluScaleImage(format, width, height, type, data, w, h, type, image);
+ if ( error != 0 ) {
+ retVal = error;
+ done = true;
+ }
+
+ /* set pixel unpacking */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ } else {
+ image = data;
+ }
+
+ ByteBuffer bufferA = null;
+ ByteBuffer bufferB = null;
+
+ int level = 0;
+ while ( !done ) {
+ if (image != data) {
+ /* set pixel unpacking */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ }
+
+ glTexImage2D(target, level, components, w, h, 0, format, type, image);
+
+ if ( w == 1 && h == 1 )
+ break;
+
+ final int newW = (w < 2) ? 1 : w >> 1;
+ final int newH = (h < 2) ? 1 : h >> 1;
+
+ final ByteBuffer newImage;
+
+ if ( bufferA == null )
+ newImage = (bufferA = BufferUtils.createByteBuffer((newW + 4) * newH * bpp));
+ else if ( bufferB == null )
+ newImage = (bufferB = BufferUtils.createByteBuffer((newW + 4) * newH * bpp));
+ else
+ newImage = bufferB;
+
+ int error = gluScaleImage(format, w, h, type, image, newW, newH, type, newImage);
+ if ( error != 0 ) {
+ retVal = error;
+ done = true;
+ }
+
+ image = newImage;
+ if ( bufferB != null )
+ bufferB = bufferA;
+
+ w = newW;
+ h = newH;
+ level++;
+ }
+
+ // Restore original glPixelStore state
+ pss.save();
+
+ return retVal;
+ }
+
+ /**
+ * Method gluScaleImage.
+ * @param format
+ * @param widthIn
+ * @param heightIn
+ * @param typein
+ * @param dataIn
+ * @param widthOut
+ * @param heightOut
+ * @param typeOut
+ * @param dataOut
+ * @return int
+ */
+ public static int gluScaleImage(int format,
+ int widthIn, int heightIn, int typein, ByteBuffer dataIn,
+ int widthOut, int heightOut, int typeOut, ByteBuffer dataOut) {
+
+ final int components = compPerPix(format);
+ if ( components == -1 )
+ return GLU_INVALID_ENUM;
+
+ int i, j, k;
+ float[] tempIn, tempOut;
+ float sx, sy;
+ int sizein, sizeout;
+ int rowstride, rowlen;
+
+ // temp image data
+ tempIn = new float[widthIn * heightIn * components];
+ tempOut = new float[widthOut * heightOut * components];
+
+ // Determine bytes per input type
+ switch ( typein ) {
+ case GL_UNSIGNED_BYTE:
+ sizein = 1;
+ break;
+ case GL_FLOAT:
+ sizein = 4;
+ break;
+ default:
+ return GL_INVALID_ENUM;
+ }
+
+ // Determine bytes per output type
+ switch ( typeOut ) {
+ case GL_UNSIGNED_BYTE:
+ sizeout = 1;
+ break;
+ case GL_FLOAT:
+ sizeout = 4;
+ break;
+ default:
+ return GL_INVALID_ENUM;
+ }
+
+ // Get glPixelStore state
+ PixelStoreState pss = new PixelStoreState();
+
+ //Unpack the pixel data and convert to floating point
+ if ( pss.unpackRowLength > 0 )
+ rowlen = pss.unpackRowLength;
+ else
+ rowlen = widthIn;
+
+ if ( sizein >= pss.unpackAlignment )
+ rowstride = components * rowlen;
+ else
+ rowstride = pss.unpackAlignment / sizein * ceil(components * rowlen * sizein, pss.unpackAlignment);
+
+ switch ( typein ) {
+ case GL_UNSIGNED_BYTE:
+ k = 0;
+ dataIn.rewind();
+ for ( i = 0; i < heightIn; i++ ) {
+ int ubptr = i * rowstride + pss.unpackSkipRows * rowstride + pss.unpackSkipPixels * components;
+ for ( j = 0; j < widthIn * components; j++ ) {
+ tempIn[k++] = dataIn.get(ubptr++) & 0xff;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ k = 0;
+ dataIn.rewind();
+ for ( i = 0; i < heightIn; i++ )
+ {
+ int fptr = 4 * (i * rowstride + pss.unpackSkipRows * rowstride + pss.unpackSkipPixels * components);
+ for ( j = 0; j < widthIn * components; j++ )
+ {
+ tempIn[k++] = dataIn.getFloat(fptr);
+ fptr += 4;
+ }
+ }
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+ // Do scaling
+ sx = (float)widthIn / (float)widthOut;
+ sy = (float)heightIn / (float)heightOut;
+
+ float[] c = new float[components];
+ int src, dst;
+
+ for ( int iy = 0; iy < heightOut; iy++ ) {
+ for ( int ix = 0; ix < widthOut; ix++ ) {
+ int x0 = (int)(ix * sx);
+ int x1 = (int)((ix + 1) * sx);
+ int y0 = (int)(iy * sy);
+ int y1 = (int)((iy + 1) * sy);
+
+ int readPix = 0;
+
+ // reset weighted pixel
+ for ( int ic = 0; ic < components; ic++ ) {
+ c[ic] = 0;
+ }
+
+ // create weighted pixel
+ for ( int ix0 = x0; ix0 < x1; ix0++ ) {
+ for ( int iy0 = y0; iy0 < y1; iy0++ ) {
+
+ src = (iy0 * widthIn + ix0) * components;
+
+ for ( int ic = 0; ic < components; ic++ ) {
+ c[ic] += tempIn[src + ic];
+ }
+
+ readPix++;
+ }
+ }
+
+ // store weighted pixel
+ dst = (iy * widthOut + ix) * components;
+
+ if ( readPix == 0 ) {
+ // Image is sized up, caused by non power of two texture as input
+ src = (y0 * widthIn + x0) * components;
+ for ( int ic = 0; ic < components; ic++ ) {
+ tempOut[dst++] = tempIn[src + ic];
+ }
+ } else {
+ // sized down
+ for ( k = 0; k < components; k++ ) {
+ tempOut[dst++] = c[k] / readPix;
+ }
+ }
+ }
+ }
+
+
+ // Convert temp output
+ if ( pss.packRowLength > 0 )
+ rowlen = pss.packRowLength;
+ else
+ rowlen = widthOut;
+
+ if ( sizeout >= pss.packAlignment )
+ rowstride = components * rowlen;
+ else
+ rowstride = pss.packAlignment / sizeout * ceil(components * rowlen * sizeout, pss.packAlignment);
+
+ switch ( typeOut ) {
+ case GL_UNSIGNED_BYTE:
+ k = 0;
+ for ( i = 0; i < heightOut; i++ ) {
+ int ubptr = i * rowstride + pss.packSkipRows * rowstride + pss.packSkipPixels * components;
+
+ for ( j = 0; j < widthOut * components; j++ ) {
+ dataOut.put(ubptr++, (byte)tempOut[k++]);
+ }
+ }
+ break;
+ case GL_FLOAT:
+ k = 0;
+ for ( i = 0; i < heightOut; i++ ) {
+ int fptr = 4 * (i * rowstride + pss.unpackSkipRows * rowstride + pss.unpackSkipPixels * components);
+
+ for ( j = 0; j < widthOut * components; j++ ) {
+ dataOut.putFloat(fptr, tempOut[k++]);
+ fptr += 4;
+ }
+ }
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+ return 0;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/PartialDisk.java b/src/de/verschwiegener/lwjgl3/util/glu/PartialDisk.java
new file mode 100644
index 0000000..ff7f8de
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/PartialDisk.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * PartialDisk.java
+ *
+ *
+ * Created 23-dec-2003
+ *
+ * @author Erik Duijs
+ */
+public class PartialDisk extends Quadric {
+
+ private static final int CACHE_SIZE = 240;
+
+ /**
+ * Constructor for PartialDisk.
+ */
+ public PartialDisk() {
+ super();
+ }
+
+ /**
+ * renders a partial disk on the z=0 plane. A partial disk is similar to a
+ * full disk, except that only the subset of the disk from startAngle
+ * through startAngle + sweepAngle is included (where 0 degrees is along
+ * the +y axis, 90 degrees along the +x axis, 180 along the -y axis, and
+ * 270 along the -x axis).
+ *
+ * The partial disk has a radius of outerRadius, and contains a concentric
+ * circular hole with a radius of innerRadius. If innerRadius is zero, then
+ * no hole is generated. The partial disk is subdivided around the z axis
+ * into slices (like pizza slices), and also about the z axis into rings
+ * (as specified by slices and loops, respectively).
+ *
+ * With respect to orientation, the +z side of the partial disk is
+ * considered to be outside (see gluQuadricOrientation). This means that if
+ * the orientation is set to GLU.GLU_OUTSIDE, then any normals generated point
+ * along the +z axis. Otherwise, they point along the -z axis.
+ *
+ * If texturing is turned on (with gluQuadricTexture), texture coordinates
+ * are generated linearly such that where r=outerRadius, the value at (r, 0, 0)
+ * is (1, 0.5), at (0, r, 0) it is (0.5, 1), at (-r, 0, 0) it is (0, 0.5),
+ * and at (0, -r, 0) it is (0.5, 0).
+ */
+ public void draw(
+ float innerRadius,
+ float outerRadius,
+ int slices,
+ int loops,
+ float startAngle,
+ float sweepAngle) {
+
+ int i, j;
+ float[] sinCache = new float[CACHE_SIZE];
+ float[] cosCache = new float[CACHE_SIZE];
+ float angle;
+ float sintemp, costemp;
+ float deltaRadius;
+ float radiusLow, radiusHigh;
+ float texLow = 0, texHigh = 0;
+ float angleOffset;
+ int slices2;
+ int finish;
+
+ if (slices >= CACHE_SIZE)
+ slices = CACHE_SIZE - 1;
+ if (slices < 2
+ || loops < 1
+ || outerRadius <= 0.0f
+ || innerRadius < 0.0f
+ || innerRadius > outerRadius) {
+ //gluQuadricError(qobj, GLU.GLU_INVALID_VALUE);
+ System.err.println("PartialDisk: GLU_INVALID_VALUE");
+ return;
+ }
+
+ if (sweepAngle < -360.0f)
+ sweepAngle = 360.0f;
+ if (sweepAngle > 360.0f)
+ sweepAngle = 360.0f;
+ if (sweepAngle < 0) {
+ startAngle += sweepAngle;
+ sweepAngle = -sweepAngle;
+ }
+
+ if (sweepAngle == 360.0f) {
+ slices2 = slices;
+ } else {
+ slices2 = slices + 1;
+ }
+
+ /* Compute length (needed for normal calculations) */
+ deltaRadius = outerRadius - innerRadius;
+
+ /* Cache is the vertex locations cache */
+
+ angleOffset = startAngle / 180.0f * PI;
+ for (i = 0; i <= slices; i++) {
+ angle = angleOffset + ((PI * sweepAngle) / 180.0f) * i / slices;
+ sinCache[i] = sin(angle);
+ cosCache[i] = cos(angle);
+ }
+
+ if (sweepAngle == 360.0f) {
+ sinCache[slices] = sinCache[0];
+ cosCache[slices] = cosCache[0];
+ }
+
+ switch (super.normals) {
+ case GLU_FLAT :
+ case GLU_SMOOTH :
+ if (super.orientation == GLU_OUTSIDE) {
+ glNormal3f(0.0f, 0.0f, 1.0f);
+ } else {
+ glNormal3f(0.0f, 0.0f, -1.0f);
+ }
+ break;
+ default :
+ case GLU_NONE :
+ break;
+ }
+
+ switch (super.drawStyle) {
+ case GLU_FILL :
+ if (innerRadius == .0f) {
+ finish = loops - 1;
+ /* Triangle strip for inner polygons */
+ glBegin(GL_TRIANGLE_FAN);
+ if (super.textureFlag) {
+ glTexCoord2f(0.5f, 0.5f);
+ }
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ radiusLow = outerRadius - deltaRadius * ((float) (loops - 1) / loops);
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+ }
+
+ if (super.orientation == GLU_OUTSIDE) {
+ for (i = slices; i >= 0; i--) {
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+ }
+ } else {
+ for (i = 0; i <= slices; i++) {
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+ }
+ }
+ glEnd();
+ } else {
+ finish = loops;
+ }
+ for (j = 0; j < finish; j++) {
+ radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+ radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+ texHigh = radiusHigh / outerRadius / 2;
+ }
+
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= slices; i++) {
+ if (super.orientation == GLU_OUTSIDE) {
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texHigh * sinCache[i] + 0.5f,
+ texHigh * cosCache[i] + 0.5f);
+ }
+ glVertex3f(
+ radiusHigh * sinCache[i],
+ radiusHigh * cosCache[i],
+ 0.0f);
+ } else {
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texHigh * sinCache[i] + 0.5f,
+ texHigh * cosCache[i] + 0.5f);
+ }
+ glVertex3f(
+ radiusHigh * sinCache[i],
+ radiusHigh * cosCache[i],
+ 0.0f);
+
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+ }
+ }
+ glEnd();
+ }
+ break;
+ case GLU_POINT :
+ glBegin(GL_POINTS);
+ for (i = 0; i < slices2; i++) {
+ sintemp = sinCache[i];
+ costemp = cosCache[i];
+ for (j = 0; j <= loops; j++) {
+ radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0f);
+ }
+ }
+ glEnd();
+ break;
+ case GLU_LINE :
+ if (innerRadius == outerRadius) {
+ glBegin(GL_LINE_STRIP);
+
+ for (i = 0; i <= slices; i++) {
+ if (super.textureFlag) {
+ glTexCoord2f(sinCache[i] / 2 + 0.5f, cosCache[i] / 2 + 0.5f);
+ }
+ glVertex3f(innerRadius * sinCache[i], innerRadius * cosCache[i], 0.0f);
+ }
+ glEnd();
+ break;
+ }
+ for (j = 0; j <= loops; j++) {
+ radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+ }
+
+ glBegin(GL_LINE_STRIP);
+ for (i = 0; i <= slices; i++) {
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+ }
+ glEnd();
+ }
+ for (i = 0; i < slices2; i++) {
+ sintemp = sinCache[i];
+ costemp = cosCache[i];
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j <= loops; j++) {
+ radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+ }
+
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0f);
+ }
+ glEnd();
+ }
+ break;
+ case GLU_SILHOUETTE :
+ if (sweepAngle < 360.0f) {
+ for (i = 0; i <= slices; i += slices) {
+ sintemp = sinCache[i];
+ costemp = cosCache[i];
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j <= loops; j++) {
+ radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0f);
+ }
+ glEnd();
+ }
+ }
+ for (j = 0; j <= loops; j += loops) {
+ radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+ if (super.textureFlag) {
+ texLow = radiusLow / outerRadius / 2;
+ }
+
+ glBegin(GL_LINE_STRIP);
+ for (i = 0; i <= slices; i++) {
+ if (super.textureFlag) {
+ glTexCoord2f(
+ texLow * sinCache[i] + 0.5f,
+ texLow * cosCache[i] + 0.5f);
+ }
+ glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+ }
+ glEnd();
+ if (innerRadius == outerRadius)
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/PixelStoreState.java b/src/de/verschwiegener/lwjgl3/util/glu/PixelStoreState.java
new file mode 100644
index 0000000..4c34530
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/PixelStoreState.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static org.lwjgl.opengl.GL11.*;
+
+/**
+ * PixelStoreState.java
+ *
+ *
+ * Created 11-jan-2004
+ * @author Erik Duijs
+ */
+class PixelStoreState extends Util {
+
+ public int unpackRowLength;
+ public int unpackAlignment;
+ public int unpackSkipRows;
+ public int unpackSkipPixels;
+ public int packRowLength;
+ public int packAlignment;
+ public int packSkipRows;
+ public int packSkipPixels;
+
+ /**
+ * Constructor for PixelStoreState.
+ */
+ PixelStoreState() {
+ super();
+ load();
+ }
+
+ public void load() {
+ unpackRowLength = glGetIntegerv(GL_UNPACK_ROW_LENGTH);
+ unpackAlignment = glGetIntegerv(GL_UNPACK_ALIGNMENT);
+ unpackSkipRows = glGetIntegerv(GL_UNPACK_SKIP_ROWS);
+ unpackSkipPixels = glGetIntegerv(GL_UNPACK_SKIP_PIXELS);
+ packRowLength = glGetIntegerv(GL_PACK_ROW_LENGTH);
+ packAlignment = glGetIntegerv(GL_PACK_ALIGNMENT);
+ packSkipRows = glGetIntegerv(GL_PACK_SKIP_ROWS);
+ packSkipPixels = glGetIntegerv(GL_PACK_SKIP_PIXELS);
+ }
+
+ public void save() {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackRowLength);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackSkipRows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackSkipPixels);
+ glPixelStorei(GL_PACK_ROW_LENGTH, packRowLength);
+ glPixelStorei(GL_PACK_ALIGNMENT, packAlignment);
+ glPixelStorei(GL_PACK_SKIP_ROWS, packSkipRows);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, packSkipPixels);
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Project.java b/src/de/verschwiegener/lwjgl3/util/glu/Project.java
new file mode 100644
index 0000000..2cd2956
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Project.java
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.GLUtil;
+
+import static org.lwjgl.opengl.GL11.*;
+
+/**
+ * Project.java
+ *
+ *
+ * Created 11-jan-2004
+ *
+ * @author Erik Duijs
+ */
+public class Project extends Util {
+
+ private static final float[] IDENTITY_MATRIX =
+ new float[] {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+
+ private static final FloatBuffer matrix = BufferUtils.createFloatBuffer(16);
+ private static final FloatBuffer finalMatrix = BufferUtils.createFloatBuffer(16);
+
+ private static final FloatBuffer tempMatrix = BufferUtils.createFloatBuffer(16);
+ private static final float[] in = new float[4];
+ private static final float[] out = new float[4];
+
+ private static final float[] forward = new float[3];
+ private static final float[] side = new float[3];
+ private static final float[] up = new float[3];
+
+ /**
+ * Make matrix an identity matrix
+ */
+ private static void __gluMakeIdentityf(FloatBuffer m) {
+ int oldPos = m.position();
+ m.put(IDENTITY_MATRIX);
+ m.position(oldPos);
+ }
+
+ /**
+ * Method __gluMultMatrixVecf
+ *
+ * @param m
+ * @param in
+ * @param out
+ */
+ private static void __gluMultMatrixVecf(FloatBuffer m, float[] in, float[] out) {
+ for (int i = 0; i < 4; i++) {
+ out[i] =
+ in[0] * m.get(m.position() + 0*4 + i)
+ + in[1] * m.get(m.position() + 1*4 + i)
+ + in[2] * m.get(m.position() + 2*4 + i)
+ + in[3] * m.get(m.position() + 3*4 + i);
+
+ }
+ }
+
+ /**
+ * @param src
+ * @param inverse
+ *
+ * @return true if the matrix was succesfully inverted
+ */
+ private static boolean __gluInvertMatrixf(FloatBuffer src, FloatBuffer inverse) {
+ int i, j, k, swap;
+ float t;
+ FloatBuffer temp = Project.tempMatrix;
+
+
+ for (i = 0; i < 16; i++) {
+ temp.put(i, src.get(i + src.position()));
+ }
+ __gluMakeIdentityf(inverse);
+
+ for (i = 0; i < 4; i++) {
+ /*
+ * * Look for largest element in column
+ */
+ swap = i;
+ for (j = i + 1; j < 4; j++) {
+ /*
+ * if (fabs(temp[j][i]) > fabs(temp[i][i])) { swap = j;
+ */
+ if (Math.abs(temp.get(j*4 + i)) > Math.abs(temp.get(i* 4 + i))) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ /*
+ * * Swap rows.
+ */
+ for (k = 0; k < 4; k++) {
+ t = temp.get(i*4 + k);
+ temp.put(i*4 + k, temp.get(swap*4 + k));
+ temp.put(swap*4 + k, t);
+
+ t = inverse.get(i*4 + k);
+ inverse.put(i*4 + k, inverse.get(swap*4 + k));
+ //inverse.put((i << 2) + k, inverse.get((swap << 2) + k));
+ inverse.put(swap*4 + k, t);
+ //inverse.put((swap << 2) + k, t);
+ }
+ }
+
+ if (temp.get(i*4 + i) == 0) {
+ /*
+ * * No non-zero pivot. The matrix is singular, which shouldn't *
+ * happen. This means the user gave us a bad matrix.
+ */
+ return false;
+ }
+
+ t = temp.get(i*4 + i);
+ for (k = 0; k < 4; k++) {
+ temp.put(i*4 + k, temp.get(i*4 + k)/t);
+ inverse.put(i*4 + k, inverse.get(i*4 + k)/t);
+ }
+ for (j = 0; j < 4; j++) {
+ if (j != i) {
+ t = temp.get(j*4 + i);
+ for (k = 0; k < 4; k++) {
+ temp.put(j*4 + k, temp.get(j*4 + k) - temp.get(i*4 + k) * t);
+ inverse.put(j*4 + k, inverse.get(j*4 + k) - inverse.get(i*4 + k) * t);
+ /*inverse.put(
+ (j << 2) + k,
+ inverse.get((j << 2) + k) - inverse.get((i << 2) + k) * t);*/
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @param a
+ * @param b
+ * @param r
+ */
+ private static void __gluMultMatricesf(FloatBuffer a, FloatBuffer b, FloatBuffer r) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ r.put(r.position() + i*4 + j,
+ a.get(a.position() + i*4 + 0) * b.get(b.position() + 0*4 + j) + a.get(a.position() + i*4 + 1) * b.get(b.position() + 1*4 + j) + a.get(a.position() + i*4 + 2) * b.get(b.position() + 2*4 + j) + a.get(a.position() + i*4 + 3) * b.get(b.position() + 3*4 + j));
+ }
+ }
+ }
+
+ /**
+ * Method gluPerspective.
+ *
+ * @param fovy
+ * @param aspect
+ * @param zNear
+ * @param zFar
+ */
+ public static void gluPerspective(float fovy, float aspect, float zNear, float zFar) {
+ float sine, cotangent, deltaZ;
+ float radians = fovy / 2 * GLU.PI / 180;
+
+ deltaZ = zFar - zNear;
+ sine = (float) Math.sin(radians);
+
+ if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
+ return;
+ }
+
+ cotangent = (float) Math.cos(radians) / sine;
+
+ __gluMakeIdentityf(matrix);
+
+ matrix.put(0 * 4 + 0, cotangent / aspect);
+ matrix.put(1 * 4 + 1, cotangent);
+ matrix.put(2 * 4 + 2, - (zFar + zNear) / deltaZ);
+ matrix.put(2 * 4 + 3, -1);
+ matrix.put(3 * 4 + 2, -2 * zNear * zFar / deltaZ);
+ matrix.put(3 * 4 + 3, 0);
+
+ glMultMatrixf(matrix);
+ }
+
+ /**
+ * Method gluLookAt
+ *
+ * @param eyex
+ * @param eyey
+ * @param eyez
+ * @param centerx
+ * @param centery
+ * @param centerz
+ * @param upx
+ * @param upy
+ * @param upz
+ */
+ public static void gluLookAt(
+ float eyex,
+ float eyey,
+ float eyez,
+ float centerx,
+ float centery,
+ float centerz,
+ float upx,
+ float upy,
+ float upz) {
+ float[] forward = Project.forward;
+ float[] side = Project.side;
+ float[] up = Project.up;
+
+ forward[0] = centerx - eyex;
+ forward[1] = centery - eyey;
+ forward[2] = centerz - eyez;
+
+ up[0] = upx;
+ up[1] = upy;
+ up[2] = upz;
+
+ normalize(forward);
+
+ /* Side = forward x up */
+ cross(forward, up, side);
+ normalize(side);
+
+ /* Recompute up as: up = side x forward */
+ cross(side, forward, up);
+
+ __gluMakeIdentityf(matrix);
+ matrix.put(0 * 4 + 0, side[0]);
+ matrix.put(1 * 4 + 0, side[1]);
+ matrix.put(2 * 4 + 0, side[2]);
+
+ matrix.put(0 * 4 + 1, up[0]);
+ matrix.put(1 * 4 + 1, up[1]);
+ matrix.put(2 * 4 + 1, up[2]);
+
+ matrix.put(0 * 4 + 2, -forward[0]);
+ matrix.put(1 * 4 + 2, -forward[1]);
+ matrix.put(2 * 4 + 2, -forward[2]);
+
+ glMultMatrixf(matrix);
+ glTranslatef(-eyex, -eyey, -eyez);
+ }
+
+ /**
+ * Method gluProject
+ *
+ * @param objx
+ * @param objy
+ * @param objz
+ * @param modelMatrix
+ * @param projMatrix
+ * @param viewport
+ * @param win_pos
+ */
+ public static boolean gluProject(
+ float objx,
+ float objy,
+ float objz,
+ FloatBuffer modelMatrix,
+ FloatBuffer projMatrix,
+ IntBuffer viewport,
+ FloatBuffer win_pos) {
+
+ float[] in = Project.in;
+ float[] out = Project.out;
+
+ in[0] = objx;
+ in[1] = objy;
+ in[2] = objz;
+ in[3] = 1.0f;
+
+ __gluMultMatrixVecf(modelMatrix, in, out);
+ __gluMultMatrixVecf(projMatrix, out, in);
+
+ if (in[3] == 0.0)
+ return false;
+
+ in[3] = (1.0f / in[3]) * 0.5f;
+
+ // Map x, y and z to range 0-1
+ in[0] = in[0] * in[3] + 0.5f;
+ in[1] = in[1] * in[3] + 0.5f;
+ in[2] = in[2] * in[3] + 0.5f;
+
+ // Map x,y to viewport
+ win_pos.put(0, in[0] * viewport.get(viewport.position() + 2) + viewport.get(viewport.position() + 0));
+ win_pos.put(1, in[1] * viewport.get(viewport.position() + 3) + viewport.get(viewport.position() + 1));
+ win_pos.put(2, in[2]);
+
+ return true;
+ }
+
+ /**
+ * Method gluUnproject
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param modelMatrix
+ * @param projMatrix
+ * @param viewport
+ * @param obj_pos
+ */
+ public static boolean gluUnProject(
+ float winx,
+ float winy,
+ float winz,
+ FloatBuffer modelMatrix,
+ FloatBuffer projMatrix,
+ IntBuffer viewport,
+ FloatBuffer obj_pos) {
+ float[] in = Project.in;
+ float[] out = Project.out;
+
+ __gluMultMatricesf(modelMatrix, projMatrix, finalMatrix);
+
+ if (!__gluInvertMatrixf(finalMatrix, finalMatrix))
+ return false;
+
+ in[0] = winx;
+ in[1] = winy;
+ in[2] = winz;
+ in[3] = 1.0f;
+
+ // Map x and y from window coordinates
+ in[0] = (in[0] - viewport.get(viewport.position() + 0)) / viewport.get(viewport.position() + 2);
+ in[1] = (in[1] - viewport.get(viewport.position() + 1)) / viewport.get(viewport.position() + 3);
+
+ // Map to range -1 to 1
+ in[0] = in[0] * 2 - 1;
+ in[1] = in[1] * 2 - 1;
+ in[2] = in[2] * 2 - 1;
+
+ __gluMultMatrixVecf(finalMatrix, in, out);
+
+ if (out[3] == 0.0)
+ return false;
+
+ out[3] = 1.0f / out[3];
+
+ obj_pos.put(obj_pos.position() + 0, out[0] * out[3]);
+ obj_pos.put(obj_pos.position() + 1, out[1] * out[3]);
+ obj_pos.put(obj_pos.position() + 2, out[2] * out[3]);
+
+ return true;
+ }
+
+ /**
+ * Method gluPickMatrix
+ *
+ * @param x
+ * @param y
+ * @param deltaX
+ * @param deltaY
+ * @param viewport
+ */
+ public static void gluPickMatrix(
+ float x,
+ float y,
+ float deltaX,
+ float deltaY,
+ IntBuffer viewport) {
+ if (deltaX <= 0 || deltaY <= 0) {
+ return;
+ }
+
+ /* Translate and scale the picked region to the entire window */
+ glTranslatef(
+ (viewport.get(viewport.position() + 2) - 2 * (x - viewport.get(viewport.position() + 0))) / deltaX,
+ (viewport.get(viewport.position() + 3) - 2 * (y - viewport.get(viewport.position() + 1))) / deltaY,
+ 0);
+ glScalef(viewport.get(viewport.position() + 2) / deltaX, viewport.get(viewport.position() + 3) / deltaY, 1.0f);
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Quadric.java b/src/de/verschwiegener/lwjgl3/util/glu/Quadric.java
new file mode 100644
index 0000000..779f98e
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Quadric.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * Quadric.java
+ *
+ *
+ * Created 22-dec-2003
+ * @author Erik Duijs
+ */
+public class Quadric {
+
+ protected int drawStyle;
+ protected int orientation;
+ protected boolean textureFlag;
+ protected int normals;
+
+ /**
+ * Constructor for Quadric.
+ */
+ public Quadric() {
+ super();
+
+ drawStyle = GLU_FILL;
+ orientation = GLU_OUTSIDE;
+ textureFlag = false;
+ normals = GLU_SMOOTH;
+ }
+
+ /**
+ * Call glNormal3f after scaling normal to unit length.
+ *
+ * @param x
+ * @param y
+ * @param z
+ */
+ protected void normal3f(float x, float y, float z) {
+ float mag;
+
+ mag = (float)Math.sqrt(x * x + y * y + z * z);
+ if (mag > 0.00001F) {
+ x /= mag;
+ y /= mag;
+ z /= mag;
+ }
+ glNormal3f(x, y, z);
+ }
+
+ /**
+ * specifies the draw style for quadrics.
+ *
+ * The legal values are as follows:
+ *
+ * GLU.FILL: Quadrics are rendered with polygon primitives. The polygons
+ * are drawn in a counterclockwise fashion with respect to
+ * their normals (as defined with glu.quadricOrientation).
+ *
+ * GLU.LINE: Quadrics are rendered as a set of lines.
+ *
+ * GLU.SILHOUETTE: Quadrics are rendered as a set of lines, except that edges
+ * separating coplanar faces will not be drawn.
+ *
+ * GLU.POINT: Quadrics are rendered as a set of points.
+ *
+ * @param drawStyle The drawStyle to set
+ */
+ public void setDrawStyle(int drawStyle) {
+ this.drawStyle = drawStyle;
+ }
+
+ /**
+ * specifies what kind of normals are desired for quadrics.
+ * The legal values are as follows:
+ *
+ * GLU.NONE: No normals are generated.
+ *
+ * GLU.FLAT: One normal is generated for every facet of a quadric.
+ *
+ * GLU.SMOOTH: One normal is generated for every vertex of a quadric. This
+ * is the default.
+ *
+ * @param normals The normals to set
+ */
+ public void setNormals(int normals) {
+ this.normals = normals;
+ }
+
+ /**
+ * specifies what kind of orientation is desired for.
+ * The orientation values are as follows:
+ *
+ * GLU.OUTSIDE: Quadrics are drawn with normals pointing outward.
+ *
+ * GLU.INSIDE: Normals point inward. The default is GLU.OUTSIDE.
+ *
+ * Note that the interpretation of outward and inward depends on the quadric
+ * being drawn.
+ *
+ * @param orientation The orientation to set
+ */
+ public void setOrientation(int orientation) {
+ this.orientation = orientation;
+ }
+
+ /**
+ * specifies if texture coordinates should be generated for
+ * quadrics rendered with qobj. If the value of textureCoords is true,
+ * then texture coordinates are generated, and if textureCoords is false,
+ * they are not.. The default is false.
+ *
+ * The manner in which texture coordinates are generated depends upon the
+ * specific quadric rendered.
+ *
+ * @param textureFlag The textureFlag to set
+ */
+ public void setTextureFlag(boolean textureFlag) {
+ this.textureFlag = textureFlag;
+ }
+
+
+ /**
+ * Returns the drawStyle.
+ * @return int
+ */
+ public int getDrawStyle() {
+ return drawStyle;
+ }
+
+ /**
+ * Returns the normals.
+ * @return int
+ */
+ public int getNormals() {
+ return normals;
+ }
+
+ /**
+ * Returns the orientation.
+ * @return int
+ */
+ public int getOrientation() {
+ return orientation;
+ }
+
+ /**
+ * Returns the textureFlag.
+ * @return boolean
+ */
+ public boolean getTextureFlag() {
+ return textureFlag;
+ }
+
+ protected void TXTR_COORD(float x, float y) {
+ if (textureFlag) glTexCoord2f(x,y);
+ }
+
+
+ protected float sin(float r) {
+ return (float)Math.sin(r);
+ }
+
+ protected float cos(float r) {
+ return (float)Math.cos(r);
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Registry.java b/src/de/verschwiegener/lwjgl3/util/glu/Registry.java
new file mode 100644
index 0000000..0ec70fa
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Registry.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * Registry.java
+ *
+ *
+ * Created 11-jan-2004
+ * @author Erik Duijs
+ */
+public class Registry extends Util {
+
+ private static final String versionString = "1.3";
+ private static final String extensionString =
+ "GLU_EXT_nurbs_tessellator " + "GLU_EXT_object_space_tess ";
+
+ /**
+ * Method gluGetString
+ * @param name
+ * @return String
+ */
+ public static String gluGetString(int name) {
+
+ if (name == GLU_VERSION) {
+ return versionString;
+ } else if (name == GLU_EXTENSIONS) {
+ return extensionString;
+ }
+ return null;
+ }
+
+ /**
+ * Method gluCheckExtension
+ *
+ * @param extName is an extension name.
+ * @param extString is a string of extensions separated by blank(s). There may or
+ * may not be leading or trailing blank(s) in extString.
+ * This works in cases of extensions being prefixes of another like
+ * GL_EXT_texture and GL_EXT_texture3D.
+ * @return boolean true if extName is found otherwise it returns false.
+ */
+ public static boolean gluCheckExtension(String extName, String extString) {
+ if (extString == null || extName == null)
+ return false;
+
+ return extString.indexOf(extName) != -1;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Sphere.java b/src/de/verschwiegener/lwjgl3/util/glu/Sphere.java
new file mode 100644
index 0000000..12afee4
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Sphere.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+/**
+ * Sphere.java
+ *
+ *
+ * Created 23-dec-2003
+ * @author Erik Duijs
+ */
+public class Sphere extends Quadric {
+
+ /**
+ * Constructor
+ */
+ public Sphere() {
+ super();
+ }
+
+ /**
+ * draws a sphere of the given radius centered around the origin.
+ * The sphere is subdivided around the z axis into slices and along the z axis
+ * into stacks (similar to lines of longitude and latitude).
+ *
+ * If the orientation is set to GLU.OUTSIDE (with glu.quadricOrientation), then
+ * any normals generated point away from the center of the sphere. Otherwise,
+ * they point toward the center of the sphere.
+
+ * If texturing is turned on (with glu.quadricTexture), then texture
+ * coordinates are generated so that t ranges from 0.0 at z=-radius to 1.0 at
+ * z=radius (t increases linearly along longitudinal lines), and s ranges from
+ * 0.0 at the +y axis, to 0.25 at the +x axis, to 0.5 at the -y axis, to 0.75
+ * at the -x axis, and back to 1.0 at the +y axis.
+ */
+ public void draw(float radius, int slices, int stacks) {
+
+ float rho, drho, theta, dtheta;
+ float x, y, z;
+ float s, t, ds, dt;
+ int i, j, imin, imax;
+ boolean normals;
+ float nsign;
+
+ normals = super.normals != GLU_NONE;
+
+ if (super.orientation == GLU_INSIDE) {
+ nsign = -1.0f;
+ } else {
+ nsign = 1.0f;
+ }
+
+ drho = PI / stacks;
+ dtheta = 2.0f * PI / slices;
+
+ if (super.drawStyle == GLU_FILL) {
+ if (!super.textureFlag) {
+ // draw +Z end as a triangle fan
+ glBegin(GL_TRIANGLE_FAN);
+ glNormal3f(0.0f, 0.0f, 1.0f);
+ glVertex3f(0.0f, 0.0f, nsign * radius);
+ for (j = 0; j <= slices; j++) {
+ theta = (j == slices) ? 0.0f : j * dtheta;
+ x = -sin(theta) * sin(drho);
+ y = cos(theta) * sin(drho);
+ z = nsign * cos(drho);
+ if (normals) {
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ }
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+
+ ds = 1.0f / slices;
+ dt = 1.0f / stacks;
+ t = 1.0f; // because loop now runs from 0
+ if (super.textureFlag) {
+ imin = 0;
+ imax = stacks;
+ } else {
+ imin = 1;
+ imax = stacks - 1;
+ }
+
+ // draw intermediate stacks as quad strips
+ for (i = imin; i < imax; i++) {
+ rho = i * drho;
+ glBegin(GL_QUAD_STRIP);
+ s = 0.0f;
+ for (j = 0; j <= slices; j++) {
+ theta = (j == slices) ? 0.0f : j * dtheta;
+ x = -sin(theta) * sin(rho);
+ y = cos(theta) * sin(rho);
+ z = nsign * cos(rho);
+ if (normals) {
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ }
+ TXTR_COORD(s, t);
+ glVertex3f(x * radius, y * radius, z * radius);
+ x = -sin(theta) * sin(rho + drho);
+ y = cos(theta) * sin(rho + drho);
+ z = nsign * cos(rho + drho);
+ if (normals) {
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ }
+ TXTR_COORD(s, t - dt);
+ s += ds;
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ t -= dt;
+ }
+
+ if (!super.textureFlag) {
+ // draw -Z end as a triangle fan
+ glBegin(GL_TRIANGLE_FAN);
+ glNormal3f(0.0f, 0.0f, -1.0f);
+ glVertex3f(0.0f, 0.0f, -radius * nsign);
+ rho = PI - drho;
+ s = 1.0f;
+ for (j = slices; j >= 0; j--) {
+ theta = (j == slices) ? 0.0f : j * dtheta;
+ x = -sin(theta) * sin(rho);
+ y = cos(theta) * sin(rho);
+ z = nsign * cos(rho);
+ if (normals)
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ s -= ds;
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ } else if (
+ super.drawStyle == GLU_LINE
+ || super.drawStyle == GLU_SILHOUETTE) {
+ // draw stack lines
+ for (i = 1;
+ i < stacks;
+ i++) { // stack line at i==stacks-1 was missing here
+ rho = i * drho;
+ glBegin(GL_LINE_LOOP);
+ for (j = 0; j < slices; j++) {
+ theta = j * dtheta;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ if (normals)
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ // draw slice lines
+ for (j = 0; j < slices; j++) {
+ theta = j * dtheta;
+ glBegin(GL_LINE_STRIP);
+ for (i = 0; i <= stacks; i++) {
+ rho = i * drho;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ if (normals)
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ } else if (super.drawStyle == GLU_POINT) {
+ // top and bottom-most points
+ glBegin(GL_POINTS);
+ if (normals)
+ glNormal3f(0.0f, 0.0f, nsign);
+ glVertex3f(0.0f, 0.0f, radius);
+ if (normals)
+ glNormal3f(0.0f, 0.0f, -nsign);
+ glVertex3f(0.0f, 0.0f, -radius);
+
+ // loop over stacks
+ for (i = 1; i < stacks - 1; i++) {
+ rho = i * drho;
+ for (j = 0; j < slices; j++) {
+ theta = j * dtheta;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ if (normals)
+ glNormal3f(x * nsign, y * nsign, z * nsign);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ }
+ glEnd();
+ }
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/Util.java b/src/de/verschwiegener/lwjgl3/util/glu/Util.java
new file mode 100644
index 0000000..202995d
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/Util.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.glu;
+
+import java.nio.IntBuffer;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.GL11;
+
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL12.*;
+
+/**
+ * Util.java
+ *
+ *
+ * Created 7-jan-2004
+ *
+ * @author Erik Duijs
+ */
+public class Util {
+
+ /**
+ * temp IntBuffer of one for getting an int from some GL functions
+ */
+ private static IntBuffer scratch = BufferUtils.createIntBuffer(16);
+
+ /**
+ * Return ceiling of integer division
+ *
+ * @param a
+ * @param b
+ *
+ * @return int
+ */
+ protected static int ceil(int a, int b) {
+ return (a % b == 0 ? a / b : a / b + 1);
+ }
+
+ /**
+ * Normalize vector
+ *
+ * @param v
+ *
+ * @return float[]
+ */
+ protected static float[] normalize(float[] v) {
+ float r;
+
+ r = (float)Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ if ( r == 0.0 )
+ return v;
+
+ r = 1.0f / r;
+
+ v[0] *= r;
+ v[1] *= r;
+ v[2] *= r;
+
+ return v;
+ }
+
+ /**
+ * Calculate cross-product
+ *
+ * @param v1
+ * @param v2
+ * @param result
+ */
+ protected static void cross(float[] v1, float[] v2, float[] result) {
+ result[0] = v1[1] * v2[2] - v1[2] * v2[1];
+ result[1] = v1[2] * v2[0] - v1[0] * v2[2];
+ result[2] = v1[0] * v2[1] - v1[1] * v2[0];
+ }
+
+ /**
+ * Method compPerPix.
+ *
+ * @param format
+ *
+ * @return int
+ */
+ protected static int compPerPix(int format) {
+ /* Determine number of components per pixel */
+ switch ( format ) {
+ case GL_COLOR_INDEX:
+ case GL_STENCIL_INDEX:
+ case GL_DEPTH_COMPONENT:
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ return 1;
+ case GL_LUMINANCE_ALPHA:
+ return 2;
+ case GL_RGB:
+ case GL_BGR:
+ return 3;
+ case GL_RGBA:
+ case GL_BGRA:
+ return 4;
+ default :
+ return -1;
+ }
+ }
+
+ /**
+ * Method nearestPower.
+ *
+ * Compute the nearest power of 2 number. This algorithm is a little strange, but it works quite well.
+ *
+ * @param value
+ *
+ * @return int
+ */
+ protected static int nearestPower(int value) {
+ int i;
+
+ i = 1;
+
+ /* Error! */
+ if ( value == 0 )
+ return -1;
+
+ for ( ; ; ) {
+ if ( value == 1 ) {
+ return i;
+ } else if ( value == 3 ) {
+ return i << 2;
+ }
+ value >>= 1;
+ i <<= 1;
+ }
+ }
+
+ /**
+ * Method bytesPerPixel.
+ *
+ * @param format
+ * @param type
+ *
+ * @return int
+ */
+ protected static int bytesPerPixel(int format, int type) {
+ int n, m;
+
+ switch ( format ) {
+ case GL_COLOR_INDEX:
+ case GL_STENCIL_INDEX:
+ case GL_DEPTH_COMPONENT:
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ n = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ n = 2;
+ break;
+ case GL_RGB:
+ case GL_BGR:
+ n = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+ n = 4;
+ break;
+ default :
+ n = 0;
+ }
+
+ switch ( type ) {
+ case GL_UNSIGNED_BYTE:
+ m = 1;
+ break;
+ case GL_BYTE:
+ m = 1;
+ break;
+ case GL_BITMAP:
+ m = 1;
+ break;
+ case GL_UNSIGNED_SHORT:
+ m = 2;
+ break;
+ case GL_SHORT:
+ m = 2;
+ break;
+ case GL_UNSIGNED_INT:
+ m = 4;
+ break;
+ case GL_INT:
+ m = 4;
+ break;
+ case GL_FLOAT:
+ m = 4;
+ break;
+ default :
+ m = 0;
+ }
+
+ return n * m;
+ }
+
+ /**
+ * Convenience method for returning an int, rather than getting it out of a buffer yourself.
+ *
+ * @param what
+ *
+ * @return int
+ */
+ protected static int glGetIntegerv(int what) {
+ scratch.rewind();
+ GL11.glGetIntegerv(what, scratch);
+ return scratch.get();
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/ActiveRegion.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/ActiveRegion.java
new file mode 100644
index 0000000..981088b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/ActiveRegion.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class ActiveRegion {
+ GLUhalfEdge eUp; /* upper edge, directed right to left */
+ DictNode nodeUp; /* dictionary node corresponding to eUp */
+ int windingNumber; /* used to determine which regions are
+ * inside the polygon */
+ boolean inside; /* is this region inside the polygon? */
+ boolean sentinel; /* marks fake edges at t = +/-infinity */
+ boolean dirty; /* marks regions where the upper or lower
+ * edge has changed, but we haven't checked
+ * whether they intersect yet */
+ boolean fixUpperEdge; /* marks temporary edges introduced when
+ * we process a "right vertex" (one without
+ * any edges leaving to the right) */
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/CachedVertex.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/CachedVertex.java
new file mode 100644
index 0000000..1fc75aa
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/CachedVertex.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class CachedVertex {
+ public double[] coords = new double[3];
+ public Object data;
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Dict.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Dict.java
new file mode 100644
index 0000000..1e6f806
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Dict.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class Dict {
+ DictNode head;
+ Object frame;
+ DictLeq leq;
+
+ private Dict() {
+ }
+
+ static Dict dictNewDict(Object frame, DictLeq leq) {
+ Dict dict = new Dict();
+ dict.head = new DictNode();
+
+ dict.head.key = null;
+ dict.head.next = dict.head;
+ dict.head.prev = dict.head;
+
+ dict.frame = frame;
+ dict.leq = leq;
+
+ return dict;
+ }
+
+ static void dictDeleteDict(Dict dict) {
+ dict.head = null;
+ dict.frame = null;
+ dict.leq = null;
+ }
+
+ static DictNode dictInsert(Dict dict, Object key) {
+ return dictInsertBefore(dict, dict.head, key);
+ }
+
+ static DictNode dictInsertBefore(Dict dict, DictNode node, Object key) {
+ do {
+ node = node.prev;
+ } while (node.key != null && !dict.leq.leq(dict.frame, node.key, key));
+
+ DictNode newNode = new DictNode();
+ newNode.key = key;
+ newNode.next = node.next;
+ node.next.prev = newNode;
+ newNode.prev = node;
+ node.next = newNode;
+
+ return newNode;
+ }
+
+ static Object dictKey(DictNode aNode) {
+ return aNode.key;
+ }
+
+ static DictNode dictSucc(DictNode aNode) {
+ return aNode.next;
+ }
+
+ static DictNode dictPred(DictNode aNode) {
+ return aNode.prev;
+ }
+
+ static DictNode dictMin(Dict aDict) {
+ return aDict.head.next;
+ }
+
+ static DictNode dictMax(Dict aDict) {
+ return aDict.head.prev;
+ }
+
+ static void dictDelete(Dict dict, DictNode node) {
+ node.next.prev = node.prev;
+ node.prev.next = node.next;
+ }
+
+ static DictNode dictSearch(Dict dict, Object key) {
+ DictNode node = dict.head;
+
+ do {
+ node = node.next;
+ } while (node.key != null && !(dict.leq.leq(dict.frame, key, node.key)));
+
+ return node;
+ }
+
+ public interface DictLeq {
+ boolean leq(Object frame, Object key1, Object key2);
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/DictNode.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/DictNode.java
new file mode 100644
index 0000000..9d40123
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/DictNode.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class DictNode {
+ Object key;
+ DictNode next;
+ DictNode prev;
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUface.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUface.java
new file mode 100644
index 0000000..9b8beb3
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUface.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class GLUface {
+ public GLUface next; /* next face (never NULL) */
+ public GLUface prev; /* previous face (never NULL) */
+ public GLUhalfEdge anEdge; /* a half edge with this left face */
+ public Object data; /* room for client's data */
+
+ /* Internal data (keep hidden) */
+ public GLUface trail; /* "stack" for conversion to strips */
+ public boolean marked; /* flag for conversion to strips */
+ public boolean inside; /* this face is in the polygon interior */
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUhalfEdge.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUhalfEdge.java
new file mode 100644
index 0000000..7e1fb87
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUhalfEdge.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+
+
+class GLUhalfEdge {
+ public GLUhalfEdge next; /* doubly-linked list (prev==Sym->next) */
+ public GLUhalfEdge Sym; /* same edge, opposite direction */
+ public GLUhalfEdge Onext; /* next edge CCW around origin */
+ public GLUhalfEdge Lnext; /* next edge CCW around left face */
+ public GLUvertex Org; /* origin vertex (Overtex too long) */
+ public GLUface Lface; /* left face */
+
+ /* Internal data (keep hidden) */
+ public ActiveRegion activeRegion; /* a region with this upper edge (sweep.c) */
+ public int winding; /* change in winding number when crossing */
+ public boolean first;
+
+ GLUhalfEdge(boolean first) {
+ this.first = first;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUmesh.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUmesh.java
new file mode 100644
index 0000000..790b8f3
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUmesh.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+
+
+class GLUmesh {
+ GLUvertex vHead = new GLUvertex(); /* dummy header for vertex list */
+ GLUface fHead = new GLUface(); /* dummy header for face list */
+ GLUhalfEdge eHead = new GLUhalfEdge(true); /* dummy header for edge list */
+ GLUhalfEdge eHeadSym = new GLUhalfEdge(false); /* and its symmetric counterpart */
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUtessellatorImpl.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUtessellatorImpl.java
new file mode 100644
index 0000000..fd1d19e
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUtessellatorImpl.java
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+
+import de.verschwiegener.lwjgl3.util.glu.GLUtessellator;
+import de.verschwiegener.lwjgl3.util.glu.GLUtessellatorCallback;
+import de.verschwiegener.lwjgl3.util.glu.GLUtessellatorCallbackAdapter;
+
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+public class GLUtessellatorImpl implements GLUtessellator {
+ public static final int TESS_MAX_CACHE = 100;
+
+ private int state; /* what begin/end calls have we seen? */
+
+ private GLUhalfEdge lastEdge; /* lastEdge->Org is the most recent vertex */
+ GLUmesh mesh; /* stores the input contours, and eventually
+ the tessellation itself */
+
+ /*** state needed for projecting onto the sweep plane ***/
+
+ double[] normal = new double[3]; /* user-specified normal (if provided) */
+ double[] sUnit = new double[3]; /* unit vector in s-direction (debugging) */
+ double[] tUnit = new double[3]; /* unit vector in t-direction (debugging) */
+
+ /*** state needed for the line sweep ***/
+
+ private double relTolerance; /* tolerance for merging features */
+ int windingRule; /* rule for determining polygon interior */
+ boolean fatalError; /* fatal error: needed combine callback */
+
+ Dict dict; /* edge dictionary for sweep line */
+ PriorityQ pq; /* priority queue of vertex events */
+ GLUvertex event; /* current sweep event being processed */
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+
+ boolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
+ boolean boundaryOnly; /* Extract contours, not triangles */
+ GLUface lonelyTriList;
+ /* list of triangles which could not be rendered as strips or fans */
+
+
+
+ /*** state needed to cache single-contour polygons for renderCache() */
+
+ private boolean flushCacheOnNextVertex; /* empty cache on next vertex() call */
+ int cacheCount; /* number of cached vertices */
+ CachedVertex[] cache = new CachedVertex[TESS_MAX_CACHE]; /* the vertex data */
+
+ /*** rendering callbacks that also pass polygon data ***/
+ private Object polygonData; /* client data for current polygon */
+
+ private GLUtessellatorCallback callBegin;
+ private GLUtessellatorCallback callEdgeFlag;
+ private GLUtessellatorCallback callVertex;
+ private GLUtessellatorCallback callEnd;
+// private GLUtessellatorCallback callMesh;
+ private GLUtessellatorCallback callError;
+ private GLUtessellatorCallback callCombine;
+
+ private GLUtessellatorCallback callBeginData;
+ private GLUtessellatorCallback callEdgeFlagData;
+ private GLUtessellatorCallback callVertexData;
+ private GLUtessellatorCallback callEndData;
+// private GLUtessellatorCallback callMeshData;
+ private GLUtessellatorCallback callErrorData;
+ private GLUtessellatorCallback callCombineData;
+
+ private static final double GLU_TESS_DEFAULT_TOLERANCE = 0.0;
+// private static final int GLU_TESS_MESH = 100112; /* void (*)(GLUmesh *mesh) */
+ private static GLUtessellatorCallback NULL_CB = new GLUtessellatorCallbackAdapter();
+
+// #define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
+// MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+ public GLUtessellatorImpl() {
+ state = TessState.T_DORMANT;
+
+ normal[0] = 0;
+ normal[1] = 0;
+ normal[2] = 0;
+
+ relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+ windingRule = GLU_TESS_WINDING_ODD;
+ flagBoundary = false;
+ boundaryOnly = false;
+
+ callBegin = NULL_CB;
+ callEdgeFlag = NULL_CB;
+ callVertex = NULL_CB;
+ callEnd = NULL_CB;
+ callError = NULL_CB;
+ callCombine = NULL_CB;
+// callMesh = NULL_CB;
+
+ callBeginData = NULL_CB;
+ callEdgeFlagData = NULL_CB;
+ callVertexData = NULL_CB;
+ callEndData = NULL_CB;
+ callErrorData = NULL_CB;
+ callCombineData = NULL_CB;
+
+ polygonData = null;
+
+ for (int i = 0; i < cache.length; i++) {
+ cache[i] = new CachedVertex();
+ }
+ }
+
+ public static GLUtessellator gluNewTess()
+ {
+ return new GLUtessellatorImpl();
+ }
+
+
+ private void makeDormant() {
+ /* Return the tessellator to its original dormant state. */
+
+ if (mesh != null) {
+ Mesh.__gl_meshDeleteMesh(mesh);
+ }
+ state = TessState.T_DORMANT;
+ lastEdge = null;
+ mesh = null;
+ }
+
+ private void requireState(int newState) {
+ if (state != newState) gotoState(newState);
+ }
+
+ private void gotoState(int newState) {
+ while (state != newState) {
+ /* We change the current state one level at a time, to get to
+ * the desired state.
+ */
+ if (state < newState) {
+ if (state == TessState.T_DORMANT) {
+ callErrorOrErrorData(GLU_TESS_MISSING_BEGIN_POLYGON);
+ gluTessBeginPolygon(null);
+ } else if (state == TessState.T_IN_POLYGON) {
+ callErrorOrErrorData(GLU_TESS_MISSING_BEGIN_CONTOUR);
+ gluTessBeginContour();
+ }
+ } else {
+ if (state == TessState.T_IN_CONTOUR) {
+ callErrorOrErrorData(GLU_TESS_MISSING_END_CONTOUR);
+ gluTessEndContour();
+ } else if (state == TessState.T_IN_POLYGON) {
+ callErrorOrErrorData(GLU_TESS_MISSING_END_POLYGON);
+ /* gluTessEndPolygon( tess ) is too much work! */
+ makeDormant();
+ }
+ }
+ }
+ }
+
+ public void gluDeleteTess() {
+ requireState(TessState.T_DORMANT);
+ }
+
+ public void gluTessProperty(int which, double value) {
+ switch (which) {
+ case GLU_TESS_TOLERANCE:
+ if (value < 0.0 || value > 1.0) break;
+ relTolerance = value;
+ return;
+
+ case GLU_TESS_WINDING_RULE:
+ int windingRule = (int) value;
+ if (windingRule != value) break; /* not an integer */
+
+ switch (windingRule) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ case GLU_TESS_WINDING_POSITIVE:
+ case GLU_TESS_WINDING_NEGATIVE:
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ this.windingRule = windingRule;
+ return;
+ default:
+ break;
+ }
+
+ case GLU_TESS_BOUNDARY_ONLY:
+ boundaryOnly = (value != 0);
+ return;
+
+ default:
+ callErrorOrErrorData(GLU_INVALID_ENUM);
+ return;
+ }
+ callErrorOrErrorData(GLU_INVALID_VALUE);
+ }
+
+/* Returns tessellator property */
+ public void gluGetTessProperty(int which, double[] value, int value_offset) {
+ switch (which) {
+ case GLU_TESS_TOLERANCE:
+/* tolerance should be in range [0..1] */
+ assert (0.0 <= relTolerance && relTolerance <= 1.0);
+ value[value_offset] = relTolerance;
+ break;
+ case GLU_TESS_WINDING_RULE:
+ assert (windingRule == GLU_TESS_WINDING_ODD ||
+ windingRule == GLU_TESS_WINDING_NONZERO ||
+ windingRule == GLU_TESS_WINDING_POSITIVE ||
+ windingRule == GLU_TESS_WINDING_NEGATIVE ||
+ windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
+ value[value_offset] = windingRule;
+ break;
+ case GLU_TESS_BOUNDARY_ONLY:
+ assert (boundaryOnly == true || boundaryOnly == false);
+ value[value_offset] = boundaryOnly ? 1 : 0;
+ break;
+ default:
+ value[value_offset] = 0.0;
+ callErrorOrErrorData(GLU_INVALID_ENUM);
+ break;
+ }
+ } /* gluGetTessProperty() */
+
+ public void gluTessNormal(double x, double y, double z) {
+ normal[0] = x;
+ normal[1] = y;
+ normal[2] = z;
+ }
+
+ public void gluTessCallback(int which, GLUtessellatorCallback aCallback) {
+ switch (which) {
+ case GLU_TESS_BEGIN:
+ callBegin = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_BEGIN_DATA:
+ callBeginData = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_EDGE_FLAG:
+ callEdgeFlag = aCallback == null ? NULL_CB : aCallback;
+/* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ flagBoundary = aCallback != null;
+ return;
+ case GLU_TESS_EDGE_FLAG_DATA:
+ callEdgeFlagData = callBegin = aCallback == null ? NULL_CB : aCallback;
+/* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ flagBoundary = (aCallback != null);
+ return;
+ case GLU_TESS_VERTEX:
+ callVertex = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_VERTEX_DATA:
+ callVertexData = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_END:
+ callEnd = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_END_DATA:
+ callEndData = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_ERROR:
+ callError = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_ERROR_DATA:
+ callErrorData = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_COMBINE:
+ callCombine = aCallback == null ? NULL_CB : aCallback;
+ return;
+ case GLU_TESS_COMBINE_DATA:
+ callCombineData = aCallback == null ? NULL_CB : aCallback;
+ return;
+// case GLU_TESS_MESH:
+// callMesh = aCallback == null ? NULL_CB : aCallback;
+// return;
+ default:
+ callErrorOrErrorData(GLU_INVALID_ENUM);
+ return;
+ }
+ }
+
+ private boolean addVertex(double[] coords, Object vertexData) {
+ GLUhalfEdge e;
+
+ e = lastEdge;
+ if (e == null) {
+/* Make a self-loop (one vertex, one edge). */
+
+ e = Mesh.__gl_meshMakeEdge(mesh);
+ if (e == null) return false;
+ if (!Mesh.__gl_meshSplice(e, e.Sym)) return false;
+ } else {
+/* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+ if (Mesh.__gl_meshSplitEdge(e) == null) return false;
+ e = e.Lnext;
+ }
+
+/* The new vertex is now e.Org. */
+ e.Org.data = vertexData;
+ e.Org.coords[0] = coords[0];
+ e.Org.coords[1] = coords[1];
+ e.Org.coords[2] = coords[2];
+
+/* The winding of an edge says how the winding number changes as we
+ * cross from the edge''s right face to its left face. We add the
+ * vertices in such an order that a CCW contour will add +1 to
+ * the winding number of the region inside the contour.
+ */
+ e.winding = 1;
+ e.Sym.winding = -1;
+
+ lastEdge = e;
+
+ return true;
+ }
+
+ private void cacheVertex(double[] coords, Object vertexData) {
+ if (cache[cacheCount] == null) {
+ cache[cacheCount] = new CachedVertex();
+ }
+
+ CachedVertex v = cache[cacheCount];
+
+ v.data = vertexData;
+ v.coords[0] = coords[0];
+ v.coords[1] = coords[1];
+ v.coords[2] = coords[2];
+ ++cacheCount;
+ }
+
+
+ private boolean flushCache() {
+ CachedVertex[] v = cache;
+
+ mesh = Mesh.__gl_meshNewMesh();
+ if (mesh == null) return false;
+
+ for (int i = 0; i < cacheCount; i++) {
+ CachedVertex vertex = v[i];
+ if (!addVertex(vertex.coords, vertex.data)) return false;
+ }
+ cacheCount = 0;
+ flushCacheOnNextVertex = false;
+
+ return true;
+ }
+
+ public void gluTessVertex(double[] coords, int coords_offset, Object vertexData) {
+ int i;
+ boolean tooLarge = false;
+ double x;
+ double[] clamped = new double[3];
+
+ requireState(TessState.T_IN_CONTOUR);
+
+ if (flushCacheOnNextVertex) {
+ if (!flushCache()) {
+ callErrorOrErrorData(GLU_OUT_OF_MEMORY);
+ return;
+ }
+ lastEdge = null;
+ }
+ for (i = 0; i < 3; ++i) {
+ x = coords[i+coords_offset];
+ if (x < -GLU_TESS_MAX_COORD) {
+ x = -GLU_TESS_MAX_COORD;
+ tooLarge = true;
+ }
+ if (x > GLU_TESS_MAX_COORD) {
+ x = GLU_TESS_MAX_COORD;
+ tooLarge = true;
+ }
+ clamped[i] = x;
+ }
+ if (tooLarge) {
+ callErrorOrErrorData(GLU_TESS_COORD_TOO_LARGE);
+ }
+
+ if (mesh == null) {
+ if (cacheCount < TESS_MAX_CACHE) {
+ cacheVertex(clamped, vertexData);
+ return;
+ }
+ if (!flushCache()) {
+ callErrorOrErrorData(GLU_OUT_OF_MEMORY);
+ return;
+ }
+ }
+
+ if (!addVertex(clamped, vertexData)) {
+ callErrorOrErrorData(GLU_OUT_OF_MEMORY);
+ }
+ }
+
+
+ public void gluTessBeginPolygon(Object data) {
+ requireState(TessState.T_DORMANT);
+
+ state = TessState.T_IN_POLYGON;
+ cacheCount = 0;
+ flushCacheOnNextVertex = false;
+ mesh = null;
+
+ polygonData = data;
+ }
+
+
+ public void gluTessBeginContour() {
+ requireState(TessState.T_IN_POLYGON);
+
+ state = TessState.T_IN_CONTOUR;
+ lastEdge = null;
+ if (cacheCount > 0) {
+/* Just set a flag so we don't get confused by empty contours
+ * -- these can be generated accidentally with the obsolete
+ * NextContour() interface.
+ */
+ flushCacheOnNextVertex = true;
+ }
+ }
+
+
+ public void gluTessEndContour() {
+ requireState(TessState.T_IN_CONTOUR);
+ state = TessState.T_IN_POLYGON;
+ }
+
+ public void gluTessEndPolygon() {
+ GLUmesh mesh;
+
+ try {
+ requireState(TessState.T_IN_POLYGON);
+ state = TessState.T_DORMANT;
+
+ if (this.mesh == null) {
+ if (!flagBoundary /*&& callMesh == NULL_CB*/) {
+
+/* Try some special code to make the easy cases go quickly
+ * (eg. convex polygons). This code does NOT handle multiple contours,
+ * intersections, edge flags, and of course it does not generate
+ * an explicit mesh either.
+ */
+ if (Render.__gl_renderCache(this)) {
+ polygonData = null;
+ return;
+ }
+ }
+ if (!flushCache()) throw new RuntimeException(); /* could've used a label*/
+ }
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ Normal.__gl_projectPolygon(this);
+
+/* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+ if (!Sweep.__gl_computeInterior(this)) {
+ throw new RuntimeException(); /* could've used a label */
+ }
+
+ mesh = this.mesh;
+ if (!fatalError) {
+ boolean rc = true;
+
+/* If the user wants only the boundary contours, we throw away all edges
+ * except those which separate the interior from the exterior.
+ * Otherwise we tessellate all the regions marked "inside".
+ */
+ if (boundaryOnly) {
+ rc = TessMono.__gl_meshSetWindingNumber(mesh, 1, true);
+ } else {
+ rc = TessMono.__gl_meshTessellateInterior(mesh);
+ }
+ if (!rc) throw new RuntimeException(); /* could've used a label */
+
+ Mesh.__gl_meshCheckMesh(mesh);
+
+ if (callBegin != NULL_CB || callEnd != NULL_CB
+ || callVertex != NULL_CB || callEdgeFlag != NULL_CB
+ || callBeginData != NULL_CB
+ || callEndData != NULL_CB
+ || callVertexData != NULL_CB
+ || callEdgeFlagData != NULL_CB) {
+ if (boundaryOnly) {
+ Render.__gl_renderBoundary(this, mesh); /* output boundary contours */
+ } else {
+ Render.__gl_renderMesh(this, mesh); /* output strips and fans */
+ }
+ }
+// if (callMesh != NULL_CB) {
+//
+///* Throw away the exterior faces, so that all faces are interior.
+// * This way the user doesn't have to check the "inside" flag,
+// * and we don't need to even reveal its existence. It also leaves
+// * the freedom for an implementation to not generate the exterior
+// * faces in the first place.
+// */
+// TessMono.__gl_meshDiscardExterior(mesh);
+// callMesh.mesh(mesh); /* user wants the mesh itself */
+// mesh = null;
+// polygonData = null;
+// return;
+// }
+ }
+ Mesh.__gl_meshDeleteMesh(mesh);
+ polygonData = null;
+ mesh = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ callErrorOrErrorData(GLU_OUT_OF_MEMORY);
+ }
+ }
+
+ /*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+ public void gluBeginPolygon() {
+ gluTessBeginPolygon(null);
+ gluTessBeginContour();
+ }
+
+
+/*ARGSUSED*/
+ public void gluNextContour(int type) {
+ gluTessEndContour();
+ gluTessBeginContour();
+ }
+
+
+ public void gluEndPolygon() {
+ gluTessEndContour();
+ gluTessEndPolygon();
+ }
+
+ void callBeginOrBeginData(int a) {
+ if (callBeginData != NULL_CB)
+ callBeginData.beginData(a, polygonData);
+ else
+ callBegin.begin(a);
+ }
+
+ void callVertexOrVertexData(Object a) {
+ if (callVertexData != NULL_CB)
+ callVertexData.vertexData(a, polygonData);
+ else
+ callVertex.vertex(a);
+ }
+
+ void callEdgeFlagOrEdgeFlagData(boolean a) {
+ if (callEdgeFlagData != NULL_CB)
+ callEdgeFlagData.edgeFlagData(a, polygonData);
+ else
+ callEdgeFlag.edgeFlag(a);
+ }
+
+ void callEndOrEndData() {
+ if (callEndData != NULL_CB)
+ callEndData.endData(polygonData);
+ else
+ callEnd.end();
+ }
+
+ void callCombineOrCombineData(double[] coords, Object[] vertexData, float[] weights, Object[] outData) {
+ if (callCombineData != NULL_CB)
+ callCombineData.combineData(coords, vertexData, weights, outData, polygonData);
+ else
+ callCombine.combine(coords, vertexData, weights, outData);
+ }
+
+ void callErrorOrErrorData(int a) {
+ if (callErrorData != NULL_CB)
+ callErrorData.errorData(a, polygonData);
+ else
+ callError.error(a);
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUvertex.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUvertex.java
new file mode 100644
index 0000000..8793b76
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/GLUvertex.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class GLUvertex {
+ public GLUvertex next; /* next vertex (never NULL) */
+ public GLUvertex prev; /* previous vertex (never NULL) */
+ public GLUhalfEdge anEdge; /* a half-edge with this origin */
+ public Object data; /* client's data */
+
+ /* Internal data (keep hidden) */
+ public double[] coords = new double[3]; /* vertex location in 3D */
+ public double s, t; /* projection onto the sweep plane */
+ public int pqHandle; /* to allow deletion from priority queue */
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Geom.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Geom.java
new file mode 100644
index 0000000..4aafab8
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Geom.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class Geom {
+ private Geom() {
+ }
+
+ /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->t = 0 and
+ * let r be the negated result (this evaluates (uw)(v->s)), then
+ * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
+ */
+ static double EdgeEval(GLUvertex u, GLUvertex v, GLUvertex w) {
+ double gapL, gapR;
+
+ assert (VertLeq(u, v) && VertLeq(v, w));
+
+ gapL = v.s - u.s;
+ gapR = w.s - v.s;
+
+ if (gapL + gapR > 0) {
+ if (gapL < gapR) {
+ return (v.t - u.t) + (u.t - w.t) * (gapL / (gapL + gapR));
+ } else {
+ return (v.t - w.t) + (w.t - u.t) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+ }
+
+ static double EdgeSign(GLUvertex u, GLUvertex v, GLUvertex w) {
+ double gapL, gapR;
+
+ assert (VertLeq(u, v) && VertLeq(v, w));
+
+ gapL = v.s - u.s;
+ gapR = w.s - v.s;
+
+ if (gapL + gapR > 0) {
+ return (v.t - w.t) * gapL + (v.t - u.t) * gapR;
+ }
+ /* vertical line */
+ return 0;
+ }
+
+
+ /***********************************************************************
+ * Define versions of EdgeSign, EdgeEval with s and t transposed.
+ */
+
+ static double TransEval(GLUvertex u, GLUvertex v, GLUvertex w) {
+ /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->s = 0 and
+ * let r be the negated result (this evaluates (uw)(v->t)), then
+ * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
+ */
+ double gapL, gapR;
+
+ assert (TransLeq(u, v) && TransLeq(v, w));
+
+ gapL = v.t - u.t;
+ gapR = w.t - v.t;
+
+ if (gapL + gapR > 0) {
+ if (gapL < gapR) {
+ return (v.s - u.s) + (u.s - w.s) * (gapL / (gapL + gapR));
+ } else {
+ return (v.s - w.s) + (w.s - u.s) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+ }
+
+ static double TransSign(GLUvertex u, GLUvertex v, GLUvertex w) {
+ /* Returns a number whose sign matches TransEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ double gapL, gapR;
+
+ assert (TransLeq(u, v) && TransLeq(v, w));
+
+ gapL = v.t - u.t;
+ gapR = w.t - v.t;
+
+ if (gapL + gapR > 0) {
+ return (v.s - w.s) * gapL + (v.s - u.s) * gapR;
+ }
+ /* vertical line */
+ return 0;
+ }
+
+
+ static boolean VertCCW(GLUvertex u, GLUvertex v, GLUvertex w) {
+ /* For almost-degenerate situations, the results are not reliable.
+ * Unless the floating-point arithmetic can be performed without
+ * rounding errors, *any* implementation will give incorrect results
+ * on some degenerate inputs, so the client must have some way to
+ * handle this situation.
+ */
+ return (u.s * (v.t - w.t) + v.s * (w.t - u.t) + w.s * (u.t - v.t)) >= 0;
+ }
+
+/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
+ * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
+ * this in the rare case that one argument is slightly negative.
+ * The implementation is extremely stable numerically.
+ * In particular it guarantees that the result r satisfies
+ * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
+ * even when a and b differ greatly in magnitude.
+ */
+ static double Interpolate(double a, double x, double b, double y) {
+ a = (a < 0) ? 0 : a;
+ b = (b < 0) ? 0 : b;
+ if (a <= b) {
+ if (b == 0) {
+ return (x + y) / 2.0;
+ } else {
+ return (x + (y - x) * (a / (a + b)));
+ }
+ } else {
+ return (y + (x - y) * (b / (a + b)));
+ }
+ }
+
+ static void EdgeIntersect(GLUvertex o1, GLUvertex d1,
+ GLUvertex o2, GLUvertex d2,
+ GLUvertex v)
+/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
+ * The computed point is guaranteed to lie in the intersection of the
+ * bounding rectangles defined by each edge.
+ */ {
+ double z1, z2;
+
+ /* This is certainly not the most efficient way to find the intersection
+ * of two line segments, but it is very numerically stable.
+ *
+ * Strategy: find the two middle vertices in the VertLeq ordering,
+ * and interpolate the intersection s-value from these. Then repeat
+ * using the TransLeq ordering to find the intersection t-value.
+ */
+
+ if (!VertLeq(o1, d1)) {
+ GLUvertex temp = o1;
+ o1 = d1;
+ d1 = temp;
+ }
+ if (!VertLeq(o2, d2)) {
+ GLUvertex temp = o2;
+ o2 = d2;
+ d2 = temp;
+ }
+ if (!VertLeq(o1, o2)) {
+ GLUvertex temp = o1;
+ o1 = o2;
+ o2 = temp;
+ temp = d1;
+ d1 = d2;
+ d2 = temp;
+ }
+
+ if (!VertLeq(o2, d1)) {
+ /* Technically, no intersection -- do our best */
+ v.s = (o2.s + d1.s) / 2.0;
+ } else if (VertLeq(d1, d2)) {
+ /* Interpolate between o2 and d1 */
+ z1 = EdgeEval(o1, o2, d1);
+ z2 = EdgeEval(o2, d1, d2);
+ if (z1 + z2 < 0) {
+ z1 = -z1;
+ z2 = -z2;
+ }
+ v.s = Interpolate(z1, o2.s, z2, d1.s);
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = EdgeSign(o1, o2, d1);
+ z2 = -EdgeSign(o1, d2, d1);
+ if (z1 + z2 < 0) {
+ z1 = -z1;
+ z2 = -z2;
+ }
+ v.s = Interpolate(z1, o2.s, z2, d2.s);
+ }
+
+ /* Now repeat the process for t */
+
+ if (!TransLeq(o1, d1)) {
+ GLUvertex temp = o1;
+ o1 = d1;
+ d1 = temp;
+ }
+ if (!TransLeq(o2, d2)) {
+ GLUvertex temp = o2;
+ o2 = d2;
+ d2 = temp;
+ }
+ if (!TransLeq(o1, o2)) {
+ GLUvertex temp = o2;
+ o2 = o1;
+ o1 = temp;
+ temp = d2;
+ d2 = d1;
+ d1 = temp;
+ }
+
+ if (!TransLeq(o2, d1)) {
+ /* Technically, no intersection -- do our best */
+ v.t = (o2.t + d1.t) / 2.0;
+ } else if (TransLeq(d1, d2)) {
+ /* Interpolate between o2 and d1 */
+ z1 = TransEval(o1, o2, d1);
+ z2 = TransEval(o2, d1, d2);
+ if (z1 + z2 < 0) {
+ z1 = -z1;
+ z2 = -z2;
+ }
+ v.t = Interpolate(z1, o2.t, z2, d1.t);
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = TransSign(o1, o2, d1);
+ z2 = -TransSign(o1, d2, d1);
+ if (z1 + z2 < 0) {
+ z1 = -z1;
+ z2 = -z2;
+ }
+ v.t = Interpolate(z1, o2.t, z2, d2.t);
+ }
+ }
+
+ static boolean VertEq(GLUvertex u, GLUvertex v) {
+ return u.s == v.s && u.t == v.t;
+ }
+
+ static boolean VertLeq(GLUvertex u, GLUvertex v) {
+ return u.s < v.s || (u.s == v.s && u.t <= v.t);
+ }
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+ static boolean TransLeq(GLUvertex u, GLUvertex v) {
+ return u.t < v.t || (u.t == v.t && u.s <= v.s);
+ }
+
+ static boolean EdgeGoesLeft(GLUhalfEdge e) {
+ return VertLeq(e.Sym.Org, e.Org);
+ }
+
+ static boolean EdgeGoesRight(GLUhalfEdge e) {
+ return VertLeq(e.Org, e.Sym.Org);
+ }
+
+ static double VertL1dist(GLUvertex u, GLUvertex v) {
+ return Math.abs(u.s - v.s) + Math.abs(u.t - v.t);
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Mesh.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Mesh.java
new file mode 100644
index 0000000..e6ad874
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Mesh.java
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class Mesh {
+ private Mesh() {
+ }
+
+ /************************ Utility Routines ************************/
+/* MakeEdge creates a new pair of half-edges which form their own loop.
+ * No vertex or face structures are allocated, but these must be assigned
+ * before the current edge operation is completed.
+ */
+ static GLUhalfEdge MakeEdge(GLUhalfEdge eNext) {
+ GLUhalfEdge e;
+ GLUhalfEdge eSym;
+ GLUhalfEdge ePrev;
+
+// EdgePair * pair = (EdgePair *)
+// memAlloc(sizeof(EdgePair));
+// if (pair == NULL) return NULL;
+//
+// e = &pair - > e;
+ e = new GLUhalfEdge(true);
+// eSym = &pair - > eSym;
+ eSym = new GLUhalfEdge(false);
+
+
+ /* Make sure eNext points to the first edge of the edge pair */
+ if (!eNext.first) {
+ eNext = eNext.Sym;
+ }
+
+ /* Insert in circular doubly-linked list before eNext.
+ * Note that the prev pointer is stored in Sym->next.
+ */
+ ePrev = eNext.Sym.next;
+ eSym.next = ePrev;
+ ePrev.Sym.next = e;
+ e.next = eNext;
+ eNext.Sym.next = eSym;
+
+ e.Sym = eSym;
+ e.Onext = e;
+ e.Lnext = eSym;
+ e.Org = null;
+ e.Lface = null;
+ e.winding = 0;
+ e.activeRegion = null;
+
+ eSym.Sym = e;
+ eSym.Onext = eSym;
+ eSym.Lnext = e;
+ eSym.Org = null;
+ eSym.Lface = null;
+ eSym.winding = 0;
+ eSym.activeRegion = null;
+
+ return e;
+ }
+
+/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
+ * CS348a notes (see mesh.h). Basically it modifies the mesh so that
+ * a->Onext and b->Onext are exchanged. This can have various effects
+ * depending on whether a and b belong to different face or vertex rings.
+ * For more explanation see __gl_meshSplice() below.
+ */
+ static void Splice(GLUhalfEdge a, GLUhalfEdge b) {
+ GLUhalfEdge aOnext = a.Onext;
+ GLUhalfEdge bOnext = b.Onext;
+
+ aOnext.Sym.Lnext = b;
+ bOnext.Sym.Lnext = a;
+ a.Onext = bOnext;
+ b.Onext = aOnext;
+ }
+
+/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
+ * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
+ * a place to insert the new vertex in the global vertex list. We insert
+ * the new vertex *before* vNext so that algorithms which walk the vertex
+ * list will not see the newly created vertices.
+ */
+ static void MakeVertex(GLUvertex newVertex,
+ GLUhalfEdge eOrig, GLUvertex vNext) {
+ GLUhalfEdge e;
+ GLUvertex vPrev;
+ GLUvertex vNew = newVertex;
+
+ assert (vNew != null);
+
+ /* insert in circular doubly-linked list before vNext */
+ vPrev = vNext.prev;
+ vNew.prev = vPrev;
+ vPrev.next = vNew;
+ vNew.next = vNext;
+ vNext.prev = vNew;
+
+ vNew.anEdge = eOrig;
+ vNew.data = null;
+ /* leave coords, s, t undefined */
+
+ /* fix other edges on this vertex loop */
+ e = eOrig;
+ do {
+ e.Org = vNew;
+ e = e.Onext;
+ } while (e != eOrig);
+ }
+
+/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
+ * face of all edges in the face loop to which eOrig belongs. "fNext" gives
+ * a place to insert the new face in the global face list. We insert
+ * the new face *before* fNext so that algorithms which walk the face
+ * list will not see the newly created faces.
+ */
+ static void MakeFace(GLUface newFace, GLUhalfEdge eOrig, GLUface fNext) {
+ GLUhalfEdge e;
+ GLUface fPrev;
+ GLUface fNew = newFace;
+
+ assert (fNew != null);
+
+ /* insert in circular doubly-linked list before fNext */
+ fPrev = fNext.prev;
+ fNew.prev = fPrev;
+ fPrev.next = fNew;
+ fNew.next = fNext;
+ fNext.prev = fNew;
+
+ fNew.anEdge = eOrig;
+ fNew.data = null;
+ fNew.trail = null;
+ fNew.marked = false;
+
+ /* The new face is marked "inside" if the old one was. This is a
+ * convenience for the common case where a face has been split in two.
+ */
+ fNew.inside = fNext.inside;
+
+ /* fix other edges on this face loop */
+ e = eOrig;
+ do {
+ e.Lface = fNew;
+ e = e.Lnext;
+ } while (e != eOrig);
+ }
+
+/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
+ * and removes from the global edge list.
+ */
+ static void KillEdge(GLUhalfEdge eDel) {
+ GLUhalfEdge ePrev, eNext;
+
+ /* Half-edges are allocated in pairs, see EdgePair above */
+ if (!eDel.first) {
+ eDel = eDel.Sym;
+ }
+
+ /* delete from circular doubly-linked list */
+ eNext = eDel.next;
+ ePrev = eDel.Sym.next;
+ eNext.Sym.next = ePrev;
+ ePrev.Sym.next = eNext;
+ }
+
+
+/* KillVertex( vDel ) destroys a vertex and removes it from the global
+ * vertex list. It updates the vertex loop to point to a given new vertex.
+ */
+ static void KillVertex(GLUvertex vDel, GLUvertex newOrg) {
+ GLUhalfEdge e, eStart = vDel.anEdge;
+ GLUvertex vPrev, vNext;
+
+ /* change the origin of all affected edges */
+ e = eStart;
+ do {
+ e.Org = newOrg;
+ e = e.Onext;
+ } while (e != eStart);
+
+ /* delete from circular doubly-linked list */
+ vPrev = vDel.prev;
+ vNext = vDel.next;
+ vNext.prev = vPrev;
+ vPrev.next = vNext;
+ }
+
+/* KillFace( fDel ) destroys a face and removes it from the global face
+ * list. It updates the face loop to point to a given new face.
+ */
+ static void KillFace(GLUface fDel, GLUface newLface) {
+ GLUhalfEdge e, eStart = fDel.anEdge;
+ GLUface fPrev, fNext;
+
+ /* change the left face of all affected edges */
+ e = eStart;
+ do {
+ e.Lface = newLface;
+ e = e.Lnext;
+ } while (e != eStart);
+
+ /* delete from circular doubly-linked list */
+ fPrev = fDel.prev;
+ fNext = fDel.next;
+ fNext.prev = fPrev;
+ fPrev.next = fNext;
+ }
+
+
+ /****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+ public static GLUhalfEdge __gl_meshMakeEdge(GLUmesh mesh) {
+ GLUvertex newVertex1 = new GLUvertex();
+ GLUvertex newVertex2 = new GLUvertex();
+ GLUface newFace = new GLUface();
+ GLUhalfEdge e;
+
+ e = MakeEdge(mesh.eHead);
+ if (e == null) return null;
+
+ MakeVertex(newVertex1, e, mesh.vHead);
+ MakeVertex(newVertex2, e.Sym, mesh.vHead);
+ MakeFace(newFace, e, mesh.fHead);
+ return e;
+ }
+
+
+/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * Some special cases:
+ * If eDst == eOrg, the operation has no effect.
+ * If eDst == eOrg->Lnext, the new face will have a single edge.
+ * If eDst == eOrg->Lprev, the old face will have a single edge.
+ * If eDst == eOrg->Onext, the new vertex will have a single edge.
+ * If eDst == eOrg->Oprev, the old vertex will have a single edge.
+ */
+ public static boolean __gl_meshSplice(GLUhalfEdge eOrg, GLUhalfEdge eDst) {
+ boolean joiningLoops = false;
+ boolean joiningVertices = false;
+
+ if (eOrg == eDst) return true;
+
+ if (eDst.Org != eOrg.Org) {
+ /* We are merging two disjoint vertices -- destroy eDst->Org */
+ joiningVertices = true;
+ KillVertex(eDst.Org, eOrg.Org);
+ }
+ if (eDst.Lface != eOrg.Lface) {
+ /* We are connecting two disjoint loops -- destroy eDst.Lface */
+ joiningLoops = true;
+ KillFace(eDst.Lface, eOrg.Lface);
+ }
+
+ /* Change the edge structure */
+ Splice(eDst, eOrg);
+
+ if (!joiningVertices) {
+ GLUvertex newVertex = new GLUvertex();
+
+ /* We split one vertex into two -- the new vertex is eDst.Org.
+ * Make sure the old vertex points to a valid half-edge.
+ */
+ MakeVertex(newVertex, eDst, eOrg.Org);
+ eOrg.Org.anEdge = eOrg;
+ }
+ if (!joiningLoops) {
+ GLUface newFace = new GLUface();
+
+ /* We split one loop into two -- the new loop is eDst.Lface.
+ * Make sure the old face points to a valid half-edge.
+ */
+ MakeFace(newFace, eDst, eOrg.Lface);
+ eOrg.Lface.anEdge = eOrg;
+ }
+
+ return true;
+ }
+
+
+/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel.Lface != eDel.Rface), we join two loops into one; the loop
+ * eDel.Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel.Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * This function could be implemented as two calls to __gl_meshSplice
+ * plus a few calls to memFree, but this would allocate and delete
+ * unnecessary vertices and faces.
+ */
+ static boolean __gl_meshDelete(GLUhalfEdge eDel) {
+ GLUhalfEdge eDelSym = eDel.Sym;
+ boolean joiningLoops = false;
+
+ /* First step: disconnect the origin vertex eDel.Org. We make all
+ * changes to get a consistent mesh in this "intermediate" state.
+ */
+ if (eDel.Lface != eDel.Sym.Lface) {
+ /* We are joining two loops into one -- remove the left face */
+ joiningLoops = true;
+ KillFace(eDel.Lface, eDel.Sym.Lface);
+ }
+
+ if (eDel.Onext == eDel) {
+ KillVertex(eDel.Org, null);
+ } else {
+ /* Make sure that eDel.Org and eDel.Sym.Lface point to valid half-edges */
+ eDel.Sym.Lface.anEdge = eDel.Sym.Lnext;
+ eDel.Org.anEdge = eDel.Onext;
+
+ Splice(eDel, eDel.Sym.Lnext);
+ if (!joiningLoops) {
+ GLUface newFace = new GLUface();
+
+ /* We are splitting one loop into two -- create a new loop for eDel. */
+ MakeFace(newFace, eDel, eDel.Lface);
+ }
+ }
+
+ /* Claim: the mesh is now in a consistent state, except that eDel.Org
+ * may have been deleted. Now we disconnect eDel.Dst.
+ */
+ if (eDelSym.Onext == eDelSym) {
+ KillVertex(eDelSym.Org, null);
+ KillFace(eDelSym.Lface, null);
+ } else {
+ /* Make sure that eDel.Dst and eDel.Lface point to valid half-edges */
+ eDel.Lface.anEdge = eDelSym.Sym.Lnext;
+ eDelSym.Org.anEdge = eDelSym.Onext;
+ Splice(eDelSym, eDelSym.Sym.Lnext);
+ }
+
+ /* Any isolated vertices or faces have already been freed. */
+ KillEdge(eDel);
+
+ return true;
+ }
+
+
+ /******************** Other Edge Operations **********************/
+
+/* All these routines can be implemented with the basic edge
+ * operations above. They are provided for convenience and efficiency.
+ */
+
+
+/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg.Lnext, and eNew.Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ */
+ static GLUhalfEdge __gl_meshAddEdgeVertex(GLUhalfEdge eOrg) {
+ GLUhalfEdge eNewSym;
+ GLUhalfEdge eNew = MakeEdge(eOrg);
+
+ eNewSym = eNew.Sym;
+
+ /* Connect the new edge appropriately */
+ Splice(eNew, eOrg.Lnext);
+
+ /* Set the vertex and face information */
+ eNew.Org = eOrg.Sym.Org;
+ {
+ GLUvertex newVertex = new GLUvertex();
+
+ MakeVertex(newVertex, eNewSym, eNew.Org);
+ }
+ eNew.Lface = eNewSym.Lface = eOrg.Lface;
+
+ return eNew;
+ }
+
+
+/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg.Lnext. The new vertex is eOrg.Sym.Org == eNew.Org.
+ * eOrg and eNew will have the same left face.
+ */
+ public static GLUhalfEdge __gl_meshSplitEdge(GLUhalfEdge eOrg) {
+ GLUhalfEdge eNew;
+ GLUhalfEdge tempHalfEdge = __gl_meshAddEdgeVertex(eOrg);
+
+ eNew = tempHalfEdge.Sym;
+
+ /* Disconnect eOrg from eOrg.Sym.Org and connect it to eNew.Org */
+ Splice(eOrg.Sym, eOrg.Sym.Sym.Lnext);
+ Splice(eOrg.Sym, eNew);
+
+ /* Set the vertex and face information */
+ eOrg.Sym.Org = eNew.Org;
+ eNew.Sym.Org.anEdge = eNew.Sym; /* may have pointed to eOrg.Sym */
+ eNew.Sym.Lface = eOrg.Sym.Lface;
+ eNew.winding = eOrg.winding; /* copy old winding information */
+ eNew.Sym.winding = eOrg.Sym.winding;
+
+ return eNew;
+ }
+
+
+/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg.Sym.Org
+ * to eDst.Org, and returns the corresponding half-edge eNew.
+ * If eOrg.Lface == eDst.Lface, this splits one loop into two,
+ * and the newly created loop is eNew.Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst.Lface is destroyed.
+ *
+ * If (eOrg == eDst), the new face will have only two edges.
+ * If (eOrg.Lnext == eDst), the old face is reduced to a single edge.
+ * If (eOrg.Lnext.Lnext == eDst), the old face is reduced to two edges.
+ */
+ static GLUhalfEdge __gl_meshConnect(GLUhalfEdge eOrg, GLUhalfEdge eDst) {
+ GLUhalfEdge eNewSym;
+ boolean joiningLoops = false;
+ GLUhalfEdge eNew = MakeEdge(eOrg);
+
+ eNewSym = eNew.Sym;
+
+ if (eDst.Lface != eOrg.Lface) {
+ /* We are connecting two disjoint loops -- destroy eDst.Lface */
+ joiningLoops = true;
+ KillFace(eDst.Lface, eOrg.Lface);
+ }
+
+ /* Connect the new edge appropriately */
+ Splice(eNew, eOrg.Lnext);
+ Splice(eNewSym, eDst);
+
+ /* Set the vertex and face information */
+ eNew.Org = eOrg.Sym.Org;
+ eNewSym.Org = eDst.Org;
+ eNew.Lface = eNewSym.Lface = eOrg.Lface;
+
+ /* Make sure the old face points to a valid half-edge */
+ eOrg.Lface.anEdge = eNewSym;
+
+ if (!joiningLoops) {
+ GLUface newFace = new GLUface();
+
+ /* We split one loop into two -- the new loop is eNew.Lface */
+ MakeFace(newFace, eNew, eOrg.Lface);
+ }
+ return eNew;
+ }
+
+
+ /******************** Other Operations **********************/
+
+/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a null pointer as their
+ * left face. Any edges which also have a null pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ */
+ static void __gl_meshZapFace(GLUface fZap) {
+ GLUhalfEdge eStart = fZap.anEdge;
+ GLUhalfEdge e, eNext, eSym;
+ GLUface fPrev, fNext;
+
+ /* walk around face, deleting edges whose right face is also null */
+ eNext = eStart.Lnext;
+ do {
+ e = eNext;
+ eNext = e.Lnext;
+
+ e.Lface = null;
+ if (e.Sym.Lface == null) {
+ /* delete the edge -- see __gl_MeshDelete above */
+
+ if (e.Onext == e) {
+ KillVertex(e.Org, null);
+ } else {
+ /* Make sure that e.Org points to a valid half-edge */
+ e.Org.anEdge = e.Onext;
+ Splice(e, e.Sym.Lnext);
+ }
+ eSym = e.Sym;
+ if (eSym.Onext == eSym) {
+ KillVertex(eSym.Org, null);
+ } else {
+ /* Make sure that eSym.Org points to a valid half-edge */
+ eSym.Org.anEdge = eSym.Onext;
+ Splice(eSym, eSym.Sym.Lnext);
+ }
+ KillEdge(e);
+ }
+ } while (e != eStart);
+
+ /* delete from circular doubly-linked list */
+ fPrev = fZap.prev;
+ fNext = fZap.next;
+ fNext.prev = fPrev;
+ fPrev.next = fNext;
+ }
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+ public static GLUmesh __gl_meshNewMesh() {
+ GLUvertex v;
+ GLUface f;
+ GLUhalfEdge e;
+ GLUhalfEdge eSym;
+ GLUmesh mesh = new GLUmesh();
+
+ v = mesh.vHead;
+ f = mesh.fHead;
+ e = mesh.eHead;
+ eSym = mesh.eHeadSym;
+
+ v.next = v.prev = v;
+ v.anEdge = null;
+ v.data = null;
+
+ f.next = f.prev = f;
+ f.anEdge = null;
+ f.data = null;
+ f.trail = null;
+ f.marked = false;
+ f.inside = false;
+
+ e.next = e;
+ e.Sym = eSym;
+ e.Onext = null;
+ e.Lnext = null;
+ e.Org = null;
+ e.Lface = null;
+ e.winding = 0;
+ e.activeRegion = null;
+
+ eSym.next = eSym;
+ eSym.Sym = e;
+ eSym.Onext = null;
+ eSym.Lnext = null;
+ eSym.Org = null;
+ eSym.Lface = null;
+ eSym.winding = 0;
+ eSym.activeRegion = null;
+
+ return mesh;
+ }
+
+
+/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ */
+ static GLUmesh __gl_meshUnion(GLUmesh mesh1, GLUmesh mesh2) {
+ GLUface f1 = mesh1.fHead;
+ GLUvertex v1 = mesh1.vHead;
+ GLUhalfEdge e1 = mesh1.eHead;
+ GLUface f2 = mesh2.fHead;
+ GLUvertex v2 = mesh2.vHead;
+ GLUhalfEdge e2 = mesh2.eHead;
+
+ /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
+ if (f2.next != f2) {
+ f1.prev.next = f2.next;
+ f2.next.prev = f1.prev;
+ f2.prev.next = f1;
+ f1.prev = f2.prev;
+ }
+
+ if (v2.next != v2) {
+ v1.prev.next = v2.next;
+ v2.next.prev = v1.prev;
+ v2.prev.next = v1;
+ v1.prev = v2.prev;
+ }
+
+ if (e2.next != e2) {
+ e1.Sym.next.Sym.next = e2.next;
+ e2.next.Sym.next = e1.Sym.next;
+ e2.Sym.next.Sym.next = e1;
+ e1.Sym.next = e2.Sym.next;
+ }
+
+ return mesh1;
+ }
+
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+ static void __gl_meshDeleteMeshZap(GLUmesh mesh) {
+ GLUface fHead = mesh.fHead;
+
+ while (fHead.next != fHead) {
+ __gl_meshZapFace(fHead.next);
+ }
+ assert (mesh.vHead.next == mesh.vHead);
+ }
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+ public static void __gl_meshDeleteMesh(GLUmesh mesh) {
+ GLUface f, fNext;
+ GLUvertex v, vNext;
+ GLUhalfEdge e, eNext;
+
+ for (f = mesh.fHead.next; f != mesh.fHead; f = fNext) {
+ fNext = f.next;
+ }
+
+ for (v = mesh.vHead.next; v != mesh.vHead; v = vNext) {
+ vNext = v.next;
+ }
+
+ for (e = mesh.eHead.next; e != mesh.eHead; e = eNext) {
+ /* One call frees both e and e.Sym (see EdgePair above) */
+ eNext = e.next;
+ }
+ }
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+ public static void __gl_meshCheckMesh(GLUmesh mesh) {
+ GLUface fHead = mesh.fHead;
+ GLUvertex vHead = mesh.vHead;
+ GLUhalfEdge eHead = mesh.eHead;
+ GLUface f, fPrev;
+ GLUvertex v, vPrev;
+ GLUhalfEdge e, ePrev;
+
+ fPrev = fHead;
+ for (fPrev = fHead; (f = fPrev.next) != fHead; fPrev = f) {
+ assert (f.prev == fPrev);
+ e = f.anEdge;
+ do {
+ assert (e.Sym != e);
+ assert (e.Sym.Sym == e);
+ assert (e.Lnext.Onext.Sym == e);
+ assert (e.Onext.Sym.Lnext == e);
+ assert (e.Lface == f);
+ e = e.Lnext;
+ } while (e != f.anEdge);
+ }
+ assert (f.prev == fPrev && f.anEdge == null && f.data == null);
+
+ vPrev = vHead;
+ for (vPrev = vHead; (v = vPrev.next) != vHead; vPrev = v) {
+ assert (v.prev == vPrev);
+ e = v.anEdge;
+ do {
+ assert (e.Sym != e);
+ assert (e.Sym.Sym == e);
+ assert (e.Lnext.Onext.Sym == e);
+ assert (e.Onext.Sym.Lnext == e);
+ assert (e.Org == v);
+ e = e.Onext;
+ } while (e != v.anEdge);
+ }
+ assert (v.prev == vPrev && v.anEdge == null && v.data == null);
+
+ ePrev = eHead;
+ for (ePrev = eHead; (e = ePrev.next) != eHead; ePrev = e) {
+ assert (e.Sym.next == ePrev.Sym);
+ assert (e.Sym != e);
+ assert (e.Sym.Sym == e);
+ assert (e.Org != null);
+ assert (e.Sym.Org != null);
+ assert (e.Lnext.Onext.Sym == e);
+ assert (e.Onext.Sym.Lnext == e);
+ }
+ assert (e.Sym.next == ePrev.Sym
+ && e.Sym == mesh.eHeadSym
+ && e.Sym.Sym == e
+ && e.Org == null && e.Sym.Org == null
+ && e.Lface == null && e.Sym.Lface == null);
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Normal.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Normal.java
new file mode 100644
index 0000000..3a1e6d2
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Normal.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+import de.verschwiegener.lwjgl3.util.glu.GLU;
+
+class Normal {
+ private Normal() {
+ }
+
+ static boolean SLANTED_SWEEP;
+ static double S_UNIT_X; /* Pre-normalized */
+ static double S_UNIT_Y;
+ private static final boolean TRUE_PROJECT = false;
+
+ static {
+ if (SLANTED_SWEEP) {
+/* The "feature merging" is not intended to be complete. There are
+ * special cases where edges are nearly parallel to the sweep line
+ * which are not implemented. The algorithm should still behave
+ * robustly (ie. produce a reasonable tesselation) in the presence
+ * of such edges, however it may miss features which could have been
+ * merged. We could minimize this effect by choosing the sweep line
+ * direction to be something unusual (ie. not parallel to one of the
+ * coordinate axes).
+ */
+ S_UNIT_X = 0.50941539564955385; /* Pre-normalized */
+ S_UNIT_Y = 0.86052074622010633;
+ } else {
+ S_UNIT_X = 1.0;
+ S_UNIT_Y = 0.0;
+ }
+ }
+
+ private static double Dot(double[] u, double[] v) {
+ return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]);
+ }
+
+ static void Normalize(double[] v) {
+ double len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+
+ assert (len > 0);
+ len = Math.sqrt(len);
+ v[0] /= len;
+ v[1] /= len;
+ v[2] /= len;
+ }
+
+ static int LongAxis(double[] v) {
+ int i = 0;
+
+ if (Math.abs(v[1]) > Math.abs(v[0])) {
+ i = 1;
+ }
+ if (Math.abs(v[2]) > Math.abs(v[i])) {
+ i = 2;
+ }
+ return i;
+ }
+
+ static void ComputeNormal(GLUtessellatorImpl tess, double[] norm) {
+ GLUvertex v, v1, v2;
+ double c, tLen2, maxLen2;
+ double[] maxVal, minVal, d1, d2, tNorm;
+ GLUvertex[] maxVert, minVert;
+ GLUvertex vHead = tess.mesh.vHead;
+ int i;
+
+ maxVal = new double[3];
+ minVal = new double[3];
+ minVert = new GLUvertex[3];
+ maxVert = new GLUvertex[3];
+ d1 = new double[3];
+ d2 = new double[3];
+ tNorm = new double[3];
+
+ maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU.TESS_MAX_COORD;
+ minVal[0] = minVal[1] = minVal[2] = 2 * GLU.TESS_MAX_COORD;
+
+ for (v = vHead.next; v != vHead; v = v.next) {
+ for (i = 0; i < 3; ++i) {
+ c = v.coords[i];
+ if (c < minVal[i]) {
+ minVal[i] = c;
+ minVert[i] = v;
+ }
+ if (c > maxVal[i]) {
+ maxVal[i] = c;
+ maxVert[i] = v;
+ }
+ }
+ }
+
+/* Find two vertices separated by at least 1/sqrt(3) of the maximum
+ * distance between any two vertices
+ */
+ i = 0;
+ if (maxVal[1] - minVal[1] > maxVal[0] - minVal[0]) {
+ i = 1;
+ }
+ if (maxVal[2] - minVal[2] > maxVal[i] - minVal[i]) {
+ i = 2;
+ }
+ if (minVal[i] >= maxVal[i]) {
+/* All vertices are the same -- normal doesn't matter */
+ norm[0] = 0;
+ norm[1] = 0;
+ norm[2] = 1;
+ return;
+ }
+
+/* Look for a third vertex which forms the triangle with maximum area
+ * (Length of normal == twice the triangle area)
+ */
+ maxLen2 = 0;
+ v1 = minVert[i];
+ v2 = maxVert[i];
+ d1[0] = v1.coords[0] - v2.coords[0];
+ d1[1] = v1.coords[1] - v2.coords[1];
+ d1[2] = v1.coords[2] - v2.coords[2];
+ for (v = vHead.next; v != vHead; v = v.next) {
+ d2[0] = v.coords[0] - v2.coords[0];
+ d2[1] = v.coords[1] - v2.coords[1];
+ d2[2] = v.coords[2] - v2.coords[2];
+ tNorm[0] = d1[1] * d2[2] - d1[2] * d2[1];
+ tNorm[1] = d1[2] * d2[0] - d1[0] * d2[2];
+ tNorm[2] = d1[0] * d2[1] - d1[1] * d2[0];
+ tLen2 = tNorm[0] * tNorm[0] + tNorm[1] * tNorm[1] + tNorm[2] * tNorm[2];
+ if (tLen2 > maxLen2) {
+ maxLen2 = tLen2;
+ norm[0] = tNorm[0];
+ norm[1] = tNorm[1];
+ norm[2] = tNorm[2];
+ }
+ }
+
+ if (maxLen2 <= 0) {
+/* All points lie on a single line -- any decent normal will do */
+ norm[0] = norm[1] = norm[2] = 0;
+ norm[LongAxis(d1)] = 1;
+ }
+ }
+
+ static void CheckOrientation(GLUtessellatorImpl tess) {
+ double area;
+ GLUface f, fHead = tess.mesh.fHead;
+ GLUvertex v, vHead = tess.mesh.vHead;
+ GLUhalfEdge e;
+
+/* When we compute the normal automatically, we choose the orientation
+ * so that the the sum of the signed areas of all contours is non-negative.
+ */
+ area = 0;
+ for (f = fHead.next; f != fHead; f = f.next) {
+ e = f.anEdge;
+ if (e.winding <= 0) continue;
+ do {
+ area += (e.Org.s - e.Sym.Org.s) * (e.Org.t + e.Sym.Org.t);
+ e = e.Lnext;
+ } while (e != f.anEdge);
+ }
+ if (area < 0) {
+/* Reverse the orientation by flipping all the t-coordinates */
+ for (v = vHead.next; v != vHead; v = v.next) {
+ v.t = -v.t;
+ }
+ tess.tUnit[0] = -tess.tUnit[0];
+ tess.tUnit[1] = -tess.tUnit[1];
+ tess.tUnit[2] = -tess.tUnit[2];
+ }
+ }
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ public static void __gl_projectPolygon(GLUtessellatorImpl tess) {
+ GLUvertex v, vHead = tess.mesh.vHead;
+ double w;
+ double[] norm = new double[3];
+ double[] sUnit, tUnit;
+ int i;
+ boolean computedNormal = false;
+
+ norm[0] = tess.normal[0];
+ norm[1] = tess.normal[1];
+ norm[2] = tess.normal[2];
+ if (norm[0] == 0 && norm[1] == 0 && norm[2] == 0) {
+ ComputeNormal(tess, norm);
+ computedNormal = true;
+ }
+ sUnit = tess.sUnit;
+ tUnit = tess.tUnit;
+ i = LongAxis(norm);
+
+ if (TRUE_PROJECT) {
+/* Choose the initial sUnit vector to be approximately perpendicular
+ * to the normal.
+ */
+ Normalize(norm);
+
+ sUnit[i] = 0;
+ sUnit[(i + 1) % 3] = S_UNIT_X;
+ sUnit[(i + 2) % 3] = S_UNIT_Y;
+
+/* Now make it exactly perpendicular */
+ w = Dot(sUnit, norm);
+ sUnit[0] -= w * norm[0];
+ sUnit[1] -= w * norm[1];
+ sUnit[2] -= w * norm[2];
+ Normalize(sUnit);
+
+/* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
+ tUnit[0] = norm[1] * sUnit[2] - norm[2] * sUnit[1];
+ tUnit[1] = norm[2] * sUnit[0] - norm[0] * sUnit[2];
+ tUnit[2] = norm[0] * sUnit[1] - norm[1] * sUnit[0];
+ Normalize(tUnit);
+ } else {
+/* Project perpendicular to a coordinate axis -- better numerically */
+ sUnit[i] = 0;
+ sUnit[(i + 1) % 3] = S_UNIT_X;
+ sUnit[(i + 2) % 3] = S_UNIT_Y;
+
+ tUnit[i] = 0;
+ tUnit[(i + 1) % 3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
+ tUnit[(i + 2) % 3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
+ }
+
+/* Project the vertices onto the sweep plane */
+ for (v = vHead.next; v != vHead; v = v.next) {
+ v.s = Dot(v.coords, sUnit);
+ v.t = Dot(v.coords, tUnit);
+ }
+ if (computedNormal) {
+ CheckOrientation(tess);
+ }
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQ.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQ.java
new file mode 100644
index 0000000..c66ef3b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQ.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+abstract class PriorityQ {
+ public static final int INIT_SIZE = 32;
+
+ public static class PQnode {
+ int handle;
+ }
+
+ public static class PQhandleElem {
+ Object key;
+ int node;
+ }
+
+ public interface Leq {
+ boolean leq(Object key1, Object key2);
+ }
+
+ // #ifdef FOR_TRITE_TEST_PROGRAM
+// private static boolean LEQ(PriorityQCommon.Leq leq, Object x,Object y) {
+// return pq.leq.leq(x,y);
+// }
+// #else
+/* Violates modularity, but a little faster */
+// #include "geom.h"
+ public static boolean LEQ(Leq leq, Object x, Object y) {
+ return Geom.VertLeq((GLUvertex) x, (GLUvertex) y);
+ }
+
+ static PriorityQ pqNewPriorityQ(Leq leq) {
+ return new PriorityQSort(leq);
+ }
+
+ abstract void pqDeletePriorityQ();
+
+ abstract boolean pqInit();
+
+ abstract int pqInsert(Object keyNew);
+
+ abstract Object pqExtractMin();
+
+ abstract void pqDelete(int hCurr);
+
+ abstract Object pqMinimum();
+
+ abstract boolean pqIsEmpty();
+// #endif
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQHeap.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQHeap.java
new file mode 100644
index 0000000..43698bb
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQHeap.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+
+
+class PriorityQHeap extends PriorityQ {
+ PQnode[] nodes;
+ PQhandleElem[] handles;
+ int size, max;
+ int freeList;
+ boolean initialized;
+ Leq leq;
+
+/* really __gl_pqHeapNewPriorityQ */
+PriorityQHeap(Leq leq) {
+ size = 0;
+ max = PriorityQ.INIT_SIZE;
+ nodes = new PQnode[PriorityQ.INIT_SIZE + 1];
+ for (int i = 0; i < nodes.length; i++) {
+ nodes[i] = new PQnode();
+ }
+ handles = new PQhandleElem[PriorityQ.INIT_SIZE + 1];
+ for (int i = 0; i < handles.length; i++) {
+ handles[i] = new PQhandleElem();
+ }
+ initialized = false;
+ freeList = 0;
+ this.leq = leq;
+
+ nodes[1].handle = 1; /* so that Minimum() returns NULL */
+ handles[1].key = null;
+ }
+
+/* really __gl_pqHeapDeletePriorityQ */
+ void pqDeletePriorityQ() {
+ handles = null;
+ nodes = null;
+ }
+
+ void FloatDown(int curr) {
+ PQnode[] n = nodes;
+ PQhandleElem[] h = handles;
+ int hCurr, hChild;
+ int child;
+
+ hCurr = n[curr].handle;
+ for (; ;) {
+ child = curr << 1;
+ if (child < size && LEQ(leq, h[n[child + 1].handle].key,
+ h[n[child].handle].key)) {
+ ++child;
+ }
+
+ assert (child <= max);
+
+ hChild = n[child].handle;
+ if (child > size || LEQ(leq, h[hCurr].key, h[hChild].key)) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hChild;
+ h[hChild].node = curr;
+ curr = child;
+ }
+ }
+
+
+ void FloatUp(int curr) {
+ PQnode[] n = nodes;
+ PQhandleElem[] h = handles;
+ int hCurr, hParent;
+ int parent;
+
+ hCurr = n[curr].handle;
+ for (; ;) {
+ parent = curr >> 1;
+ hParent = n[parent].handle;
+ if (parent == 0 || LEQ(leq, h[hParent].key, h[hCurr].key)) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hParent;
+ h[hParent].node = curr;
+ curr = parent;
+ }
+ }
+
+/* really __gl_pqHeapInit */
+ boolean pqInit() {
+ int i;
+
+ /* This method of building a heap is O(n), rather than O(n lg n). */
+
+ for (i = size; i >= 1; --i) {
+ FloatDown(i);
+ }
+ initialized = true;
+
+ return true;
+ }
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+ int pqInsert(Object keyNew) {
+ int curr;
+ int free;
+
+ curr = ++size;
+ if ((curr * 2) > max) {
+ PQnode[] saveNodes = nodes;
+ PQhandleElem[] saveHandles = handles;
+
+ /* If the heap overflows, double its size. */
+ max <<= 1;
+// pq->nodes = (PQnode *)memRealloc( pq->nodes, (size_t) ((pq->max + 1) * sizeof( pq->nodes[0] )));
+ PQnode[] pqNodes = new PQnode[max + 1];
+ System.arraycopy( nodes, 0, pqNodes, 0, nodes.length );
+ for (int i = nodes.length; i < pqNodes.length; i++) {
+ pqNodes[i] = new PQnode();
+ }
+ nodes = pqNodes;
+ if (nodes == null) {
+ nodes = saveNodes; /* restore ptr to free upon return */
+ return Integer.MAX_VALUE;
+ }
+
+// pq->handles = (PQhandleElem *)memRealloc( pq->handles,(size_t)((pq->max + 1) * sizeof( pq->handles[0] )));
+ PQhandleElem[] pqHandles = new PQhandleElem[max + 1];
+ System.arraycopy( handles, 0, pqHandles, 0, handles.length );
+ for (int i = handles.length; i < pqHandles.length; i++) {
+ pqHandles[i] = new PQhandleElem();
+ }
+ handles = pqHandles;
+ if (handles == null) {
+ handles = saveHandles; /* restore ptr to free upon return */
+ return Integer.MAX_VALUE;
+ }
+ }
+
+ if (freeList == 0) {
+ free = curr;
+ } else {
+ free = freeList;
+ freeList = handles[free].node;
+ }
+
+ nodes[curr].handle = free;
+ handles[free].node = curr;
+ handles[free].key = keyNew;
+
+ if (initialized) {
+ FloatUp(curr);
+ }
+ assert (free != Integer.MAX_VALUE);
+ return free;
+ }
+
+/* really __gl_pqHeapExtractMin */
+ Object pqExtractMin() {
+ PQnode[] n = nodes;
+ PQhandleElem[] h = handles;
+ int hMin = n[1].handle;
+ Object min = h[hMin].key;
+
+ if (size > 0) {
+ n[1].handle = n[size].handle;
+ h[n[1].handle].node = 1;
+
+ h[hMin].key = null;
+ h[hMin].node = freeList;
+ freeList = hMin;
+
+ if (--size > 0) {
+ FloatDown(1);
+ }
+ }
+ return min;
+ }
+
+/* really __gl_pqHeapDelete */
+ void pqDelete(int hCurr) {
+ PQnode[] n = nodes;
+ PQhandleElem[] h = handles;
+ int curr;
+
+ assert (hCurr >= 1 && hCurr <= max && h[hCurr].key != null);
+
+ curr = h[hCurr].node;
+ n[curr].handle = n[size].handle;
+ h[n[curr].handle].node = curr;
+
+ if (curr <= --size) {
+ if (curr <= 1 || LEQ(leq, h[n[curr >> 1].handle].key, h[n[curr].handle].key)) {
+ FloatDown(curr);
+ } else {
+ FloatUp(curr);
+ }
+ }
+ h[hCurr].key = null;
+ h[hCurr].node = freeList;
+ freeList = hCurr;
+ }
+
+ Object pqMinimum() {
+ return handles[nodes[1].handle].key;
+ }
+
+ boolean pqIsEmpty() {
+ return size == 0;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQSort.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQSort.java
new file mode 100644
index 0000000..d040c8f
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/PriorityQSort.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+
+
+class PriorityQSort extends PriorityQ {
+ PriorityQHeap heap;
+ Object[] keys;
+
+ // JAVA: 'order' contains indices into the keys array.
+ // This simulates the indirect pointers used in the original C code
+ // (from Frank Suykens, Luciad.com).
+ int[] order;
+ int size, max;
+ boolean initialized;
+ Leq leq;
+
+ PriorityQSort(Leq leq) {
+ heap = new PriorityQHeap(leq);
+
+ keys = new Object[PriorityQ.INIT_SIZE];
+
+ size = 0;
+ max = PriorityQ.INIT_SIZE;
+ initialized = false;
+ this.leq = leq;
+ }
+
+/* really __gl_pqSortDeletePriorityQ */
+ void pqDeletePriorityQ() {
+ if (heap != null) heap.pqDeletePriorityQ();
+ order = null;
+ keys = null;
+ }
+
+ private static boolean LT(Leq leq, Object x, Object y) {
+ return (!PriorityQHeap.LEQ(leq, y, x));
+ }
+
+ private static boolean GT(Leq leq, Object x, Object y) {
+ return (!PriorityQHeap.LEQ(leq, x, y));
+ }
+
+ private static void Swap(int[] array, int a, int b) {
+ if (true) {
+ int tmp = array[a];
+ array[a] = array[b];
+ array[b] = tmp;
+ } else {
+
+ }
+ }
+
+ private static class Stack {
+ int p, r;
+ }
+
+/* really __gl_pqSortInit */
+ boolean pqInit() {
+ int p, r, i, j;
+ int piv;
+ Stack[] stack = new Stack[50];
+ for (int k = 0; k < stack.length; k++) {
+ stack[k] = new Stack();
+ }
+ int top = 0;
+
+ int seed = 2016473283;
+
+ /* Create an array of indirect pointers to the keys, so that we
+ * the handles we have returned are still valid.
+ */
+ order = new int[size + 1];
+/* the previous line is a patch to compensate for the fact that IBM */
+/* machines return a null on a malloc of zero bytes (unlike SGI), */
+/* so we have to put in this defense to guard against a memory */
+/* fault four lines down. from fossum@austin.ibm.com. */
+ p = 0;
+ r = size - 1;
+ for (piv = 0, i = p; i <= r; ++piv, ++i) {
+ // indirect pointers: keep an index into the keys array, not a direct pointer to its contents
+ order[i] = piv;
+ }
+
+ /* Sort the indirect pointers in descending order,
+ * using randomized Quicksort
+ */
+ stack[top].p = p;
+ stack[top].r = r;
+ ++top;
+ while (--top >= 0) {
+ p = stack[top].p;
+ r = stack[top].r;
+ while (r > p + 10) {
+ seed = Math.abs( seed * 1539415821 + 1 );
+ i = p + seed % (r - p + 1);
+ piv = order[i];
+ order[i] = order[p];
+ order[p] = piv;
+ i = p - 1;
+ j = r + 1;
+ do {
+ do {
+ ++i;
+ } while (GT(leq, keys[order[i]], keys[piv]));
+ do {
+ --j;
+ } while (LT(leq, keys[order[j]], keys[piv]));
+ Swap(order, i, j);
+ } while (i < j);
+ Swap(order, i, j); /* Undo last swap */
+ if (i - p < r - j) {
+ stack[top].p = j + 1;
+ stack[top].r = r;
+ ++top;
+ r = i - 1;
+ } else {
+ stack[top].p = p;
+ stack[top].r = i - 1;
+ ++top;
+ p = j + 1;
+ }
+ }
+ /* Insertion sort small lists */
+ for (i = p + 1; i <= r; ++i) {
+ piv = order[i];
+ for (j = i; j > p && LT(leq, keys[order[j - 1]], keys[piv]); --j) {
+ order[j] = order[j - 1];
+ }
+ order[j] = piv;
+ }
+ }
+ max = size;
+ initialized = true;
+ heap.pqInit(); /* always succeeds */
+
+/* #ifndef NDEBUG
+ p = order;
+ r = p + size - 1;
+ for (i = p; i < r; ++i) {
+ Assertion.doAssert(LEQ( * * (i + 1), **i ));
+ }
+ #endif*/
+
+ return true;
+ }
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */
+ int pqInsert(Object keyNew) {
+ int curr;
+
+ if (initialized) {
+ return heap.pqInsert(keyNew);
+ }
+ curr = size;
+ if (++size >= max) {
+ Object[] saveKey = keys;
+
+ /* If the heap overflows, double its size. */
+ max <<= 1;
+// pq->keys = (PQHeapKey *)memRealloc( pq->keys,(size_t)(pq->max * sizeof( pq->keys[0] )));
+ Object[] pqKeys = new Object[max];
+ System.arraycopy( keys, 0, pqKeys, 0, keys.length );
+ keys = pqKeys;
+ if (keys == null) {
+ keys = saveKey; /* restore ptr to free upon return */
+ return Integer.MAX_VALUE;
+ }
+ }
+ assert curr != Integer.MAX_VALUE;
+ keys[curr] = keyNew;
+
+ /* Negative handles index the sorted array. */
+ return -(curr + 1);
+ }
+
+/* really __gl_pqSortExtractMin */
+ Object pqExtractMin() {
+ Object sortMin, heapMin;
+
+ if (size == 0) {
+ return heap.pqExtractMin();
+ }
+ sortMin = keys[order[size - 1]];
+ if (!heap.pqIsEmpty()) {
+ heapMin = heap.pqMinimum();
+ if (LEQ(leq, heapMin, sortMin)) {
+ return heap.pqExtractMin();
+ }
+ }
+ do {
+ --size;
+ } while (size > 0 && keys[order[size - 1]] == null);
+ return sortMin;
+ }
+
+/* really __gl_pqSortMinimum */
+ Object pqMinimum() {
+ Object sortMin, heapMin;
+
+ if (size == 0) {
+ return heap.pqMinimum();
+ }
+ sortMin = keys[order[size - 1]];
+ if (!heap.pqIsEmpty()) {
+ heapMin = heap.pqMinimum();
+ if (PriorityQHeap.LEQ(leq, heapMin, sortMin)) {
+ return heapMin;
+ }
+ }
+ return sortMin;
+ }
+
+/* really __gl_pqSortIsEmpty */
+ boolean pqIsEmpty() {
+ return (size == 0) && heap.pqIsEmpty();
+ }
+
+/* really __gl_pqSortDelete */
+ void pqDelete(int curr) {
+ if (curr >= 0) {
+ heap.pqDelete(curr);
+ return;
+ }
+ curr = -(curr + 1);
+ assert curr < max && keys[curr] != null;
+
+ keys[curr] = null;
+ while (size > 0 && keys[order[size - 1]] == null) {
+ --size;
+ }
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Render.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Render.java
new file mode 100644
index 0000000..759c75b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Render.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+import static org.lwjgl.opengl.GL11.*;
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+class Render {
+ private static final boolean USE_OPTIMIZED_CODE_PATH = false;
+
+ private Render() {
+ }
+
+ private static final RenderFan renderFan = new RenderFan();
+ private static final RenderStrip renderStrip = new RenderStrip();
+ private static final RenderTriangle renderTriangle = new RenderTriangle();
+
+/* This structure remembers the information we need about a primitive
+ * to be able to render it later, once we have determined which
+ * primitive is able to use the most triangles.
+ */
+ private static class FaceCount {
+ private FaceCount() {
+ }
+
+ private FaceCount(long size, GLUhalfEdge eStart, renderCallBack render) {
+ this.size = size;
+ this.eStart = eStart;
+ this.render = render;
+ }
+
+ long size; /* number of triangles used */
+ GLUhalfEdge eStart; /* edge where this primitive starts */
+ renderCallBack render;
+ };
+
+ private interface renderCallBack {
+ void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size);
+ }
+
+ /************************ Strips and Fans decomposition ******************/
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+ public static void __gl_renderMesh(GLUtessellatorImpl tess, GLUmesh mesh) {
+ GLUface f;
+
+ /* Make a list of separate triangles so we can render them all at once */
+ tess.lonelyTriList = null;
+
+ for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) {
+ f.marked = false;
+ }
+ for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) {
+
+ /* We examine all faces in an arbitrary order. Whenever we find
+ * an unprocessed face F, we output a group of faces including F
+ * whose size is maximum.
+ */
+ if (f.inside && !f.marked) {
+ RenderMaximumFaceGroup(tess, f);
+ assert (f.marked);
+ }
+ }
+ if (tess.lonelyTriList != null) {
+ RenderLonelyTriangles(tess, tess.lonelyTriList);
+ tess.lonelyTriList = null;
+ }
+ }
+
+
+ static void RenderMaximumFaceGroup(GLUtessellatorImpl tess, GLUface fOrig) {
+ /* We want to find the largest triangle fan or strip of unmarked faces
+ * which includes the given face fOrig. There are 3 possible fans
+ * passing through fOrig (one centered at each vertex), and 3 possible
+ * strips (one for each CCW permutation of the vertices). Our strategy
+ * is to try all of these, and take the primitive which uses the most
+ * triangles (a greedy approach).
+ */
+ GLUhalfEdge e = fOrig.anEdge;
+ FaceCount max = new FaceCount();
+ FaceCount newFace;
+
+ max.size = 1;
+ max.eStart = e;
+ max.render = renderTriangle;
+
+ if (!tess.flagBoundary) {
+ newFace = MaximumFan(e);
+ if (newFace.size > max.size) {
+ max = newFace;
+ }
+ newFace = MaximumFan(e.Lnext);
+ if (newFace.size > max.size) {
+ max = newFace;
+ }
+ newFace = MaximumFan(e.Onext.Sym);
+ if (newFace.size > max.size) {
+ max = newFace;
+ }
+
+ newFace = MaximumStrip(e);
+ if (newFace.size > max.size) {
+ max = newFace;
+ }
+ newFace = MaximumStrip(e.Lnext);
+ if (newFace.size > max.size) {
+ max = newFace;
+ }
+ newFace = MaximumStrip(e.Onext.Sym);
+ if (newFace.size > max.size) {
+ max = newFace;
+ }
+ }
+ max.render.render(tess, max.eStart, max.size);
+ }
+
+
+/* Macros which keep track of faces we have marked temporarily, and allow
+ * us to backtrack when necessary. With triangle fans, this is not
+ * really necessary, since the only awkward case is a loop of triangles
+ * around a single origin vertex. However with strips the situation is
+ * more complicated, and we need a general tracking method like the
+ * one here.
+ */
+ private static boolean Marked(GLUface f) {
+ return !f.inside || f.marked;
+ }
+
+ private static GLUface AddToTrail(GLUface f, GLUface t) {
+ f.trail = t;
+ f.marked = true;
+ return f;
+ }
+
+ private static void FreeTrail(GLUface t) {
+ if (true) {
+ while (t != null) {
+ t.marked = false;
+ t = t.trail;
+ }
+ } else {
+ /* absorb trailing semicolon */
+ }
+ }
+
+ static FaceCount MaximumFan(GLUhalfEdge eOrig) {
+ /* eOrig.Lface is the face we want to render. We want to find the size
+ * of a maximal fan around eOrig.Org. To do this we just walk around
+ * the origin vertex as far as possible in both directions.
+ */
+ FaceCount newFace = new FaceCount(0, null, renderFan);
+ GLUface trail = null;
+ GLUhalfEdge e;
+
+ for (e = eOrig; !Marked(e.Lface); e = e.Onext) {
+ trail = AddToTrail(e.Lface, trail);
+ ++newFace.size;
+ }
+ for (e = eOrig; !Marked(e.Sym.Lface); e = e.Sym.Lnext) {
+ trail = AddToTrail(e.Sym.Lface, trail);
+ ++newFace.size;
+ }
+ newFace.eStart = e;
+ /*LINTED*/
+ FreeTrail(trail);
+ return newFace;
+ }
+
+
+ private static boolean IsEven(long n) {
+ return (n & 0x1L) == 0;
+ }
+
+ static FaceCount MaximumStrip(GLUhalfEdge eOrig) {
+ /* Here we are looking for a maximal strip that contains the vertices
+ * eOrig.Org, eOrig.Dst, eOrig.Lnext.Dst (in that order or the
+ * reverse, such that all triangles are oriented CCW).
+ *
+ * Again we walk forward and backward as far as possible. However for
+ * strips there is a twist: to get CCW orientations, there must be
+ * an *even* number of triangles in the strip on one side of eOrig.
+ * We walk the strip starting on a side with an even number of triangles;
+ * if both side have an odd number, we are forced to shorten one side.
+ */
+ FaceCount newFace = new FaceCount(0, null, renderStrip);
+ long headSize = 0, tailSize = 0;
+ GLUface trail = null;
+ GLUhalfEdge e, eTail, eHead;
+
+ for (e = eOrig; !Marked(e.Lface); ++tailSize, e = e.Onext) {
+ trail = AddToTrail(e.Lface, trail);
+ ++tailSize;
+ e = e.Lnext.Sym;
+ if (Marked(e.Lface)) break;
+ trail = AddToTrail(e.Lface, trail);
+ }
+ eTail = e;
+
+ for (e = eOrig; !Marked(e.Sym.Lface); ++headSize, e = e.Sym.Onext.Sym) {
+ trail = AddToTrail(e.Sym.Lface, trail);
+ ++headSize;
+ e = e.Sym.Lnext;
+ if (Marked(e.Sym.Lface)) break;
+ trail = AddToTrail(e.Sym.Lface, trail);
+ }
+ eHead = e;
+
+ newFace.size = tailSize + headSize;
+ if (IsEven(tailSize)) {
+ newFace.eStart = eTail.Sym;
+ } else if (IsEven(headSize)) {
+ newFace.eStart = eHead;
+ } else {
+ /* Both sides have odd length, we must shorten one of them. In fact,
+ * we must start from eHead to guarantee inclusion of eOrig.Lface.
+ */
+ --newFace.size;
+ newFace.eStart = eHead.Onext;
+ }
+ /*LINTED*/
+ FreeTrail(trail);
+ return newFace;
+ }
+
+ private static class RenderTriangle implements renderCallBack {
+ public void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size) {
+ /* Just add the triangle to a triangle list, so we can render all
+ * the separate triangles at once.
+ */
+ assert (size == 1);
+ tess.lonelyTriList = AddToTrail(e.Lface, tess.lonelyTriList);
+ }
+ }
+
+
+ static void RenderLonelyTriangles(GLUtessellatorImpl tess, GLUface f) {
+ /* Now we render all the separate triangles which could not be
+ * grouped into a triangle fan or strip.
+ */
+ GLUhalfEdge e;
+ int newState;
+ int edgeState = -1; /* force edge state output for first vertex */
+
+ tess.callBeginOrBeginData(GL_TRIANGLES);
+
+ for (; f != null; f = f.trail) {
+ /* Loop once for each edge (there will always be 3 edges) */
+
+ e = f.anEdge;
+ do {
+ if (tess.flagBoundary) {
+ /* Set the "edge state" to true just before we output the
+ * first vertex of each edge on the polygon boundary.
+ */
+ newState = (!e.Sym.Lface.inside) ? 1 : 0;
+ if (edgeState != newState) {
+ edgeState = newState;
+ tess.callEdgeFlagOrEdgeFlagData( edgeState != 0);
+ }
+ }
+ tess.callVertexOrVertexData( e.Org.data);
+
+ e = e.Lnext;
+ } while (e != f.anEdge);
+ }
+ tess.callEndOrEndData();
+ }
+
+ private static class RenderFan implements renderCallBack {
+ public void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size) {
+ /* Render as many CCW triangles as possible in a fan starting from
+ * edge "e". The fan *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ tess.callBeginOrBeginData(GL_TRIANGLE_FAN);
+ tess.callVertexOrVertexData( e.Org.data);
+ tess.callVertexOrVertexData( e.Sym.Org.data);
+
+ while (!Marked(e.Lface)) {
+ e.Lface.marked = true;
+ --size;
+ e = e.Onext;
+ tess.callVertexOrVertexData( e.Sym.Org.data);
+ }
+
+ assert (size == 0);
+ tess.callEndOrEndData();
+ }
+ }
+
+ private static class RenderStrip implements renderCallBack {
+ public void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size) {
+ /* Render as many CCW triangles as possible in a strip starting from
+ * edge "e". The strip *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ tess.callBeginOrBeginData(GL_TRIANGLE_STRIP);
+ tess.callVertexOrVertexData( e.Org.data);
+ tess.callVertexOrVertexData( e.Sym.Org.data);
+
+ while (!Marked(e.Lface)) {
+ e.Lface.marked = true;
+ --size;
+ e = e.Lnext.Sym;
+ tess.callVertexOrVertexData( e.Org.data);
+ if (Marked(e.Lface)) break;
+
+ e.Lface.marked = true;
+ --size;
+ e = e.Onext;
+ tess.callVertexOrVertexData( e.Sym.Org.data);
+ }
+
+ assert (size == 0);
+ tess.callEndOrEndData();
+ }
+ }
+
+ /************************ Boundary contour decomposition ******************/
+
+/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
+ * contour for each face marked "inside". The rendering output is
+ * provided as callbacks (see the api).
+ */
+ public static void __gl_renderBoundary(GLUtessellatorImpl tess, GLUmesh mesh) {
+ GLUface f;
+ GLUhalfEdge e;
+
+ for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) {
+ if (f.inside) {
+ tess.callBeginOrBeginData(GL_LINE_LOOP);
+ e = f.anEdge;
+ do {
+ tess.callVertexOrVertexData( e.Org.data);
+ e = e.Lnext;
+ } while (e != f.anEdge);
+ tess.callEndOrEndData();
+ }
+ }
+ }
+
+
+ /************************ Quick-and-dirty decomposition ******************/
+
+ private static final int SIGN_INCONSISTENT = 2;
+
+ static int ComputeNormal(GLUtessellatorImpl tess, double[] norm, boolean check)
+/*
+ * If check==false, we compute the polygon normal and place it in norm[].
+ * If check==true, we check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm[]. If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */ {
+ CachedVertex[] v = tess.cache;
+// CachedVertex vn = v0 + tess.cacheCount;
+ int vn = tess.cacheCount;
+// CachedVertex vc;
+ int vc;
+ double dot, xc, yc, zc, xp, yp, zp;
+ double[] n = new double[3];
+ int sign = 0;
+
+ /* Find the polygon normal. It is important to get a reasonable
+ * normal even when the polygon is self-intersecting (eg. a bowtie).
+ * Otherwise, the computed normal could be very tiny, but perpendicular
+ * to the true plane of the polygon due to numerical noise. Then all
+ * the triangles would appear to be degenerate and we would incorrectly
+ * decompose the polygon as a fan (or simply not render it at all).
+ *
+ * We use a sum-of-triangles normal algorithm rather than the more
+ * efficient sum-of-trapezoids method (used in CheckOrientation()
+ * in normal.c). This lets us explicitly reverse the signed area
+ * of some triangles to get a reasonable normal in the self-intersecting
+ * case.
+ */
+ if (!check) {
+ norm[0] = norm[1] = norm[2] = 0.0;
+ }
+
+ vc = 1;
+ xc = v[vc].coords[0] - v[0].coords[0];
+ yc = v[vc].coords[1] - v[0].coords[1];
+ zc = v[vc].coords[2] - v[0].coords[2];
+ while (++vc < vn) {
+ xp = xc;
+ yp = yc;
+ zp = zc;
+ xc = v[vc].coords[0] - v[0].coords[0];
+ yc = v[vc].coords[1] - v[0].coords[1];
+ zc = v[vc].coords[2] - v[0].coords[2];
+
+ /* Compute (vp - v0) cross (vc - v0) */
+ n[0] = yp * zc - zp * yc;
+ n[1] = zp * xc - xp * zc;
+ n[2] = xp * yc - yp * xc;
+
+ dot = n[0] * norm[0] + n[1] * norm[1] + n[2] * norm[2];
+ if (!check) {
+ /* Reverse the contribution of back-facing triangles to get
+ * a reasonable normal for self-intersecting polygons (see above)
+ */
+ if (dot >= 0) {
+ norm[0] += n[0];
+ norm[1] += n[1];
+ norm[2] += n[2];
+ } else {
+ norm[0] -= n[0];
+ norm[1] -= n[1];
+ norm[2] -= n[2];
+ }
+ } else if (dot != 0) {
+ /* Check the new orientation for consistency with previous triangles */
+ if (dot > 0) {
+ if (sign < 0) return SIGN_INCONSISTENT;
+ sign = 1;
+ } else {
+ if (sign > 0) return SIGN_INCONSISTENT;
+ sign = -1;
+ }
+ }
+ }
+ return sign;
+ }
+
+/* __gl_renderCache( tess ) takes a single contour and tries to render it
+ * as a triangle fan. This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns true if the polygon was successfully rendered. The rendering
+ * output is provided as callbacks (see the api).
+ */
+ public static boolean __gl_renderCache(GLUtessellatorImpl tess) {
+ CachedVertex[] v = tess.cache;
+// CachedVertex vn = v0 + tess.cacheCount;
+ int vn = tess.cacheCount;
+// CachedVertex vc;
+ int vc;
+ double[] norm = new double[3];
+ int sign;
+
+ if (tess.cacheCount < 3) {
+ /* Degenerate contour -- no output */
+ return true;
+ }
+
+ norm[0] = tess.normal[0];
+ norm[1] = tess.normal[1];
+ norm[2] = tess.normal[2];
+ if (norm[0] == 0 && norm[1] == 0 && norm[2] == 0) {
+ ComputeNormal( tess, norm, false);
+ }
+
+ sign = ComputeNormal( tess, norm, true);
+ if (sign == SIGN_INCONSISTENT) {
+ /* Fan triangles did not have a consistent orientation */
+ return false;
+ }
+ if (sign == 0) {
+ /* All triangles were degenerate */
+ return true;
+ }
+
+ if ( !USE_OPTIMIZED_CODE_PATH ) {
+ return false;
+ } else {
+ /* Make sure we do the right thing for each winding rule */
+ switch (tess.windingRule) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ break;
+ case GLU_TESS_WINDING_POSITIVE:
+ if (sign < 0) return true;
+ break;
+ case GLU_TESS_WINDING_NEGATIVE:
+ if (sign > 0) return true;
+ break;
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return true;
+ }
+
+ tess.callBeginOrBeginData( tess.boundaryOnly ? GL_LINE_LOOP
+ : (tess.cacheCount > 3) ? GL_TRIANGLE_FAN
+ : GL_TRIANGLES);
+
+ tess.callVertexOrVertexData( v[0].data);
+ if (sign > 0) {
+ for (vc = 1; vc < vn; ++vc) {
+ tess.callVertexOrVertexData( v[vc].data);
+ }
+ } else {
+ for (vc = vn - 1; vc > 0; --vc) {
+ tess.callVertexOrVertexData( v[vc].data);
+ }
+ }
+ tess.callEndOrEndData();
+ return true;
+ }
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Sweep.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Sweep.java
new file mode 100644
index 0000000..4be2c54
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/Sweep.java
@@ -0,0 +1,1384 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+import static de.verschwiegener.lwjgl3.util.glu.GLU.*;
+
+class Sweep {
+ private Sweep() {
+ }
+
+// #ifdef FOR_TRITE_TEST_PROGRAM
+// extern void DebugEvent( GLUtessellator *tess );
+// #else
+ private static void DebugEvent(GLUtessellatorImpl tess) {
+
+ }
+// #endif
+
+/*
+ * Invariants for the Edge Dictionary.
+ * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ * at any valid location of the sweep event
+ * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ * share a common endpoint
+ * - for each e, e.Dst has been processed, but not e.Org
+ * - each edge e satisfies VertLeq(e.Dst,event) && VertLeq(event,e.Org)
+ * where "event" is the current sweep line event.
+ * - no edge e has zero length
+ *
+ * Invariants for the Mesh (the processed portion).
+ * - the portion of the mesh left of the sweep line is a planar graph,
+ * ie. there is *some* way to embed it in the plane
+ * - no processed edge has zero length
+ * - no two processed vertices have identical coordinates
+ * - each "inside" region is monotone, ie. can be broken into two chains
+ * of monotonically increasing vertices according to VertLeq(v1,v2)
+ * - a non-invariant: these chains may intersect (very slightly)
+ *
+ * Invariants for the Sweep.
+ * - if none of the edges incident to the event vertex have an activeRegion
+ * (ie. none of these edges are in the edge dictionary), then the vertex
+ * has only right-going edges.
+ * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ * by ConnectRightVertex), then it is the only right-going edge from
+ * its associated vertex. (This says that these edges exist only
+ * when it is necessary.)
+ */
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+ private static void AddWinding(GLUhalfEdge eDst, GLUhalfEdge eSrc) {
+ eDst.winding += eSrc.winding;
+ eDst.Sym.winding += eSrc.Sym.winding;
+ }
+
+
+ private static ActiveRegion RegionBelow(ActiveRegion r) {
+ return ((ActiveRegion) Dict.dictKey(Dict.dictPred(r.nodeUp)));
+ }
+
+ private static ActiveRegion RegionAbove(ActiveRegion r) {
+ return ((ActiveRegion) Dict.dictKey(Dict.dictSucc(r.nodeUp)));
+ }
+
+ static boolean EdgeLeq(GLUtessellatorImpl tess, ActiveRegion reg1, ActiveRegion reg2)
+/*
+ * Both edges must be directed from right to left (this is the canonical
+ * direction for the upper edge of each region).
+ *
+ * The strategy is to evaluate a "t" value for each edge at the
+ * current sweep line position, given by tess.event. The calculations
+ * are designed to be very stable, but of course they are not perfect.
+ *
+ * Special case: if both edge destinations are at the sweep event,
+ * we sort the edges by slope (they would otherwise compare equally).
+ */ {
+ GLUvertex event = tess.event;
+ GLUhalfEdge e1, e2;
+ double t1, t2;
+
+ e1 = reg1.eUp;
+ e2 = reg2.eUp;
+
+ if (e1.Sym.Org == event) {
+ if (e2.Sym.Org == event) {
+ /* Two edges right of the sweep line which meet at the sweep event.
+ * Sort them by slope.
+ */
+ if (Geom.VertLeq(e1.Org, e2.Org)) {
+ return Geom.EdgeSign(e2.Sym.Org, e1.Org, e2.Org) <= 0;
+ }
+ return Geom.EdgeSign(e1.Sym.Org, e2.Org, e1.Org) >= 0;
+ }
+ return Geom.EdgeSign(e2.Sym.Org, event, e2.Org) <= 0;
+ }
+ if (e2.Sym.Org == event) {
+ return Geom.EdgeSign(e1.Sym.Org, event, e1.Org) >= 0;
+ }
+
+ /* General case - compute signed distance *from* e1, e2 to event */
+ t1 = Geom.EdgeEval(e1.Sym.Org, event, e1.Org);
+ t2 = Geom.EdgeEval(e2.Sym.Org, event, e2.Org);
+ return (t1 >= t2);
+ }
+
+
+ static void DeleteRegion(GLUtessellatorImpl tess, ActiveRegion reg) {
+ if (reg.fixUpperEdge) {
+ /* It was created with zero winding number, so it better be
+ * deleted with zero winding number (ie. it better not get merged
+ * with a real edge).
+ */
+ assert (reg.eUp.winding == 0);
+ }
+ reg.eUp.activeRegion = null;
+ Dict.dictDelete(tess.dict, reg.nodeUp); /* __gl_dictListDelete */
+ }
+
+
+ static boolean FixUpperEdge(ActiveRegion reg, GLUhalfEdge newEdge)
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */ {
+ assert (reg.fixUpperEdge);
+ if (!Mesh.__gl_meshDelete(reg.eUp)) return false;
+ reg.fixUpperEdge = false;
+ reg.eUp = newEdge;
+ newEdge.activeRegion = reg;
+
+ return true;
+ }
+
+ static ActiveRegion TopLeftRegion(ActiveRegion reg) {
+ GLUvertex org = reg.eUp.Org;
+ GLUhalfEdge e;
+
+ /* Find the region above the uppermost edge with the same origin */
+ do {
+ reg = RegionAbove(reg);
+ } while (reg.eUp.Org == org);
+
+ /* If the edge above was a temporary edge introduced by ConnectRightVertex,
+ * now is the time to fix it.
+ */
+ if (reg.fixUpperEdge) {
+ e = Mesh.__gl_meshConnect(RegionBelow(reg).eUp.Sym, reg.eUp.Lnext);
+ if (e == null) return null;
+ if (!FixUpperEdge(reg, e)) return null;
+ reg = RegionAbove(reg);
+ }
+ return reg;
+ }
+
+ static ActiveRegion TopRightRegion(ActiveRegion reg) {
+ GLUvertex dst = reg.eUp.Sym.Org;
+
+ /* Find the region above the uppermost edge with the same destination */
+ do {
+ reg = RegionAbove(reg);
+ } while (reg.eUp.Sym.Org == dst);
+ return reg;
+ }
+
+ static ActiveRegion AddRegionBelow(GLUtessellatorImpl tess,
+ ActiveRegion regAbove,
+ GLUhalfEdge eNewUp)
+/*
+ * Add a new active region to the sweep line, *somewhere* below "regAbove"
+ * (according to where the new edge belongs in the sweep-line dictionary).
+ * The upper edge of the new region will be "eNewUp".
+ * Winding number and "inside" flag are not updated.
+ */ {
+ ActiveRegion regNew = new ActiveRegion();
+ if (regNew == null) throw new RuntimeException();
+
+ regNew.eUp = eNewUp;
+ /* __gl_dictListInsertBefore */
+ regNew.nodeUp = Dict.dictInsertBefore(tess.dict, regAbove.nodeUp, regNew);
+ if (regNew.nodeUp == null) throw new RuntimeException();
+ regNew.fixUpperEdge = false;
+ regNew.sentinel = false;
+ regNew.dirty = false;
+
+ eNewUp.activeRegion = regNew;
+ return regNew;
+ }
+
+ static boolean IsWindingInside(GLUtessellatorImpl tess, int n) {
+ switch (tess.windingRule) {
+ case GLU_TESS_WINDING_ODD:
+ return (n & 1) != 0;
+ case GLU_TESS_WINDING_NONZERO:
+ return (n != 0);
+ case GLU_TESS_WINDING_POSITIVE:
+ return (n > 0);
+ case GLU_TESS_WINDING_NEGATIVE:
+ return (n < 0);
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return (n >= 2) || (n <= -2);
+ }
+ /*LINTED*/
+// assert (false);
+ throw new InternalError();
+ /*NOTREACHED*/
+ }
+
+
+ static void ComputeWinding(GLUtessellatorImpl tess, ActiveRegion reg) {
+ reg.windingNumber = RegionAbove(reg).windingNumber + reg.eUp.winding;
+ reg.inside = IsWindingInside(tess, reg.windingNumber);
+ }
+
+
+ static void FinishRegion(GLUtessellatorImpl tess, ActiveRegion reg)
+/*
+ * Delete a region from the sweep line. This happens when the upper
+ * and lower chains of a region meet (at a vertex on the sweep line).
+ * The "inside" flag is copied to the appropriate mesh face (we could
+ * not do this before -- since the structure of the mesh is always
+ * changing, this face may not have even existed until now).
+ */ {
+ GLUhalfEdge e = reg.eUp;
+ GLUface f = e.Lface;
+
+ f.inside = reg.inside;
+ f.anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */
+ DeleteRegion(tess, reg);
+ }
+
+
+ static GLUhalfEdge FinishLeftRegions(GLUtessellatorImpl tess,
+ ActiveRegion regFirst, ActiveRegion regLast)
+/*
+ * We are given a vertex with one or more left-going edges. All affected
+ * edges should be in the edge dictionary. Starting at regFirst.eUp,
+ * we walk down deleting all regions where both edges have the same
+ * origin vOrg. At the same time we copy the "inside" flag from the
+ * active region to the face, since at this point each face will belong
+ * to at most one region (this was not necessarily true until this point
+ * in the sweep). The walk stops at the region above regLast; if regLast
+ * is null we walk as far as possible. At the same time we relink the
+ * mesh if necessary, so that the ordering of edges around vOrg is the
+ * same as in the dictionary.
+ */ {
+ ActiveRegion reg, regPrev;
+ GLUhalfEdge e, ePrev;
+
+ regPrev = regFirst;
+ ePrev = regFirst.eUp;
+ while (regPrev != regLast) {
+ regPrev.fixUpperEdge = false; /* placement was OK */
+ reg = RegionBelow(regPrev);
+ e = reg.eUp;
+ if (e.Org != ePrev.Org) {
+ if (!reg.fixUpperEdge) {
+ /* Remove the last left-going edge. Even though there are no further
+ * edges in the dictionary with this origin, there may be further
+ * such edges in the mesh (if we are adding left edges to a vertex
+ * that has already been processed). Thus it is important to call
+ * FinishRegion rather than just DeleteRegion.
+ */
+ FinishRegion(tess, regPrev);
+ break;
+ }
+ /* If the edge below was a temporary edge introduced by
+ * ConnectRightVertex, now is the time to fix it.
+ */
+ e = Mesh.__gl_meshConnect(ePrev.Onext.Sym, e.Sym);
+ if (e == null) throw new RuntimeException();
+ if (!FixUpperEdge(reg, e)) throw new RuntimeException();
+ }
+
+ /* Relink edges so that ePrev.Onext == e */
+ if (ePrev.Onext != e) {
+ if (!Mesh.__gl_meshSplice(e.Sym.Lnext, e)) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(ePrev, e)) throw new RuntimeException();
+ }
+ FinishRegion(tess, regPrev); /* may change reg.eUp */
+ ePrev = reg.eUp;
+ regPrev = reg;
+ }
+ return ePrev;
+ }
+
+
+ static void AddRightEdges(GLUtessellatorImpl tess, ActiveRegion regUp,
+ GLUhalfEdge eFirst, GLUhalfEdge eLast, GLUhalfEdge eTopLeft,
+ boolean cleanUp)
+/*
+ * Purpose: insert right-going edges into the edge dictionary, and update
+ * winding numbers and mesh connectivity appropriately. All right-going
+ * edges share a common origin vOrg. Edges are inserted CCW starting at
+ * eFirst; the last edge inserted is eLast.Sym.Lnext. If vOrg has any
+ * left-going edges already processed, then eTopLeft must be the edge
+ * such that an imaginary upward vertical segment from vOrg would be
+ * contained between eTopLeft.Sym.Lnext and eTopLeft; otherwise eTopLeft
+ * should be null.
+ */ {
+ ActiveRegion reg, regPrev;
+ GLUhalfEdge e, ePrev;
+ boolean firstTime = true;
+
+ /* Insert the new right-going edges in the dictionary */
+ e = eFirst;
+ do {
+ assert (Geom.VertLeq(e.Org, e.Sym.Org));
+ AddRegionBelow(tess, regUp, e.Sym);
+ e = e.Onext;
+ } while (e != eLast);
+
+ /* Walk *all* right-going edges from e.Org, in the dictionary order,
+ * updating the winding numbers of each region, and re-linking the mesh
+ * edges to match the dictionary ordering (if necessary).
+ */
+ if (eTopLeft == null) {
+ eTopLeft = RegionBelow(regUp).eUp.Sym.Onext;
+ }
+ regPrev = regUp;
+ ePrev = eTopLeft;
+ for (; ;) {
+ reg = RegionBelow(regPrev);
+ e = reg.eUp.Sym;
+ if (e.Org != ePrev.Org) break;
+
+ if (e.Onext != ePrev) {
+ /* Unlink e from its current position, and relink below ePrev */
+ if (!Mesh.__gl_meshSplice(e.Sym.Lnext, e)) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(ePrev.Sym.Lnext, e)) throw new RuntimeException();
+ }
+ /* Compute the winding number and "inside" flag for the new regions */
+ reg.windingNumber = regPrev.windingNumber - e.winding;
+ reg.inside = IsWindingInside(tess, reg.windingNumber);
+
+ /* Check for two outgoing edges with same slope -- process these
+ * before any intersection tests (see example in __gl_computeInterior).
+ */
+ regPrev.dirty = true;
+ if (!firstTime && CheckForRightSplice(tess, regPrev)) {
+ AddWinding(e, ePrev);
+ DeleteRegion(tess, regPrev);
+ if (!Mesh.__gl_meshDelete(ePrev)) throw new RuntimeException();
+ }
+ firstTime = false;
+ regPrev = reg;
+ ePrev = e;
+ }
+ regPrev.dirty = true;
+ assert (regPrev.windingNumber - e.winding == reg.windingNumber);
+
+ if (cleanUp) {
+ /* Check for intersections between newly adjacent edges. */
+ WalkDirtyRegions(tess, regPrev);
+ }
+ }
+
+
+ static void CallCombine(GLUtessellatorImpl tess, GLUvertex isect,
+ Object[] data, float[] weights, boolean needed) {
+ double[] coords = new double[3];
+
+ /* Copy coord data in case the callback changes it. */
+ coords[0] = isect.coords[0];
+ coords[1] = isect.coords[1];
+ coords[2] = isect.coords[2];
+
+ Object[] outData = new Object[1];
+ tess.callCombineOrCombineData(coords, data, weights, outData);
+ isect.data = outData[0];
+ if (isect.data == null) {
+ if (!needed) {
+ isect.data = data[0];
+ } else if (!tess.fatalError) {
+ /* The only way fatal error is when two edges are found to intersect,
+ * but the user has not provided the callback necessary to handle
+ * generated intersection points.
+ */
+ tess.callErrorOrErrorData(GLU_TESS_NEED_COMBINE_CALLBACK);
+ tess.fatalError = true;
+ }
+ }
+ }
+
+ static void SpliceMergeVertices(GLUtessellatorImpl tess, GLUhalfEdge e1,
+ GLUhalfEdge e2)
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1.Org is kept, while e2.Org is discarded.
+ */ {
+ Object[] data = new Object[4];
+ float[] weights = new float[]{0.5f, 0.5f, 0.0f, 0.0f};
+
+ data[0] = e1.Org.data;
+ data[1] = e2.Org.data;
+ CallCombine(tess, e1.Org, data, weights, false);
+ if (!Mesh.__gl_meshSplice(e1, e2)) throw new RuntimeException();
+ }
+
+ static void VertexWeights(GLUvertex isect, GLUvertex org, GLUvertex dst,
+ float[] weights)
+/*
+ * Find some weights which describe how the intersection vertex is
+ * a linear combination of "org" and "dest". Each of the two edges
+ * which generated "isect" is allocated 50% of the weight; each edge
+ * splits the weight between its org and dst according to the
+ * relative distance to "isect".
+ */ {
+ double t1 = Geom.VertL1dist(org, isect);
+ double t2 = Geom.VertL1dist(dst, isect);
+
+ weights[0] = (float) (0.5 * t2 / (t1 + t2));
+ weights[1] = (float) (0.5 * t1 / (t1 + t2));
+ isect.coords[0] += weights[0] * org.coords[0] + weights[1] * dst.coords[0];
+ isect.coords[1] += weights[0] * org.coords[1] + weights[1] * dst.coords[1];
+ isect.coords[2] += weights[0] * org.coords[2] + weights[1] * dst.coords[2];
+ }
+
+
+ static void GetIntersectData(GLUtessellatorImpl tess, GLUvertex isect,
+ GLUvertex orgUp, GLUvertex dstUp,
+ GLUvertex orgLo, GLUvertex dstLo)
+/*
+ * We've computed a new intersection point, now we need a "data" pointer
+ * from the user so that we can refer to this new vertex in the
+ * rendering callbacks.
+ */ {
+ Object[] data = new Object[4];
+ float[] weights = new float[4];
+ float[] weights1 = new float[2];
+ float[] weights2 = new float[2];
+
+ data[0] = orgUp.data;
+ data[1] = dstUp.data;
+ data[2] = orgLo.data;
+ data[3] = dstLo.data;
+
+ isect.coords[0] = isect.coords[1] = isect.coords[2] = 0;
+ VertexWeights(isect, orgUp, dstUp, weights1);
+ VertexWeights(isect, orgLo, dstLo, weights2);
+ System.arraycopy(weights1, 0, weights, 0, 2);
+ System.arraycopy(weights2, 0, weights, 2, 2);
+
+ CallCombine(tess, isect, data, weights, true);
+ }
+
+ static boolean CheckForRightSplice(GLUtessellatorImpl tess, ActiveRegion regUp)
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp.Org is above eLo, or eLo.Org is below eUp (depending on which
+ * origin is leftmost).
+ *
+ * The main purpose is to splice right-going edges with the same
+ * dest vertex and nearly identical slopes (ie. we can't distinguish
+ * the slopes numerically). However the splicing can also help us
+ * to recover from numerical errors. For example, suppose at one
+ * point we checked eUp and eLo, and decided that eUp.Org is barely
+ * above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * our test so that now eUp.Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants.
+ *
+ * One possibility is to check these edges for intersection again
+ * (ie. CheckForIntersect). This is what we do if possible. However
+ * CheckForIntersect requires that tess.event lies between eUp and eLo,
+ * so that it has something to fall back on when the intersection
+ * calculation gives us an unusable answer. So, for those cases where
+ * we can't check for intersection, this routine fixes the problem
+ * by just splicing the offending vertex into the other edge.
+ * This is a guaranteed solution, no matter how degenerate things get.
+ * Basically this is a combinatorial solution to a numerical problem.
+ */ {
+ ActiveRegion regLo = RegionBelow(regUp);
+ GLUhalfEdge eUp = regUp.eUp;
+ GLUhalfEdge eLo = regLo.eUp;
+
+ if (Geom.VertLeq(eUp.Org, eLo.Org)) {
+ if (Geom.EdgeSign(eLo.Sym.Org, eUp.Org, eLo.Org) > 0) return false;
+
+ /* eUp.Org appears to be below eLo */
+ if (!Geom.VertEq(eUp.Org, eLo.Org)) {
+ /* Splice eUp.Org into eLo */
+ if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eUp, eLo.Sym.Lnext)) throw new RuntimeException();
+ regUp.dirty = regLo.dirty = true;
+
+ } else if (eUp.Org != eLo.Org) {
+ /* merge the two vertices, discarding eUp.Org */
+ tess.pq.pqDelete(eUp.Org.pqHandle); /* __gl_pqSortDelete */
+ SpliceMergeVertices(tess, eLo.Sym.Lnext, eUp);
+ }
+ } else {
+ if (Geom.EdgeSign(eUp.Sym.Org, eLo.Org, eUp.Org) < 0) return false;
+
+ /* eLo.Org appears to be above eUp, so splice eLo.Org into eUp */
+ RegionAbove(regUp).dirty = regUp.dirty = true;
+ if (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eLo.Sym.Lnext, eUp)) throw new RuntimeException();
+ }
+ return true;
+ }
+
+ static boolean CheckForLeftSplice(GLUtessellatorImpl tess, ActiveRegion regUp)
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp.Sym.Org is above eLo, or eLo.Sym.Org is below eUp (depending on which
+ * destination is rightmost).
+ *
+ * Theoretically, this should always be true. However, splitting an edge
+ * into two pieces can change the results of previous tests. For example,
+ * suppose at one point we checked eUp and eLo, and decided that eUp.Sym.Org
+ * is barely above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * the test so that now eUp.Sym.Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants
+ * (otherwise new edges might get inserted in the wrong place in the
+ * dictionary, and bad stuff will happen).
+ *
+ * We fix the problem by just splicing the offending vertex into the
+ * other edge.
+ */ {
+ ActiveRegion regLo = RegionBelow(regUp);
+ GLUhalfEdge eUp = regUp.eUp;
+ GLUhalfEdge eLo = regLo.eUp;
+ GLUhalfEdge e;
+
+ assert (!Geom.VertEq(eUp.Sym.Org, eLo.Sym.Org));
+
+ if (Geom.VertLeq(eUp.Sym.Org, eLo.Sym.Org)) {
+ if (Geom.EdgeSign(eUp.Sym.Org, eLo.Sym.Org, eUp.Org) < 0) return false;
+
+ /* eLo.Sym.Org is above eUp, so splice eLo.Sym.Org into eUp */
+ RegionAbove(regUp).dirty = regUp.dirty = true;
+ e = Mesh.__gl_meshSplitEdge(eUp);
+ if (e == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eLo.Sym, e)) throw new RuntimeException();
+ e.Lface.inside = regUp.inside;
+ } else {
+ if (Geom.EdgeSign(eLo.Sym.Org, eUp.Sym.Org, eLo.Org) > 0) return false;
+
+ /* eUp.Sym.Org is below eLo, so splice eUp.Sym.Org into eLo */
+ regUp.dirty = regLo.dirty = true;
+ e = Mesh.__gl_meshSplitEdge(eLo);
+ if (e == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eUp.Lnext, eLo.Sym)) throw new RuntimeException();
+ e.Sym.Lface.inside = regUp.inside;
+ }
+ return true;
+ }
+
+
+ static boolean CheckForIntersect(GLUtessellatorImpl tess, ActiveRegion regUp)
+/*
+ * Check the upper and lower edges of the given region to see if
+ * they intersect. If so, create the intersection and add it
+ * to the data structures.
+ *
+ * Returns true if adding the new intersection resulted in a recursive
+ * call to AddRightEdges(); in this case all "dirty" regions have been
+ * checked for intersections, and possibly regUp has been deleted.
+ */ {
+ ActiveRegion regLo = RegionBelow(regUp);
+ GLUhalfEdge eUp = regUp.eUp;
+ GLUhalfEdge eLo = regLo.eUp;
+ GLUvertex orgUp = eUp.Org;
+ GLUvertex orgLo = eLo.Org;
+ GLUvertex dstUp = eUp.Sym.Org;
+ GLUvertex dstLo = eLo.Sym.Org;
+ double tMinUp, tMaxLo;
+ GLUvertex isect = new GLUvertex();
+ GLUvertex orgMin;
+ GLUhalfEdge e;
+
+ assert (!Geom.VertEq(dstLo, dstUp));
+ assert (Geom.EdgeSign(dstUp, tess.event, orgUp) <= 0);
+ assert (Geom.EdgeSign(dstLo, tess.event, orgLo) >= 0);
+ assert (orgUp != tess.event && orgLo != tess.event);
+ assert (!regUp.fixUpperEdge && !regLo.fixUpperEdge);
+
+ if (orgUp == orgLo) return false; /* right endpoints are the same */
+
+ tMinUp = Math.min(orgUp.t, dstUp.t);
+ tMaxLo = Math.max(orgLo.t, dstLo.t);
+ if (tMinUp > tMaxLo) return false; /* t ranges do not overlap */
+
+ if (Geom.VertLeq(orgUp, orgLo)) {
+ if (Geom.EdgeSign(dstLo, orgUp, orgLo) > 0) return false;
+ } else {
+ if (Geom.EdgeSign(dstUp, orgLo, orgUp) < 0) return false;
+ }
+
+ /* At this point the edges intersect, at least marginally */
+ DebugEvent(tess);
+
+ Geom.EdgeIntersect(dstUp, orgUp, dstLo, orgLo, isect);
+ /* The following properties are guaranteed: */
+ assert (Math.min(orgUp.t, dstUp.t) <= isect.t);
+ assert (isect.t <= Math.max(orgLo.t, dstLo.t));
+ assert (Math.min(dstLo.s, dstUp.s) <= isect.s);
+ assert (isect.s <= Math.max(orgLo.s, orgUp.s));
+
+ if (Geom.VertLeq(isect, tess.event)) {
+ /* The intersection point lies slightly to the left of the sweep line,
+ * so move it until it''s slightly to the right of the sweep line.
+ * (If we had perfect numerical precision, this would never happen
+ * in the first place). The easiest and safest thing to do is
+ * replace the intersection by tess.event.
+ */
+ isect.s = tess.event.s;
+ isect.t = tess.event.t;
+ }
+ /* Similarly, if the computed intersection lies to the right of the
+ * rightmost origin (which should rarely happen), it can cause
+ * unbelievable inefficiency on sufficiently degenerate inputs.
+ * (If you have the test program, try running test54.d with the
+ * "X zoom" option turned on).
+ */
+ orgMin = Geom.VertLeq(orgUp, orgLo) ? orgUp : orgLo;
+ if (Geom.VertLeq(orgMin, isect)) {
+ isect.s = orgMin.s;
+ isect.t = orgMin.t;
+ }
+
+ if (Geom.VertEq(isect, orgUp) || Geom.VertEq(isect, orgLo)) {
+ /* Easy case -- intersection at one of the right endpoints */
+ CheckForRightSplice(tess, regUp);
+ return false;
+ }
+
+ if ((!Geom.VertEq(dstUp, tess.event)
+ && Geom.EdgeSign(dstUp, tess.event, isect) >= 0)
+ || (!Geom.VertEq(dstLo, tess.event)
+ && Geom.EdgeSign(dstLo, tess.event, isect) <= 0)) {
+ /* Very unusual -- the new upper or lower edge would pass on the
+ * wrong side of the sweep event, or through it. This can happen
+ * due to very small numerical errors in the intersection calculation.
+ */
+ if (dstLo == tess.event) {
+ /* Splice dstLo into eUp, and process the new region(s) */
+ if (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eLo.Sym, eUp)) throw new RuntimeException();
+ regUp = TopLeftRegion(regUp);
+ if (regUp == null) throw new RuntimeException();
+ eUp = RegionBelow(regUp).eUp;
+ FinishLeftRegions(tess, RegionBelow(regUp), regLo);
+ AddRightEdges(tess, regUp, eUp.Sym.Lnext, eUp, eUp, true);
+ return true;
+ }
+ if (dstUp == tess.event) {
+ /* Splice dstUp into eLo, and process the new region(s) */
+ if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eUp.Lnext, eLo.Sym.Lnext)) throw new RuntimeException();
+ regLo = regUp;
+ regUp = TopRightRegion(regUp);
+ e = RegionBelow(regUp).eUp.Sym.Onext;
+ regLo.eUp = eLo.Sym.Lnext;
+ eLo = FinishLeftRegions(tess, regLo, null);
+ AddRightEdges(tess, regUp, eLo.Onext, eUp.Sym.Onext, e, true);
+ return true;
+ }
+ /* Special case: called from ConnectRightVertex. If either
+ * edge passes on the wrong side of tess.event, split it
+ * (and wait for ConnectRightVertex to splice it appropriately).
+ */
+ if (Geom.EdgeSign(dstUp, tess.event, isect) >= 0) {
+ RegionAbove(regUp).dirty = regUp.dirty = true;
+ if (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+ eUp.Org.s = tess.event.s;
+ eUp.Org.t = tess.event.t;
+ }
+ if (Geom.EdgeSign(dstLo, tess.event, isect) <= 0) {
+ regUp.dirty = regLo.dirty = true;
+ if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+ eLo.Org.s = tess.event.s;
+ eLo.Org.t = tess.event.t;
+ }
+ /* leave the rest for ConnectRightVertex */
+ return false;
+ }
+
+ /* General case -- split both edges, splice into new vertex.
+ * When we do the splice operation, the order of the arguments is
+ * arbitrary as far as correctness goes. However, when the operation
+ * creates a new face, the work done is proportional to the size of
+ * the new face. We expect the faces in the processed part of
+ * the mesh (ie. eUp.Lface) to be smaller than the faces in the
+ * unprocessed original contours (which will be eLo.Sym.Lnext.Lface).
+ */
+ if (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+ if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+ if (!Mesh.__gl_meshSplice(eLo.Sym.Lnext, eUp)) throw new RuntimeException();
+ eUp.Org.s = isect.s;
+ eUp.Org.t = isect.t;
+ eUp.Org.pqHandle = tess.pq.pqInsert(eUp.Org); /* __gl_pqSortInsert */
+ if (eUp.Org.pqHandle == Long.MAX_VALUE) {
+ tess.pq.pqDeletePriorityQ(); /* __gl_pqSortDeletePriorityQ */
+ tess.pq = null;
+ throw new RuntimeException();
+ }
+ GetIntersectData(tess, eUp.Org, orgUp, dstUp, orgLo, dstLo);
+ RegionAbove(regUp).dirty = regUp.dirty = regLo.dirty = true;
+ return false;
+ }
+
+ static void WalkDirtyRegions(GLUtessellatorImpl tess, ActiveRegion regUp)
+/*
+ * When the upper or lower edge of any region changes, the region is
+ * marked "dirty". This routine walks through all the dirty regions
+ * and makes sure that the dictionary invariants are satisfied
+ * (see the comments at the beginning of this file). Of course
+ * new dirty regions can be created as we make changes to restore
+ * the invariants.
+ */ {
+ ActiveRegion regLo = RegionBelow(regUp);
+ GLUhalfEdge eUp, eLo;
+
+ for (; ;) {
+ /* Find the lowest dirty region (we walk from the bottom up). */
+ while (regLo.dirty) {
+ regUp = regLo;
+ regLo = RegionBelow(regLo);
+ }
+ if (!regUp.dirty) {
+ regLo = regUp;
+ regUp = RegionAbove(regUp);
+ if (regUp == null || !regUp.dirty) {
+ /* We've walked all the dirty regions */
+ return;
+ }
+ }
+ regUp.dirty = false;
+ eUp = regUp.eUp;
+ eLo = regLo.eUp;
+
+ if (eUp.Sym.Org != eLo.Sym.Org) {
+ /* Check that the edge ordering is obeyed at the Dst vertices. */
+ if (CheckForLeftSplice(tess, regUp)) {
+
+ /* If the upper or lower edge was marked fixUpperEdge, then
+ * we no longer need it (since these edges are needed only for
+ * vertices which otherwise have no right-going edges).
+ */
+ if (regLo.fixUpperEdge) {
+ DeleteRegion(tess, regLo);
+ if (!Mesh.__gl_meshDelete(eLo)) throw new RuntimeException();
+ regLo = RegionBelow(regUp);
+ eLo = regLo.eUp;
+ } else if (regUp.fixUpperEdge) {
+ DeleteRegion(tess, regUp);
+ if (!Mesh.__gl_meshDelete(eUp)) throw new RuntimeException();
+ regUp = RegionAbove(regLo);
+ eUp = regUp.eUp;
+ }
+ }
+ }
+ if (eUp.Org != eLo.Org) {
+ if (eUp.Sym.Org != eLo.Sym.Org
+ && !regUp.fixUpperEdge && !regLo.fixUpperEdge
+ && (eUp.Sym.Org == tess.event || eLo.Sym.Org == tess.event)) {
+ /* When all else fails in CheckForIntersect(), it uses tess.event
+ * as the intersection location. To make this possible, it requires
+ * that tess.event lie between the upper and lower edges, and also
+ * that neither of these is marked fixUpperEdge (since in the worst
+ * case it might splice one of these edges into tess.event, and
+ * violate the invariant that fixable edges are the only right-going
+ * edge from their associated vertex).
+ */
+ if (CheckForIntersect(tess, regUp)) {
+ /* WalkDirtyRegions() was called recursively; we're done */
+ return;
+ }
+ } else {
+ /* Even though we can't use CheckForIntersect(), the Org vertices
+ * may violate the dictionary edge ordering. Check and correct this.
+ */
+ CheckForRightSplice(tess, regUp);
+ }
+ }
+ if (eUp.Org == eLo.Org && eUp.Sym.Org == eLo.Sym.Org) {
+ /* A degenerate loop consisting of only two edges -- delete it. */
+ AddWinding(eLo, eUp);
+ DeleteRegion(tess, regUp);
+ if (!Mesh.__gl_meshDelete(eUp)) throw new RuntimeException();
+ regUp = RegionAbove(regLo);
+ }
+ }
+ }
+
+
+ static void ConnectRightVertex(GLUtessellatorImpl tess, ActiveRegion regUp,
+ GLUhalfEdge eBottomLeft)
+/*
+ * Purpose: connect a "right" vertex vEvent (one where all edges go left)
+ * to the unprocessed portion of the mesh. Since there are no right-going
+ * edges, two regions (one above vEvent and one below) are being merged
+ * into one. "regUp" is the upper of these two regions.
+ *
+ * There are two reasons for doing this (adding a right-going edge):
+ * - if the two regions being merged are "inside", we must add an edge
+ * to keep them separated (the combined region would not be monotone).
+ * - in any case, we must leave some record of vEvent in the dictionary,
+ * so that we can merge vEvent with features that we have not seen yet.
+ * For example, maybe there is a vertical edge which passes just to
+ * the right of vEvent; we would like to splice vEvent into this edge.
+ *
+ * However, we don't want to connect vEvent to just any vertex. We don''t
+ * want the new edge to cross any other edges; otherwise we will create
+ * intersection vertices even when the input data had no self-intersections.
+ * (This is a bad thing; if the user's input data has no intersections,
+ * we don't want to generate any false intersections ourselves.)
+ *
+ * Our eventual goal is to connect vEvent to the leftmost unprocessed
+ * vertex of the combined region (the union of regUp and regLo).
+ * But because of unseen vertices with all right-going edges, and also
+ * new vertices which may be created by edge intersections, we don''t
+ * know where that leftmost unprocessed vertex is. In the meantime, we
+ * connect vEvent to the closest vertex of either chain, and mark the region
+ * as "fixUpperEdge". This flag says to delete and reconnect this edge
+ * to the next processed vertex on the boundary of the combined region.
+ * Quite possibly the vertex we connected to will turn out to be the
+ * closest one, in which case we won''t need to make any changes.
+ */ {
+ GLUhalfEdge eNew;
+ GLUhalfEdge eTopLeft = eBottomLeft.Onext;
+ ActiveRegion regLo = RegionBelow(regUp);
+ GLUhalfEdge eUp = regUp.eUp;
+ GLUhalfEdge eLo = regLo.eUp;
+ boolean degenerate = false;
+
+ if (eUp.Sym.Org != eLo.Sym.Org) {
+ CheckForIntersect(tess, regUp);
+ }
+
+ /* Possible new degeneracies: upper or lower edge of regUp may pass
+ * through vEvent, or may coincide with new intersection vertex
+ */
+ if (Geom.VertEq(eUp.Org, tess.event)) {
+ if (!Mesh.__gl_meshSplice(eTopLeft.Sym.Lnext, eUp)) throw new RuntimeException();
+ regUp = TopLeftRegion(regUp);
+ if (regUp == null) throw new RuntimeException();
+ eTopLeft = RegionBelow(regUp).eUp;
+ FinishLeftRegions(tess, RegionBelow(regUp), regLo);
+ degenerate = true;
+ }
+ if (Geom.VertEq(eLo.Org, tess.event)) {
+ if (!Mesh.__gl_meshSplice(eBottomLeft, eLo.Sym.Lnext)) throw new RuntimeException();
+ eBottomLeft = FinishLeftRegions(tess, regLo, null);
+ degenerate = true;
+ }
+ if (degenerate) {
+ AddRightEdges(tess, regUp, eBottomLeft.Onext, eTopLeft, eTopLeft, true);
+ return;
+ }
+
+ /* Non-degenerate situation -- need to add a temporary, fixable edge.
+ * Connect to the closer of eLo.Org, eUp.Org.
+ */
+ if (Geom.VertLeq(eLo.Org, eUp.Org)) {
+ eNew = eLo.Sym.Lnext;
+ } else {
+ eNew = eUp;
+ }
+ eNew = Mesh.__gl_meshConnect(eBottomLeft.Onext.Sym, eNew);
+ if (eNew == null) throw new RuntimeException();
+
+ /* Prevent cleanup, otherwise eNew might disappear before we've even
+ * had a chance to mark it as a temporary edge.
+ */
+ AddRightEdges(tess, regUp, eNew, eNew.Onext, eNew.Onext, false);
+ eNew.Sym.activeRegion.fixUpperEdge = true;
+ WalkDirtyRegions(tess, regUp);
+ }
+
+/* Because vertices at exactly the same location are merged together
+ * before we process the sweep event, some degenerate cases can't occur.
+ * However if someone eventually makes the modifications required to
+ * merge features which are close together, the cases below marked
+ * TOLERANCE_NONZERO will be useful. They were debugged before the
+ * code to merge identical vertices in the main loop was added.
+ */
+ private static final boolean TOLERANCE_NONZERO = false;
+
+ static void ConnectLeftDegenerate(GLUtessellatorImpl tess,
+ ActiveRegion regUp, GLUvertex vEvent)
+/*
+ * The event vertex lies exacty on an already-processed edge or vertex.
+ * Adding the new vertex involves splicing it into the already-processed
+ * part of the mesh.
+ */ {
+ GLUhalfEdge e, eTopLeft, eTopRight, eLast;
+ ActiveRegion reg;
+
+ e = regUp.eUp;
+ if (Geom.VertEq(e.Org, vEvent)) {
+ /* e.Org is an unprocessed vertex - just combine them, and wait
+ * for e.Org to be pulled from the queue
+ */
+ assert (TOLERANCE_NONZERO);
+ SpliceMergeVertices(tess, e, vEvent.anEdge);
+ return;
+ }
+
+ if (!Geom.VertEq(e.Sym.Org, vEvent)) {
+ /* General case -- splice vEvent into edge e which passes through it */
+ if (Mesh.__gl_meshSplitEdge(e.Sym) == null) throw new RuntimeException();
+ if (regUp.fixUpperEdge) {
+ /* This edge was fixable -- delete unused portion of original edge */
+ if (!Mesh.__gl_meshDelete(e.Onext)) throw new RuntimeException();
+ regUp.fixUpperEdge = false;
+ }
+ if (!Mesh.__gl_meshSplice(vEvent.anEdge, e)) throw new RuntimeException();
+ SweepEvent(tess, vEvent); /* recurse */
+ return;
+ }
+
+ /* vEvent coincides with e.Sym.Org, which has already been processed.
+ * Splice in the additional right-going edges.
+ */
+ assert (TOLERANCE_NONZERO);
+ regUp = TopRightRegion(regUp);
+ reg = RegionBelow(regUp);
+ eTopRight = reg.eUp.Sym;
+ eTopLeft = eLast = eTopRight.Onext;
+ if (reg.fixUpperEdge) {
+ /* Here e.Sym.Org has only a single fixable edge going right.
+ * We can delete it since now we have some real right-going edges.
+ */
+ assert (eTopLeft != eTopRight); /* there are some left edges too */
+ DeleteRegion(tess, reg);
+ if (!Mesh.__gl_meshDelete(eTopRight)) throw new RuntimeException();
+ eTopRight = eTopLeft.Sym.Lnext;
+ }
+ if (!Mesh.__gl_meshSplice(vEvent.anEdge, eTopRight)) throw new RuntimeException();
+ if (!Geom.EdgeGoesLeft(eTopLeft)) {
+ /* e.Sym.Org had no left-going edges -- indicate this to AddRightEdges() */
+ eTopLeft = null;
+ }
+ AddRightEdges(tess, regUp, eTopRight.Onext, eLast, eTopLeft, true);
+ }
+
+
+ static void ConnectLeftVertex(GLUtessellatorImpl tess, GLUvertex vEvent)
+/*
+ * Purpose: connect a "left" vertex (one where both edges go right)
+ * to the processed portion of the mesh. Let R be the active region
+ * containing vEvent, and let U and L be the upper and lower edge
+ * chains of R. There are two possibilities:
+ *
+ * - the normal case: split R into two regions, by connecting vEvent to
+ * the rightmost vertex of U or L lying to the left of the sweep line
+ *
+ * - the degenerate case: if vEvent is close enough to U or L, we
+ * merge vEvent into that edge chain. The subcases are:
+ * - merging with the rightmost vertex of U or L
+ * - merging with the active edge of U or L
+ * - merging with an already-processed portion of U or L
+ */ {
+ ActiveRegion regUp, regLo, reg;
+ GLUhalfEdge eUp, eLo, eNew;
+ ActiveRegion tmp = new ActiveRegion();
+
+ /* assert ( vEvent.anEdge.Onext.Onext == vEvent.anEdge ); */
+
+ /* Get a pointer to the active region containing vEvent */
+ tmp.eUp = vEvent.anEdge.Sym;
+ /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
+ regUp = (ActiveRegion) Dict.dictKey(Dict.dictSearch(tess.dict, tmp));
+ regLo = RegionBelow(regUp);
+ eUp = regUp.eUp;
+ eLo = regLo.eUp;
+
+ /* Try merging with U or L first */
+ if (Geom.EdgeSign(eUp.Sym.Org, vEvent, eUp.Org) == 0) {
+ ConnectLeftDegenerate(tess, regUp, vEvent);
+ return;
+ }
+
+ /* Connect vEvent to rightmost processed vertex of either chain.
+ * e.Sym.Org is the vertex that we will connect to vEvent.
+ */
+ reg = Geom.VertLeq(eLo.Sym.Org, eUp.Sym.Org) ? regUp : regLo;
+
+ if (regUp.inside || reg.fixUpperEdge) {
+ if (reg == regUp) {
+ eNew = Mesh.__gl_meshConnect(vEvent.anEdge.Sym, eUp.Lnext);
+ if (eNew == null) throw new RuntimeException();
+ } else {
+ GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(eLo.Sym.Onext.Sym, vEvent.anEdge);
+ if (tempHalfEdge == null) throw new RuntimeException();
+
+ eNew = tempHalfEdge.Sym;
+ }
+ if (reg.fixUpperEdge) {
+ if (!FixUpperEdge(reg, eNew)) throw new RuntimeException();
+ } else {
+ ComputeWinding(tess, AddRegionBelow(tess, regUp, eNew));
+ }
+ SweepEvent(tess, vEvent);
+ } else {
+ /* The new vertex is in a region which does not belong to the polygon.
+ * We don''t need to connect this vertex to the rest of the mesh.
+ */
+ AddRightEdges(tess, regUp, vEvent.anEdge, vEvent.anEdge, null, true);
+ }
+ }
+
+
+ static void SweepEvent(GLUtessellatorImpl tess, GLUvertex vEvent)
+/*
+ * Does everything necessary when the sweep line crosses a vertex.
+ * Updates the mesh and the edge dictionary.
+ */ {
+ ActiveRegion regUp, reg;
+ GLUhalfEdge e, eTopLeft, eBottomLeft;
+
+ tess.event = vEvent; /* for access in EdgeLeq() */
+ DebugEvent(tess);
+
+ /* Check if this vertex is the right endpoint of an edge that is
+ * already in the dictionary. In this case we don't need to waste
+ * time searching for the location to insert new edges.
+ */
+ e = vEvent.anEdge;
+ while (e.activeRegion == null) {
+ e = e.Onext;
+ if (e == vEvent.anEdge) {
+ /* All edges go right -- not incident to any processed edges */
+ ConnectLeftVertex(tess, vEvent);
+ return;
+ }
+ }
+
+ /* Processing consists of two phases: first we "finish" all the
+ * active regions where both the upper and lower edges terminate
+ * at vEvent (ie. vEvent is closing off these regions).
+ * We mark these faces "inside" or "outside" the polygon according
+ * to their winding number, and delete the edges from the dictionary.
+ * This takes care of all the left-going edges from vEvent.
+ */
+ regUp = TopLeftRegion(e.activeRegion);
+ if (regUp == null) throw new RuntimeException();
+ reg = RegionBelow(regUp);
+ eTopLeft = reg.eUp;
+ eBottomLeft = FinishLeftRegions(tess, reg, null);
+
+ /* Next we process all the right-going edges from vEvent. This
+ * involves adding the edges to the dictionary, and creating the
+ * associated "active regions" which record information about the
+ * regions between adjacent dictionary edges.
+ */
+ if (eBottomLeft.Onext == eTopLeft) {
+ /* No right-going edges -- add a temporary "fixable" edge */
+ ConnectRightVertex(tess, regUp, eBottomLeft);
+ } else {
+ AddRightEdges(tess, regUp, eBottomLeft.Onext, eTopLeft, eTopLeft, true);
+ }
+ }
+
+
+/* Make the sentinel coordinates big enough that they will never be
+ * merged with real input features. (Even with the largest possible
+ * input contour and the maximum tolerance of 1.0, no merging will be
+ * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
+ */
+ private static final double SENTINEL_COORD = (4.0 * GLU_TESS_MAX_COORD);
+
+ static void AddSentinel(GLUtessellatorImpl tess, double t)
+/*
+ * We add two sentinel edges above and below all other edges,
+ * to avoid special cases at the top and bottom.
+ */ {
+ GLUhalfEdge e;
+ ActiveRegion reg = new ActiveRegion();
+ if (reg == null) throw new RuntimeException();
+
+ e = Mesh.__gl_meshMakeEdge(tess.mesh);
+ if (e == null) throw new RuntimeException();
+
+ e.Org.s = SENTINEL_COORD;
+ e.Org.t = t;
+ e.Sym.Org.s = -SENTINEL_COORD;
+ e.Sym.Org.t = t;
+ tess.event = e.Sym.Org; /* initialize it */
+
+ reg.eUp = e;
+ reg.windingNumber = 0;
+ reg.inside = false;
+ reg.fixUpperEdge = false;
+ reg.sentinel = true;
+ reg.dirty = false;
+ reg.nodeUp = Dict.dictInsert(tess.dict, reg); /* __gl_dictListInsertBefore */
+ if (reg.nodeUp == null) throw new RuntimeException();
+ }
+
+
+ static void InitEdgeDict(final GLUtessellatorImpl tess)
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */ {
+ /* __gl_dictListNewDict */
+ tess.dict = Dict.dictNewDict(tess, new Dict.DictLeq() {
+ public boolean leq(Object frame, Object key1, Object key2) {
+ return EdgeLeq(tess, (ActiveRegion) key1, (ActiveRegion) key2);
+ }
+ });
+ if (tess.dict == null) throw new RuntimeException();
+
+ AddSentinel(tess, -SENTINEL_COORD);
+ AddSentinel(tess, SENTINEL_COORD);
+ }
+
+
+ static void DoneEdgeDict(GLUtessellatorImpl tess) {
+ ActiveRegion reg;
+ int fixedEdges = 0;
+
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ while ((reg = (ActiveRegion) Dict.dictKey(Dict.dictMin(tess.dict))) != null) {
+ /*
+ * At the end of all processing, the dictionary should contain
+ * only the two sentinel edges, plus at most one "fixable" edge
+ * created by ConnectRightVertex().
+ */
+ if (!reg.sentinel) {
+ assert (reg.fixUpperEdge);
+ assert (++fixedEdges == 1);
+ }
+ assert (reg.windingNumber == 0);
+ DeleteRegion(tess, reg);
+/* __gl_meshDelete( reg.eUp );*/
+ }
+ Dict.dictDeleteDict(tess.dict); /* __gl_dictListDeleteDict */
+ }
+
+
+ static void RemoveDegenerateEdges(GLUtessellatorImpl tess)
+/*
+ * Remove zero-length edges, and contours with fewer than 3 vertices.
+ */ {
+ GLUhalfEdge e, eNext, eLnext;
+ GLUhalfEdge eHead = tess.mesh.eHead;
+
+ /*LINTED*/
+ for (e = eHead.next; e != eHead; e = eNext) {
+ eNext = e.next;
+ eLnext = e.Lnext;
+
+ if (Geom.VertEq(e.Org, e.Sym.Org) && e.Lnext.Lnext != e) {
+ /* Zero-length edge, contour has at least 3 edges */
+
+ SpliceMergeVertices(tess, eLnext, e); /* deletes e.Org */
+ if (!Mesh.__gl_meshDelete(e)) throw new RuntimeException(); /* e is a self-loop */
+ e = eLnext;
+ eLnext = e.Lnext;
+ }
+ if (eLnext.Lnext == e) {
+ /* Degenerate contour (one or two edges) */
+
+ if (eLnext != e) {
+ if (eLnext == eNext || eLnext == eNext.Sym) {
+ eNext = eNext.next;
+ }
+ if (!Mesh.__gl_meshDelete(eLnext)) throw new RuntimeException();
+ }
+ if (e == eNext || e == eNext.Sym) {
+ eNext = eNext.next;
+ }
+ if (!Mesh.__gl_meshDelete(e)) throw new RuntimeException();
+ }
+ }
+ }
+
+ static boolean InitPriorityQ(GLUtessellatorImpl tess)
+/*
+ * Insert all vertices into the priority queue which determines the
+ * order in which vertices cross the sweep line.
+ */ {
+ PriorityQ pq;
+ GLUvertex v, vHead;
+
+ /* __gl_pqSortNewPriorityQ */
+ pq = tess.pq = PriorityQ.pqNewPriorityQ(new PriorityQ.Leq() {
+ public boolean leq(Object key1, Object key2) {
+ return Geom.VertLeq(((GLUvertex) key1), (GLUvertex) key2);
+ }
+ });
+ if (pq == null) return false;
+
+ vHead = tess.mesh.vHead;
+ for (v = vHead.next; v != vHead; v = v.next) {
+ v.pqHandle = pq.pqInsert(v); /* __gl_pqSortInsert */
+ if (v.pqHandle == Long.MAX_VALUE) break;
+ }
+ if (v != vHead || !pq.pqInit()) { /* __gl_pqSortInit */
+ tess.pq.pqDeletePriorityQ(); /* __gl_pqSortDeletePriorityQ */
+ tess.pq = null;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ static void DonePriorityQ(GLUtessellatorImpl tess) {
+ tess.pq.pqDeletePriorityQ(); /* __gl_pqSortDeletePriorityQ */
+ }
+
+
+ static boolean RemoveDegenerateFaces(GLUmesh mesh)
+/*
+ * Delete any degenerate faces with only two edges. WalkDirtyRegions()
+ * will catch almost all of these, but it won't catch degenerate faces
+ * produced by splice operations on already-processed edges.
+ * The two places this can happen are in FinishLeftRegions(), when
+ * we splice in a "temporary" edge produced by ConnectRightVertex(),
+ * and in CheckForLeftSplice(), where we splice already-processed
+ * edges to ensure that our dictionary invariants are not violated
+ * by numerical errors.
+ *
+ * In both these cases it is *very* dangerous to delete the offending
+ * edge at the time, since one of the routines further up the stack
+ * will sometimes be keeping a pointer to that edge.
+ */ {
+ GLUface f, fNext;
+ GLUhalfEdge e;
+
+ /*LINTED*/
+ for (f = mesh.fHead.next; f != mesh.fHead; f = fNext) {
+ fNext = f.next;
+ e = f.anEdge;
+ assert (e.Lnext != e);
+
+ if (e.Lnext.Lnext == e) {
+ /* A face with only two edges */
+ AddWinding(e.Onext, e);
+ if (!Mesh.__gl_meshDelete(e)) return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean __gl_computeInterior(GLUtessellatorImpl tess)
+/*
+ * __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess.windingRule.
+ * Each interior region is guaranteed be monotone.
+ */ {
+ GLUvertex v, vNext;
+
+ tess.fatalError = false;
+
+ /* Each vertex defines an event for our sweep line. Start by inserting
+ * all the vertices in a priority queue. Events are processed in
+ * lexicographic order, ie.
+ *
+ * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
+ */
+ RemoveDegenerateEdges(tess);
+ if (!InitPriorityQ(tess)) return false; /* if error */
+ InitEdgeDict(tess);
+
+ /* __gl_pqSortExtractMin */
+ while ((v = (GLUvertex) tess.pq.pqExtractMin()) != null) {
+ for (; ;) {
+ vNext = (GLUvertex) tess.pq.pqMinimum(); /* __gl_pqSortMinimum */
+ if (vNext == null || !Geom.VertEq(vNext, v)) break;
+
+ /* Merge together all vertices at exactly the same location.
+ * This is more efficient than processing them one at a time,
+ * simplifies the code (see ConnectLeftDegenerate), and is also
+ * important for correct handling of certain degenerate cases.
+ * For example, suppose there are two identical edges A and B
+ * that belong to different contours (so without this code they would
+ * be processed by separate sweep events). Suppose another edge C
+ * crosses A and B from above. When A is processed, we split it
+ * at its intersection point with C. However this also splits C,
+ * so when we insert B we may compute a slightly different
+ * intersection point. This might leave two edges with a small
+ * gap between them. This kind of error is especially obvious
+ * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
+ */
+ vNext = (GLUvertex) tess.pq.pqExtractMin(); /* __gl_pqSortExtractMin*/
+ SpliceMergeVertices(tess, v.anEdge, vNext.anEdge);
+ }
+ SweepEvent(tess, v);
+ }
+
+ /* Set tess.event for debugging purposes */
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ tess.event = ((ActiveRegion) Dict.dictKey(Dict.dictMin(tess.dict))).eUp.Org;
+ DebugEvent(tess);
+ DoneEdgeDict(tess);
+ DonePriorityQ(tess);
+
+ if (!RemoveDegenerateFaces(tess.mesh)) return false;
+ Mesh.__gl_meshCheckMesh(tess.mesh);
+
+ return true;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/TessMono.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/TessMono.java
new file mode 100644
index 0000000..ed3a23a
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/TessMono.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class TessMono {
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * The basic idea is explained in Preparata and Shamos (which I don''t
+ * have handy right now), although their implementation is more
+ * complicated than this one. The are two edge chains, an upper chain
+ * and a lower chain. We process all vertices from both chains in order,
+ * from right to left.
+ *
+ * The algorithm ensures that the following invariant holds after each
+ * vertex is processed: the untessellated region consists of two
+ * chains, where one chain (say the upper) is a single edge, and
+ * the other chain is concave. The left vertex of the single edge
+ * is always to the left of all vertices in the concave chain.
+ *
+ * Each step consists of adding the rightmost unprocessed vertex to one
+ * of the two chains, and forming a fan of triangles from the rightmost
+ * of two chain endpoints. Determining whether we can add each triangle
+ * to the fan is a simple orientation test. By making the fan as large
+ * as possible, we restore the invariant (check it yourself).
+ */
+ static boolean __gl_meshTessellateMonoRegion(GLUface face) {
+ GLUhalfEdge up, lo;
+
+ /* All edges are oriented CCW around the boundary of the region.
+ * First, find the half-edge whose origin vertex is rightmost.
+ * Since the sweep goes from left to right, face->anEdge should
+ * be close to the edge we want.
+ */
+ up = face.anEdge;
+ assert (up.Lnext != up && up.Lnext.Lnext != up);
+
+ for (; Geom.VertLeq(up.Sym.Org, up.Org); up = up.Onext.Sym)
+ ;
+ for (; Geom.VertLeq(up.Org, up.Sym.Org); up = up.Lnext)
+ ;
+ lo = up.Onext.Sym;
+
+ while (up.Lnext != lo) {
+ if (Geom.VertLeq(up.Sym.Org, lo.Org)) {
+ /* up.Sym.Org is on the left. It is safe to form triangles from lo.Org.
+ * The EdgeGoesLeft test guarantees progress even when some triangles
+ * are CW, given that the upper and lower chains are truly monotone.
+ */
+ while (lo.Lnext != up && (Geom.EdgeGoesLeft(lo.Lnext)
+ || Geom.EdgeSign(lo.Org, lo.Sym.Org, lo.Lnext.Sym.Org) <= 0)) {
+ GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(lo.Lnext, lo);
+ if (tempHalfEdge == null) return false;
+ lo = tempHalfEdge.Sym;
+ }
+ lo = lo.Onext.Sym;
+ } else {
+ /* lo.Org is on the left. We can make CCW triangles from up.Sym.Org. */
+ while (lo.Lnext != up && (Geom.EdgeGoesRight(up.Onext.Sym)
+ || Geom.EdgeSign(up.Sym.Org, up.Org, up.Onext.Sym.Org) >= 0)) {
+ GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(up, up.Onext.Sym);
+ if (tempHalfEdge == null) return false;
+ up = tempHalfEdge.Sym;
+ }
+ up = up.Lnext;
+ }
+ }
+
+ /* Now lo.Org == up.Sym.Org == the leftmost vertex. The remaining region
+ * can be tessellated in a fan from this leftmost vertex.
+ */
+ assert (lo.Lnext != up);
+ while (lo.Lnext.Lnext != up) {
+ GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(lo.Lnext, lo);
+ if (tempHalfEdge == null) return false;
+ lo = tempHalfEdge.Sym;
+ }
+
+ return true;
+ }
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ */
+ public static boolean __gl_meshTessellateInterior(GLUmesh mesh) {
+ GLUface f, next;
+
+ /*LINTED*/
+ for (f = mesh.fHead.next; f != mesh.fHead; f = next) {
+ /* Make sure we don''t try to tessellate the new triangles. */
+ next = f.next;
+ if (f.inside) {
+ if (!__gl_meshTessellateMonoRegion(f)) return false;
+ }
+ }
+
+ return true;
+ }
+
+
+/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ */
+ public static void __gl_meshDiscardExterior(GLUmesh mesh) {
+ GLUface f, next;
+
+ /*LINTED*/
+ for (f = mesh.fHead.next; f != mesh.fHead; f = next) {
+ /* Since f will be destroyed, save its next pointer. */
+ next = f.next;
+ if (!f.inside) {
+ Mesh.__gl_meshZapFace(f);
+ }
+ }
+ }
+
+// private static final int MARKED_FOR_DELETION = 0x7fffffff;
+
+/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+ public static boolean __gl_meshSetWindingNumber(GLUmesh mesh, int value, boolean keepOnlyBoundary) {
+ GLUhalfEdge e, eNext;
+
+ for (e = mesh.eHead.next; e != mesh.eHead; e = eNext) {
+ eNext = e.next;
+ if (e.Sym.Lface.inside != e.Lface.inside) {
+
+ /* This is a boundary edge (one side is interior, one is exterior). */
+ e.winding = (e.Lface.inside) ? value : -value;
+ } else {
+
+ /* Both regions are interior, or both are exterior. */
+ if (!keepOnlyBoundary) {
+ e.winding = 0;
+ } else {
+ if (!Mesh.__gl_meshDelete(e)) return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/glu/tessellation/TessState.java b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/TessState.java
new file mode 100644
index 0000000..263b843
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/glu/tessellation/TessState.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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.
+ */
+
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package de.verschwiegener.lwjgl3.util.glu.tessellation;
+
+class TessState {
+ public static final int T_DORMANT = 0;
+ public static final int T_IN_POLYGON = 1;
+ public static final int T_IN_CONTOUR = 2;
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Matrix.java b/src/de/verschwiegener/lwjgl3/util/vector/Matrix.java
new file mode 100644
index 0000000..4a38fc6
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Matrix.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+/**
+ *
+ * Base class for matrices. When a matrix is constructed it will be the identity
+ * matrix unless otherwise stated.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+public abstract class Matrix implements Serializable {
+
+ /**
+ * Constructor for Matrix.
+ */
+ protected Matrix() {
+ super();
+ }
+
+ /**
+ * Set this matrix to be the identity matrix.
+ * @return this
+ */
+ public abstract Matrix setIdentity();
+
+
+ /**
+ * Invert this matrix
+ * @return this
+ */
+ public abstract Matrix invert();
+
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in column major
+ * (OpenGL) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public abstract Matrix load(FloatBuffer buf);
+
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in row major
+ * (mathematical) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public abstract Matrix loadTranspose(FloatBuffer buf);
+
+
+ /**
+ * Negate this matrix
+ * @return this
+ */
+ public abstract Matrix negate();
+
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in column
+ * major (openGL) order.
+ * @param buf The buffer to store this matrix in
+ * @return this
+ */
+ public abstract Matrix store(FloatBuffer buf);
+
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in row
+ * major (maths) order.
+ * @param buf The buffer to store this matrix in
+ * @return this
+ */
+ public abstract Matrix storeTranspose(FloatBuffer buf);
+
+
+ /**
+ * Transpose this matrix
+ * @return this
+ */
+ public abstract Matrix transpose();
+
+
+ /**
+ * Set this matrix to 0.
+ * @return this
+ */
+ public abstract Matrix setZero();
+
+
+ /**
+ * @return the determinant of the matrix
+ */
+ public abstract float determinant();
+
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Matrix2f.java b/src/de/verschwiegener/lwjgl3/util/vector/Matrix2f.java
new file mode 100644
index 0000000..183e675
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Matrix2f.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+/**
+ *
+ * Holds a 2x2 matrix
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+
+public class Matrix2f extends Matrix implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public float m00, m01, m10, m11;
+
+ /**
+ * Constructor for Matrix2f. The matrix is initialised to the identity.
+ */
+ public Matrix2f() {
+ setIdentity();
+ }
+
+ /**
+ * Constructor
+ */
+ public Matrix2f(Matrix2f src) {
+ load(src);
+ }
+
+ /**
+ * Load from another matrix
+ * @param src The source matrix
+ * @return this
+ */
+ public Matrix2f load(Matrix2f src) {
+ return load(src, this);
+ }
+
+ /**
+ * Copy the source matrix to the destination matrix.
+ * @param src The source matrix
+ * @param dest The destination matrix, or null if a new one should be created.
+ * @return The copied matrix
+ */
+ public static Matrix2f load(Matrix2f src, Matrix2f dest) {
+ if (dest == null)
+ dest = new Matrix2f();
+
+ dest.m00 = src.m00;
+ dest.m01 = src.m01;
+ dest.m10 = src.m10;
+ dest.m11 = src.m11;
+
+ return dest;
+ }
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in column major
+ * (OpenGL) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public Matrix load(FloatBuffer buf) {
+
+ m00 = buf.get();
+ m01 = buf.get();
+ m10 = buf.get();
+ m11 = buf.get();
+
+ return this;
+ }
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in row major
+ * (mathematical) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public Matrix loadTranspose(FloatBuffer buf) {
+
+ m00 = buf.get();
+ m10 = buf.get();
+ m01 = buf.get();
+ m11 = buf.get();
+
+ return this;
+ }
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in column
+ * major (openGL) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix store(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m01);
+ buf.put(m10);
+ buf.put(m11);
+ return this;
+ }
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in row
+ * major (maths) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix storeTranspose(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m10);
+ buf.put(m01);
+ buf.put(m11);
+ return this;
+ }
+
+
+
+ /**
+ * Add two matrices together and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix2f add(Matrix2f left, Matrix2f right, Matrix2f dest) {
+ if (dest == null)
+ dest = new Matrix2f();
+
+ dest.m00 = left.m00 + right.m00;
+ dest.m01 = left.m01 + right.m01;
+ dest.m10 = left.m10 + right.m10;
+ dest.m11 = left.m11 + right.m11;
+
+ return dest;
+ }
+
+ /**
+ * Subtract the right matrix from the left and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix2f sub(Matrix2f left, Matrix2f right, Matrix2f dest) {
+ if (dest == null)
+ dest = new Matrix2f();
+
+ dest.m00 = left.m00 - right.m00;
+ dest.m01 = left.m01 - right.m01;
+ dest.m10 = left.m10 - right.m10;
+ dest.m11 = left.m11 - right.m11;
+
+ return dest;
+ }
+
+ /**
+ * Multiply the right matrix by the left and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix2f mul(Matrix2f left, Matrix2f right, Matrix2f dest) {
+ if (dest == null)
+ dest = new Matrix2f();
+
+ float m00 = left.m00 * right.m00 + left.m10 * right.m01;
+ float m01 = left.m01 * right.m00 + left.m11 * right.m01;
+ float m10 = left.m00 * right.m10 + left.m10 * right.m11;
+ float m11 = left.m01 * right.m10 + left.m11 * right.m11;
+
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m10 = m10;
+ dest.m11 = m11;
+
+ return dest;
+ }
+
+ /**
+ * Transform a Vector by a matrix and return the result in a destination
+ * vector.
+ * @param left The left matrix
+ * @param right The right vector
+ * @param dest The destination vector, or null if a new one is to be created
+ * @return the destination vector
+ */
+ public static Vector2f transform(Matrix2f left, Vector2f right, Vector2f dest) {
+ if (dest == null)
+ dest = new Vector2f();
+
+ float x = left.m00 * right.x + left.m10 * right.y;
+ float y = left.m01 * right.x + left.m11 * right.y;
+
+ dest.x = x;
+ dest.y = y;
+
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix
+ * @return this
+ */
+ public Matrix transpose() {
+ return transpose(this);
+ }
+
+ /**
+ * Transpose this matrix and place the result in another matrix.
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the transposed matrix
+ */
+ public Matrix2f transpose(Matrix2f dest) {
+ return transpose(this, dest);
+ }
+
+ /**
+ * Transpose the source matrix and place the result in the destination matrix.
+ * @param src The source matrix or null if a new matrix is to be created
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the transposed matrix
+ */
+ public static Matrix2f transpose(Matrix2f src, Matrix2f dest) {
+ if (dest == null)
+ dest = new Matrix2f();
+
+ float m01 = src.m10;
+ float m10 = src.m01;
+
+ dest.m01 = m01;
+ dest.m10 = m10;
+
+ return dest;
+ }
+
+ /**
+ * Invert this matrix
+ * @return this if successful, null otherwise
+ */
+ public Matrix invert() {
+ return invert(this, this);
+ }
+
+ /**
+ * Invert the source matrix and place the result in the destination matrix.
+ * @param src The source matrix to be inverted
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return The inverted matrix, or null if source can't be reverted.
+ */
+ public static Matrix2f invert(Matrix2f src, Matrix2f dest) {
+ /*
+ *inv(A) = 1/det(A) * adj(A);
+ */
+
+ float determinant = src.determinant();
+ if (determinant != 0) {
+ if (dest == null)
+ dest = new Matrix2f();
+ float determinant_inv = 1f/determinant;
+ float t00 = src.m11*determinant_inv;
+ float t01 = -src.m01*determinant_inv;
+ float t11 = src.m00*determinant_inv;
+ float t10 = -src.m10*determinant_inv;
+
+ dest.m00 = t00;
+ dest.m01 = t01;
+ dest.m10 = t10;
+ dest.m11 = t11;
+ return dest;
+ } else
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this matrix
+ */
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append(m00).append(' ').append(m10).append(' ').append('\n');
+ buf.append(m01).append(' ').append(m11).append(' ').append('\n');
+ return buf.toString();
+ }
+
+ /**
+ * Negate this matrix
+ * @return this
+ */
+ public Matrix negate() {
+ return negate(this);
+ }
+
+ /**
+ * Negate this matrix and stash the result in another matrix.
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return the negated matrix
+ */
+ public Matrix2f negate(Matrix2f dest) {
+ return negate(this, dest);
+ }
+
+ /**
+ * Negate the source matrix and stash the result in the destination matrix.
+ * @param src The source matrix to be negated
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return the negated matrix
+ */
+ public static Matrix2f negate(Matrix2f src, Matrix2f dest) {
+ if (dest == null)
+ dest = new Matrix2f();
+
+ dest.m00 = -src.m00;
+ dest.m01 = -src.m01;
+ dest.m10 = -src.m10;
+ dest.m11 = -src.m11;
+
+ return dest;
+ }
+
+ /**
+ * Set this matrix to be the identity matrix.
+ * @return this
+ */
+ public Matrix setIdentity() {
+ return setIdentity(this);
+ }
+
+ /**
+ * Set the source matrix to be the identity matrix.
+ * @param src The matrix to set to the identity.
+ * @return The source matrix
+ */
+ public static Matrix2f setIdentity(Matrix2f src) {
+ src.m00 = 1.0f;
+ src.m01 = 0.0f;
+ src.m10 = 0.0f;
+ src.m11 = 1.0f;
+ return src;
+ }
+
+ /**
+ * Set this matrix to 0.
+ * @return this
+ */
+ public Matrix setZero() {
+ return setZero(this);
+ }
+
+ public static Matrix2f setZero(Matrix2f src) {
+ src.m00 = 0.0f;
+ src.m01 = 0.0f;
+ src.m10 = 0.0f;
+ src.m11 = 0.0f;
+ return src;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Matrix#determinant()
+ */
+ public float determinant() {
+ return m00 * m11 - m01*m10;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Matrix3f.java b/src/de/verschwiegener/lwjgl3/util/vector/Matrix3f.java
new file mode 100644
index 0000000..69fb37f
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Matrix3f.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+/**
+ *
+ * Holds a 3x3 matrix.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+
+public class Matrix3f extends Matrix implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public float m00,
+ m01,
+ m02,
+ m10,
+ m11,
+ m12,
+ m20,
+ m21,
+ m22;
+
+ /**
+ * Constructor for Matrix3f. Matrix is initialised to the identity.
+ */
+ public Matrix3f() {
+ super();
+ setIdentity();
+ }
+
+ /**
+ * Load from another matrix
+ * @param src The source matrix
+ * @return this
+ */
+ public Matrix3f load(Matrix3f src) {
+ return load(src, this);
+ }
+
+ /**
+ * Copy source matrix to destination matrix
+ * @param src The source matrix
+ * @param dest The destination matrix, or null of a new matrix is to be created
+ * @return The copied matrix
+ */
+ public static Matrix3f load(Matrix3f src, Matrix3f dest) {
+ if (dest == null)
+ dest = new Matrix3f();
+
+ dest.m00 = src.m00;
+ dest.m10 = src.m10;
+ dest.m20 = src.m20;
+ dest.m01 = src.m01;
+ dest.m11 = src.m11;
+ dest.m21 = src.m21;
+ dest.m02 = src.m02;
+ dest.m12 = src.m12;
+ dest.m22 = src.m22;
+
+ return dest;
+ }
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in column major
+ * (OpenGL) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public Matrix load(FloatBuffer buf) {
+
+ m00 = buf.get();
+ m01 = buf.get();
+ m02 = buf.get();
+ m10 = buf.get();
+ m11 = buf.get();
+ m12 = buf.get();
+ m20 = buf.get();
+ m21 = buf.get();
+ m22 = buf.get();
+
+ return this;
+ }
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in row major
+ * (maths) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public Matrix loadTranspose(FloatBuffer buf) {
+
+ m00 = buf.get();
+ m10 = buf.get();
+ m20 = buf.get();
+ m01 = buf.get();
+ m11 = buf.get();
+ m21 = buf.get();
+ m02 = buf.get();
+ m12 = buf.get();
+ m22 = buf.get();
+
+ return this;
+ }
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in column
+ * major (openGL) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix store(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m01);
+ buf.put(m02);
+ buf.put(m10);
+ buf.put(m11);
+ buf.put(m12);
+ buf.put(m20);
+ buf.put(m21);
+ buf.put(m22);
+ return this;
+ }
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in row
+ * major (maths) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix storeTranspose(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m10);
+ buf.put(m20);
+ buf.put(m01);
+ buf.put(m11);
+ buf.put(m21);
+ buf.put(m02);
+ buf.put(m12);
+ buf.put(m22);
+ return this;
+ }
+
+ /**
+ * Add two matrices together and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix3f add(Matrix3f left, Matrix3f right, Matrix3f dest) {
+ if (dest == null)
+ dest = new Matrix3f();
+
+ dest.m00 = left.m00 + right.m00;
+ dest.m01 = left.m01 + right.m01;
+ dest.m02 = left.m02 + right.m02;
+ dest.m10 = left.m10 + right.m10;
+ dest.m11 = left.m11 + right.m11;
+ dest.m12 = left.m12 + right.m12;
+ dest.m20 = left.m20 + right.m20;
+ dest.m21 = left.m21 + right.m21;
+ dest.m22 = left.m22 + right.m22;
+
+ return dest;
+ }
+
+ /**
+ * Subtract the right matrix from the left and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix3f sub(Matrix3f left, Matrix3f right, Matrix3f dest) {
+ if (dest == null)
+ dest = new Matrix3f();
+
+ dest.m00 = left.m00 - right.m00;
+ dest.m01 = left.m01 - right.m01;
+ dest.m02 = left.m02 - right.m02;
+ dest.m10 = left.m10 - right.m10;
+ dest.m11 = left.m11 - right.m11;
+ dest.m12 = left.m12 - right.m12;
+ dest.m20 = left.m20 - right.m20;
+ dest.m21 = left.m21 - right.m21;
+ dest.m22 = left.m22 - right.m22;
+
+ return dest;
+ }
+
+ /**
+ * Multiply the right matrix by the left and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix3f mul(Matrix3f left, Matrix3f right, Matrix3f dest) {
+ if (dest == null)
+ dest = new Matrix3f();
+
+ float m00 =
+ left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02;
+ float m01 =
+ left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02;
+ float m02 =
+ left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02;
+ float m10 =
+ left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12;
+ float m11 =
+ left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12;
+ float m12 =
+ left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12;
+ float m20 =
+ left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22;
+ float m21 =
+ left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22;
+ float m22 =
+ left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22;
+
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+
+ return dest;
+ }
+
+ /**
+ * Transform a Vector by a matrix and return the result in a destination
+ * vector.
+ * @param left The left matrix
+ * @param right The right vector
+ * @param dest The destination vector, or null if a new one is to be created
+ * @return the destination vector
+ */
+ public static Vector3f transform(Matrix3f left, Vector3f right, Vector3f dest) {
+ if (dest == null)
+ dest = new Vector3f();
+
+ float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z;
+ float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z;
+ float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z;
+
+ dest.x = x;
+ dest.y = y;
+ dest.z = z;
+
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix
+ * @return this
+ */
+ public Matrix transpose() {
+ return transpose(this, this);
+ }
+
+ /**
+ * Transpose this matrix and place the result in another matrix
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the transposed matrix
+ */
+ public Matrix3f transpose(Matrix3f dest) {
+ return transpose(this, dest);
+ }
+
+ /**
+ * Transpose the source matrix and place the result into the destination matrix
+ * @param src The source matrix to be transposed
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the transposed matrix
+ */
+ public static Matrix3f transpose(Matrix3f src, Matrix3f dest) {
+ if (dest == null)
+ dest = new Matrix3f();
+ float m00 = src.m00;
+ float m01 = src.m10;
+ float m02 = src.m20;
+ float m10 = src.m01;
+ float m11 = src.m11;
+ float m12 = src.m21;
+ float m20 = src.m02;
+ float m21 = src.m12;
+ float m22 = src.m22;
+
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ return dest;
+ }
+
+ /**
+ * @return the determinant of the matrix
+ */
+ public float determinant() {
+ float f =
+ m00 * (m11 * m22 - m12 * m21)
+ + m01 * (m12 * m20 - m10 * m22)
+ + m02 * (m10 * m21 - m11 * m20);
+ return f;
+ }
+
+ /**
+ * Returns a string representation of this matrix
+ */
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append(m00).append(' ').append(m10).append(' ').append(m20).append(' ').append('\n');
+ buf.append(m01).append(' ').append(m11).append(' ').append(m21).append(' ').append('\n');
+ buf.append(m02).append(' ').append(m12).append(' ').append(m22).append(' ').append('\n');
+ return buf.toString();
+ }
+
+ /**
+ * Invert this matrix
+ * @return this if successful, null otherwise
+ */
+ public Matrix invert() {
+ return invert(this, this);
+ }
+
+ /**
+ * Invert the source matrix and put the result into the destination matrix
+ * @param src The source matrix to be inverted
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return The inverted matrix if successful, null otherwise
+ */
+ public static Matrix3f invert(Matrix3f src, Matrix3f dest) {
+ float determinant = src.determinant();
+
+ if (determinant != 0) {
+ if (dest == null)
+ dest = new Matrix3f();
+ /* do it the ordinary way
+ *
+ * inv(A) = 1/det(A) * adj(T), where adj(T) = transpose(Conjugate Matrix)
+ *
+ * m00 m01 m02
+ * m10 m11 m12
+ * m20 m21 m22
+ */
+ float determinant_inv = 1f/determinant;
+
+ // get the conjugate matrix
+ float t00 = src.m11 * src.m22 - src.m12* src.m21;
+ float t01 = - src.m10 * src.m22 + src.m12 * src.m20;
+ float t02 = src.m10 * src.m21 - src.m11 * src.m20;
+ float t10 = - src.m01 * src.m22 + src.m02 * src.m21;
+ float t11 = src.m00 * src.m22 - src.m02 * src.m20;
+ float t12 = - src.m00 * src.m21 + src.m01 * src.m20;
+ float t20 = src.m01 * src.m12 - src.m02 * src.m11;
+ float t21 = -src.m00 * src.m12 + src.m02 * src.m10;
+ float t22 = src.m00 * src.m11 - src.m01 * src.m10;
+
+ dest.m00 = t00*determinant_inv;
+ dest.m11 = t11*determinant_inv;
+ dest.m22 = t22*determinant_inv;
+ dest.m01 = t10*determinant_inv;
+ dest.m10 = t01*determinant_inv;
+ dest.m20 = t02*determinant_inv;
+ dest.m02 = t20*determinant_inv;
+ dest.m12 = t21*determinant_inv;
+ dest.m21 = t12*determinant_inv;
+ return dest;
+ } else
+ return null;
+ }
+
+
+ /**
+ * Negate this matrix
+ * @return this
+ */
+ public Matrix negate() {
+ return negate(this);
+ }
+
+ /**
+ * Negate this matrix and place the result in a destination matrix.
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return the negated matrix
+ */
+ public Matrix3f negate(Matrix3f dest) {
+ return negate(this, dest);
+ }
+
+ /**
+ * Negate the source matrix and place the result in the destination matrix.
+ * @param src The source matrix
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return the negated matrix
+ */
+ public static Matrix3f negate(Matrix3f src, Matrix3f dest) {
+ if (dest == null)
+ dest = new Matrix3f();
+
+ dest.m00 = -src.m00;
+ dest.m01 = -src.m02;
+ dest.m02 = -src.m01;
+ dest.m10 = -src.m10;
+ dest.m11 = -src.m12;
+ dest.m12 = -src.m11;
+ dest.m20 = -src.m20;
+ dest.m21 = -src.m22;
+ dest.m22 = -src.m21;
+ return dest;
+ }
+
+ /**
+ * Set this matrix to be the identity matrix.
+ * @return this
+ */
+ public Matrix setIdentity() {
+ return setIdentity(this);
+ }
+
+ /**
+ * Set the matrix to be the identity matrix.
+ * @param m The matrix to be set to the identity
+ * @return m
+ */
+ public static Matrix3f setIdentity(Matrix3f m) {
+ m.m00 = 1.0f;
+ m.m01 = 0.0f;
+ m.m02 = 0.0f;
+ m.m10 = 0.0f;
+ m.m11 = 1.0f;
+ m.m12 = 0.0f;
+ m.m20 = 0.0f;
+ m.m21 = 0.0f;
+ m.m22 = 1.0f;
+ return m;
+ }
+
+ /**
+ * Set this matrix to 0.
+ * @return this
+ */
+ public Matrix setZero() {
+ return setZero(this);
+ }
+
+ /**
+ * Set the matrix matrix to 0.
+ * @param m The matrix to be set to 0
+ * @return m
+ */
+ public static Matrix3f setZero(Matrix3f m) {
+ m.m00 = 0.0f;
+ m.m01 = 0.0f;
+ m.m02 = 0.0f;
+ m.m10 = 0.0f;
+ m.m11 = 0.0f;
+ m.m12 = 0.0f;
+ m.m20 = 0.0f;
+ m.m21 = 0.0f;
+ m.m22 = 0.0f;
+ return m;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Matrix4f.java b/src/de/verschwiegener/lwjgl3/util/vector/Matrix4f.java
new file mode 100644
index 0000000..dde362a
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Matrix4f.java
@@ -0,0 +1,849 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+/**
+ * Holds a 4x4 float matrix.
+ *
+ * @author foo
+ */
+public class Matrix4f extends Matrix implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public float m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33;
+
+ /**
+ * Construct a new matrix, initialized to the identity.
+ */
+ public Matrix4f() {
+ super();
+ setIdentity();
+ }
+
+ public Matrix4f(final Matrix4f src) {
+ super();
+ load(src);
+ }
+
+ /**
+ * Returns a string representation of this matrix
+ */
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append(m00).append(' ').append(m10).append(' ').append(m20).append(' ').append(m30).append('\n');
+ buf.append(m01).append(' ').append(m11).append(' ').append(m21).append(' ').append(m31).append('\n');
+ buf.append(m02).append(' ').append(m12).append(' ').append(m22).append(' ').append(m32).append('\n');
+ buf.append(m03).append(' ').append(m13).append(' ').append(m23).append(' ').append(m33).append('\n');
+ return buf.toString();
+ }
+
+ /**
+ * Set this matrix to be the identity matrix.
+ * @return this
+ */
+ public Matrix setIdentity() {
+ return setIdentity(this);
+ }
+
+ /**
+ * Set the given matrix to be the identity matrix.
+ * @param m The matrix to set to the identity
+ * @return m
+ */
+ public static Matrix4f setIdentity(Matrix4f m) {
+ m.m00 = 1.0f;
+ m.m01 = 0.0f;
+ m.m02 = 0.0f;
+ m.m03 = 0.0f;
+ m.m10 = 0.0f;
+ m.m11 = 1.0f;
+ m.m12 = 0.0f;
+ m.m13 = 0.0f;
+ m.m20 = 0.0f;
+ m.m21 = 0.0f;
+ m.m22 = 1.0f;
+ m.m23 = 0.0f;
+ m.m30 = 0.0f;
+ m.m31 = 0.0f;
+ m.m32 = 0.0f;
+ m.m33 = 1.0f;
+
+ return m;
+ }
+
+ /**
+ * Set this matrix to 0.
+ * @return this
+ */
+ public Matrix setZero() {
+ return setZero(this);
+ }
+
+ /**
+ * Set the given matrix to 0.
+ * @param m The matrix to set to 0
+ * @return m
+ */
+ public static Matrix4f setZero(Matrix4f m) {
+ m.m00 = 0.0f;
+ m.m01 = 0.0f;
+ m.m02 = 0.0f;
+ m.m03 = 0.0f;
+ m.m10 = 0.0f;
+ m.m11 = 0.0f;
+ m.m12 = 0.0f;
+ m.m13 = 0.0f;
+ m.m20 = 0.0f;
+ m.m21 = 0.0f;
+ m.m22 = 0.0f;
+ m.m23 = 0.0f;
+ m.m30 = 0.0f;
+ m.m31 = 0.0f;
+ m.m32 = 0.0f;
+ m.m33 = 0.0f;
+
+ return m;
+ }
+
+ /**
+ * Load from another matrix4f
+ * @param src The source matrix
+ * @return this
+ */
+ public Matrix4f load(Matrix4f src) {
+ return load(src, this);
+ }
+
+ /**
+ * Copy the source matrix to the destination matrix
+ * @param src The source matrix
+ * @param dest The destination matrix, or null of a new one is to be created
+ * @return The copied matrix
+ */
+ public static Matrix4f load(Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+ dest.m00 = src.m00;
+ dest.m01 = src.m01;
+ dest.m02 = src.m02;
+ dest.m03 = src.m03;
+ dest.m10 = src.m10;
+ dest.m11 = src.m11;
+ dest.m12 = src.m12;
+ dest.m13 = src.m13;
+ dest.m20 = src.m20;
+ dest.m21 = src.m21;
+ dest.m22 = src.m22;
+ dest.m23 = src.m23;
+ dest.m30 = src.m30;
+ dest.m31 = src.m31;
+ dest.m32 = src.m32;
+ dest.m33 = src.m33;
+
+ return dest;
+ }
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in column major
+ * (OpenGL) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public Matrix load(FloatBuffer buf) {
+
+ m00 = buf.get();
+ m01 = buf.get();
+ m02 = buf.get();
+ m03 = buf.get();
+ m10 = buf.get();
+ m11 = buf.get();
+ m12 = buf.get();
+ m13 = buf.get();
+ m20 = buf.get();
+ m21 = buf.get();
+ m22 = buf.get();
+ m23 = buf.get();
+ m30 = buf.get();
+ m31 = buf.get();
+ m32 = buf.get();
+ m33 = buf.get();
+
+ return this;
+ }
+
+ /**
+ * Load from a float buffer. The buffer stores the matrix in row major
+ * (maths) order.
+ *
+ * @param buf A float buffer to read from
+ * @return this
+ */
+ public Matrix loadTranspose(FloatBuffer buf) {
+
+ m00 = buf.get();
+ m10 = buf.get();
+ m20 = buf.get();
+ m30 = buf.get();
+ m01 = buf.get();
+ m11 = buf.get();
+ m21 = buf.get();
+ m31 = buf.get();
+ m02 = buf.get();
+ m12 = buf.get();
+ m22 = buf.get();
+ m32 = buf.get();
+ m03 = buf.get();
+ m13 = buf.get();
+ m23 = buf.get();
+ m33 = buf.get();
+
+ return this;
+ }
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in column
+ * major (openGL) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix store(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m01);
+ buf.put(m02);
+ buf.put(m03);
+ buf.put(m10);
+ buf.put(m11);
+ buf.put(m12);
+ buf.put(m13);
+ buf.put(m20);
+ buf.put(m21);
+ buf.put(m22);
+ buf.put(m23);
+ buf.put(m30);
+ buf.put(m31);
+ buf.put(m32);
+ buf.put(m33);
+ return this;
+ }
+
+ /**
+ * Store this matrix in a float buffer. The matrix is stored in row
+ * major (maths) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix storeTranspose(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m10);
+ buf.put(m20);
+ buf.put(m30);
+ buf.put(m01);
+ buf.put(m11);
+ buf.put(m21);
+ buf.put(m31);
+ buf.put(m02);
+ buf.put(m12);
+ buf.put(m22);
+ buf.put(m32);
+ buf.put(m03);
+ buf.put(m13);
+ buf.put(m23);
+ buf.put(m33);
+ return this;
+ }
+
+ /**
+ * Store the rotation portion of this matrix in a float buffer. The matrix is stored in column
+ * major (openGL) order.
+ * @param buf The buffer to store this matrix in
+ */
+ public Matrix store3f(FloatBuffer buf) {
+ buf.put(m00);
+ buf.put(m01);
+ buf.put(m02);
+ buf.put(m10);
+ buf.put(m11);
+ buf.put(m12);
+ buf.put(m20);
+ buf.put(m21);
+ buf.put(m22);
+ return this;
+ }
+
+ /**
+ * Add two matrices together and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix4f add(Matrix4f left, Matrix4f right, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+
+ dest.m00 = left.m00 + right.m00;
+ dest.m01 = left.m01 + right.m01;
+ dest.m02 = left.m02 + right.m02;
+ dest.m03 = left.m03 + right.m03;
+ dest.m10 = left.m10 + right.m10;
+ dest.m11 = left.m11 + right.m11;
+ dest.m12 = left.m12 + right.m12;
+ dest.m13 = left.m13 + right.m13;
+ dest.m20 = left.m20 + right.m20;
+ dest.m21 = left.m21 + right.m21;
+ dest.m22 = left.m22 + right.m22;
+ dest.m23 = left.m23 + right.m23;
+ dest.m30 = left.m30 + right.m30;
+ dest.m31 = left.m31 + right.m31;
+ dest.m32 = left.m32 + right.m32;
+ dest.m33 = left.m33 + right.m33;
+
+ return dest;
+ }
+
+ /**
+ * Subtract the right matrix from the left and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix4f sub(Matrix4f left, Matrix4f right, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+
+ dest.m00 = left.m00 - right.m00;
+ dest.m01 = left.m01 - right.m01;
+ dest.m02 = left.m02 - right.m02;
+ dest.m03 = left.m03 - right.m03;
+ dest.m10 = left.m10 - right.m10;
+ dest.m11 = left.m11 - right.m11;
+ dest.m12 = left.m12 - right.m12;
+ dest.m13 = left.m13 - right.m13;
+ dest.m20 = left.m20 - right.m20;
+ dest.m21 = left.m21 - right.m21;
+ dest.m22 = left.m22 - right.m22;
+ dest.m23 = left.m23 - right.m23;
+ dest.m30 = left.m30 - right.m30;
+ dest.m31 = left.m31 - right.m31;
+ dest.m32 = left.m32 - right.m32;
+ dest.m33 = left.m33 - right.m33;
+
+ return dest;
+ }
+
+ /**
+ * Multiply the right matrix by the left and place the result in a third matrix.
+ * @param left The left source matrix
+ * @param right The right source matrix
+ * @param dest The destination matrix, or null if a new one is to be created
+ * @return the destination matrix
+ */
+ public static Matrix4f mul(Matrix4f left, Matrix4f right, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+
+ float m00 = left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02 + left.m30 * right.m03;
+ float m01 = left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02 + left.m31 * right.m03;
+ float m02 = left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02 + left.m32 * right.m03;
+ float m03 = left.m03 * right.m00 + left.m13 * right.m01 + left.m23 * right.m02 + left.m33 * right.m03;
+ float m10 = left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12 + left.m30 * right.m13;
+ float m11 = left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12 + left.m31 * right.m13;
+ float m12 = left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12 + left.m32 * right.m13;
+ float m13 = left.m03 * right.m10 + left.m13 * right.m11 + left.m23 * right.m12 + left.m33 * right.m13;
+ float m20 = left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22 + left.m30 * right.m23;
+ float m21 = left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22 + left.m31 * right.m23;
+ float m22 = left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22 + left.m32 * right.m23;
+ float m23 = left.m03 * right.m20 + left.m13 * right.m21 + left.m23 * right.m22 + left.m33 * right.m23;
+ float m30 = left.m00 * right.m30 + left.m10 * right.m31 + left.m20 * right.m32 + left.m30 * right.m33;
+ float m31 = left.m01 * right.m30 + left.m11 * right.m31 + left.m21 * right.m32 + left.m31 * right.m33;
+ float m32 = left.m02 * right.m30 + left.m12 * right.m31 + left.m22 * right.m32 + left.m32 * right.m33;
+ float m33 = left.m03 * right.m30 + left.m13 * right.m31 + left.m23 * right.m32 + left.m33 * right.m33;
+
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m03 = m03;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m13 = m13;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m23 = m23;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.m33 = m33;
+
+ return dest;
+ }
+
+ /**
+ * Transform a Vector by a matrix and return the result in a destination
+ * vector.
+ * @param left The left matrix
+ * @param right The right vector
+ * @param dest The destination vector, or null if a new one is to be created
+ * @return the destination vector
+ */
+ public static Vector4f transform(Matrix4f left, Vector4f right, Vector4f dest) {
+ if (dest == null)
+ dest = new Vector4f();
+
+ float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z + left.m30 * right.w;
+ float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z + left.m31 * right.w;
+ float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z + left.m32 * right.w;
+ float w = left.m03 * right.x + left.m13 * right.y + left.m23 * right.z + left.m33 * right.w;
+
+ dest.x = x;
+ dest.y = y;
+ dest.z = z;
+ dest.w = w;
+
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix
+ * @return this
+ */
+ public Matrix transpose() {
+ return transpose(this);
+ }
+
+ /**
+ * Translate this matrix
+ * @param vec The vector to translate by
+ * @return this
+ */
+ public Matrix4f translate(Vector2f vec) {
+ return translate(vec, this);
+ }
+
+ /**
+ * Translate this matrix
+ * @param vec The vector to translate by
+ * @return this
+ */
+ public Matrix4f translate(Vector3f vec) {
+ return translate(vec, this);
+ }
+
+ /**
+ * Scales this matrix
+ * @param vec The vector to scale by
+ * @return this
+ */
+ public Matrix4f scale(Vector3f vec) {
+ return scale(vec, this, this);
+ }
+
+ /**
+ * Scales the source matrix and put the result in the destination matrix
+ * @param vec The vector to scale by
+ * @param src The source matrix
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return The scaled matrix
+ */
+ public static Matrix4f scale(Vector3f vec, Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+ dest.m00 = src.m00 * vec.x;
+ dest.m01 = src.m01 * vec.x;
+ dest.m02 = src.m02 * vec.x;
+ dest.m03 = src.m03 * vec.x;
+ dest.m10 = src.m10 * vec.y;
+ dest.m11 = src.m11 * vec.y;
+ dest.m12 = src.m12 * vec.y;
+ dest.m13 = src.m13 * vec.y;
+ dest.m20 = src.m20 * vec.z;
+ dest.m21 = src.m21 * vec.z;
+ dest.m22 = src.m22 * vec.z;
+ dest.m23 = src.m23 * vec.z;
+ return dest;
+ }
+
+ /**
+ * Rotates the matrix around the given axis the specified angle
+ * @param angle the angle, in radians.
+ * @param axis The vector representing the rotation axis. Must be normalized.
+ * @return this
+ */
+ public Matrix4f rotate(float angle, Vector3f axis) {
+ return rotate(angle, axis, this);
+ }
+
+ /**
+ * Rotates the matrix around the given axis the specified angle
+ * @param angle the angle, in radians.
+ * @param axis The vector representing the rotation axis. Must be normalized.
+ * @param dest The matrix to put the result, or null if a new matrix is to be created
+ * @return The rotated matrix
+ */
+ public Matrix4f rotate(float angle, Vector3f axis, Matrix4f dest) {
+ return rotate(angle, axis, this, dest);
+ }
+
+ /**
+ * Rotates the source matrix around the given axis the specified angle and
+ * put the result in the destination matrix.
+ * @param angle the angle, in radians.
+ * @param axis The vector representing the rotation axis. Must be normalized.
+ * @param src The matrix to rotate
+ * @param dest The matrix to put the result, or null if a new matrix is to be created
+ * @return The rotated matrix
+ */
+ public static Matrix4f rotate(float angle, Vector3f axis, Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+ float c = (float) Math.cos(angle);
+ float s = (float) Math.sin(angle);
+ float oneminusc = 1.0f - c;
+ float xy = axis.x*axis.y;
+ float yz = axis.y*axis.z;
+ float xz = axis.x*axis.z;
+ float xs = axis.x*s;
+ float ys = axis.y*s;
+ float zs = axis.z*s;
+
+ float f00 = axis.x*axis.x*oneminusc+c;
+ float f01 = xy*oneminusc+zs;
+ float f02 = xz*oneminusc-ys;
+ // n[3] not used
+ float f10 = xy*oneminusc-zs;
+ float f11 = axis.y*axis.y*oneminusc+c;
+ float f12 = yz*oneminusc+xs;
+ // n[7] not used
+ float f20 = xz*oneminusc+ys;
+ float f21 = yz*oneminusc-xs;
+ float f22 = axis.z*axis.z*oneminusc+c;
+
+ float t00 = src.m00 * f00 + src.m10 * f01 + src.m20 * f02;
+ float t01 = src.m01 * f00 + src.m11 * f01 + src.m21 * f02;
+ float t02 = src.m02 * f00 + src.m12 * f01 + src.m22 * f02;
+ float t03 = src.m03 * f00 + src.m13 * f01 + src.m23 * f02;
+ float t10 = src.m00 * f10 + src.m10 * f11 + src.m20 * f12;
+ float t11 = src.m01 * f10 + src.m11 * f11 + src.m21 * f12;
+ float t12 = src.m02 * f10 + src.m12 * f11 + src.m22 * f12;
+ float t13 = src.m03 * f10 + src.m13 * f11 + src.m23 * f12;
+ dest.m20 = src.m00 * f20 + src.m10 * f21 + src.m20 * f22;
+ dest.m21 = src.m01 * f20 + src.m11 * f21 + src.m21 * f22;
+ dest.m22 = src.m02 * f20 + src.m12 * f21 + src.m22 * f22;
+ dest.m23 = src.m03 * f20 + src.m13 * f21 + src.m23 * f22;
+ dest.m00 = t00;
+ dest.m01 = t01;
+ dest.m02 = t02;
+ dest.m03 = t03;
+ dest.m10 = t10;
+ dest.m11 = t11;
+ dest.m12 = t12;
+ dest.m13 = t13;
+ return dest;
+ }
+
+ /**
+ * Translate this matrix and stash the result in another matrix
+ * @param vec The vector to translate by
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the translated matrix
+ */
+ public Matrix4f translate(Vector3f vec, Matrix4f dest) {
+ return translate(vec, this, dest);
+ }
+
+ /**
+ * Translate the source matrix and stash the result in the destination matrix
+ * @param vec The vector to translate by
+ * @param src The source matrix
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return The translated matrix
+ */
+ public static Matrix4f translate(Vector3f vec, Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+
+ dest.m30 += src.m00 * vec.x + src.m10 * vec.y + src.m20 * vec.z;
+ dest.m31 += src.m01 * vec.x + src.m11 * vec.y + src.m21 * vec.z;
+ dest.m32 += src.m02 * vec.x + src.m12 * vec.y + src.m22 * vec.z;
+ dest.m33 += src.m03 * vec.x + src.m13 * vec.y + src.m23 * vec.z;
+
+ return dest;
+ }
+
+ /**
+ * Translate this matrix and stash the result in another matrix
+ * @param vec The vector to translate by
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the translated matrix
+ */
+ public Matrix4f translate(Vector2f vec, Matrix4f dest) {
+ return translate(vec, this, dest);
+ }
+
+ /**
+ * Translate the source matrix and stash the result in the destination matrix
+ * @param vec The vector to translate by
+ * @param src The source matrix
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return The translated matrix
+ */
+ public static Matrix4f translate(Vector2f vec, Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+
+ dest.m30 += src.m00 * vec.x + src.m10 * vec.y;
+ dest.m31 += src.m01 * vec.x + src.m11 * vec.y;
+ dest.m32 += src.m02 * vec.x + src.m12 * vec.y;
+ dest.m33 += src.m03 * vec.x + src.m13 * vec.y;
+
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix and place the result in another matrix
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the transposed matrix
+ */
+ public Matrix4f transpose(Matrix4f dest) {
+ return transpose(this, dest);
+ }
+
+ /**
+ * Transpose the source matrix and place the result in the destination matrix
+ * @param src The source matrix
+ * @param dest The destination matrix or null if a new matrix is to be created
+ * @return the transposed matrix
+ */
+ public static Matrix4f transpose(Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+ float m00 = src.m00;
+ float m01 = src.m10;
+ float m02 = src.m20;
+ float m03 = src.m30;
+ float m10 = src.m01;
+ float m11 = src.m11;
+ float m12 = src.m21;
+ float m13 = src.m31;
+ float m20 = src.m02;
+ float m21 = src.m12;
+ float m22 = src.m22;
+ float m23 = src.m32;
+ float m30 = src.m03;
+ float m31 = src.m13;
+ float m32 = src.m23;
+ float m33 = src.m33;
+
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m03 = m03;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m13 = m13;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m23 = m23;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.m33 = m33;
+
+ return dest;
+ }
+
+ /**
+ * @return the determinant of the matrix
+ */
+ public float determinant() {
+ float f =
+ m00
+ * ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
+ - m13 * m22 * m31
+ - m11 * m23 * m32
+ - m12 * m21 * m33);
+ f -= m01
+ * ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32)
+ - m13 * m22 * m30
+ - m10 * m23 * m32
+ - m12 * m20 * m33);
+ f += m02
+ * ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31)
+ - m13 * m21 * m30
+ - m10 * m23 * m31
+ - m11 * m20 * m33);
+ f -= m03
+ * ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31)
+ - m12 * m21 * m30
+ - m10 * m22 * m31
+ - m11 * m20 * m32);
+ return f;
+ }
+
+ /**
+ * Calculate the determinant of a 3x3 matrix
+ * @return result
+ */
+
+ private static float determinant3x3(float t00, float t01, float t02,
+ float t10, float t11, float t12,
+ float t20, float t21, float t22)
+ {
+ return t00 * (t11 * t22 - t12 * t21)
+ + t01 * (t12 * t20 - t10 * t22)
+ + t02 * (t10 * t21 - t11 * t20);
+ }
+
+ /**
+ * Invert this matrix
+ * @return this if successful, null otherwise
+ */
+ public Matrix invert() {
+ return invert(this, this);
+ }
+
+ /**
+ * Invert the source matrix and put the result in the destination
+ * @param src The source matrix
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return The inverted matrix if successful, null otherwise
+ */
+ public static Matrix4f invert(Matrix4f src, Matrix4f dest) {
+ float determinant = src.determinant();
+
+ if (determinant != 0) {
+ /*
+ * m00 m01 m02 m03
+ * m10 m11 m12 m13
+ * m20 m21 m22 m23
+ * m30 m31 m32 m33
+ */
+ if (dest == null)
+ dest = new Matrix4f();
+ float determinant_inv = 1f/determinant;
+
+ // first row
+ float t00 = determinant3x3(src.m11, src.m12, src.m13, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33);
+ float t01 = -determinant3x3(src.m10, src.m12, src.m13, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33);
+ float t02 = determinant3x3(src.m10, src.m11, src.m13, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33);
+ float t03 = -determinant3x3(src.m10, src.m11, src.m12, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32);
+ // second row
+ float t10 = -determinant3x3(src.m01, src.m02, src.m03, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33);
+ float t11 = determinant3x3(src.m00, src.m02, src.m03, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33);
+ float t12 = -determinant3x3(src.m00, src.m01, src.m03, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33);
+ float t13 = determinant3x3(src.m00, src.m01, src.m02, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32);
+ // third row
+ float t20 = determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m31, src.m32, src.m33);
+ float t21 = -determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m30, src.m32, src.m33);
+ float t22 = determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m30, src.m31, src.m33);
+ float t23 = -determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m30, src.m31, src.m32);
+ // fourth row
+ float t30 = -determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m21, src.m22, src.m23);
+ float t31 = determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m20, src.m22, src.m23);
+ float t32 = -determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m20, src.m21, src.m23);
+ float t33 = determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m20, src.m21, src.m22);
+
+ // transpose and divide by the determinant
+ dest.m00 = t00*determinant_inv;
+ dest.m11 = t11*determinant_inv;
+ dest.m22 = t22*determinant_inv;
+ dest.m33 = t33*determinant_inv;
+ dest.m01 = t10*determinant_inv;
+ dest.m10 = t01*determinant_inv;
+ dest.m20 = t02*determinant_inv;
+ dest.m02 = t20*determinant_inv;
+ dest.m12 = t21*determinant_inv;
+ dest.m21 = t12*determinant_inv;
+ dest.m03 = t30*determinant_inv;
+ dest.m30 = t03*determinant_inv;
+ dest.m13 = t31*determinant_inv;
+ dest.m31 = t13*determinant_inv;
+ dest.m32 = t23*determinant_inv;
+ dest.m23 = t32*determinant_inv;
+ return dest;
+ } else
+ return null;
+ }
+
+ /**
+ * Negate this matrix
+ * @return this
+ */
+ public Matrix negate() {
+ return negate(this);
+ }
+
+ /**
+ * Negate this matrix and place the result in a destination matrix.
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return the negated matrix
+ */
+ public Matrix4f negate(Matrix4f dest) {
+ return negate(this, dest);
+ }
+
+ /**
+ * Negate this matrix and place the result in a destination matrix.
+ * @param src The source matrix
+ * @param dest The destination matrix, or null if a new matrix is to be created
+ * @return The negated matrix
+ */
+ public static Matrix4f negate(Matrix4f src, Matrix4f dest) {
+ if (dest == null)
+ dest = new Matrix4f();
+
+ dest.m00 = -src.m00;
+ dest.m01 = -src.m01;
+ dest.m02 = -src.m02;
+ dest.m03 = -src.m03;
+ dest.m10 = -src.m10;
+ dest.m11 = -src.m11;
+ dest.m12 = -src.m12;
+ dest.m13 = -src.m13;
+ dest.m20 = -src.m20;
+ dest.m21 = -src.m21;
+ dest.m22 = -src.m22;
+ dest.m23 = -src.m23;
+ dest.m30 = -src.m30;
+ dest.m31 = -src.m31;
+ dest.m32 = -src.m32;
+ dest.m33 = -src.m33;
+
+ return dest;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Quaternion.java b/src/de/verschwiegener/lwjgl3/util/vector/Quaternion.java
new file mode 100644
index 0000000..277136a
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Quaternion.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ *
+ * Quaternions for LWJGL!
+ *
+ * @author fbi
+ * @version $Revision$
+ * $Id$
+ */
+
+import java.nio.FloatBuffer;
+
+public class Quaternion extends Vector implements ReadableVector4f {
+ private static final long serialVersionUID = 1L;
+
+ public float x, y, z, w;
+
+ /**
+ * C'tor. The quaternion will be initialized to the identity.
+ */
+ public Quaternion() {
+ super();
+ setIdentity();
+ }
+
+ /**
+ * C'tor
+ *
+ * @param src
+ */
+ public Quaternion(ReadableVector4f src) {
+ set(src);
+ }
+
+ /**
+ * C'tor
+ *
+ */
+ public Quaternion(float x, float y, float z, float w) {
+ set(x, y, z, w);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
+ */
+ public void set(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float)
+ */
+ public void set(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.lwjgl.util.vector.WritableVector4f#set(float, float, float,
+ * float)
+ */
+ public void set(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Load from another Vector4f
+ *
+ * @param src
+ * The source vector
+ * @return this
+ */
+ public Quaternion set(ReadableVector4f src) {
+ x = src.getX();
+ y = src.getY();
+ z = src.getZ();
+ w = src.getW();
+ return this;
+ }
+
+ /**
+ * Set this quaternion to the multiplication identity.
+ * @return this
+ */
+ public Quaternion setIdentity() {
+ return setIdentity(this);
+ }
+
+ /**
+ * Set the given quaternion to the multiplication identity.
+ * @param q The quaternion
+ * @return q
+ */
+ public static Quaternion setIdentity(Quaternion q) {
+ q.x = 0;
+ q.y = 0;
+ q.z = 0;
+ q.w = 1;
+ return q;
+ }
+
+ /**
+ * @return the length squared of the quaternion
+ */
+ public float lengthSquared() {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ /**
+ * Normalise the source quaternion and place the result in another quaternion.
+ *
+ * @param src
+ * The source quaternion
+ * @param dest
+ * The destination quaternion, or null if a new quaternion is to be
+ * created
+ * @return The normalised quaternion
+ */
+ public static Quaternion normalise(Quaternion src, Quaternion dest) {
+ float inv_l = 1f/src.length();
+
+ if (dest == null)
+ dest = new Quaternion();
+
+ dest.set(src.x * inv_l, src.y * inv_l, src.z * inv_l, src.w * inv_l);
+
+ return dest;
+ }
+
+ /**
+ * Normalise this quaternion and place the result in another quaternion.
+ *
+ * @param dest
+ * The destination quaternion, or null if a new quaternion is to be
+ * created
+ * @return the normalised quaternion
+ */
+ public Quaternion normalise(Quaternion dest) {
+ return normalise(this, dest);
+ }
+
+ /**
+ * The dot product of two quaternions
+ *
+ * @param left
+ * The LHS quat
+ * @param right
+ * The RHS quat
+ * @return left dot right
+ */
+ public static float dot(Quaternion left, Quaternion right) {
+ return left.x * right.x + left.y * right.y + left.z * right.z + left.w
+ * right.w;
+ }
+
+ /**
+ * Calculate the conjugate of this quaternion and put it into the given one
+ *
+ * @param dest
+ * The quaternion which should be set to the conjugate of this
+ * quaternion
+ */
+ public Quaternion negate(Quaternion dest) {
+ return negate(this, dest);
+ }
+
+ /**
+ * Calculate the conjugate of this quaternion and put it into the given one
+ *
+ * @param src
+ * The source quaternion
+ * @param dest
+ * The quaternion which should be set to the conjugate of this
+ * quaternion
+ */
+ public static Quaternion negate(Quaternion src, Quaternion dest) {
+ if (dest == null)
+ dest = new Quaternion();
+
+ dest.x = -src.x;
+ dest.y = -src.y;
+ dest.z = -src.z;
+ dest.w = src.w;
+
+ return dest;
+ }
+
+ /**
+ * Calculate the conjugate of this quaternion
+ */
+ public Vector negate() {
+ return negate(this, this);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.Vector#load(java.nio.FloatBuffer)
+ */
+ public Vector load(FloatBuffer buf) {
+ x = buf.get();
+ y = buf.get();
+ z = buf.get();
+ w = buf.get();
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.lwjgl.vector.Vector#scale(float)
+ */
+ public Vector scale(float scale) {
+ return scale(scale, this, this);
+ }
+
+ /**
+ * Scale the source quaternion by scale and put the result in the destination
+ * @param scale The amount to scale by
+ * @param src The source quaternion
+ * @param dest The destination quaternion, or null if a new quaternion is to be created
+ * @return The scaled quaternion
+ */
+ public static Quaternion scale(float scale, Quaternion src, Quaternion dest) {
+ if (dest == null)
+ dest = new Quaternion();
+ dest.x = src.x * scale;
+ dest.y = src.y * scale;
+ dest.z = src.z * scale;
+ dest.w = src.w * scale;
+ return dest;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.ReadableVector#store(java.nio.FloatBuffer)
+ */
+ public Vector store(FloatBuffer buf) {
+ buf.put(x);
+ buf.put(y);
+ buf.put(z);
+ buf.put(w);
+
+ return this;
+ }
+
+ /**
+ * @return x
+ */
+ public final float getX() {
+ return x;
+ }
+
+ /**
+ * @return y
+ */
+ public final float getY() {
+ return y;
+ }
+
+ /**
+ * Set X
+ *
+ * @param x
+ */
+ public final void setX(float x) {
+ this.x = x;
+ }
+
+ /**
+ * Set Y
+ *
+ * @param y
+ */
+ public final void setY(float y) {
+ this.y = y;
+ }
+
+ /**
+ * Set Z
+ *
+ * @param z
+ */
+ public void setZ(float z) {
+ this.z = z;
+ }
+
+ /*
+ * (Overrides)
+ *
+ * @see org.lwjgl.vector.ReadableVector3f#getZ()
+ */
+ public float getZ() {
+ return z;
+ }
+
+ /**
+ * Set W
+ *
+ * @param w
+ */
+ public void setW(float w) {
+ this.w = w;
+ }
+
+ /*
+ * (Overrides)
+ *
+ * @see org.lwjgl.vector.ReadableVector3f#getW()
+ */
+ public float getW() {
+ return w;
+ }
+
+ public String toString() {
+ return "Quaternion: " + x + " " + y + " " + z + " " + w;
+ }
+
+ /**
+ * Sets the value of this quaternion to the quaternion product of
+ * quaternions left and right (this = left * right). Note that this is safe
+ * for aliasing (e.g. this can be left or right).
+ *
+ * @param left
+ * the first quaternion
+ * @param right
+ * the second quaternion
+ */
+ public static Quaternion mul(Quaternion left, Quaternion right,
+ Quaternion dest) {
+ if (dest == null)
+ dest = new Quaternion();
+ dest.set(left.x * right.w + left.w * right.x + left.y * right.z
+ - left.z * right.y, left.y * right.w + left.w * right.y
+ + left.z * right.x - left.x * right.z, left.z * right.w
+ + left.w * right.z + left.x * right.y - left.y * right.x,
+ left.w * right.w - left.x * right.x - left.y * right.y
+ - left.z * right.z);
+ return dest;
+ }
+
+ /**
+ *
+ * Multiplies quaternion left by the inverse of quaternion right and places
+ * the value into this quaternion. The value of both argument quaternions is
+ * preservered (this = left * right^-1).
+ *
+ * @param left
+ * the left quaternion
+ * @param right
+ * the right quaternion
+ */
+ public static Quaternion mulInverse(Quaternion left, Quaternion right,
+ Quaternion dest) {
+ float n = right.lengthSquared();
+ // zero-div may occur.
+ n = (n == 0.0 ? n : 1 / n);
+ // store on stack once for aliasing-safty
+ if (dest == null)
+ dest = new Quaternion();
+ dest
+ .set((left.x * right.w - left.w * right.x - left.y
+ * right.z + left.z * right.y)
+ * n, (left.y * right.w - left.w * right.y - left.z
+ * right.x + left.x * right.z)
+ * n, (left.z * right.w - left.w * right.z - left.x
+ * right.y + left.y * right.x)
+ * n, (left.w * right.w + left.x * right.x + left.y
+ * right.y + left.z * right.z)
+ * n);
+
+ return dest;
+ }
+
+ /**
+ * Sets the value of this quaternion to the equivalent rotation of the
+ * Axis-Angle argument.
+ *
+ * @param a1
+ * the axis-angle: (x,y,z) is the axis and w is the angle
+ */
+ public final void setFromAxisAngle(Vector4f a1) {
+ x = a1.x;
+ y = a1.y;
+ z = a1.z;
+ float n = (float) Math.sqrt(x * x + y * y + z * z);
+ // zero-div may occur.
+ float s = (float) (Math.sin(0.5 * a1.w) / n);
+ x *= s;
+ y *= s;
+ z *= s;
+ w = (float) Math.cos(0.5 * a1.w);
+ }
+
+ /**
+ * Sets the value of this quaternion using the rotational component of the
+ * passed matrix.
+ *
+ * @param m
+ * The matrix
+ * @return this
+ */
+ public final Quaternion setFromMatrix(Matrix4f m) {
+ return setFromMatrix(m, this);
+ }
+
+ /**
+ * Sets the value of the source quaternion using the rotational component of the
+ * passed matrix.
+ *
+ * @param m
+ * The source matrix
+ * @param q
+ * The destination quaternion, or null if a new quaternion is to be created
+ * @return q
+ */
+ public static Quaternion setFromMatrix(Matrix4f m, Quaternion q) {
+ return q.setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20,
+ m.m21, m.m22);
+ }
+
+ /**
+ * Sets the value of this quaternion using the rotational component of the
+ * passed matrix.
+ *
+ * @param m
+ * The source matrix
+ */
+ public final Quaternion setFromMatrix(Matrix3f m) {
+ return setFromMatrix(m, this);
+ }
+
+ /**
+ * Sets the value of the source quaternion using the rotational component of the
+ * passed matrix.
+ *
+ * @param m
+ * The source matrix
+ * @param q
+ * The destination quaternion, or null if a new quaternion is to be created
+ * @return q
+ */
+ public static Quaternion setFromMatrix(Matrix3f m, Quaternion q) {
+ return q.setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20,
+ m.m21, m.m22);
+ }
+
+ /**
+ * Private method to perform the matrix-to-quaternion conversion
+ */
+ private Quaternion setFromMat(float m00, float m01, float m02, float m10,
+ float m11, float m12, float m20, float m21, float m22) {
+
+ float s;
+ float tr = m00 + m11 + m22;
+ if (tr >= 0.0) {
+ s = (float) Math.sqrt(tr + 1.0);
+ w = s * 0.5f;
+ s = 0.5f / s;
+ x = (m21 - m12) * s;
+ y = (m02 - m20) * s;
+ z = (m10 - m01) * s;
+ } else {
+ float max = Math.max(Math.max(m00, m11), m22);
+ if (max == m00) {
+ s = (float) Math.sqrt(m00 - (m11 + m22) + 1.0);
+ x = s * 0.5f;
+ s = 0.5f / s;
+ y = (m01 + m10) * s;
+ z = (m20 + m02) * s;
+ w = (m21 - m12) * s;
+ } else if (max == m11) {
+ s = (float) Math.sqrt(m11 - (m22 + m00) + 1.0);
+ y = s * 0.5f;
+ s = 0.5f / s;
+ z = (m12 + m21) * s;
+ x = (m01 + m10) * s;
+ w = (m02 - m20) * s;
+ } else {
+ s = (float) Math.sqrt(m22 - (m00 + m11) + 1.0);
+ z = s * 0.5f;
+ s = 0.5f / s;
+ x = (m20 + m02) * s;
+ y = (m12 + m21) * s;
+ w = (m10 - m01) * s;
+ }
+ }
+ return this;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector.java b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector.java
new file mode 100644
index 0000000..b5a24e0
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.nio.FloatBuffer;
+
+/**
+ * @author foo
+ */
+public interface ReadableVector {
+ /**
+ * @return the length of the vector
+ */
+ float length();
+ /**
+ * @return the length squared of the vector
+ */
+ float lengthSquared();
+ /**
+ * Store this vector in a FloatBuffer
+ * @param buf The buffer to store it in, at the current position
+ * @return this
+ */
+ Vector store(FloatBuffer buf);
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector2f.java b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector2f.java
new file mode 100644
index 0000000..a414c30
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector2f.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ * @author foo
+ */
+public interface ReadableVector2f extends ReadableVector {
+ /**
+ * @return x
+ */
+ float getX();
+ /**
+ * @return y
+ */
+ float getY();
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector3f.java b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector3f.java
new file mode 100644
index 0000000..25b2766
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector3f.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ * @author foo
+ */
+public interface ReadableVector3f extends ReadableVector2f {
+ /**
+ * @return z
+ */
+ float getZ();
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector4f.java b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector4f.java
new file mode 100644
index 0000000..48dd23b
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/ReadableVector4f.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ * @author foo
+ */
+public interface ReadableVector4f extends ReadableVector3f {
+
+ /**
+ * @return w
+ */
+ float getW();
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Vector.java b/src/de/verschwiegener/lwjgl3/util/vector/Vector.java
new file mode 100644
index 0000000..4808289
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Vector.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+/**
+ *
+ * Base class for vectors.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+public abstract class Vector implements Serializable, ReadableVector {
+
+ /**
+ * Constructor for Vector.
+ */
+ protected Vector() {
+ super();
+ }
+
+ /**
+ * @return the length of the vector
+ */
+ public final float length() {
+ return (float) Math.sqrt(lengthSquared());
+ }
+
+
+ /**
+ * @return the length squared of the vector
+ */
+ public abstract float lengthSquared();
+
+ /**
+ * Load this vector from a FloatBuffer
+ * @param buf The buffer to load it from, at the current position
+ * @return this
+ */
+ public abstract Vector load(FloatBuffer buf);
+
+ /**
+ * Negate a vector
+ * @return this
+ */
+ public abstract Vector negate();
+
+
+ /**
+ * Normalise this vector
+ * @return this
+ */
+ public final Vector normalise() {
+ float len = length();
+ if (len != 0.0f) {
+ float l = 1.0f / len;
+ return scale(l);
+ } else
+ throw new IllegalStateException("Zero length vector");
+ }
+
+
+ /**
+ * Store this vector in a FloatBuffer
+ * @param buf The buffer to store it in, at the current position
+ * @return this
+ */
+ public abstract Vector store(FloatBuffer buf);
+
+
+ /**
+ * Scale this vector
+ * @param scale The scale factor
+ * @return this
+ */
+ public abstract Vector scale(float scale);
+
+
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Vector2f.java b/src/de/verschwiegener/lwjgl3/util/vector/Vector2f.java
new file mode 100644
index 0000000..1b22c67
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Vector2f.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+
+/**
+ *
+ * Holds a 2-tuple vector.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+
+public class Vector2f extends Vector implements Serializable, ReadableVector2f, WritableVector2f {
+
+ private static final long serialVersionUID = 1L;
+
+ public float x, y;
+
+ /**
+ * Constructor for Vector2f.
+ */
+ public Vector2f() {
+ super();
+ }
+
+ /**
+ * Constructor.
+ */
+ public Vector2f(ReadableVector2f src) {
+ set(src);
+ }
+
+ /**
+ * Constructor.
+ */
+ public Vector2f(float x, float y) {
+ set(x, y);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
+ */
+ public void set(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Load from another Vector2f
+ * @param src The source vector
+ * @return this
+ */
+ public Vector2f set(ReadableVector2f src) {
+ x = src.getX();
+ y = src.getY();
+ return this;
+ }
+
+ /**
+ * @return the length squared of the vector
+ */
+ public float lengthSquared() {
+ return x * x + y * y;
+ }
+
+ /**
+ * Translate a vector
+ * @param x The translation in x
+ * @param y the translation in y
+ * @return this
+ */
+ public Vector2f translate(float x, float y) {
+ this.x += x;
+ this.y += y;
+ return this;
+ }
+
+ /**
+ * Negate a vector
+ * @return this
+ */
+ public Vector negate() {
+ x = -x;
+ y = -y;
+ return this;
+ }
+
+ /**
+ * Negate a vector and place the result in a destination vector.
+ * @param dest The destination vector or null if a new vector is to be created
+ * @return the negated vector
+ */
+ public Vector2f negate(Vector2f dest) {
+ if (dest == null)
+ dest = new Vector2f();
+ dest.x = -x;
+ dest.y = -y;
+ return dest;
+ }
+
+
+ /**
+ * Normalise this vector and place the result in another vector.
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return the normalised vector
+ */
+ public Vector2f normalise(Vector2f dest) {
+ float l = length();
+
+ if (dest == null)
+ dest = new Vector2f(x / l, y / l);
+ else
+ dest.set(x / l, y / l);
+
+ return dest;
+ }
+
+ /**
+ * The dot product of two vectors is calculated as
+ * v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @return left dot right
+ */
+ public static float dot(Vector2f left, Vector2f right) {
+ return left.x * right.x + left.y * right.y;
+ }
+
+
+
+ /**
+ * Calculate the angle between two vectors, in radians
+ * @param a A vector
+ * @param b The other vector
+ * @return the angle between the two vectors, in radians
+ */
+ public static float angle(Vector2f a, Vector2f b) {
+ float dls = dot(a, b) / (a.length() * b.length());
+ if (dls < -1f)
+ dls = -1f;
+ else if (dls > 1.0f)
+ dls = 1.0f;
+ return (float)Math.acos(dls);
+ }
+
+ /**
+ * Add a vector to another vector and place the result in a destination
+ * vector.
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return the sum of left and right in dest
+ */
+ public static Vector2f add(Vector2f left, Vector2f right, Vector2f dest) {
+ if (dest == null)
+ return new Vector2f(left.x + right.x, left.y + right.y);
+ else {
+ dest.set(left.x + right.x, left.y + right.y);
+ return dest;
+ }
+ }
+
+ /**
+ * Subtract a vector from another vector and place the result in a destination
+ * vector.
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return left minus right in dest
+ */
+ public static Vector2f sub(Vector2f left, Vector2f right, Vector2f dest) {
+ if (dest == null)
+ return new Vector2f(left.x - right.x, left.y - right.y);
+ else {
+ dest.set(left.x - right.x, left.y - right.y);
+ return dest;
+ }
+ }
+
+ /**
+ * Store this vector in a FloatBuffer
+ * @param buf The buffer to store it in, at the current position
+ * @return this
+ */
+ public Vector store(FloatBuffer buf) {
+ buf.put(x);
+ buf.put(y);
+ return this;
+ }
+
+ /**
+ * Load this vector from a FloatBuffer
+ * @param buf The buffer to load it from, at the current position
+ * @return this
+ */
+ public Vector load(FloatBuffer buf) {
+ x = buf.get();
+ y = buf.get();
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#scale(float)
+ */
+ public Vector scale(float scale) {
+
+ x *= scale;
+ y *= scale;
+
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+
+ sb.append("Vector2f[");
+ sb.append(x);
+ sb.append(", ");
+ sb.append(y);
+ sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * @return x
+ */
+ public final float getX() {
+ return x;
+ }
+
+ /**
+ * @return y
+ */
+ public final float getY() {
+ return y;
+ }
+
+ /**
+ * Set X
+ * @param x
+ */
+ public final void setX(float x) {
+ this.x = x;
+ }
+
+ /**
+ * Set Y
+ * @param y
+ */
+ public final void setY(float y) {
+ this.y = y;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ Vector2f other = (Vector2f)obj;
+
+ if (x == other.x && y == other.y) return true;
+
+ return false;
+ }
+
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Vector3f.java b/src/de/verschwiegener/lwjgl3/util/vector/Vector3f.java
new file mode 100644
index 0000000..d221981
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Vector3f.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+
+/**
+ *
+ * Holds a 3-tuple vector.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+
+public class Vector3f extends Vector implements Serializable, ReadableVector3f, WritableVector3f {
+
+ private static final long serialVersionUID = 1L;
+
+ public float x, y, z;
+
+ /**
+ * Constructor for Vector3f.
+ */
+ public Vector3f() {
+ super();
+ }
+
+ /**
+ * Constructor
+ */
+ public Vector3f(ReadableVector3f src) {
+ set(src);
+ }
+
+ /**
+ * Constructor
+ */
+ public Vector3f(float x, float y, float z) {
+ set(x, y, z);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
+ */
+ public void set(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float)
+ */
+ public void set(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /**
+ * Load from another Vector3f
+ * @param src The source vector
+ * @return this
+ */
+ public Vector3f set(ReadableVector3f src) {
+ x = src.getX();
+ y = src.getY();
+ z = src.getZ();
+ return this;
+ }
+
+ /**
+ * @return the length squared of the vector
+ */
+ public float lengthSquared() {
+ return x * x + y * y + z * z;
+ }
+
+ /**
+ * Translate a vector
+ * @param x The translation in x
+ * @param y the translation in y
+ * @return this
+ */
+ public Vector3f translate(float x, float y, float z) {
+ this.x += x;
+ this.y += y;
+ this.z += z;
+ return this;
+ }
+
+ /**
+ * Add a vector to another vector and place the result in a destination
+ * vector.
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return the sum of left and right in dest
+ */
+ public static Vector3f add(Vector3f left, Vector3f right, Vector3f dest) {
+ if (dest == null)
+ return new Vector3f(left.x + right.x, left.y + right.y, left.z + right.z);
+ else {
+ dest.set(left.x + right.x, left.y + right.y, left.z + right.z);
+ return dest;
+ }
+ }
+
+ /**
+ * Subtract a vector from another vector and place the result in a destination
+ * vector.
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return left minus right in dest
+ */
+ public static Vector3f sub(Vector3f left, Vector3f right, Vector3f dest) {
+ if (dest == null)
+ return new Vector3f(left.x - right.x, left.y - right.y, left.z - right.z);
+ else {
+ dest.set(left.x - right.x, left.y - right.y, left.z - right.z);
+ return dest;
+ }
+ }
+
+ /**
+ * The cross product of two vectors.
+ *
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination result, or null if a new vector is to be created
+ * @return left cross right
+ */
+ public static Vector3f cross(
+ Vector3f left,
+ Vector3f right,
+ Vector3f dest)
+ {
+
+ if (dest == null)
+ dest = new Vector3f();
+
+ dest.set(
+ left.y * right.z - left.z * right.y,
+ right.x * left.z - right.z * left.x,
+ left.x * right.y - left.y * right.x
+ );
+
+ return dest;
+ }
+
+
+
+ /**
+ * Negate a vector
+ * @return this
+ */
+ public Vector negate() {
+ x = -x;
+ y = -y;
+ z = -z;
+ return this;
+ }
+
+ /**
+ * Negate a vector and place the result in a destination vector.
+ * @param dest The destination vector or null if a new vector is to be created
+ * @return the negated vector
+ */
+ public Vector3f negate(Vector3f dest) {
+ if (dest == null)
+ dest = new Vector3f();
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ return dest;
+ }
+
+
+ /**
+ * Normalise this vector and place the result in another vector.
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return the normalised vector
+ */
+ public Vector3f normalise(Vector3f dest) {
+ float l = length();
+
+ if (dest == null)
+ dest = new Vector3f(x / l, y / l, z / l);
+ else
+ dest.set(x / l, y / l, z / l);
+
+ return dest;
+ }
+
+ /**
+ * The dot product of two vectors is calculated as
+ * v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @return left dot right
+ */
+ public static float dot(Vector3f left, Vector3f right) {
+ return left.x * right.x + left.y * right.y + left.z * right.z;
+ }
+
+ /**
+ * Calculate the angle between two vectors, in radians
+ * @param a A vector
+ * @param b The other vector
+ * @return the angle between the two vectors, in radians
+ */
+ public static float angle(Vector3f a, Vector3f b) {
+ float dls = dot(a, b) / (a.length() * b.length());
+ if (dls < -1f)
+ dls = -1f;
+ else if (dls > 1.0f)
+ dls = 1.0f;
+ return (float)Math.acos(dls);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#load(FloatBuffer)
+ */
+ public Vector load(FloatBuffer buf) {
+ x = buf.get();
+ y = buf.get();
+ z = buf.get();
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#scale(float)
+ */
+ public Vector scale(float scale) {
+
+ x *= scale;
+ y *= scale;
+ z *= scale;
+
+ return this;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#store(FloatBuffer)
+ */
+ public Vector store(FloatBuffer buf) {
+
+ buf.put(x);
+ buf.put(y);
+ buf.put(z);
+
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+
+ sb.append("Vector3f[");
+ sb.append(x);
+ sb.append(", ");
+ sb.append(y);
+ sb.append(", ");
+ sb.append(z);
+ sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * @return x
+ */
+ public final float getX() {
+ return x;
+ }
+
+ /**
+ * @return y
+ */
+ public final float getY() {
+ return y;
+ }
+
+ /**
+ * Set X
+ * @param x
+ */
+ public final void setX(float x) {
+ this.x = x;
+ }
+
+ /**
+ * Set Y
+ * @param y
+ */
+ public final void setY(float y) {
+ this.y = y;
+ }
+
+ /**
+ * Set Z
+ * @param z
+ */
+ public void setZ(float z) {
+ this.z = z;
+ }
+
+ /* (Overrides)
+ * @see org.lwjgl.vector.ReadableVector3f#getZ()
+ */
+ public float getZ() {
+ return z;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ Vector3f other = (Vector3f)obj;
+
+ if (x == other.x && y == other.y && z == other.z) return true;
+
+ return false;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/Vector4f.java b/src/de/verschwiegener/lwjgl3/util/vector/Vector4f.java
new file mode 100644
index 0000000..adb8730
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/Vector4f.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+import java.io.Serializable;
+import java.nio.FloatBuffer;
+
+/**
+ *
+ * Holds a 4-tuple vector.
+ *
+ * @author cix_foo
+ * @version $Revision$
+ * $Id$
+ */
+
+public class Vector4f extends Vector implements Serializable, ReadableVector4f, WritableVector4f {
+
+ private static final long serialVersionUID = 1L;
+
+ public float x, y, z, w;
+
+ /**
+ * Constructor for Vector4f.
+ */
+ public Vector4f() {
+ super();
+ }
+
+ /**
+ * Constructor
+ */
+ public Vector4f(ReadableVector4f src) {
+ set(src);
+ }
+
+ /**
+ * Constructor
+ */
+ public Vector4f(float x, float y, float z, float w) {
+ set(x, y, z, w);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
+ */
+ public void set(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float)
+ */
+ public void set(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.util.vector.WritableVector4f#set(float, float, float, float)
+ */
+ public void set(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Load from another Vector4f
+ * @param src The source vector
+ * @return this
+ */
+ public Vector4f set(ReadableVector4f src) {
+ x = src.getX();
+ y = src.getY();
+ z = src.getZ();
+ w = src.getW();
+ return this;
+ }
+
+ /**
+ * @return the length squared of the vector
+ */
+ public float lengthSquared() {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ /**
+ * Translate a vector
+ * @param x The translation in x
+ * @param y the translation in y
+ * @return this
+ */
+ public Vector4f translate(float x, float y, float z, float w) {
+ this.x += x;
+ this.y += y;
+ this.z += z;
+ this.w += w;
+ return this;
+ }
+
+ /**
+ * Add a vector to another vector and place the result in a destination
+ * vector.
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return the sum of left and right in dest
+ */
+ public static Vector4f add(Vector4f left, Vector4f right, Vector4f dest) {
+ if (dest == null)
+ return new Vector4f(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ else {
+ dest.set(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ return dest;
+ }
+ }
+
+ /**
+ * Subtract a vector from another vector and place the result in a destination
+ * vector.
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return left minus right in dest
+ */
+ public static Vector4f sub(Vector4f left, Vector4f right, Vector4f dest) {
+ if (dest == null)
+ return new Vector4f(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ else {
+ dest.set(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ return dest;
+ }
+ }
+
+
+ /**
+ * Negate a vector
+ * @return this
+ */
+ public Vector negate() {
+ x = -x;
+ y = -y;
+ z = -z;
+ w = -w;
+ return this;
+ }
+
+ /**
+ * Negate a vector and place the result in a destination vector.
+ * @param dest The destination vector or null if a new vector is to be created
+ * @return the negated vector
+ */
+ public Vector4f negate(Vector4f dest) {
+ if (dest == null)
+ dest = new Vector4f();
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ dest.w = -w;
+ return dest;
+ }
+
+
+ /**
+ * Normalise this vector and place the result in another vector.
+ * @param dest The destination vector, or null if a new vector is to be created
+ * @return the normalised vector
+ */
+ public Vector4f normalise(Vector4f dest) {
+ float l = length();
+
+ if (dest == null)
+ dest = new Vector4f(x / l, y / l, z / l, w / l);
+ else
+ dest.set(x / l, y / l, z / l, w / l);
+
+ return dest;
+ }
+
+ /**
+ * The dot product of two vectors is calculated as
+ * v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w
+ * @param left The LHS vector
+ * @param right The RHS vector
+ * @return left dot right
+ */
+ public static float dot(Vector4f left, Vector4f right) {
+ return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w;
+ }
+
+ /**
+ * Calculate the angle between two vectors, in radians
+ * @param a A vector
+ * @param b The other vector
+ * @return the angle between the two vectors, in radians
+ */
+ public static float angle(Vector4f a, Vector4f b) {
+ float dls = dot(a, b) / (a.length() * b.length());
+ if (dls < -1f)
+ dls = -1f;
+ else if (dls > 1.0f)
+ dls = 1.0f;
+ return (float)Math.acos(dls);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#load(FloatBuffer)
+ */
+ public Vector load(FloatBuffer buf) {
+ x = buf.get();
+ y = buf.get();
+ z = buf.get();
+ w = buf.get();
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#scale(float)
+ */
+ public Vector scale(float scale) {
+ x *= scale;
+ y *= scale;
+ z *= scale;
+ w *= scale;
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lwjgl.vector.Vector#store(FloatBuffer)
+ */
+ public Vector store(FloatBuffer buf) {
+
+ buf.put(x);
+ buf.put(y);
+ buf.put(z);
+ buf.put(w);
+
+ return this;
+ }
+
+ public String toString() {
+ return "Vector4f: " + x + " " + y + " " + z + " " + w;
+ }
+
+ /**
+ * @return x
+ */
+ public final float getX() {
+ return x;
+ }
+
+ /**
+ * @return y
+ */
+ public final float getY() {
+ return y;
+ }
+
+ /**
+ * Set X
+ * @param x
+ */
+ public final void setX(float x) {
+ this.x = x;
+ }
+
+ /**
+ * Set Y
+ * @param y
+ */
+ public final void setY(float y) {
+ this.y = y;
+ }
+
+ /**
+ * Set Z
+ * @param z
+ */
+ public void setZ(float z) {
+ this.z = z;
+ }
+
+
+ /* (Overrides)
+ * @see org.lwjgl.vector.ReadableVector3f#getZ()
+ */
+ public float getZ() {
+ return z;
+ }
+
+ /**
+ * Set W
+ * @param w
+ */
+ public void setW(float w) {
+ this.w = w;
+ }
+
+ /* (Overrides)
+ * @see org.lwjgl.vector.ReadableVector3f#getZ()
+ */
+ public float getW() {
+ return w;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ Vector4f other = (Vector4f)obj;
+
+ if (x == other.x && y == other.y && z == other.z && w == other.w) return true;
+
+ return false;
+ }
+}
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/WritableVector2f.java b/src/de/verschwiegener/lwjgl3/util/vector/WritableVector2f.java
new file mode 100644
index 0000000..e381b99
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/WritableVector2f.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ * Writable interface to Vector2fs
+ * @author $author$
+ * @version $revision$
+ * $Id$
+ */
+public interface WritableVector2f {
+
+ /**
+ * Set the X value
+ * @param x
+ */
+ void setX(float x);
+
+ /**
+ * Set the Y value
+ * @param y
+ */
+ void setY(float y);
+
+ /**
+ * Set the X,Y values
+ * @param x
+ * @param y
+ */
+ void set(float x, float y);
+
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/WritableVector3f.java b/src/de/verschwiegener/lwjgl3/util/vector/WritableVector3f.java
new file mode 100644
index 0000000..3668f1a
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/WritableVector3f.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ * Writable interface to Vector3fs
+ * @author $author$
+ * @version $revision$
+ * $Id$
+ */
+public interface WritableVector3f extends WritableVector2f {
+
+ /**
+ * Set the Z value
+ * @param z
+ */
+ void setZ(float z);
+
+ /**
+ * Set the X,Y,Z values
+ * @param x
+ * @param y
+ * @param z
+ */
+ void set(float x, float y, float z);
+
+}
\ No newline at end of file
diff --git a/src/de/verschwiegener/lwjgl3/util/vector/WritableVector4f.java b/src/de/verschwiegener/lwjgl3/util/vector/WritableVector4f.java
new file mode 100644
index 0000000..eb48b65
--- /dev/null
+++ b/src/de/verschwiegener/lwjgl3/util/vector/WritableVector4f.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL 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 'LWJGL' 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 de.verschwiegener.lwjgl3.util.vector;
+
+/**
+ * Writable interface to Vector4fs
+ * @author $author$
+ * @version $revision$
+ * $Id$
+ */
+public interface WritableVector4f extends WritableVector3f {
+
+ /**
+ * Set the W value
+ * @param w
+ */
+ void setW(float w);
+
+ /**
+ * Set the X,Y,Z,W values
+ * @param x
+ * @param y
+ * @param z
+ * @param w
+ */
+ void set(float x, float y, float z, float w);
+
+}
\ No newline at end of file
diff --git a/src/org/lwjgl/LWJGLException.java b/src/org/lwjgl/LWJGLException.java
new file mode 100644
index 0000000..7696211
--- /dev/null
+++ b/src/org/lwjgl/LWJGLException.java
@@ -0,0 +1,39 @@
+package org.lwjgl;
+
+public class LWJGLException extends Exception{
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Plain c'tor
+ */
+ public LWJGLException() {
+ super();
+ }
+
+ /**
+ * Creates a new LWJGLException
+ *
+ * @param msg
+ * String identifier for exception
+ */
+ public LWJGLException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public LWJGLException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param cause
+ */
+ public LWJGLException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/src/org/lwjgl/input/Keyboard.java b/src/org/lwjgl/input/Keyboard.java
new file mode 100644
index 0000000..57f87b3
--- /dev/null
+++ b/src/org/lwjgl/input/Keyboard.java
@@ -0,0 +1,487 @@
+package org.lwjgl.input;
+
+import de.verschwiegener.lwjgl3.BufferUtils;
+import de.verschwiegener.lwjgl3.display.Display;
+import org.lwjgl.glfw.GLFWCharCallback;
+import org.lwjgl.glfw.GLFWKeyCallback;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.lwjgl.glfw.GLFW.*;
+
+public class Keyboard {
+
+ public static final int KEY_NONE = 0x00;
+
+ public static final int KEY_ESCAPE = 0x01;
+ public static final int KEY_1 = 0x02;
+ public static final int KEY_2 = 0x03;
+ public static final int KEY_3 = 0x04;
+ public static final int KEY_4 = 0x05;
+ public static final int KEY_5 = 0x06;
+ public static final int KEY_6 = 0x07;
+ public static final int KEY_7 = 0x08;
+ public static final int KEY_8 = 0x09;
+ public static final int KEY_9 = 0x0A;
+ public static final int KEY_0 = 0x0B;
+ public static final int KEY_MINUS = 0x0C; /* - on main keyboard */
+ public static final int KEY_EQUALS = 0x0D;
+ public static final int KEY_BACK = 0x0E; /* backspace */
+ public static final int KEY_TAB = 0x0F;
+ public static final int KEY_Q = 0x10;
+ public static final int KEY_W = 0x11;
+ public static final int KEY_E = 0x12;
+ public static final int KEY_R = 0x13;
+ public static final int KEY_T = 0x14;
+ public static final int KEY_Y = 0x15;
+ public static final int KEY_U = 0x16;
+ public static final int KEY_I = 0x17;
+ public static final int KEY_O = 0x18;
+ public static final int KEY_P = 0x19;
+ public static final int KEY_LBRACKET = 0x1A;
+ public static final int KEY_RBRACKET = 0x1B;
+ public static final int KEY_RETURN = 0x1C; /* Enter on main keyboard */
+ public static final int KEY_LCONTROL = 0x1D;
+ public static final int KEY_A = 0x1E;
+ public static final int KEY_S = 0x1F;
+ public static final int KEY_D = 0x20;
+ public static final int KEY_F = 0x21;
+ public static final int KEY_G = 0x22;
+ public static final int KEY_H = 0x23;
+ public static final int KEY_J = 0x24;
+ public static final int KEY_K = 0x25;
+ public static final int KEY_L = 0x26;
+ public static final int KEY_SEMICOLON = 0x27;
+ public static final int KEY_APOSTROPHE = 0x28;
+ public static final int KEY_GRAVE = 0x29; /* accent grave */
+ public static final int KEY_LSHIFT = 0x2A;
+ public static final int KEY_BACKSLASH = 0x2B;
+ public static final int KEY_Z = 0x2C;
+ public static final int KEY_X = 0x2D;
+ public static final int KEY_C = 0x2E;
+ public static final int KEY_V = 0x2F;
+ public static final int KEY_B = 0x30;
+ public static final int KEY_N = 0x31;
+ public static final int KEY_M = 0x32;
+ public static final int KEY_COMMA = 0x33;
+ public static final int KEY_PERIOD = 0x34; /* . on main keyboard */
+ public static final int KEY_SLASH = 0x35; /* / on main keyboard */
+ public static final int KEY_RSHIFT = 0x36;
+ public static final int KEY_MULTIPLY = 0x37; /* * on numeric keypad */
+ public static final int KEY_LMENU = 0x38; /* left Alt */
+ public static final int KEY_SPACE = 0x39;
+ public static final int KEY_CAPITAL = 0x3A;
+ public static final int KEY_F1 = 0x3B;
+ public static final int KEY_F2 = 0x3C;
+ public static final int KEY_F3 = 0x3D;
+ public static final int KEY_F4 = 0x3E;
+ public static final int KEY_F5 = 0x3F;
+ public static final int KEY_F6 = 0x40;
+ public static final int KEY_F7 = 0x41;
+ public static final int KEY_F8 = 0x42;
+ public static final int KEY_F9 = 0x43;
+ public static final int KEY_F10 = 0x44;
+ public static final int KEY_NUMLOCK = 0x45;
+ public static final int KEY_SCROLL = 0x46; /* Scroll Lock */
+ public static final int KEY_NUMPAD7 = 0x47;
+ public static final int KEY_NUMPAD8 = 0x48;
+ public static final int KEY_NUMPAD9 = 0x49;
+ public static final int KEY_SUBTRACT = 0x4A; /* - on numeric keypad */
+ public static final int KEY_NUMPAD4 = 0x4B;
+ public static final int KEY_NUMPAD5 = 0x4C;
+ public static final int KEY_NUMPAD6 = 0x4D;
+ public static final int KEY_ADD = 0x4E; /* + on numeric keypad */
+ public static final int KEY_NUMPAD1 = 0x4F;
+ public static final int KEY_NUMPAD2 = 0x50;
+ public static final int KEY_NUMPAD3 = 0x51;
+ public static final int KEY_NUMPAD0 = 0x52;
+ public static final int KEY_DECIMAL = 0x53; /* . on numeric keypad */
+ public static final int KEY_F11 = 0x57;
+ public static final int KEY_F12 = 0x58;
+ public static final int KEY_F13 = 0x64; /* (NEC PC98) */
+ public static final int KEY_F14 = 0x65; /* (NEC PC98) */
+ public static final int KEY_F15 = 0x66; /* (NEC PC98) */
+ public static final int KEY_F16 = 0x67; /* Extended Function keys - (Mac) */
+ public static final int KEY_F17 = 0x68;
+ public static final int KEY_F18 = 0x69;
+ public static final int KEY_KANA = 0x70; /* (Japanese keyboard) */
+ public static final int KEY_F19 = 0x71; /* Extended Function keys - (Mac) */
+ public static final int KEY_CONVERT = 0x79; /* (Japanese keyboard) */
+ public static final int KEY_NOCONVERT = 0x7B; /* (Japanese keyboard) */
+ public static final int KEY_YEN = 0x7D; /* (Japanese keyboard) */
+ public static final int KEY_NUMPADEQUALS = 0x8D; /* = on numeric keypad (NEC PC98) */
+ public static final int KEY_CIRCUMFLEX = 0x90; /* (Japanese keyboard) */
+ public static final int KEY_AT = 0x91; /* (NEC PC98) */
+ public static final int KEY_COLON = 0x92; /* (NEC PC98) */
+ public static final int KEY_UNDERLINE = 0x93; /* (NEC PC98) */
+ public static final int KEY_KANJI = 0x94; /* (Japanese keyboard) */
+ public static final int KEY_STOP = 0x95; /* (NEC PC98) */
+ public static final int KEY_AX = 0x96; /* (Japan AX) */
+ public static final int KEY_UNLABELED = 0x97; /* (J3100) */
+ public static final int KEY_NUMPADENTER = 0x9C; /* Enter on numeric keypad */
+ public static final int KEY_RCONTROL = 0x9D;
+ public static final int KEY_SECTION = 0xA7; /* Section symbol (Mac) */
+ public static final int KEY_NUMPADCOMMA = 0xB3; /* , on numeric keypad (NEC PC98) */
+ public static final int KEY_DIVIDE = 0xB5; /* / on numeric keypad */
+ public static final int KEY_SYSRQ = 0xB7;
+ public static final int KEY_RMENU = 0xB8; /* right Alt */
+ public static final int KEY_FUNCTION = 0xC4; /* Function (Mac) */
+ public static final int KEY_PAUSE = 0xC5; /* Pause */
+ public static final int KEY_HOME = 0xC7; /* Home on arrow keypad */
+ public static final int KEY_UP = 0xC8; /* UpArrow on arrow keypad */
+ public static final int KEY_PRIOR = 0xC9; /* PgUp on arrow keypad */
+ public static final int KEY_LEFT = 0xCB; /* LeftArrow on arrow keypad */
+ public static final int KEY_RIGHT = 0xCD; /* RightArrow on arrow keypad */
+ public static final int KEY_END = 0xCF; /* End on arrow keypad */
+ public static final int KEY_DOWN = 0xD0; /* DownArrow on arrow keypad */
+ public static final int KEY_NEXT = 0xD1; /* PgDn on arrow keypad */
+ public static final int KEY_INSERT = 0xD2; /* Insert on arrow keypad */
+ public static final int KEY_DELETE = 0xD3; /* Delete on arrow keypad */
+ public static final int KEY_CLEAR = 0xDA; /* Clear key (Mac) */
+ public static final int KEY_LMETA = 0xDB; /* Left Windows/Option key */
+ /**
+ * The left windows key, mapped to KEY_LMETA
+ *
+ * @deprecated Use KEY_LMETA instead
+ */
+ public static final int KEY_LWIN = KEY_LMETA; /* Left Windows key */
+ public static final int KEY_RMETA = 0xDC; /* Right Windows/Option key */
+ /**
+ * The right windows key, mapped to KEY_RMETA
+ *
+ * @deprecated Use KEY_RMETA instead
+ */
+ public static final int KEY_RWIN = KEY_RMETA; /* Right Windows key */
+ public static final int KEY_APPS = 0xDD; /* AppMenu key */
+ public static final int KEY_POWER = 0xDE;
+ public static final int KEY_SLEEP = 0xDF;
+
+ public static final int KEYBOARD_SIZE = 256;
+
+ public static final ByteBuffer keyDownBuffer = BufferUtils.createByteBuffer(KEYBOARD_SIZE);
+
+ private static final int BUFFER_SIZE = 50;
+ public static final int EVENT_SIZE = 4 + 1 + 4 + 8 + 1;
+ private static ByteBuffer readBuffer;
+ private static boolean created;
+ private static boolean repeat_enabled;
+
+ /**
+ * Key names
+ */
+ private static final String[] keyName = new String[KEYBOARD_SIZE];
+ private static final Map keyMap = new HashMap<>(KEYBOARD_SIZE);
+ private static final Map glfwKeys = new HashMap<>(348);
+ private static int counter;
+
+ private static final KeyEvent current_event = new KeyEvent();
+
+
+ static {
+ // Use reflection to find out key names
+ Field[] fields = Keyboard.class.getFields();
+ try {
+ for (Field field : fields) {
+ if (Modifier.isStatic(field.getModifiers())
+ && Modifier.isPublic(field.getModifiers())
+ && Modifier.isFinal(field.getModifiers())
+ && field.getType().equals(int.class)
+ && field.getName().startsWith("KEY_")
+ && !field.getName().endsWith("WIN")) { /* Don't use deprecated names */
+
+ int key = field.getInt(null);
+ String name = field.getName().substring(4);
+ keyName[key] = name;
+ keyMap.put(name, key);
+ counter++;
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+ public static int getKeyCount() {
+ return counter;
+ }
+
+ public static String getKeyName(int key) {
+ return keyName[key];
+ }
+
+ public static int getKeyIndex(String keyName) {
+ Integer ret = keyMap.get(keyName);
+ if (ret == null)
+ return KEY_NONE;
+ else
+ return ret;
+ }
+
+ public static void create() {
+ if(created)
+ return;
+
+ createGLFWKeyMap();
+ created = true;
+ repeat_enabled = false;
+ readBuffer = ByteBuffer.allocate(EVENT_SIZE * BUFFER_SIZE);
+ reset();;
+ }
+
+ public static void destroy() {
+ if (!created)
+ return;
+ created = false;
+ reset();
+ }
+
+ public static boolean next() {
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can read events");
+ boolean result;
+ while ((result = readNext(current_event)) && current_event.repeat && !repeat_enabled)
+ ;
+ return result;
+
+ }
+
+ private static boolean readNext(KeyEvent event) {
+ if (readBuffer.hasRemaining()) {
+ event.key = readBuffer.getInt() & 0xFF;
+ event.state = readBuffer.get() != 0;
+ event.character = readBuffer.getChar();
+ boolean repeat = readBuffer.get() == 1;
+ if (repeat_enabled) event.repeat = repeat;
+ return true;
+ } else
+ return false;
+ }
+
+ public static void enableRepeatEvents(boolean enable) {
+ System.out.println("SetRepeat: " + enable);
+ repeat_enabled = enable;
+ }
+
+ public static int getEventKey() {
+ return current_event.key;
+ }
+
+ public static boolean getEventKeyState() {
+ return current_event.state;
+ }
+
+ public static char getEventCharacter() {
+ return (char) current_event.character;
+ }
+
+ public static boolean isRepeatEvent() {
+ return repeat_enabled;
+ }
+
+ public static boolean isCreated() {
+ return created;
+ }
+
+ public static boolean isKeyDown(int key) {
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can query key state");
+ return keyDownBuffer.get(key) != 0;
+ }
+
+ public static void reset() {
+ readBuffer.limit(0);
+ for (int i = 0; i < keyDownBuffer.remaining(); i++)
+ keyDownBuffer.put(i, (byte) 0);
+ current_event.reset();
+ }
+
+ public static void pollGLFW(){
+ glfwSetCharCallback(Display.getWindow(), new GLFWCharCallback() {
+ @Override
+ public void invoke(long l, int i) {
+ parseGLFWCodes(0, 1, i);
+ }
+ });
+ glfwSetKeyCallback(Display.getWindow(), new GLFWKeyCallback() {
+ @Override
+ public void invoke(long l, int key, int scancode, int action, int modifierBits) {
+ if(!repeat_enabled && action == 2) return;
+ int poll_key = glfwKeys.get(key);
+ parseGLFWCodes(poll_key, action,0 );
+
+ keyDownBuffer.compact();
+ keyDownBuffer.put(poll_key, (byte) ((action == 2 || action == 1) ? 1 : 0));
+ keyDownBuffer.flip();
+ }
+ });
+ }
+
+
+ public static void parseGLFWCodes(int key, int action,int character) {
+ readBuffer.compact();
+ readBuffer.putInt(key);
+ readBuffer.put((byte) ((action == 2 || action == 1) ? 1 : 0));
+ readBuffer.putChar((char) character);
+ readBuffer.put((byte) ((action == 2) ? 1 : 0));
+ readBuffer.flip();
+ }
+
+ private static void createGLFWKeyMap() {
+ glfwKeys.put(GLFW_KEY_UNKNOWN, KEY_NONE);
+ glfwKeys.put(GLFW_KEY_SPACE, KEY_SPACE);
+ glfwKeys.put(GLFW_KEY_APOSTROPHE, KEY_APOSTROPHE);
+ glfwKeys.put(GLFW_KEY_COMMA, KEY_COMMA);
+ glfwKeys.put(GLFW_KEY_MINUS, KEY_MINUS);
+ glfwKeys.put(GLFW_KEY_PERIOD, KEY_PERIOD);
+ glfwKeys.put(GLFW_KEY_SLASH, KEY_SLASH);
+ glfwKeys.put(GLFW_KEY_0, KEY_0);
+ glfwKeys.put(GLFW_KEY_1, KEY_1);
+ glfwKeys.put(GLFW_KEY_2, KEY_2);
+ glfwKeys.put(GLFW_KEY_3, KEY_3);
+ glfwKeys.put(GLFW_KEY_4, KEY_4);
+ glfwKeys.put(GLFW_KEY_5, KEY_5);
+ glfwKeys.put(GLFW_KEY_6, KEY_6);
+ glfwKeys.put(GLFW_KEY_7, KEY_7);
+ glfwKeys.put(GLFW_KEY_8, KEY_8);
+ glfwKeys.put(GLFW_KEY_9, KEY_9);
+ glfwKeys.put(GLFW_KEY_SEMICOLON, KEY_SEMICOLON);
+ glfwKeys.put(GLFW_KEY_EQUAL, KEY_EQUALS);
+ glfwKeys.put(GLFW_KEY_A, KEY_A);
+ glfwKeys.put(GLFW_KEY_B, KEY_B);
+ glfwKeys.put(GLFW_KEY_C, KEY_C);
+ glfwKeys.put(GLFW_KEY_D, KEY_D);
+ glfwKeys.put(GLFW_KEY_E, KEY_E);
+ glfwKeys.put(GLFW_KEY_F, KEY_F);
+ glfwKeys.put(GLFW_KEY_G, KEY_G);
+ glfwKeys.put(GLFW_KEY_H, KEY_H);
+ glfwKeys.put(GLFW_KEY_I, KEY_I);
+ glfwKeys.put(GLFW_KEY_J, KEY_J);
+ glfwKeys.put(GLFW_KEY_K, KEY_K);
+ glfwKeys.put(GLFW_KEY_L, KEY_L);
+ glfwKeys.put(GLFW_KEY_M, KEY_M);
+ glfwKeys.put(GLFW_KEY_N, KEY_N);
+ glfwKeys.put(GLFW_KEY_O, KEY_O);
+ glfwKeys.put(GLFW_KEY_P, KEY_P);
+ glfwKeys.put(GLFW_KEY_Q, KEY_Q);
+ glfwKeys.put(GLFW_KEY_R, KEY_R);
+ glfwKeys.put(GLFW_KEY_S, KEY_S);
+ glfwKeys.put(GLFW_KEY_T, KEY_T);
+ glfwKeys.put(GLFW_KEY_U, KEY_U);
+ glfwKeys.put(GLFW_KEY_V, KEY_V);
+ glfwKeys.put(GLFW_KEY_W, KEY_W);
+ glfwKeys.put(GLFW_KEY_X, KEY_X);
+ glfwKeys.put(GLFW_KEY_Y, KEY_Y);
+ glfwKeys.put(GLFW_KEY_Z, KEY_Z);
+ glfwKeys.put(GLFW_KEY_LEFT_BRACKET, KEY_LBRACKET);
+ glfwKeys.put(GLFW_KEY_BACKSLASH, KEY_BACKSLASH);
+ glfwKeys.put(GLFW_KEY_RIGHT_BRACKET, KEY_RBRACKET);
+ glfwKeys.put(GLFW_KEY_GRAVE_ACCENT, KEY_GRAVE);
+ //IDK which keys this are, but there are not on US Layout
+ //glfwKeys.put(GLFW_KEY_WORLD_1,KEY_WORLD_1);
+ //glfwKeys.put(GLFW_KEY_WORLD_2,KEY_WORLD_2);
+ glfwKeys.put(GLFW_KEY_ESCAPE, KEY_ESCAPE);
+ glfwKeys.put(GLFW_KEY_ENTER, KEY_RETURN);
+ glfwKeys.put(GLFW_KEY_TAB, KEY_TAB);
+ glfwKeys.put(GLFW_KEY_BACKSPACE, KEY_BACK);
+ glfwKeys.put(GLFW_KEY_INSERT, KEY_INSERT);
+ glfwKeys.put(GLFW_KEY_DELETE, KEY_DELETE);
+ glfwKeys.put(GLFW_KEY_RIGHT, KEY_RIGHT);
+ glfwKeys.put(GLFW_KEY_LEFT, KEY_LEFT);
+ glfwKeys.put(GLFW_KEY_DOWN, KEY_DOWN);
+ glfwKeys.put(GLFW_KEY_UP, KEY_UP);
+ glfwKeys.put(GLFW_KEY_PAGE_UP, KEY_PRIOR);
+ glfwKeys.put(GLFW_KEY_PAGE_DOWN, KEY_NEXT);
+ glfwKeys.put(GLFW_KEY_HOME, KEY_HOME);
+ glfwKeys.put(GLFW_KEY_END, KEY_END);
+ glfwKeys.put(GLFW_KEY_CAPS_LOCK, KEY_CAPITAL);
+ glfwKeys.put(GLFW_KEY_SCROLL_LOCK, KEY_SCROLL);
+ glfwKeys.put(GLFW_KEY_NUM_LOCK, KEY_NUMLOCK);
+ glfwKeys.put(GLFW_KEY_PRINT_SCREEN, KEY_SYSRQ);
+ glfwKeys.put(GLFW_KEY_PAUSE, KEY_PAUSE);
+ glfwKeys.put(GLFW_KEY_F1, KEY_F1);
+ glfwKeys.put(GLFW_KEY_F2, KEY_F2);
+ glfwKeys.put(GLFW_KEY_F3, KEY_F3);
+ glfwKeys.put(GLFW_KEY_F4, KEY_F4);
+ glfwKeys.put(GLFW_KEY_F5, KEY_F5);
+ glfwKeys.put(GLFW_KEY_F6, KEY_F6);
+ glfwKeys.put(GLFW_KEY_F7, KEY_F7);
+ glfwKeys.put(GLFW_KEY_F8, KEY_F8);
+ glfwKeys.put(GLFW_KEY_F9, KEY_F9);
+ glfwKeys.put(GLFW_KEY_F10, KEY_F10);
+ glfwKeys.put(GLFW_KEY_F11, KEY_F11);
+ glfwKeys.put(GLFW_KEY_F12, KEY_F12);
+ glfwKeys.put(GLFW_KEY_F13, KEY_F13);
+ glfwKeys.put(GLFW_KEY_F14, KEY_F14);
+ glfwKeys.put(GLFW_KEY_F15, KEY_F15);
+ glfwKeys.put(GLFW_KEY_F16, KEY_F16);
+ glfwKeys.put(GLFW_KEY_F17, KEY_F17);
+ glfwKeys.put(GLFW_KEY_F18, KEY_F18);
+ glfwKeys.put(GLFW_KEY_F19, KEY_F19);
+ //lwjgl2 doesnt suport all F keys
+ //glfwKeys.put(GLFW_KEY_F20,KEY_F20);
+ //glfwKeys.put(GLFW_KEY_F21,KEY_F21);
+ //glfwKeys.put(GLFW_KEY_F22,KEY_F22);
+ //glfwKeys.put(GLFW_KEY_F23,KEY_F23);
+ //glfwKeys.put(GLFW_KEY_F24,KEY_F24);
+ //glfwKeys.put(GLFW_KEY_F25,KEY_F25);
+ glfwKeys.put(GLFW_KEY_KP_0, KEY_NUMPAD0);
+ glfwKeys.put(GLFW_KEY_KP_1, KEY_NUMPAD1);
+ glfwKeys.put(GLFW_KEY_KP_2, KEY_NUMPAD2);
+ glfwKeys.put(GLFW_KEY_KP_3, KEY_NUMPAD3);
+ glfwKeys.put(GLFW_KEY_KP_4, KEY_NUMPAD4);
+ glfwKeys.put(GLFW_KEY_KP_5, KEY_NUMPAD5);
+ glfwKeys.put(GLFW_KEY_KP_6, KEY_NUMPAD6);
+ glfwKeys.put(GLFW_KEY_KP_7, KEY_NUMPAD7);
+ glfwKeys.put(GLFW_KEY_KP_8, KEY_NUMPAD8);
+ glfwKeys.put(GLFW_KEY_KP_9, KEY_NUMPAD9);
+ glfwKeys.put(GLFW_KEY_KP_DECIMAL, KEY_DECIMAL);
+ glfwKeys.put(GLFW_KEY_KP_DIVIDE, KEY_DIVIDE);
+ glfwKeys.put(GLFW_KEY_KP_MULTIPLY, KEY_MULTIPLY);
+ glfwKeys.put(GLFW_KEY_KP_SUBTRACT, KEY_SUBTRACT);
+ glfwKeys.put(GLFW_KEY_KP_ADD, KEY_ADD);
+ glfwKeys.put(GLFW_KEY_KP_ENTER, KEY_NUMPADENTER);
+ glfwKeys.put(GLFW_KEY_KP_EQUAL, KEY_NUMPADEQUALS);
+ glfwKeys.put(GLFW_KEY_LEFT_SHIFT, KEY_LSHIFT);
+ glfwKeys.put(GLFW_KEY_LEFT_CONTROL, KEY_LCONTROL);
+ glfwKeys.put(GLFW_KEY_LEFT_ALT, KEY_LMENU);
+ glfwKeys.put(GLFW_KEY_LEFT_SUPER, KEY_LMETA);
+ glfwKeys.put(GLFW_KEY_RIGHT_SHIFT, KEY_RSHIFT);
+ glfwKeys.put(GLFW_KEY_RIGHT_CONTROL, KEY_RCONTROL);
+ glfwKeys.put(GLFW_KEY_RIGHT_ALT, KEY_RMENU);
+ glfwKeys.put(GLFW_KEY_RIGHT_SUPER, KEY_RMETA);
+ glfwKeys.put(GLFW_KEY_MENU, KEY_RMENU);
+ }
+
+
+ private static final class KeyEvent {
+ /**
+ * The current keyboard character being examined
+ */
+ private int character;
+
+ /**
+ * The current keyboard event key being examined
+ */
+ private int key;
+
+ /**
+ * The current state of the key being examined in the event queue
+ */
+ private boolean state;
+
+ /**
+ * Is the current event a repeated event?
+ */
+ private boolean repeat;
+
+ private void reset() {
+ character = 0;
+ key = 0;
+ state = false;
+ repeat = false;
+ }
+ }
+
+}
diff --git a/src/org/lwjgl/input/Mouse.java b/src/org/lwjgl/input/Mouse.java
new file mode 100644
index 0000000..f243b13
--- /dev/null
+++ b/src/org/lwjgl/input/Mouse.java
@@ -0,0 +1,256 @@
+package org.lwjgl.input;
+
+import de.verschwiegener.lwjgl3.display.Display;
+import org.lwjgl.BufferUtils;
+import org.lwjgl.glfw.GLFWCursorEnterCallback;
+import org.lwjgl.glfw.GLFWCursorPosCallback;
+import org.lwjgl.glfw.GLFWMouseButtonCallback;
+import org.lwjgl.glfw.GLFWScrollCallback;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.lwjgl.glfw.GLFW.*;
+
+public class Mouse {
+
+ private static boolean created;
+
+ private static String[] buttonName;
+ private static final Map buttonMap = new HashMap<>(8);
+ private static ByteBuffer readBuffer;
+ private static ByteBuffer buttons;
+ private static final int BUFFER_SIZE = 50;
+ //Max Nummber of buttons glfw supports https://www.glfw.org/docs/3.3/group__buttons.html
+ private static final int BUTTON_COUNT = 8;
+ //int = 4 boolean = 1, long = 8
+ // 4 + 1 + 4 + 4 + 4 + 4 + 4
+ public static final int EVENT_SIZE = 4 + 1 + 4 + 4 + 4 + 4 + 4;
+ private static MouseEvent current_Event;
+ private static boolean isGrabbed;
+
+ private static int last_event_raw_x;
+ private static int last_event_raw_y;
+ private static boolean clipMouseCoordinatesToWindow;
+
+ private static int poll_button = 0;
+ private static int poll_action = 0;
+ public static int poll_xPos = 0;
+ public static int poll_yPos = 0;
+ public static int poll_scrollY = 0;
+ private static int current_dx = 0;
+ private static int current_dy = 0;
+ public static int last_x = 0;
+ public static int last_y = 0;
+ private static boolean poll_outside;
+ private static boolean pollNeed;
+
+
+ public static void pollGLFW(){
+ if(!created) return;
+ glfwSetMouseButtonCallback(Display.getWindow(), new GLFWMouseButtonCallback() {
+ @Override
+ public void invoke(long l, int i, int i1, int i2) {
+ poll_button = i;
+ poll_action = i1;
+ buttons.put(i, (byte)i1);
+ pollNeed = true;
+ }
+ });
+ glfwSetCursorPosCallback(Display.getWindow(), new GLFWCursorPosCallback() {
+ @Override
+ public void invoke(long l, double v, double v1) {
+ if(Display.isActive()){
+ last_x = poll_xPos;
+ last_y = poll_yPos;
+ poll_xPos = (int) v;
+ poll_yPos = (int) (Display.getHeight() - v1);
+ current_dx = ((poll_xPos - last_x) * 8);
+ current_dy = ((poll_yPos - last_y) * 8);
+ pollNeed = true;
+ }
+ }
+ });
+ glfwSetScrollCallback(Display.getWindow(), new GLFWScrollCallback() {
+ @Override
+ public void invoke(long l, double v, double v1) {
+ poll_scrollY = (int) v1;
+ pollNeed = true;
+ }
+ });
+ glfwSetCursorEnterCallback(Display.getWindow(), new GLFWCursorEnterCallback() {
+ @Override
+ public void invoke(long l, boolean entered) {
+ poll_outside = entered;
+ }
+ });
+ }
+ public static void createEvent(){
+ if(!created || !pollNeed) return;
+ readBuffer.compact();
+ pollNeed = false;
+ readBuffer.putInt(poll_button);
+ readBuffer.put((byte)poll_action);
+ if(isGrabbed){
+ readBuffer.putInt(normalize(poll_xPos - last_x));
+ readBuffer.putInt(normalize(poll_yPos - last_y));
+ }else {
+ readBuffer.putInt(poll_xPos);
+ readBuffer.putInt(poll_yPos);
+ }
+ readBuffer.putInt(poll_scrollY);
+ readBuffer.flip();
+ }
+
+
+
+ public static void create(){
+ if(created) return;
+ buttons = BufferUtils.createByteBuffer(BUTTON_COUNT);
+ readBuffer = ByteBuffer.allocate(EVENT_SIZE * BUFFER_SIZE);
+ readBuffer.limit(0);
+ clipMouseCoordinatesToWindow = true;
+ created = true;
+
+ buttonName = new String[8];
+ for (int i = 0; i < 8; i++) {
+ buttonName[i] = "BUTTON" + i;
+ buttonMap.put(buttonName[i], i);
+ }
+
+ }
+ public static boolean next(){
+ if(!created) throw new IllegalStateException("Mouse must be created before you can read events");
+ if(readBuffer.hasRemaining()){
+ MouseEvent event = new MouseEvent();
+ event.eventButton = readBuffer.getInt();
+ event.eventState = readBuffer.get() != 0;
+
+ if(isGrabbed){
+ event.dx = readBuffer.getInt();
+ event.dy = readBuffer.getInt();
+ event.x += event.dx;
+ event.y += event.dy;
+ last_event_raw_x = event.x;
+ last_event_raw_y = event.y;
+ }else{
+ int new_event_x = readBuffer.getInt();
+ int new_event_y = readBuffer.getInt();
+ event.dx = new_event_x - last_event_raw_x;
+ event.dy = new_event_y - last_event_raw_y;
+ event.x = new_event_x;
+ event.y = new_event_y;
+ last_event_raw_x = new_event_x;
+ last_event_raw_y = new_event_y;
+ }
+ if(clipMouseCoordinatesToWindow) {
+ event.x = Math.min(Display.getWidth() - 1, Math.max(0, event.x));
+ event.y = Math.min(Display.getHeight() - 1, Math.max(0, event.y));
+ }
+ event.event_dwheel = readBuffer.getInt();
+ current_Event = event;
+ return true;
+ }
+ return false;
+ }
+
+
+ public static int getButtonIndex(String buttonName) {
+ Integer ret = buttonMap.get(buttonName);
+ if (ret == null)
+ return -1;
+ else
+ return ret;
+ }
+
+ public static String getButtonName(int button) {
+ if (button >= buttonName.length || button < 0)
+ return null;
+ else
+ return buttonName[button];
+ }
+
+ public static boolean isInsideWindow() {
+ return poll_outside;
+ }
+ public static int getEventButton(){
+ return current_Event.eventButton;
+ }
+ public static boolean getEventButtonState(){
+ return current_Event.eventState;
+ }
+ public static int getEventDWheel(){
+ return current_Event.event_dwheel;
+ }
+ public static int getEventX(){
+ return current_Event.x;
+ }
+ public static int getEventY(){
+ return current_Event.y;
+ }
+ public static boolean isCreated(){
+ return created;
+ }
+ public static int getX(){
+ return Math.min(Math.max(poll_xPos, 0), Display.getWidth() - 1);
+ }
+ public static int getY(){
+ return Math.min(Math.max(poll_yPos, 0), Display.getHeight() - 1);
+ }
+ public static void setClipMouseCoordinatesToWindow(boolean clip) {
+ clipMouseCoordinatesToWindow = clip;
+ }
+ public static boolean isButtonDown(int button){
+ if (!created) throw new IllegalStateException("Mouse must be created before you can poll the button state");
+ if (button >= BUTTON_COUNT || button < 0)
+ return false;
+ else
+ return buttons.get(button) == 1;
+ }
+ public static void setGrabbed(boolean grab){
+ if (!created) throw new IllegalStateException("Mouse must be created before you can poll the button state");
+ isGrabbed = grab;
+ if(!grab) glfwSetInputMode(Display.getWindow(), GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+ else glfwSetInputMode(Display.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+ glfwSetCursorPos(Display.getWindow(), poll_xPos, poll_yPos);
+ }
+ public static void setCursorPosition(int x, int y){
+ if (!isCreated()) throw new IllegalStateException("Mouse is not created");
+ poll_xPos = current_Event.x = x;
+ poll_yPos = current_Event.y = y;
+ glfwSetCursorPos(Display.getWindow(), x, y);
+ }
+ public static int getDX(){
+ int result = current_dx;
+ current_dx = 0;
+ return result;
+ }
+ public static int getDY(){
+ int result = current_dy;
+ current_dy = 0;
+ return result;
+ }
+ private static int normalize(int input){
+ if(input < 0) return input /-1;
+ return input;
+ }
+
+ public static int getDWheel() {
+ return poll_scrollY;
+ }
+
+
+ private static final class MouseEvent {
+
+ private int eventButton;
+ private boolean eventState;
+
+ private int dx;
+ private int dy;
+ private int x;
+ private int y;
+ private int event_dwheel;
+
+ }
+}
diff --git a/src/paulscode/sound/libraries/ChannelLWJGLOpenAL.java b/src/paulscode/sound/libraries/ChannelLWJGLOpenAL.java
new file mode 100644
index 0000000..37e09a5
--- /dev/null
+++ b/src/paulscode/sound/libraries/ChannelLWJGLOpenAL.java
@@ -0,0 +1,696 @@
+package paulscode.sound.libraries;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.LinkedList;
+import javax.sound.sampled.AudioFormat;
+
+// From the lwjgl library, http://www.lwjgl.org
+import org.lwjgl.BufferUtils;
+import org.lwjgl.openal.AL10;
+import org.lwjgl.openal.AL11;
+
+import paulscode.sound.Channel;
+import paulscode.sound.SoundSystemConfig;
+
+/**
+ * The ChannelLWJGLOpenAL class is used to reserve a sound-card voice using the
+ * lwjgl binding of OpenAL. Channels can be either normal or streaming
+ * channels.
+ *
+ * This software is based on or using the LWJGL Lightweight Java Gaming
+ * Library available from
+ * http://www.lwjgl.org/.
+ *
+ * LWJGL License:
+ *
+ * Copyright (c) 2002-2008 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.
+ *
+ * SoundSystem LibraryLWJGLOpenAL License:
+ *
+ * You are free to use this library for any purpose, commercial or otherwise.
+ * You may modify this library or source code, and distribute it any way you
+ * like, provided the following conditions are met:
+ *
+ * 1) You must abide by the conditions of the aforementioned LWJGL License.
+ *
+ * 2) You may not falsely claim to be the author of this library or any
+ * unmodified portion of it.
+ *
+ * 3) You may not copyright this library or a modified version of it and then
+ * sue me for copyright infringement.
+ *
+ * 4) If you modify the source code, you must clearly document the changes
+ * made before redistributing the modified source code, so other users know
+ * it is not the original code.
+ *
+ * 5) You are not required to give me credit for this library in any derived
+ * work, but if you do, you must also mention my website:
+ * http://www.paulscode.com
+ *
+ * 6) I the author will not be responsible for any damages (physical,
+ * financial, or otherwise) caused by the use if this library or any part
+ * of it.
+ *
+ * 7) I the author do not guarantee, warrant, or make any representations,
+ * either expressed or implied, regarding the use of this library or any
+ * part of it.
+ *
+ * Author: Paul Lamb
+ *
+ * http://www.paulscode.com
+ *
+ */
+public class ChannelLWJGLOpenAL extends Channel
+{
+/**
+ * OpenAL's IntBuffer identifier for this channel.
+ */
+ public IntBuffer ALSource;
+
+/**
+ * OpenAL data format to use when playing back the assigned source.
+ */
+ public int ALformat; // OpenAL data format
+
+/**
+ * Sample rate (speed) to use for play-back.
+ */
+ public int sampleRate; // sample rate
+
+/**
+ * Miliseconds of buffers previously played (streaming sources).
+ */
+ public float millisPreviouslyPlayed = 0;
+
+/**
+ * Constructor: takes channelType identifier and a handle to the OpenAL
+ * IntBuffer identifier to use for this channel. Possible values for channel
+ * type can be found in the
+ * {@link SoundSystemConfig SoundSystemConfig} class.
+ * @param type Type of channel (normal or streaming).
+ * @param src Handle to the OpenAL source identifier.
+ */
+ public ChannelLWJGLOpenAL( int type, IntBuffer src )
+ {
+ super( type );
+ libraryType = LibraryLWJGLOpenAL.class;
+ ALSource = src;
+ }
+
+/**
+ * Empties the streamBuffers list, stops and deletes the ALSource, shuts the
+ * channel down, and removes references to all instantiated objects.
+ */
+ @Override
+ public void cleanup()
+ {
+ if( ALSource != null )
+ {
+ try
+ {
+ // Stop playing the source:
+ AL10.alSourceStopv( ALSource );
+ AL10.alGetError();
+ }
+ catch( Exception e )
+ {}
+ try
+ {
+ // Delete the source:
+ AL10.alDeleteSources( ALSource );
+ AL10.alGetError();
+ }
+ catch( Exception e )
+ {}
+ ALSource.clear();
+ }
+ ALSource = null;
+
+ super.cleanup();
+ }
+
+/**
+ * Attaches an OpenAL sound-buffer identifier for the sound data to be played
+ * back for a normal source.
+ * @param buf Intbuffer identifier for the sound data to play.
+ * @return False if an error occurred.
+ */
+ public boolean attachBuffer( IntBuffer buf )
+ {
+ // A sound buffer can only be attached to a normal source:
+ if( errorCheck( channelType != SoundSystemConfig.TYPE_NORMAL,
+ "Sound buffers may only be attached to normal " +
+ "sources." ) )
+ return false;
+
+ // send the sound buffer to the channel:
+ AL10.alSourcei( ALSource.get( 0 ), AL10.AL_BUFFER,
+ buf.get(0) );
+
+
+ // save the format for later, for determining milliseconds played
+ if( attachedSource != null && attachedSource.soundBuffer != null &&
+ attachedSource.soundBuffer.audioFormat != null )
+ setAudioFormat( attachedSource.soundBuffer.audioFormat );
+
+ // Check for errors and return:
+ return checkALError();
+ }
+/**
+ * Sets the channel up to receive the specified audio format.
+ * @param audioFormat Format to use when playing the stream data.
+ */
+ @Override
+ public void setAudioFormat( AudioFormat audioFormat )
+ {
+ int soundFormat = 0;
+ if( audioFormat.getChannels() == 1 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method " +
+ "'setAudioFormat'" );
+ return;
+ }
+ }
+ else if( audioFormat.getChannels() == 2 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method " +
+ "'setAudioFormat'" );
+ return;
+ }
+ }
+ else
+ {
+ errorMessage( "Audio data neither mono nor stereo in " +
+ "method 'setAudioFormat'" );
+ return;
+ }
+ ALformat = soundFormat;
+ sampleRate = (int) audioFormat.getSampleRate();
+ }
+/**
+ * Sets the channel up to receive the specified OpenAL audio format and sample
+ * rate.
+ * @param format Format to use.
+ * @param rate Sample rate (speed) to use.
+ */
+ public void setFormat( int format, int rate )
+ {
+ ALformat = format;
+ sampleRate = rate;
+ }
+
+/**
+ * Queues up the initial byte[] buffers of data to be streamed.
+ * @param bufferList List of the first buffers to be played for a streaming source.
+ * @return False if problem occurred or if end of stream was reached.
+ */
+ @Override
+ public boolean preLoadBuffers( LinkedList bufferList )
+ {
+ // Stream buffers can only be queued for streaming sources:
+ if( errorCheck( channelType != SoundSystemConfig.TYPE_STREAMING,
+ "Buffers may only be queued for streaming sources." ) )
+ return false;
+
+ if( errorCheck( bufferList == null,
+ "Buffer List null in method 'preLoadBuffers'" ) )
+ return false;
+
+ IntBuffer streamBuffers;
+
+ // Remember if the channel was playing:
+ boolean playing = playing();
+ // stop the channel if it is playing:
+ if( playing )
+ {
+ AL10.alSourceStop( ALSource.get( 0 ) );
+ checkALError();
+ }
+ // Clear out any previously queued buffers:
+ int processed = AL10.alGetSourcei( ALSource.get( 0 ),
+ AL10.AL_BUFFERS_PROCESSED );
+ if( processed > 0 )
+ {
+ streamBuffers = BufferUtils.createIntBuffer( processed );
+ AL10.alGenBuffers( streamBuffers );
+ if( errorCheck( checkALError(),
+ "Error clearing stream buffers in method 'preLoadBuffers'" ) )
+ return false;
+ AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), streamBuffers );
+ if( errorCheck( checkALError(),
+ "Error unqueuing stream buffers in method 'preLoadBuffers'" ) )
+ return false;
+ }
+
+ // restart the channel if it was previously playing:
+ if( playing )
+ {
+ AL10.alSourcePlay( ALSource.get( 0 ) );
+ checkALError();
+ }
+
+ streamBuffers = BufferUtils.createIntBuffer( bufferList.size() );
+ AL10.alGenBuffers( streamBuffers );
+ if( errorCheck( checkALError(),
+ "Error generating stream buffers in method 'preLoadBuffers'" ) )
+ return false;
+
+ ByteBuffer byteBuffer = null;
+ for( int i = 0; i < bufferList.size(); i++ )
+ {
+ //byteBuffer = ByteBuffer.wrap( bufferList.get(i), 0,
+ // bufferList.get(i).length );
+ byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer(
+ bufferList.get(i).length ).put( bufferList.get( i ) ).flip();
+
+ try
+ {
+ AL10.alBufferData( streamBuffers.get(i), ALformat, byteBuffer,
+ sampleRate );
+ }
+ catch( Exception e )
+ {
+ errorMessage( "Error creating buffers in method " +
+ "'preLoadBuffers'" );
+ printStackTrace( e );
+ return false;
+ }
+ if( errorCheck( checkALError(),
+ "Error creating buffers in method 'preLoadBuffers'" ) )
+ return false;
+
+ }
+
+ try
+ {
+ AL10.alSourceQueueBuffers( ALSource.get( 0 ), streamBuffers );
+ }
+ catch( Exception e )
+ {
+ errorMessage( "Error queuing buffers in method 'preLoadBuffers'" );
+ printStackTrace( e );
+ return false;
+ }
+ if( errorCheck( checkALError(),
+ "Error queuing buffers in method 'preLoadBuffers'" ) )
+ return false;
+
+ AL10.alSourcePlay( ALSource.get( 0 ) );
+ if( errorCheck( checkALError(),
+ "Error playing source in method 'preLoadBuffers'" ) )
+ return false;
+
+ // Success:
+ return true;
+ }
+
+/**
+ * Queues up a byte[] buffer of data to be streamed.
+ * @param buffer The next buffer to be played for a streaming source.
+ * @return False if an error occurred or if the channel is shutting down.
+ */
+ @Override
+ public boolean queueBuffer( byte[] buffer )
+ {
+ // Stream buffers can only be queued for streaming sources:
+ if( errorCheck( channelType != SoundSystemConfig.TYPE_STREAMING,
+ "Buffers may only be queued for streaming sources." ) )
+ return false;
+
+ //ByteBuffer byteBuffer = ByteBuffer.wrap( buffer, 0, buffer.length );
+ ByteBuffer byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer(
+ buffer.length ).put( buffer ).flip();
+
+ IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 );
+
+ AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), intBuffer );
+ if( checkALError() )
+ return false;
+
+ if( AL10.alIsBuffer( intBuffer.get( 0 ) ) )
+ millisPreviouslyPlayed += millisInBuffer( intBuffer.get( 0 ) );
+ checkALError();
+
+ AL10.alBufferData( intBuffer.get(0), ALformat, byteBuffer, sampleRate );
+ if( checkALError() )
+ return false;
+
+ AL10.alSourceQueueBuffers( ALSource.get( 0 ), intBuffer );
+ if( checkALError() )
+ return false;
+
+ return true;
+ }
+
+/**
+ * Feeds raw data to the stream.
+ * @param buffer Buffer containing raw audio data to stream.
+ * @return Number of prior buffers that have been processed., or -1 if error.
+ */
+ @Override
+ public int feedRawAudioData( byte[] buffer )
+ {
+ // Stream buffers can only be queued for streaming sources:
+ if( errorCheck( channelType != SoundSystemConfig.TYPE_STREAMING,
+ "Raw audio data can only be fed to streaming sources." ) )
+ return -1;
+
+ //ByteBuffer byteBuffer = ByteBuffer.wrap( buffer, 0, buffer.length );
+ ByteBuffer byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer(
+ buffer.length ).put( buffer ).flip();
+
+ IntBuffer intBuffer;
+
+ // Clear out any previously queued buffers:
+ int processed = AL10.alGetSourcei( ALSource.get( 0 ),
+ AL10.AL_BUFFERS_PROCESSED );
+ if( processed > 0 )
+ {
+ intBuffer = BufferUtils.createIntBuffer( processed );
+ AL10.alGenBuffers( intBuffer );
+ if( errorCheck( checkALError(),
+ "Error clearing stream buffers in method 'feedRawAudioData'" ) )
+ return -1;
+ AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), intBuffer );
+ if( errorCheck( checkALError(),
+ "Error unqueuing stream buffers in method 'feedRawAudioData'" ) )
+ return -1;
+ int i;
+ intBuffer.rewind();
+ while( intBuffer.hasRemaining() )
+ {
+ i = intBuffer.get();
+ if( AL10.alIsBuffer( i ) )
+ {
+ millisPreviouslyPlayed += millisInBuffer( i );
+ }
+ checkALError();
+ }
+ AL10.alDeleteBuffers( intBuffer );
+ checkALError();
+ }
+ intBuffer = BufferUtils.createIntBuffer( 1 );
+ AL10.alGenBuffers( intBuffer );
+ if( errorCheck( checkALError(),
+ "Error generating stream buffers in method 'preLoadBuffers'" ) )
+ return -1;
+
+ AL10.alBufferData( intBuffer.get(0), ALformat, byteBuffer, sampleRate );
+ if( checkALError() )
+ return -1;
+
+ AL10.alSourceQueueBuffers( ALSource.get( 0 ), intBuffer );
+ if( checkALError() )
+ return -1;
+
+ if( attachedSource != null && attachedSource.channel == this &&
+ attachedSource.active() )
+ {
+ // restart the channel if it was previously playing:
+ if( !playing() )
+ {
+ AL10.alSourcePlay( ALSource.get( 0 ) );
+ checkALError();
+ }
+ }
+
+ return processed;
+ }
+
+/**
+ * Returns the number of milliseconds of audio contained in specified buffer.
+ * @return milliseconds, or 0 if unable to calculate.
+ */
+ public float millisInBuffer( int alBufferi )
+ {
+ return( ( (float) AL10.alGetBufferi( alBufferi, AL10.AL_SIZE ) /
+ (float) AL10.alGetBufferi( alBufferi, AL10.AL_CHANNELS ) /
+ ( (float) AL10.alGetBufferi( alBufferi, AL10.AL_BITS ) / 8.0f ) /
+ (float) sampleRate ) * 1000 );
+ }
+
+/**
+ * Calculates the number of milliseconds since the channel began playing.
+ * @return Milliseconds, or -1 if unable to calculate.
+ */
+ @Override
+ public float millisecondsPlayed()
+ {
+ // get number of samples played in current buffer
+ float offset = (float)AL10.alGetSourcei( ALSource.get( 0 ),
+ AL11.AL_BYTE_OFFSET );
+
+ float bytesPerFrame = 1f;
+ switch( ALformat )
+ {
+ case AL10.AL_FORMAT_MONO8 :
+ bytesPerFrame = 1f;
+ break;
+ case AL10.AL_FORMAT_MONO16 :
+ bytesPerFrame = 2f;
+ break;
+ case AL10.AL_FORMAT_STEREO8 :
+ bytesPerFrame = 2f;
+ break;
+ case AL10.AL_FORMAT_STEREO16 :
+ bytesPerFrame = 4f;
+ break;
+ default :
+ break;
+ }
+
+ offset = ( ( (float) offset / bytesPerFrame ) / (float) sampleRate )
+ * 1000;
+
+ // add the milliseconds from stream-buffers that played previously
+ if( channelType == SoundSystemConfig.TYPE_STREAMING )
+ offset += millisPreviouslyPlayed;
+
+ // Return millis played:
+ return( offset );
+ }
+
+/**
+ * Returns the number of queued byte[] buffers that have finished playing.
+ * @return Number of buffers processed.
+ */
+ @Override
+ public int buffersProcessed()
+ {
+ // Only streaming sources process buffers:
+ if( channelType != SoundSystemConfig.TYPE_STREAMING )
+ return 0;
+
+ // determine how many have been processed:
+ int processed = AL10.alGetSourcei( ALSource.get( 0 ),
+ AL10.AL_BUFFERS_PROCESSED );
+
+ // Check for errors:
+ if( checkALError() )
+ return 0;
+
+ // Return how many were processed:
+ return processed;
+ }
+
+/**
+ * Dequeues all previously queued data.
+ */
+ @Override
+ public void flush()
+ {
+ // Only a streaming source can be flushed, because only streaming
+ // sources have queued buffers:
+ if( channelType != SoundSystemConfig.TYPE_STREAMING )
+ return;
+
+ // determine how many buffers have been queued:
+ int queued = AL10.alGetSourcei( ALSource.get( 0 ),
+ AL10.AL_BUFFERS_QUEUED );
+ // Check for errors:
+ if( checkALError() )
+ return;
+
+ IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 );
+ while( queued > 0 )
+ {
+ try
+ {
+ AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), intBuffer );
+ }
+ catch( Exception e )
+ {
+ return;
+ }
+ if( checkALError() )
+ return;
+ queued--;
+ }
+ millisPreviouslyPlayed = 0;
+ }
+
+/**
+ * Stops the channel, dequeues any queued data, and closes the channel.
+ */
+ @Override
+ public void close()
+ {
+ try
+ {
+ AL10.alSourceStop( ALSource.get( 0 ) );
+ AL10.alGetError();
+ }
+ catch( Exception e )
+ {}
+
+ if( channelType == SoundSystemConfig.TYPE_STREAMING )
+ flush();
+ }
+
+/**
+ * Plays the currently attached normal source, opens this channel up for
+ * streaming, or resumes playback if this channel was paused.
+ */
+ @Override
+ public void play()
+ {
+ AL10.alSourcePlay( ALSource.get( 0 ) );
+ checkALError();
+ }
+
+/**
+ * Temporarily stops playback for this channel.
+ */
+ @Override
+ public void pause()
+ {
+ AL10.alSourcePause( ALSource.get( 0 ) );
+ checkALError();
+ }
+
+/**
+ * Stops playback for this channel and rewinds the attached source to the
+ * beginning.
+ */
+ @Override
+ public void stop()
+ {
+ AL10.alSourceStop( ALSource.get( 0 ) );
+ if( !checkALError() )
+ millisPreviouslyPlayed = 0;
+ }
+
+/**
+ * Rewinds the attached source to the beginning. Stops the source if it was
+ * paused.
+ */
+ @Override
+ public void rewind()
+ {
+ // rewinding for streaming sources is handled elsewhere
+ if( channelType == SoundSystemConfig.TYPE_STREAMING )
+ return;
+
+ AL10.alSourceRewind( ALSource.get( 0 ) );
+ if( !checkALError() )
+ millisPreviouslyPlayed = 0;
+ }
+
+
+/**
+ * Used to determine if a channel is actively playing a source. This method
+ * will return false if the channel is paused or stopped and when no data is
+ * queued to be streamed.
+ * @return True if this channel is playing a source.
+ */
+ @Override
+ public boolean playing()
+ {
+ int state = AL10.alGetSourcei( ALSource.get( 0 ),
+ AL10.AL_SOURCE_STATE );
+ if( checkALError() )
+ return false;
+
+ return( state == AL10.AL_PLAYING );
+ }
+
+/**
+ * Checks for OpenAL errors, and prints a message if there is an error.
+ * @return True if there was an error, False if not.
+ */
+ private boolean checkALError()
+ {
+ switch( AL10.alGetError() )
+ {
+ case AL10.AL_NO_ERROR:
+ return false;
+ case AL10.AL_INVALID_NAME:
+ errorMessage( "Invalid name parameter." );
+ return true;
+ case AL10.AL_INVALID_ENUM:
+ errorMessage( "Invalid parameter." );
+ return true;
+ case AL10.AL_INVALID_VALUE:
+ errorMessage( "Invalid enumerated parameter value." );
+ return true;
+ case AL10.AL_INVALID_OPERATION:
+ errorMessage( "Illegal call." );
+ return true;
+ case AL10.AL_OUT_OF_MEMORY:
+ errorMessage( "Unable to allocate memory." );
+ return true;
+ default:
+ errorMessage( "An unrecognized error occurred." );
+ return true;
+ }
+ }
+}
diff --git a/src/paulscode/sound/libraries/LibraryLWJGLOpenAL.java b/src/paulscode/sound/libraries/LibraryLWJGLOpenAL.java
new file mode 100644
index 0000000..daa52bd
--- /dev/null
+++ b/src/paulscode/sound/libraries/LibraryLWJGLOpenAL.java
@@ -0,0 +1,1150 @@
+package paulscode.sound.libraries;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.FloatBuffer;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+import javax.sound.sampled.AudioFormat;
+
+// From the lwjgl library, http://www.lwjgl.org
+import org.lwjgl.BufferUtils;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.openal.*;
+
+import org.lwjgl.system.MemoryUtil;
+import paulscode.sound.Channel;
+import paulscode.sound.FilenameURL;
+import paulscode.sound.ICodec;
+import paulscode.sound.Library;
+import paulscode.sound.ListenerData;
+import paulscode.sound.SoundBuffer;
+import paulscode.sound.SoundSystemConfig;
+import paulscode.sound.SoundSystemException;
+import paulscode.sound.Source;
+
+/**
+ * The LibraryLWJGLOpenAL class interfaces the lwjgl binding of OpenAL.
+ *
+ * This software is based on or using the LWJGL Lightweight Java Gaming
+ * Library available from
+ * http://www.lwjgl.org/.
+ *
+ * LWJGL License:
+ *
+ * Copyright (c) 2002-2008 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.
+ *
+ * SoundSystem LibraryLWJGLOpenAL License:
+ *
+ * You are free to use this library for any purpose, commercial or otherwise.
+ * You may modify this library or source code, and distribute it any way you
+ * like, provided the following conditions are met:
+ *
+ * 1) You must abide by the conditions of the aforementioned LWJGL License.
+ *
+ * 2) You may not falsely claim to be the author of this library or any
+ * unmodified portion of it.
+ *
+ * 3) You may not copyright this library or a modified version of it and then
+ * sue me for copyright infringement.
+ *
+ * 4) If you modify the source code, you must clearly document the changes
+ * made before redistributing the modified source code, so other users know
+ * it is not the original code.
+ *
+ * 5) You are not required to give me credit for this library in any derived
+ * work, but if you do, you must also mention my website:
+ * http://www.paulscode.com
+ *
+ * 6) I the author will not be responsible for any damages (physical,
+ * financial, or otherwise) caused by the use if this library or any part
+ * of it.
+ *
+ * 7) I the author do not guarantee, warrant, or make any representations,
+ * either expressed or implied, regarding the use of this library or any
+ * part of it.
+ *
+ * Author: Paul Lamb
+ *
+ * http://www.paulscode.com
+ *
+ */
+public class LibraryLWJGLOpenAL extends Library
+{
+/**
+ * Used to return a current value from one of the synchronized
+ * boolean-interface methods.
+ */
+ private static final boolean GET = false;
+/**
+ * Used to set the value in one of the synchronized boolean-interface methods.
+ */
+ private static final boolean SET = true;
+/**
+ * Used when a parameter for one of the synchronized boolean-interface methods
+ * is not aplicable.
+ */
+ private static final boolean XXX = false;
+
+/**
+ * Position of the listener in 3D space.
+ */
+ private FloatBuffer listenerPositionAL = null;
+/**
+ * Information about the listener's orientation.
+ */
+ private FloatBuffer listenerOrientation = null;
+/**
+ * Velocity of the listener.
+ */
+ private FloatBuffer listenerVelocity = null;
+/**
+ * Map containing OpenAL identifiers for sound buffers.
+ */
+ private HashMap ALBufferMap = null;
+
+/**
+ * Whether or not the AL_PITCH control is supported.
+ */
+ private static boolean alPitchSupported = true;
+
+/**
+ * Constructor: Instantiates the source map, buffer map and listener
+ * information. Also sets the library type to
+ * SoundSystemConfig.LIBRARY_OPENAL
+ */
+ public LibraryLWJGLOpenAL() throws SoundSystemException
+ {
+ super();
+ ALBufferMap = new HashMap();
+ reverseByteOrder = true;
+ }
+
+/**
+ * Initializes OpenAL, creates the listener, and grabs up audio channels.
+ */
+ @Override
+ public void init() throws SoundSystemException
+ {
+ boolean errors = false; // set to 'true' if error(s) occur:
+
+ try
+ {
+ // Try and create the sound system:
+ long device = ALC10.alcOpenDevice((ByteBuffer) null);
+ if (device == MemoryUtil.NULL) {
+ throw new IllegalStateException("Failed to open the default OpenAL device.");
+ }
+ ALCCapabilities deviceCaps = ALC.createCapabilities(device);
+ long context = ALC10.alcCreateContext(device, (IntBuffer) null);
+ if (context == MemoryUtil.NULL) {
+ throw new IllegalStateException("Failed to create OpenAL context.");
+ }
+ ALC10.alcMakeContextCurrent(context);
+ AL.createCapabilities(deviceCaps);
+ //AL.create();
+ errors = checkALError();
+ }
+ catch( java.lang.Exception e )
+ {
+ // There was an exception
+ errorMessage( "Unable to initialize OpenAL. Probable cause: " +
+ "OpenAL not supported." );
+ printStackTrace( e );
+ throw new Exception( e.getMessage(),
+ Exception.CREATE );
+ }
+
+ // Let user know if the library loaded properly
+ if( errors )
+ importantMessage( "OpenAL did not initialize properly!" );
+ else
+ message( "OpenAL initialized." );
+
+ // Listener is at the origin, facing along the z axis, no velocity:
+ listenerPositionAL = BufferUtils.createFloatBuffer( 3 ).put(
+ new float[] { listener.position.x,
+ listener.position.y,
+ listener.position.z } );
+ listenerOrientation = BufferUtils.createFloatBuffer( 6 ).put (
+ new float[] { listener.lookAt.x, listener.lookAt.y,
+ listener.lookAt.z, listener.up.x, listener.up.y,
+ listener.up.z } );
+ listenerVelocity = BufferUtils.createFloatBuffer( 3 ).put (
+ new float[] { 0.0f, 0.0f, 0.0f } );
+
+ // Flip the buffers, so they can be used:
+ listenerPositionAL.flip();
+ listenerOrientation.flip();
+ listenerVelocity.flip();
+
+ // Pass the buffers to the sound system, and check for potential errors:
+ AL10.alListenerfv( AL10.AL_POSITION, listenerPositionAL );
+ errors = checkALError() || errors;
+ AL10.alListenerfv( AL10.AL_ORIENTATION, listenerOrientation );
+ errors = checkALError() || errors;
+ AL10.alListenerfv( AL10.AL_VELOCITY, listenerVelocity );
+ errors = checkALError() || errors;
+
+ AL10.alDopplerFactor( SoundSystemConfig.getDopplerFactor() );
+ errors = checkALError() || errors;
+
+ AL10.alDopplerVelocity( SoundSystemConfig.getDopplerVelocity() );
+ errors = checkALError() || errors;
+
+ // Let user know what caused the above error messages:
+ if( errors )
+ {
+ importantMessage( "OpenAL did not initialize properly!" );
+ throw new Exception( "Problem encountered " +
+ "while loading OpenAL or " +
+ "creating the listener. " +
+ "Probable cause: OpenAL not " +
+ "supported",
+ Exception.CREATE );
+ }
+
+ super.init();
+
+ // Check if we can use the AL_PITCH control:
+ ChannelLWJGLOpenAL channel = (ChannelLWJGLOpenAL)
+ normalChannels.get( 1 );
+ try
+ {
+ AL10.alSourcef( channel.ALSource.get( 0 ),
+ AL10.AL_PITCH, 1.0f );
+ if( checkALError() )
+ {
+ alPitchSupported( SET, false );
+ throw new Exception( "OpenAL: AL_PITCH not " +
+ "supported.", Exception.NO_AL_PITCH );
+ }
+ else
+ {
+ alPitchSupported( SET, true );
+ }
+ }
+ catch( java.lang.Exception e )
+ {
+ alPitchSupported( SET, false );
+ throw new Exception( "OpenAL: AL_PITCH not " +
+ "supported.", Exception.NO_AL_PITCH );
+ }
+ }
+
+/**
+ * Checks if the OpenAL library type is compatible.
+ * @return True or false.
+ */
+ public static boolean libraryCompatible()
+ {
+ if( AL.getCapabilities() != null)
+ return true;
+
+ try
+ {
+ long device = ALC10.alcOpenDevice((ByteBuffer) null);
+ if (device == MemoryUtil.NULL) {
+ throw new IllegalStateException("Failed to open the default OpenAL device.");
+ }
+ ALCCapabilities deviceCaps = ALC.createCapabilities(device);
+ long context = ALC10.alcCreateContext(device, (IntBuffer) null);
+ if (context == MemoryUtil.NULL) {
+ throw new IllegalStateException("Failed to create OpenAL context.");
+ }
+ ALC10.alcMakeContextCurrent(context);
+ AL.createCapabilities(deviceCaps);
+ //AL.create();
+ }
+ catch( java.lang.Exception e )
+ {
+ return false;
+ }
+
+ try
+ {
+ AL.setCurrentProcess(null);
+ //AL.destroy();
+ }
+ catch( java.lang.Exception e )
+ {}
+
+ return true;
+ }
+
+/**
+ * Creates a new channel of the specified type (normal or streaming). Possible
+ * values for channel type can be found in the
+ * {@link SoundSystemConfig SoundSystemConfig} class.
+ * @param type Type of channel.
+ */
+ @Override
+ protected Channel createChannel( int type )
+ {
+ ChannelLWJGLOpenAL channel;
+ IntBuffer ALSource;
+
+ ALSource = BufferUtils.createIntBuffer( 1 );
+ try
+ {
+ AL10.alGenSources( ALSource );
+ }
+ catch( java.lang.Exception e )
+ {
+ AL10.alGetError();
+ return null; // no more voices left
+ }
+
+ if( AL10.alGetError() != AL10.AL_NO_ERROR )
+ return null;
+
+ channel = new ChannelLWJGLOpenAL( type, ALSource );
+ return channel;
+ }
+
+ /**
+ * Stops all sources, shuts down OpenAL, and removes references to all
+ * instantiated objects.
+ */
+ @Override
+ public void cleanup()
+ {
+ super.cleanup();
+
+ Set keys = bufferMap.keySet();
+ Iterator iter = keys.iterator();
+ String filename;
+ IntBuffer buffer;
+
+ // loop through and clear all sound buffers:
+ while( iter.hasNext() )
+ {
+ filename = iter.next();
+ buffer = ALBufferMap.get( filename );
+ if( buffer != null )
+ {
+ AL10.alDeleteBuffers( buffer );
+ checkALError();
+ buffer.clear();
+ }
+ }
+
+ bufferMap.clear();
+ //AL.destroy();
+ AL.setCurrentProcess(null);
+
+ bufferMap = null;
+ listenerPositionAL = null;
+ listenerOrientation = null;
+ listenerVelocity = null;
+ }
+
+/**
+ * Pre-loads a sound into memory.
+ * @param filenameURL Filename/URL of the sound file to load.
+ * @return True if the sound loaded properly.
+ */
+ @Override
+ public boolean loadSound( FilenameURL filenameURL )
+ {
+ // Make sure the buffer map exists:
+ if( bufferMap == null )
+ {
+ bufferMap = new HashMap();
+ importantMessage( "Buffer Map was null in method 'loadSound'" );
+ }
+ // Make sure the OpenAL buffer map exists:
+ if( ALBufferMap == null )
+ {
+ ALBufferMap = new HashMap();
+ importantMessage( "Open AL Buffer Map was null in method" +
+ "'loadSound'" );
+ }
+
+ // make sure they gave us a filename:
+ if( errorCheck( filenameURL == null,
+ "Filename/URL not specified in method 'loadSound'" ) )
+ return false;
+
+ // check if it is already loaded:
+ if( bufferMap.get( filenameURL.getFilename() ) != null )
+ return true;
+
+ ICodec codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );
+ if( errorCheck( codec == null, "No codec found for file '" +
+ filenameURL.getFilename() +
+ "' in method 'loadSound'" ) )
+ return false;
+ codec.reverseByteOrder( true );
+
+ URL url = filenameURL.getURL();
+ if( errorCheck( url == null, "Unable to open file '" +
+ filenameURL.getFilename() +
+ "' in method 'loadSound'" ) )
+ return false;
+
+ codec.initialize( url );
+ SoundBuffer buffer = codec.readAll();
+ codec.cleanup();
+ codec = null;
+ if( errorCheck( buffer == null,
+ "Sound buffer null in method 'loadSound'" ) )
+ return false;
+
+ bufferMap.put( filenameURL.getFilename(), buffer );
+
+ AudioFormat audioFormat = buffer.audioFormat;
+ int soundFormat = 0;
+ if( audioFormat.getChannels() == 1 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method 'loadSound'" );
+ return false;
+ }
+ }
+ else if( audioFormat.getChannels() == 2 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method 'loadSound'" );
+ return false;
+ }
+ }
+ else
+ {
+ errorMessage( "File neither mono nor stereo in method " +
+ "'loadSound'" );
+ return false;
+ }
+
+ IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 );
+ AL10.alGenBuffers( intBuffer );
+ if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR,
+ "alGenBuffers error when loading " +
+ filenameURL.getFilename() ) )
+ return false;
+
+// AL10.alBufferData( intBuffer.get( 0 ), soundFormat,
+// ByteBuffer.wrap( buffer.audioData ),
+// (int) audioFormat.getSampleRate() );
+ AL10.alBufferData( intBuffer.get( 0 ), soundFormat,
+ (ByteBuffer) BufferUtils.createByteBuffer(
+ buffer.audioData.length ).put(
+ buffer.audioData ).flip(),
+ (int) audioFormat.getSampleRate() );
+
+ if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR,
+ "alBufferData error when loading " +
+ filenameURL.getFilename() ) )
+
+
+ if( errorCheck( intBuffer == null,
+ "Sound buffer was not created for " +
+ filenameURL.getFilename() ) )
+ return false;
+
+ ALBufferMap.put( filenameURL.getFilename(), intBuffer );
+
+ return true;
+ }
+
+/**
+ * Saves the specified sample data, under the specified identifier. This
+ * identifier can be later used in place of 'filename' parameters to reference
+ * the sample data.
+ * @param buffer the sample data and audio format to save.
+ * @param identifier What to call the sample.
+ * @return True if there weren't any problems.
+ */
+ @Override
+ public boolean loadSound( SoundBuffer buffer, String identifier )
+ {
+ // Make sure the buffer map exists:
+ if( bufferMap == null )
+ {
+ bufferMap = new HashMap();
+ importantMessage( "Buffer Map was null in method 'loadSound'" );
+ }
+ // Make sure the OpenAL buffer map exists:
+ if( ALBufferMap == null )
+ {
+ ALBufferMap = new HashMap();
+ importantMessage( "Open AL Buffer Map was null in method" +
+ "'loadSound'" );
+ }
+
+ // make sure they gave us an identifier:
+ if( errorCheck( identifier == null,
+ "Identifier not specified in method 'loadSound'" ) )
+ return false;
+
+ // check if it is already loaded:
+ if( bufferMap.get( identifier ) != null )
+ return true;
+
+ if( errorCheck( buffer == null,
+ "Sound buffer null in method 'loadSound'" ) )
+ return false;
+
+ bufferMap.put( identifier, buffer );
+
+ AudioFormat audioFormat = buffer.audioFormat;
+ int soundFormat = 0;
+ if( audioFormat.getChannels() == 1 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method 'loadSound'" );
+ return false;
+ }
+ }
+ else if( audioFormat.getChannels() == 2 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method 'loadSound'" );
+ return false;
+ }
+ }
+ else
+ {
+ errorMessage( "File neither mono nor stereo in method " +
+ "'loadSound'" );
+ return false;
+ }
+
+ IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 );
+ AL10.alGenBuffers( intBuffer );
+ if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR,
+ "alGenBuffers error when saving " +
+ identifier ) )
+ return false;
+
+// AL10.alBufferData( intBuffer.get( 0 ), soundFormat,
+// ByteBuffer.wrap( buffer.audioData ),
+// (int) audioFormat.getSampleRate() );
+ AL10.alBufferData( intBuffer.get( 0 ), soundFormat,
+ (ByteBuffer) BufferUtils.createByteBuffer(
+ buffer.audioData.length ).put(
+ buffer.audioData ).flip(),
+ (int) audioFormat.getSampleRate() );
+
+ if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR,
+ "alBufferData error when saving " +
+ identifier ) )
+
+
+ if( errorCheck( intBuffer == null,
+ "Sound buffer was not created for " +
+ identifier ) )
+ return false;
+
+ ALBufferMap.put( identifier, intBuffer );
+
+ return true;
+ }
+
+/**
+ * Removes a pre-loaded sound from memory. This is a good method to use for
+ * freeing up memory after a large sound file is no longer needed. NOTE: the
+ * source will remain in memory after this method has been called, for as long
+ * as the sound is attached to an existing source.
+ * @param filename Filename/identifier of the sound file to unload.
+ */
+ @Override
+ public void unloadSound( String filename )
+ {
+ ALBufferMap.remove( filename );
+ super.unloadSound( filename );
+ }
+
+ /**
+ * Sets the overall volume to the specified value, affecting all sources.
+ * @param value New volume, float value ( 0.0f - 1.0f ).
+ */
+ @Override
+ public void setMasterVolume( float value )
+ {
+ super.setMasterVolume( value );
+
+ AL10.alListenerf( AL10.AL_GAIN, value );
+ checkALError();
+ }
+
+/**
+ * Creates a new source and places it into the source map.
+ * @param priority Setting this to true will prevent other sounds from overriding this one.
+ * @param toStream Setting this to true will load the sound in pieces rather than all at once.
+ * @param toLoop Should this source loop, or play only once.
+ * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
+ * @param filenameURL Filename/URL of the sound file to play at this source.
+ * @param x X position for this source.
+ * @param y Y position for this source.
+ * @param z Z position for this source.
+ * @param attModel Attenuation model to use.
+ * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".
+ */
+ @Override
+ public void newSource( boolean priority, boolean toStream, boolean toLoop,
+ String sourcename, FilenameURL filenameURL, float x,
+ float y, float z, int attModel, float distOrRoll )
+ {
+ IntBuffer myBuffer = null;
+ if( !toStream )
+ {
+ // Grab the sound buffer for this file:
+ myBuffer = ALBufferMap.get( filenameURL.getFilename() );
+
+ // if not found, try loading it:
+ if( myBuffer == null )
+ {
+ if( !loadSound( filenameURL ) )
+ {
+ errorMessage( "Source '" + sourcename + "' was not created "
+ + "because an error occurred while loading "
+ + filenameURL.getFilename() );
+ return;
+ }
+ }
+
+ // try and grab the sound buffer again:
+ myBuffer = ALBufferMap.get( filenameURL.getFilename() );
+ // see if it was there this time:
+ if( myBuffer == null )
+ {
+ errorMessage( "Source '" + sourcename + "' was not created "
+ + "because a sound buffer was not found for "
+ + filenameURL.getFilename() );
+ return;
+ }
+ }
+ SoundBuffer buffer = null;
+
+ if( !toStream )
+ {
+ // Grab the audio data for this file:
+ buffer = bufferMap.get( filenameURL.getFilename() );
+ // if not found, try loading it:
+ if( buffer == null )
+ {
+ if( !loadSound( filenameURL ) )
+ {
+ errorMessage( "Source '" + sourcename + "' was not created "
+ + "because an error occurred while loading "
+ + filenameURL.getFilename() );
+ return;
+ }
+ }
+ // try and grab the sound buffer again:
+ buffer = bufferMap.get( filenameURL.getFilename() );
+ // see if it was there this time:
+ if( buffer == null )
+ {
+ errorMessage( "Source '" + sourcename + "' was not created "
+ + "because audio data was not found for "
+ + filenameURL.getFilename() );
+ return;
+ }
+ }
+
+ sourceMap.put( sourcename,
+ new SourceLWJGLOpenAL( listenerPositionAL, myBuffer,
+ priority, toStream, toLoop,
+ sourcename, filenameURL, buffer, x,
+ y, z, attModel, distOrRoll,
+ false ) );
+ }
+
+ /**
+ * Opens a direct line for streaming audio data.
+ * @param audioFormat Format that the data will be in.
+ * @param priority Setting this to true will prevent other sounds from overriding this one.
+ * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
+ * @param x X position for this source.
+ * @param y Y position for this source.
+ * @param z Z position for this source.
+ * @param attModel Attenuation model to use.
+ * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".
+ */
+ @Override
+ public void rawDataStream( AudioFormat audioFormat, boolean priority,
+ String sourcename, float x, float y,
+ float z, int attModel, float distOrRoll )
+ {
+ sourceMap.put( sourcename,
+ new SourceLWJGLOpenAL( listenerPositionAL, audioFormat,
+ priority, sourcename, x, y, z,
+ attModel, distOrRoll ) );
+ }
+
+/**
+ * Creates and immediately plays a new source.
+ * @param priority Setting this to true will prevent other sounds from overriding this one.
+ * @param toStream Setting this to true will load the sound in pieces rather than all at once.
+ * @param toLoop Should this source loop, or play only once.
+ * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
+ * @param filenameURL Filename/URL of the sound file to play at this source.
+ * @param x X position for this source.
+ * @param y Y position for this source.
+ * @param z Z position for this source.
+ * @param attModel Attenuation model to use.
+ * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".
+ * @param temporary Whether or not this source should be removed after it finishes playing.
+ */
+ @Override
+ public void quickPlay( boolean priority, boolean toStream, boolean toLoop,
+ String sourcename, FilenameURL filenameURL, float x,
+ float y, float z, int attModel, float distOrRoll,
+ boolean temporary )
+ {
+ IntBuffer myBuffer = null;
+ if( !toStream )
+ {
+ // Grab the sound buffer for this file:
+ myBuffer = ALBufferMap.get( filenameURL.getFilename() );
+ // if not found, try loading it:
+ if( myBuffer == null )
+ loadSound( filenameURL );
+ // try and grab the sound buffer again:
+ myBuffer = ALBufferMap.get( filenameURL.getFilename() );
+ // see if it was there this time:
+ if( myBuffer == null )
+ {
+ errorMessage( "Sound buffer was not created for " +
+ filenameURL.getFilename() );
+ return;
+ }
+ }
+
+ SoundBuffer buffer = null;
+
+ if( !toStream )
+ {
+ // Grab the sound buffer for this file:
+ buffer = bufferMap.get( filenameURL.getFilename() );
+ // if not found, try loading it:
+ if( buffer == null )
+ {
+ if( !loadSound( filenameURL ) )
+ {
+ errorMessage( "Source '" + sourcename + "' was not created "
+ + "because an error occurred while loading "
+ + filenameURL.getFilename() );
+ return;
+ }
+ }
+ // try and grab the sound buffer again:
+ buffer = bufferMap.get( filenameURL.getFilename() );
+ // see if it was there this time:
+ if( buffer == null )
+ {
+ errorMessage( "Source '" + sourcename + "' was not created "
+ + "because audio data was not found for "
+ + filenameURL.getFilename() );
+ return;
+ }
+ }
+ SourceLWJGLOpenAL s = new SourceLWJGLOpenAL( listenerPositionAL,
+ myBuffer, priority,
+ toStream, toLoop,
+ sourcename, filenameURL,
+ buffer, x, y, z,
+ attModel, distOrRoll,
+ false );
+
+ sourceMap.put( sourcename, s );
+ play( s );
+ if( temporary )
+ s.setTemporary( true );
+}
+
+/**
+ * Creates sources based on the source map provided.
+ * @param srcMap Sources to copy.
+ */
+ @Override
+ public void copySources( HashMap srcMap )
+ {
+ if( srcMap == null )
+ return;
+ Set keys = srcMap.keySet();
+ Iterator iter = keys.iterator();
+ String sourcename;
+ Source source;
+
+ // Make sure the buffer map exists:
+ if( bufferMap == null )
+ {
+ bufferMap = new HashMap();
+ importantMessage( "Buffer Map was null in method 'copySources'" );
+ }
+ // Make sure the OpenAL buffer map exists:
+ if( ALBufferMap == null )
+ {
+ ALBufferMap = new HashMap();
+ importantMessage( "Open AL Buffer Map was null in method" +
+ "'copySources'" );
+ }
+
+ // remove any existing sources before starting:
+ sourceMap.clear();
+
+ SoundBuffer buffer;
+ // loop through and copy all the sources:
+ while( iter.hasNext() )
+ {
+ sourcename = iter.next();
+ source = srcMap.get( sourcename );
+ if( source != null )
+ {
+ buffer = null;
+ if( !source.toStream )
+ {
+ loadSound( source.filenameURL );
+ buffer = bufferMap.get( source.filenameURL.getFilename() );
+ }
+ if( source.toStream || buffer != null )
+ sourceMap.put( sourcename, new SourceLWJGLOpenAL(
+ listenerPositionAL,
+ ALBufferMap.get(
+ source.filenameURL.getFilename() ),
+ source, buffer ) );
+ }
+ }
+ }
+
+/**
+ * Changes the listener's position.
+ * @param x Destination X coordinate.
+ * @param y Destination Y coordinate.
+ * @param z Destination Z coordinate.
+ */
+ @Override
+ public void setListenerPosition( float x, float y, float z )
+ {
+ super.setListenerPosition( x, y, z );
+
+ listenerPositionAL.put( 0, x );
+ listenerPositionAL.put( 1, y );
+ listenerPositionAL.put( 2, z );
+
+ // Update OpenAL listener position:
+ AL10.alListenerfv( AL10.AL_POSITION, listenerPositionAL );
+ // Check for errors:
+ checkALError();
+ }
+
+/**
+ * Changes the listeners orientation to the specified 'angle' radians
+ * counterclockwise around the y-Axis.
+ * @param angle Radians.
+ */
+ @Override
+ public void setListenerAngle( float angle )
+ {
+ super.setListenerAngle( angle );
+
+ listenerOrientation.put( 0, listener.lookAt.x );
+ listenerOrientation.put( 2, listener.lookAt.z );
+
+ // Update OpenAL listener orientation:
+ AL10.alListenerfv( AL10.AL_ORIENTATION, listenerOrientation );
+ // Check for errors:
+ checkALError();
+ }
+
+/**
+ * Changes the listeners orientation using the specified coordinates.
+ * @param lookX X element of the look-at direction.
+ * @param lookY Y element of the look-at direction.
+ * @param lookZ Z element of the look-at direction.
+ * @param upX X element of the up direction.
+ * @param upY Y element of the up direction.
+ * @param upZ Z element of the up direction.
+ */
+ @Override
+ public void setListenerOrientation( float lookX, float lookY, float lookZ,
+ float upX, float upY, float upZ )
+ {
+ super.setListenerOrientation( lookX, lookY, lookZ, upX, upY, upZ );
+ listenerOrientation.put( 0, lookX );
+ listenerOrientation.put( 1, lookY );
+ listenerOrientation.put( 2, lookZ );
+ listenerOrientation.put( 3, upX );
+ listenerOrientation.put( 4, upY );
+ listenerOrientation.put( 5, upZ );
+ AL10.alListenerfv( AL10.AL_ORIENTATION, listenerOrientation );
+ checkALError();
+ }
+
+/**
+ * Changes the listeners position and orientation using the specified listener
+ * data.
+ * @param l Listener data to use.
+ */
+ @Override
+ public void setListenerData( ListenerData l )
+ {
+ super.setListenerData( l );
+
+ listenerPositionAL.put( 0, l.position.x );
+ listenerPositionAL.put( 1, l.position.y );
+ listenerPositionAL.put( 2, l.position.z );
+ AL10.alListenerfv( AL10.AL_POSITION, listenerPositionAL );
+ checkALError();
+
+ listenerOrientation.put( 0, l.lookAt.x );
+ listenerOrientation.put( 1, l.lookAt.y );
+ listenerOrientation.put( 2, l.lookAt.z );
+ listenerOrientation.put( 3, l.up.x );
+ listenerOrientation.put( 4, l.up.y );
+ listenerOrientation.put( 5, l.up.z );
+ AL10.alListenerfv( AL10.AL_ORIENTATION, listenerOrientation );
+ checkALError();
+
+ listenerVelocity.put( 0, l.velocity.x );
+ listenerVelocity.put( 1, l.velocity.y );
+ listenerVelocity.put( 2, l.velocity.z );
+ AL10.alListenerfv( AL10.AL_VELOCITY, listenerVelocity );
+ checkALError();
+ }
+
+/**
+ * Sets the listener's velocity, for use in Doppler effect.
+ * @param x Velocity along world x-axis.
+ * @param y Velocity along world y-axis.
+ * @param z Velocity along world z-axis.
+ */
+ @Override
+ public void setListenerVelocity( float x, float y, float z )
+ {
+ super.setListenerVelocity( x, y, z );
+
+ listenerVelocity.put( 0, listener.velocity.x );
+ listenerVelocity.put( 1, listener.velocity.y );
+ listenerVelocity.put( 2, listener.velocity.z );
+ AL10.alListenerfv( AL10.AL_VELOCITY, listenerVelocity );
+ }
+
+/**
+ * The Doppler parameters have changed.
+ */
+ @Override
+ public void dopplerChanged()
+ {
+ super.dopplerChanged();
+
+ AL10.alDopplerFactor( SoundSystemConfig.getDopplerFactor() );
+ checkALError();
+ AL10.alDopplerVelocity( SoundSystemConfig.getDopplerVelocity() );
+ checkALError();
+ }
+
+/**
+ * Checks for OpenAL errors, and prints a message if there is an error.
+ * @return True if there was an error, False if not.
+ */
+ private boolean checkALError()
+ {
+ switch( AL10.alGetError() )
+ {
+ case AL10.AL_NO_ERROR:
+ return false;
+ case AL10.AL_INVALID_NAME:
+ errorMessage( "Invalid name parameter." );
+ return true;
+ case AL10.AL_INVALID_ENUM:
+ errorMessage( "Invalid parameter." );
+ return true;
+ case AL10.AL_INVALID_VALUE:
+ errorMessage( "Invalid enumerated parameter value." );
+ return true;
+ case AL10.AL_INVALID_OPERATION:
+ errorMessage( "Illegal call." );
+ return true;
+ case AL10.AL_OUT_OF_MEMORY:
+ errorMessage( "Unable to allocate memory." );
+ return true;
+ default:
+ errorMessage( "An unrecognized error occurred." );
+ return true;
+ }
+ }
+
+/**
+ * Whether or not the AL_PITCH control is supported.
+ * @return True if AL_PITCH is supported.
+ */
+ public static boolean alPitchSupported()
+ {
+ return alPitchSupported( GET, XXX );
+ }
+/**
+ * Sets or returns the value of boolean 'alPitchSupported'.
+ * @param action Action to perform (GET or SET).
+ * @param value New value if action is SET, otherwise XXX.
+ * @return value of boolean 'alPitchSupported'.
+ */
+ private static synchronized boolean alPitchSupported( boolean action,
+ boolean value )
+ {
+ if( action == SET )
+ alPitchSupported = value;
+ return alPitchSupported;
+ }
+
+/**
+ * Returns the short title of this library type.
+ * @return A short title.
+ */
+ public static String getTitle()
+ {
+ return "LWJGL OpenAL";
+ }
+
+/**
+ * Returns a longer description of this library type.
+ * @return A longer description.
+ */
+ public static String getDescription()
+ {
+ return "The LWJGL binding of OpenAL. For more information, see " +
+ "http://www.lwjgl.org";
+ }
+
+/**
+ * Returns the name of the class.
+ * @return "Library" + library title.
+ */
+ @Override
+ public String getClassName()
+ {
+ return "LibraryLWJGLOpenAL";
+ }
+
+/**
+ * The LibraryLWJGLOpenAL.Exception class provides library-specific error
+ * information.
+ */
+ public static class Exception extends SoundSystemException
+ {
+ private static final long serialVersionUID = -7502452059037798035L;
+ /**
+ * Global identifier for an exception during AL.create(). Probably
+ * means that OpenAL is not supported.
+ */
+ public static final int CREATE = 101;
+ /**
+ * Global identifier for an invalid name parameter in OpenAL.
+ */
+ public static final int INVALID_NAME = 102;
+ /**
+ * Global identifier for an invalid parameter in OpenAL.
+ */
+ public static final int INVALID_ENUM = 103;
+ /**
+ * Global identifier for an invalid enumerated parameter value in OpenAL.
+ */
+ public static final int INVALID_VALUE = 104;
+ /**
+ * Global identifier for an illegal call in OpenAL.
+ */
+ public static final int INVALID_OPERATION = 105;
+ /**
+ * Global identifier for OpenAL out of memory.
+ */
+ public static final int OUT_OF_MEMORY = 106;
+ /**
+ * Global identifier for an exception while creating the OpenAL Listener.
+ */
+ public static final int LISTENER = 107;
+ /**
+ * Global identifier for OpenAL AL_PITCH not supported.
+ */
+ public static final int NO_AL_PITCH = 108;
+
+ /**
+ * Constructor: Generates a standard "unknown error" exception with the
+ * specified message.
+ * @param message A brief description of the problem that occurred.
+ */
+ public Exception( String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Constructor: Generates an exception of the specified type, with the
+ * specified message.
+ * @param message A brief description of the problem that occurred.
+ * @param type Identifier indicating they type of error.
+ */
+ public Exception( String message, int type )
+ {
+ super( message, type );
+ }
+ }
+}
diff --git a/src/paulscode/sound/libraries/SourceLWJGLOpenAL.java b/src/paulscode/sound/libraries/SourceLWJGLOpenAL.java
new file mode 100644
index 0000000..7a771aa
--- /dev/null
+++ b/src/paulscode/sound/libraries/SourceLWJGLOpenAL.java
@@ -0,0 +1,801 @@
+package paulscode.sound.libraries;
+
+import java.nio.IntBuffer;
+import java.nio.FloatBuffer;
+import java.util.LinkedList;
+import javax.sound.sampled.AudioFormat;
+
+// From the lwjgl library, http://www.lwjgl.org
+import org.lwjgl.BufferUtils;
+import org.lwjgl.openal.AL10;
+
+import paulscode.sound.Channel;
+import paulscode.sound.FilenameURL;
+import paulscode.sound.Source;
+import paulscode.sound.SoundBuffer;
+import paulscode.sound.SoundSystemConfig;
+
+/**
+ * The SourceLWJGLOpenAL class provides an interface to the lwjgl binding of OpenAL.
+ *
+ * This software is based on or using the LWJGL Lightweight Java Gaming
+ * Library available from
+ * http://www.lwjgl.org/.
+ *
+ * LWJGL License:
+ *
+ * Copyright (c) 2002-2008 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.
+ *
+ * SoundSystem LibraryLWJGLOpenAL License:
+ *
+ * You are free to use this library for any purpose, commercial or otherwise.
+ * You may modify this library or source code, and distribute it any way you
+ * like, provided the following conditions are met:
+ *
+ * 1) You must abide by the conditions of the aforementioned LWJGL License.
+ *
+ * 2) You may not falsely claim to be the author of this library or any
+ * unmodified portion of it.
+ *
+ * 3) You may not copyright this library or a modified version of it and then
+ * sue me for copyright infringement.
+ *
+ * 4) If you modify the source code, you must clearly document the changes
+ * made before redistributing the modified source code, so other users know
+ * it is not the original code.
+ *
+ * 5) You are not required to give me credit for this library in any derived
+ * work, but if you do, you must also mention my website:
+ * http://www.paulscode.com
+ *
+ * 6) I the author will not be responsible for any damages (physical,
+ * financial, or otherwise) caused by the use if this library or any part
+ * of it.
+ *
+ * 7) I the author do not guarantee, warrant, or make any representations,
+ * either expressed or implied, regarding the use of this library or any
+ * part of it.
+ *
+ * Author: Paul Lamb
+ *
+ * http://www.paulscode.com
+ *
+ */
+public class SourceLWJGLOpenAL extends Source
+{
+/**
+ * The source's basic Channel type-cast to a ChannelLWJGLOpenAL.
+ */
+ private ChannelLWJGLOpenAL channelOpenAL = (ChannelLWJGLOpenAL) channel;
+
+/**
+ * OpenAL IntBuffer sound-buffer identifier for this source if it is a normal
+ * source.
+ */
+ private IntBuffer myBuffer;
+
+/**
+ * FloatBuffer containing the listener's 3D coordinates.
+ */
+ private FloatBuffer listenerPosition;
+
+/**
+ * FloatBuffer containing the source's 3D coordinates.
+ */
+ private FloatBuffer sourcePosition;
+
+/**
+ * FloatBuffer containing the source's velocity vector.
+ */
+ private FloatBuffer sourceVelocity;
+
+/**
+ * Constructor: Creates a new source using the specified parameters.
+ * @param listenerPosition FloatBuffer containing the listener's 3D coordinates.
+ * @param myBuffer OpenAL IntBuffer sound-buffer identifier to use for a new normal source.
+ * @param priority Setting this to true will prevent other sounds from overriding this one.
+ * @param toStream Setting this to true will create a streaming source.
+ * @param toLoop Should this source loop, or play only once.
+ * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
+ * @param filenameURL Filename/URL of the sound file to play at this source.
+ * @param soundBuffer Buffer containing audio data, or null if not loaded yet.
+ * @param x X position for this source.
+ * @param y Y position for this source.
+ * @param z Z position for this source.
+ * @param attModel Attenuation model to use.
+ * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.
+ * @param temporary Whether or not to remove this source after it finishes playing.
+ */
+ public SourceLWJGLOpenAL( FloatBuffer listenerPosition, IntBuffer myBuffer,
+ boolean priority, boolean toStream,
+ boolean toLoop, String sourcename,
+ FilenameURL filenameURL, SoundBuffer soundBuffer,
+ float x, float y, float z, int attModel,
+ float distOrRoll, boolean temporary )
+ {
+ super( priority, toStream, toLoop, sourcename, filenameURL, soundBuffer,
+ x, y, z, attModel, distOrRoll, temporary );
+ if( codec != null )
+ codec.reverseByteOrder( true );
+ this.listenerPosition = listenerPosition;
+ this.myBuffer = myBuffer;
+ libraryType = LibraryLWJGLOpenAL.class;
+ pitch = 1.0f;
+ resetALInformation();
+ }
+
+/**
+ * Constructor: Creates a new source matching the specified source.
+ * @param listenerPosition FloatBuffer containing the listener's 3D coordinates.
+ * @param myBuffer OpenAL IntBuffer sound-buffer identifier to use for a new normal source.
+ * @param old Source to copy information from.
+ * @param soundBuffer Buffer containing audio data, or null if not loaded yet.
+ */
+ public SourceLWJGLOpenAL( FloatBuffer listenerPosition, IntBuffer myBuffer,
+ Source old, SoundBuffer soundBuffer )
+ {
+ super( old, soundBuffer );
+ if( codec != null )
+ codec.reverseByteOrder( true );
+ this.listenerPosition = listenerPosition;
+ this.myBuffer = myBuffer;
+ libraryType = LibraryLWJGLOpenAL.class;
+ pitch = 1.0f;
+ resetALInformation();
+ }
+
+ /**
+ * Constructor: Creates a new streaming source that will be directly fed with
+ * raw audio data.
+ * @param listenerPosition FloatBuffer containing the listener's 3D coordinates.
+ * @param audioFormat Format that the data will be in.
+ * @param priority Setting this to true will prevent other sounds from overriding this one.
+ * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
+ * @param x X position for this source.
+ * @param y Y position for this source.
+ * @param z Z position for this source.
+ * @param attModel Attenuation model to use.
+ * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.
+ */
+ public SourceLWJGLOpenAL( FloatBuffer listenerPosition,
+ AudioFormat audioFormat, boolean priority,
+ String sourcename, float x, float y, float z,
+ int attModel, float distOrRoll )
+ {
+ super( audioFormat, priority, sourcename, x, y, z, attModel,
+ distOrRoll );
+ this.listenerPosition = listenerPosition;
+ libraryType = LibraryLWJGLOpenAL.class;
+ pitch = 1.0f;
+ resetALInformation();
+ }
+
+/**
+ * Shuts the source down and removes references to all instantiated objects.
+ */
+ @Override
+ public void cleanup()
+ {
+
+ super.cleanup();
+ }
+
+/**
+ * Changes the peripheral information about the source using the specified
+ * parameters.
+ * @param listenerPosition FloatBuffer containing the listener's 3D coordinates.
+ * @param myBuffer OpenAL IntBuffer sound-buffer identifier to use for a new normal source.
+ * @param priority Setting this to true will prevent other sounds from overriding this one.
+ * @param toStream Setting this to true will create a streaming source.
+ * @param toLoop Should this source loop, or play only once.
+ * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
+ * @param filenameURL Filename/URL of the sound file to play at this source.
+ * @param soundBuffer Buffer containing audio data, or null if not loaded yet.
+ * @param x X position for this source.
+ * @param y Y position for this source.
+ * @param z Z position for this source.
+ * @param attModel Attenuation model to use.
+ * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.
+ * @param temporary Whether or not to remove this source after it finishes playing.
+ */
+ public void changeSource( FloatBuffer listenerPosition, IntBuffer myBuffer,
+ boolean priority, boolean toStream,
+ boolean toLoop, String sourcename,
+ FilenameURL filenameURL, SoundBuffer soundBuffer,
+ float x, float y, float z, int attModel,
+ float distOrRoll, boolean temporary )
+ {
+ super.changeSource( priority, toStream, toLoop, sourcename,
+ filenameURL, soundBuffer, x, y, z, attModel,
+ distOrRoll, temporary );
+ this.listenerPosition = listenerPosition;
+ this.myBuffer = myBuffer;
+ pitch = 1.0f;
+ resetALInformation();
+ }
+
+/**
+ * Removes the next filename from the sound sequence queue and assigns it to
+ * this source. This method has no effect on non-streaming sources. This
+ * method is used internally by SoundSystem, and it is unlikely that the user
+ * will ever need to use it.
+ * @return True if there was something in the queue.
+ */
+ @Override
+ public boolean incrementSoundSequence()
+ {
+ if( !toStream )
+ {
+ errorMessage( "Method 'incrementSoundSequence' may only be used " +
+ "for streaming sources." );
+ return false;
+ }
+ synchronized( soundSequenceLock )
+ {
+ if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 )
+ {
+ filenameURL = soundSequenceQueue.remove( 0 );
+ if( codec != null )
+ codec.cleanup();
+ codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );
+ if( codec != null )
+ {
+ codec.reverseByteOrder( true );
+ if( codec.getAudioFormat() == null )
+ codec.initialize( filenameURL.getURL() );
+
+ AudioFormat audioFormat = codec.getAudioFormat();
+
+ if( audioFormat == null )
+ {
+ errorMessage( "Audio Format null in method " +
+ "'incrementSoundSequence'" );
+ return false;
+ }
+
+ int soundFormat = 0;
+ if( audioFormat.getChannels() == 1 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method " +
+ "'incrementSoundSequence'" );
+ return false;
+ }
+ }
+ else if( audioFormat.getChannels() == 2 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method " +
+ "'incrementSoundSequence'" );
+ return false;
+ }
+ }
+ else
+ {
+ errorMessage( "Audio data neither mono nor stereo in " +
+ "method 'incrementSoundSequence'" );
+ return false;
+ }
+
+ // Let the channel know what format and sample rate to use:
+ channelOpenAL.setFormat( soundFormat,
+ (int) audioFormat.getSampleRate() );
+ preLoad = true;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+/**
+ * Called every time the listener's position or orientation changes.
+ */
+ @Override
+ public void listenerMoved()
+ {
+ positionChanged();
+ }
+
+/**
+ * Moves the source to the specified position.
+ * @param x X coordinate to move to.
+ * @param y Y coordinate to move to.
+ * @param z Z coordinate to move to.
+ */
+ @Override
+ public void setPosition( float x, float y, float z )
+ {
+ super.setPosition( x, y, z );
+
+ // Make sure OpenAL information has been created
+ if( sourcePosition == null )
+ resetALInformation();
+ else
+ positionChanged();
+
+ // put the new position information into the buffer:
+ sourcePosition.put( 0, x );
+ sourcePosition.put( 1, y );
+ sourcePosition.put( 2, z );
+
+ // make sure we are assigned to a channel:
+ if( channel != null && channel.attachedSource == this &&
+ channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ // move the source:
+ AL10.alSourcefv( channelOpenAL.ALSource.get( 0 ), AL10.AL_POSITION,
+ sourcePosition );
+ checkALError();
+ }
+ }
+
+/**
+ * Recalculates the distance from the listner and the gain.
+ */
+ @Override
+ public void positionChanged()
+ {
+ calculateDistance();
+ calculateGain();
+
+ if( channel != null && channel.attachedSource == this &&
+ channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_GAIN, (gain * sourceVolume
+ * (float) Math.abs( fadeOutGain )
+ * fadeInGain) );
+ checkALError();
+ }
+ checkPitch();
+ }
+
+/**
+ * Checks the source's pitch.
+ */
+ private void checkPitch()
+ {
+ if( channel != null && channel.attachedSource == this &&
+ LibraryLWJGLOpenAL.alPitchSupported() && channelOpenAL != null &&
+ channelOpenAL.ALSource != null )
+ {
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_PITCH, pitch );
+ checkALError();
+ }
+ }
+
+/**
+ * Sets whether this source should loop or only play once.
+ * @param lp True or false.
+ */
+ @Override
+ public void setLooping( boolean lp )
+ {
+ super.setLooping( lp );
+
+ // make sure we are assigned to a channel:
+ if( channel != null && channel.attachedSource == this &&
+ channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ if( lp )
+ AL10.alSourcei( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_LOOPING, AL10.AL_TRUE );
+ else
+ AL10.alSourcei( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_LOOPING, AL10.AL_FALSE );
+ checkALError();
+ }
+ }
+
+/**
+ * Sets this source's attenuation model.
+ * @param model Attenuation model to use.
+ */
+ @Override
+ public void setAttenuation( int model )
+ {
+ super.setAttenuation( model );
+ // make sure we are assigned to a channel:
+ if( channel != null && channel.attachedSource == this &&
+ channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ // attenuation changed, so update the rolloff factor accordingly
+ if( model == SoundSystemConfig.ATTENUATION_ROLLOFF )
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_ROLLOFF_FACTOR, distOrRoll );
+ else
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_ROLLOFF_FACTOR, 0.0f );
+ checkALError();
+ }
+ }
+
+/**
+ * Sets this source's fade distance or rolloff factor, depending on the
+ * attenuation model.
+ * @param dr New value for fade distance or rolloff factor.
+ */
+ @Override
+ public void setDistOrRoll( float dr)
+ {
+ super.setDistOrRoll( dr );
+ // make sure we are assigned to a channel:
+ if( channel != null && channel.attachedSource == this &&
+ channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ // if we are using rolloff attenuation, then dr is a rolloff factor:
+ if( attModel == SoundSystemConfig.ATTENUATION_ROLLOFF )
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_ROLLOFF_FACTOR, dr );
+ else
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_ROLLOFF_FACTOR, 0.0f );
+ checkALError();
+ }
+ }
+
+/**
+ * Sets this source's velocity, for use in Doppler effect.
+ * @param x Velocity along world x-axis.
+ * @param y Velocity along world y-axis.
+ * @param z Velocity along world z-axis.
+ */
+ @Override
+ public void setVelocity( float x, float y, float z )
+ {
+ super.setVelocity( x, y, z );
+
+ sourceVelocity = BufferUtils.createFloatBuffer( 3 ).put( new float[]
+ { x, y, z } );
+ sourceVelocity.flip();
+ // make sure we are assigned to a channel:
+ if( channel != null && channel.attachedSource == this &&
+ channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ AL10.alSourcefv( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_VELOCITY, sourceVelocity );
+ checkALError();
+ }
+ }
+
+/**
+ * Manually sets this source's pitch.
+ * @param value A float value ( 0.5f - 2.0f ).
+ */
+ @Override
+ public void setPitch( float value )
+ {
+ super.setPitch( value );
+ checkPitch();
+ }
+
+/**
+ * Plays the source on the specified channel.
+ * @param c Channel to play on.
+ */
+ @Override
+ public void play( Channel c )
+ {
+ if( !active() )
+ {
+ if( toLoop )
+ toPlay = true;
+ return;
+ }
+
+ if( c == null )
+ {
+ errorMessage( "Unable to play source, because channel was null" );
+ return;
+ }
+
+ boolean newChannel = (channel != c);
+ if( channel != null && channel.attachedSource != this )
+ newChannel = true;
+
+ boolean wasPaused = paused();
+
+ super.play( c );
+
+ channelOpenAL = (ChannelLWJGLOpenAL) channel;
+
+ // Make sure the channel exists:
+ // check if we are already on this channel:
+ if( newChannel )
+ {
+ setPosition( position.x, position.y, position.z );
+ checkPitch();
+
+ // Send the source's attributes to the channel:
+ if( channelOpenAL != null && channelOpenAL.ALSource != null )
+ {
+ if( LibraryLWJGLOpenAL.alPitchSupported() )
+ {
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_PITCH, pitch );
+ checkALError();
+ }
+ AL10.alSourcefv( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_POSITION, sourcePosition );
+ checkALError();
+
+ AL10.alSourcefv( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_VELOCITY, sourceVelocity );
+
+ checkALError();
+
+ if( attModel == SoundSystemConfig.ATTENUATION_ROLLOFF )
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_ROLLOFF_FACTOR, distOrRoll );
+ else
+ AL10.alSourcef( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_ROLLOFF_FACTOR, 0.0f );
+ checkALError();
+
+ if( toLoop && (!toStream) )
+ AL10.alSourcei( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_LOOPING, AL10.AL_TRUE );
+ else
+ AL10.alSourcei( channelOpenAL.ALSource.get( 0 ),
+ AL10.AL_LOOPING, AL10.AL_FALSE );
+ checkALError();
+ }
+ if( !toStream )
+ {
+ // This is not a streaming source, so make sure there is
+ // a sound buffer loaded to play:
+ if( myBuffer == null )
+ {
+ errorMessage( "No sound buffer to play" );
+ return;
+ }
+
+ channelOpenAL.attachBuffer( myBuffer );
+ }
+ }
+
+ // See if we are already playing:
+ if( !playing() )
+ {
+ if( toStream && !wasPaused )
+ {
+ if( codec == null )
+ {
+ errorMessage( "Decoder null in method 'play'" );
+ return;
+ }
+ if( codec.getAudioFormat() == null )
+ codec.initialize( filenameURL.getURL() );
+
+ AudioFormat audioFormat = codec.getAudioFormat();
+
+ if( audioFormat == null )
+ {
+ errorMessage( "Audio Format null in method 'play'" );
+ return;
+ }
+
+ int soundFormat = 0;
+ if( audioFormat.getChannels() == 1 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_MONO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method 'play'" );
+ return;
+ }
+ }
+ else if( audioFormat.getChannels() == 2 )
+ {
+ if( audioFormat.getSampleSizeInBits() == 8 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO8;
+ }
+ else if( audioFormat.getSampleSizeInBits() == 16 )
+ {
+ soundFormat = AL10.AL_FORMAT_STEREO16;
+ }
+ else
+ {
+ errorMessage( "Illegal sample size in method 'play'" );
+ return;
+ }
+ }
+ else
+ {
+ errorMessage( "Audio data neither mono nor stereo in " +
+ "method 'play'" );
+ return;
+ }
+
+ // Let the channel know what format and sample rate to use:
+ channelOpenAL.setFormat( soundFormat,
+ (int) audioFormat.getSampleRate() );
+ preLoad = true;
+ }
+ channel.play();
+ if( pitch != 1.0f )
+ checkPitch();
+ }
+ }
+
+/**
+ * Queues up the initial stream-buffers for the stream.
+ * @return False if the end of the stream was reached.
+ */
+ @Override
+ public boolean preLoad()
+ {
+ if( codec == null )
+ return false;
+
+ codec.initialize( filenameURL.getURL() );
+ LinkedList preLoadBuffers = new LinkedList();
+ for( int i = 0; i < SoundSystemConfig.getNumberStreamingBuffers(); i++ )
+ {
+ soundBuffer = codec.read();
+
+ if( soundBuffer == null || soundBuffer.audioData == null )
+ break;
+
+ preLoadBuffers.add( soundBuffer.audioData );
+ }
+ positionChanged();
+
+ channel.preLoadBuffers( preLoadBuffers );
+
+ preLoad = false;
+ return true;
+ }
+
+/**
+ * Resets all the information OpenAL uses to play this source.
+ */
+ private void resetALInformation()
+ {
+ // Create buffers for the source's position and velocity
+ sourcePosition = BufferUtils.createFloatBuffer( 3 ).put(
+ new float[] { position.x, position.y, position.z } );
+ sourceVelocity = BufferUtils.createFloatBuffer( 3 ).put(
+ new float[] { velocity.x, velocity.y, velocity.z } );
+
+ // flip the buffers, so they can be used:
+ sourcePosition.flip();
+ sourceVelocity.flip();
+
+ positionChanged();
+ }
+
+/**
+ * Calculates this source's distance from the listener.
+ */
+ private void calculateDistance()
+ {
+ if( listenerPosition != null )
+ {
+ // Calculate the source's distance from the listener:
+ double dX = position.x - listenerPosition.get( 0 );
+ double dY = position.y - listenerPosition.get( 1 );
+ double dZ = position.z - listenerPosition.get( 2 );
+ distanceFromListener = (float) Math.sqrt( dX*dX + dY*dY + dZ*dZ );
+ }
+ }
+
+/**
+ * If using linear attenuation, calculates the gain for this source based on
+ * its distance from the listener.
+ */
+ private void calculateGain()
+ {
+ // If using linear attenuation, calculate the source's gain:
+ if( attModel == SoundSystemConfig.ATTENUATION_LINEAR )
+ {
+ if( distanceFromListener <= 0 )
+ {
+ gain = 1.0f;
+ }
+ else if( distanceFromListener >= distOrRoll )
+ {
+ gain = 0.0f;
+ }
+ else
+ {
+ gain = 1.0f - (distanceFromListener / distOrRoll);
+ }
+ if( gain > 1.0f )
+ gain = 1.0f;
+ if( gain < 0.0f )
+ gain = 0.0f;
+ }
+ else
+ {
+ gain = 1.0f;
+ }
+ }
+
+/**
+ * Checks for OpenAL errors, and prints a message if there is an error.
+ * @return True if there was an error, False if not.
+ */
+ private boolean checkALError()
+ {
+ switch( AL10.alGetError() )
+ {
+ case AL10.AL_NO_ERROR:
+ return false;
+ case AL10.AL_INVALID_NAME:
+ errorMessage( "Invalid name parameter." );
+ return true;
+ case AL10.AL_INVALID_ENUM:
+ errorMessage( "Invalid parameter." );
+ return true;
+ case AL10.AL_INVALID_VALUE:
+ errorMessage( "Invalid enumerated parameter value." );
+ return true;
+ case AL10.AL_INVALID_OPERATION:
+ errorMessage( "Illegal call." );
+ return true;
+ case AL10.AL_OUT_OF_MEMORY:
+ errorMessage( "Unable to allocate memory." );
+ return true;
+ default:
+ errorMessage( "An unrecognized error occurred." );
+ return true;
+ }
+ }
+}