aboutsummaryrefslogtreecommitdiffstats
path: root/ardor3d-lwjgl/src/main
diff options
context:
space:
mode:
authorneothemachine <[email protected]>2012-12-05 17:03:16 +0100
committerneothemachine <[email protected]>2012-12-05 17:03:16 +0100
commit9dd02f103042cb8a196f8a3ed2278da443e345bf (patch)
tree422449f0c62ff9518316ce5d4219bb2b12f0ed15 /ardor3d-lwjgl/src/main
parent2b26b12fd794de0f03a064a10024a3d9f5583756 (diff)
move all files from trunk to root folder
Diffstat (limited to 'ardor3d-lwjgl/src/main')
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglAwtCanvas.java110
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvas.java280
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasCallback.java31
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasRenderer.java208
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglDisplayCanvas.java137
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglHeadlessCanvas.java257
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglLibraryPaths.java80
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/input/jinput/JInputControllerWrapper.java125
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglControllerWrapper.java124
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKey.java173
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKeyboardWrapper.java64
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseManager.java142
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseWrapper.java144
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglContextCapabilities.java237
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglPbufferTextureRenderer.java397
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglRenderer.java1743
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRenderer.java566
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRendererProvider.java48
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglBlendStateUtil.java425
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglClipStateUtil.java68
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglColorMaskStateUtil.java43
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglCullStateUtil.java93
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFogStateUtil.java153
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFragmentProgramStateUtil.java113
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglLightStateUtil.java372
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglMaterialStateUtil.java199
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglOffsetStateUtil.java85
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShaderObjectsStateUtil.java361
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShadingStateUtil.java52
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglStencilStateUtil.java186
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglTextureStateUtil.java1686
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglVertexProgramStateUtil.java123
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglWireframeStateUtil.java83
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglZBufferStateUtil.java90
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/shader/LwjglShaderUtil.java400
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglRendererUtil.java99
-rw-r--r--ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglTextureUtil.java633
-rw-r--r--ardor3d-lwjgl/src/main/native/linux/libjinput-linux.sobin0 -> 10604 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/linux/libjinput-linux64.sobin0 -> 13776 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/linux/liblwjgl.sobin0 -> 277580 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/linux/liblwjgl64.sobin0 -> 346360 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/linux/libopenal.sobin0 -> 158152 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/linux/libopenal64.sobin0 -> 177410 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/macosx/libjinput-osx.jnilibbin0 -> 49016 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/macosx/liblwjgl.jnilibbin0 -> 841968 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/solaris/liblwjgl.sobin0 -> 247112 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/solaris/libopenal.sobin0 -> 253928 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/win32/OpenAL32.dllbin0 -> 103936 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/win32/jinput-dx8.dllbin0 -> 31232 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/win32/jinput-raw.dllbin0 -> 29184 bytes
-rw-r--r--ardor3d-lwjgl/src/main/native/win32/lwjgl.dllbin0 -> 153600 bytes
51 files changed, 10130 insertions, 0 deletions
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglAwtCanvas.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglAwtCanvas.java
new file mode 100644
index 0000000..e3387f2
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglAwtCanvas.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.lwjgl;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.AWTGLCanvas;
+import org.lwjgl.opengl.PixelFormat;
+
+import com.ardor3d.annotation.MainThread;
+import com.ardor3d.framework.Canvas;
+import com.ardor3d.framework.DisplaySettings;
+
+public class LwjglAwtCanvas extends AWTGLCanvas implements Canvas {
+
+ private static final long serialVersionUID = 1L;
+
+ private final LwjglCanvasRenderer _canvasRenderer;
+ private boolean _inited = false;
+ private final DisplaySettings _settings;
+
+ private volatile boolean _updated = false;
+ // _latch would have to be volatile if we are not careful with the order of reads and writes between this one and
+ // '_updated'
+ private CountDownLatch _latch = null;
+
+ public LwjglAwtCanvas(final DisplaySettings settings, final LwjglCanvasRenderer canvasRenderer)
+ throws LWJGLException {
+ super(new PixelFormat(settings.getColorDepth(), settings.getAlphaBits(), settings.getDepthBits(), settings
+ .getStencilBits(), settings.getSamples()).withStereo(settings.isStereo()));
+ _settings = settings;
+ _canvasRenderer = canvasRenderer;
+ _canvasRenderer.setCanvasCallback(new LwjglCanvasCallback() {
+ @Override
+ public void makeCurrent() throws LWJGLException {
+ LwjglAwtCanvas.this.makeCurrent();
+ }
+
+ @Override
+ public void releaseContext() throws LWJGLException {
+ LwjglAwtCanvas.this.releaseContext();
+ }
+ });
+ }
+
+ public void draw(final CountDownLatch latch) {
+ if (!shouldDraw(latch)) {
+ latch.countDown();
+ return;
+ }
+
+ // need to set _latch before _updated, for memory consistency reasons
+ _latch = latch;
+ _updated = true;
+ repaint();
+ }
+
+ private boolean shouldDraw(final CountDownLatch latch) {
+ final boolean showing = isShowing();
+ final boolean lastUpdateComplete = latch == null || !_updated;
+ return showing && lastUpdateComplete;
+ }
+
+ @Override
+ @MainThread
+ protected void paintGL() {
+ if (!_inited) {
+ _canvasRenderer.init(_settings, false); // false - do not do back buffer swap, awt will do that.
+ _canvasRenderer.getCamera().resize(getWidth(), getHeight());
+ _inited = true;
+ }
+
+ if (_latch != null && !_updated) {
+ return;
+ }
+
+ try {
+ if (_canvasRenderer.draw()) {
+ swapBuffers();
+ }
+ } catch (final LWJGLException e) {
+ throw new RuntimeException(e);
+ } finally {
+ // release our context - because swap is external, we release here instead.
+ _canvasRenderer.releaseCurrentContext();
+ }
+
+ if (_latch != null) {
+ _updated = false;
+ _latch.countDown();
+ }
+ }
+
+ public void init() {
+ ; // ignore - can only be inited inside our paintGL
+ }
+
+ public LwjglCanvasRenderer getCanvasRenderer() {
+ return _canvasRenderer;
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvas.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvas.java
new file mode 100644
index 0000000..7fe8b9f
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvas.java
@@ -0,0 +1,280 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.DisplayMode;
+import org.lwjgl.opengl.PixelFormat;
+
+import com.ardor3d.annotation.MainThread;
+import com.ardor3d.framework.CanvasRenderer;
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.framework.NativeCanvas;
+import com.ardor3d.image.Image;
+import com.ardor3d.image.ImageDataFormat;
+import com.ardor3d.image.PixelDataType;
+import com.ardor3d.input.FocusWrapper;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * A canvas implementation for use with native LWJGL windows.
+ */
+public class LwjglCanvas implements NativeCanvas, FocusWrapper {
+ private static final Logger logger = Logger.getLogger(LwjglCanvas.class.getName());
+
+ private final LwjglCanvasRenderer _canvasRenderer;
+
+ private final DisplaySettings _settings;
+ private boolean _inited = false;
+
+ private volatile boolean _focusLost = false;
+
+ /**
+ * If true, we will not try to drop and reclaim the context on each frame.
+ */
+ public static boolean SINGLE_THREADED_MODE = true;
+
+ public LwjglCanvas(final DisplaySettings settings, final LwjglCanvasRenderer canvasRenderer) {
+ _canvasRenderer = canvasRenderer;
+ _canvasRenderer.setCanvasCallback(new LwjglCanvasCallback() {
+ @Override
+ public void makeCurrent() throws LWJGLException {
+ if (!SINGLE_THREADED_MODE) {
+ Display.makeCurrent();
+ }
+ }
+
+ @Override
+ public void releaseContext() throws LWJGLException {
+ if (!SINGLE_THREADED_MODE) {
+ Display.releaseContext();
+ }
+ }
+ });
+ _settings = settings;
+ }
+
+ public boolean getAndClearFocusLost() {
+ final boolean result = _focusLost;
+
+ _focusLost = false;
+
+ return result;
+ }
+
+ @MainThread
+ // hm, seem to have to control the order of initialization: display first, then keyboard/etc, in native windows
+ public void init() {
+ if (_inited) {
+ return;
+ }
+
+ // create the Display.
+ DisplayMode mode;
+ if (_settings.isFullScreen()) {
+ mode = getValidDisplayMode(_settings);
+ if (null == mode) {
+ throw new Ardor3dException("Bad display mode (w/h/bpp/freq): " + _settings.getWidth() + " / "
+ + _settings.getHeight() + " / " + _settings.getColorDepth() + " / " + _settings.getFrequency());
+ }
+ } else {
+ mode = new DisplayMode(_settings.getWidth(), _settings.getHeight());
+ }
+
+ final PixelFormat format = new PixelFormat(_settings.getAlphaBits(), _settings.getDepthBits(),
+ _settings.getStencilBits()).withSamples(_settings.getSamples()).withStereo(_settings.isStereo());
+
+ try {
+ Display.setDisplayMode(mode);
+ Display.setFullscreen(_settings.isFullScreen());
+ Display.create(format);
+ } catch (final Exception e) {
+ logger.severe("Cannot create window");
+ logger.logp(Level.SEVERE, this.getClass().toString(), "initDisplay()", "Exception", e);
+ throw new Ardor3dException("Cannot create window: " + e.getMessage());
+ }
+
+ _canvasRenderer.init(_settings, true); // true - do swap in renderer.
+ _inited = true;
+ }
+
+ @MainThread
+ public void draw(final CountDownLatch latch) {
+ if (!_inited) {
+ init();
+ }
+
+ checkFocus();
+
+ _canvasRenderer.draw();
+
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ private void checkFocus() {
+ // focusLost should be true if it is already true (hasn't been read/cleared yet), or
+ // the display is presently not in focus
+ _focusLost = _focusLost || !(Display.isActive() && Display.isVisible());
+
+ //
+ // final boolean newFocus =
+ //
+ // if (!focusLost && newFocus) {
+ // // didn't use to have focus, but now we do
+ // // do nothing for now, just keep track of the fact that we have focus
+ // focusLost = newFocus;
+ // } else if (focusLost && !newFocus) {
+ // // had focus, but don't anymore - notify the physical input layer
+ // physicalLayer.lostFocus();
+ // focusLost = newFocus;
+ // }
+ }
+
+ public CanvasRenderer getCanvasRenderer() {
+ return _canvasRenderer;
+ }
+
+ /**
+ * @return a <code>DisplayMode</code> object that has the requested settings. If there is no mode that supports a
+ * requested resolution, null is returned.
+ */
+ private DisplayMode getValidDisplayMode(final DisplaySettings settings) {
+ // get all the modes, and find one that matches our settings.
+ DisplayMode[] modes;
+ try {
+ modes = Display.getAvailableDisplayModes();
+ } catch (final LWJGLException e) {
+ logger.logp(Level.SEVERE, this.getClass().toString(), "getValidDisplayMode(width, height, bpp, freq)",
+ "Exception", e);
+ return null;
+ }
+
+ // Try to find a best match.
+ int best_match = -1; // looking for request size/bpp followed by exact or highest freq
+ int match_freq = -1;
+ for (int i = 0; i < modes.length; i++) {
+ if (modes[i].getWidth() != settings.getWidth()) {
+ logger.fine("DisplayMode " + modes[i] + ": Width != " + settings.getWidth());
+ continue;
+ }
+ if (modes[i].getHeight() != settings.getHeight()) {
+ logger.fine("DisplayMode " + modes[i] + ": Height != " + settings.getHeight());
+ continue;
+ }
+ if (settings.getColorDepth() != 0 && modes[i].getBitsPerPixel() != settings.getColorDepth()) {
+ // should pick based on best match here too
+ logger.fine("DisplayMode " + modes[i] + ": Bits per pixel != " + settings.getColorDepth());
+ continue;
+ }
+ if (best_match == -1) {
+ logger.fine("DisplayMode " + modes[i] + ": Match! ");
+ best_match = i;
+ match_freq = modes[i].getFrequency();
+ } else {
+ final int cur_freq = modes[i].getFrequency();
+ if (match_freq != settings.getFrequency() && // Previous is not a perfect match
+ (cur_freq == settings.getFrequency() || // Current is perfect match
+ match_freq < cur_freq)) // or is higher freq
+ {
+ logger.fine("DisplayMode " + modes[i] + ": Better match!");
+ best_match = i;
+ match_freq = cur_freq;
+ }
+ }
+ }
+
+ if (best_match == -1) {
+ return null; // none found;
+ } else {
+ logger.info("Selected DisplayMode: " + modes[best_match]);
+ return modes[best_match];
+ }
+ }
+
+ public void close() {
+ if (Display.isCreated()) {
+ Display.destroy();
+ }
+ }
+
+ public boolean isActive() {
+ return Display.isCreated() && Display.isActive();
+ }
+
+ @MainThread
+ public boolean isClosing() {
+ return Display.isCreated() && Display.isCloseRequested();
+ }
+
+ public void moveWindowTo(final int locX, final int locY) {
+ if (Display.isCreated()) {
+ Display.setLocation(locX, locY);
+ }
+ }
+
+ public void setIcon(final Image[] iconImages) {
+ final ByteBuffer[] iconData = new ByteBuffer[iconImages.length];
+ for (int i = 0; i < iconData.length; i++) {
+ // Image.Format.RGBA8 is the format that LWJGL requires, so try to convert if it's not.
+ if (iconImages[i].getDataType() != PixelDataType.UnsignedByte) {
+ throw new Ardor3dException(
+ "Your icon is in a format that could not be converted to UnsignedByte - RGBA");
+ }
+
+ if (iconImages[i].getDataFormat() != ImageDataFormat.RGBA) {
+ if (iconImages[i].getDataFormat() != ImageDataFormat.RGB) {
+ throw new Ardor3dException(
+ "Your icon is in a format that could not be converted to UnsignedByte - RGBA");
+ }
+ iconImages[i] = _RGB888_to_RGBA8888(iconImages[i]);
+ }
+
+ iconData[i] = iconImages[i].getData(0);
+ iconData[i].rewind();
+ }
+ Display.setIcon(iconData);
+ }
+
+ private static Image _RGB888_to_RGBA8888(final Image rgb888) {
+ final int size = rgb888.getWidth() * rgb888.getHeight() * 4;
+
+ final ByteBuffer rgb = rgb888.getData(0);
+
+ final ByteBuffer rgba8888 = BufferUtils.createByteBuffer(size);
+ rgb.rewind();
+ for (int j = 0; j < size; j++) {
+ if ((j + 1) % 4 == 0) {
+ rgba8888.put((byte) 0xFF);
+ } else {
+ rgba8888.put(rgb.get());
+ }
+ }
+ return new Image(ImageDataFormat.RGBA, PixelDataType.UnsignedByte, rgb888.getWidth(), rgb888.getHeight(),
+ rgba8888, null);
+ }
+
+ public void setTitle(final String title) {
+ Display.setTitle(title);
+ }
+
+ public void setVSyncEnabled(final boolean enabled) {
+ Display.setVSyncEnabled(enabled);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasCallback.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasCallback.java
new file mode 100644
index 0000000..a65c7e2
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasCallback.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.lwjgl;
+
+import org.lwjgl.LWJGLException;
+
+public interface LwjglCanvasCallback {
+
+ /**
+ * Request this canvas as the current opengl owner.
+ *
+ * @throws LWJGLException
+ */
+ void makeCurrent() throws LWJGLException;
+
+ /**
+ * Release this canvas as the current opengl owner.
+ *
+ * @throws LWJGLException
+ */
+ void releaseContext() throws LWJGLException;
+
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasRenderer.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasRenderer.java
new file mode 100644
index 0000000..ab66a1d
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglCanvasRenderer.java
@@ -0,0 +1,208 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.lwjgl;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.ARBMultisample;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GLContext;
+
+import com.ardor3d.annotation.MainThread;
+import com.ardor3d.framework.CanvasRenderer;
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.framework.Scene;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.Camera.ProjectionMode;
+import com.ardor3d.renderer.lwjgl.LwjglContextCapabilities;
+import com.ardor3d.renderer.lwjgl.LwjglRenderer;
+import com.ardor3d.util.Ardor3dException;
+
+public class LwjglCanvasRenderer implements CanvasRenderer {
+ protected Scene _scene;
+ protected Camera _camera;
+ protected boolean _doSwap;
+ protected LwjglRenderer _renderer;
+ protected Object _context = new Object();
+ protected int _frameClear = Renderer.BUFFER_COLOR_AND_DEPTH;
+
+ private RenderContext _currentContext;
+ private LwjglCanvasCallback _canvasCallback;
+
+ // NOTE: This code commented out by Petter 090224, since it isn't really ready to be used,
+ // and since it is at the moment more work than it is worth to get it ready. Later on, when
+ // we have solved some more fundamental problems, it is probably time to revisit this.
+
+ // ensure availability of LWJGL natives
+ // {
+ // final String[] libraryPaths = LwjglLibraryPaths.getLibraryPaths(System.getProperty("os.name"), System
+ // .getProperty("os.arch"));
+ //
+ // try {
+ // NativeLoader.makeLibrariesAvailable(libraryPaths);
+ // } catch (final Exception e) {
+ // ; // ignore
+ // }
+ // }
+
+ public LwjglCanvasRenderer(final Scene scene) {
+ _scene = scene;
+ }
+
+ @MainThread
+ protected ContextCapabilities createContextCapabilities() {
+ return new LwjglContextCapabilities(GLContext.getCapabilities());
+ }
+
+ @MainThread
+ public void init(final DisplaySettings settings, final boolean doSwap) {
+ _doSwap = doSwap;
+
+ // Look up a shared context, if a shared LwjglCanvasRenderer is given.
+ // XXX: Shared contexts will probably not work... lwjgl does not seem to have a way to make a new glcontext that
+ // shares lists, textures, etc.
+ RenderContext sharedContext = null;
+ if (settings.getShareContext() != null) {
+ sharedContext = ContextManager.getContextForKey(settings.getShareContext().getRenderContext()
+ .getContextKey());
+ }
+
+ try {
+ _canvasCallback.makeCurrent();
+ GLContext.useContext(_context);
+ } catch (final LWJGLException e) {
+ throw new Ardor3dException("Unable to init CanvasRenderer.", e);
+ }
+
+ final ContextCapabilities caps = createContextCapabilities();
+ _currentContext = new RenderContext(this, caps, sharedContext);
+
+ ContextManager.addContext(this, _currentContext);
+ ContextManager.switchContext(this);
+
+ _renderer = new LwjglRenderer();
+
+ if (settings.getSamples() != 0 && caps.isMultisampleSupported()) {
+ GL11.glEnable(ARBMultisample.GL_MULTISAMPLE_ARB);
+ }
+
+ _renderer.setBackgroundColor(ColorRGBA.BLACK);
+
+ if (_camera == null) {
+ /** Set up how our camera sees. */
+ _camera = new Camera(settings.getWidth(), settings.getHeight());
+ _camera.setFrustumPerspective(45.0f, (float) settings.getWidth() / (float) settings.getHeight(), 1, 1000);
+ _camera.setProjectionMode(ProjectionMode.Perspective);
+
+ final Vector3 loc = new Vector3(0.0f, 0.0f, 10.0f);
+ final Vector3 left = new Vector3(-1.0f, 0.0f, 0.0f);
+ final Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
+ final Vector3 dir = new Vector3(0.0f, 0f, -1.0f);
+ /** Move our camera to a correct place and orientation. */
+ _camera.setFrame(loc, left, up, dir);
+ } else {
+ // use new width and height to set ratio.
+ _camera.setFrustumPerspective(_camera.getFovY(),
+ (float) settings.getWidth() / (float) settings.getHeight(), _camera.getFrustumNear(), _camera
+ .getFrustumFar());
+ }
+ }
+
+ @MainThread
+ public boolean draw() {
+
+ // set up context for rendering this canvas
+ makeCurrentContext();
+
+ // render stuff, first apply our camera if we have one
+ if (_camera != null) {
+ if (Camera.getCurrentCamera() != _camera) {
+ _camera.update();
+ }
+ _camera.apply(_renderer);
+ }
+ _renderer.clearBuffers(_frameClear);
+
+ final boolean drew = _scene.renderUnto(_renderer);
+ _renderer.flushFrame(drew && _doSwap);
+
+ // release the context if we're done (swapped and all)
+ if (_doSwap) {
+ releaseCurrentContext();
+ }
+
+ return drew;
+ }
+
+ public Camera getCamera() {
+ return _camera;
+ }
+
+ public Scene getScene() {
+ return _scene;
+ }
+
+ public void setScene(final Scene scene) {
+ _scene = scene;
+ }
+
+ public LwjglCanvasCallback getCanvasCallback() {
+ return _canvasCallback;
+ }
+
+ public void setCanvasCallback(final LwjglCanvasCallback canvasCallback) {
+ _canvasCallback = canvasCallback;
+ }
+
+ public Renderer getRenderer() {
+ return _renderer;
+ }
+
+ public void makeCurrentContext() throws Ardor3dException {
+ try {
+ _canvasCallback.makeCurrent();
+ GLContext.useContext(_context);
+ ContextManager.switchContext(this);
+ } catch (final LWJGLException e) {
+ throw new Ardor3dException("Failed to claim OpenGL context.", e);
+ }
+ }
+
+ public void releaseCurrentContext() {
+ try {
+ GLContext.useContext(null);
+ _canvasCallback.releaseContext();
+ } catch (final LWJGLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setCamera(final Camera camera) {
+ _camera = camera;
+ }
+
+ public RenderContext getRenderContext() {
+ return _currentContext;
+ }
+
+ public int getFrameClear() {
+ return _frameClear;
+ }
+
+ public void setFrameClear(final int buffers) {
+ _frameClear = buffers;
+ }
+} \ No newline at end of file
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglDisplayCanvas.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglDisplayCanvas.java
new file mode 100644
index 0000000..efacc46
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglDisplayCanvas.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.lwjgl;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.PixelFormat;
+
+import com.ardor3d.framework.Canvas;
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.input.FocusWrapper;
+import com.ardor3d.util.Ardor3dException;
+
+/**
+ * A Canvas implementation intended for use with an existing awt canvas.
+ * <p>
+ * XXX: Could/should this be merged with LwjglCanvas?
+ * </p>
+ */
+public class LwjglDisplayCanvas implements Canvas, FocusWrapper {
+ private static final Logger logger = Logger.getLogger(LwjglDisplayCanvas.class.getName());
+
+ private final LwjglCanvasRenderer _canvasRenderer;
+ private boolean _inited = false;
+ private final DisplaySettings _settings;
+
+ private volatile boolean _focusLost = false;
+
+ private final java.awt.Canvas _canvas;
+
+ public LwjglDisplayCanvas(final java.awt.Canvas canvas, final DisplaySettings settings,
+ final LwjglCanvasRenderer canvasRenderer) throws LWJGLException {
+ _settings = settings;
+ _canvasRenderer = canvasRenderer;
+ _canvas = canvas;
+ _canvasRenderer.setCanvasCallback(new LwjglCanvasCallback() {
+ @Override
+ public void makeCurrent() throws LWJGLException {
+ if (!LwjglCanvas.SINGLE_THREADED_MODE) {
+ Display.makeCurrent();
+ }
+ }
+
+ @Override
+ public void releaseContext() throws LWJGLException {
+ if (!LwjglCanvas.SINGLE_THREADED_MODE) {
+ Display.releaseContext();
+ }
+ }
+ });
+ }
+
+ public void draw(final CountDownLatch latch) {
+ if (!_inited) {
+ init();
+ }
+
+ checkFocus();
+
+ _canvasRenderer.draw();
+
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ private void checkFocus() {
+ // focusLost should be true if it is already true (hasn't been read/cleared yet), or
+ // the display is presently not in focus
+ _focusLost = _focusLost || !(Display.isActive() && Display.isVisible());
+ }
+
+ public boolean getAndClearFocusLost() {
+ final boolean result = _focusLost;
+
+ _focusLost = false;
+
+ return result;
+ }
+
+ public void init() {
+ if (_inited) {
+ return;
+ }
+
+ // create the Display.
+ final PixelFormat format = new PixelFormat(_settings.getAlphaBits(), _settings.getDepthBits(),
+ _settings.getStencilBits()).withSamples(_settings.getSamples()).withStereo(_settings.isStereo());
+
+ try {
+ Display.setParent(_canvas);
+ // NOTE: Workaround for possible lwjgl "pixel not accelerated" bug, as suggested by user "faust"
+ try {
+ Display.create(format);
+ } catch (final LWJGLException e) {
+ // failed to create Display, apply workaround (sleep for 1 second) and try again
+ Thread.sleep(1000);
+ Display.create(format);
+ }
+ } catch (final Exception e) {
+ logger.severe("Cannot create window");
+ logger.logp(Level.SEVERE, this.getClass().toString(), "initDisplay()", "Exception", e);
+ throw new Ardor3dException("Cannot create window: " + e.getMessage());
+ }
+
+ _canvasRenderer.init(_settings, true); // true - do swap in renderer.
+ _inited = true;
+ }
+
+ public LwjglCanvasRenderer getCanvasRenderer() {
+ return _canvasRenderer;
+ }
+
+ public void setVSyncEnabled(final boolean enabled) {
+ Display.setVSyncEnabled(enabled);
+ }
+
+ public void setFullScreen(final boolean fullScreen) throws LWJGLException {
+ Display.setFullscreen(fullScreen);
+ }
+
+ public boolean isFullScreen() {
+ return Display.isFullscreen();
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglHeadlessCanvas.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglHeadlessCanvas.java
new file mode 100644
index 0000000..26f8d78
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglHeadlessCanvas.java
@@ -0,0 +1,257 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.ARBMultisample;
+import org.lwjgl.opengl.EXTFramebufferObject;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GLContext;
+import org.lwjgl.opengl.Pbuffer;
+import org.lwjgl.opengl.PixelFormat;
+
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.framework.Scene;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Camera.ProjectionMode;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.lwjgl.LwjglContextCapabilities;
+import com.ardor3d.renderer.lwjgl.LwjglRenderer;
+import com.ardor3d.renderer.lwjgl.LwjglTextureRenderer;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.Constants;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * <p>
+ * A "canvas" class for use in drawing Scene data to an off-screen target. The data is read back after each call to draw
+ * into a local IntBuffer for use.
+ * </p>
+ *
+ * <p>
+ * Note: this class is not currently setup for use with other render contexts.
+ * </p>
+ */
+public class LwjglHeadlessCanvas {
+
+ protected Scene _scene;
+ protected Renderer _renderer = new LwjglRenderer();
+ protected final DisplaySettings _settings;
+ protected Camera _camera;
+
+ protected int _fboID, _depthRBID, _colorRBID;
+ protected IntBuffer _data;
+ protected Pbuffer _buff;
+
+ /**
+ * Construct a new LwjglHeadlessCanvas. Only width, height, alpha, depth and stencil are used. Samples will be
+ * applied as well but may cause issues on some platforms.
+ *
+ * @param settings
+ * the settings to use.
+ * @param scene
+ * the scene we will render.
+ */
+ public LwjglHeadlessCanvas(final DisplaySettings settings, final Scene scene) {
+ _scene = scene;
+ _settings = settings;
+ init();
+ }
+
+ protected void init() {
+ final int width = _settings.getWidth();
+ final int height = _settings.getHeight();
+
+ try {
+ // Create a Pbuffer so we can have a valid gl context to work with
+ final PixelFormat format = new PixelFormat(_settings.getAlphaBits(), _settings.getDepthBits(),
+ _settings.getStencilBits()).withSamples(_settings.getSamples());
+ _buff = new Pbuffer(1, 1, format, null);
+ _buff.makeCurrent();
+ } catch (final LWJGLException ex) {
+ try {
+ // try again without samples
+ final PixelFormat format = new PixelFormat(_settings.getAlphaBits(), _settings.getDepthBits(),
+ _settings.getStencilBits());
+ _buff = new Pbuffer(1, 1, format, null);
+ _buff.makeCurrent();
+ } catch (final LWJGLException ex2) {
+ ex2.printStackTrace();
+ }
+ }
+
+ // Set up our Ardor3D context and capabilities objects
+ final LwjglContextCapabilities caps = new LwjglContextCapabilities(GLContext.getCapabilities());
+ final RenderContext currentContext = new RenderContext(this, caps, null);
+
+ if (!caps.isFBOSupported()) {
+ throw new Ardor3dException("Headless requires FBO support.");
+ }
+
+ // Init our FBO.
+ final IntBuffer buffer = BufferUtils.createIntBuffer(1);
+ EXTFramebufferObject.glGenFramebuffersEXT(buffer); // generate id
+
+ // Bind the FBO
+ _fboID = buffer.get(0);
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, _fboID);
+
+ // initial our color renderbuffer
+ EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
+ _colorRBID = buffer.get(0);
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _colorRBID);
+ EXTFramebufferObject.glRenderbufferStorageEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, GL11.GL_RGBA, width,
+ height);
+ // Attach color renderbuffer to framebuffer
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, _colorRBID);
+
+ // initialize our depth renderbuffer
+ EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
+ _depthRBID = buffer.get(0);
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _depthRBID);
+ EXTFramebufferObject.glRenderbufferStorageEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT,
+ GL11.GL_DEPTH_COMPONENT, width, height);
+ // Attach depth renderbuffer to framebuffer
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, _depthRBID);
+
+ // Check FBO complete
+ LwjglTextureRenderer.checkFBOComplete(_fboID);
+
+ // Setup our data buffer for storing rendered image data.
+ _data = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
+
+ // Add context to manager and set as active.
+ ContextManager.addContext(this, currentContext);
+ ContextManager.switchContext(this);
+
+ // Turn on multisample if requested...
+ if (_settings.getSamples() != 0 && caps.isMultisampleSupported()) {
+ GL11.glEnable(ARBMultisample.GL_MULTISAMPLE_ARB);
+ }
+
+ // Setup a default bg color.
+ _renderer.setBackgroundColor(ColorRGBA.BLACK);
+
+ // Setup a default camera
+ _camera = new Camera(width, _settings.getHeight());
+ _camera.setFrustumPerspective(45.0f, (float) width / (float) _settings.getHeight(), 1, 1000);
+ _camera.setProjectionMode(ProjectionMode.Perspective);
+
+ // setup camera orientation and position.
+ final Vector3 loc = new Vector3(0.0f, 0.0f, 0.0f);
+ final Vector3 left = new Vector3(-1.0f, 0.0f, 0.0f);
+ final Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
+ final Vector3 dir = new Vector3(0.0f, 0f, -1.0f);
+ _camera.setFrame(loc, left, up, dir);
+
+ if (Constants.useMultipleContexts) {
+ // release our FBO until used.
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
+ }
+ }
+
+ public void draw() {
+ if (Constants.useMultipleContexts) {
+ // activate FBO
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, _fboID);
+ }
+
+ // Make sure this OpenGL context is current.
+ ContextManager.switchContext(this);
+ try {
+ _buff.makeCurrent();
+ } catch (final LWJGLException ex) {
+ ex.printStackTrace();
+ }
+
+ // make sure camera is set
+ if (Camera.getCurrentCamera() != _camera) {
+ _camera.update();
+ }
+ _camera.apply(_renderer);
+
+ // clear buffers
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+ _renderer.clearBuffers(Renderer.BUFFER_COLOR | Renderer.BUFFER_DEPTH);
+
+ // draw our scene
+ _scene.renderUnto(_renderer);
+ _renderer.flushFrame(false);
+
+ // read data from our color buffer
+ _data.rewind();
+ GL11.glReadBuffer(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT);
+ GL11.glReadPixels(0, 0, _settings.getWidth(), _settings.getHeight(), GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, _data);
+
+ if (Constants.useMultipleContexts) {
+ // release our FBO.
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
+ }
+ }
+
+ public void releaseContext() throws LWJGLException {
+ _buff.releaseContext();
+ }
+
+ public void cleanup() {
+ if (_fboID != 0) {
+ final IntBuffer id = BufferUtils.createIntBuffer(1);
+ id.put(_fboID);
+ id.rewind();
+ EXTFramebufferObject.glDeleteFramebuffersEXT(id);
+ _fboID = 0;
+ }
+
+ if (_depthRBID != 0) {
+ final IntBuffer id = BufferUtils.createIntBuffer(1);
+ id.put(_depthRBID);
+ id.rewind();
+ EXTFramebufferObject.glDeleteRenderbuffersEXT(id);
+ _depthRBID = 0;
+ }
+
+ if (_colorRBID != 0) {
+ final IntBuffer id = BufferUtils.createIntBuffer(1);
+ id.put(_colorRBID);
+ id.rewind();
+ EXTFramebufferObject.glDeleteRenderbuffersEXT(id);
+ _colorRBID = 0;
+ }
+ ContextManager.removeContext(this);
+ }
+
+ public IntBuffer getDataBuffer() {
+ return _data;
+ }
+
+ public Renderer getRenderer() {
+ return _renderer;
+ }
+
+ public Camera getCamera() {
+ return _camera;
+ }
+
+ public void setCamera(final Camera camera) {
+ _camera = camera;
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglLibraryPaths.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglLibraryPaths.java
new file mode 100644
index 0000000..b6e38df
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/framework/lwjgl/LwjglLibraryPaths.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+
+package com.ardor3d.framework.lwjgl;
+
+/**
+ * TODO: document this class!
+ *
+ */
+public enum LwjglLibraryPaths {
+ MACOSX("Mac OS X", null, new String[] {
+ "/macosx/libjinput-osx.jnilib",
+ "/macosx/liblwjgl.jnilib",
+ "/macosx/openal.dylib",
+ }),
+ LINUX_AMD64("Linux", "amd64", new String[] {
+ "/linux/libjinput-linux64.so",
+ "/linux/liblwjgl64.so",
+ "/linux/libopenal64.so",
+ }),
+ LINUX_I386("Linux", "i386", new String[] {
+ "/linux/libjinput-linux.so",
+ "/linux/liblwjgl.so",
+ "/linux/libopenal.so",
+ }),
+ // NOTE: the order of the elements in this array is significant, so the catchall has to come last,
+ // or it will shadow more specific alternatives
+ LINUX_CATCHALL("Linux", null, new String[] {
+ "/linux/libjinput-linux.so",
+ "/linux/liblwjgl.so",
+ "/linux/libopenal.so",
+ }),
+ SOLARIS("TODO", null, new String[] {
+ "/solaris/liblwjgl.so",
+ "/solaris/libopenal.so",
+ }),
+ WINDOWS_XP("Windows XP", null, new String[] {
+ "/windows/jinput-dx8.dll",
+ "/windows/jinput-raw.dll",
+ "/windows/lwjgl.dll",
+ "/windows/OpenAL32.dll",
+ });
+
+ private final String _operatingSystem;
+ private final String _architecture;
+ private final String[] _libraryPaths;
+
+
+ LwjglLibraryPaths(String operatingSystem, String architecture, String[] libraryPaths) {
+ _operatingSystem = operatingSystem;
+ _architecture = architecture;
+ _libraryPaths = libraryPaths;
+ }
+
+ public static String[] getLibraryPaths(String operatingSystem, String architecture) {
+ for (LwjglLibraryPaths libraryPath : values()) {
+ if (operatingSystem.equals(libraryPath._operatingSystem) &&
+ (libraryPath._architecture == null || architecture.equals(libraryPath._architecture))) {
+ return libraryPath._libraryPaths;
+ }
+ }
+
+ throw new IllegalStateException("No matching set of library paths found for " + operatingSystem + ", " + architecture);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(System.getProperty("os.name"));
+ System.out.println(System.getProperty("os.arch"));
+
+ System.getProperties();
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/input/jinput/JInputControllerWrapper.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/jinput/JInputControllerWrapper.java
new file mode 100644
index 0000000..fed0775
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/jinput/JInputControllerWrapper.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.input.jinput;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import net.java.games.input.Component;
+import net.java.games.input.Component.Identifier;
+import net.java.games.input.Controller;
+import net.java.games.input.Controller.Type;
+import net.java.games.input.ControllerEnvironment;
+import net.java.games.input.Event;
+
+import com.ardor3d.input.ControllerEvent;
+import com.ardor3d.input.ControllerInfo;
+import com.ardor3d.input.ControllerState;
+import com.ardor3d.input.ControllerWrapper;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Lists;
+import com.google.common.collect.PeekingIterator;
+
+public class JInputControllerWrapper implements ControllerWrapper {
+
+ protected final Event _event = new Event();
+ protected final List<ControllerEvent> _events = Collections.synchronizedList(new ArrayList<ControllerEvent>());
+ protected JInputControllerEventIterator _eventsIt = new JInputControllerEventIterator();
+ protected final List<ControllerInfo> _controllers = Lists.newArrayList();
+ protected static boolean _inited = false;
+
+ public PeekingIterator<ControllerEvent> getEvents() {
+ init();
+ if (!_eventsIt.hasNext()) {
+ _eventsIt = new JInputControllerEventIterator();
+ }
+ for (final Controller controller : ControllerEnvironment.getDefaultEnvironment().getControllers()) {
+ controller.poll();
+ while (controller.getEventQueue().getNextEvent(_event)) {
+ if (controller.getType() != Type.KEYBOARD && controller.getType() != Type.MOUSE) {
+ _events.add(createControllerEvent(controller, _event));
+ }
+ }
+ }
+
+ return _eventsIt;
+ }
+
+ @Override
+ public int getControllerCount() {
+ init();
+ return _controllers.size();
+ }
+
+ @Override
+ public ControllerInfo getControllerInfo(final int controllerIndex) {
+ init();
+ return _controllers.get(controllerIndex);
+ }
+
+ public synchronized void init() {
+ if (_inited) {
+ return;
+ }
+
+ try {
+ ControllerEnvironment.getDefaultEnvironment();
+
+ for (final Controller controller : ControllerEnvironment.getDefaultEnvironment().getControllers()) {
+ if (controller.getType() != Type.KEYBOARD && controller.getType() != Type.MOUSE) {
+ _controllers.add(getControllerInfo(controller));
+ for (final Component component : controller.getComponents()) {
+ ControllerState.NOTHING.set(controller.getName(), component.getIdentifier().getName(), 0);
+ }
+ }
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ } finally {
+ _inited = true;
+ }
+ }
+
+ protected ControllerInfo getControllerInfo(final Controller controller) {
+ final List<String> axisNames = Lists.newArrayList();
+ final List<String> buttonNames = Lists.newArrayList();
+
+ for (final Component comp : controller.getComponents()) {
+ if (comp.getIdentifier() instanceof Identifier.Axis) {
+ axisNames.add(comp.getName());
+ } else if (comp.getIdentifier() instanceof Identifier.Button) {
+ buttonNames.add(comp.getName());
+ }
+ }
+
+ return new ControllerInfo(controller.getName(), axisNames, buttonNames);
+ }
+
+ protected ControllerEvent createControllerEvent(final Controller controller, final Event event) {
+ return new ControllerEvent(event.getNanos(), controller.getName(), event.getComponent().getIdentifier()
+ .getName(), event.getValue());
+ }
+
+ protected class JInputControllerEventIterator extends AbstractIterator<ControllerEvent> implements
+ PeekingIterator<ControllerEvent> {
+
+ @Override
+ protected ControllerEvent computeNext() {
+ if (_events.size() > 0) {
+ final ControllerEvent controllerEvent = _events.remove(0);
+ return controllerEvent;
+ } else {
+ return endOfData();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglControllerWrapper.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglControllerWrapper.java
new file mode 100644
index 0000000..d92fdc3
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglControllerWrapper.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.input.lwjgl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.lwjgl.input.Controller;
+import org.lwjgl.input.Controllers;
+
+import com.ardor3d.input.ControllerEvent;
+import com.ardor3d.input.ControllerInfo;
+import com.ardor3d.input.ControllerState;
+import com.ardor3d.input.ControllerWrapper;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Lists;
+import com.google.common.collect.PeekingIterator;
+
+public class LwjglControllerWrapper implements ControllerWrapper {
+
+ protected static boolean _inited = false;
+ protected final List<ControllerEvent> _events = Collections.synchronizedList(new ArrayList<ControllerEvent>());
+ protected LwjglControllerEventIterator _eventsIt = new LwjglControllerEventIterator();
+ protected final List<ControllerInfo> _controllers = Lists.newArrayList();
+
+ private class LwjglControllerEventIterator extends AbstractIterator<ControllerEvent> implements
+ PeekingIterator<ControllerEvent> {
+
+ @Override
+ protected ControllerEvent computeNext() {
+ if (_events.size() > 0) {
+ return _events.remove(0);
+ } else {
+ return endOfData();
+ }
+ }
+ }
+
+ public PeekingIterator<ControllerEvent> getEvents() {
+ init();
+ if (!_eventsIt.hasNext()) {
+ _eventsIt = new LwjglControllerEventIterator();
+ }
+
+ while (Controllers.next()) {
+ final Controller source = Controllers.getEventSource();
+ if (Controllers.isEventButton()) {
+ _events.add(new ControllerEvent(Controllers.getEventNanoseconds(), source.getName(), source
+ .getButtonName(Controllers.getEventControlIndex()), source.isButtonPressed(Controllers
+ .getEventControlIndex()) ? 1f : 0f));
+ } else if (Controllers.isEventAxis()) {
+ _events.add(new ControllerEvent(Controllers.getEventNanoseconds(), source.getName(), source
+ .getAxisName(Controllers.getEventControlIndex()), source.getAxisValue(Controllers
+ .getEventControlIndex())));
+ } else if (Controllers.isEventPovX()) {
+ _events.add(new ControllerEvent(Controllers.getEventNanoseconds(), source.getName(), "Pov X", source
+ .getPovX()));
+ } else if (Controllers.isEventPovY()) {
+ _events.add(new ControllerEvent(Controllers.getEventNanoseconds(), source.getName(), "Pov Y", source
+ .getPovY()));
+ }
+ }
+
+ return _eventsIt;
+ }
+
+ public synchronized void init() {
+ if (_inited) {
+ return;
+ }
+ try {
+ Controllers.create();
+ for (int i = 0, max = Controllers.getControllerCount(); i < max; i++) {
+ final Controller controller = Controllers.getController(i);
+ _controllers.add(getControllerInfo(controller));
+ for (int j = 0; j < controller.getAxisCount(); j++) {
+ ControllerState.NOTHING.set(controller.getName(), controller.getAxisName(j), 0);
+ }
+ for (int j = 0; j < controller.getButtonCount(); j++) {
+ ControllerState.NOTHING.set(controller.getName(), controller.getButtonName(j), 0);
+ }
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ } finally {
+ _inited = true;
+ }
+ }
+
+ protected ControllerInfo getControllerInfo(final Controller controller) {
+ final List<String> axisNames = Lists.newArrayList();
+ final List<String> buttonNames = Lists.newArrayList();
+
+ for (int i = 0; i < controller.getAxisCount(); i++) {
+ axisNames.add(controller.getAxisName(i));
+ }
+ for (int i = 0; i < controller.getButtonCount(); i++) {
+ buttonNames.add(controller.getButtonName(i));
+ }
+
+ return new ControllerInfo(controller.getName(), axisNames, buttonNames);
+ }
+
+ @Override
+ public int getControllerCount() {
+ init();
+ return Controllers.getControllerCount();
+ }
+
+ @Override
+ public ControllerInfo getControllerInfo(final int controllerIndex) {
+ init();
+ return _controllers.get(controllerIndex);
+ }
+} \ No newline at end of file
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKey.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKey.java
new file mode 100644
index 0000000..8b4a03b
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKey.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.input.lwjgl;
+
+import org.lwjgl.input.Keyboard;
+
+import com.ardor3d.input.Key;
+
+public enum LwjglKey {
+
+ ZERO(Keyboard.KEY_0, Key.ZERO), //
+ ONE(Keyboard.KEY_1, Key.ONE), //
+ TWO(Keyboard.KEY_2, Key.TWO), //
+ THREE(Keyboard.KEY_3, Key.THREE), //
+ FOUR(Keyboard.KEY_4, Key.FOUR), //
+ FIVE(Keyboard.KEY_5, Key.FIVE), //
+ SIX(Keyboard.KEY_6, Key.SIX), //
+ SEVEN(Keyboard.KEY_7, Key.SEVEN), //
+ EIGHT(Keyboard.KEY_8, Key.EIGHT), //
+ NINE(Keyboard.KEY_9, Key.NINE), //
+ A(Keyboard.KEY_A, Key.A), //
+ ADD(Keyboard.KEY_ADD, Key.NUMPADADD), //
+ APOSTROPHE(Keyboard.KEY_APOSTROPHE, Key.APOSTROPHE), //
+ APPS(Keyboard.KEY_APPS, Key.APPS), //
+ AT(Keyboard.KEY_AT, Key.AT), //
+ AX(Keyboard.KEY_AX, Key.AX), //
+ B(Keyboard.KEY_B, Key.B), //
+ BACK(Keyboard.KEY_BACK, Key.BACK), //
+ BACKSLASH(Keyboard.KEY_BACKSLASH, Key.BACKSLASH), //
+ C(Keyboard.KEY_C, Key.C), //
+ CAPITAL(Keyboard.KEY_CAPITAL, Key.CAPITAL), //
+ CIRCUMFLEX(Keyboard.KEY_CIRCUMFLEX, Key.CIRCUMFLEX), //
+ COLON(Keyboard.KEY_COLON, Key.COLON), //
+ COMMA(Keyboard.KEY_COMMA, Key.COMMA), //
+ CONVERT(Keyboard.KEY_CONVERT, Key.CONVERT), //
+ D(Keyboard.KEY_D, Key.D), //
+ DECIMAL(Keyboard.KEY_DECIMAL, Key.DECIMAL), //
+ DELETE(Keyboard.KEY_DELETE, Key.DELETE), //
+ DIVIDE(Keyboard.KEY_DIVIDE, Key.DIVIDE), //
+ DOWN(Keyboard.KEY_DOWN, Key.DOWN), //
+ E(Keyboard.KEY_E, Key.E), //
+ END(Keyboard.KEY_END, Key.END), //
+ EQUALS(Keyboard.KEY_EQUALS, Key.EQUALS), //
+ ESCAPE(Keyboard.KEY_ESCAPE, Key.ESCAPE), //
+ F(Keyboard.KEY_F, Key.F), //
+ F1(Keyboard.KEY_F1, Key.F1), //
+ F2(Keyboard.KEY_F2, Key.F2), //
+ F3(Keyboard.KEY_F3, Key.F3), //
+ F4(Keyboard.KEY_F4, Key.F4), //
+ F5(Keyboard.KEY_F5, Key.F5), //
+ F6(Keyboard.KEY_F6, Key.F6), //
+ F7(Keyboard.KEY_F7, Key.F7), //
+ F8(Keyboard.KEY_F8, Key.F8), //
+ F9(Keyboard.KEY_F9, Key.F9), //
+ F10(Keyboard.KEY_F10, Key.F10), //
+ F11(Keyboard.KEY_F11, Key.F11), //
+ F12(Keyboard.KEY_F12, Key.F12), //
+ F13(Keyboard.KEY_F13, Key.F13), //
+ F14(Keyboard.KEY_F14, Key.F14), //
+ F15(Keyboard.KEY_F15, Key.F15), //
+ G(Keyboard.KEY_G, Key.G), //
+ GRAVE(Keyboard.KEY_GRAVE, Key.GRAVE), //
+ H(Keyboard.KEY_H, Key.H), //
+ HOME(Keyboard.KEY_HOME, Key.HOME), //
+ I(Keyboard.KEY_I, Key.I), //
+ INSERT(Keyboard.KEY_INSERT, Key.INSERT), //
+ J(Keyboard.KEY_J, Key.J), //
+ K(Keyboard.KEY_K, Key.K), //
+ KANA(Keyboard.KEY_KANA, Key.KANA), //
+ KANJI(Keyboard.KEY_KANJI, Key.KANJI), //
+ L(Keyboard.KEY_L, Key.L), //
+ LBRACKET(Keyboard.KEY_LBRACKET, Key.LBRACKET), //
+ LCONTROL(Keyboard.KEY_LCONTROL, Key.LCONTROL), //
+ LEFT(Keyboard.KEY_LEFT, Key.LEFT), //
+ LMENU(Keyboard.KEY_LMENU, Key.LMENU), //
+ LMETA(Keyboard.KEY_LMETA, Key.LMETA), //
+ LSHIFT(Keyboard.KEY_LSHIFT, Key.LSHIFT), //
+ M(Keyboard.KEY_M, Key.M), //
+ MINUS(Keyboard.KEY_MINUS, Key.MINUS), //
+ MULTIPLY(Keyboard.KEY_MULTIPLY, Key.MULTIPLY), //
+ N(Keyboard.KEY_N, Key.N), //
+ NEXT(Keyboard.KEY_NEXT, Key.PAGEDOWN_NEXT), //
+ NOCONVERT(Keyboard.KEY_NOCONVERT, Key.NOCONVERT), //
+ NUMLOCK(Keyboard.KEY_NUMLOCK, Key.NUMLOCK), //
+ NUMPAD0(Keyboard.KEY_NUMPAD0, Key.NUMPAD0), //
+ NUMPAD1(Keyboard.KEY_NUMPAD1, Key.NUMPAD1), //
+ NUMPAD2(Keyboard.KEY_NUMPAD2, Key.NUMPAD2), //
+ NUMPAD3(Keyboard.KEY_NUMPAD3, Key.NUMPAD3), //
+ NUMPAD4(Keyboard.KEY_NUMPAD4, Key.NUMPAD4), //
+ NUMPAD5(Keyboard.KEY_NUMPAD5, Key.NUMPAD5), //
+ NUMPAD6(Keyboard.KEY_NUMPAD6, Key.NUMPAD6), //
+ NUMPAD7(Keyboard.KEY_NUMPAD7, Key.NUMPAD7), //
+ NUMPAD8(Keyboard.KEY_NUMPAD8, Key.NUMPAD8), //
+ NUMPAD9(Keyboard.KEY_NUMPAD9, Key.NUMPAD9), //
+ NUMPADCOMMA(Keyboard.KEY_NUMPADCOMMA, Key.NUMPADCOMMA), //
+ NUMPADENTER(Keyboard.KEY_NUMPADENTER, Key.NUMPADENTER), //
+ NUMPADEQUALS(Keyboard.KEY_NUMPADEQUALS, Key.NUMPADEQUALS), //
+ O(Keyboard.KEY_O, Key.O), //
+ P(Keyboard.KEY_P, Key.P), //
+ PAUSE(Keyboard.KEY_PAUSE, Key.PAUSE), //
+ POWER(Keyboard.KEY_POWER, Key.POWER), //
+ PERIOD(Keyboard.KEY_PERIOD, Key.PERIOD), //
+ PRIOR(Keyboard.KEY_PRIOR, Key.PAGEUP_PRIOR), //
+ Q(Keyboard.KEY_Q, Key.Q), //
+ R(Keyboard.KEY_R, Key.R), //
+ RBRACKET(Keyboard.KEY_RBRACKET, Key.RBRACKET), //
+ RCONTROL(Keyboard.KEY_RCONTROL, Key.RCONTROL), //
+ RETURN(Keyboard.KEY_RETURN, Key.RETURN), //
+ RIGHT(Keyboard.KEY_RIGHT, Key.RIGHT), //
+ RMENU(Keyboard.KEY_RMENU, Key.RMENU), //
+ RMETA(Keyboard.KEY_RMETA, Key.RMETA), //
+ RSHIFT(Keyboard.KEY_RSHIFT, Key.RSHIFT), //
+ S(Keyboard.KEY_S, Key.S), //
+ SCROLL(Keyboard.KEY_SCROLL, Key.SCROLL), //
+ SEMICOLON(Keyboard.KEY_SEMICOLON, Key.SEMICOLON), //
+ SLASH(Keyboard.KEY_SLASH, Key.SLASH), //
+ SLEEP(Keyboard.KEY_SLEEP, Key.SLEEP), //
+ SPACE(Keyboard.KEY_SPACE, Key.SPACE), //
+ STOP(Keyboard.KEY_STOP, Key.STOP), //
+ NUMPADSUBTRACT(Keyboard.KEY_SUBTRACT, Key.NUMPADSUBTRACT), // XXX: Not sure if this is correct?
+ SYSRQ(Keyboard.KEY_SYSRQ, Key.SYSRQ), //
+ T(Keyboard.KEY_T, Key.T), //
+ TAB(Keyboard.KEY_TAB, Key.TAB), //
+ U(Keyboard.KEY_U, Key.U), //
+ UNDERLINE(Keyboard.KEY_UNDERLINE, Key.UNDERLINE), //
+ UNLABELED(Keyboard.KEY_UNLABELED, Key.UNLABELED), //
+ UP(Keyboard.KEY_UP, Key.UP), //
+ V(Keyboard.KEY_V, Key.V), //
+ W(Keyboard.KEY_W, Key.W), //
+ X(Keyboard.KEY_X, Key.X), //
+ Y(Keyboard.KEY_Y, Key.Y), //
+ YEN(Keyboard.KEY_YEN, Key.YEN), //
+ Z(Keyboard.KEY_Z, Key.Z), //
+ NONE(Keyboard.KEY_NONE, Key.UNKNOWN);
+
+ private final int _lwjglCode;
+ private final Key _key;
+
+ private LwjglKey(final int lwjglCode, final Key key) {
+ _lwjglCode = lwjglCode;
+ _key = key;
+ }
+
+ /**
+ * Locate a key, given a specific lwjgl key code.
+ *
+ * @param lwjglCode
+ * the lwjgl key code.
+ * @return the Ardor3D Key enum value.
+ */
+ public static Key findByCode(final int lwjglCode) {
+ for (final LwjglKey ak : values()) {
+ if (ak._lwjglCode == lwjglCode) {
+ return ak._key;
+ }
+ }
+
+ return Key.UNKNOWN;
+ }
+
+ public int getLwjglCode() {
+ return _lwjglCode;
+ }
+
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKeyboardWrapper.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKeyboardWrapper.java
new file mode 100644
index 0000000..de4c991
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglKeyboardWrapper.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.input.lwjgl;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Keyboard;
+
+import com.ardor3d.input.Key;
+import com.ardor3d.input.KeyEvent;
+import com.ardor3d.input.KeyState;
+import com.ardor3d.input.KeyboardWrapper;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.PeekingIterator;
+
+/**
+ * Wraps the {@link org.lwjgl.input.Keyboard} class.
+ */
+public class LwjglKeyboardWrapper implements KeyboardWrapper {
+ private LwjglKeyEventIterator _currentIterator = null;
+
+ public void init() {
+ if (!Keyboard.isCreated()) {
+ try {
+ Keyboard.create();
+ } catch (final LWJGLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public PeekingIterator<KeyEvent> getEvents() {
+ if (_currentIterator == null || !_currentIterator.hasNext()) {
+ _currentIterator = new LwjglKeyEventIterator();
+ }
+
+ return _currentIterator;
+ }
+
+ private static class LwjglKeyEventIterator extends AbstractIterator<KeyEvent> implements PeekingIterator<KeyEvent> {
+
+ @Override
+ protected KeyEvent computeNext() {
+ if (!Keyboard.next()) {
+ return endOfData();
+ }
+
+ final int keyCode = Keyboard.getEventKey();
+ final boolean pressed = Keyboard.getEventKeyState();
+ final char keyChar = Keyboard.getEventCharacter();
+
+ final Key k = LwjglKey.findByCode(keyCode);
+
+ return new KeyEvent(k, pressed ? KeyState.DOWN : KeyState.UP, keyChar);
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseManager.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseManager.java
new file mode 100644
index 0000000..b689841
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseManager.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.input.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Cursor;
+import org.lwjgl.input.Mouse;
+
+import com.ardor3d.annotation.MainThread;
+import com.ardor3d.image.Image;
+import com.ardor3d.image.ImageDataFormat;
+import com.ardor3d.input.GrabbedState;
+import com.ardor3d.input.MouseCursor;
+import com.ardor3d.input.MouseManager;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * LWJGL-specific implementation of the {@link com.ardor3d.input.MouseManager} interface. No methods in this class
+ * should be called before the LWJGL Display has been initialized, since this class is dependent on being able to
+ * initialize the {@link org.lwjgl.input.Mouse} class.
+ */
+public class LwjglMouseManager implements MouseManager {
+ private boolean _inited = false;
+
+ private void init() {
+ if (!_inited) {
+ if (!Mouse.isCreated()) {
+ try {
+ Mouse.create();
+ } catch (final Exception e) {
+ // this typically happens if the Display hasn't been initialized.
+ throw new RuntimeException("Unable to initialise mouse manager", e);
+ }
+ }
+ _inited = true;
+ }
+ }
+
+ @MainThread
+ public void setCursor(final MouseCursor cursor) {
+ init();
+
+ try {
+ final Cursor lwjglCursor = createLwjglCursor(cursor);
+
+ if (lwjglCursor == null || !lwjglCursor.equals(Mouse.getNativeCursor())) {
+ Mouse.setNativeCursor(lwjglCursor);
+ }
+ } catch (final LWJGLException e) {
+ throw new RuntimeException("Unable to set cursor", e);
+ }
+ }
+
+ private Cursor createLwjglCursor(final MouseCursor cursor) throws LWJGLException {
+ if (cursor == MouseCursor.SYSTEM_DEFAULT) {
+ return null; // setting the cursor to null in LWJGL means using the system default one
+ }
+
+ final boolean eightBitAlpha = (Cursor.getCapabilities() & Cursor.CURSOR_8_BIT_ALPHA) != 0;
+
+ final Image image = cursor.getImage();
+
+ final boolean isRgba = image.getDataFormat() == ImageDataFormat.RGBA;
+ final int imageWidth = image.getWidth();
+ final int imageHeight = image.getHeight();
+
+ final ByteBuffer imageData = image.getData(0);
+ imageData.rewind();
+ final IntBuffer imageDataCopy = BufferUtils.createIntBuffer(imageWidth * imageHeight);
+
+ for (int y = 0; y < imageHeight; y++) {
+ for (int x = 0; x < imageWidth; x++) {
+ final int index = y * imageWidth + x;
+
+ int r = imageData.get() & 0xff;
+ int g = imageData.get() & 0xff;
+ int b = imageData.get() & 0xff;
+ int a = 0xff;
+ if (isRgba) {
+ a = imageData.get() & 0xff;
+ if (!eightBitAlpha) {
+ if (a < 0x7f) {
+ a = 0x00;
+ // small hack to prevent triggering "reverse screen" on windows.
+ r = g = b = 0;
+ } else {
+ a = 0xff;
+ }
+ }
+ }
+
+ imageDataCopy.put(index, (a << 24) | (r << 16) | (g << 8) | b);
+ }
+ }
+
+ return new Cursor(imageWidth, imageHeight, cursor.getHotspotX(), cursor.getHotspotY(), 1, imageDataCopy, null);
+ }
+
+ public void setPosition(final int x, final int y) {
+ init();
+
+ Mouse.setCursorPosition(x, y);
+ }
+
+ public void setGrabbed(final GrabbedState grabbedState) {
+ init();
+
+ switch (grabbedState) {
+ case GRABBED:
+ Mouse.setGrabbed(true);
+ break;
+ case NOT_GRABBED:
+ Mouse.setGrabbed(false);
+ break;
+ default:
+ throw new IllegalStateException("Unhandled GrabbedState: " + grabbedState);
+ }
+ }
+
+ public boolean isSetPositionSupported() {
+ return true;
+ }
+
+ public boolean isSetGrabbedSupported() {
+ return true;
+ }
+
+ public GrabbedState getGrabbed() {
+ return Mouse.isGrabbed() ? GrabbedState.GRABBED : GrabbedState.NOT_GRABBED;
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseWrapper.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseWrapper.java
new file mode 100644
index 0000000..d554183
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/input/lwjgl/LwjglMouseWrapper.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.input.lwjgl;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import org.lwjgl.input.Mouse;
+
+import com.ardor3d.input.ButtonState;
+import com.ardor3d.input.MouseButton;
+import com.ardor3d.input.MouseState;
+import com.ardor3d.input.MouseWrapper;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.EnumMultiset;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.PeekingIterator;
+
+/**
+ * Wrapper over the {@link org.lwjgl.input.Mouse} mouse interface class.
+ */
+public class LwjglMouseWrapper implements MouseWrapper {
+ private LwjglMouseIterator _currentIterator = null;
+
+ private static final Multiset<MouseButton> _clicks = EnumMultiset.create(MouseButton.class);
+ private static final EnumMap<MouseButton, Long> _lastClickTime = Maps.newEnumMap(MouseButton.class);
+ private static final EnumSet<MouseButton> _clickArmed = EnumSet.noneOf(MouseButton.class);
+
+ private static boolean _sendClickState = false;
+ private static MouseState _nextState;
+
+ public LwjglMouseWrapper() {
+ for (final MouseButton mb : MouseButton.values()) {
+ _lastClickTime.put(mb, 0L);
+ }
+ }
+
+ public void init() {
+ if (!Mouse.isCreated()) {
+ try {
+ Mouse.create();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public PeekingIterator<MouseState> getEvents() {
+ // only create a new iterator if there isn't an existing, valid, one.
+ if (_currentIterator == null || !_currentIterator.hasNext()) {
+ _currentIterator = new LwjglMouseIterator();
+ }
+
+ return _currentIterator;
+ }
+
+ private static class LwjglMouseIterator extends AbstractIterator<MouseState> implements PeekingIterator<MouseState> {
+
+ public LwjglMouseIterator() {}
+
+ @Override
+ protected MouseState computeNext() {
+ if (_nextState != null) {
+ final MouseState rVal = _nextState;
+ _nextState = null;
+ return rVal;
+ }
+
+ if (!Mouse.next()) {
+ return endOfData();
+ }
+
+ final EnumMap<MouseButton, ButtonState> buttons = Maps.newEnumMap(MouseButton.class);
+
+ if (Mouse.getButtonCount() > 0) {
+ final boolean down = Mouse.isButtonDown(0);
+ processButtonForClick(MouseButton.LEFT, down);
+ buttons.put(MouseButton.LEFT, down ? ButtonState.DOWN : ButtonState.UP);
+ }
+ if (Mouse.getButtonCount() > 1) {
+ final boolean down = Mouse.isButtonDown(1);
+ processButtonForClick(MouseButton.RIGHT, down);
+ buttons.put(MouseButton.RIGHT, down ? ButtonState.DOWN : ButtonState.UP);
+ }
+ if (Mouse.getButtonCount() > 2) {
+ final boolean down = Mouse.isButtonDown(2);
+ processButtonForClick(MouseButton.MIDDLE, down);
+ buttons.put(MouseButton.MIDDLE, down ? ButtonState.DOWN : ButtonState.UP);
+ }
+
+ final MouseState nextState = new MouseState(Mouse.getEventX(), Mouse.getEventY(), Mouse.getEventDX(), Mouse
+ .getEventDY(), Mouse.getEventDWheel(), buttons, null);
+
+ if (nextState.getDx() != 0.0 || nextState.getDy() != 0.0) {
+ _clickArmed.clear();
+ _clicks.clear();
+ _sendClickState = false;
+ }
+
+ if (_sendClickState) {
+ _nextState = nextState;
+ _sendClickState = false;
+ return new MouseState(nextState.getX(), nextState.getY(), nextState.getDx(), nextState.getDy(),
+ nextState.getDwheel(), buttons, EnumMultiset.create(_clicks));
+ } else {
+ return nextState;
+ }
+ }
+
+ private void processButtonForClick(final MouseButton b, final boolean down) {
+ boolean expired = false;
+ if (System.currentTimeMillis() - _lastClickTime.get(b) > MouseState.CLICK_TIME_MS) {
+ _clicks.setCount(b, 0);
+ expired = true;
+ }
+ if (down) {
+ if (_clickArmed.contains(b)) {
+ _clicks.setCount(b, 0);
+ }
+ _clickArmed.add(b);
+ _lastClickTime.put(b, System.currentTimeMillis());
+ } else {
+ if (!expired && _clickArmed.contains(b)) {
+ _clicks.add(b); // increment count of clicks for button b.
+ // XXX: Note the double event add... this prevents sticky click counts, but is it the best way?
+ _sendClickState = true;
+ } else {
+ _clicks.setCount(b, 0); // clear click count for button b.
+ }
+ _clickArmed.remove(b);
+ }
+ }
+
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglContextCapabilities.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglContextCapabilities.java
new file mode 100644
index 0000000..af52d28
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglContextCapabilities.java
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.renderer.lwjgl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+import org.lwjgl.opengl.ARBFragmentShader;
+import org.lwjgl.opengl.ARBMultitexture;
+import org.lwjgl.opengl.ARBVertexShader;
+import org.lwjgl.opengl.EXTFramebufferMultisample;
+import org.lwjgl.opengl.EXTFramebufferObject;
+import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
+import org.lwjgl.opengl.EXTTextureLODBias;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL20;
+
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.util.geom.BufferUtils;
+
+public class LwjglContextCapabilities extends ContextCapabilities {
+
+ public LwjglContextCapabilities(final ContextCapabilities caps) {
+ super(caps);
+ }
+
+ public LwjglContextCapabilities(final org.lwjgl.opengl.ContextCapabilities caps) {
+ final IntBuffer buf = BufferUtils.createIntBuffer(16);
+
+ _supportsVBO = caps.GL_ARB_vertex_buffer_object;
+ _supportsGL1_2 = caps.OpenGL12;
+ _supportsMultisample = caps.GL_ARB_multisample;
+
+ _supportsConstantColor = _supportsEq = caps.GL_ARB_imaging;
+ _supportsSeparateFunc = caps.GL_EXT_blend_func_separate;
+ _supportsSeparateEq = caps.GL_EXT_blend_equation_separate;
+ _supportsMinMax = caps.GL_EXT_blend_minmax;
+ _supportsSubtract = caps.GL_EXT_blend_subtract;
+
+ _supportsFogCoords = caps.GL_EXT_fog_coord;
+ _supportsFragmentProgram = caps.GL_ARB_fragment_program;
+ _supportsVertexProgram = caps.GL_ARB_vertex_program;
+
+ _supportsPointSprites = caps.GL_ARB_point_sprite;
+ _supportsPointParameters = caps.GL_ARB_point_parameters;
+
+ _supportsTextureLodBias = caps.GL_EXT_texture_lod_bias;
+ if (_supportsTextureLodBias) {
+ GL11.glGetInteger(EXTTextureLODBias.GL_MAX_TEXTURE_LOD_BIAS_EXT, buf);
+ _maxTextureLodBias = buf.get(0);
+ } else {
+ _maxTextureLodBias = 0f;
+ }
+
+ GL11.glGetInteger(GL11.GL_MAX_CLIP_PLANES, buf);
+ _maxUserClipPlanes = buf.get(0);
+
+ _glslSupported = caps.GL_ARB_shader_objects && caps.GL_ARB_fragment_shader && caps.GL_ARB_vertex_shader
+ && caps.GL_ARB_shading_language_100;
+
+ _geometryShader4Supported = caps.GL_ARB_geometry_shader4 && _glslSupported;
+
+ _geometryInstancingSupported = caps.GL_EXT_draw_instanced || caps.OpenGL30;
+
+ if (_glslSupported) {
+ GL11.glGetInteger(ARBVertexShader.GL_MAX_VERTEX_ATTRIBS_ARB, buf);
+ _maxGLSLVertexAttribs = buf.get(0);
+ }
+
+ // Pbuffer
+ _pbufferSupported = caps.GL_ARB_pixel_buffer_object;
+
+ // FBO
+ _fboSupported = caps.GL_EXT_framebuffer_object;
+ if (_fboSupported) {
+ if (caps.GL_ARB_draw_buffers) {
+ GL11.glGetInteger(EXTFramebufferObject.GL_MAX_COLOR_ATTACHMENTS_EXT, buf);
+ _maxFBOColorAttachments = buf.get(0);
+ } else {
+ _maxFBOColorAttachments = 1;
+ }
+
+ // Max multisample samples.
+ if (caps.GL_EXT_framebuffer_multisample && caps.GL_EXT_framebuffer_blit) {
+ GL11.glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT, buf);
+ _maxFBOSamples = buf.get(0);
+ } else {
+ _maxFBOSamples = 0;
+ }
+ } else {
+ _maxFBOColorAttachments = 0;
+ }
+
+ _twoSidedStencilSupport = caps.GL_EXT_stencil_two_side;
+ _stencilWrapSupport = caps.GL_EXT_stencil_wrap;
+
+ // number of available auxiliary draw buffers
+ GL11.glGetInteger(GL11.GL_AUX_BUFFERS, buf);
+ _numAuxDrawBuffers = buf.get(0);
+
+ // max texture size.
+ GL11.glGetInteger(GL11.GL_MAX_TEXTURE_SIZE, buf);
+ _maxTextureSize = buf.get(0);
+
+ // Check for support of multitextures.
+ _supportsMultiTexture = caps.GL_ARB_multitexture;
+
+ // Support for texture formats
+ _supportsFloatTextures = caps.GL_ARB_texture_float;
+ _supportsIntegerTextures = caps.GL_EXT_texture_integer;
+ _supportsOneTwoComponentTextures = caps.GL_ARB_texture_rg;
+
+ // Check for support of fixed function dot3 environment settings
+ _supportsEnvDot3 = caps.GL_ARB_texture_env_dot3;
+
+ // Check for support of fixed function dot3 environment settings
+ _supportsEnvCombine = caps.GL_ARB_texture_env_combine;
+
+ // Check for support of automatic mipmap generation
+ _automaticMipMaps = caps.GL_SGIS_generate_mipmap;
+
+ _supportsDepthTexture = caps.GL_ARB_depth_texture;
+ _supportsShadow = caps.GL_ARB_shadow;
+
+ // If we do support multitexturing, find out how many textures we
+ // can handle.
+ if (_supportsMultiTexture) {
+ GL11.glGetInteger(ARBMultitexture.GL_MAX_TEXTURE_UNITS_ARB, buf);
+ _numFixedTexUnits = buf.get(0);
+ } else {
+ _numFixedTexUnits = 1;
+ }
+
+ // Go on to check number of texture units supported for vertex and
+ // fragment shaders
+ if (caps.GL_ARB_shader_objects && caps.GL_ARB_vertex_shader && caps.GL_ARB_fragment_shader) {
+ GL11.glGetInteger(ARBVertexShader.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, buf);
+ _numVertexTexUnits = buf.get(0);
+ GL11.glGetInteger(ARBFragmentShader.GL_MAX_TEXTURE_IMAGE_UNITS_ARB, buf);
+ _numFragmentTexUnits = buf.get(0);
+ GL11.glGetInteger(ARBFragmentShader.GL_MAX_TEXTURE_COORDS_ARB, buf);
+ _numFragmentTexCoordUnits = buf.get(0);
+ } else {
+ // based on nvidia dev doc:
+ // http://developer.nvidia.com/object/General_FAQ.html#t6
+ // "For GPUs that do not support GL_ARB_fragment_program and
+ // GL_NV_fragment_program, those two limits are set equal to
+ // GL_MAX_TEXTURE_UNITS."
+ _numFragmentTexCoordUnits = _numFixedTexUnits;
+ _numFragmentTexUnits = _numFixedTexUnits;
+
+ // We'll set this to 0 for now since we do not know:
+ _numVertexTexUnits = 0;
+ }
+ // ARBShaderObjects.GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB
+ // caps.GL_EXT_bindable_uniform
+ // EXTBindableUniform.GL_MAX_BINDABLE_UNIFORM_SIZE_EXT;
+
+ // Now determine the maximum number of supported texture units
+ _numTotalTexUnits = Math.max(_numFragmentTexCoordUnits,
+ Math.max(_numFixedTexUnits, Math.max(_numFragmentTexUnits, _numVertexTexUnits)));
+
+ // Check for S3 texture compression capability.
+ _supportsS3TCCompression = caps.GL_EXT_texture_compression_s3tc;
+
+ // Check for LA texture compression capability.
+ _supportsLATCCompression = caps.GL_EXT_texture_compression_latc;
+
+ // Check for generic texture compression capability.
+ _supportsGenericCompression = caps.GL_ARB_texture_compression;
+
+ // Check for 3D texture capability.
+ _supportsTexture3D = caps.OpenGL12;
+
+ // Check for cubemap capability.
+ _supportsTextureCubeMap = caps.GL_ARB_texture_cube_map;
+
+ // See if we support anisotropic filtering
+ _supportsAniso = caps.GL_EXT_texture_filter_anisotropic;
+
+ if (_supportsAniso) {
+ // Due to LWJGL buffer check, you can't use smaller sized
+ // buffers (min_size = 16 for glGetFloat()).
+ final FloatBuffer max_a = BufferUtils.createFloatBuffer(16);
+ max_a.rewind();
+
+ // Grab the maximum anisotropic filter.
+ GL11.glGetFloat(EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_a);
+
+ // set max.
+ _maxAnisotropic = max_a.get(0);
+ }
+
+ // See if we support textures that are not power of 2 in size.
+ _supportsNonPowerTwo = caps.GL_ARB_texture_non_power_of_two;
+
+ // See if we support textures that do not have width == height.
+ _supportsRectangular = caps.GL_ARB_texture_rectangle;
+
+ _supportsMirroredRepeat = caps.GL_ARB_texture_mirrored_repeat;
+ _supportsMirrorClamp = _supportsMirrorEdgeClamp = _supportsMirrorBorderClamp = caps.GL_EXT_texture_mirror_clamp;
+ _supportsBorderClamp = caps.GL_ARB_texture_border_clamp;
+ _supportsEdgeClamp = _supportsGL1_2;
+
+ try {
+ _displayVendor = GL11.glGetString(GL11.GL_VENDOR);
+ } catch (final Exception e) {
+ _displayVendor = "Unable to retrieve vendor.";
+ }
+
+ try {
+ _displayRenderer = GL11.glGetString(GL11.GL_RENDERER);
+ } catch (final Exception e) {
+ _displayRenderer = "Unable to retrieve adapter details.";
+ }
+
+ try {
+ _displayVersion = GL11.glGetString(GL11.GL_VERSION);
+ } catch (final Exception e) {
+ _displayVersion = "Unable to retrieve API version.";
+ }
+
+ try {
+ _shadingLanguageVersion = GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION);
+ } catch (final Exception e) {
+ _shadingLanguageVersion = "Unable to retrieve shading language version.";
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglPbufferTextureRenderer.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglPbufferTextureRenderer.java
new file mode 100644
index 0000000..da28b53
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglPbufferTextureRenderer.java
@@ -0,0 +1,397 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.renderer.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.AWTGLCanvas;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GLContext;
+import org.lwjgl.opengl.Pbuffer;
+import org.lwjgl.opengl.PixelFormat;
+import org.lwjgl.opengl.RenderTexture;
+
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.framework.Scene;
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture.Type;
+import com.ardor3d.math.MathUtils;
+import com.ardor3d.renderer.AbstractPbufferTextureRenderer;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRendererFactory;
+import com.ardor3d.renderer.state.RenderState;
+import com.ardor3d.renderer.state.record.TextureRecord;
+import com.ardor3d.renderer.state.record.TextureStateRecord;
+import com.ardor3d.scene.state.lwjgl.LwjglTextureStateUtil;
+import com.ardor3d.scene.state.lwjgl.util.LwjglTextureUtil;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.TextureKey;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * <p>
+ * This class is used by Ardor3D's LWJGL implementation to render textures. Users should <b>not </b> create this class
+ * directly.
+ * </p>
+ *
+ * @see TextureRendererFactory
+ */
+public class LwjglPbufferTextureRenderer extends AbstractPbufferTextureRenderer {
+ private static final Logger logger = Logger.getLogger(LwjglPbufferTextureRenderer.class.getName());
+
+ /* Pbuffer instance */
+ private Pbuffer _pbuffer;
+
+ private RenderTexture _texture;
+
+ public LwjglPbufferTextureRenderer(final DisplaySettings settings, final Renderer parentRenderer,
+ final ContextCapabilities caps) {
+ super(settings, parentRenderer, caps);
+
+ int pTarget = RenderTexture.RENDER_TEXTURE_2D;
+
+ if (!MathUtils.isPowerOfTwo(_width) || !MathUtils.isPowerOfTwo(_height)) {
+ pTarget = RenderTexture.RENDER_TEXTURE_RECTANGLE;
+ }
+
+ // signature: boolean useRGB, boolean useRGBA, boolean useDepth, boolean isRectangle, int target, int mipmaps
+ _texture = new RenderTexture(false, true, true, pTarget == RenderTexture.RENDER_TEXTURE_RECTANGLE, pTarget, 0);
+
+ setMultipleTargets(false);
+ }
+
+ /**
+ * <code>setupTexture</code> initializes a new Texture object for use with TextureRenderer. Generates a valid gl
+ * texture id for this texture and inits the data type for the texture.
+ */
+ public void setupTexture(final Texture tex) {
+ if (tex.getType() != Type.TwoDimensional) {
+ throw new IllegalArgumentException("Unsupported type: " + tex.getType());
+ }
+ final RenderContext context = ContextManager.getCurrentContext();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(RenderState.StateType.Texture);
+
+ // check if we are already setup... if so, throw error.
+ if (tex.getTextureKey() == null) {
+ tex.setTextureKey(TextureKey.getRTTKey(tex.getMinificationFilter()));
+ } else if (tex.getTextureIdForContext(context.getGlContextRep()) != 0) {
+ throw new Ardor3dException("Texture is already setup and has id.");
+ }
+
+ // Create the texture
+ final IntBuffer ibuf = BufferUtils.createIntBuffer(1);
+ GL11.glGenTextures(ibuf);
+ final int textureId = ibuf.get(0);
+ tex.setTextureIdForContext(context.getGlContextRep(), textureId);
+
+ LwjglTextureStateUtil.doTextureBind(tex, 0, true);
+
+ // Initialize our texture with some default data.
+ final int internalFormat = LwjglTextureUtil.getGLInternalFormat(tex.getTextureStoreFormat());
+ final int dataFormat = LwjglTextureUtil.getGLPixelFormatFromStoreFormat(tex.getTextureStoreFormat());
+ final int pixelDataType = LwjglTextureUtil.getGLPixelDataType(tex.getRenderedTexturePixelDataType());
+
+ GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, dataFormat, pixelDataType,
+ (ByteBuffer) null);
+
+ // Setup filtering and wrap
+ final TextureRecord texRecord = record.getTextureRecord(textureId, tex.getType());
+ LwjglTextureStateUtil.applyFilter(tex, texRecord, 0, record, context.getCapabilities());
+ LwjglTextureStateUtil.applyWrap(tex, texRecord, 0, record, context.getCapabilities());
+
+ logger.fine("setup pbuffer tex" + textureId + ": " + _width + "," + _height);
+ }
+
+ public void render(final Spatial spat, final Texture tex, final int clear) {
+ render(null, spat, null, tex, clear);
+ }
+
+ public void render(final List<? extends Spatial> spat, final Texture tex, final int clear) {
+ render(spat, null, null, tex, clear);
+ }
+
+ public void render(final Scene scene, final Texture tex, final int clear) {
+ render(null, null, scene, tex, clear);
+ }
+
+ private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC,
+ final Texture tex, final int clear) {
+ try {
+ if (_pbuffer == null || _pbuffer.isBufferLost()) {
+ if (_pbuffer != null && _pbuffer.isBufferLost()) {
+ logger.warning("PBuffer contents lost - will recreate the buffer");
+ deactivate();
+ _pbuffer.destroy();
+ }
+ initPbuffer();
+ }
+
+ if (_useDirectRender && !tex.getTextureStoreFormat().isDepthFormat()) {
+ // setup and render directly to a 2d texture.
+ _pbuffer.releaseTexImage(Pbuffer.FRONT_LEFT_BUFFER);
+ activate();
+ switchCameraIn(clear);
+
+ if (toDrawA != null) {
+ doDraw(toDrawA);
+ } else if (toDrawB != null) {
+ doDraw(toDrawB);
+ } else {
+ doDraw(toDrawC);
+ }
+
+ deactivate();
+ switchCameraOut();
+ LwjglTextureStateUtil.doTextureBind(tex, 0, true);
+ _pbuffer.bindTexImage(Pbuffer.FRONT_LEFT_BUFFER);
+ } else {
+ // render and copy to a texture
+ activate();
+ switchCameraIn(clear);
+
+ if (toDrawA != null) {
+ doDraw(toDrawA);
+ } else {
+ doDraw(toDrawB);
+ }
+
+ switchCameraOut();
+
+ copyToTexture(tex, 0, 0, _width, _height, 0, 0);
+
+ deactivate();
+ }
+
+ } catch (final Exception e) {
+ logger.logp(Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e);
+ }
+ }
+
+ public void render(final Spatial spat, final List<Texture> texs, final int clear) {
+ render(null, spat, null, texs, clear);
+ }
+
+ public void render(final List<? extends Spatial> spat, final List<Texture> texs, final int clear) {
+ render(spat, null, null, texs, clear);
+ }
+
+ public void render(final Scene scene, final List<Texture> texs, final int clear) {
+ render(null, null, scene, texs, clear);
+ }
+
+ private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC,
+ final List<Texture> texs, final int clear) {
+ try {
+ if (_pbuffer == null || _pbuffer.isBufferLost()) {
+ if (_pbuffer != null && _pbuffer.isBufferLost()) {
+ logger.warning("PBuffer contents lost - will recreate the buffer");
+ deactivate();
+ _pbuffer.destroy();
+ }
+ initPbuffer();
+ }
+
+ if (texs.size() == 1 && _useDirectRender && !texs.get(0).getTextureStoreFormat().isDepthFormat()) {
+ // setup and render directly to a 2d texture.
+ LwjglTextureStateUtil.doTextureBind(texs.get(0), 0, true);
+ activate();
+ switchCameraIn(clear);
+ _pbuffer.releaseTexImage(Pbuffer.FRONT_LEFT_BUFFER);
+
+ if (toDrawA != null) {
+ doDraw(toDrawA);
+ } else {
+ doDraw(toDrawB);
+ }
+
+ switchCameraOut();
+
+ deactivate();
+ _pbuffer.bindTexImage(Pbuffer.FRONT_LEFT_BUFFER);
+ } else {
+ // render and copy to a texture
+ activate();
+ switchCameraIn(clear);
+
+ if (toDrawA != null) {
+ doDraw(toDrawA);
+ } else {
+ doDraw(toDrawB);
+ }
+
+ switchCameraOut();
+
+ for (int i = 0; i < texs.size(); i++) {
+ copyToTexture(texs.get(i), 0, 0, _width, _height, 0, 0);
+ }
+
+ deactivate();
+ }
+
+ } catch (final Exception e) {
+ logger.logp(Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e);
+ }
+ }
+
+ public void copyToTexture(final Texture tex, final int x, final int y, final int width, final int height,
+ final int xoffset, final int yoffset) {
+ LwjglTextureStateUtil.doTextureBind(tex, 0, true);
+
+ GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height);
+ }
+
+ @Override
+ protected void clearBuffers(final int clear) {
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+ _parentRenderer.clearBuffers(clear);
+ }
+
+ private void initPbuffer() {
+
+ try {
+ if (_pbuffer != null) {
+ giveBackContext();
+ ContextManager.removeContext(_pbuffer);
+ }
+ final PixelFormat format = new PixelFormat(_settings.getAlphaBits(), _settings.getDepthBits(),
+ _settings.getStencilBits()).withSamples(_settings.getSamples())
+ .withBitsPerPixel(_settings.getColorDepth()).withStereo(_settings.isStereo());
+ _pbuffer = new Pbuffer(_width, _height, format, _texture, null);
+ final Object contextKey = _pbuffer;
+ try {
+ _pbuffer.makeCurrent();
+ } catch (final LWJGLException e) {
+ throw new RuntimeException(e);
+ }
+
+ final LwjglContextCapabilities caps = new LwjglContextCapabilities(GLContext.getCapabilities());
+ ContextManager.addContext(contextKey,
+ new RenderContext(contextKey, caps, ContextManager.getCurrentContext()));
+
+ } catch (final Exception e) {
+ logger.logp(Level.SEVERE, this.getClass().toString(), "initPbuffer()", "Exception", e);
+
+ if (_texture != null && _useDirectRender) {
+ logger.warning("Your card claims to support Render to Texture but fails to enact it. Updating your driver might solve this problem.");
+ logger.warning("Attempting to fall back to Copy Texture.");
+ _texture = null;
+ _useDirectRender = false;
+ initPbuffer();
+ return;
+ }
+
+ logger.log(Level.WARNING, "Failed to create Pbuffer.", e);
+ return;
+ }
+
+ try {
+ activate();
+
+ _width = _pbuffer.getWidth();
+ _height = _pbuffer.getHeight();
+
+ deactivate();
+ } catch (final Exception e) {
+ logger.log(Level.WARNING, "Failed to initialize created Pbuffer.", e);
+ return;
+ }
+ }
+
+ private void activate() {
+ if (_active == 0) {
+ try {
+ _oldContext = ContextManager.getCurrentContext();
+ _pbuffer.makeCurrent();
+
+ ContextManager.switchContext(_pbuffer);
+
+ ContextManager.getCurrentContext().clearEnforcedStates();
+ ContextManager.getCurrentContext().enforceStates(_enforcedStates);
+
+ if (_bgColorDirty) {
+ GL11.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(),
+ _backgroundColor.getBlue(), _backgroundColor.getAlpha());
+ _bgColorDirty = false;
+ }
+ } catch (final LWJGLException e) {
+ logger.logp(Level.SEVERE, this.getClass().toString(), "activate()", "Exception", e);
+ throw new Ardor3dException();
+ }
+ }
+ _active++;
+ }
+
+ private void deactivate() {
+ if (_active == 1) {
+ try {
+ giveBackContext();
+ } catch (final LWJGLException e) {
+ logger.logp(Level.SEVERE, this.getClass().toString(), "deactivate()", "Exception", e);
+ throw new Ardor3dException();
+ }
+ }
+ _active--;
+ }
+
+ // XXX: Need another look at this to make it generic?
+ private void giveBackContext() throws LWJGLException {
+ if (Display.isCreated()) {
+ Display.makeCurrent();
+ ContextManager.switchContext(_oldContext.getContextKey());
+ } else if (_oldContext.getContextKey() instanceof AWTGLCanvas) {
+ ((AWTGLCanvas) _oldContext.getContextKey()).makeCurrent();
+ ContextManager.switchContext(_oldContext.getContextKey());
+ }
+ }
+
+ public void cleanup() {
+ ContextManager.removeContext(_pbuffer);
+ _pbuffer.destroy();
+ }
+
+ public void setMultipleTargets(final boolean force) {
+ if (force) {
+ logger.fine("Copy Texture Pbuffer used!");
+ _useDirectRender = false;
+ _texture = null;
+ if (_pbuffer != null) {
+ try {
+ giveBackContext();
+ } catch (final LWJGLException ex) {
+ }
+ ContextManager.removeContext(_pbuffer);
+ }
+ } else {
+ if ((Pbuffer.getCapabilities() & Pbuffer.RENDER_TEXTURE_SUPPORTED) != 0) {
+ logger.fine("Render to Texture Pbuffer supported!");
+ if (_texture == null) {
+ logger.fine("No RenderTexture used in init, falling back to Copy Texture PBuffer.");
+ _useDirectRender = false;
+ } else {
+ _useDirectRender = true;
+ }
+ } else {
+ logger.fine("Copy Texture Pbuffer supported!");
+ _texture = null;
+ }
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglRenderer.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglRenderer.java
new file mode 100644
index 0000000..d856465
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglRenderer.java
@@ -0,0 +1,1743 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.renderer.lwjgl;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBBufferObject;
+import org.lwjgl.opengl.ARBMultitexture;
+import org.lwjgl.opengl.ARBPointParameters;
+import org.lwjgl.opengl.ARBPointSprite;
+import org.lwjgl.opengl.ARBVertexBufferObject;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.EXTFogCoord;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GL31;
+import org.lwjgl.opengl.OpenGLException;
+
+import com.ardor3d.image.ImageDataFormat;
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture1D;
+import com.ardor3d.image.Texture2D;
+import com.ardor3d.image.Texture3D;
+import com.ardor3d.image.TextureCubeMap;
+import com.ardor3d.image.TextureCubeMap.Face;
+import com.ardor3d.math.Matrix4;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.math.type.ReadOnlyRectangle2;
+import com.ardor3d.math.type.ReadOnlyTransform;
+import com.ardor3d.math.type.ReadOnlyVector3;
+import com.ardor3d.renderer.AbstractRenderer;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.DrawBufferTarget;
+import com.ardor3d.renderer.IndexMode;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.queue.RenderBucketType;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.ClipState;
+import com.ardor3d.renderer.state.ColorMaskState;
+import com.ardor3d.renderer.state.CullState;
+import com.ardor3d.renderer.state.FogState;
+import com.ardor3d.renderer.state.FragmentProgramState;
+import com.ardor3d.renderer.state.GLSLShaderObjectsState;
+import com.ardor3d.renderer.state.LightState;
+import com.ardor3d.renderer.state.MaterialState;
+import com.ardor3d.renderer.state.OffsetState;
+import com.ardor3d.renderer.state.RenderState;
+import com.ardor3d.renderer.state.ShadingState;
+import com.ardor3d.renderer.state.StencilState;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.renderer.state.VertexProgramState;
+import com.ardor3d.renderer.state.WireframeState;
+import com.ardor3d.renderer.state.ZBufferState;
+import com.ardor3d.renderer.state.record.LineRecord;
+import com.ardor3d.renderer.state.record.RendererRecord;
+import com.ardor3d.scene.state.lwjgl.LwjglBlendStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglClipStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglColorMaskStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglCullStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglFogStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglFragmentProgramStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglLightStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglMaterialStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglOffsetStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglShaderObjectsStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglShadingStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglStencilStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglTextureStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglVertexProgramStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglWireframeStateUtil;
+import com.ardor3d.scene.state.lwjgl.LwjglZBufferStateUtil;
+import com.ardor3d.scene.state.lwjgl.util.LwjglRendererUtil;
+import com.ardor3d.scene.state.lwjgl.util.LwjglTextureUtil;
+import com.ardor3d.scenegraph.AbstractBufferData;
+import com.ardor3d.scenegraph.AbstractBufferData.VBOAccessMode;
+import com.ardor3d.scenegraph.FloatBufferData;
+import com.ardor3d.scenegraph.IndexBufferData;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.Renderable;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.scenegraph.hint.NormalsMode;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.Constants;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.stat.StatCollector;
+import com.ardor3d.util.stat.StatType;
+
+/**
+ * <code>LwjglRenderer</code> provides an implementation of the <code>Renderer</code> interface using the LWJGL API.
+ *
+ * @see com.ardor3d.renderer.Renderer
+ */
+public class LwjglRenderer extends AbstractRenderer {
+ private static final Logger logger = Logger.getLogger(LwjglRenderer.class.getName());
+
+ private final FloatBuffer _transformBuffer = BufferUtils.createFloatBuffer(16);
+ private final Matrix4 _transformMatrix = new Matrix4();
+
+ /**
+ * Constructor instantiates a new <code>LwjglRenderer</code> object.
+ */
+ public LwjglRenderer() {
+ logger.fine("LwjglRenderer created.");
+ }
+
+ public void setBackgroundColor(final ReadOnlyColorRGBA color) {
+ _backgroundColor.set(color);
+ GL11.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(),
+ _backgroundColor.getAlpha());
+ }
+
+ @Override
+ public void renderBuckets() {
+ renderBuckets(true, true);
+ }
+
+ @Override
+ public void renderBuckets(final boolean doSort, final boolean doClear) {
+ _processingQueue = true;
+ if (doSort && doClear) {
+ _queue.renderBuckets(this);
+ } else {
+ if (doSort) {
+ _queue.sortBuckets();
+ }
+ _queue.renderOnly(this);
+ if (doClear) {
+ _queue.clearBuckets();
+ }
+ }
+ _processingQueue = false;
+ }
+
+ /**
+ * clear the render queue
+ */
+ public void clearQueue() {
+ _queue.clearBuckets();
+ }
+
+ public void clearBuffers(final int buffers) {
+ clearBuffers(buffers, false);
+ }
+
+ public void clearBuffers(final int buffers, final boolean strict) {
+
+ int clear = 0;
+
+ if ((buffers & Renderer.BUFFER_COLOR) != 0) {
+ clear |= GL11.GL_COLOR_BUFFER_BIT;
+ }
+
+ if ((buffers & Renderer.BUFFER_DEPTH) != 0) {
+ clear |= GL11.GL_DEPTH_BUFFER_BIT;
+
+ // make sure no funny business is going on in the z before clearing.
+ if (defaultStateList.containsKey(RenderState.StateType.ZBuffer)) {
+ defaultStateList.get(RenderState.StateType.ZBuffer).setNeedsRefresh(true);
+ doApplyState(defaultStateList.get(RenderState.StateType.ZBuffer));
+ }
+ }
+
+ if ((buffers & Renderer.BUFFER_STENCIL) != 0) {
+ clear |= GL11.GL_STENCIL_BUFFER_BIT;
+
+ GL11.glClearStencil(_stencilClearValue);
+ GL11.glStencilMask(~0);
+ GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
+ }
+
+ if ((buffers & Renderer.BUFFER_ACCUMULATION) != 0) {
+ clear |= GL11.GL_ACCUM_BUFFER_BIT;
+ }
+
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+
+ if (strict) {
+ // grab our camera to get width and height info.
+ final Camera cam = Camera.getCurrentCamera();
+
+ GL11.glEnable(GL11.GL_SCISSOR_TEST);
+ GL11.glScissor(0, 0, cam.getWidth(), cam.getHeight());
+ record.setClippingTestEnabled(true);
+ }
+
+ GL11.glClear(clear);
+
+ if (strict) {
+ // put us back.
+ LwjglRendererUtil.applyScissors(record);
+ }
+ }
+
+ public void flushFrame(final boolean doSwap) {
+ renderBuckets();
+
+ GL11.glFlush();
+ if (doSwap) {
+ doApplyState(defaultStateList.get(RenderState.StateType.ColorMask));
+
+ if (Constants.stats) {
+ StatCollector.startStat(StatType.STAT_DISPLAYSWAP_TIMER);
+ }
+ Display.update();
+ if (Constants.stats) {
+ StatCollector.endStat(StatType.STAT_DISPLAYSWAP_TIMER);
+ }
+ }
+
+ if (Constants.stats) {
+ StatCollector.addStat(StatType.STAT_FRAMES, 1);
+ }
+ }
+
+ public void setOrtho() {
+ if (_inOrthoMode) {
+ throw new Ardor3dException("Already in Orthographic mode.");
+ }
+ // set up ortho mode
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_PROJECTION);
+ GL11.glPushMatrix();
+ GL11.glLoadIdentity();
+ final Camera camera = Camera.getCurrentCamera();
+ final double viewportWidth = camera.getWidth() * (camera.getViewPortRight() - camera.getViewPortLeft());
+ final double viewportHeight = camera.getHeight() * (camera.getViewPortTop() - camera.getViewPortBottom());
+ GL11.glOrtho(0, viewportWidth, 0, viewportHeight, -1, 1);
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_MODELVIEW);
+ GL11.glPushMatrix();
+ GL11.glLoadIdentity();
+ _inOrthoMode = true;
+ }
+
+ public void unsetOrtho() {
+ if (!_inOrthoMode) {
+ throw new Ardor3dException("Not in Orthographic mode.");
+ }
+ // remove ortho mode, and go back to original
+ // state
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_PROJECTION);
+ GL11.glPopMatrix();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_MODELVIEW);
+ GL11.glPopMatrix();
+ _inOrthoMode = false;
+ }
+
+ public void grabScreenContents(final ByteBuffer buff, final ImageDataFormat format, final int x, final int y,
+ final int w, final int h) {
+ final int pixFormat = LwjglTextureUtil.getGLPixelFormat(format);
+ GL11.glReadPixels(x, y, w, h, pixFormat, GL11.GL_UNSIGNED_BYTE, buff);
+ }
+
+ public void draw(final Spatial s) {
+ if (s != null) {
+ s.onDraw(this);
+ }
+ }
+
+ public boolean checkAndAdd(final Spatial s) {
+ final RenderBucketType rqMode = s.getSceneHints().getRenderBucketType();
+ if (rqMode != RenderBucketType.Skip) {
+ getQueue().addToQueue(s, rqMode);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * re-initializes the GL context for rendering of another piece of geometry.
+ */
+ protected void postdrawGeometry(final Mesh g) {
+ // Nothing to do here yet
+ }
+
+ public void flushGraphics() {
+ GL11.glFlush();
+ }
+
+ public void finishGraphics() {
+ GL11.glFinish();
+ }
+
+ public void applyNormalsMode(final NormalsMode normalsMode, final ReadOnlyTransform worldTransform) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+ if (normalsMode != NormalsMode.Off) {
+ final ContextCapabilities caps = context.getCapabilities();
+ switch (normalsMode) {
+ case NormalizeIfScaled:
+ if (worldTransform.isRotationMatrix()) {
+ final ReadOnlyVector3 scale = worldTransform.getScale();
+ if (!(scale.getX() == 1.0 && scale.getY() == 1.0 && scale.getZ() == 1.0)) {
+ if (scale.getX() == scale.getY() && scale.getY() == scale.getZ()
+ && caps.isOpenGL1_2Supported()
+ && rendRecord.getNormalMode() != GL12.GL_RESCALE_NORMAL) {
+ if (rendRecord.getNormalMode() == GL11.GL_NORMALIZE) {
+ GL11.glDisable(GL11.GL_NORMALIZE);
+ }
+ GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+ rendRecord.setNormalMode(GL12.GL_RESCALE_NORMAL);
+ } else if (rendRecord.getNormalMode() != GL11.GL_NORMALIZE) {
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ }
+ GL11.glEnable(GL11.GL_NORMALIZE);
+ rendRecord.setNormalMode(GL11.GL_NORMALIZE);
+ }
+ } else {
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ } else if (rendRecord.getNormalMode() == GL11.GL_NORMALIZE) {
+ GL11.glDisable(GL11.GL_NORMALIZE);
+ }
+ rendRecord.setNormalMode(GL11.GL_ZERO);
+ }
+ } else {
+ if (!worldTransform.getMatrix().isIdentity()) {
+ // *might* be scaled...
+ if (rendRecord.getNormalMode() != GL11.GL_NORMALIZE) {
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ }
+ GL11.glEnable(GL11.GL_NORMALIZE);
+ rendRecord.setNormalMode(GL11.GL_NORMALIZE);
+ }
+ } else {
+ // not scaled
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ } else if (rendRecord.getNormalMode() == GL11.GL_NORMALIZE) {
+ GL11.glDisable(GL11.GL_NORMALIZE);
+ }
+ rendRecord.setNormalMode(GL11.GL_ZERO);
+ }
+ }
+ break;
+ case AlwaysNormalize:
+ if (rendRecord.getNormalMode() != GL11.GL_NORMALIZE) {
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ }
+ GL11.glEnable(GL11.GL_NORMALIZE);
+ rendRecord.setNormalMode(GL11.GL_NORMALIZE);
+ }
+ break;
+ case UseProvided:
+ default:
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ } else if (rendRecord.getNormalMode() == GL11.GL_NORMALIZE) {
+ GL11.glDisable(GL11.GL_NORMALIZE);
+ }
+ rendRecord.setNormalMode(GL11.GL_ZERO);
+ break;
+ }
+ } else {
+ if (rendRecord.getNormalMode() == GL12.GL_RESCALE_NORMAL) {
+ GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+ } else if (rendRecord.getNormalMode() == GL11.GL_NORMALIZE) {
+ GL11.glDisable(GL11.GL_NORMALIZE);
+ }
+ rendRecord.setNormalMode(GL11.GL_ZERO);
+ }
+ }
+
+ public void applyDefaultColor(final ReadOnlyColorRGBA defaultColor) {
+ if (defaultColor != null) {
+ GL11.glColor4f(defaultColor.getRed(), defaultColor.getGreen(), defaultColor.getBlue(),
+ defaultColor.getAlpha());
+ } else {
+ GL11.glColor4f(1, 1, 1, 1);
+ }
+ }
+
+ public void deleteVBOs(final Collection<Integer> ids) {
+ final IntBuffer idBuffer = BufferUtils.createIntBuffer(ids.size());
+ idBuffer.clear();
+ for (final Integer i : ids) {
+ if (i != null && i != 0) {
+ idBuffer.put(i);
+ }
+ }
+ idBuffer.flip();
+ if (idBuffer.remaining() > 0) {
+ ARBBufferObject.glDeleteBuffersARB(idBuffer);
+ }
+ }
+
+ public void deleteDisplayLists(final Collection<Integer> ids) {
+ for (final Integer i : ids) {
+ if (i != null && i != 0) {
+ System.err.println("deleted DL: " + i);
+ GL11.glDeleteLists(i, 1);
+ }
+ }
+ }
+
+ public void deleteVBOs(final AbstractBufferData<?> buffer) {
+ if (buffer == null) {
+ return;
+ }
+
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+
+ final int id = buffer.getVBOID(context.getGlContextRep());
+ if (id == 0) {
+ // Not on card... return.
+ return;
+ }
+
+ buffer.removeVBOID(context.getGlContextRep());
+
+ final IntBuffer idBuff = BufferUtils.createIntBuffer(1);
+ idBuff.put(id);
+ idBuff.flip();
+ ARBBufferObject.glDeleteBuffersARB(idBuff);
+ }
+
+ public void updateTexture1DSubImage(final Texture1D destination, final int dstOffsetX, final int dstWidth,
+ final ByteBuffer source, final int srcOffsetX) {
+ updateTexSubImage(destination, dstOffsetX, 0, 0, dstWidth, 0, 0, source, srcOffsetX, 0, 0, 0, 0, null);
+ }
+
+ public void updateTexture2DSubImage(final Texture2D destination, final int dstOffsetX, final int dstOffsetY,
+ final int dstWidth, final int dstHeight, final ByteBuffer source, final int srcOffsetX,
+ final int srcOffsetY, final int srcTotalWidth) {
+ updateTexSubImage(destination, dstOffsetX, dstOffsetY, 0, dstWidth, dstHeight, 0, source, srcOffsetX,
+ srcOffsetY, 0, srcTotalWidth, 0, null);
+ }
+
+ public void updateTexture3DSubImage(final Texture3D destination, final int dstOffsetX, final int dstOffsetY,
+ final int dstOffsetZ, final int dstWidth, final int dstHeight, final int dstDepth, final ByteBuffer source,
+ final int srcOffsetX, final int srcOffsetY, final int srcOffsetZ, final int srcTotalWidth,
+ final int srcTotalHeight) {
+ updateTexSubImage(destination, dstOffsetX, dstOffsetY, dstOffsetZ, dstWidth, dstHeight, dstDepth, source,
+ srcOffsetX, srcOffsetY, srcOffsetZ, srcTotalWidth, srcTotalHeight, null);
+ }
+
+ public void updateTextureCubeMapSubImage(final TextureCubeMap destination, final TextureCubeMap.Face dstFace,
+ final int dstOffsetX, final int dstOffsetY, final int dstWidth, final int dstHeight,
+ final ByteBuffer source, final int srcOffsetX, final int srcOffsetY, final int srcTotalWidth) {
+ updateTexSubImage(destination, dstOffsetX, dstOffsetY, 0, dstWidth, dstHeight, 0, source, srcOffsetX,
+ srcOffsetY, 0, srcTotalWidth, 0, dstFace);
+ }
+
+ private void updateTexSubImage(final Texture destination, final int dstOffsetX, final int dstOffsetY,
+ final int dstOffsetZ, final int dstWidth, final int dstHeight, final int dstDepth, final ByteBuffer source,
+ final int srcOffsetX, final int srcOffsetY, final int srcOffsetZ, final int srcTotalWidth,
+ final int srcTotalHeight, final Face dstFace) {
+
+ // Ignore textures that do not have an id set
+ if (destination.getTextureIdForContext(ContextManager.getCurrentContext().getGlContextRep()) == 0) {
+ logger.warning("Attempting to update a texture that is not currently on the card.");
+ return;
+ }
+
+ // Determine the original texture configuration, so that this method can
+ // restore the texture configuration to its original state.
+ final IntBuffer idBuff = BufferUtils.createIntBuffer(16);
+ GL11.glGetInteger(GL11.GL_UNPACK_ALIGNMENT, idBuff);
+ final int origAlignment = idBuff.get(0);
+ final int origRowLength = 0;
+ final int origImageHeight = 0;
+ final int origSkipPixels = 0;
+ final int origSkipRows = 0;
+ final int origSkipImages = 0;
+
+ final int alignment = 1;
+
+ int rowLength;
+ if (srcTotalWidth == dstWidth) {
+ // When the row length is zero, then the width parameter is used.
+ // We use zero in these cases in the hope that we can avoid two
+ // unnecessary calls to glPixelStorei.
+ rowLength = 0;
+ } else {
+ // The number of pixels in a row is different than the number of
+ // pixels in the region to be uploaded to the texture.
+ rowLength = srcTotalWidth;
+ }
+
+ int imageHeight;
+ if (srcTotalHeight == dstHeight) {
+ // When the image height is zero, then the height parameter is used.
+ // We use zero in these cases in the hope that we can avoid two
+ // unnecessary calls to glPixelStorei.
+ imageHeight = 0;
+ } else {
+ // The number of pixels in a row is different than the number of
+ // pixels in the region to be uploaded to the texture.
+ imageHeight = srcTotalHeight;
+ }
+
+ // Grab pixel format
+ final int pixelFormat;
+ if (destination.getImage() != null) {
+ pixelFormat = LwjglTextureUtil.getGLPixelFormat(destination.getImage().getDataFormat());
+ } else {
+ pixelFormat = LwjglTextureUtil.getGLPixelFormatFromStoreFormat(destination.getTextureStoreFormat());
+ }
+
+ // bind...
+ LwjglTextureStateUtil.doTextureBind(destination, 0, false);
+
+ // Update the texture configuration (when necessary).
+
+ if (origAlignment != alignment) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, alignment);
+ }
+ if (origRowLength != rowLength) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, rowLength);
+ }
+ if (origSkipPixels != srcOffsetX) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, srcOffsetX);
+ }
+ // NOTE: The below will be skipped for texture types that don't support them because we are passing in 0's.
+ if (origSkipRows != srcOffsetY) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, srcOffsetY);
+ }
+ if (origImageHeight != imageHeight) {
+ GL11.glPixelStorei(GL12.GL_UNPACK_IMAGE_HEIGHT, imageHeight);
+ }
+ if (origSkipImages != srcOffsetZ) {
+ GL11.glPixelStorei(GL12.GL_UNPACK_SKIP_IMAGES, srcOffsetZ);
+ }
+
+ // Upload the image region into the texture.
+ try {
+ switch (destination.getType()) {
+ case TwoDimensional:
+ GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, dstOffsetX, dstOffsetY, dstWidth, dstHeight,
+ pixelFormat, GL11.GL_UNSIGNED_BYTE, source);
+ break;
+ case OneDimensional:
+ GL11.glTexSubImage1D(GL11.GL_TEXTURE_1D, 0, dstOffsetX, dstWidth, pixelFormat,
+ GL11.GL_UNSIGNED_BYTE, source);
+ break;
+ case ThreeDimensional:
+ GL12.glTexSubImage3D(GL12.GL_TEXTURE_3D, 0, dstOffsetX, dstOffsetY, dstOffsetZ, dstWidth,
+ dstHeight, dstDepth, pixelFormat, GL11.GL_UNSIGNED_BYTE, source);
+ break;
+ case CubeMap:
+ GL11.glTexSubImage2D(LwjglTextureStateUtil.getGLCubeMapFace(dstFace), 0, dstOffsetX, dstOffsetY,
+ dstWidth, dstHeight, pixelFormat, GL11.GL_UNSIGNED_BYTE, source);
+ break;
+ default:
+ throw new Ardor3dException("Unsupported type for updateTextureSubImage: " + destination.getType());
+ }
+ } finally {
+ // Restore the texture configuration (when necessary)...
+ // Restore alignment.
+ if (origAlignment != alignment) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, origAlignment);
+ }
+ // Restore row length.
+ if (origRowLength != rowLength) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, origRowLength);
+ }
+ // Restore skip pixels.
+ if (origSkipPixels != srcOffsetX) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, origSkipPixels);
+ }
+ // Restore skip rows.
+ if (origSkipRows != srcOffsetY) {
+ GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, origSkipRows);
+ }
+ // Restore image height.
+ if (origImageHeight != imageHeight) {
+ GL11.glPixelStorei(GL12.GL_UNPACK_IMAGE_HEIGHT, origImageHeight);
+ }
+ // Restore skip images.
+ if (origSkipImages != srcOffsetZ) {
+ GL11.glPixelStorei(GL12.GL_UNPACK_SKIP_IMAGES, origSkipImages);
+ }
+ }
+ }
+
+ public void checkCardError() throws Ardor3dException {
+ try {
+ org.lwjgl.opengl.Util.checkGLError();
+ } catch (final OpenGLException exception) {
+ throw new Ardor3dException("Error in opengl: " + exception.getMessage(), exception);
+ }
+ }
+
+ public void draw(final Renderable renderable) {
+ if (renderLogic != null) {
+ renderLogic.apply(renderable);
+ }
+ renderable.render(this);
+ if (renderLogic != null) {
+ renderLogic.restore(renderable);
+ }
+ }
+
+ public boolean doTransforms(final ReadOnlyTransform transform) {
+ // set world matrix
+ if (!transform.isIdentity()) {
+ synchronized (_transformMatrix) {
+ transform.getGLApplyMatrix(_transformBuffer);
+
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_MODELVIEW);
+ GL11.glPushMatrix();
+ GL11.glMultMatrix(_transformBuffer);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void undoTransforms(final ReadOnlyTransform transform) {
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_MODELVIEW);
+ GL11.glPopMatrix();
+ }
+
+ public void setupVertexData(final FloatBufferData vertexBufferData) {
+ final FloatBuffer vertexBuffer = vertexBufferData != null ? vertexBufferData.getBuffer() : null;
+
+ if (vertexBuffer == null) {
+ GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
+ } else {
+ GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
+ vertexBuffer.rewind();
+ GL11.glVertexPointer(vertexBufferData.getValuesPerTuple(), 0, vertexBuffer);
+ }
+ }
+
+ public void setupNormalData(final FloatBufferData normalBufferData) {
+ final FloatBuffer normalBuffer = normalBufferData != null ? normalBufferData.getBuffer() : null;
+
+ if (normalBuffer == null) {
+ GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
+ } else {
+ GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
+ normalBuffer.rewind();
+ GL11.glNormalPointer(0, normalBuffer);
+ }
+ }
+
+ public void setupColorData(final FloatBufferData colorBufferData) {
+ final FloatBuffer colorBuffer = colorBufferData != null ? colorBufferData.getBuffer() : null;
+
+ if (colorBuffer == null) {
+ GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
+ } else {
+ GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
+ colorBuffer.rewind();
+ GL11.glColorPointer(colorBufferData.getValuesPerTuple(), 0, colorBuffer);
+ }
+ }
+
+ public void setupFogData(final FloatBufferData fogBufferData) {
+ final FloatBuffer fogBuffer = fogBufferData != null ? fogBufferData.getBuffer() : null;
+
+ if (fogBuffer == null) {
+ GL11.glDisableClientState(EXTFogCoord.GL_FOG_COORDINATE_ARRAY_EXT);
+ } else {
+ GL11.glEnableClientState(EXTFogCoord.GL_FOG_COORDINATE_ARRAY_EXT);
+ fogBuffer.rewind();
+ EXTFogCoord.glFogCoordPointerEXT(0, fogBuffer);
+ }
+ }
+
+ public void setupTextureData(final List<FloatBufferData> textureCoords) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+ final RendererRecord rendRecord = context.getRendererRecord();
+
+ final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture);
+ int enabledTextures = rendRecord.getEnabledTextures();
+ final boolean valid = rendRecord.isTexturesValid();
+ boolean isOn, wasOn;
+ if (ts != null) {
+ final int max = caps.isMultitextureSupported() ? Math.min(caps.getNumberOfFragmentTexCoordUnits(),
+ TextureState.MAX_TEXTURES) : 1;
+ for (int i = 0; i < max; i++) {
+ wasOn = (enabledTextures & (2 << i)) != 0;
+ isOn = textureCoords != null && i < textureCoords.size() && textureCoords.get(i) != null
+ && textureCoords.get(i).getBuffer() != null;
+
+ if (!isOn) {
+ if (valid && !wasOn) {
+ continue;
+ } else {
+ checkAndSetTextureArrayUnit(i, rendRecord, caps);
+
+ // disable bit in tracking int
+ enabledTextures &= ~(2 << i);
+
+ // disable state
+ GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+
+ continue;
+ }
+ } else {
+ checkAndSetTextureArrayUnit(i, rendRecord, caps);
+
+ if (!valid || !wasOn) {
+ // enable state
+ GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+
+ // enable bit in tracking int
+ enabledTextures |= (2 << i);
+ }
+
+ final FloatBufferData textureBufferData = textureCoords.get(i);
+ final FloatBuffer textureBuffer = textureBufferData.getBuffer();
+
+ GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+ textureBuffer.rewind();
+ GL11.glTexCoordPointer(textureBufferData.getValuesPerTuple(), 0, textureBuffer);
+ }
+ }
+ }
+
+ rendRecord.setEnabledTextures(enabledTextures);
+ rendRecord.setTexturesValid(true);
+ }
+
+ @Override
+ public void drawElements(final IndexBufferData<?> indices, final int[] indexLengths, final IndexMode[] indexModes,
+ final int primcount) {
+ if (indices == null || indices.getBuffer() == null) {
+ logger.severe("Missing indices for drawElements call without VBO");
+ return;
+ }
+
+ if (indexLengths == null) {
+ final int glIndexMode = getGLIndexMode(indexModes[0]);
+
+ indices.position(0);
+ if (indices.getBuffer() instanceof IntBuffer) {
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, (IntBuffer) indices.getBuffer());
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, (IntBuffer) indices.getBuffer(), primcount);
+ }
+ } else if (indices.getBuffer() instanceof ShortBuffer) {
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, (ShortBuffer) indices.getBuffer());
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, (ShortBuffer) indices.getBuffer(), primcount);
+ }
+
+ } else if (indices.getBuffer() instanceof ByteBuffer) {
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, (ByteBuffer) indices.getBuffer());
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, (ByteBuffer) indices.getBuffer(), primcount);
+ }
+ }
+
+ if (Constants.stats) {
+ addStats(indexModes[0], indices.getBufferLimit());
+ }
+ } else {
+ int offset = 0;
+ int indexModeCounter = 0;
+ for (int i = 0; i < indexLengths.length; i++) {
+ final int count = indexLengths[i];
+
+ final int glIndexMode = getGLIndexMode(indexModes[indexModeCounter]);
+
+ indices.getBuffer().position(offset);
+ indices.getBuffer().limit(offset + count);
+ if (indices.getBuffer() instanceof IntBuffer) {
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, (IntBuffer) indices.getBuffer());
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, (IntBuffer) indices.getBuffer(), primcount);
+ }
+
+ } else if (indices.getBuffer() instanceof ShortBuffer) {
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, (ShortBuffer) indices.getBuffer());
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, (ShortBuffer) indices.getBuffer(), primcount);
+ }
+
+ } else if (indices.getBuffer() instanceof ByteBuffer) {
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, (ByteBuffer) indices.getBuffer());
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, (ByteBuffer) indices.getBuffer(), primcount);
+ }
+ }
+
+ if (Constants.stats) {
+ addStats(indexModes[indexModeCounter], count);
+ }
+
+ offset += count;
+
+ if (indexModeCounter < indexModes.length - 1) {
+ indexModeCounter++;
+ }
+ }
+ }
+ }
+
+ public static int setupVBO(final AbstractBufferData<? extends Buffer> data, final RenderContext context) {
+ if (data == null) {
+ return 0;
+ }
+
+ final RendererRecord rendRecord = context.getRendererRecord();
+
+ int vboID = data.getVBOID(context.getGlContextRep());
+ if (vboID != 0) {
+ updateVBO(data, rendRecord, vboID, 0);
+
+ return vboID;
+ }
+
+ final Buffer dataBuffer = data.getBuffer();
+ if (dataBuffer != null) {
+ // XXX: should we be rewinding? Maybe make that the programmer's responsibility.
+ dataBuffer.rewind();
+ vboID = makeVBOId();
+ data.setVBOID(context.getGlContextRep(), vboID);
+
+ rendRecord.invalidateVBO();
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ if (dataBuffer instanceof FloatBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, (FloatBuffer) dataBuffer,
+ getGLVBOAccessMode(data.getVboAccessMode()));
+ } else if (dataBuffer instanceof ByteBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, (ByteBuffer) dataBuffer,
+ getGLVBOAccessMode(data.getVboAccessMode()));
+ } else if (dataBuffer instanceof IntBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, (IntBuffer) dataBuffer,
+ getGLVBOAccessMode(data.getVboAccessMode()));
+ } else if (dataBuffer instanceof ShortBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, (ShortBuffer) dataBuffer,
+ getGLVBOAccessMode(data.getVboAccessMode()));
+ }
+ } else {
+ throw new Ardor3dException("Attempting to create a vbo id for a FloatBufferData with no Buffer value.");
+ }
+ return vboID;
+ }
+
+ public static void updateVBO(final AbstractBufferData<? extends Buffer> data, final RendererRecord rendRecord,
+ final int vboID, final int offsetBytes) {
+ if (data.isNeedsRefresh()) {
+ final Buffer dataBuffer = data.getBuffer();
+ dataBuffer.rewind();
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ if (dataBuffer instanceof FloatBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ (FloatBuffer) dataBuffer);
+ } else if (dataBuffer instanceof ByteBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ (ByteBuffer) dataBuffer);
+ } else if (dataBuffer instanceof IntBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ (IntBuffer) dataBuffer);
+ } else if (dataBuffer instanceof ShortBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ (ShortBuffer) dataBuffer);
+ }
+ data.setNeedsRefresh(false);
+ }
+ }
+
+ private int setupIndicesVBO(final IndexBufferData<?> data, final RenderContext context,
+ final RendererRecord rendRecord) {
+ if (data == null) {
+ return 0;
+ }
+
+ int vboID = data.getVBOID(context.getGlContextRep());
+ if (vboID != 0) {
+ if (data.isNeedsRefresh()) {
+ final Buffer dataBuffer = data.getBuffer();
+ dataBuffer.rewind();
+ LwjglRendererUtil.setBoundElementVBO(rendRecord, vboID);
+ if (dataBuffer instanceof IntBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 0,
+ (IntBuffer) dataBuffer);
+ } else if (dataBuffer instanceof ShortBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 0,
+ (ShortBuffer) dataBuffer);
+ } else if (dataBuffer instanceof ByteBuffer) {
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 0,
+ (ByteBuffer) dataBuffer);
+ }
+ data.setNeedsRefresh(false);
+ }
+
+ return vboID;
+ }
+
+ final Buffer dataBuffer = data.getBuffer();
+ if (dataBuffer != null) {
+ // XXX: should we be rewinding? Maybe make that the programmer's responsibility.
+ dataBuffer.rewind();
+ vboID = makeVBOId();
+ data.setVBOID(context.getGlContextRep(), vboID);
+
+ rendRecord.invalidateVBO();
+ LwjglRendererUtil.setBoundElementVBO(rendRecord, vboID);
+ if (dataBuffer instanceof IntBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
+ (IntBuffer) dataBuffer, getGLVBOAccessMode(data.getVboAccessMode()));
+ } else if (dataBuffer instanceof ShortBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
+ (ShortBuffer) dataBuffer, getGLVBOAccessMode(data.getVboAccessMode()));
+ } else if (dataBuffer instanceof ByteBuffer) {
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
+ (ByteBuffer) dataBuffer, getGLVBOAccessMode(data.getVboAccessMode()));
+ }
+ } else {
+ throw new Ardor3dException("Attempting to create a vbo id for a IndexBufferData with no Buffer value.");
+ }
+ return vboID;
+ }
+
+ public void setupVertexDataVBO(final FloatBufferData data) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+
+ final int vboID = setupVBO(data, context);
+
+ if (vboID != 0) {
+ GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ GL11.glVertexPointer(data.getValuesPerTuple(), GL11.GL_FLOAT, 0, 0);
+ } else {
+ GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
+ }
+ }
+
+ public void setupNormalDataVBO(final FloatBufferData data) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+
+ final int vboID = setupVBO(data, context);
+
+ if (vboID != 0) {
+ GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ GL11.glNormalPointer(GL11.GL_FLOAT, 0, 0);
+ } else {
+ GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
+ }
+ }
+
+ public void setupColorDataVBO(final FloatBufferData data) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+
+ final int vboID = setupVBO(data, context);
+
+ if (vboID != 0) {
+ GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ GL11.glColorPointer(data.getValuesPerTuple(), GL11.GL_FLOAT, 0, 0);
+ } else {
+ GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
+ }
+ }
+
+ public void setupFogDataVBO(final FloatBufferData data) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+
+ if (!caps.isFogCoordinatesSupported()) {
+ return;
+ }
+
+ final RendererRecord rendRecord = context.getRendererRecord();
+ final int vboID = setupVBO(data, context);
+
+ if (vboID != 0) {
+ GL11.glEnableClientState(EXTFogCoord.GL_FOG_COORDINATE_ARRAY_EXT);
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ EXTFogCoord.glFogCoordPointerEXT(GL11.GL_FLOAT, 0, 0);
+ } else {
+ GL11.glDisableClientState(EXTFogCoord.GL_FOG_COORDINATE_ARRAY_EXT);
+ }
+ }
+
+ public void setupTextureDataVBO(final List<FloatBufferData> textureCoords) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+ final ContextCapabilities caps = context.getCapabilities();
+
+ final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture);
+ int enabledTextures = rendRecord.getEnabledTextures();
+ final boolean valid = rendRecord.isTexturesValid();
+ boolean exists, wasOn;
+ if (ts != null) {
+ final int max = caps.isMultitextureSupported() ? Math.min(caps.getNumberOfFragmentTexCoordUnits(),
+ TextureState.MAX_TEXTURES) : 1;
+ for (int i = 0; i < max; i++) {
+ wasOn = (enabledTextures & (2 << i)) != 0;
+ exists = textureCoords != null && i < textureCoords.size();
+
+ if (!exists) {
+ if (valid && !wasOn) {
+ continue;
+ } else {
+ checkAndSetTextureArrayUnit(i, rendRecord, caps);
+
+ // disable bit in tracking int
+ enabledTextures &= ~(2 << i);
+
+ // disable state
+ GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+
+ continue;
+ }
+ } else {
+ checkAndSetTextureArrayUnit(i, rendRecord, caps);
+
+ // grab a vboID and make sure it exists and is up to date.
+ final FloatBufferData data = textureCoords.get(i);
+ final int vboID = setupVBO(data, context);
+
+ // Found good vbo
+ if (vboID != 0) {
+ if (!valid || !wasOn) {
+ // enable bit in tracking int
+ enabledTextures |= (2 << i);
+
+ // enable state
+ GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+ }
+
+ // set our active vbo
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+
+ // send data
+ GL11.glTexCoordPointer(data.getValuesPerTuple(), GL11.GL_FLOAT, 0, 0);
+ }
+ // Not a good vbo, disable it.
+ else {
+ if (!valid || wasOn) {
+ // disable bit in tracking int
+ enabledTextures &= ~(2 << i);
+
+ // disable state
+ GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+ }
+ }
+ }
+ }
+ }
+
+ rendRecord.setEnabledTextures(enabledTextures);
+ rendRecord.setTexturesValid(true);
+ }
+
+ public void setupInterleavedDataVBO(final FloatBufferData interleaved, final FloatBufferData vertexCoords,
+ final FloatBufferData normalCoords, final FloatBufferData colorCoords,
+ final List<FloatBufferData> textureCoords) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+ final ContextCapabilities caps = context.getCapabilities();
+
+ final int lengthBytes = getTotalInterleavedSize(context, vertexCoords, normalCoords, colorCoords, textureCoords);
+ int currLengthBytes = 0;
+ if (interleaved.getBufferLimit() > 0) {
+ interleaved.getBuffer().rewind();
+ currLengthBytes = Math.round(interleaved.getBuffer().get());
+ }
+
+ if (lengthBytes != currLengthBytes || interleaved.getVBOID(context.getGlContextRep()) == 0
+ || interleaved.isNeedsRefresh()) {
+ initializeInterleavedVBO(context, interleaved, vertexCoords, normalCoords, colorCoords, textureCoords,
+ lengthBytes);
+ }
+
+ final int vboID = interleaved.getVBOID(context.getGlContextRep());
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+
+ int offsetBytes = 0;
+
+ if (normalCoords != null) {
+ updateVBO(normalCoords, rendRecord, vboID, offsetBytes);
+ GL11.glNormalPointer(GL11.GL_FLOAT, 0, offsetBytes);
+ GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
+ offsetBytes += normalCoords.getBufferLimit() * 4;
+ } else {
+ GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
+ }
+
+ if (colorCoords != null) {
+ updateVBO(colorCoords, rendRecord, vboID, offsetBytes);
+ GL11.glColorPointer(colorCoords.getValuesPerTuple(), GL11.GL_FLOAT, 0, offsetBytes);
+ GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
+ offsetBytes += colorCoords.getBufferLimit() * 4;
+ } else {
+ GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
+ }
+
+ if (textureCoords != null) {
+ final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture);
+ int enabledTextures = rendRecord.getEnabledTextures();
+ final boolean valid = rendRecord.isTexturesValid();
+ boolean exists, wasOn;
+ if (ts != null) {
+ final int max = caps.isMultitextureSupported() ? Math.min(caps.getNumberOfFragmentTexCoordUnits(),
+ TextureState.MAX_TEXTURES) : 1;
+ for (int i = 0; i < max; i++) {
+ wasOn = (enabledTextures & (2 << i)) != 0;
+ exists = textureCoords != null && i < textureCoords.size() && textureCoords.get(i) != null
+ && i <= ts.getMaxTextureIndexUsed();
+
+ if (!exists) {
+ if (valid && !wasOn) {
+ continue;
+ } else {
+ checkAndSetTextureArrayUnit(i, rendRecord, caps);
+
+ // disable bit in tracking int
+ enabledTextures &= ~(2 << i);
+
+ // disable state
+ GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+
+ continue;
+ }
+
+ } else {
+ checkAndSetTextureArrayUnit(i, rendRecord, caps);
+
+ // grab a vboID and make sure it exists and is up to date.
+ final FloatBufferData textureBufferData = textureCoords.get(i);
+ updateVBO(textureBufferData, rendRecord, vboID, offsetBytes);
+
+ if (!valid || !wasOn) {
+ // enable bit in tracking int
+ enabledTextures |= (2 << i);
+
+ // enable state
+ GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+ }
+
+ // send data
+ GL11.glTexCoordPointer(textureBufferData.getValuesPerTuple(), GL11.GL_FLOAT, 0, offsetBytes);
+ offsetBytes += textureBufferData.getBufferLimit() * 4;
+ }
+ }
+ }
+
+ rendRecord.setEnabledTextures(enabledTextures);
+ rendRecord.setTexturesValid(true);
+ }
+
+ if (vertexCoords != null) {
+ updateVBO(vertexCoords, rendRecord, vboID, offsetBytes);
+ GL11.glVertexPointer(vertexCoords.getValuesPerTuple(), GL11.GL_FLOAT, 0, offsetBytes);
+ GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
+ } else {
+ GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
+ }
+ }
+
+ private void initializeInterleavedVBO(final RenderContext context, final FloatBufferData interleaved,
+ final FloatBufferData vertexCoords, final FloatBufferData normalCoords, final FloatBufferData colorCoords,
+ final List<FloatBufferData> textureCoords, final int bufferSize) {
+
+ // keep around buffer size
+ if (interleaved.getBufferCapacity() != 1) {
+ final FloatBuffer buffer = BufferUtils.createFloatBufferOnHeap(1);
+ interleaved.setBuffer(buffer);
+ }
+ interleaved.getBuffer().rewind();
+ interleaved.getBuffer().put(bufferSize);
+
+ final RendererRecord rendRecord = context.getRendererRecord();
+ final ContextCapabilities caps = context.getCapabilities();
+
+ final int vboID = makeVBOId();
+ interleaved.setVBOID(context.getGlContextRep(), vboID);
+
+ rendRecord.invalidateVBO();
+ LwjglRendererUtil.setBoundVBO(rendRecord, vboID);
+ ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, bufferSize,
+ getGLVBOAccessMode(interleaved.getVboAccessMode()));
+
+ int offsetBytes = 0;
+ if (normalCoords != null) {
+ normalCoords.getBuffer().rewind();
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ normalCoords.getBuffer());
+ offsetBytes += normalCoords.getBufferLimit() * 4;
+ }
+ if (colorCoords != null) {
+ colorCoords.getBuffer().rewind();
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ colorCoords.getBuffer());
+ offsetBytes += colorCoords.getBufferLimit() * 4;
+ }
+ if (textureCoords != null) {
+ final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture);
+ if (ts != null) {
+ for (int i = 0; i <= ts.getMaxTextureIndexUsed() && i < caps.getNumberOfFragmentTexCoordUnits(); i++) {
+ if (textureCoords == null || i >= textureCoords.size()) {
+ continue;
+ }
+
+ final FloatBufferData textureBufferData = textureCoords.get(i);
+ final FloatBuffer textureBuffer = textureBufferData != null ? textureBufferData.getBuffer() : null;
+ if (textureBuffer != null) {
+ textureBuffer.rewind();
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ textureBuffer);
+ offsetBytes += textureBufferData.getBufferLimit() * 4;
+ }
+ }
+ }
+ }
+ if (vertexCoords != null) {
+ vertexCoords.getBuffer().rewind();
+ ARBBufferObject.glBufferSubDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, offsetBytes,
+ vertexCoords.getBuffer());
+ }
+
+ interleaved.setNeedsRefresh(false);
+ }
+
+ @Override
+ public void drawElementsVBO(final IndexBufferData<?> indices, final int[] indexLengths,
+ final IndexMode[] indexModes, final int primcount) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+
+ final int vboID = setupIndicesVBO(indices, context, rendRecord);
+
+ LwjglRendererUtil.setBoundElementVBO(rendRecord, vboID);
+
+ if (indexLengths == null) {
+ final int glIndexMode = getGLIndexMode(indexModes[0]);
+
+ final int type = getGLDataType(indices);
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, indices.getBufferLimit(), type, 0);
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, indices.getBufferLimit(), type, 0, primcount);
+ }
+ if (Constants.stats) {
+ addStats(indexModes[0], indices.getBufferLimit());
+ }
+ } else {
+ int offset = 0;
+ int indexModeCounter = 0;
+ for (int i = 0; i < indexLengths.length; i++) {
+ final int count = indexLengths[i];
+
+ final int glIndexMode = getGLIndexMode(indexModes[indexModeCounter]);
+
+ final int type = getGLDataType(indices);
+ final int byteSize = indices.getByteCount();
+ // offset in this call is done in bytes.
+ if (primcount < 0) {
+ GL11.glDrawElements(glIndexMode, count, type, offset * byteSize);
+ } else {
+ GL31.glDrawElementsInstanced(glIndexMode, count, type, offset * byteSize, primcount);
+ }
+
+ if (Constants.stats) {
+ addStats(indexModes[indexModeCounter], count);
+ }
+
+ offset += count;
+
+ if (indexModeCounter < indexModes.length - 1) {
+ indexModeCounter++;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void drawArrays(final FloatBufferData vertices, final int[] indexLengths, final IndexMode[] indexModes,
+ final int primcount) {
+ if (indexLengths == null) {
+ final int glIndexMode = getGLIndexMode(indexModes[0]);
+
+ if (primcount < 0) {
+ GL11.glDrawArrays(glIndexMode, 0, vertices.getTupleCount());
+ } else {
+ GL31.glDrawArraysInstanced(glIndexMode, 0, vertices.getTupleCount(), primcount);
+ }
+
+ if (Constants.stats) {
+ addStats(indexModes[0], vertices.getTupleCount());
+ }
+ } else {
+ int offset = 0;
+ int indexModeCounter = 0;
+ for (int i = 0; i < indexLengths.length; i++) {
+ final int count = indexLengths[i];
+
+ final int glIndexMode = getGLIndexMode(indexModes[indexModeCounter]);
+
+ if (primcount < 0) {
+ GL11.glDrawArrays(glIndexMode, offset, count);
+ } else {
+ GL31.glDrawArraysInstanced(glIndexMode, offset, count, primcount);
+ }
+
+ if (Constants.stats) {
+ addStats(indexModes[indexModeCounter], count);
+ }
+
+ offset += count;
+
+ if (indexModeCounter < indexModes.length - 1) {
+ indexModeCounter++;
+ }
+ }
+ }
+ }
+
+ public static int makeVBOId() {
+ final IntBuffer idBuff = BufferUtils.createIntBuffer(1);
+ ARBBufferObject.glGenBuffersARB(idBuff);
+ return idBuff.get(0);
+ }
+
+ public void unbindVBO() {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord rendRecord = context.getRendererRecord();
+ LwjglRendererUtil.setBoundVBO(rendRecord, 0);
+ LwjglRendererUtil.setBoundElementVBO(rendRecord, 0);
+ }
+
+ private static int getGLVBOAccessMode(final VBOAccessMode vboAccessMode) {
+ int glMode = ARBBufferObject.GL_STATIC_DRAW_ARB;
+ switch (vboAccessMode) {
+ case StaticDraw:
+ glMode = ARBBufferObject.GL_STATIC_DRAW_ARB;
+ break;
+ case StaticRead:
+ glMode = ARBBufferObject.GL_STATIC_READ_ARB;
+ break;
+ case StaticCopy:
+ glMode = ARBBufferObject.GL_STATIC_COPY_ARB;
+ break;
+ case DynamicDraw:
+ glMode = ARBBufferObject.GL_DYNAMIC_DRAW_ARB;
+ break;
+ case DynamicRead:
+ glMode = ARBBufferObject.GL_DYNAMIC_READ_ARB;
+ break;
+ case DynamicCopy:
+ glMode = ARBBufferObject.GL_DYNAMIC_COPY_ARB;
+ break;
+ case StreamDraw:
+ glMode = ARBBufferObject.GL_STREAM_DRAW_ARB;
+ break;
+ case StreamRead:
+ glMode = ARBBufferObject.GL_STREAM_READ_ARB;
+ break;
+ case StreamCopy:
+ glMode = ARBBufferObject.GL_STREAM_COPY_ARB;
+ break;
+ }
+ return glMode;
+ }
+
+ private int getGLIndexMode(final IndexMode indexMode) {
+ int glMode = GL11.GL_TRIANGLES;
+ switch (indexMode) {
+ case Triangles:
+ glMode = GL11.GL_TRIANGLES;
+ break;
+ case TriangleStrip:
+ glMode = GL11.GL_TRIANGLE_STRIP;
+ break;
+ case TriangleFan:
+ glMode = GL11.GL_TRIANGLE_FAN;
+ break;
+ case Quads:
+ glMode = GL11.GL_QUADS;
+ break;
+ case QuadStrip:
+ glMode = GL11.GL_QUAD_STRIP;
+ break;
+ case Lines:
+ glMode = GL11.GL_LINES;
+ break;
+ case LineStrip:
+ glMode = GL11.GL_LINE_STRIP;
+ break;
+ case LineLoop:
+ glMode = GL11.GL_LINE_LOOP;
+ break;
+ case Points:
+ glMode = GL11.GL_POINTS;
+ break;
+ }
+ return glMode;
+ }
+
+ private int getGLDataType(final IndexBufferData<?> indices) {
+ if (indices.getBuffer() instanceof ByteBuffer) {
+ return GL11.GL_UNSIGNED_BYTE;
+ } else if (indices.getBuffer() instanceof ShortBuffer) {
+ return GL11.GL_UNSIGNED_SHORT;
+ } else if (indices.getBuffer() instanceof IntBuffer) {
+ return GL11.GL_UNSIGNED_INT;
+ }
+
+ throw new IllegalArgumentException("Unknown buffer type: " + indices.getBuffer());
+ }
+
+ public void setModelViewMatrix(final FloatBuffer matrix) {
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_MODELVIEW);
+ loadMatrix(matrix);
+ }
+
+ public void setProjectionMatrix(final FloatBuffer matrix) {
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_PROJECTION);
+ loadMatrix(matrix);
+ }
+
+ private void loadMatrix(final FloatBuffer matrix) {
+ GL11.glLoadMatrix(matrix);
+ }
+
+ public FloatBuffer getModelViewMatrix(final FloatBuffer store) {
+ return getMatrix(GL11.GL_MODELVIEW_MATRIX, store);
+ }
+
+ public FloatBuffer getProjectionMatrix(final FloatBuffer store) {
+ return getMatrix(GL11.GL_PROJECTION_MATRIX, store);
+ }
+
+ private FloatBuffer getMatrix(final int matrixType, final FloatBuffer store) {
+ FloatBuffer result = store;
+ if (result.remaining() < 16) {
+ result = BufferUtils.createFloatBuffer(16);
+ }
+ GL11.glGetFloat(matrixType, store);
+ return result;
+ }
+
+ public void setViewport(final int x, final int y, final int width, final int height) {
+ GL11.glViewport(x, y, width, height);
+ }
+
+ public void setDepthRange(final double depthRangeNear, final double depthRangeFar) {
+ GL11.glDepthRange(depthRangeNear, depthRangeFar);
+ }
+
+ public void setDrawBuffer(final DrawBufferTarget target) {
+ final RendererRecord record = ContextManager.getCurrentContext().getRendererRecord();
+ if (record.getDrawBufferTarget() != target) {
+ int buffer = GL11.GL_BACK;
+ switch (target) {
+ case Back:
+ break;
+ case Front:
+ buffer = GL11.GL_FRONT;
+ break;
+ case BackLeft:
+ buffer = GL11.GL_BACK_LEFT;
+ break;
+ case BackRight:
+ buffer = GL11.GL_BACK_RIGHT;
+ break;
+ case FrontLeft:
+ buffer = GL11.GL_FRONT_LEFT;
+ break;
+ case FrontRight:
+ buffer = GL11.GL_FRONT_RIGHT;
+ break;
+ case FrontAndBack:
+ buffer = GL11.GL_FRONT_AND_BACK;
+ break;
+ case Left:
+ buffer = GL11.GL_LEFT;
+ break;
+ case Right:
+ buffer = GL11.GL_RIGHT;
+ break;
+ case Aux0:
+ buffer = GL11.GL_AUX0;
+ break;
+ case Aux1:
+ buffer = GL11.GL_AUX1;
+ break;
+ case Aux2:
+ buffer = GL11.GL_AUX2;
+ break;
+ case Aux3:
+ buffer = GL11.GL_AUX3;
+ break;
+ }
+
+ GL11.glDrawBuffer(buffer);
+ record.setDrawBufferTarget(target);
+ }
+ }
+
+ public void setupLineParameters(final float lineWidth, final int stippleFactor, final short stipplePattern,
+ final boolean antialiased) {
+ final LineRecord lineRecord = ContextManager.getCurrentContext().getLineRecord();
+
+ if (!lineRecord.isValid() || lineRecord.width != lineWidth) {
+ GL11.glLineWidth(lineWidth);
+ lineRecord.width = lineWidth;
+ }
+
+ if (stipplePattern != (short) 0xFFFF) {
+ if (!lineRecord.isValid() || !lineRecord.stippled) {
+ GL11.glEnable(GL11.GL_LINE_STIPPLE);
+ lineRecord.stippled = true;
+ }
+
+ if (!lineRecord.isValid() || stippleFactor != lineRecord.stippleFactor
+ || stipplePattern != lineRecord.stipplePattern) {
+ GL11.glLineStipple(stippleFactor, stipplePattern);
+ lineRecord.stippleFactor = stippleFactor;
+ lineRecord.stipplePattern = stipplePattern;
+ }
+ } else if (!lineRecord.isValid() || lineRecord.stippled) {
+ GL11.glDisable(GL11.GL_LINE_STIPPLE);
+ lineRecord.stippled = false;
+ }
+
+ if (antialiased) {
+ if (!lineRecord.isValid() || !lineRecord.smoothed) {
+ GL11.glEnable(GL11.GL_LINE_SMOOTH);
+ lineRecord.smoothed = true;
+ }
+ if (!lineRecord.isValid() || lineRecord.smoothHint != GL11.GL_NICEST) {
+ GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
+ lineRecord.smoothHint = GL11.GL_NICEST;
+ }
+ } else if (!lineRecord.isValid() || lineRecord.smoothed) {
+ GL11.glDisable(GL11.GL_LINE_SMOOTH);
+ lineRecord.smoothed = false;
+ }
+
+ if (!lineRecord.isValid()) {
+ lineRecord.validate();
+ }
+ }
+
+ @Override
+ public void setupPointParameters(final float pointSize, final boolean antialiased, final boolean isSprite,
+ final boolean useDistanceAttenuation, final FloatBuffer attenuationCoefficients, final float minPointSize,
+ final float maxPointSize) {
+ final RenderContext context = ContextManager.getCurrentContext();
+
+ // TODO: make a record for point states
+ GL11.glPointSize(pointSize);
+
+ if (isSprite && context.getCapabilities().isPointSpritesSupported()) {
+ GL11.glEnable(ARBPointSprite.GL_POINT_SPRITE_ARB);
+ GL11.glTexEnvi(ARBPointSprite.GL_POINT_SPRITE_ARB, ARBPointSprite.GL_COORD_REPLACE_ARB, GL11.GL_TRUE);
+ }
+
+ if (useDistanceAttenuation && context.getCapabilities().isPointParametersSupported()) {
+ ARBPointParameters.glPointParameterARB(ARBPointParameters.GL_POINT_DISTANCE_ATTENUATION_ARB,
+ attenuationCoefficients);
+ ARBPointParameters.glPointParameterfARB(ARBPointParameters.GL_POINT_SIZE_MIN_ARB, minPointSize);
+ ARBPointParameters.glPointParameterfARB(ARBPointParameters.GL_POINT_SIZE_MAX_ARB, maxPointSize);
+ }
+
+ if (antialiased) {
+ GL11.glEnable(GL11.GL_POINT_SMOOTH);
+ GL11.glHint(GL11.GL_POINT_SMOOTH_HINT, GL11.GL_NICEST);
+ }
+ }
+
+ @Override
+ public void doApplyState(final RenderState state) {
+ if (state == null) {
+ logger.warning("tried to apply a null state.");
+ return;
+ }
+ switch (state.getType()) {
+ case Texture:
+ LwjglTextureStateUtil.apply((TextureState) state);
+ return;
+ case Light:
+ LwjglLightStateUtil.apply((LightState) state);
+ return;
+ case Blend:
+ LwjglBlendStateUtil.apply((BlendState) state);
+ return;
+ case Clip:
+ LwjglClipStateUtil.apply((ClipState) state);
+ return;
+ case ColorMask:
+ LwjglColorMaskStateUtil.apply((ColorMaskState) state);
+ return;
+ case Cull:
+ LwjglCullStateUtil.apply((CullState) state);
+ return;
+ case Fog:
+ LwjglFogStateUtil.apply((FogState) state);
+ return;
+ case FragmentProgram:
+ LwjglFragmentProgramStateUtil.apply((FragmentProgramState) state);
+ return;
+ case GLSLShader:
+ LwjglShaderObjectsStateUtil.apply(this, (GLSLShaderObjectsState) state);
+ return;
+ case Material:
+ LwjglMaterialStateUtil.apply((MaterialState) state);
+ return;
+ case Offset:
+ LwjglOffsetStateUtil.apply(this, (OffsetState) state);
+ return;
+ case Shading:
+ LwjglShadingStateUtil.apply((ShadingState) state);
+ return;
+ case Stencil:
+ LwjglStencilStateUtil.apply((StencilState) state);
+ return;
+ case VertexProgram:
+ LwjglVertexProgramStateUtil.apply((VertexProgramState) state);
+ return;
+ case Wireframe:
+ LwjglWireframeStateUtil.apply(this, (WireframeState) state);
+ return;
+ case ZBuffer:
+ LwjglZBufferStateUtil.apply((ZBufferState) state);
+ return;
+ }
+ throw new IllegalArgumentException("Unknown state: " + state);
+ }
+
+ public void deleteTexture(final Texture texture) {
+ LwjglTextureStateUtil.deleteTexture(texture);
+ }
+
+ public void loadTexture(final Texture texture, final int unit) {
+ LwjglTextureStateUtil.load(texture, unit);
+ }
+
+ public void deleteTextureIds(final Collection<Integer> ids) {
+ LwjglTextureStateUtil.deleteTextureIds(ids);
+ }
+
+ /**
+ * Start a new display list. All further renderer commands that can be stored in a display list are part of this new
+ * list until {@link #endDisplayList()} is called.
+ *
+ * @return id of new display list
+ */
+ public int startDisplayList() {
+ final int id = GL11.glGenLists(1);
+
+ GL11.glNewList(id, GL11.GL_COMPILE);
+
+ return id;
+ }
+
+ /**
+ * Ends a display list. Will likely cause an OpenGL exception is a display list is not currently being generated.
+ */
+ public void endDisplayList() {
+ GL11.glEndList();
+ }
+
+ /**
+ * Draw the given display list.
+ */
+ public void renderDisplayList(final int displayListID) {
+ GL11.glCallList(displayListID);
+ }
+
+ public void clearClips() {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+ record.getScissorClips().clear();
+
+ LwjglRendererUtil.applyScissors(record);
+ }
+
+ public void popClip() {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+ record.getScissorClips().pop();
+
+ LwjglRendererUtil.applyScissors(record);
+ }
+
+ public void pushClip(final ReadOnlyRectangle2 rectangle) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+ record.getScissorClips().push(rectangle);
+
+ LwjglRendererUtil.applyScissors(record);
+ }
+
+ public void pushEmptyClip() {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+ record.getScissorClips().push(null);
+
+ LwjglRendererUtil.applyScissors(record);
+ }
+
+ public void setClipTestEnabled(final boolean enabled) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+
+ LwjglRendererUtil.setClippingEnabled(record, enabled);
+ }
+
+ public void checkAndSetTextureArrayUnit(final int unit, final RendererRecord record, final ContextCapabilities caps) {
+ if (record.getCurrentTextureArraysUnit() != unit && caps.isMultitextureSupported()) {
+ ARBMultitexture.glClientActiveTextureARB(ARBMultitexture.GL_TEXTURE0_ARB + unit);
+ record.setCurrentTextureArraysUnit(unit);
+ }
+ }
+
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRenderer.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRenderer.java
new file mode 100644
index 0000000..5f66a48
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRenderer.java
@@ -0,0 +1,566 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.renderer.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBDepthTexture;
+import org.lwjgl.opengl.ARBDrawBuffers;
+import org.lwjgl.opengl.EXTFramebufferBlit;
+import org.lwjgl.opengl.EXTFramebufferMultisample;
+import org.lwjgl.opengl.EXTFramebufferObject;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.framework.Scene;
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture.Type;
+import com.ardor3d.image.TextureCubeMap;
+import com.ardor3d.image.TextureCubeMap.Face;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.renderer.AbstractFBOTextureRenderer;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRendererFactory;
+import com.ardor3d.renderer.state.RenderState;
+import com.ardor3d.renderer.state.record.RendererRecord;
+import com.ardor3d.renderer.state.record.TextureRecord;
+import com.ardor3d.renderer.state.record.TextureStateRecord;
+import com.ardor3d.scene.state.lwjgl.LwjglTextureStateUtil;
+import com.ardor3d.scene.state.lwjgl.util.LwjglTextureUtil;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.TextureKey;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * <p>
+ * This class is used by Ardor3D's LWJGL implementation to render textures. Users should <b>not</b> create this class
+ * directly.
+ * </p>
+ *
+ * @see TextureRendererFactory
+ */
+public class LwjglTextureRenderer extends AbstractFBOTextureRenderer {
+ private static final Logger logger = Logger.getLogger(LwjglTextureRenderer.class.getName());
+
+ public LwjglTextureRenderer(final int width, final int height, final int depthBits, final int samples,
+ final Renderer parentRenderer, final ContextCapabilities caps) {
+ super(width, height, depthBits, samples, parentRenderer, caps);
+
+ if (caps.getMaxFBOColorAttachments() > 1) {
+ _attachBuffer = BufferUtils.createIntBuffer(caps.getMaxFBOColorAttachments());
+ for (int i = 0; i < caps.getMaxFBOColorAttachments(); i++) {
+ _attachBuffer.put(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT + i);
+ }
+ }
+ }
+
+ /**
+ * <code>setupTexture</code> initializes a new Texture object for use with TextureRenderer. Generates a valid OpenGL
+ * texture id for this texture and initializes the data type for the texture.
+ */
+ public void setupTexture(final Texture tex) {
+ if (tex.getType() != Type.TwoDimensional && tex.getType() != Type.CubeMap) {
+ throw new IllegalArgumentException("Texture type not supported: " + tex.getType());
+ }
+
+ final RenderContext context = ContextManager.getCurrentContext();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(RenderState.StateType.Texture);
+
+ // check if we are already setup... if so, throw error.
+ if (tex.getTextureKey() == null) {
+ tex.setTextureKey(TextureKey.getRTTKey(tex.getMinificationFilter()));
+ } else if (tex.getTextureIdForContext(context.getGlContextRep()) != 0) {
+ throw new Ardor3dException("Texture is already setup and has id.");
+ }
+
+ // Create the texture
+ final IntBuffer ibuf = BufferUtils.createIntBuffer(1);
+ GL11.glGenTextures(ibuf);
+ final int textureId = ibuf.get(0);
+ tex.setTextureIdForContext(context.getGlContextRep(), textureId);
+
+ LwjglTextureStateUtil.doTextureBind(tex, 0, true);
+
+ // Initialize our texture with some default data.
+ final int internalFormat = LwjglTextureUtil.getGLInternalFormat(tex.getTextureStoreFormat());
+ final int dataFormat = LwjglTextureUtil.getGLPixelFormatFromStoreFormat(tex.getTextureStoreFormat());
+ final int pixelDataType = LwjglTextureUtil.getGLPixelDataType(tex.getRenderedTexturePixelDataType());
+
+ if (tex.getType() == Type.TwoDimensional) {
+ GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, dataFormat, pixelDataType,
+ (ByteBuffer) null);
+ } else {
+ for (final Face face : Face.values()) {
+ GL11.glTexImage2D(LwjglTextureStateUtil.getGLCubeMapFace(face), 0, internalFormat, _width, _height, 0,
+ dataFormat, pixelDataType, (ByteBuffer) null);
+ }
+ }
+
+ // Initialize mipmapping for this texture, if requested
+ if (tex.getMinificationFilter().usesMipMapLevels()) {
+ EXTFramebufferObject.glGenerateMipmapEXT(LwjglTextureStateUtil.getGLType(tex.getType()));
+ }
+
+ // Setup filtering and wrap
+ final TextureRecord texRecord = record.getTextureRecord(textureId, tex.getType());
+ LwjglTextureStateUtil.applyFilter(tex, texRecord, 0, record, context.getCapabilities());
+ LwjglTextureStateUtil.applyWrap(tex, texRecord, 0, record, context.getCapabilities());
+
+ logger.fine("setup fbo tex with id " + textureId + ": " + _width + "," + _height);
+ }
+
+ public void render(final Spatial spat, final List<Texture> texs, final int clear) {
+ render(null, spat, null, texs, clear);
+ }
+
+ public void render(final List<? extends Spatial> spat, final List<Texture> texs, final int clear) {
+ render(spat, null, null, texs, clear);
+ }
+
+ @Override
+ public void render(final Scene scene, final List<Texture> texs, final int clear) {
+ render(null, null, scene, texs, clear);
+ }
+
+ private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC,
+ final List<Texture> texs, final int clear) {
+
+ final int maxDrawBuffers = ContextManager.getCurrentContext().getCapabilities().getMaxFBOColorAttachments();
+
+ // if we only support 1 draw buffer at a time anyway, we'll have to render to each texture individually...
+ if (maxDrawBuffers == 1 || texs.size() == 1) {
+ try {
+ ContextManager.getCurrentContext().pushFBOTextureRenderer(this);
+
+ for (int i = 0; i < texs.size(); i++) {
+ final Texture tex = texs.get(i);
+
+ setupForSingleTexDraw(tex);
+
+ if (_samples > 0 && _supportsMultisample) {
+ setMSFBO();
+ }
+
+ switchCameraIn(clear);
+ if (toDrawA != null) {
+ doDraw(toDrawA);
+ } else if (toDrawB != null) {
+ doDraw(toDrawB);
+ } else {
+ doDraw(toDrawC);
+ }
+ switchCameraOut();
+
+ if (_samples > 0 && _supportsMultisample) {
+ blitMSFBO();
+ }
+
+ takedownForSingleTexDraw(tex);
+ }
+ } finally {
+ ContextManager.getCurrentContext().popFBOTextureRenderer();
+ }
+ return;
+ }
+ try {
+ ContextManager.getCurrentContext().pushFBOTextureRenderer(this);
+
+ // Otherwise, we can streamline this by rendering to multiple textures at once.
+ // first determine how many groups we need
+ final LinkedList<Texture> depths = new LinkedList<Texture>();
+ final LinkedList<Texture> colors = new LinkedList<Texture>();
+ for (int i = 0; i < texs.size(); i++) {
+ final Texture tex = texs.get(i);
+ if (tex.getTextureStoreFormat().isDepthFormat()) {
+ depths.add(tex);
+ } else {
+ colors.add(tex);
+ }
+ }
+ // we can only render to 1 depth texture at a time, so # groups is at minimum == numDepth
+ final int groups = Math.max(depths.size(), (int) Math.ceil(colors.size() / (float) maxDrawBuffers));
+
+ final RenderContext context = ContextManager.getCurrentContext();
+ for (int i = 0; i < groups; i++) {
+ // First handle colors
+ int colorsAdded = 0;
+ while (colorsAdded < maxDrawBuffers && !colors.isEmpty()) {
+ final Texture tex = colors.removeFirst();
+ if (tex.getType() == Type.TwoDimensional) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT + colorsAdded, GL11.GL_TEXTURE_2D,
+ tex.getTextureIdForContext(context.getGlContextRep()), 0);
+ } else if (tex.getType() == Type.CubeMap) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT + colorsAdded,
+ LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()),
+ tex.getTextureIdForContext(context.getGlContextRep()), 0);
+ } else {
+ throw new IllegalArgumentException("Invalid texture type: " + tex.getType());
+ }
+ colorsAdded++;
+ }
+
+ // Now take care of depth.
+ if (!depths.isEmpty()) {
+ final Texture tex = depths.removeFirst();
+ // Set up our depth texture
+ if (tex.getType() == Type.TwoDimensional) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D,
+ tex.getTextureIdForContext(context.getGlContextRep()), 0);
+ } else if (tex.getType() == Type.CubeMap) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT,
+ LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()),
+ tex.getTextureIdForContext(context.getGlContextRep()), 0);
+ } else {
+ throw new IllegalArgumentException("Invalid texture type: " + tex.getType());
+ }
+ _usingDepthRB = false;
+ } else if (!_usingDepthRB) {
+ // setup our default depth render buffer if not already set
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT,
+ _depthRBID);
+ _usingDepthRB = true;
+ }
+
+ setDrawBuffers(colorsAdded);
+ setReadBuffer(colorsAdded != 0 ? EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT : GL11.GL_NONE);
+
+ // Check FBO complete
+ checkFBOComplete(_fboID);
+
+ switchCameraIn(clear);
+
+ if (toDrawA != null) {
+ doDraw(toDrawA);
+ } else {
+ doDraw(toDrawB);
+ }
+
+ switchCameraOut();
+ }
+
+ // automatically generate mipmaps for our textures.
+ for (int x = 0, max = texs.size(); x < max; x++) {
+ if (texs.get(x).getMinificationFilter().usesMipMapLevels()) {
+ final Texture tex = texs.get(x);
+ if (tex.getMinificationFilter().usesMipMapLevels()) {
+ LwjglTextureStateUtil.doTextureBind(texs.get(x), 0, true);
+ EXTFramebufferObject.glGenerateMipmapEXT(LwjglTextureStateUtil.getGLType(tex.getType()));
+ }
+ }
+ }
+
+ } finally {
+ ContextManager.getCurrentContext().popFBOTextureRenderer();
+ }
+ }
+
+ @Override
+ protected void setupForSingleTexDraw(final Texture tex) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final int textureId = tex.getTextureIdForContext(context.getGlContextRep());
+
+ if (tex.getTextureStoreFormat().isDepthFormat()) {
+ // No color buffer
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
+
+ // Setup depth texture into FBO
+ if (tex.getType() == Type.TwoDimensional) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, textureId, 0);
+ } else if (tex.getType() == Type.CubeMap) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT,
+ LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), textureId,
+ 0);
+ } else {
+ throw new IllegalArgumentException("Can not render to texture of type: " + tex.getType());
+ }
+
+ setDrawBuffer(GL11.GL_NONE);
+ setReadBuffer(GL11.GL_NONE);
+ } else {
+ // Set color texture into FBO
+ if (tex.getType() == Type.TwoDimensional) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, textureId, 0);
+ } else if (tex.getType() == Type.CubeMap) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
+ LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), textureId,
+ 0);
+ } else {
+ throw new IllegalArgumentException("Can not render to texture of type: " + tex.getType());
+ }
+
+ // setup depth RB
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, _depthRBID);
+
+ setDrawBuffer(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT);
+ setReadBuffer(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT);
+ }
+
+ // Check FBO complete
+ checkFBOComplete(_fboID);
+ }
+
+ private void setReadBuffer(final int attachVal) {
+ GL11.glReadBuffer(attachVal);
+ }
+
+ private void setDrawBuffer(final int attachVal) {
+ GL11.glDrawBuffer(attachVal);
+ }
+
+ private void setDrawBuffers(final int maxEntry) {
+ if (maxEntry <= 1) {
+ setDrawBuffer(maxEntry != 0 ? EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT : GL11.GL_NONE);
+ } else {
+ // We should only get to this point if we support ARBDrawBuffers.
+ _attachBuffer.clear();
+ _attachBuffer.limit(maxEntry);
+ ARBDrawBuffers.glDrawBuffersARB(_attachBuffer);
+ }
+ }
+
+ @Override
+ protected void takedownForSingleTexDraw(final Texture tex) {
+ // automatically generate mipmaps for our texture.
+ if (tex.getMinificationFilter().usesMipMapLevels()) {
+ LwjglTextureStateUtil.doTextureBind(tex, 0, true);
+ EXTFramebufferObject.glGenerateMipmapEXT(LwjglTextureStateUtil.getGLType(tex.getType()));
+ }
+ }
+
+ @Override
+ protected void setMSFBO() {
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT, _msfboID);
+ }
+
+ @Override
+ protected void blitMSFBO() {
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_READ_FRAMEBUFFER_EXT, _msfboID);
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT, _fboID);
+ EXTFramebufferBlit.glBlitFramebufferEXT(0, 0, _width, _height, 0, 0, _width, _height, GL11.GL_COLOR_BUFFER_BIT
+ | GL11.GL_DEPTH_BUFFER_BIT, GL11.GL_NEAREST);
+
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_READ_FRAMEBUFFER_EXT, 0);
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT, 0);
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
+ }
+
+ /**
+ * Check the currently bound FBO status for completeness. The passed in fboID is for informational purposes only.
+ *
+ * @param fboID
+ * an id to use for log messages, particularly if there are any issues.
+ */
+ public static void checkFBOComplete(final int fboID) {
+ final int status = EXTFramebufferObject.glCheckFramebufferStatusEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT);
+ switch (status) {
+ case EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT:
+ break;
+ case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT exception");
+ case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT exception");
+ case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT exception");
+ case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT exception");
+ case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT exception");
+ case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT exception");
+ case EXTFramebufferObject.GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_UNSUPPORTED_EXT exception.");
+ case EXTFramebufferMultisample.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
+ throw new IllegalStateException("FrameBuffer: " + fboID
+ + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT exception.");
+ default:
+ throw new IllegalStateException("Unexpected reply from glCheckFramebufferStatusEXT: " + status);
+ }
+ }
+
+ public void copyToTexture(final Texture tex, final int x, final int y, final int width, final int height,
+ final int xoffset, final int yoffset) {
+ LwjglTextureStateUtil.doTextureBind(tex, 0, true);
+
+ if (tex.getType() == Type.TwoDimensional) {
+ GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height);
+ } else if (tex.getType() == Type.CubeMap) {
+ GL11.glCopyTexSubImage2D(
+ LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), 0, xoffset,
+ yoffset, x, y, width, height);
+ } else {
+ throw new IllegalArgumentException("Invalid texture type: " + tex.getType());
+ }
+ }
+
+ @Override
+ protected void clearBuffers(final int clear) {
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+ _parentRenderer.clearBuffers(clear);
+ }
+
+ @Override
+ protected void activate() {
+ // Lazy init
+ if (_fboID == 0) {
+ final IntBuffer buffer = BufferUtils.createIntBuffer(1);
+
+ // Create our texture binding FBO
+ EXTFramebufferObject.glGenFramebuffersEXT(buffer); // generate id
+ _fboID = buffer.get(0);
+
+ // Create a depth renderbuffer to use for RTT use
+ EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
+ _depthRBID = buffer.get(0);
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _depthRBID);
+ int format = GL11.GL_DEPTH_COMPONENT;
+ if (_supportsDepthTexture && _depthBits > 0) {
+ switch (_depthBits) {
+ case 16:
+ format = ARBDepthTexture.GL_DEPTH_COMPONENT16_ARB;
+ break;
+ case 24:
+ format = ARBDepthTexture.GL_DEPTH_COMPONENT24_ARB;
+ break;
+ case 32:
+ format = ARBDepthTexture.GL_DEPTH_COMPONENT32_ARB;
+ break;
+ default:
+ // stick with the "undefined" GL_DEPTH_COMPONENT
+ }
+ }
+ EXTFramebufferObject.glRenderbufferStorageEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, format, _width,
+ _height);
+
+ // unbind...
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
+
+ // If we support it, rustle up a multisample framebuffer + renderbuffers
+ if (_samples != 0 && _supportsMultisample) {
+ // create ms framebuffer object
+ EXTFramebufferObject.glGenFramebuffersEXT(buffer);
+ _msfboID = buffer.get(0);
+
+ // create ms renderbuffers
+ EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
+ _mscolorRBID = buffer.get(0);
+ EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
+ _msdepthRBID = buffer.get(0);
+
+ // set up renderbuffer properties
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _mscolorRBID);
+ EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT,
+ _samples, GL11.GL_RGBA, _width, _height);
+
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _msdepthRBID);
+ EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT,
+ _samples, format, _width, _height);
+
+ EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
+
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, _msfboID);
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT,
+ _mscolorRBID);
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
+ EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT,
+ _msdepthRBID);
+
+ // check for errors
+ checkFBOComplete(_msfboID);
+
+ // release
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
+ }
+
+ }
+
+ if (_active == 0) {
+
+ final RenderContext context = ContextManager.getCurrentContext();
+ final RendererRecord record = context.getRendererRecord();
+
+ // needed as FBOs do not share this flag it seems
+ record.setClippingTestValid(false);
+
+ // push a delimiter onto the clip stack
+ _neededClip = _parentRenderer.isClipTestEnabled();
+ if (_neededClip) {
+ _parentRenderer.pushEmptyClip();
+ }
+
+ GL11.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(),
+ _backgroundColor.getAlpha());
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, _fboID);
+ ContextManager.getCurrentContext().pushEnforcedStates();
+ ContextManager.getCurrentContext().clearEnforcedStates();
+ ContextManager.getCurrentContext().enforceStates(_enforcedStates);
+ }
+ _active++;
+ }
+
+ @Override
+ protected void deactivate() {
+ if (_active == 1) {
+ final ReadOnlyColorRGBA bgColor = _parentRenderer.getBackgroundColor();
+ GL11.glClearColor(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), bgColor.getAlpha());
+ EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
+
+ ContextManager.getCurrentContext().popEnforcedStates();
+
+ if (_neededClip) {
+ _parentRenderer.popClip();
+ }
+ }
+ _active--;
+ }
+
+ public void cleanup() {
+ if (_fboID != 0) {
+ final IntBuffer id = BufferUtils.createIntBuffer(1);
+ id.put(_fboID);
+ id.rewind();
+ EXTFramebufferObject.glDeleteFramebuffersEXT(id);
+ }
+
+ if (_depthRBID != 0) {
+ final IntBuffer id = BufferUtils.createIntBuffer(1);
+ id.put(_depthRBID);
+ id.rewind();
+ EXTFramebufferObject.glDeleteRenderbuffersEXT(id);
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRendererProvider.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRendererProvider.java
new file mode 100644
index 0000000..a491fe5
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/renderer/lwjgl/LwjglTextureRendererProvider.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.renderer.lwjgl;
+
+import java.util.logging.Logger;
+
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRenderer;
+import com.ardor3d.renderer.TextureRendererProvider;
+
+public class LwjglTextureRendererProvider implements TextureRendererProvider {
+
+ private static final Logger logger = Logger.getLogger(LwjglTextureRendererProvider.class.getName());
+
+ public TextureRenderer createTextureRenderer(final int width, final int height, final Renderer renderer,
+ final ContextCapabilities caps) {
+ return createTextureRenderer(width, height, 0, 0, renderer, caps);
+ }
+
+ public TextureRenderer createTextureRenderer(final int width, final int height, final int depthBits,
+ final int samples, final Renderer renderer, final ContextCapabilities caps) {
+ return createTextureRenderer(new DisplaySettings(width, height, depthBits, samples), false, renderer, caps);
+ }
+
+ public TextureRenderer createTextureRenderer(final DisplaySettings settings, final boolean forcePbuffer,
+ final Renderer renderer, final ContextCapabilities caps) {
+ if (!forcePbuffer && caps.isFBOSupported()) {
+ return new LwjglTextureRenderer(settings.getWidth(), settings.getHeight(), settings.getDepthBits(),
+ settings.getSamples(), renderer, caps);
+ } else if (caps.isPbufferSupported()) {
+ return new LwjglPbufferTextureRenderer(settings, renderer, caps);
+ } else {
+ logger.severe("No texture renderer support (FBO or Pbuffer).");
+ return null;
+ }
+
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglBlendStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglBlendStateUtil.java
new file mode 100644
index 0000000..9a65133
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglBlendStateUtil.java
@@ -0,0 +1,425 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.ARBImaging;
+import org.lwjgl.opengl.ARBMultisample;
+import org.lwjgl.opengl.EXTBlendColor;
+import org.lwjgl.opengl.EXTBlendEquationSeparate;
+import org.lwjgl.opengl.EXTBlendFuncSeparate;
+import org.lwjgl.opengl.EXTBlendMinmax;
+import org.lwjgl.opengl.EXTBlendSubtract;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.BlendState.BlendEquation;
+import com.ardor3d.renderer.state.BlendState.DestinationFunction;
+import com.ardor3d.renderer.state.BlendState.SourceFunction;
+import com.ardor3d.renderer.state.BlendState.TestFunction;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.BlendStateRecord;
+
+public abstract class LwjglBlendStateUtil {
+
+ public static void apply(final BlendState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final BlendStateRecord record = (BlendStateRecord) context.getStateRecord(StateType.Blend);
+ final ContextCapabilities caps = context.getCapabilities();
+ context.setCurrentState(StateType.Blend, state);
+
+ if (state.isEnabled()) {
+ applyBlendEquations(state.isBlendEnabled(), state, record, caps);
+ applyBlendColor(state.isBlendEnabled(), state, record, caps);
+ applyBlendFunctions(state.isBlendEnabled(), state, record, caps);
+
+ applyTest(state.isTestEnabled(), state, record);
+
+ if (caps.isMultisampleSupported()) {
+ applyAlphaCoverage(state.isSampleAlphaToCoverageEnabled(), state.isSampleAlphaToOneEnabled(), record,
+ caps);
+ applySampleCoverage(state.isSampleCoverageEnabled(), state, record, caps);
+ }
+ } else {
+ // disable blend
+ applyBlendEquations(false, state, record, caps);
+
+ // disable alpha test
+ applyTest(false, state, record);
+
+ // disable sample coverage
+ if (caps.isMultisampleSupported()) {
+ applyAlphaCoverage(false, false, record, caps);
+ applySampleCoverage(false, state, record, caps);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ protected static void applyBlendEquations(final boolean enabled, final BlendState state,
+ final BlendStateRecord record, final ContextCapabilities caps) {
+ if (record.isValid()) {
+ if (enabled) {
+ if (!record.blendEnabled) {
+ GL11.glEnable(GL11.GL_BLEND);
+ record.blendEnabled = true;
+ }
+ final int blendEqRGB = getGLEquationValue(state.getBlendEquationRGB(), caps);
+ if (caps.isSeparateBlendEquationsSupported()) {
+ final int blendEqAlpha = getGLEquationValue(state.getBlendEquationAlpha(), caps);
+ if (record.blendEqRGB != blendEqRGB || record.blendEqAlpha != blendEqAlpha) {
+ EXTBlendEquationSeparate.glBlendEquationSeparateEXT(blendEqRGB, blendEqAlpha);
+ record.blendEqRGB = blendEqRGB;
+ record.blendEqAlpha = blendEqAlpha;
+ }
+ } else if (caps.isBlendEquationSupported()) {
+ if (record.blendEqRGB != blendEqRGB) {
+ ARBImaging.glBlendEquation(blendEqRGB);
+ record.blendEqRGB = blendEqRGB;
+ }
+ }
+ } else if (record.blendEnabled) {
+ GL11.glDisable(GL11.GL_BLEND);
+ record.blendEnabled = false;
+ }
+
+ } else {
+ if (enabled) {
+ GL11.glEnable(GL11.GL_BLEND);
+ record.blendEnabled = true;
+ final int blendEqRGB = getGLEquationValue(state.getBlendEquationRGB(), caps);
+ if (caps.isSeparateBlendEquationsSupported()) {
+ final int blendEqAlpha = getGLEquationValue(state.getBlendEquationAlpha(), caps);
+ EXTBlendEquationSeparate.glBlendEquationSeparateEXT(blendEqRGB, blendEqAlpha);
+ record.blendEqRGB = blendEqRGB;
+ record.blendEqAlpha = blendEqAlpha;
+ } else if (caps.isBlendEquationSupported()) {
+ ARBImaging.glBlendEquation(blendEqRGB);
+ record.blendEqRGB = blendEqRGB;
+ }
+ } else {
+ GL11.glDisable(GL11.GL_BLEND);
+ record.blendEnabled = false;
+ }
+ }
+ }
+
+ protected static void applyBlendColor(final boolean enabled, final BlendState state, final BlendStateRecord record,
+ final ContextCapabilities caps) {
+ if (enabled) {
+ final boolean applyConstant = state.getDestinationFunctionRGB().usesConstantColor()
+ || state.getSourceFunctionRGB().usesConstantColor()
+ || (caps.isConstantBlendColorSupported() && (state.getDestinationFunctionAlpha()
+ .usesConstantColor() || state.getSourceFunctionAlpha().usesConstantColor()));
+ if (applyConstant && caps.isConstantBlendColorSupported()) {
+ final ReadOnlyColorRGBA constant = state.getConstantColor();
+ if (!record.isValid() || (caps.isConstantBlendColorSupported() && !record.blendColor.equals(constant))) {
+ ARBImaging.glBlendColor(constant.getRed(), constant.getGreen(), constant.getBlue(),
+ constant.getAlpha());
+ record.blendColor.set(constant);
+ }
+ }
+ }
+ }
+
+ protected static void applyBlendFunctions(final boolean enabled, final BlendState state,
+ final BlendStateRecord record, final ContextCapabilities caps) {
+ if (record.isValid()) {
+ if (enabled) {
+ final int glSrcRGB = getGLSrcValue(state.getSourceFunctionRGB(), caps);
+ final int glDstRGB = getGLDstValue(state.getDestinationFunctionRGB(), caps);
+ if (caps.isSeparateBlendFunctionsSupported()) {
+ final int glSrcAlpha = getGLSrcValue(state.getSourceFunctionAlpha(), caps);
+ final int glDstAlpha = getGLDstValue(state.getDestinationFunctionAlpha(), caps);
+ if (record.srcFactorRGB != glSrcRGB || record.dstFactorRGB != glDstRGB
+ || record.srcFactorAlpha != glSrcAlpha || record.dstFactorAlpha != glDstAlpha) {
+ EXTBlendFuncSeparate.glBlendFuncSeparateEXT(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha);
+ record.srcFactorRGB = glSrcRGB;
+ record.dstFactorRGB = glDstRGB;
+ record.srcFactorAlpha = glSrcAlpha;
+ record.dstFactorAlpha = glDstAlpha;
+ }
+ } else if (record.srcFactorRGB != glSrcRGB || record.dstFactorRGB != glDstRGB) {
+ GL11.glBlendFunc(glSrcRGB, glDstRGB);
+ record.srcFactorRGB = glSrcRGB;
+ record.dstFactorRGB = glDstRGB;
+ }
+ }
+ } else {
+ if (enabled) {
+ final int glSrcRGB = getGLSrcValue(state.getSourceFunctionRGB(), caps);
+ final int glDstRGB = getGLDstValue(state.getDestinationFunctionRGB(), caps);
+ if (caps.isSeparateBlendFunctionsSupported()) {
+ final int glSrcAlpha = getGLSrcValue(state.getSourceFunctionAlpha(), caps);
+ final int glDstAlpha = getGLDstValue(state.getDestinationFunctionAlpha(), caps);
+ EXTBlendFuncSeparate.glBlendFuncSeparateEXT(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha);
+ record.srcFactorRGB = glSrcRGB;
+ record.dstFactorRGB = glDstRGB;
+ record.srcFactorAlpha = glSrcAlpha;
+ record.dstFactorAlpha = glDstAlpha;
+ } else {
+ GL11.glBlendFunc(glSrcRGB, glDstRGB);
+ record.srcFactorRGB = glSrcRGB;
+ record.dstFactorRGB = glDstRGB;
+ }
+ }
+ }
+ }
+
+ protected static void applyAlphaCoverage(final boolean sampleAlphaToCoverageEnabled,
+ final boolean sampleAlphaToOneEnabled, final BlendStateRecord record, final ContextCapabilities caps) {
+ if (record.isValid()) {
+ if (sampleAlphaToCoverageEnabled != record.sampleAlphaToCoverageEnabled) {
+ if (sampleAlphaToCoverageEnabled) {
+ GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+ } else {
+ GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+ }
+ record.sampleAlphaToCoverageEnabled = sampleAlphaToCoverageEnabled;
+ }
+ if (sampleAlphaToOneEnabled != record.sampleAlphaToOneEnabled) {
+ if (sampleAlphaToOneEnabled) {
+ GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB);
+ } else {
+ GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB);
+ }
+ record.sampleAlphaToOneEnabled = sampleAlphaToOneEnabled;
+ }
+ } else {
+ if (sampleAlphaToCoverageEnabled) {
+ GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+ } else {
+ GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+ }
+ record.sampleAlphaToCoverageEnabled = sampleAlphaToCoverageEnabled;
+ if (sampleAlphaToOneEnabled) {
+ GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB);
+ } else {
+ GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB);
+ }
+ record.sampleAlphaToOneEnabled = sampleAlphaToOneEnabled;
+ }
+ }
+
+ protected static void applySampleCoverage(final boolean enabled, final BlendState state,
+ final BlendStateRecord record, final ContextCapabilities caps) {
+
+ final boolean coverageInverted = state.isSampleCoverageInverted();
+ final float coverageValue = state.getSampleCoverage();
+
+ if (record.isValid()) {
+ if (enabled) {
+ if (!record.sampleCoverageEnabled) {
+ GL11.glEnable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB);
+ record.sampleCoverageEnabled = true;
+ }
+ if (record.sampleCoverageInverted != coverageInverted || record.sampleCoverage != coverageValue) {
+ ARBMultisample.glSampleCoverageARB(coverageValue, coverageInverted);
+ record.sampleCoverageInverted = coverageInverted;
+ record.sampleCoverage = coverageValue;
+ }
+ } else {
+ if (record.sampleCoverageEnabled) {
+ GL11.glDisable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB);
+ record.sampleCoverageEnabled = false;
+ }
+ }
+ } else {
+ if (enabled) {
+ GL11.glEnable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB);
+ record.sampleCoverageEnabled = true;
+ ARBMultisample.glSampleCoverageARB(coverageValue, coverageInverted);
+ record.sampleCoverageInverted = coverageInverted;
+ record.sampleCoverage = coverageValue;
+ } else {
+ GL11.glDisable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB);
+ record.sampleCoverageEnabled = false;
+ }
+ }
+ }
+
+ protected static int getGLSrcValue(final SourceFunction function, final ContextCapabilities caps) {
+ switch (function) {
+ case Zero:
+ return GL11.GL_ZERO;
+ case DestinationColor:
+ return GL11.GL_DST_COLOR;
+ case OneMinusDestinationColor:
+ return GL11.GL_ONE_MINUS_DST_COLOR;
+ case SourceAlpha:
+ return GL11.GL_SRC_ALPHA;
+ case OneMinusSourceAlpha:
+ return GL11.GL_ONE_MINUS_SRC_ALPHA;
+ case DestinationAlpha:
+ return GL11.GL_DST_ALPHA;
+ case OneMinusDestinationAlpha:
+ return GL11.GL_ONE_MINUS_DST_ALPHA;
+ case SourceAlphaSaturate:
+ return GL11.GL_SRC_ALPHA_SATURATE;
+ case ConstantColor:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_CONSTANT_COLOR_EXT;
+ }
+ // FALLS THROUGH
+ case OneMinusConstantColor:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_ONE_MINUS_CONSTANT_COLOR_EXT;
+ }
+ // FALLS THROUGH
+ case ConstantAlpha:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_CONSTANT_ALPHA_EXT;
+ }
+ // FALLS THROUGH
+ case OneMinusConstantAlpha:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_ONE_MINUS_CONSTANT_ALPHA_EXT;
+ }
+ // FALLS THROUGH
+ case One:
+ return GL11.GL_ONE;
+ }
+ throw new IllegalArgumentException("Invalid source function type: " + function);
+ }
+
+ protected static int getGLDstValue(final DestinationFunction function, final ContextCapabilities caps) {
+ switch (function) {
+ case Zero:
+ return GL11.GL_ZERO;
+ case SourceColor:
+ return GL11.GL_SRC_COLOR;
+ case OneMinusSourceColor:
+ return GL11.GL_ONE_MINUS_SRC_COLOR;
+ case SourceAlpha:
+ return GL11.GL_SRC_ALPHA;
+ case OneMinusSourceAlpha:
+ return GL11.GL_ONE_MINUS_SRC_ALPHA;
+ case DestinationAlpha:
+ return GL11.GL_DST_ALPHA;
+ case OneMinusDestinationAlpha:
+ return GL11.GL_ONE_MINUS_DST_ALPHA;
+ case ConstantColor:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_CONSTANT_COLOR_EXT;
+ }
+ // FALLS THROUGH
+ case OneMinusConstantColor:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_ONE_MINUS_CONSTANT_COLOR_EXT;
+ }
+ // FALLS THROUGH
+ case ConstantAlpha:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_CONSTANT_ALPHA_EXT;
+ }
+ // FALLS THROUGH
+ case OneMinusConstantAlpha:
+ if (caps.isConstantBlendColorSupported()) {
+ return EXTBlendColor.GL_ONE_MINUS_CONSTANT_ALPHA_EXT;
+ }
+ // FALLS THROUGH
+ case One:
+ return GL11.GL_ONE;
+ }
+ throw new IllegalArgumentException("Invalid destination function type: " + function);
+ }
+
+ protected static int getGLEquationValue(final BlendEquation eq, final ContextCapabilities caps) {
+ switch (eq) {
+ case Min:
+ if (caps.isMinMaxBlendEquationsSupported()) {
+ return EXTBlendMinmax.GL_MIN_EXT;
+ }
+ // FALLS THROUGH
+ case Max:
+ if (caps.isMinMaxBlendEquationsSupported()) {
+ return EXTBlendMinmax.GL_MAX_EXT;
+ } else {
+ return ARBImaging.GL_FUNC_ADD;
+ }
+ case Subtract:
+ if (caps.isSubtractBlendEquationsSupported()) {
+ return EXTBlendSubtract.GL_FUNC_SUBTRACT_EXT;
+ }
+ // FALLS THROUGH
+ case ReverseSubtract:
+ if (caps.isSubtractBlendEquationsSupported()) {
+ return EXTBlendSubtract.GL_FUNC_REVERSE_SUBTRACT_EXT;
+ }
+ // FALLS THROUGH
+ case Add:
+ return ARBImaging.GL_FUNC_ADD;
+ }
+ throw new IllegalArgumentException("Invalid blend equation: " + eq);
+ }
+
+ protected static void applyTest(final boolean enabled, final BlendState state, final BlendStateRecord record) {
+ if (record.isValid()) {
+ if (enabled) {
+ if (!record.testEnabled) {
+ GL11.glEnable(GL11.GL_ALPHA_TEST);
+ record.testEnabled = true;
+ }
+ final int glFunc = getGLFuncValue(state.getTestFunction());
+ if (record.alphaFunc != glFunc || record.alphaRef != state.getReference()) {
+ GL11.glAlphaFunc(glFunc, state.getReference());
+ record.alphaFunc = glFunc;
+ record.alphaRef = state.getReference();
+ }
+ } else if (record.testEnabled) {
+ GL11.glDisable(GL11.GL_ALPHA_TEST);
+ record.testEnabled = false;
+ }
+
+ } else {
+ if (enabled) {
+ GL11.glEnable(GL11.GL_ALPHA_TEST);
+ record.testEnabled = true;
+ final int glFunc = getGLFuncValue(state.getTestFunction());
+ GL11.glAlphaFunc(glFunc, state.getReference());
+ record.alphaFunc = glFunc;
+ record.alphaRef = state.getReference();
+ } else {
+ GL11.glDisable(GL11.GL_ALPHA_TEST);
+ record.testEnabled = false;
+ }
+ }
+ }
+
+ protected static int getGLFuncValue(final TestFunction function) {
+ switch (function) {
+ case Never:
+ return GL11.GL_NEVER;
+ case LessThan:
+ return GL11.GL_LESS;
+ case EqualTo:
+ return GL11.GL_EQUAL;
+ case LessThanOrEqualTo:
+ return GL11.GL_LEQUAL;
+ case GreaterThan:
+ return GL11.GL_GREATER;
+ case NotEqualTo:
+ return GL11.GL_NOTEQUAL;
+ case GreaterThanOrEqualTo:
+ return GL11.GL_GEQUAL;
+ case Always:
+ return GL11.GL_ALWAYS;
+ }
+ throw new IllegalArgumentException("Invalid test function type: " + function);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglClipStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglClipStateUtil.java
new file mode 100644
index 0000000..d3ee2a0
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglClipStateUtil.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.ClipState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.ClipStateRecord;
+
+public abstract class LwjglClipStateUtil {
+
+ public static void apply(final ClipState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ClipStateRecord record = (ClipStateRecord) context.getStateRecord(StateType.Clip);
+ context.setCurrentState(StateType.Clip, state);
+
+ final ContextCapabilities caps = context.getCapabilities();
+ final int max = Math.min(ClipState.MAX_CLIP_PLANES, caps.getMaxUserClipPlanes());
+
+ if (state.isEnabled()) {
+ for (int i = 0; i < max; i++) {
+ enableClipPlane(i, state.getPlaneEnabled(i), state, record);
+ }
+ } else {
+ for (int i = 0; i < max; i++) {
+ enableClipPlane(i, false, state, record);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void enableClipPlane(final int planeIndex, final boolean enable, final ClipState state,
+ final ClipStateRecord record) {
+ if (enable) {
+ if (!record.isValid() || !record.planeEnabled[planeIndex]) {
+ GL11.glEnable(GL11.GL_CLIP_PLANE0 + planeIndex);
+ record.planeEnabled[planeIndex] = true;
+ }
+
+ record.buf.rewind();
+ record.buf.put(state.getPlaneEquations(planeIndex));
+ record.buf.flip();
+ GL11.glClipPlane(GL11.GL_CLIP_PLANE0 + planeIndex, record.buf);
+
+ } else {
+ if (!record.isValid() || record.planeEnabled[planeIndex]) {
+ GL11.glDisable(GL11.GL_CLIP_PLANE0 + planeIndex);
+ record.planeEnabled[planeIndex] = false;
+ }
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglColorMaskStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglColorMaskStateUtil.java
new file mode 100644
index 0000000..0a45a97
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglColorMaskStateUtil.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.ColorMaskState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.ColorMaskStateRecord;
+
+public abstract class LwjglColorMaskStateUtil {
+
+ public static void apply(final ColorMaskState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ColorMaskStateRecord record = (ColorMaskStateRecord) context.getStateRecord(StateType.ColorMask);
+ context.setCurrentState(StateType.ColorMask, state);
+
+ if (state.isEnabled()) {
+ if (!record.isValid() || !record.is(state.getRed(), state.getGreen(), state.getBlue(), state.getAlpha())) {
+ GL11.glColorMask(state.getRed(), state.getGreen(), state.getBlue(), state.getAlpha());
+ record.set(state.getRed(), state.getGreen(), state.getBlue(), state.getAlpha());
+ }
+ } else if (!record.isValid() || !record.is(true, true, true, true)) {
+ GL11.glColorMask(true, true, true, true);
+ record.set(true, true, true, true);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglCullStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglCullStateUtil.java
new file mode 100644
index 0000000..7a27d18
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglCullStateUtil.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.CullState;
+import com.ardor3d.renderer.state.CullState.Face;
+import com.ardor3d.renderer.state.CullState.PolygonWind;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.CullStateRecord;
+
+public abstract class LwjglCullStateUtil {
+
+ public static void apply(final CullState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final CullStateRecord record = (CullStateRecord) context.getStateRecord(StateType.Cull);
+ context.setCurrentState(StateType.Cull, state);
+
+ if (state.isEnabled()) {
+ final Face useCullMode = state.getCullFace();
+
+ switch (useCullMode) {
+ case Front:
+ setCull(GL11.GL_FRONT, record);
+ setCullEnabled(true, record);
+ break;
+ case Back:
+ setCull(GL11.GL_BACK, record);
+ setCullEnabled(true, record);
+ break;
+ case FrontAndBack:
+ setCull(GL11.GL_FRONT_AND_BACK, record);
+ setCullEnabled(true, record);
+ break;
+ case None:
+ setCullEnabled(false, record);
+ break;
+ }
+ setGLPolygonWind(state.getPolygonWind(), record);
+ } else {
+ setCullEnabled(false, record);
+ setGLPolygonWind(PolygonWind.CounterClockWise, record);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void setCullEnabled(final boolean enable, final CullStateRecord record) {
+ if (!record.isValid() || record.enabled != enable) {
+ if (enable) {
+ GL11.glEnable(GL11.GL_CULL_FACE);
+ } else {
+ GL11.glDisable(GL11.GL_CULL_FACE);
+ }
+ record.enabled = enable;
+ }
+ }
+
+ private static void setCull(final int face, final CullStateRecord record) {
+ if (!record.isValid() || record.face != face) {
+ GL11.glCullFace(face);
+ record.face = face;
+ }
+ }
+
+ private static void setGLPolygonWind(final PolygonWind windOrder, final CullStateRecord record) {
+ if (!record.isValid() || record.windOrder != windOrder) {
+ switch (windOrder) {
+ case CounterClockWise:
+ GL11.glFrontFace(GL11.GL_CCW);
+ break;
+ case ClockWise:
+ GL11.glFrontFace(GL11.GL_CW);
+ break;
+ }
+ record.windOrder = windOrder;
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFogStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFogStateUtil.java
new file mode 100644
index 0000000..71f4342
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFogStateUtil.java
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.EXTFogCoord;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.FogState;
+import com.ardor3d.renderer.state.FogState.CoordinateSource;
+import com.ardor3d.renderer.state.FogState.DensityFunction;
+import com.ardor3d.renderer.state.FogState.Quality;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.FogStateRecord;
+
+public abstract class LwjglFogStateUtil {
+
+ public static void apply(final FogState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final FogStateRecord record = (FogStateRecord) context.getStateRecord(StateType.Fog);
+ context.setCurrentState(StateType.Fog, state);
+
+ if (state.isEnabled()) {
+ enableFog(true, record);
+
+ if (record.isValid()) {
+ if (record.fogStart != state.getStart()) {
+ GL11.glFogf(GL11.GL_FOG_START, state.getStart());
+ record.fogStart = state.getStart();
+ }
+ if (record.fogEnd != state.getEnd()) {
+ GL11.glFogf(GL11.GL_FOG_END, state.getEnd());
+ record.fogEnd = state.getEnd();
+ }
+ if (record.density != state.getDensity()) {
+ GL11.glFogf(GL11.GL_FOG_DENSITY, state.getDensity());
+ record.density = state.getDensity();
+ }
+ } else {
+ GL11.glFogf(GL11.GL_FOG_START, state.getStart());
+ record.fogStart = state.getStart();
+ GL11.glFogf(GL11.GL_FOG_END, state.getEnd());
+ record.fogEnd = state.getEnd();
+ GL11.glFogf(GL11.GL_FOG_DENSITY, state.getDensity());
+ record.density = state.getDensity();
+ }
+
+ final ReadOnlyColorRGBA fogColor = state.getColor();
+ applyFogColor(fogColor, record);
+ applyFogMode(state.getDensityFunction(), record);
+ applyFogHint(state.getQuality(), record);
+ applyFogSource(state.getSource(), record, context.getCapabilities());
+ } else {
+ enableFog(false, record);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void enableFog(final boolean enable, final FogStateRecord record) {
+ if (record.isValid()) {
+ if (enable && !record.enabled) {
+ GL11.glEnable(GL11.GL_FOG);
+ record.enabled = true;
+ } else if (!enable && record.enabled) {
+ GL11.glDisable(GL11.GL_FOG);
+ record.enabled = false;
+ }
+ } else {
+ if (enable) {
+ GL11.glEnable(GL11.GL_FOG);
+ } else {
+ GL11.glDisable(GL11.GL_FOG);
+ }
+ record.enabled = enable;
+ }
+ }
+
+ private static void applyFogColor(final ReadOnlyColorRGBA color, final FogStateRecord record) {
+ if (!record.isValid() || !color.equals(record.fogColor)) {
+ record.fogColor.set(color);
+ record.colorBuff.clear();
+ record.colorBuff.put(record.fogColor.getRed()).put(record.fogColor.getGreen())
+ .put(record.fogColor.getBlue()).put(record.fogColor.getAlpha());
+ record.colorBuff.flip();
+ GL11.glFog(GL11.GL_FOG_COLOR, record.colorBuff);
+ }
+ }
+
+ private static void applyFogSource(final CoordinateSource source, final FogStateRecord record,
+ final ContextCapabilities caps) {
+ if (caps.isFogCoordinatesSupported()) {
+ if (!record.isValid() || !source.equals(record.source)) {
+ if (source == CoordinateSource.Depth) {
+ GL11.glFogi(EXTFogCoord.GL_FOG_COORDINATE_SOURCE_EXT, EXTFogCoord.GL_FRAGMENT_DEPTH_EXT);
+ } else {
+ GL11.glFogi(EXTFogCoord.GL_FOG_COORDINATE_SOURCE_EXT, EXTFogCoord.GL_FOG_COORDINATE_EXT);
+ }
+ }
+ }
+ }
+
+ private static void applyFogMode(final DensityFunction densityFunction, final FogStateRecord record) {
+ int glMode = 0;
+ switch (densityFunction) {
+ case Exponential:
+ glMode = GL11.GL_EXP;
+ break;
+ case Linear:
+ glMode = GL11.GL_LINEAR;
+ break;
+ case ExponentialSquared:
+ glMode = GL11.GL_EXP2;
+ break;
+ }
+
+ if (!record.isValid() || record.fogMode != glMode) {
+ GL11.glFogi(GL11.GL_FOG_MODE, glMode);
+ record.fogMode = glMode;
+ }
+ }
+
+ private static void applyFogHint(final Quality quality, final FogStateRecord record) {
+ int glHint = 0;
+ switch (quality) {
+ case PerVertex:
+ glHint = GL11.GL_FASTEST;
+ break;
+ case PerPixel:
+ glHint = GL11.GL_NICEST;
+ break;
+ }
+
+ if (!record.isValid() || record.fogHint != glHint) {
+ GL11.glHint(GL11.GL_FOG_HINT, glHint);
+ record.fogHint = glHint;
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFragmentProgramStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFragmentProgramStateUtil.java
new file mode 100644
index 0000000..fc2ac8f
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglFragmentProgramStateUtil.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBFragmentProgram;
+import org.lwjgl.opengl.ARBProgram;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.FragmentProgramState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.FragmentProgramStateRecord;
+import com.ardor3d.util.geom.BufferUtils;
+
+public final class LwjglFragmentProgramStateUtil {
+ private static final Logger logger = Logger.getLogger(LwjglFragmentProgramStateUtil.class.getName());
+
+ /**
+ * Queries OpenGL for errors in the fragment program. Errors are logged as SEVERE, noting both the line number and
+ * message.
+ */
+ private static void checkProgramError() {
+ if (GL11.glGetError() == GL11.GL_INVALID_OPERATION) {
+ // retrieve the error position
+ final IntBuffer errorloc = BufferUtils.createIntBuffer(16);
+ GL11.glGetInteger(ARBProgram.GL_PROGRAM_ERROR_POSITION_ARB, errorloc);
+
+ logger.severe("Error " + GL11.glGetString(ARBProgram.GL_PROGRAM_ERROR_STRING_ARB)
+ + " in fragment program on line " + errorloc.get(0));
+ }
+ }
+
+ private static int create(final ByteBuffer program) {
+
+ final IntBuffer buf = BufferUtils.createIntBuffer(1);
+
+ ARBProgram.glGenProgramsARB(buf);
+ ARBProgram.glBindProgramARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, buf.get(0));
+ ARBProgram.glProgramStringARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB,
+ ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, program);
+
+ checkProgramError();
+
+ return buf.get(0);
+ }
+
+ public static void apply(final FragmentProgramState state) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ if (context.getCapabilities().isFragmentProgramSupported()) {
+ final FragmentProgramStateRecord record = (FragmentProgramStateRecord) context
+ .getStateRecord(StateType.FragmentProgram);
+ context.setCurrentState(StateType.FragmentProgram, state);
+
+ if (!record.isValid() || record.getReference() != state) {
+ record.setReference(state);
+ if (state.isEnabled()) {
+ // Fragment program not yet loaded
+ if (state._getProgramID() == -1) {
+ if (state.getProgramAsBuffer() != null) {
+ final int id = create(state.getProgramAsBuffer());
+ state._setProgramID(id);
+ } else {
+ return;
+ }
+ }
+
+ GL11.glEnable(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB);
+ ARBProgram.glBindProgramARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, state._getProgramID());
+
+ // load environmental parameters...
+ // TODO: Reevaluate how this is done.
+ /*
+ * for (int i = 0; i < envparameters.length; i++) if (envparameters[i] != null)
+ * ARBFragmentProgram.glProgramEnvParameter4fARB( ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, i,
+ * envparameters[i][0], envparameters[i][1], envparameters[i][2], envparameters[i][3]);
+ */
+
+ // load local parameters...
+ if (state.isUsingParameters()) {
+ // no parameters are used
+ for (int i = 0; i < state._getParameters().length; i++) {
+ if (state._getParameters()[i] != null) {
+ ARBProgram.glProgramLocalParameter4fARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, i,
+ state._getParameters()[i][0], state._getParameters()[i][1],
+ state._getParameters()[i][2], state._getParameters()[i][3]);
+ }
+ }
+ }
+
+ } else {
+ GL11.glDisable(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglLightStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglLightStateUtil.java
new file mode 100644
index 0000000..0ef2391
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglLightStateUtil.java
@@ -0,0 +1,372 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+
+import com.ardor3d.light.DirectionalLight;
+import com.ardor3d.light.Light;
+import com.ardor3d.light.PointLight;
+import com.ardor3d.light.SpotLight;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.math.type.ReadOnlyMatrix4;
+import com.ardor3d.math.type.ReadOnlyVector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.LightState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.LightRecord;
+import com.ardor3d.renderer.state.record.LightStateRecord;
+
+public abstract class LwjglLightStateUtil {
+
+ public static void apply(final LightState state) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final LightStateRecord record = (LightStateRecord) context.getStateRecord(StateType.Light);
+ context.setCurrentState(StateType.Light, state);
+
+ if (state.isEnabled() && LightState.LIGHTS_ENABLED) {
+ setLightEnabled(true, record);
+ setTwoSided(state.getTwoSidedLighting(), record);
+ setLocalViewer(state.getLocalViewer(), record);
+ if (context.getCapabilities().isOpenGL1_2Supported()) {
+ setSpecularControl(state.getSeparateSpecular(), record);
+ }
+
+ for (int i = 0, max = state.getNumberOfChildren(); i < max; i++) {
+ final Light light = state.get(i);
+ LightRecord lr = record.getLightRecord(i);
+ // TODO: use the reference to get the lightrecord - rherlitz
+
+ if (lr == null) {
+ lr = new LightRecord();
+ record.setLightRecord(lr, i);
+ }
+
+ if (light == null) {
+ setSingleLightEnabled(false, i, record, lr);
+ } else {
+ if (light.isEnabled()) {
+ setLight(i, light, state, record, lr);
+ } else {
+ setSingleLightEnabled(false, i, record, lr);
+ }
+ }
+ }
+
+ // disable lights at and above the max count in this state
+ for (int i = state.getNumberOfChildren(); i < LightState.MAX_LIGHTS_ALLOWED; i++) {
+ LightRecord lr = record.getLightRecord(i);
+
+ if (lr == null) {
+ lr = new LightRecord();
+ record.setLightRecord(lr, i);
+ }
+ setSingleLightEnabled(false, i, record, lr);
+ }
+
+ if ((state.getLightMask() & LightState.MASK_GLOBALAMBIENT) == 0) {
+ setModelAmbient(record, state.getGlobalAmbient());
+ } else {
+ setModelAmbient(record, ColorRGBA.BLACK_NO_ALPHA);
+ }
+ } else {
+ setLightEnabled(false, record);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void setLight(final int index, final Light light, final LightState state,
+ final LightStateRecord record, final LightRecord lr) {
+ setSingleLightEnabled(true, index, record, lr);
+
+ if ((state.getLightMask() & LightState.MASK_AMBIENT) == 0
+ && (light.getLightMask() & LightState.MASK_AMBIENT) == 0) {
+ setAmbient(index, record, light.getAmbient(), lr);
+ } else {
+ setAmbient(index, record, ColorRGBA.BLACK_NO_ALPHA, lr);
+ }
+
+ if ((state.getLightMask() & LightState.MASK_DIFFUSE) == 0
+ && (light.getLightMask() & LightState.MASK_DIFFUSE) == 0) {
+ setDiffuse(index, record, light.getDiffuse(), lr);
+ } else {
+ setDiffuse(index, record, ColorRGBA.BLACK_NO_ALPHA, lr);
+ }
+
+ if ((state.getLightMask() & LightState.MASK_SPECULAR) == 0
+ && (light.getLightMask() & LightState.MASK_SPECULAR) == 0) {
+ setSpecular(index, record, light.getSpecular(), lr);
+ } else {
+ setSpecular(index, record, ColorRGBA.BLACK_NO_ALPHA, lr);
+ }
+
+ if (light.isAttenuate()) {
+ setAttenuate(true, index, light, record, lr);
+
+ } else {
+ setAttenuate(false, index, light, record, lr);
+
+ }
+
+ switch (light.getType()) {
+ case Directional: {
+ final DirectionalLight dirLight = (DirectionalLight) light;
+
+ final ReadOnlyVector3 direction = dirLight.getDirection();
+ setPosition(index, record, -direction.getXf(), -direction.getYf(), -direction.getZf(), 0, lr);
+ break;
+ }
+ case Point:
+ case Spot: {
+ final PointLight pointLight = (PointLight) light;
+ final ReadOnlyVector3 location = pointLight.getLocation();
+ setPosition(index, record, location.getXf(), location.getYf(), location.getZf(), 1, lr);
+ break;
+ }
+ }
+
+ if (light.getType() == Light.Type.Spot) {
+ final SpotLight spot = (SpotLight) light;
+ setSpotCutoff(index, record, spot.getAngle(), lr);
+ final ReadOnlyVector3 direction = spot.getDirection();
+ setSpotDirection(index, record, direction.getXf(), direction.getYf(), direction.getZf(), 0);
+ setSpotExponent(index, record, spot.getExponent(), lr);
+ } else {
+ // set the cutoff to 180, which causes the other spot params to be
+ // ignored.
+ setSpotCutoff(index, record, 180, lr);
+ }
+ }
+
+ private static void setSingleLightEnabled(final boolean enable, final int index, final LightStateRecord record,
+ final LightRecord lr) {
+ if (!record.isValid() || lr.isEnabled() != enable) {
+ if (enable) {
+ GL11.glEnable(GL11.GL_LIGHT0 + index);
+ } else {
+ GL11.glDisable(GL11.GL_LIGHT0 + index);
+ }
+
+ lr.setEnabled(enable);
+ }
+ }
+
+ private static void setLightEnabled(final boolean enable, final LightStateRecord record) {
+ if (!record.isValid() || record.isEnabled() != enable) {
+ if (enable) {
+ GL11.glEnable(GL11.GL_LIGHTING);
+ } else {
+ GL11.glDisable(GL11.GL_LIGHTING);
+ }
+ record.setEnabled(enable);
+ }
+ }
+
+ private static void setTwoSided(final boolean twoSided, final LightStateRecord record) {
+ if (!record.isValid() || record.isTwoSidedOn() != twoSided) {
+ if (twoSided) {
+ GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_TRUE);
+ } else {
+ GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_FALSE);
+ }
+ record.setTwoSidedOn(twoSided);
+ }
+ }
+
+ private static void setLocalViewer(final boolean localViewer, final LightStateRecord record) {
+ if (!record.isValid() || record.isLocalViewer() != localViewer) {
+ if (localViewer) {
+ GL11.glLightModeli(GL11.GL_LIGHT_MODEL_LOCAL_VIEWER, GL11.GL_TRUE);
+ } else {
+ GL11.glLightModeli(GL11.GL_LIGHT_MODEL_LOCAL_VIEWER, GL11.GL_FALSE);
+ }
+ record.setLocalViewer(localViewer);
+ }
+ }
+
+ private static void setSpecularControl(final boolean separateSpecularOn, final LightStateRecord record) {
+ if (!record.isValid() || record.isSeparateSpecular() != separateSpecularOn) {
+ if (separateSpecularOn) {
+ GL11.glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SEPARATE_SPECULAR_COLOR);
+ } else {
+ GL11.glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SINGLE_COLOR);
+ }
+ record.setSeparateSpecular(separateSpecularOn);
+ }
+ }
+
+ private static void setModelAmbient(final LightStateRecord record, final ReadOnlyColorRGBA color) {
+ if (!record.isValid() || !record.globalAmbient.equals(color)) {
+ record.lightBuffer.clear();
+ record.lightBuffer.put(color.getRed());
+ record.lightBuffer.put(color.getGreen());
+ record.lightBuffer.put(color.getBlue());
+ record.lightBuffer.put(color.getAlpha());
+ record.lightBuffer.flip();
+ GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, record.lightBuffer);
+ record.globalAmbient.set(color);
+ }
+ }
+
+ private static void setAmbient(final int index, final LightStateRecord record, final ReadOnlyColorRGBA ambient,
+ final LightRecord lr) {
+ if (!record.isValid() || !lr.ambient.equals(ambient)) {
+ record.lightBuffer.clear();
+ record.lightBuffer.put(ambient.getRed());
+ record.lightBuffer.put(ambient.getGreen());
+ record.lightBuffer.put(ambient.getBlue());
+ record.lightBuffer.put(ambient.getAlpha());
+ record.lightBuffer.flip();
+ GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_AMBIENT, record.lightBuffer);
+ lr.ambient.set(ambient);
+ }
+ }
+
+ private static void setDiffuse(final int index, final LightStateRecord record, final ReadOnlyColorRGBA diffuse,
+ final LightRecord lr) {
+ if (!record.isValid() || !lr.diffuse.equals(diffuse)) {
+ record.lightBuffer.clear();
+ record.lightBuffer.put(diffuse.getRed());
+ record.lightBuffer.put(diffuse.getGreen());
+ record.lightBuffer.put(diffuse.getBlue());
+ record.lightBuffer.put(diffuse.getAlpha());
+ record.lightBuffer.flip();
+ GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_DIFFUSE, record.lightBuffer);
+ lr.diffuse.set(diffuse);
+ }
+ }
+
+ private static void setSpecular(final int index, final LightStateRecord record, final ReadOnlyColorRGBA specular,
+ final LightRecord lr) {
+ if (!record.isValid() || !lr.specular.equals(specular)) {
+ record.lightBuffer.clear();
+ record.lightBuffer.put(specular.getRed());
+ record.lightBuffer.put(specular.getGreen());
+ record.lightBuffer.put(specular.getBlue());
+ record.lightBuffer.put(specular.getAlpha());
+ record.lightBuffer.flip();
+ GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_SPECULAR, record.lightBuffer);
+ lr.specular.set(specular);
+ }
+ }
+
+ private static void setPosition(final int index, final LightStateRecord record, final float positionX,
+ final float positionY, final float positionZ, final float positionW, final LightRecord lr) {
+ // From OpenGL Docs:
+ // The light position is transformed by the contents of the current top
+ // of the ModelView matrix stack when you specify the light position
+ // with a call to glLightfv(GL_LIGHT_POSITION,...). If you later change
+ // the ModelView matrix, such as when the view changes for the next
+ // frame, the light position isn't automatically retransformed by the
+ // new contents of the ModelView matrix. If you want to update the
+ // light's position, you must again specify the light position with a
+ // call to glLightfv(GL_LIGHT_POSITION,...).
+
+ // XXX: This is a hack until we get a better lighting model up
+ final ReadOnlyMatrix4 modelViewMatrix = Camera.getCurrentCamera().getModelViewMatrix();
+
+ if (!record.isValid() || lr.position.getXf() != positionX || lr.position.getYf() != positionY
+ || lr.position.getZf() != positionZ || lr.position.getWf() != positionW
+ || !lr.modelViewMatrix.equals(modelViewMatrix)) {
+
+ record.lightBuffer.clear();
+ record.lightBuffer.put(positionX);
+ record.lightBuffer.put(positionY);
+ record.lightBuffer.put(positionZ);
+ record.lightBuffer.put(positionW);
+ record.lightBuffer.flip();
+ GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_POSITION, record.lightBuffer);
+
+ lr.position.set(positionX, positionY, positionZ, positionW);
+ if (!Camera.getCurrentCamera().isFrameDirty()) {
+ lr.modelViewMatrix.set(modelViewMatrix);
+ }
+ }
+ }
+
+ private static void setSpotDirection(final int index, final LightStateRecord record, final float directionX,
+ final float directionY, final float directionZ, final float value) {
+ // From OpenGL Docs:
+ // The light position is transformed by the contents of the current top
+ // of the ModelView matrix stack when you specify the light position
+ // with a call to glLightfv(GL_LIGHT_POSITION,...). If you later change
+ // the ModelView matrix, such as when the view changes for the next
+ // frame, the light position isn't automatically retransformed by the
+ // new contents of the ModelView matrix. If you want to update the
+ // light's position, you must again specify the light position with a
+ // call to glLightfv(GL_LIGHT_POSITION,...).
+ record.lightBuffer.clear();
+ record.lightBuffer.put(directionX);
+ record.lightBuffer.put(directionY);
+ record.lightBuffer.put(directionZ);
+ record.lightBuffer.put(value);
+ record.lightBuffer.flip();
+ GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_SPOT_DIRECTION, record.lightBuffer);
+ }
+
+ private static void setConstant(final int index, final float constant, final LightRecord lr, final boolean force) {
+ if (force || constant != lr.getConstant()) {
+ GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_CONSTANT_ATTENUATION, constant);
+ lr.setConstant(constant);
+ }
+ }
+
+ private static void setLinear(final int index, final float linear, final LightRecord lr, final boolean force) {
+ if (force || linear != lr.getLinear()) {
+ GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_LINEAR_ATTENUATION, linear);
+ lr.setLinear(linear);
+ }
+ }
+
+ private static void setQuadratic(final int index, final float quad, final LightRecord lr, final boolean force) {
+ if (force || quad != lr.getQuadratic()) {
+ GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_QUADRATIC_ATTENUATION, quad);
+ lr.setQuadratic(quad);
+ }
+ }
+
+ private static void setAttenuate(final boolean attenuate, final int index, final Light light,
+ final LightStateRecord record, final LightRecord lr) {
+ if (attenuate) {
+ setConstant(index, light.getConstant(), lr, !record.isValid());
+ setLinear(index, light.getLinear(), lr, !record.isValid());
+ setQuadratic(index, light.getQuadratic(), lr, !record.isValid());
+ } else {
+ setConstant(index, 1, lr, !record.isValid());
+ setLinear(index, 0, lr, !record.isValid());
+ setQuadratic(index, 0, lr, !record.isValid());
+ }
+ lr.setAttenuate(attenuate);
+ }
+
+ private static void setSpotExponent(final int index, final LightStateRecord record, final float exponent,
+ final LightRecord lr) {
+ if (!record.isValid() || lr.getSpotExponent() != exponent) {
+ GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_SPOT_EXPONENT, exponent);
+ lr.setSpotExponent(exponent);
+ }
+ }
+
+ private static void setSpotCutoff(final int index, final LightStateRecord record, final float cutoff,
+ final LightRecord lr) {
+ if (!record.isValid() || lr.getSpotCutoff() != cutoff) {
+ GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_SPOT_CUTOFF, cutoff);
+ lr.setSpotCutoff(cutoff);
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglMaterialStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglMaterialStateUtil.java
new file mode 100644
index 0000000..287624e
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglMaterialStateUtil.java
@@ -0,0 +1,199 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.MaterialState;
+import com.ardor3d.renderer.state.MaterialState.ColorMaterial;
+import com.ardor3d.renderer.state.MaterialState.MaterialFace;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.MaterialStateRecord;
+
+public abstract class LwjglMaterialStateUtil {
+
+ public static void apply(final MaterialState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final MaterialStateRecord record = (MaterialStateRecord) context.getStateRecord(StateType.Material);
+ context.setCurrentState(StateType.Material, state);
+
+ if (state.isEnabled()) {
+ // setup colormaterial, if changed.
+ applyColorMaterial(state.getColorMaterial(), state.getColorMaterialFace(), record);
+
+ // apply colors, if needed and not what is currently set.
+ applyColor(ColorMaterial.Ambient, state.getAmbient(), state.getBackAmbient(), record);
+ applyColor(ColorMaterial.Diffuse, state.getDiffuse(), state.getBackDiffuse(), record);
+ applyColor(ColorMaterial.Emissive, state.getEmissive(), state.getBackEmissive(), record);
+ applyColor(ColorMaterial.Specular, state.getSpecular(), state.getBackSpecular(), record);
+
+ // set our shine
+ applyShininess(state.getShininess(), state.getBackShininess(), record);
+ } else {
+ // apply defaults
+ applyColorMaterial(MaterialState.DEFAULT_COLOR_MATERIAL, MaterialState.DEFAULT_COLOR_MATERIAL_FACE, record);
+
+ applyColor(ColorMaterial.Ambient, MaterialState.DEFAULT_AMBIENT, MaterialState.DEFAULT_AMBIENT, record);
+ applyColor(ColorMaterial.Diffuse, MaterialState.DEFAULT_DIFFUSE, MaterialState.DEFAULT_DIFFUSE, record);
+ applyColor(ColorMaterial.Emissive, MaterialState.DEFAULT_EMISSIVE, MaterialState.DEFAULT_EMISSIVE, record);
+ applyColor(ColorMaterial.Specular, MaterialState.DEFAULT_SPECULAR, MaterialState.DEFAULT_SPECULAR, record);
+
+ applyShininess(MaterialState.DEFAULT_SHININESS, MaterialState.DEFAULT_SHININESS, record);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void applyColor(final ColorMaterial glMatColor, final ReadOnlyColorRGBA frontColor,
+ final ReadOnlyColorRGBA backColor, final MaterialStateRecord record) {
+ final int glMat = getGLColorMaterial(glMatColor);
+ if (frontColor.equals(backColor)) {
+ // consolidate to one call
+ if (!isVertexProvidedColor(MaterialFace.FrontAndBack, glMatColor, record)) {
+ if (!record.isValid() || !record.isSetColor(MaterialFace.FrontAndBack, glMatColor, frontColor, record)) {
+ record.tempColorBuff.clear();
+ record.tempColorBuff.put(frontColor.getRed()).put(frontColor.getGreen()).put(frontColor.getBlue())
+ .put(frontColor.getAlpha());
+ record.tempColorBuff.flip();
+ GL11.glMaterial(getGLMaterialFace(MaterialFace.FrontAndBack), glMat, record.tempColorBuff);
+ record.setColor(MaterialFace.FrontAndBack, glMatColor, frontColor);
+ }
+ }
+ } else {
+ if (!isVertexProvidedColor(MaterialFace.Front, glMatColor, record)) {
+ if (!record.isValid() || !record.isSetColor(MaterialFace.Front, glMatColor, frontColor, record)) {
+ record.tempColorBuff.clear();
+ record.tempColorBuff.put(frontColor.getRed()).put(frontColor.getGreen()).put(frontColor.getBlue())
+ .put(frontColor.getAlpha());
+ record.tempColorBuff.flip();
+ GL11.glMaterial(getGLMaterialFace(MaterialFace.Front), glMat, record.tempColorBuff);
+ record.setColor(MaterialFace.Front, glMatColor, frontColor);
+ }
+ }
+
+ if (!isVertexProvidedColor(MaterialFace.Back, glMatColor, record)) {
+ if (!record.isValid() || !record.isSetColor(MaterialFace.Back, glMatColor, backColor, record)) {
+ record.tempColorBuff.clear();
+ record.tempColorBuff.put(backColor.getRed()).put(backColor.getGreen()).put(backColor.getBlue())
+ .put(backColor.getAlpha());
+ record.tempColorBuff.flip();
+ GL11.glMaterial(getGLMaterialFace(MaterialFace.Back), glMat, record.tempColorBuff);
+ record.setColor(MaterialFace.Back, glMatColor, backColor);
+ }
+ }
+ }
+ }
+
+ private static boolean isVertexProvidedColor(final MaterialFace face, final ColorMaterial glMatColor,
+ final MaterialStateRecord record) {
+ if (face != record.colorMaterialFace) {
+ return false;
+ }
+ switch (glMatColor) {
+ case Ambient:
+ return record.colorMaterial == ColorMaterial.Ambient
+ || record.colorMaterial == ColorMaterial.AmbientAndDiffuse;
+ case Diffuse:
+ return record.colorMaterial == ColorMaterial.Diffuse
+ || record.colorMaterial == ColorMaterial.AmbientAndDiffuse;
+ case Specular:
+ return record.colorMaterial == ColorMaterial.Specular;
+ case Emissive:
+ return record.colorMaterial == ColorMaterial.Emissive;
+ }
+ return false;
+ }
+
+ private static void applyColorMaterial(final ColorMaterial colorMaterial, final MaterialFace face,
+ final MaterialStateRecord record) {
+ if (!record.isValid() || face != record.colorMaterialFace || colorMaterial != record.colorMaterial) {
+ if (colorMaterial == ColorMaterial.None) {
+ GL11.glDisable(GL11.GL_COLOR_MATERIAL);
+ } else {
+ final int glMat = getGLColorMaterial(colorMaterial);
+ final int glFace = getGLMaterialFace(face);
+
+ GL11.glColorMaterial(glFace, glMat);
+ GL11.glEnable(GL11.GL_COLOR_MATERIAL);
+ record.resetColorsForCM(face, colorMaterial);
+ }
+ record.colorMaterial = colorMaterial;
+ record.colorMaterialFace = face;
+ }
+ }
+
+ private static void applyShininess(final float frontShininess, final float backShininess,
+ final MaterialStateRecord record) {
+ if (frontShininess == backShininess) {
+ // consolidate to one call
+ if (!record.isValid() || frontShininess != record.frontShininess || record.backShininess != backShininess) {
+ GL11.glMaterialf(getGLMaterialFace(MaterialFace.FrontAndBack), GL11.GL_SHININESS, frontShininess);
+ record.backShininess = record.frontShininess = frontShininess;
+ }
+ } else {
+ if (!record.isValid() || frontShininess != record.frontShininess) {
+ GL11.glMaterialf(getGLMaterialFace(MaterialFace.Front), GL11.GL_SHININESS, frontShininess);
+ record.frontShininess = frontShininess;
+ }
+
+ if (!record.isValid() || backShininess != record.backShininess) {
+ GL11.glMaterialf(getGLMaterialFace(MaterialFace.Back), GL11.GL_SHININESS, backShininess);
+ record.backShininess = backShininess;
+ }
+ }
+ }
+
+ /**
+ * Converts the color material setting of this state to a GL constant.
+ *
+ * @return the GL constant
+ */
+ private static int getGLColorMaterial(final ColorMaterial material) {
+ switch (material) {
+ case None:
+ return GL11.GL_NONE;
+ case Ambient:
+ return GL11.GL_AMBIENT;
+ case Diffuse:
+ return GL11.GL_DIFFUSE;
+ case AmbientAndDiffuse:
+ return GL11.GL_AMBIENT_AND_DIFFUSE;
+ case Emissive:
+ return GL11.GL_EMISSION;
+ case Specular:
+ return GL11.GL_SPECULAR;
+ }
+ throw new IllegalArgumentException("invalid color material setting: " + material);
+ }
+
+ /**
+ * Converts the material face setting of this state to a GL constant.
+ *
+ * @return the GL constant
+ */
+ private static int getGLMaterialFace(final MaterialFace face) {
+ switch (face) {
+ case Front:
+ return GL11.GL_FRONT;
+ case Back:
+ return GL11.GL_BACK;
+ case FrontAndBack:
+ return GL11.GL_FRONT_AND_BACK;
+ }
+ throw new IllegalArgumentException("invalid material face setting: " + face);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglOffsetStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglOffsetStateUtil.java
new file mode 100644
index 0000000..2737373
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglOffsetStateUtil.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.lwjgl.LwjglRenderer;
+import com.ardor3d.renderer.state.OffsetState;
+import com.ardor3d.renderer.state.OffsetState.OffsetType;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.OffsetStateRecord;
+
+public abstract class LwjglOffsetStateUtil {
+
+ public static void apply(final LwjglRenderer renderer, final OffsetState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final OffsetStateRecord record = (OffsetStateRecord) context.getStateRecord(StateType.Offset);
+ context.setCurrentState(StateType.Offset, state);
+
+ if (state.isEnabled()) {
+ // enable any set offset types
+ setOffsetEnabled(OffsetType.Fill, state.isTypeEnabled(OffsetType.Fill), record);
+ setOffsetEnabled(OffsetType.Line, state.isTypeEnabled(OffsetType.Line), record);
+ setOffsetEnabled(OffsetType.Point, state.isTypeEnabled(OffsetType.Point), record);
+
+ // set factor and units.
+ setOffset(state.getFactor(), state.getUnits(), record);
+ } else {
+ // disable all offset types
+ setOffsetEnabled(OffsetType.Fill, false, record);
+ setOffsetEnabled(OffsetType.Line, false, record);
+ setOffsetEnabled(OffsetType.Point, false, record);
+
+ // set factor and units to default 0, 0.
+ setOffset(0, 0, record);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void setOffsetEnabled(final OffsetType type, final boolean typeEnabled,
+ final OffsetStateRecord record) {
+ final int glType = getGLType(type);
+ if (!record.isValid() || typeEnabled != record.enabledOffsets.contains(type)) {
+ if (typeEnabled) {
+ GL11.glEnable(glType);
+ } else {
+ GL11.glDisable(glType);
+ }
+ }
+ }
+
+ private static void setOffset(final float factor, final float units, final OffsetStateRecord record) {
+ if (!record.isValid() || record.factor != factor || record.units != units) {
+ GL11.glPolygonOffset(factor, units);
+ record.factor = factor;
+ record.units = units;
+ }
+ }
+
+ private static int getGLType(final OffsetType type) {
+ switch (type) {
+ case Fill:
+ return GL11.GL_POLYGON_OFFSET_FILL;
+ case Line:
+ return GL11.GL_POLYGON_OFFSET_LINE;
+ case Point:
+ return GL11.GL_POLYGON_OFFSET_POINT;
+ }
+ throw new IllegalArgumentException("invalid type: " + type);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShaderObjectsStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShaderObjectsStateUtil.java
new file mode 100644
index 0000000..1440cd1
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShaderObjectsStateUtil.java
@@ -0,0 +1,361 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBFragmentShader;
+import org.lwjgl.opengl.ARBGeometryShader4;
+import org.lwjgl.opengl.ARBShaderObjects;
+import org.lwjgl.opengl.ARBTessellationShader;
+import org.lwjgl.opengl.ARBVertexProgram;
+import org.lwjgl.opengl.ARBVertexShader;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL20;
+
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.lwjgl.LwjglRenderer;
+import com.ardor3d.renderer.state.GLSLShaderObjectsState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.ShaderObjectsStateRecord;
+import com.ardor3d.scene.state.lwjgl.shader.LwjglShaderUtil;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.shader.ShaderVariable;
+
+public abstract class LwjglShaderObjectsStateUtil {
+ private static final Logger logger = Logger.getLogger(LwjglShaderObjectsStateUtil.class.getName());
+
+ protected static void sendToGL(final GLSLShaderObjectsState state, final ContextCapabilities caps) {
+ if (state.getVertexShader() == null && state.getFragmentShader() == null) {
+ logger.warning("Could not find shader resources!" + "(both inputbuffers are null)");
+ state._needSendShader = false;
+ return;
+ }
+
+ if (state._programID == -1) {
+ state._programID = ARBShaderObjects.glCreateProgramObjectARB();
+ }
+
+ if (state.getVertexShader() != null) {
+ if (state._vertexShaderID != -1) {
+ removeVertShader(state);
+ }
+
+ state._vertexShaderID = ARBShaderObjects.glCreateShaderObjectARB(ARBVertexShader.GL_VERTEX_SHADER_ARB);
+
+ // Create the sources
+ ARBShaderObjects.glShaderSourceARB(state._vertexShaderID, state.getVertexShader());
+
+ // Compile the vertex shader
+ final IntBuffer compiled = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glCompileShaderARB(state._vertexShaderID);
+ ARBShaderObjects.glGetObjectParameterARB(state._vertexShaderID,
+ ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
+ checkProgramError(compiled, state._vertexShaderID, state._vertexShaderName);
+
+ // Attach the program
+ ARBShaderObjects.glAttachObjectARB(state._programID, state._vertexShaderID);
+ } else if (state._vertexShaderID != -1) {
+ removeVertShader(state);
+ state._vertexShaderID = -1;
+ }
+
+ if (state.getFragmentShader() != null) {
+ if (state._fragmentShaderID != -1) {
+ removeFragShader(state);
+ }
+
+ state._fragmentShaderID = ARBShaderObjects
+ .glCreateShaderObjectARB(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
+
+ // Create the sources
+ ARBShaderObjects.glShaderSourceARB(state._fragmentShaderID, state.getFragmentShader());
+
+ // Compile the fragment shader
+ final IntBuffer compiled = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glCompileShaderARB(state._fragmentShaderID);
+ ARBShaderObjects.glGetObjectParameterARB(state._fragmentShaderID,
+ ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
+ checkProgramError(compiled, state._fragmentShaderID, state._fragmentShaderName);
+
+ // Attach the program
+ ARBShaderObjects.glAttachObjectARB(state._programID, state._fragmentShaderID);
+ } else if (state._fragmentShaderID != -1) {
+ removeFragShader(state);
+ state._fragmentShaderID = -1;
+ }
+
+ if (caps.isGeometryShader4Supported()) {
+ if (state.getGeometryShader() != null) {
+ if (state._geometryShaderID != -1) {
+ removeGeomShader(state);
+ }
+
+ state._geometryShaderID = ARBShaderObjects
+ .glCreateShaderObjectARB(ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB);
+
+ // Create the sources
+ ARBShaderObjects.glShaderSourceARB(state._geometryShaderID, state.getGeometryShader());
+
+ // Compile the fragment shader
+ final IntBuffer compiled = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glCompileShaderARB(state._geometryShaderID);
+ ARBShaderObjects.glGetObjectParameterARB(state._geometryShaderID,
+ ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
+ checkProgramError(compiled, state._geometryShaderID, state._geometryShaderName);
+
+ // Attach the program
+ ARBShaderObjects.glAttachObjectARB(state._programID, state._geometryShaderID);
+ } else if (state._geometryShaderID != -1) {
+ removeGeomShader(state);
+ state._geometryShaderID = -1;
+ }
+ }
+
+ if (caps.isTessellationShadersSupported()) {
+ if (state.getTessellationControlShader() != null) {
+ if (state._tessellationControlShaderID != -1) {
+ removeTessControlShader(state);
+ }
+
+ state._tessellationControlShaderID = ARBShaderObjects
+ .glCreateShaderObjectARB(ARBTessellationShader.GL_TESS_CONTROL_SHADER);
+
+ // Create the sources
+ ARBShaderObjects.glShaderSourceARB(state._tessellationControlShaderID,
+ state.getTessellationControlShader());
+
+ // Compile the tessellation control shader
+ final IntBuffer compiled = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glCompileShaderARB(state._tessellationControlShaderID);
+ ARBShaderObjects.glGetObjectParameterARB(state._tessellationControlShaderID,
+ ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
+ checkProgramError(compiled, state._tessellationControlShaderID, state._tessellationControlShaderName);
+
+ // Attach the program
+ ARBShaderObjects.glAttachObjectARB(state._programID, state._tessellationControlShaderID);
+ } else if (state._tessellationControlShaderID != -1) {
+ removeTessControlShader(state);
+ state._tessellationControlShaderID = -1;
+ }
+
+ if (state.getTessellationEvaluationShader() != null) {
+ if (state._tessellationEvaluationShaderID != -1) {
+ removeTessEvalShader(state);
+ }
+
+ state._tessellationEvaluationShaderID = ARBShaderObjects
+ .glCreateShaderObjectARB(ARBTessellationShader.GL_TESS_CONTROL_SHADER);
+
+ // Create the sources
+ ARBShaderObjects.glShaderSourceARB(state._tessellationEvaluationShaderID,
+ state.getTessellationEvaluationShader());
+
+ // Compile the tessellation control shader
+ final IntBuffer compiled = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glCompileShaderARB(state._tessellationEvaluationShaderID);
+ ARBShaderObjects.glGetObjectParameterARB(state._tessellationEvaluationShaderID,
+ ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
+ checkProgramError(compiled, state._tessellationEvaluationShaderID,
+ state._tessellationEvaluationShaderName);
+
+ // Attach the program
+ ARBShaderObjects.glAttachObjectARB(state._programID, state._tessellationEvaluationShaderID);
+ } else if (state._tessellationEvaluationShaderID != -1) {
+ removeTessEvalShader(state);
+ state._tessellationEvaluationShaderID = -1;
+ }
+ }
+
+ ARBShaderObjects.glLinkProgramARB(state._programID);
+ checkLinkError(state._programID);
+ state.setNeedsRefresh(true);
+ state._needSendShader = false;
+ }
+
+ private static void checkLinkError(final int programId) {
+ final IntBuffer compiled = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glGetObjectParameterARB(programId, GL20.GL_LINK_STATUS, compiled);
+ if (compiled.get(0) == GL11.GL_FALSE) {
+ ARBShaderObjects.glGetObjectParameterARB(programId, GL20.GL_INFO_LOG_LENGTH, compiled);
+ final int length = compiled.get(0);
+ String out = null;
+ if (length > 0) {
+ final ByteBuffer infoLog = BufferUtils.createByteBuffer(length);
+
+ ARBShaderObjects.glGetInfoLogARB(programId, compiled, infoLog);
+
+ final byte[] infoBytes = new byte[length];
+ infoLog.get(infoBytes);
+ out = new String(infoBytes);
+ }
+
+ logger.severe(out);
+
+ throw new Ardor3dException("Error linking GLSL shader: " + out);
+ }
+ }
+
+ /** Removes the geometry shader */
+ private static void removeGeomShader(final GLSLShaderObjectsState state) {
+ if (state._geometryShaderID != -1) {
+ ARBShaderObjects.glDetachObjectARB(state._programID, state._geometryShaderID);
+ ARBShaderObjects.glDeleteObjectARB(state._geometryShaderID);
+ }
+ }
+
+ /** Removes the fragment shader */
+ private static void removeFragShader(final GLSLShaderObjectsState state) {
+ if (state._fragmentShaderID != -1) {
+ ARBShaderObjects.glDetachObjectARB(state._programID, state._fragmentShaderID);
+ ARBShaderObjects.glDeleteObjectARB(state._fragmentShaderID);
+ }
+ }
+
+ /**
+ * Removes the vertex shader
+ */
+ private static void removeVertShader(final GLSLShaderObjectsState state) {
+ if (state._vertexShaderID != -1) {
+ ARBShaderObjects.glDetachObjectARB(state._programID, state._vertexShaderID);
+ ARBShaderObjects.glDeleteObjectARB(state._vertexShaderID);
+ }
+ }
+
+ /** Removes the tessellation control shader */
+ private static void removeTessControlShader(final GLSLShaderObjectsState state) {
+ if (state._tessellationControlShaderID != -1) {
+ ARBShaderObjects.glDetachObjectARB(state._programID, state._tessellationControlShaderID);
+ ARBShaderObjects.glDeleteObjectARB(state._tessellationControlShaderID);
+ }
+ }
+
+ /** Removes the tessellation evaluation shader */
+ private static void removeTessEvalShader(final GLSLShaderObjectsState state) {
+ if (state._tessellationEvaluationShaderID != -1) {
+ ARBShaderObjects.glDetachObjectARB(state._programID, state._tessellationEvaluationShaderID);
+ ARBShaderObjects.glDeleteObjectARB(state._tessellationEvaluationShaderID);
+ }
+ }
+
+ /**
+ * Check for program errors. If an error is detected, program exits.
+ *
+ * @param compiled
+ * the compiler state for a given shader
+ * @param id
+ * shader's id
+ */
+ private static void checkProgramError(final IntBuffer compiled, final int id, final String shaderName) {
+ if (compiled.get(0) == GL11.GL_FALSE) {
+ final IntBuffer iVal = BufferUtils.createIntBuffer(1);
+ ARBShaderObjects.glGetObjectParameterARB(id, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
+ final int length = iVal.get(0);
+ String out = null;
+
+ if (length > 0) {
+ final ByteBuffer infoLog = BufferUtils.createByteBuffer(length);
+
+ ARBShaderObjects.glGetInfoLogARB(id, iVal, infoLog);
+
+ final byte[] infoBytes = new byte[length];
+ infoLog.get(infoBytes);
+ out = new String(infoBytes);
+ }
+
+ logger.severe(out);
+ final String nameString = shaderName.equals("") ? "" : " [ " + shaderName + " ]";
+ throw new Ardor3dException("Error compiling GLSL shader " + nameString + ": " + out);
+
+ }
+ }
+
+ public static void apply(final LwjglRenderer renderer, final GLSLShaderObjectsState state) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+
+ if (caps.isGLSLSupported()) {
+ // Ask for the current state record
+ final ShaderObjectsStateRecord record = (ShaderObjectsStateRecord) context
+ .getStateRecord(StateType.GLSLShader);
+ context.setCurrentState(StateType.GLSLShader, state);
+
+ if (state.isEnabled()) {
+ if (state._needSendShader) {
+ sendToGL(state, caps);
+ }
+
+ if (state._shaderDataLogic != null) {
+ state._shaderDataLogic.applyData(state, state._mesh, renderer);
+ }
+ }
+
+ if (!record.isValid() || record.getReference() != state || state.needsRefresh()) {
+ record.setReference(state);
+ if (state.isEnabled() && state._programID != -1) {
+ // clear any previously existing attributes
+ clearEnabledAttributes(record);
+
+ // set our current shader
+ LwjglShaderUtil.useShaderProgram(state._programID, record);
+
+ for (int i = state.getShaderAttributes().size(); --i >= 0;) {
+ final ShaderVariable shaderVariable = state.getShaderAttributes().get(i);
+ if (shaderVariable.needsRefresh) {
+ LwjglShaderUtil.updateAttributeLocation(shaderVariable, state._programID);
+ shaderVariable.needsRefresh = false;
+ }
+ LwjglShaderUtil.updateShaderAttribute(renderer, shaderVariable, state.isUseAttributeVBO());
+ }
+
+ for (int i = state.getShaderUniforms().size(); --i >= 0;) {
+ final ShaderVariable shaderVariable = state.getShaderUniforms().get(i);
+ if (shaderVariable.needsRefresh) {
+ LwjglShaderUtil.updateUniformLocation(shaderVariable, state._programID);
+ LwjglShaderUtil.updateShaderUniform(shaderVariable);
+ shaderVariable.needsRefresh = false;
+ }
+ }
+ } else {
+ LwjglShaderUtil.useShaderProgram(0, record);
+
+ clearEnabledAttributes(record);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+ }
+
+ private static void clearEnabledAttributes(final ShaderObjectsStateRecord record) {
+ // go through and disable any enabled attributes
+ if (!record.enabledAttributes.isEmpty()) {
+ for (int i = 0, maxI = record.enabledAttributes.size(); i < maxI; i++) {
+ final ShaderVariable var = record.enabledAttributes.get(i);
+ if (var.getSize() == 1) {
+ ARBVertexProgram.glDisableVertexAttribArrayARB(var.variableID);
+ } else {
+ for (int j = 0, maxJ = var.getSize(); j < maxJ; j++) {
+ ARBVertexProgram.glDisableVertexAttribArrayARB(var.variableID + j);
+ }
+ }
+ }
+ record.enabledAttributes.clear();
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShadingStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShadingStateUtil.java
new file mode 100644
index 0000000..a46aa17
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglShadingStateUtil.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.ShadingState;
+import com.ardor3d.renderer.state.ShadingState.ShadingMode;
+import com.ardor3d.renderer.state.record.ShadingStateRecord;
+
+public abstract class LwjglShadingStateUtil {
+
+ public static void apply(final ShadingState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ShadingStateRecord record = (ShadingStateRecord) context.getStateRecord(StateType.Shading);
+ context.setCurrentState(StateType.Shading, state);
+
+ // If not enabled, we'll use smooth
+ final int toApply = state.isEnabled() ? getGLShade(state.getShadingMode()) : GL11.GL_SMOOTH;
+ // only apply if we're different. Update record to reflect any changes.
+ if (!record.isValid() || toApply != record.lastShade) {
+ GL11.glShadeModel(toApply);
+ record.lastShade = toApply;
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static int getGLShade(final ShadingMode shadeMode) {
+ switch (shadeMode) {
+ case Flat:
+ return GL11.GL_FLAT;
+ case Smooth:
+ return GL11.GL_SMOOTH;
+ }
+ throw new IllegalStateException("unknown shade mode: " + shadeMode);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglStencilStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglStencilStateUtil.java
new file mode 100644
index 0000000..176fc8c
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglStencilStateUtil.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.EXTStencilTwoSide;
+import org.lwjgl.opengl.EXTStencilWrap;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.StencilState;
+import com.ardor3d.renderer.state.StencilState.StencilFunction;
+import com.ardor3d.renderer.state.StencilState.StencilOperation;
+import com.ardor3d.renderer.state.record.StencilStateRecord;
+
+public abstract class LwjglStencilStateUtil {
+
+ public static void apply(final StencilState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+ final StencilStateRecord record = (StencilStateRecord) context.getStateRecord(StateType.Stencil);
+ context.setCurrentState(StateType.Stencil, state);
+
+ setEnabled(state.isEnabled(), caps.isTwoSidedStencilSupported() ? state.isUseTwoSided() : false, record, caps);
+ if (state.isEnabled()) {
+ if (state.isUseTwoSided() && caps.isTwoSidedStencilSupported()) {
+ EXTStencilTwoSide.glActiveStencilFaceEXT(GL11.GL_BACK);
+ applyMask(state.getStencilWriteMaskBack(), record, 2);
+ applyFunc(getGLStencilFunction(state.getStencilFunctionBack()), state.getStencilReferenceBack(),
+ state.getStencilFuncMaskBack(), record, 2);
+ applyOp(getGLStencilOp(state.getStencilOpFailBack(), caps),
+ getGLStencilOp(state.getStencilOpZFailBack(), caps),
+ getGLStencilOp(state.getStencilOpZPassBack(), caps), record, 2);
+
+ EXTStencilTwoSide.glActiveStencilFaceEXT(GL11.GL_FRONT);
+ applyMask(state.getStencilWriteMaskFront(), record, 1);
+ applyFunc(getGLStencilFunction(state.getStencilFunctionFront()), state.getStencilReferenceFront(),
+ state.getStencilFuncMaskFront(), record, 1);
+ applyOp(getGLStencilOp(state.getStencilOpFailFront(), caps),
+ getGLStencilOp(state.getStencilOpZFailFront(), caps),
+ getGLStencilOp(state.getStencilOpZPassFront(), caps), record, 1);
+ } else {
+ applyMask(state.getStencilWriteMaskFront(), record, 0);
+ applyFunc(getGLStencilFunction(state.getStencilFunctionFront()), state.getStencilReferenceFront(),
+ state.getStencilFuncMaskFront(), record, 0);
+ applyOp(getGLStencilOp(state.getStencilOpFailFront(), caps),
+ getGLStencilOp(state.getStencilOpZFailFront(), caps),
+ getGLStencilOp(state.getStencilOpZPassFront(), caps), record, 0);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static int getGLStencilFunction(final StencilFunction function) {
+ switch (function) {
+ case Always:
+ return GL11.GL_ALWAYS;
+ case Never:
+ return GL11.GL_NEVER;
+ case EqualTo:
+ return GL11.GL_EQUAL;
+ case NotEqualTo:
+ return GL11.GL_NOTEQUAL;
+ case GreaterThan:
+ return GL11.GL_GREATER;
+ case GreaterThanOrEqualTo:
+ return GL11.GL_GEQUAL;
+ case LessThan:
+ return GL11.GL_LESS;
+ case LessThanOrEqualTo:
+ return GL11.GL_LEQUAL;
+ }
+ throw new IllegalArgumentException("unknown function: " + function);
+ }
+
+ private static int getGLStencilOp(final StencilOperation operation, final ContextCapabilities caps) {
+ switch (operation) {
+ case Keep:
+ return GL11.GL_KEEP;
+ case DecrementWrap:
+ if (caps.isStencilWrapSupported()) {
+ return EXTStencilWrap.GL_DECR_WRAP_EXT;
+ }
+ // FALLS THROUGH
+ case Decrement:
+ return GL11.GL_DECR;
+ case IncrementWrap:
+ if (caps.isStencilWrapSupported()) {
+ return EXTStencilWrap.GL_INCR_WRAP_EXT;
+ }
+ // FALLS THROUGH
+ case Increment:
+ return GL11.GL_INCR;
+ case Invert:
+ return GL11.GL_INVERT;
+ case Replace:
+ return GL11.GL_REPLACE;
+ case Zero:
+ return GL11.GL_ZERO;
+ }
+ throw new IllegalArgumentException("unknown operation: " + operation);
+ }
+
+ private static void setEnabled(final boolean enable, final boolean twoSided, final StencilStateRecord record,
+ final ContextCapabilities caps) {
+ if (record.isValid()) {
+ if (enable && !record.enabled) {
+ GL11.glEnable(GL11.GL_STENCIL_TEST);
+ } else if (!enable && record.enabled) {
+ GL11.glDisable(GL11.GL_STENCIL_TEST);
+ }
+ } else {
+ if (enable) {
+ GL11.glEnable(GL11.GL_STENCIL_TEST);
+ } else {
+ GL11.glDisable(GL11.GL_STENCIL_TEST);
+ }
+ }
+
+ setTwoSidedEnabled(enable ? twoSided : false, record, caps);
+ record.enabled = enable;
+ }
+
+ private static void setTwoSidedEnabled(final boolean enable, final StencilStateRecord record,
+ final ContextCapabilities caps) {
+ if (caps.isTwoSidedStencilSupported()) {
+ if (record.isValid()) {
+ if (enable && !record.useTwoSided) {
+ GL11.glEnable(EXTStencilTwoSide.GL_STENCIL_TEST_TWO_SIDE_EXT);
+ } else if (!enable && record.useTwoSided) {
+ GL11.glDisable(EXTStencilTwoSide.GL_STENCIL_TEST_TWO_SIDE_EXT);
+ }
+ } else {
+ if (enable) {
+ GL11.glEnable(EXTStencilTwoSide.GL_STENCIL_TEST_TWO_SIDE_EXT);
+ } else {
+ GL11.glDisable(EXTStencilTwoSide.GL_STENCIL_TEST_TWO_SIDE_EXT);
+ }
+ }
+ }
+ record.useTwoSided = enable;
+ }
+
+ private static void applyMask(final int writeMask, final StencilStateRecord record, final int face) {
+ // if (!record.isValid() || writeMask != record.writeMask[face]) {
+ GL11.glStencilMask(writeMask);
+ // record.writeMask[face] = writeMask;
+ // }
+ }
+
+ private static void applyFunc(final int glfunc, final int stencilRef, final int funcMask,
+ final StencilStateRecord record, final int face) {
+ // if (!record.isValid() || glfunc != record.func[face] || stencilRef != record.ref[face]
+ // || funcMask != record.funcMask[face]) {
+ GL11.glStencilFunc(glfunc, stencilRef, funcMask);
+ // record.func[face] = glfunc;
+ // record.ref[face] = stencilRef;
+ // record.funcMask[face] = funcMask;
+ // }
+ }
+
+ private static void applyOp(final int fail, final int zfail, final int zpass, final StencilStateRecord record,
+ final int face) {
+ // if (!record.isValid() || fail != record.fail[face] || zfail != record.zfail[face]
+ // || zpass != record.zpass[face]) {
+ GL11.glStencilOp(fail, zfail, zpass);
+ // record.fail[face] = fail;
+ // record.zfail[face] = zfail;
+ // record.zpass[face] = zpass;
+ // }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglTextureStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglTextureStateUtil.java
new file mode 100644
index 0000000..de21789
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglTextureStateUtil.java
@@ -0,0 +1,1686 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.Collection;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBDepthTexture;
+import org.lwjgl.opengl.ARBMultitexture;
+import org.lwjgl.opengl.ARBShadow;
+import org.lwjgl.opengl.ARBTextureBorderClamp;
+import org.lwjgl.opengl.ARBTextureCompression;
+import org.lwjgl.opengl.ARBTextureCubeMap;
+import org.lwjgl.opengl.ARBTextureEnvCombine;
+import org.lwjgl.opengl.ARBTextureMirroredRepeat;
+import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
+import org.lwjgl.opengl.EXTTextureLODBias;
+import org.lwjgl.opengl.EXTTextureMirrorClamp;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.SGISGenerateMipmap;
+import org.lwjgl.opengl.Util;
+import org.lwjgl.util.glu.GLU;
+import org.lwjgl.util.glu.MipMap;
+
+import com.ardor3d.image.Image;
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture.ApplyMode;
+import com.ardor3d.image.Texture.CombinerFunctionAlpha;
+import com.ardor3d.image.Texture.CombinerFunctionRGB;
+import com.ardor3d.image.Texture.CombinerOperandAlpha;
+import com.ardor3d.image.Texture.CombinerOperandRGB;
+import com.ardor3d.image.Texture.CombinerSource;
+import com.ardor3d.image.Texture.Type;
+import com.ardor3d.image.Texture.WrapAxis;
+import com.ardor3d.image.Texture.WrapMode;
+import com.ardor3d.image.Texture1D;
+import com.ardor3d.image.Texture2D;
+import com.ardor3d.image.Texture3D;
+import com.ardor3d.image.TextureCubeMap;
+import com.ardor3d.image.util.ImageUtils;
+import com.ardor3d.math.MathUtils;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.renderer.state.record.RendererRecord;
+import com.ardor3d.renderer.state.record.TextureRecord;
+import com.ardor3d.renderer.state.record.TextureStateRecord;
+import com.ardor3d.renderer.state.record.TextureUnitRecord;
+import com.ardor3d.scene.state.lwjgl.util.LwjglRendererUtil;
+import com.ardor3d.scene.state.lwjgl.util.LwjglTextureUtil;
+import com.ardor3d.util.Constants;
+import com.ardor3d.util.TextureManager;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.stat.StatCollector;
+import com.ardor3d.util.stat.StatType;
+
+public abstract class LwjglTextureStateUtil {
+ private static final Logger logger = Logger.getLogger(LwjglTextureStateUtil.class.getName());
+
+ public static void load(final Texture texture, final int unit) {
+ if (texture == null) {
+ return;
+ }
+
+ final RenderContext context = ContextManager.getCurrentContext();
+ if (context == null) {
+ logger.warning("RenderContext is null for texture: " + texture);
+ return;
+ }
+
+ final ContextCapabilities caps = context.getCapabilities();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture);
+
+ // Check we are in the right unit
+ if (record != null) {
+ checkAndSetUnit(unit, record, caps);
+ }
+
+ // Create the texture...
+ // First, look for a texture in the cache just like ours
+ final Texture cached = TextureManager.findCachedTexture(texture.getTextureKey());
+
+ if (cached == null) {
+ TextureManager.addToCache(texture);
+ } else {
+ final int textureId = cached.getTextureIdForContext(context.getGlContextRep());
+ if (textureId != 0) {
+ doTextureBind(cached, unit, false);
+ return;
+ }
+ }
+
+ // Create a new texture id for this texture
+ final IntBuffer id = BufferUtils.createIntBuffer(1);
+ id.clear();
+ GL11.glGenTextures(id);
+ final int textureId = id.get(0);
+
+ // store the new id by our current gl context.
+ texture.setTextureIdForContext(context.getGlContextRep(), textureId);
+
+ update(texture, unit);
+ }
+
+ /**
+ * bind texture and upload image data to card
+ */
+ public static void update(final Texture texture, final int unit) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+
+ texture.getTextureKey().setClean(context.getGlContextRep());
+
+ // our texture type:
+ final Texture.Type type = texture.getType();
+
+ // bind our texture id to this unit.
+ doTextureBind(texture, unit, false);
+
+ // pass image data to OpenGL
+ final Image image = texture.getImage();
+ final boolean hasBorder = texture.hasBorder();
+ if (image == null) {
+ logger.warning("Image data for texture is null.");
+ }
+
+ // set alignment to support images with width % 4 != 0, as images are
+ // not aligned
+ GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
+
+ // Get texture image data. Not all textures have image data.
+ // For example, ApplyMode.Combine modes can use primary colors,
+ // texture output, and constants to modify fragments via the
+ // texture units.
+ if (image != null) {
+ final int maxSize = caps.getMaxTextureSize();
+ final int actualWidth = image.getWidth();
+ final int actualHeight = image.getHeight();
+
+ final boolean needsPowerOfTwo = !caps.isNonPowerOfTwoTextureSupported()
+ && (!MathUtils.isPowerOfTwo(image.getWidth()) || !MathUtils.isPowerOfTwo(image.getHeight()));
+ if (actualWidth > maxSize || actualHeight > maxSize || needsPowerOfTwo) {
+ if (needsPowerOfTwo) {
+ logger.warning("(card unsupported) Attempted to apply texture with size that is not power of 2: "
+ + image.getWidth() + " x " + image.getHeight());
+ }
+ if (actualWidth > maxSize || actualHeight > maxSize) {
+ logger.warning("(card unsupported) Attempted to apply texture with size bigger than max texture size ["
+ + maxSize + "]: " + image.getWidth() + " x " + image.getHeight());
+ }
+
+ int w = actualWidth;
+ if (needsPowerOfTwo) {
+ w = MathUtils.nearestPowerOfTwo(actualWidth);
+ }
+ if (w > maxSize) {
+ w = maxSize;
+ }
+
+ int h = actualHeight;
+ if (needsPowerOfTwo) {
+ h = MathUtils.nearestPowerOfTwo(actualHeight);
+ }
+ if (h > maxSize) {
+ h = maxSize;
+ }
+ logger.warning("Rescaling image to " + w + " x " + h + " !!!");
+
+ // must rescale image to get "top" mipmap texture image
+ final int pixFormat = LwjglTextureUtil.getGLPixelFormat(image.getDataFormat());
+ final int pixDataType = LwjglTextureUtil.getGLPixelDataType(image.getDataType());
+ final int bpp = ImageUtils.getPixelByteSize(image.getDataFormat(), image.getDataType());
+ final ByteBuffer scaledImage = BufferUtils.createByteBuffer((w + 4) * h * bpp);
+ final int error = MipMap.gluScaleImage(pixFormat, actualWidth, actualHeight, pixDataType,
+ image.getData(0), w, h, pixDataType, scaledImage);
+ if (error != 0) {
+ Util.checkGLError();
+ }
+
+ image.setWidth(w);
+ image.setHeight(h);
+ image.setData(scaledImage);
+ }
+
+ if (!texture.getMinificationFilter().usesMipMapLevels() && !texture.getTextureStoreFormat().isCompressed()) {
+
+ // Load textures which do not need mipmap auto-generating and
+ // which aren't using compressed images.
+
+ switch (texture.getType()) {
+ case TwoDimensional:
+ // ensure the buffer is ready for reading
+ image.getData(0).rewind();
+ // send top level to card
+ GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getHeight(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), image.getData(0));
+ break;
+ case OneDimensional:
+ // ensure the buffer is ready for reading
+ image.getData(0).rewind();
+ // send top level to card
+ GL11.glTexImage1D(GL11.GL_TEXTURE_1D, 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), image.getData(0));
+ break;
+ case ThreeDimensional:
+ if (caps.isTexture3DSupported()) {
+ // concat data into single buffer:
+ int dSize = 0;
+ int count = 0;
+ ByteBuffer data = null;
+ for (int x = 0; x < image.getData().size(); x++) {
+ if (image.getData(x) != null) {
+ data = image.getData(x);
+ dSize += data.limit();
+ count++;
+ }
+ }
+ // reuse buffer if we can.
+ if (count != 1) {
+ data = BufferUtils.createByteBuffer(dSize);
+ for (int x = 0; x < image.getData().size(); x++) {
+ if (image.getData(x) != null) {
+ data.put(image.getData(x));
+ }
+ }
+ // ensure the buffer is ready for reading
+ data.flip();
+ }
+ // send top level to card
+ GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getHeight(), image.getDepth(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), data);
+ } else {
+ logger.warning("This card does not support Texture3D.");
+ }
+ break;
+ case CubeMap:
+ // NOTE: Cubemaps MUST be square, so height is ignored
+ // on purpose.
+ if (caps.isTextureCubeMapSupported()) {
+ for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) {
+ // ensure the buffer is ready for reading
+ image.getData(face.ordinal()).rewind();
+ // send top level to card
+ GL11.glTexImage2D(getGLCubeMapFace(face), 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getWidth(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()),
+ image.getData(face.ordinal()));
+ }
+ } else {
+ logger.warning("This card does not support Cubemaps.");
+ }
+ break;
+ }
+ } else if (texture.getMinificationFilter().usesMipMapLevels() && !image.hasMipmaps()
+ && !texture.getTextureStoreFormat().isCompressed()) {
+
+ // For textures which need mipmaps auto-generating and which
+ // aren't using compressed images, generate the mipmaps.
+ // A new mipmap builder may be needed to build mipmaps for
+ // compressed textures.
+
+ if (caps.isAutomaticMipmapsSupported()) {
+ // Flag the card to generate mipmaps
+ GL11.glTexParameteri(getGLType(type), SGISGenerateMipmap.GL_GENERATE_MIPMAP_SGIS, GL11.GL_TRUE);
+ }
+
+ switch (type) {
+ case TwoDimensional:
+ // ensure the buffer is ready for reading
+ image.getData(0).rewind();
+ if (caps.isAutomaticMipmapsSupported()) {
+ // send top level to card
+ GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getHeight(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), image.getData(0));
+ } else {
+ // send to card
+ GLU.gluBuild2DMipmaps(GL11.GL_TEXTURE_2D,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getHeight(),
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), image.getData(0));
+ }
+ break;
+ case OneDimensional:
+ // ensure the buffer is ready for reading
+ image.getData(0).rewind();
+ if (caps.isAutomaticMipmapsSupported()) {
+ // send top level to card
+ GL11.glTexImage1D(GL11.GL_TEXTURE_1D, 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), image.getData(0));
+ } else {
+ // Note: LWJGL's GLU class does not support
+ // gluBuild1DMipmaps.
+ logger.warning("non-fbo 1d mipmap generation is not currently supported. Use DDS or a non-mipmap minification filter.");
+ return;
+ }
+ break;
+ case ThreeDimensional:
+ if (caps.isTexture3DSupported()) {
+ if (caps.isAutomaticMipmapsSupported()) {
+ // concat data into single buffer:
+ int dSize = 0;
+ int count = 0;
+ ByteBuffer data = null;
+ for (int x = 0; x < image.getData().size(); x++) {
+ if (image.getData(x) != null) {
+ data = image.getData(x);
+ dSize += data.limit();
+ count++;
+ }
+ }
+ // reuse buffer if we can.
+ if (count != 1) {
+ data = BufferUtils.createByteBuffer(dSize);
+ for (int x = 0; x < image.getData().size(); x++) {
+ if (image.getData(x) != null) {
+ data.put(image.getData(x));
+ }
+ }
+ // ensure the buffer is ready for reading
+ data.flip();
+ }
+ // send top level to card
+ GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getHeight(), image.getDepth(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), data);
+ } else {
+ // Note: LWJGL's GLU class does not support
+ // gluBuild3DMipmaps.
+ logger.warning("non-fbo 3d mipmap generation is not currently supported. Use DDS or a non-mipmap minification filter.");
+ return;
+ }
+ } else {
+ logger.warning("This card does not support Texture3D.");
+ return;
+ }
+ break;
+ case CubeMap:
+ // NOTE: Cubemaps MUST be square, so height is ignored
+ // on purpose.
+ if (caps.isTextureCubeMapSupported()) {
+ if (caps.isAutomaticMipmapsSupported()) {
+ for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) {
+ // ensure the buffer is ready for reading
+ image.getData(face.ordinal()).rewind();
+ // send top level to card
+ GL11.glTexImage2D(getGLCubeMapFace(face), 0,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getWidth(), hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()),
+ image.getData(face.ordinal()));
+ }
+ } else {
+ for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) {
+ // ensure the buffer is ready for reading
+ image.getData(face.ordinal()).rewind();
+ // send to card
+ GLU.gluBuild2DMipmaps(getGLCubeMapFace(face),
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ image.getWidth(), image.getWidth(),
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()),
+ image.getData(face.ordinal()));
+ }
+ }
+ } else {
+ logger.warning("This card does not support Cubemaps.");
+ return;
+ }
+ break;
+ }
+
+ if (texture.getTextureMaxLevel() >= 0) {
+ GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, texture.getTextureMaxLevel());
+ }
+ } else {
+ // Here we handle textures that are either compressed or have predefined mipmaps.
+ // Get mipmap data sizes and amount of mipmaps to send to opengl. Then loop through all mipmaps and send
+ // them.
+ int[] mipSizes = image.getMipMapByteSizes();
+ ByteBuffer data = null;
+
+ if (type == Type.CubeMap) {
+ if (caps.isTextureCubeMapSupported()) {
+ for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) {
+ data = image.getData(face.ordinal());
+ int pos = 0;
+ int max = 1;
+
+ if (mipSizes == null) {
+ mipSizes = new int[] { data.capacity() };
+ } else if (texture.getMinificationFilter().usesMipMapLevels()) {
+ max = mipSizes.length;
+ }
+
+ // set max mip level
+ GL11.glTexParameteri(getGLCubeMapFace(face), GL12.GL_TEXTURE_MAX_LEVEL, max - 1);
+
+ for (int m = 0; m < max; m++) {
+ final int width = Math.max(1, image.getWidth() >> m);
+ final int height = Math.max(1, image.getHeight() >> m);
+
+ data.position(pos);
+ data.limit(pos + mipSizes[m]);
+
+ if (texture.getTextureStoreFormat().isCompressed()) {
+ ARBTextureCompression.glCompressedTexImage2DARB(getGLCubeMapFace(face), m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, height, hasBorder ? 1 : 0, data);
+ } else {
+ GL11.glTexImage2D(getGLCubeMapFace(face), m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, height, hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), data);
+ }
+ pos += mipSizes[m];
+ }
+ }
+ } else {
+ logger.warning("This card does not support CubeMaps.");
+ return;
+ }
+ } else {
+ data = image.getData(0);
+ int pos = 0;
+ int max = 1;
+
+ if (mipSizes == null) {
+ mipSizes = new int[] { data.capacity() };
+ } else if (texture.getMinificationFilter().usesMipMapLevels()) {
+ max = mipSizes.length;
+ }
+
+ // Set max mip level
+ switch (type) {
+ case TwoDimensional:
+ GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, max - 1);
+ break;
+ case ThreeDimensional:
+ GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_MAX_LEVEL, max - 1);
+ break;
+ case OneDimensional:
+ GL11.glTexParameteri(GL11.GL_TEXTURE_1D, GL12.GL_TEXTURE_MAX_LEVEL, max - 1);
+ break;
+ }
+
+ if (type == Type.ThreeDimensional) {
+ if (caps.isTexture3DSupported()) {
+ // concat data into single buffer:
+ int dSize = 0;
+ int count = 0;
+ for (int x = 0; x < image.getData().size(); x++) {
+ if (image.getData(x) != null) {
+ data = image.getData(x);
+ dSize += data.limit();
+ count++;
+ }
+ }
+ // reuse buffer if we can.
+ if (count != 1) {
+ data = BufferUtils.createByteBuffer(dSize);
+ for (int x = 0; x < image.getData().size(); x++) {
+ if (image.getData(x) != null) {
+ data.put(image.getData(x));
+ }
+ }
+ // ensure the buffer is ready for reading
+ data.flip();
+ }
+ } else {
+ logger.warning("This card does not support Texture3D.");
+ return;
+ }
+ }
+
+ for (int m = 0; m < max; m++) {
+ final int width = Math.max(1, image.getWidth() >> m);
+ final int height = Math.max(1, image.getHeight() >> m);
+
+ data.position(pos);
+ data.limit(pos + mipSizes[m]);
+
+ switch (type) {
+ case TwoDimensional:
+ if (texture.getTextureStoreFormat().isCompressed()) {
+ ARBTextureCompression.glCompressedTexImage2DARB(GL11.GL_TEXTURE_2D, m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, height, hasBorder ? 1 : 0, data);
+ } else {
+ GL11.glTexImage2D(GL11.GL_TEXTURE_2D, m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, height, hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), data);
+ }
+ break;
+ case OneDimensional:
+ if (texture.getTextureStoreFormat().isCompressed()) {
+ ARBTextureCompression.glCompressedTexImage1DARB(GL11.GL_TEXTURE_1D, m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, hasBorder ? 1 : 0, data);
+ } else {
+ GL11.glTexImage1D(GL11.GL_TEXTURE_1D, m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), data);
+ }
+ break;
+ case ThreeDimensional:
+ final int depth = Math.max(1, image.getDepth() >> m);
+ // already checked for support above...
+ if (texture.getTextureStoreFormat().isCompressed()) {
+ ARBTextureCompression.glCompressedTexImage3DARB(GL12.GL_TEXTURE_3D, m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, height, depth, hasBorder ? 1 : 0, data);
+ } else {
+ GL12.glTexImage3D(GL12.GL_TEXTURE_3D, m,
+ LwjglTextureUtil.getGLInternalFormat(texture.getTextureStoreFormat()),
+ width, height, depth, hasBorder ? 1 : 0,
+ LwjglTextureUtil.getGLPixelFormat(image.getDataFormat()),
+ LwjglTextureUtil.getGLPixelDataType(image.getDataType()), data);
+ }
+ break;
+ }
+ pos += mipSizes[m];
+ }
+ }
+ if (data != null) {
+ data.clear();
+ }
+ }
+ }
+ }
+
+ public static void apply(final TextureState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture);
+ context.setCurrentState(StateType.Texture, state);
+
+ if (state.isEnabled()) {
+
+ Texture texture;
+ Texture.Type type;
+ TextureUnitRecord unitRecord;
+ TextureRecord texRecord;
+
+ final int glHint = LwjglTextureUtil.getPerspHint(state.getCorrectionType());
+ if (!record.isValid() || record.hint != glHint) {
+ // set up correction mode
+ GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, glHint);
+ record.hint = glHint;
+ }
+
+ // loop through all available texture units...
+ for (int i = 0; i < caps.getNumberOfTotalTextureUnits(); i++) {
+ unitRecord = record.units[i];
+
+ // grab a texture for this unit, if available
+ texture = state.getTexture(i);
+
+ // pull our texture id for this texture, for this context.
+ int textureId = texture != null ? texture.getTextureIdForContext(context.getGlContextRep()) : 0;
+
+ // check for invalid textures - ones that have no opengl id and
+ // no image data
+ if (texture != null && textureId == 0 && texture.getImage() == null) {
+ texture = null;
+ }
+
+ // null textures above fixed limit do not need to be disabled
+ // since they are not really part of the pipeline.
+ if (texture == null) {
+ if (i >= caps.getNumberOfFixedTextureUnits()) {
+ continue;
+ } else {
+ // a null texture indicates no texturing at this unit
+ // Disable texturing on this unit if enabled.
+ disableTexturing(unitRecord, record, i, caps);
+
+ if (i < state._keyCache.length) {
+ state._keyCache[i] = null;
+ }
+
+ // next texture!
+ continue;
+ }
+ }
+
+ type = texture.getType();
+
+ // disable other texturing types for this unit, if enabled.
+ disableTexturing(unitRecord, record, i, type, caps);
+
+ // Time to bind the texture, so see if we need to load in image
+ // data for this texture.
+ if (textureId == 0) {
+ // texture not yet loaded.
+ // this will load and bind and set the records...
+ load(texture, i);
+ textureId = texture.getTextureIdForContext(context.getGlContextRep());
+ if (textureId == 0) {
+ continue;
+ }
+ } else if (texture.isDirty(context.getGlContextRep())) {
+ update(texture, i);
+ textureId = texture.getTextureIdForContext(context.getGlContextRep());
+ if (textureId == 0) {
+ continue;
+ }
+ } else {
+ // texture already exists in OpenGL, just bind it if needed
+ if (!unitRecord.isValid() || unitRecord.boundTexture != textureId) {
+ checkAndSetUnit(i, record, caps);
+ GL11.glBindTexture(getGLType(type), textureId);
+ if (Constants.stats) {
+ StatCollector.addStat(StatType.STAT_TEXTURE_BINDS, 1);
+ }
+ unitRecord.boundTexture = textureId;
+ }
+ }
+
+ // Use the Java Integer object for the getTextureRecord call to avoid
+ // boxing/unboxing ints for map lookups.
+ final Integer textureIdInteger = texture.getTextureIdForContextAsInteger(context.getGlContextRep());
+
+ // Grab our record for this texture
+ texRecord = record.getTextureRecord(textureIdInteger, texture.getType());
+
+ // Set the keyCache value for this unit of this texture state
+ // This is done so during state comparison we don't have to
+ // spend a lot of time pulling out classes and finding field
+ // data.
+ state._keyCache[i] = texture.getTextureKey();
+
+ // Some texture things only apply to fixed function pipeline
+ if (i < caps.getNumberOfFixedTextureUnits()) {
+
+ // Enable 2D texturing on this unit if not enabled.
+ if (!unitRecord.isValid() || !unitRecord.enabled[type.ordinal()]) {
+ checkAndSetUnit(i, record, caps);
+ GL11.glEnable(getGLType(type));
+ unitRecord.enabled[type.ordinal()] = true;
+ }
+
+ // Set our blend color, if needed.
+ applyBlendColor(texture, unitRecord, i, record, caps);
+
+ // Set the texture environment mode if this unit isn't
+ // already set properly
+ applyEnvMode(texture.getApply(), unitRecord, i, record, caps);
+
+ // If our mode is combine, and we support multitexturing
+ // apply combine settings.
+ if (texture.getApply() == ApplyMode.Combine && caps.isMultitextureSupported()
+ && caps.isEnvCombineSupported()) {
+ applyCombineFactors(texture, unitRecord, i, record, caps);
+ }
+ }
+
+ // Other items only apply to textures below the frag unit limit
+ if (i < caps.getNumberOfFragmentTextureUnits()) {
+
+ // texture specific params
+ applyFilter(texture, texRecord, i, record, caps);
+ applyWrap(texture, texRecord, i, record, caps);
+ applyShadow(texture, texRecord, i, record, caps);
+
+ // Set our border color, if needed.
+ applyBorderColor(texture, texRecord, i, record);
+
+ // all states have now been applied for a tex record, so we
+ // can safely make it valid
+ if (!texRecord.isValid()) {
+ texRecord.validate();
+ }
+
+ }
+
+ // Other items only apply to textures below the frag tex coord
+ // unit limit
+ if (i < caps.getNumberOfFragmentTexCoordUnits()) {
+
+ // Now time to play with texture matrices
+ // Determine which transforms to do.
+ applyTextureTransforms(texture, i, record, caps);
+
+ // Now let's look at automatic texture coordinate
+ // generation.
+ applyTexCoordGeneration(texture, unitRecord, i, record, caps);
+
+ // Set our texture lod bias, if needed.
+ applyLodBias(texture, unitRecord, i, record, caps);
+ }
+
+ }
+
+ } else {
+ // turn off texturing
+ TextureUnitRecord unitRecord;
+
+ if (caps.isMultitextureSupported()) {
+ for (int i = 0; i < caps.getNumberOfFixedTextureUnits(); i++) {
+ unitRecord = record.units[i];
+ disableTexturing(unitRecord, record, i, caps);
+ }
+ } else {
+ unitRecord = record.units[0];
+ disableTexturing(unitRecord, record, 0, caps);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void disableTexturing(final TextureUnitRecord unitRecord, final TextureStateRecord record,
+ final int unit, final Type exceptedType, final ContextCapabilities caps) {
+ if (exceptedType != Type.TwoDimensional) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.TwoDimensional.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(GL11.GL_TEXTURE_2D);
+ unitRecord.enabled[Type.TwoDimensional.ordinal()] = false;
+ }
+ }
+
+ if (exceptedType != Type.OneDimensional) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.OneDimensional.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(GL11.GL_TEXTURE_1D);
+ unitRecord.enabled[Type.OneDimensional.ordinal()] = false;
+ }
+ }
+
+ if (caps.isTexture3DSupported() && exceptedType != Type.ThreeDimensional) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.ThreeDimensional.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(GL12.GL_TEXTURE_3D);
+ unitRecord.enabled[Type.ThreeDimensional.ordinal()] = false;
+ }
+ }
+
+ if (caps.isTextureCubeMapSupported() && exceptedType != Type.CubeMap) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.CubeMap.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_ARB);
+ unitRecord.enabled[Type.CubeMap.ordinal()] = false;
+ }
+ }
+
+ }
+
+ private static void disableTexturing(final TextureUnitRecord unitRecord, final TextureStateRecord record,
+ final int unit, final ContextCapabilities caps) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.TwoDimensional.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(GL11.GL_TEXTURE_2D);
+ unitRecord.enabled[Type.TwoDimensional.ordinal()] = false;
+ }
+
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.OneDimensional.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(GL11.GL_TEXTURE_1D);
+ unitRecord.enabled[Type.OneDimensional.ordinal()] = false;
+ }
+
+ if (caps.isTexture3DSupported()) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.ThreeDimensional.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(GL12.GL_TEXTURE_3D);
+ unitRecord.enabled[Type.ThreeDimensional.ordinal()] = false;
+ }
+ }
+
+ if (caps.isTextureCubeMapSupported()) {
+ if (!unitRecord.isValid() || unitRecord.enabled[Type.CubeMap.ordinal()]) {
+ // Check we are in the right unit
+ checkAndSetUnit(unit, record, caps);
+ GL11.glDisable(ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_ARB);
+ unitRecord.enabled[Type.CubeMap.ordinal()] = false;
+ }
+ }
+
+ }
+
+ public static void applyCombineFactors(final Texture texture, final TextureUnitRecord unitRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ // check that this is a valid fixed function unit. glTexEnv is only
+ // supported for unit < GL_MAX_TEXTURE_UNITS
+ if (unit >= caps.getNumberOfFixedTextureUnits()) {
+ return;
+ }
+
+ // first thing's first... if we are doing dot3 and don't
+ // support it, disable this texture.
+ boolean checked = false;
+ if (!caps.isEnvDot3TextureCombineSupported()
+ && (texture.getCombineFuncRGB() == CombinerFunctionRGB.Dot3RGB || texture.getCombineFuncRGB() == CombinerFunctionRGB.Dot3RGBA)) {
+
+ // disable
+ disableTexturing(unitRecord, record, unit, caps);
+
+ // No need to continue
+ return;
+ }
+
+ // Okay, now let's set our scales if we need to:
+ // First RGB Combine scale
+ if (!unitRecord.isValid() || unitRecord.envRGBScale != texture.getCombineScaleRGB()) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_RGB_SCALE_ARB, texture.getCombineScaleRGB()
+ .floatValue());
+ unitRecord.envRGBScale = texture.getCombineScaleRGB();
+ }
+ // Then Alpha Combine scale
+ if (!unitRecord.isValid() || unitRecord.envAlphaScale != texture.getCombineScaleAlpha()) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_ALPHA_SCALE, texture.getCombineScaleAlpha().floatValue());
+ unitRecord.envAlphaScale = texture.getCombineScaleAlpha();
+ }
+
+ // Time to set the RGB combines
+ final CombinerFunctionRGB rgbCombineFunc = texture.getCombineFuncRGB();
+ if (!unitRecord.isValid() || unitRecord.rgbCombineFunc != rgbCombineFunc) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_COMBINE_RGB_ARB,
+ LwjglTextureUtil.getGLCombineFuncRGB(rgbCombineFunc));
+ unitRecord.rgbCombineFunc = rgbCombineFunc;
+ }
+
+ CombinerSource combSrcRGB = texture.getCombineSrc0RGB();
+ if (!unitRecord.isValid() || unitRecord.combSrcRGB0 != combSrcRGB) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_SOURCE0_RGB_ARB,
+ LwjglTextureUtil.getGLCombineSrc(combSrcRGB));
+ unitRecord.combSrcRGB0 = combSrcRGB;
+ }
+
+ CombinerOperandRGB combOpRGB = texture.getCombineOp0RGB();
+ if (!unitRecord.isValid() || unitRecord.combOpRGB0 != combOpRGB) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_OPERAND0_RGB_ARB,
+ LwjglTextureUtil.getGLCombineOpRGB(combOpRGB));
+ unitRecord.combOpRGB0 = combOpRGB;
+ }
+
+ // We only need to do Arg1 or Arg2 if we aren't in Replace mode
+ if (rgbCombineFunc != CombinerFunctionRGB.Replace) {
+
+ combSrcRGB = texture.getCombineSrc1RGB();
+ if (!unitRecord.isValid() || unitRecord.combSrcRGB1 != combSrcRGB) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_SOURCE1_RGB_ARB,
+ LwjglTextureUtil.getGLCombineSrc(combSrcRGB));
+ unitRecord.combSrcRGB1 = combSrcRGB;
+ }
+
+ combOpRGB = texture.getCombineOp1RGB();
+ if (!unitRecord.isValid() || unitRecord.combOpRGB1 != combOpRGB) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_OPERAND1_RGB_ARB,
+ LwjglTextureUtil.getGLCombineOpRGB(combOpRGB));
+ unitRecord.combOpRGB1 = combOpRGB;
+ }
+
+ // We only need to do Arg2 if we are in Interpolate mode
+ if (rgbCombineFunc == CombinerFunctionRGB.Interpolate) {
+
+ combSrcRGB = texture.getCombineSrc2RGB();
+ if (!unitRecord.isValid() || unitRecord.combSrcRGB2 != combSrcRGB) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_SOURCE2_RGB_ARB,
+ LwjglTextureUtil.getGLCombineSrc(combSrcRGB));
+ unitRecord.combSrcRGB2 = combSrcRGB;
+ }
+
+ combOpRGB = texture.getCombineOp2RGB();
+ if (!unitRecord.isValid() || unitRecord.combOpRGB2 != combOpRGB) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_OPERAND2_RGB_ARB,
+ LwjglTextureUtil.getGLCombineOpRGB(combOpRGB));
+ unitRecord.combOpRGB2 = combOpRGB;
+ }
+
+ }
+ }
+
+ // Now Alpha combines
+ final CombinerFunctionAlpha alphaCombineFunc = texture.getCombineFuncAlpha();
+ if (!unitRecord.isValid() || unitRecord.alphaCombineFunc != alphaCombineFunc) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_COMBINE_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineFuncAlpha(alphaCombineFunc));
+ unitRecord.alphaCombineFunc = alphaCombineFunc;
+ }
+
+ CombinerSource combSrcAlpha = texture.getCombineSrc0Alpha();
+ if (!unitRecord.isValid() || unitRecord.combSrcAlpha0 != combSrcAlpha) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_SOURCE0_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineSrc(combSrcAlpha));
+ unitRecord.combSrcAlpha0 = combSrcAlpha;
+ }
+
+ CombinerOperandAlpha combOpAlpha = texture.getCombineOp0Alpha();
+ if (!unitRecord.isValid() || unitRecord.combOpAlpha0 != combOpAlpha) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_OPERAND0_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineOpAlpha(combOpAlpha));
+ unitRecord.combOpAlpha0 = combOpAlpha;
+ }
+
+ // We only need to do Arg1 or Arg2 if we aren't in Replace mode
+ if (alphaCombineFunc != CombinerFunctionAlpha.Replace) {
+
+ combSrcAlpha = texture.getCombineSrc1Alpha();
+ if (!unitRecord.isValid() || unitRecord.combSrcAlpha1 != combSrcAlpha) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_SOURCE1_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineSrc(combSrcAlpha));
+ unitRecord.combSrcAlpha1 = combSrcAlpha;
+ }
+
+ combOpAlpha = texture.getCombineOp1Alpha();
+ if (!unitRecord.isValid() || unitRecord.combOpAlpha1 != combOpAlpha) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_OPERAND1_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineOpAlpha(combOpAlpha));
+ unitRecord.combOpAlpha1 = combOpAlpha;
+ }
+
+ // We only need to do Arg2 if we are in Interpolate mode
+ if (alphaCombineFunc == CombinerFunctionAlpha.Interpolate) {
+
+ combSrcAlpha = texture.getCombineSrc2Alpha();
+ if (!unitRecord.isValid() || unitRecord.combSrcAlpha2 != combSrcAlpha) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_SOURCE2_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineSrc(combSrcAlpha));
+ unitRecord.combSrcAlpha2 = combSrcAlpha;
+ }
+
+ combOpAlpha = texture.getCombineOp2Alpha();
+ if (!unitRecord.isValid() || unitRecord.combOpAlpha2 != combOpAlpha) {
+ if (!checked) {
+ checkAndSetUnit(unit, record, caps);
+ checked = true;
+ }
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, ARBTextureEnvCombine.GL_OPERAND2_ALPHA_ARB,
+ LwjglTextureUtil.getGLCombineOpAlpha(combOpAlpha));
+ unitRecord.combOpAlpha2 = combOpAlpha;
+ }
+ }
+ }
+ }
+
+ public static void applyEnvMode(final ApplyMode mode, final TextureUnitRecord unitRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ if (!unitRecord.isValid() || unitRecord.envMode != mode) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, LwjglTextureUtil.getGLEnvMode(mode));
+ unitRecord.envMode = mode;
+ }
+ }
+
+ public static void applyBlendColor(final Texture texture, final TextureUnitRecord unitRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ final ReadOnlyColorRGBA texBlend = texture.getConstantColor();
+ if (!unitRecord.isValid() || !unitRecord.blendColor.equals(texBlend)) {
+ checkAndSetUnit(unit, record, caps);
+ TextureRecord.colorBuffer.clear();
+ TextureRecord.colorBuffer.put(texBlend.getRed()).put(texBlend.getGreen()).put(texBlend.getBlue())
+ .put(texBlend.getAlpha());
+ TextureRecord.colorBuffer.rewind();
+ GL11.glTexEnv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, TextureRecord.colorBuffer);
+ unitRecord.blendColor.set(texBlend);
+ }
+ }
+
+ public static void applyLodBias(final Texture texture, final TextureUnitRecord unitRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ if (caps.isTextureLodBiasSupported()) {
+ final float bias = texture.getLodBias() < caps.getMaxLodBias() ? texture.getLodBias() : caps
+ .getMaxLodBias();
+ if (!unitRecord.isValid() || unitRecord.lodBias != bias) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexEnvf(EXTTextureLODBias.GL_TEXTURE_FILTER_CONTROL_EXT,
+ EXTTextureLODBias.GL_TEXTURE_LOD_BIAS_EXT, bias);
+ unitRecord.lodBias = bias;
+ }
+ }
+ }
+
+ public static void applyBorderColor(final Texture texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record) {
+ final ReadOnlyColorRGBA texBorder = texture.getBorderColor();
+ if (!texRecord.isValid() || !texRecord.borderColor.equals(texBorder)) {
+ TextureRecord.colorBuffer.clear();
+ TextureRecord.colorBuffer.put(texBorder.getRed()).put(texBorder.getGreen()).put(texBorder.getBlue())
+ .put(texBorder.getAlpha());
+ TextureRecord.colorBuffer.rewind();
+ GL11.glTexParameter(getGLType(texture.getType()), GL11.GL_TEXTURE_BORDER_COLOR, TextureRecord.colorBuffer);
+ texRecord.borderColor.set(texBorder);
+ }
+ }
+
+ public static void applyTextureTransforms(final Texture texture, final int unit, final TextureStateRecord record,
+ final ContextCapabilities caps) {
+ final boolean needsReset = !record.units[unit].identityMatrix;
+
+ // Should we apply the transform?
+ final boolean doTrans = !texture.getTextureMatrix().isIdentity();
+
+ // Now do them.
+ final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord();
+ if (doTrans) {
+ checkAndSetUnit(unit, record, caps);
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_TEXTURE);
+
+ record.tmp_matrixBuffer.rewind();
+ texture.getTextureMatrix().toDoubleBuffer(record.tmp_matrixBuffer, true);
+ record.tmp_matrixBuffer.rewind();
+ GL11.glLoadMatrix(record.tmp_matrixBuffer);
+
+ record.units[unit].identityMatrix = false;
+ } else if (needsReset) {
+ checkAndSetUnit(unit, record, caps);
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_TEXTURE);
+ GL11.glLoadIdentity();
+ record.units[unit].identityMatrix = true;
+ }
+ // Switch back to the modelview matrix for further operations
+ LwjglRendererUtil.switchMode(matRecord, GL11.GL_MODELVIEW);
+ }
+
+ public static void applyTexCoordGeneration(final Texture texture, final TextureUnitRecord unitRecord,
+ final int unit, final TextureStateRecord record, final ContextCapabilities caps) {
+ switch (texture.getEnvironmentalMapMode()) {
+ case None:
+ // No coordinate generation
+ setTextureGen(unitRecord, unit, record, caps, false, false, false, false);
+ break;
+ case SphereMap:
+ // generate spherical texture coordinates
+ if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL11.GL_SPHERE_MAP) {
+ checkAndSetUnit(unit, record, caps);
+
+ GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_SPHERE_MAP);
+ unitRecord.textureGenSMode = GL11.GL_SPHERE_MAP;
+
+ GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_SPHERE_MAP);
+ unitRecord.textureGenTMode = GL11.GL_SPHERE_MAP;
+ }
+
+ setTextureGen(unitRecord, unit, record, caps, true, true, false, false);
+ break;
+ case NormalMap:
+ // generate normals based texture coordinates
+ if (!unitRecord.isValid() || unitRecord.textureGenSMode != ARBTextureCubeMap.GL_NORMAL_MAP_ARB) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, ARBTextureCubeMap.GL_NORMAL_MAP_ARB);
+ unitRecord.textureGenSMode = ARBTextureCubeMap.GL_NORMAL_MAP_ARB;
+
+ GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, ARBTextureCubeMap.GL_NORMAL_MAP_ARB);
+ unitRecord.textureGenTMode = ARBTextureCubeMap.GL_NORMAL_MAP_ARB;
+
+ GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, ARBTextureCubeMap.GL_NORMAL_MAP_ARB);
+ unitRecord.textureGenRMode = ARBTextureCubeMap.GL_NORMAL_MAP_ARB;
+ }
+
+ setTextureGen(unitRecord, unit, record, caps, true, true, true, false);
+ break;
+ case ReflectionMap:
+ // generate reflection texture coordinates
+ if (!unitRecord.isValid() || unitRecord.textureGenSMode != ARBTextureCubeMap.GL_REFLECTION_MAP_ARB) {
+ checkAndSetUnit(unit, record, caps);
+
+ GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, ARBTextureCubeMap.GL_REFLECTION_MAP_ARB);
+ unitRecord.textureGenSMode = ARBTextureCubeMap.GL_REFLECTION_MAP_ARB;
+
+ GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, ARBTextureCubeMap.GL_REFLECTION_MAP_ARB);
+ unitRecord.textureGenTMode = ARBTextureCubeMap.GL_REFLECTION_MAP_ARB;
+
+ GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, ARBTextureCubeMap.GL_REFLECTION_MAP_ARB);
+ unitRecord.textureGenRMode = ARBTextureCubeMap.GL_REFLECTION_MAP_ARB;
+ }
+
+ setTextureGen(unitRecord, unit, record, caps, true, true, true, false);
+ break;
+ case EyeLinear:
+ // do here because we don't check planes
+ checkAndSetUnit(unit, record, caps);
+
+ // generate eye linear texture coordinates
+ if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL11.GL_EYE_LINEAR) {
+ GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
+ unitRecord.textureGenSMode = GL11.GL_EYE_LINEAR;
+
+ GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
+ unitRecord.textureGenTMode = GL11.GL_EYE_LINEAR;
+
+ GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
+ unitRecord.textureGenRMode = GL11.GL_EYE_LINEAR;
+
+ GL11.glTexGeni(GL11.GL_Q, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
+ unitRecord.textureGenQMode = GL11.GL_EYE_LINEAR;
+ }
+
+ record.prepPlane(texture.getEnvPlaneS(), TextureStateRecord.DEFAULT_S_PLANE);
+ GL11.glTexGen(GL11.GL_S, GL11.GL_EYE_PLANE, record.plane);
+ record.prepPlane(texture.getEnvPlaneT(), TextureStateRecord.DEFAULT_T_PLANE);
+ GL11.glTexGen(GL11.GL_T, GL11.GL_EYE_PLANE, record.plane);
+ record.prepPlane(texture.getEnvPlaneR(), TextureStateRecord.DEFAULT_R_PLANE);
+ GL11.glTexGen(GL11.GL_R, GL11.GL_EYE_PLANE, record.plane);
+ record.prepPlane(texture.getEnvPlaneQ(), TextureStateRecord.DEFAULT_Q_PLANE);
+ GL11.glTexGen(GL11.GL_Q, GL11.GL_EYE_PLANE, record.plane);
+
+ setTextureGen(unitRecord, unit, record, caps, true, true, true, true);
+ break;
+ case ObjectLinear:
+ // do here because we don't check planes
+ checkAndSetUnit(unit, record, caps);
+
+ // generate object linear texture coordinates
+ if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL11.GL_OBJECT_LINEAR) {
+ GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_OBJECT_LINEAR);
+ unitRecord.textureGenSMode = GL11.GL_OBJECT_LINEAR;
+
+ GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_OBJECT_LINEAR);
+ unitRecord.textureGenTMode = GL11.GL_OBJECT_LINEAR;
+
+ GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_OBJECT_LINEAR);
+ unitRecord.textureGenRMode = GL11.GL_OBJECT_LINEAR;
+
+ GL11.glTexGeni(GL11.GL_Q, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_OBJECT_LINEAR);
+ unitRecord.textureGenQMode = GL11.GL_OBJECT_LINEAR;
+ }
+
+ record.prepPlane(texture.getEnvPlaneS(), TextureStateRecord.DEFAULT_S_PLANE);
+ GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, record.plane);
+ record.prepPlane(texture.getEnvPlaneT(), TextureStateRecord.DEFAULT_T_PLANE);
+ GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, record.plane);
+ record.prepPlane(texture.getEnvPlaneR(), TextureStateRecord.DEFAULT_R_PLANE);
+ GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, record.plane);
+ record.prepPlane(texture.getEnvPlaneQ(), TextureStateRecord.DEFAULT_Q_PLANE);
+ GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, record.plane);
+
+ setTextureGen(unitRecord, unit, record, caps, true, true, true, true);
+ break;
+ }
+ }
+
+ private static void setTextureGen(final TextureUnitRecord unitRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps, final boolean genS, final boolean genT,
+ final boolean genR, final boolean genQ) {
+ if (!unitRecord.isValid()) {
+ checkAndSetUnit(unit, record, caps);
+
+ if (genS) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_S);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_S);
+ }
+ if (genT) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_T);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_T);
+ }
+ if (genR) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_R);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_R);
+ }
+ if (genQ) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_Q);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_Q);
+ }
+ } else {
+ if (genS != unitRecord.textureGenS) {
+ checkAndSetUnit(unit, record, caps);
+ if (genS) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_S);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_S);
+ }
+ }
+ if (genT != unitRecord.textureGenT) {
+ checkAndSetUnit(unit, record, caps);
+ if (genT) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_T);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_T);
+ }
+ }
+ if (genR != unitRecord.textureGenR) {
+ checkAndSetUnit(unit, record, caps);
+ if (genR) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_R);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_R);
+ }
+ }
+ if (genQ != unitRecord.textureGenQ) {
+ checkAndSetUnit(unit, record, caps);
+ if (genQ) {
+ GL11.glEnable(GL11.GL_TEXTURE_GEN_Q);
+ } else {
+ GL11.glDisable(GL11.GL_TEXTURE_GEN_Q);
+ }
+ }
+ }
+
+ unitRecord.textureGenS = genS;
+ unitRecord.textureGenT = genT;
+ unitRecord.textureGenR = genR;
+ unitRecord.textureGenQ = genQ;
+ }
+
+ // If we support multtexturing, specify the unit we are affecting.
+ public static void checkAndSetUnit(final int unit, final TextureStateRecord record, final ContextCapabilities caps) {
+ // No need to worry about valid record, since invalidate sets record's
+ // currentUnit to -1.
+ if (record.currentUnit != unit) {
+ if (unit >= caps.getNumberOfTotalTextureUnits() || !caps.isMultitextureSupported() || unit < 0) {
+ // ignore this request as it is not valid for the user's hardware.
+ return;
+ }
+ ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE0_ARB + unit);
+ record.currentUnit = unit;
+ }
+ }
+
+ /**
+ * Check if the filter settings of this particular texture have been changed and apply as needed.
+ *
+ * @param texture
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the texture in gl
+ * @param record
+ */
+ public static void applyShadow(final Texture texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ final Type type = texture.getType();
+
+ if (caps.isDepthTextureSupported()) {
+ final int depthMode = LwjglTextureUtil.getGLDepthTextureMode(texture.getDepthMode());
+ // set up magnification filter
+ if (!texRecord.isValid() || texRecord.depthTextureMode != depthMode) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(getGLType(type), ARBDepthTexture.GL_DEPTH_TEXTURE_MODE_ARB, depthMode);
+ texRecord.depthTextureMode = depthMode;
+ }
+ }
+
+ if (caps.isARBShadowSupported()) {
+ final int depthCompareMode = LwjglTextureUtil.getGLDepthTextureCompareMode(texture.getDepthCompareMode());
+ // set up magnification filter
+ if (!texRecord.isValid() || texRecord.depthTextureCompareMode != depthCompareMode) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(getGLType(type), ARBShadow.GL_TEXTURE_COMPARE_MODE_ARB, depthCompareMode);
+ texRecord.depthTextureCompareMode = depthCompareMode;
+ }
+
+ final int depthCompareFunc = LwjglTextureUtil.getGLDepthTextureCompareFunc(texture.getDepthCompareFunc());
+ // set up magnification filter
+ if (!texRecord.isValid() || texRecord.depthTextureCompareFunc != depthCompareFunc) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(getGLType(type), ARBShadow.GL_TEXTURE_COMPARE_FUNC_ARB, depthCompareFunc);
+ texRecord.depthTextureCompareFunc = depthCompareFunc;
+ }
+ }
+ }
+
+ /**
+ * Check if the filter settings of this particular texture have been changed and apply as needed.
+ *
+ * @param texture
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the texture in gl
+ * @param record
+ */
+ public static void applyFilter(final Texture texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ final Type type = texture.getType();
+
+ final int magFilter = LwjglTextureUtil.getGLMagFilter(texture.getMagnificationFilter());
+ // set up magnification filter
+ if (!texRecord.isValid() || texRecord.magFilter != magFilter) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(getGLType(type), GL11.GL_TEXTURE_MAG_FILTER, magFilter);
+ texRecord.magFilter = magFilter;
+ }
+
+ final int minFilter = LwjglTextureUtil.getGLMinFilter(texture.getMinificationFilter());
+ // set up mipmap filter
+ if (!texRecord.isValid() || texRecord.minFilter != minFilter) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(getGLType(type), GL11.GL_TEXTURE_MIN_FILTER, minFilter);
+ texRecord.minFilter = minFilter;
+ }
+
+ // set up aniso filter
+ if (caps.isAnisoSupported()) {
+ float aniso = texture.getAnisotropicFilterPercent() * (caps.getMaxAnisotropic() - 1.0f);
+ aniso += 1.0f;
+ if (!texRecord.isValid() || (texRecord.anisoLevel - aniso > MathUtils.ZERO_TOLERANCE)) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameterf(getGLType(type), EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
+ texRecord.anisoLevel = aniso;
+ }
+ }
+ }
+
+ /**
+ * Check if the wrap mode of this particular texture has been changed and apply as needed.
+ *
+ * @param texture
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the unit in gl
+ * @param record
+ */
+ public static void applyWrap(final Texture3D texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ if (!caps.isTexture3DSupported()) {
+ return;
+ }
+
+ final int wrapS = getGLWrap(texture.getWrap(WrapAxis.S), caps);
+ final int wrapT = getGLWrap(texture.getWrap(WrapAxis.T), caps);
+ final int wrapR = getGLWrap(texture.getWrap(WrapAxis.R), caps);
+
+ if (!texRecord.isValid() || texRecord.wrapS != wrapS) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_WRAP_S, wrapS);
+ texRecord.wrapS = wrapS;
+ }
+ if (!texRecord.isValid() || texRecord.wrapT != wrapT) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_WRAP_T, wrapT);
+ texRecord.wrapT = wrapT;
+ }
+ if (!texRecord.isValid() || texRecord.wrapR != wrapR) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_R, wrapR);
+ texRecord.wrapR = wrapR;
+ }
+
+ }
+
+ /**
+ * Check if the wrap mode of this particular texture has been changed and apply as needed.
+ *
+ * @param texture
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the unit in gl
+ * @param record
+ */
+ public static void applyWrap(final Texture1D texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ final int wrapS = getGLWrap(texture.getWrap(WrapAxis.S), caps);
+
+ if (!texRecord.isValid() || texRecord.wrapS != wrapS) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(GL11.GL_TEXTURE_1D, GL11.GL_TEXTURE_WRAP_S, wrapS);
+ texRecord.wrapS = wrapS;
+ }
+ }
+
+ /**
+ * Check if the wrap mode of this particular texture has been changed and apply as needed.
+ *
+ * @param texture
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the unit in gl
+ * @param record
+ */
+ public static void applyWrap(final Texture texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ if (texture instanceof Texture2D) {
+ applyWrap((Texture2D) texture, texRecord, unit, record, caps);
+ } else if (texture instanceof Texture1D) {
+ applyWrap((Texture1D) texture, texRecord, unit, record, caps);
+ } else if (texture instanceof Texture3D) {
+ applyWrap((Texture3D) texture, texRecord, unit, record, caps);
+ } else if (texture instanceof TextureCubeMap) {
+ applyWrap((TextureCubeMap) texture, texRecord, unit, record, caps);
+ }
+ }
+
+ /**
+ * Check if the wrap mode of this particular texture has been changed and apply as needed.
+ *
+ * @param texture
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the unit in gl
+ * @param record
+ */
+ public static void applyWrap(final Texture2D texture, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ final int wrapS = getGLWrap(texture.getWrap(WrapAxis.S), caps);
+ final int wrapT = getGLWrap(texture.getWrap(WrapAxis.T), caps);
+
+ if (!texRecord.isValid() || texRecord.wrapS != wrapS) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrapS);
+ texRecord.wrapS = wrapS;
+ }
+ if (!texRecord.isValid() || texRecord.wrapT != wrapT) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrapT);
+ texRecord.wrapT = wrapT;
+ }
+
+ }
+
+ /**
+ * Check if the wrap mode of this particular texture has been changed and apply as needed.
+ *
+ * @param cubeMap
+ * our texture object
+ * @param texRecord
+ * our record of the last state of the unit in gl
+ * @param record
+ */
+ public static void applyWrap(final TextureCubeMap cubeMap, final TextureRecord texRecord, final int unit,
+ final TextureStateRecord record, final ContextCapabilities caps) {
+ if (!caps.isTextureCubeMapSupported()) {
+ return;
+ }
+
+ final int wrapS = getGLWrap(cubeMap.getWrap(WrapAxis.S), caps);
+ final int wrapT = getGLWrap(cubeMap.getWrap(WrapAxis.T), caps);
+ final int wrapR = getGLWrap(cubeMap.getWrap(WrapAxis.R), caps);
+
+ if (!texRecord.isValid() || texRecord.wrapS != wrapS) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_ARB, GL11.GL_TEXTURE_WRAP_S, wrapS);
+ texRecord.wrapS = wrapS;
+ }
+ if (!texRecord.isValid() || texRecord.wrapT != wrapT) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_ARB, GL11.GL_TEXTURE_WRAP_T, wrapT);
+ texRecord.wrapT = wrapT;
+ }
+ if (!texRecord.isValid() || texRecord.wrapR != wrapR) {
+ checkAndSetUnit(unit, record, caps);
+ GL11.glTexParameteri(ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_ARB, GL12.GL_TEXTURE_WRAP_R, wrapR);
+ texRecord.wrapR = wrapR;
+ }
+ }
+
+ public static void deleteTexture(final Texture texture) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture);
+
+ final Integer id = texture.getTextureIdForContextAsInteger(context.getGlContextRep());
+ if (id.intValue() == 0) {
+ // Not on card... return.
+ return;
+ }
+
+ final IntBuffer idBuffer = BufferUtils.createIntBuffer(1);
+ idBuffer.clear();
+ idBuffer.put(id.intValue());
+ idBuffer.rewind();
+ GL11.glDeleteTextures(idBuffer);
+ record.removeTextureRecord(id);
+ texture.removeFromIdCache(context.getGlContextRep());
+ }
+
+ public static void deleteTextureIds(final Collection<Integer> ids) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture);
+
+ final IntBuffer idBuffer = BufferUtils.createIntBuffer(ids.size());
+ idBuffer.clear();
+ for (final Integer i : ids) {
+ if (i != null) {
+ idBuffer.put(i);
+ record.removeTextureRecord(i);
+ }
+ }
+ idBuffer.flip();
+ if (idBuffer.remaining() > 0) {
+ GL11.glDeleteTextures(idBuffer);
+ }
+ }
+
+ /**
+ * Useful for external lwjgl based classes that need to safely set the current texture.
+ */
+ public static void doTextureBind(final Texture texture, final int unit, final boolean invalidateState) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+ final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture);
+ if (invalidateState) {
+ // Set this to null because no current state really matches anymore
+ context.setCurrentState(StateType.Texture, null);
+ }
+ checkAndSetUnit(unit, record, caps);
+
+ final int id = texture.getTextureIdForContext(context.getGlContextRep());
+ GL11.glBindTexture(getGLType(texture.getType()), id);
+ if (Constants.stats) {
+ StatCollector.addStat(StatType.STAT_TEXTURE_BINDS, 1);
+ }
+ if (record != null) {
+ record.units[unit].boundTexture = id;
+ }
+ }
+
+ public static int getGLType(final Type type) {
+ switch (type) {
+ case TwoDimensional:
+ return GL11.GL_TEXTURE_2D;
+ case OneDimensional:
+ return GL11.GL_TEXTURE_1D;
+ case ThreeDimensional:
+ return GL12.GL_TEXTURE_3D;
+ case CubeMap:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_ARB;
+ }
+ throw new IllegalArgumentException("invalid texture type: " + type);
+ }
+
+ public static int getGLCubeMapFace(final TextureCubeMap.Face face) {
+ switch (face) {
+ case PositiveX:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
+ case NegativeX:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB;
+ case PositiveY:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB;
+ case NegativeY:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB;
+ case PositiveZ:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB;
+ case NegativeZ:
+ return ARBTextureCubeMap.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB;
+ }
+ throw new IllegalArgumentException("invalid cubemap face: " + face);
+ }
+
+ public static int getGLWrap(final WrapMode wrap, final ContextCapabilities caps) {
+ switch (wrap) {
+ case Repeat:
+ return GL11.GL_REPEAT;
+ case MirroredRepeat:
+ if (caps.isTextureMirroredRepeatSupported()) {
+ return ARBTextureMirroredRepeat.GL_MIRRORED_REPEAT_ARB;
+ } else {
+ return GL11.GL_REPEAT;
+ }
+ case MirrorClamp:
+ if (caps.isTextureMirrorClampSupported()) {
+ return EXTTextureMirrorClamp.GL_MIRROR_CLAMP_EXT;
+ }
+ // FALLS THROUGH
+ case Clamp:
+ return GL11.GL_CLAMP;
+ case MirrorBorderClamp:
+ if (caps.isTextureMirrorBorderClampSupported()) {
+ return EXTTextureMirrorClamp.GL_MIRROR_CLAMP_TO_BORDER_EXT;
+ }
+ // FALLS THROUGH
+ case BorderClamp:
+ if (caps.isTextureBorderClampSupported()) {
+ return ARBTextureBorderClamp.GL_CLAMP_TO_BORDER_ARB;
+ } else {
+ return GL11.GL_CLAMP;
+ }
+ case MirrorEdgeClamp:
+ if (caps.isTextureMirrorEdgeClampSupported()) {
+ return EXTTextureMirrorClamp.GL_MIRROR_CLAMP_TO_EDGE_EXT;
+ }
+ // FALLS THROUGH
+ case EdgeClamp:
+ if (caps.isTextureEdgeClampSupported()) {
+ return GL12.GL_CLAMP_TO_EDGE;
+ } else {
+ return GL11.GL_CLAMP;
+ }
+ }
+ throw new IllegalArgumentException("invalid WrapMode type: " + wrap);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglVertexProgramStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglVertexProgramStateUtil.java
new file mode 100644
index 0000000..462b0a3
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglVertexProgramStateUtil.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBProgram;
+import org.lwjgl.opengl.ARBVertexProgram;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.VertexProgramState;
+import com.ardor3d.renderer.state.record.VertexProgramStateRecord;
+import com.ardor3d.util.geom.BufferUtils;
+
+public abstract class LwjglVertexProgramStateUtil {
+ private static final Logger logger = Logger.getLogger(LwjglVertexProgramStateUtil.class.getName());
+
+ /**
+ * Queries OpenGL for errors in the vertex program. Errors are logged as SEVERE, noting both the line number and
+ * message.
+ */
+ private static void checkProgramError() {
+ if (GL11.glGetError() == GL11.GL_INVALID_OPERATION) {
+ // retrieve the error position
+ final IntBuffer errorloc = BufferUtils.createIntBuffer(16);
+ GL11.glGetInteger(ARBProgram.GL_PROGRAM_ERROR_POSITION_ARB, errorloc);
+
+ logger.severe("Error " + GL11.glGetString(ARBProgram.GL_PROGRAM_ERROR_STRING_ARB)
+ + " in vertex program on line " + errorloc.get(0));
+ }
+ }
+
+ protected static int create(final ByteBuffer program) {
+
+ final IntBuffer buf = BufferUtils.createIntBuffer(1);
+
+ ARBProgram.glGenProgramsARB(buf);
+ ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, buf.get(0));
+ ARBProgram.glProgramStringARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB,
+ program);
+
+ checkProgramError();
+
+ return buf.get(0);
+ }
+
+ /**
+ * Applies this vertex program to the current scene. Checks if the GL_ARB_vertex_program extension is supported
+ * before attempting to enable this program.
+ *
+ * @see com.ardor3d.renderer.state.RenderState#apply()
+ */
+ public static void apply(final VertexProgramState state) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ if (context.getCapabilities().isVertexProgramSupported()) {
+ // ask for the current state record
+ final VertexProgramStateRecord record = (VertexProgramStateRecord) context
+ .getStateRecord(StateType.VertexProgram);
+ context.setCurrentState(StateType.VertexProgram, state);
+
+ if (!record.isValid() || record.getReference() != state) {
+ record.setReference(state);
+ if (state.isEnabled()) {
+ // Vertex program not yet loaded
+ if (state._getProgramID() == -1) {
+ if (state.getProgramAsBuffer() != null) {
+ final int id = create(state.getProgramAsBuffer());
+ state._setProgramID(id);
+ } else {
+ return;
+ }
+ }
+
+ GL11.glEnable(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB);
+ ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, state._getProgramID());
+
+ // load environmental parameters...
+ for (int i = 0; i < VertexProgramState._getEnvParameters().length; i++) {
+ if (VertexProgramState._getEnvParameters()[i] != null) {
+ ARBProgram.glProgramEnvParameter4fARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, i,
+ VertexProgramState._getEnvParameters()[i][0],
+ VertexProgramState._getEnvParameters()[i][1],
+ VertexProgramState._getEnvParameters()[i][2],
+ VertexProgramState._getEnvParameters()[i][3]);
+ }
+ }
+
+ // load local parameters...
+ if (state.isUsingParameters()) {
+ // no parameters are used
+ for (int i = 0; i < state._getParameters().length; i++) {
+ if (state._getParameters()[i] != null) {
+ ARBProgram.glProgramLocalParameter4fARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, i,
+ state._getParameters()[i][0], state._getParameters()[i][1],
+ state._getParameters()[i][2], state._getParameters()[i][3]);
+ }
+ }
+ }
+
+ } else {
+ GL11.glDisable(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB);
+ }
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglWireframeStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglWireframeStateUtil.java
new file mode 100644
index 0000000..7ce1b24
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglWireframeStateUtil.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.lwjgl.LwjglRenderer;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.WireframeState;
+import com.ardor3d.renderer.state.record.WireframeStateRecord;
+
+public abstract class LwjglWireframeStateUtil {
+
+ public static void apply(final LwjglRenderer renderer, final WireframeState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final WireframeStateRecord record = (WireframeStateRecord) context.getStateRecord(StateType.Wireframe);
+ context.setCurrentState(StateType.Wireframe, state);
+
+ if (state.isEnabled()) {
+ renderer.setupLineParameters(state.getLineWidth(), 1, (short) 0xFFFF, state.isAntialiased());
+
+ switch (state.getFace()) {
+ case Front:
+ applyPolyMode(GL11.GL_LINE, GL11.GL_FILL, record);
+ break;
+ case Back:
+ applyPolyMode(GL11.GL_FILL, GL11.GL_LINE, record);
+ break;
+ case FrontAndBack:
+ default:
+ applyPolyMode(GL11.GL_LINE, GL11.GL_LINE, record);
+ break;
+ }
+ } else {
+ applyPolyMode(GL11.GL_FILL, GL11.GL_FILL, record);
+ }
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void applyPolyMode(final int frontMode, final int backMode, final WireframeStateRecord record) {
+
+ if (record.isValid()) {
+ if (frontMode == backMode && (record.frontMode != frontMode || record.backMode != backMode)) {
+ GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, frontMode);
+ record.frontMode = frontMode;
+ record.backMode = backMode;
+ } else if (frontMode != backMode) {
+ if (record.frontMode != frontMode) {
+ GL11.glPolygonMode(GL11.GL_FRONT, frontMode);
+ record.frontMode = frontMode;
+ }
+ if (record.backMode != backMode) {
+ GL11.glPolygonMode(GL11.GL_BACK, backMode);
+ record.backMode = backMode;
+ }
+ }
+
+ } else {
+ if (frontMode == backMode) {
+ GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, frontMode);
+ } else if (frontMode != backMode) {
+ GL11.glPolygonMode(GL11.GL_FRONT, frontMode);
+ GL11.glPolygonMode(GL11.GL_BACK, backMode);
+ }
+ record.frontMode = frontMode;
+ record.backMode = backMode;
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglZBufferStateUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglZBufferStateUtil.java
new file mode 100644
index 0000000..dbebc5c
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/LwjglZBufferStateUtil.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl;
+
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.ZBufferState;
+import com.ardor3d.renderer.state.record.ZBufferStateRecord;
+
+public abstract class LwjglZBufferStateUtil {
+
+ public static void apply(final ZBufferState state) {
+ // ask for the current state record
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ZBufferStateRecord record = (ZBufferStateRecord) context.getStateRecord(StateType.ZBuffer);
+ context.setCurrentState(StateType.ZBuffer, state);
+
+ enableDepthTest(state.isEnabled(), record);
+ if (state.isEnabled()) {
+ int depthFunc = 0;
+ switch (state.getFunction()) {
+ case Never:
+ depthFunc = GL11.GL_NEVER;
+ break;
+ case LessThan:
+ depthFunc = GL11.GL_LESS;
+ break;
+ case EqualTo:
+ depthFunc = GL11.GL_EQUAL;
+ break;
+ case LessThanOrEqualTo:
+ depthFunc = GL11.GL_LEQUAL;
+ break;
+ case GreaterThan:
+ depthFunc = GL11.GL_GREATER;
+ break;
+ case NotEqualTo:
+ depthFunc = GL11.GL_NOTEQUAL;
+ break;
+ case GreaterThanOrEqualTo:
+ depthFunc = GL11.GL_GEQUAL;
+ break;
+ case Always:
+ depthFunc = GL11.GL_ALWAYS;
+ }
+ applyFunction(depthFunc, record);
+ }
+
+ enableWrite(state.isWritable(), record);
+
+ if (!record.isValid()) {
+ record.validate();
+ }
+ }
+
+ private static void enableDepthTest(final boolean enable, final ZBufferStateRecord record) {
+ if (enable && (!record.depthTest || !record.isValid())) {
+ GL11.glEnable(GL11.GL_DEPTH_TEST);
+ record.depthTest = true;
+ } else if (!enable && (record.depthTest || !record.isValid())) {
+ GL11.glDisable(GL11.GL_DEPTH_TEST);
+ record.depthTest = false;
+ }
+ }
+
+ private static void applyFunction(final int depthFunc, final ZBufferStateRecord record) {
+ if (depthFunc != record.depthFunc || !record.isValid()) {
+ GL11.glDepthFunc(depthFunc);
+ record.depthFunc = depthFunc;
+ }
+ }
+
+ private static void enableWrite(final boolean enable, final ZBufferStateRecord record) {
+ if (enable != record.writable || !record.isValid()) {
+ GL11.glDepthMask(enable);
+ record.writable = enable;
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/shader/LwjglShaderUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/shader/LwjglShaderUtil.java
new file mode 100644
index 0000000..877f2fd
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/shader/LwjglShaderUtil.java
@@ -0,0 +1,400 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl.shader;
+
+import java.nio.ByteBuffer;
+import java.util.logging.Logger;
+
+import org.lwjgl.opengl.ARBShaderObjects;
+import org.lwjgl.opengl.ARBVertexProgram;
+import org.lwjgl.opengl.ARBVertexShader;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.lwjgl.LwjglRenderer;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.record.ShaderObjectsStateRecord;
+import com.ardor3d.scene.state.lwjgl.util.LwjglRendererUtil;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.shader.ShaderVariable;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat2;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat3;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat4;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloatArray;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt2;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt3;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt4;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableIntArray;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix2;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix3;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix4;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix4Array;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerByte;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerFloat;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerFloatMatrix;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerInt;
+import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerShort;
+
+/** Utility class for updating shadervariables(uniforms and attributes) */
+public abstract class LwjglShaderUtil {
+ private static final Logger logger = Logger.getLogger(LwjglShaderUtil.class.getName());
+
+ /**
+ * Updates a uniform shadervariable.
+ *
+ * @param shaderVariable
+ * variable to update
+ */
+ public static void updateShaderUniform(final ShaderVariable shaderVariable) {
+ if (!shaderVariable.hasData()) {
+ throw new IllegalArgumentException("shaderVariable has no data: " + shaderVariable.name + " type: "
+ + shaderVariable.getClass().getName());
+ }
+
+ if (shaderVariable instanceof ShaderVariableInt) {
+ updateShaderUniform((ShaderVariableInt) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableInt2) {
+ updateShaderUniform((ShaderVariableInt2) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableInt3) {
+ updateShaderUniform((ShaderVariableInt3) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableInt4) {
+ updateShaderUniform((ShaderVariableInt4) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableIntArray) {
+ updateShaderUniform((ShaderVariableIntArray) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableFloat) {
+ updateShaderUniform((ShaderVariableFloat) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableFloat2) {
+ updateShaderUniform((ShaderVariableFloat2) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableFloat3) {
+ updateShaderUniform((ShaderVariableFloat3) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableFloat4) {
+ updateShaderUniform((ShaderVariableFloat4) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableFloatArray) {
+ updateShaderUniform((ShaderVariableFloatArray) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableMatrix2) {
+ updateShaderUniform((ShaderVariableMatrix2) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableMatrix3) {
+ updateShaderUniform((ShaderVariableMatrix3) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableMatrix4) {
+ updateShaderUniform((ShaderVariableMatrix4) shaderVariable);
+ } else if (shaderVariable instanceof ShaderVariableMatrix4Array) {
+ updateShaderUniform((ShaderVariableMatrix4Array) shaderVariable);
+ } else {
+ logger.warning("updateShaderUniform: Unknown shaderVariable type!");
+ }
+ }
+
+ /**
+ * Update variableID for uniform shadervariable if needed.
+ *
+ * @param variable
+ * shadervaribale to update ID on
+ * @param programID
+ * shader program context ID
+ */
+ public static void updateUniformLocation(final ShaderVariable variable, final int programID) {
+ if (variable.variableID == -1) {
+ final ByteBuffer nameBuf = BufferUtils.createByteBuffer(variable.name.getBytes().length + 1);
+ nameBuf.clear();
+ nameBuf.put(variable.name.getBytes());
+ nameBuf.rewind();
+
+ variable.variableID = ARBShaderObjects.glGetUniformLocationARB(programID, nameBuf);
+
+ if (variable.variableID == -1 && !variable.errorLogged) {
+ logger.severe("Shader uniform [" + variable.name + "] could not be located in shader");
+ variable.errorLogged = true;
+ }
+ }
+ }
+
+ private static void updateShaderUniform(final ShaderVariableInt shaderUniform) {
+ ARBShaderObjects.glUniform1iARB(shaderUniform.variableID, shaderUniform.value1);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableInt2 shaderUniform) {
+ ARBShaderObjects.glUniform2iARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableInt3 shaderUniform) {
+ ARBShaderObjects.glUniform3iARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2,
+ shaderUniform.value3);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableInt4 shaderUniform) {
+ ARBShaderObjects.glUniform4iARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2,
+ shaderUniform.value3, shaderUniform.value4);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableIntArray shaderUniform) {
+ switch (shaderUniform.size) {
+ case 1:
+ ARBShaderObjects.glUniform1ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ case 2:
+ ARBShaderObjects.glUniform2ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ case 3:
+ ARBShaderObjects.glUniform3ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ case 4:
+ ARBShaderObjects.glUniform4ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ default:
+ throw new IllegalArgumentException("Wrong size: " + shaderUniform.size);
+ }
+ }
+
+ private static void updateShaderUniform(final ShaderVariableFloat shaderUniform) {
+ ARBShaderObjects.glUniform1fARB(shaderUniform.variableID, shaderUniform.value1);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableFloat2 shaderUniform) {
+ ARBShaderObjects.glUniform2fARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableFloat3 shaderUniform) {
+ ARBShaderObjects.glUniform3fARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2,
+ shaderUniform.value3);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableFloat4 shaderUniform) {
+ ARBShaderObjects.glUniform4fARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2,
+ shaderUniform.value3, shaderUniform.value4);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableFloatArray shaderUniform) {
+ switch (shaderUniform.size) {
+ case 1:
+ ARBShaderObjects.glUniform1ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ case 2:
+ ARBShaderObjects.glUniform2ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ case 3:
+ ARBShaderObjects.glUniform3ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ case 4:
+ ARBShaderObjects.glUniform4ARB(shaderUniform.variableID, shaderUniform.value);
+ break;
+ default:
+ throw new IllegalArgumentException("Wrong size: " + shaderUniform.size);
+ }
+ }
+
+ private static void updateShaderUniform(final ShaderVariableMatrix2 shaderUniform) {
+ shaderUniform.matrixBuffer.rewind();
+ ARBShaderObjects.glUniformMatrix2ARB(shaderUniform.variableID, shaderUniform.rowMajor,
+ shaderUniform.matrixBuffer);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableMatrix3 shaderUniform) {
+ shaderUniform.matrixBuffer.rewind();
+ ARBShaderObjects.glUniformMatrix3ARB(shaderUniform.variableID, shaderUniform.rowMajor,
+ shaderUniform.matrixBuffer);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableMatrix4 shaderUniform) {
+ shaderUniform.matrixBuffer.rewind();
+ ARBShaderObjects.glUniformMatrix4ARB(shaderUniform.variableID, shaderUniform.rowMajor,
+ shaderUniform.matrixBuffer);
+ }
+
+ private static void updateShaderUniform(final ShaderVariableMatrix4Array shaderUniform) {
+ shaderUniform.matrixBuffer.rewind();
+ ARBShaderObjects.glUniformMatrix4ARB(shaderUniform.variableID, shaderUniform.rowMajor,
+ shaderUniform.matrixBuffer);
+ }
+
+ /**
+ * Update variableID for attribute shadervariable if needed.
+ *
+ * @param variable
+ * shadervaribale to update ID on
+ * @param programID
+ * shader program context ID
+ */
+ public static void updateAttributeLocation(final ShaderVariable variable, final int programID) {
+ if (variable.variableID == -1) {
+ final ByteBuffer nameBuf = BufferUtils.createByteBuffer(variable.name.getBytes().length + 1);
+ nameBuf.clear();
+ nameBuf.put(variable.name.getBytes());
+ nameBuf.rewind();
+
+ variable.variableID = ARBVertexShader.glGetAttribLocationARB(programID, nameBuf);
+
+ if (variable.variableID == -1 && !variable.errorLogged) {
+ logger.severe("Shader attribute [" + variable.name + "] could not be located in shader");
+ variable.errorLogged = true;
+ }
+ }
+ }
+
+ /**
+ * Updates an vertex attribute pointer.
+ *
+ * @param renderer
+ * the current renderer
+ * @param shaderVariable
+ * variable to update
+ * @param useVBO
+ * if true, we'll use VBO for the attributes, if false we'll use arrays.
+ */
+ public static void updateShaderAttribute(final Renderer renderer, final ShaderVariable shaderVariable,
+ final boolean useVBO) {
+ if (shaderVariable.variableID == -1) {
+ // attribute is not bound, or was not found in shader.
+ return;
+ }
+
+ if (!shaderVariable.hasData()) {
+ throw new IllegalArgumentException("shaderVariable has no data: " + shaderVariable.name + " type: "
+ + shaderVariable.getClass().getName());
+ }
+
+ final RenderContext context = ContextManager.getCurrentContext();
+ final ContextCapabilities caps = context.getCapabilities();
+ if (caps.isVBOSupported() && !useVBO) {
+ renderer.unbindVBO();
+ }
+
+ final ShaderObjectsStateRecord record = (ShaderObjectsStateRecord) context.getStateRecord(StateType.GLSLShader);
+
+ if (shaderVariable instanceof ShaderVariablePointerFloat) {
+ updateShaderAttribute((ShaderVariablePointerFloat) shaderVariable, record, useVBO);
+ } else if (shaderVariable instanceof ShaderVariablePointerFloatMatrix) {
+ updateShaderAttribute((ShaderVariablePointerFloatMatrix) shaderVariable, record, useVBO);
+ } else if (shaderVariable instanceof ShaderVariablePointerByte) {
+ updateShaderAttribute((ShaderVariablePointerByte) shaderVariable, record, useVBO);
+ } else if (shaderVariable instanceof ShaderVariablePointerInt) {
+ updateShaderAttribute((ShaderVariablePointerInt) shaderVariable, record, useVBO);
+ } else if (shaderVariable instanceof ShaderVariablePointerShort) {
+ updateShaderAttribute((ShaderVariablePointerShort) shaderVariable, record, useVBO);
+ } else {
+ logger.warning("updateShaderAttribute: Unknown shaderVariable type!");
+ return;
+ }
+ }
+
+ public static void useShaderProgram(final int id, final ShaderObjectsStateRecord record) {
+ if (record.shaderId != id) {
+ ARBShaderObjects.glUseProgramObjectARB(id);
+ record.shaderId = id;
+ }
+ }
+
+ private static void enableVertexAttribute(final ShaderVariable var, final ShaderObjectsStateRecord record) {
+ if (!record.enabledAttributes.contains(var)) {
+ if (var.getSize() == 1) {
+ ARBVertexProgram.glEnableVertexAttribArrayARB(var.variableID);
+ } else {
+ for (int i = 0, max = var.getSize(); i < max; i++) {
+ ARBVertexProgram.glEnableVertexAttribArrayARB(var.variableID + i);
+ }
+ }
+ record.enabledAttributes.add(var);
+ }
+ }
+
+ private static void updateShaderAttribute(final ShaderVariablePointerFloat variable,
+ final ShaderObjectsStateRecord record, final boolean useVBO) {
+ enableVertexAttribute(variable, record);
+ if (useVBO) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final int vboId = LwjglRenderer.setupVBO(variable.data, context);
+ LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId);
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, GL11.GL_FLOAT,
+ variable.normalized, variable.stride, 0);
+ } else {
+ variable.data.getBuffer().rewind();
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.normalized,
+ variable.stride, variable.data.getBuffer());
+ }
+ }
+
+ private static void updateShaderAttribute(final ShaderVariablePointerFloatMatrix variable,
+ final ShaderObjectsStateRecord record, final boolean useVBO) {
+ final int size = variable.size;
+ final int length = variable.data.getBuffer().capacity() / size;
+ final RenderContext context = ContextManager.getCurrentContext();
+ int pos = 0;
+ enableVertexAttribute(variable, record);
+ for (int i = 0; i < size; i++) {
+ pos = (i * length);
+ if (useVBO) {
+ final int vboId = LwjglRenderer.setupVBO(variable.data, context);
+ LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId);
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID + i, size, GL11.GL_FLOAT,
+ variable.normalized, 0, pos);
+ } else {
+ variable.data.getBuffer().limit(pos + length - 1);
+ variable.data.getBuffer().position(pos);
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID + i, size, variable.normalized, 0,
+ variable.data.getBuffer());
+ }
+ }
+ }
+
+ private static void updateShaderAttribute(final ShaderVariablePointerByte variable,
+ final ShaderObjectsStateRecord record, final boolean useVBO) {
+ enableVertexAttribute(variable, record);
+ if (useVBO) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final int vboId = LwjglRenderer.setupVBO(variable.data, context);
+ LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId);
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size,
+ variable.unsigned ? GL11.GL_UNSIGNED_BYTE : GL11.GL_BYTE, variable.normalized, variable.stride, 0);
+ } else {
+ variable.data.getBuffer().rewind();
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned,
+ variable.normalized, variable.stride, variable.data.getBuffer());
+ }
+ }
+
+ private static void updateShaderAttribute(final ShaderVariablePointerInt variable,
+ final ShaderObjectsStateRecord record, final boolean useVBO) {
+ enableVertexAttribute(variable, record);
+ if (useVBO) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final int vboId = LwjglRenderer.setupVBO(variable.data, context);
+ LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId);
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size,
+ variable.unsigned ? GL11.GL_UNSIGNED_INT : GL11.GL_INT, variable.normalized, variable.stride, 0);
+ } else {
+ variable.data.getBuffer().rewind();
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned,
+ variable.normalized, variable.stride, variable.data.getBuffer());
+ }
+ }
+
+ private static void updateShaderAttribute(final ShaderVariablePointerShort variable,
+ final ShaderObjectsStateRecord record, final boolean useVBO) {
+ enableVertexAttribute(variable, record);
+ if (useVBO) {
+ final RenderContext context = ContextManager.getCurrentContext();
+ final int vboId = LwjglRenderer.setupVBO(variable.data, context);
+ LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId);
+ ARBVertexProgram
+ .glVertexAttribPointerARB(variable.variableID, variable.size,
+ variable.unsigned ? GL11.GL_UNSIGNED_SHORT : GL11.GL_SHORT, variable.normalized,
+ variable.stride, 0);
+ } else {
+ variable.data.getBuffer().rewind();
+ ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned,
+ variable.normalized, variable.stride, variable.data.getBuffer());
+ }
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglRendererUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglRendererUtil.java
new file mode 100644
index 0000000..8abbe4d
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglRendererUtil.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl.util;
+
+import java.util.Stack;
+
+import org.lwjgl.opengl.ARBBufferObject;
+import org.lwjgl.opengl.ARBVertexBufferObject;
+import org.lwjgl.opengl.GL11;
+
+import com.ardor3d.math.Rectangle2;
+import com.ardor3d.math.type.ReadOnlyRectangle2;
+import com.ardor3d.renderer.state.record.RendererRecord;
+
+public abstract class LwjglRendererUtil {
+
+ public static void switchMode(final RendererRecord rendRecord, final int mode) {
+ if (!rendRecord.isMatrixValid() || rendRecord.getMatrixMode() != mode) {
+ GL11.glMatrixMode(mode);
+ rendRecord.setMatrixMode(mode);
+ rendRecord.setMatrixValid(true);
+ }
+ }
+
+ public static void setBoundVBO(final RendererRecord rendRecord, final int id) {
+ if (!rendRecord.isVboValid() || rendRecord.getCurrentVboId() != id) {
+ ARBBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, id);
+ rendRecord.setCurrentVboId(id);
+ rendRecord.setVboValid(true);
+ }
+ }
+
+ public static void setBoundElementVBO(final RendererRecord rendRecord, final int id) {
+ if (!rendRecord.isElementVboValid() || rendRecord.getCurrentElementVboId() != id) {
+ ARBBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, id);
+ rendRecord.setCurrentElementVboId(id);
+ rendRecord.setElementVboValid(true);
+ }
+ }
+
+ public static void applyScissors(final RendererRecord rendRecord) {
+ final Stack<ReadOnlyRectangle2> clips = rendRecord.getScissorClips();
+
+ if (clips.size() > 0) {
+ final Rectangle2 init = Rectangle2.fetchTempInstance();
+ init.set(-1, -1, -1, -1);
+ ReadOnlyRectangle2 r;
+ boolean first = true;
+ for (int i = clips.size(); --i >= 0;) {
+ r = clips.get(i);
+
+ if (r == null) {
+ break;
+ }
+ if (first) {
+ init.set(r);
+ first = false;
+ } else {
+ init.intersect(r, init);
+ }
+ if (init.getWidth() <= 0 || init.getHeight() <= 0) {
+ init.setWidth(0);
+ init.setHeight(0);
+ break;
+ }
+ }
+
+ if (init.getWidth() == -1) {
+ setClippingEnabled(rendRecord, false);
+ } else {
+ setClippingEnabled(rendRecord, true);
+ GL11.glScissor(init.getX(), init.getY(), init.getWidth(), init.getHeight());
+ }
+ Rectangle2.releaseTempInstance(init);
+ } else {
+ // no clips, so disable
+ setClippingEnabled(rendRecord, false);
+ }
+ }
+
+ public static void setClippingEnabled(final RendererRecord rendRecord, final boolean enabled) {
+ if (enabled && (!rendRecord.isClippingTestValid() || !rendRecord.isClippingTestEnabled())) {
+ GL11.glEnable(GL11.GL_SCISSOR_TEST);
+ rendRecord.setClippingTestEnabled(true);
+ } else if (!enabled && (!rendRecord.isClippingTestValid() || rendRecord.isClippingTestEnabled())) {
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+ rendRecord.setClippingTestEnabled(false);
+ }
+ rendRecord.setClippingTestValid(true);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglTextureUtil.java b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglTextureUtil.java
new file mode 100644
index 0000000..1380fe5
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/java/com/ardor3d/scene/state/lwjgl/util/LwjglTextureUtil.java
@@ -0,0 +1,633 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.scene.state.lwjgl.util;
+
+import org.lwjgl.opengl.ARBDepthBufferFloat;
+import org.lwjgl.opengl.ARBDepthTexture;
+import org.lwjgl.opengl.ARBHalfFloatPixel;
+import org.lwjgl.opengl.ARBMultitexture;
+import org.lwjgl.opengl.ARBShadow;
+import org.lwjgl.opengl.ARBTextureCompression;
+import org.lwjgl.opengl.ARBTextureEnvCombine;
+import org.lwjgl.opengl.ARBTextureEnvDot3;
+import org.lwjgl.opengl.ARBTextureFloat;
+import org.lwjgl.opengl.ARBTextureRg;
+import org.lwjgl.opengl.EXTTextureCompressionLATC;
+import org.lwjgl.opengl.EXTTextureCompressionS3TC;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GL30;
+
+import com.ardor3d.image.ImageDataFormat;
+import com.ardor3d.image.PixelDataType;
+import com.ardor3d.image.Texture.ApplyMode;
+import com.ardor3d.image.Texture.CombinerFunctionAlpha;
+import com.ardor3d.image.Texture.CombinerFunctionRGB;
+import com.ardor3d.image.Texture.CombinerOperandAlpha;
+import com.ardor3d.image.Texture.CombinerOperandRGB;
+import com.ardor3d.image.Texture.CombinerSource;
+import com.ardor3d.image.Texture.DepthTextureCompareFunc;
+import com.ardor3d.image.Texture.DepthTextureCompareMode;
+import com.ardor3d.image.Texture.DepthTextureMode;
+import com.ardor3d.image.Texture.MagnificationFilter;
+import com.ardor3d.image.Texture.MinificationFilter;
+import com.ardor3d.image.TextureStoreFormat;
+import com.ardor3d.renderer.state.TextureState.CorrectionType;
+
+public abstract class LwjglTextureUtil {
+
+ public static int getGLInternalFormat(final TextureStoreFormat format) {
+ switch (format) {
+ // first some frequently used formats
+ case RGBA8:
+ return GL11.GL_RGBA8;
+ case RGB8:
+ return GL11.GL_RGB8;
+ case Alpha8:
+ return GL11.GL_ALPHA8;
+ case CompressedRGBA:
+ return ARBTextureCompression.GL_COMPRESSED_RGBA_ARB;
+ case CompressedRGB:
+ return ARBTextureCompression.GL_COMPRESSED_RGB_ARB;
+ case CompressedRG:
+ return GL30.GL_COMPRESSED_RG;
+ case CompressedRed:
+ return GL30.GL_COMPRESSED_RED;
+ case CompressedLuminance:
+ return ARBTextureCompression.GL_COMPRESSED_LUMINANCE_ARB;
+ case CompressedLuminanceAlpha:
+ return ARBTextureCompression.GL_COMPRESSED_LUMINANCE_ALPHA_ARB;
+ case NativeDXT1:
+ return EXTTextureCompressionS3TC.GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ case NativeDXT1A:
+ return EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ case NativeDXT3:
+ return EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ case NativeDXT5:
+ return EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ case NativeLATC_L:
+ return EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_LATC1_EXT;
+ case NativeLATC_LA:
+ return EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
+
+ // The rest...
+ case Alpha4:
+ return GL11.GL_ALPHA4;
+ case Alpha12:
+ return GL11.GL_ALPHA12;
+ case Alpha16:
+ return GL11.GL_ALPHA16;
+ case Luminance4:
+ return GL11.GL_LUMINANCE4;
+ case Luminance8:
+ return GL11.GL_LUMINANCE8;
+ case Luminance12:
+ return GL11.GL_LUMINANCE12;
+ case Luminance16:
+ return GL11.GL_LUMINANCE16;
+ case Intensity4:
+ return GL11.GL_INTENSITY4;
+ case Intensity8:
+ return GL11.GL_INTENSITY8;
+ case Intensity12:
+ return GL11.GL_INTENSITY12;
+ case Intensity16:
+ return GL11.GL_INTENSITY16;
+ case Luminance4Alpha4:
+ return GL11.GL_LUMINANCE4_ALPHA4;
+ case Luminance6Alpha2:
+ return GL11.GL_LUMINANCE6_ALPHA2;
+ case Luminance8Alpha8:
+ return GL11.GL_LUMINANCE8_ALPHA8;
+ case Luminance12Alpha4:
+ return GL11.GL_LUMINANCE12_ALPHA4;
+ case Luminance12Alpha12:
+ return GL11.GL_LUMINANCE12_ALPHA12;
+ case Luminance16Alpha16:
+ return GL11.GL_LUMINANCE16_ALPHA16;
+ case R3G3B2:
+ return GL11.GL_R3_G3_B2;
+ case RGB4:
+ return GL11.GL_RGB4;
+ case RGB5:
+ return GL11.GL_RGB5;
+ case RGB10:
+ return GL11.GL_RGB10;
+ case RGB12:
+ return GL11.GL_RGB12;
+ case RGB16:
+ return GL11.GL_RGB16;
+ case RGBA2:
+ return GL11.GL_RGBA2;
+ case RGBA4:
+ return GL11.GL_RGBA4;
+ case RGB5A1:
+ return GL11.GL_RGB5_A1;
+ case RGB10A2:
+ return GL11.GL_RGB10_A2;
+ case RGBA12:
+ return GL11.GL_RGBA12;
+ case RGBA16:
+ return GL11.GL_RGBA16;
+ case Depth:
+ return GL11.GL_DEPTH_COMPONENT;
+ case Depth16:
+ return ARBDepthTexture.GL_DEPTH_COMPONENT16_ARB;
+ case Depth24:
+ return ARBDepthTexture.GL_DEPTH_COMPONENT24_ARB;
+ case Depth32:
+ return ARBDepthTexture.GL_DEPTH_COMPONENT32_ARB;
+ case Depth32F:
+ return ARBDepthBufferFloat.GL_DEPTH_COMPONENT32F;
+ case RGB16F:
+ return ARBTextureFloat.GL_RGB16F_ARB;
+ case RGB32F:
+ return ARBTextureFloat.GL_RGB32F_ARB;
+ case RGBA16F:
+ return ARBTextureFloat.GL_RGBA16F_ARB;
+ case RGBA32F:
+ return ARBTextureFloat.GL_RGBA32F_ARB;
+ case Alpha16F:
+ return ARBTextureFloat.GL_ALPHA16F_ARB;
+ case Alpha32F:
+ return ARBTextureFloat.GL_ALPHA32F_ARB;
+ case Luminance16F:
+ return ARBTextureFloat.GL_LUMINANCE16F_ARB;
+ case Luminance32F:
+ return ARBTextureFloat.GL_LUMINANCE32F_ARB;
+ case LuminanceAlpha16F:
+ return ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB;
+ case LuminanceAlpha32F:
+ return ARBTextureFloat.GL_LUMINANCE_ALPHA32F_ARB;
+ case Intensity16F:
+ return ARBTextureFloat.GL_INTENSITY16F_ARB;
+ case Intensity32F:
+ return ARBTextureFloat.GL_INTENSITY32F_ARB;
+ case R8:
+ return ARBTextureRg.GL_R8;
+ case R16:
+ return ARBTextureRg.GL_R16;
+ case RG8:
+ return ARBTextureRg.GL_RG8;
+ case RG16:
+ return ARBTextureRg.GL_RG16;
+ case R16F:
+ return ARBTextureRg.GL_R16F;
+ case R32F:
+ return ARBTextureRg.GL_R32F;
+ case RG16F:
+ return ARBTextureRg.GL_RG16F;
+ case RG32F:
+ return ARBTextureRg.GL_RG32F;
+ case R8I:
+ return ARBTextureRg.GL_R8I;
+ case R8UI:
+ return ARBTextureRg.GL_R8UI;
+ case R16I:
+ return ARBTextureRg.GL_R16I;
+ case R16UI:
+ return ARBTextureRg.GL_R16UI;
+ case R32I:
+ return ARBTextureRg.GL_R32I;
+ case R32UI:
+ return ARBTextureRg.GL_R32UI;
+ case RG8I:
+ return ARBTextureRg.GL_RG8I;
+ case RG8UI:
+ return ARBTextureRg.GL_RG8UI;
+ case RG16I:
+ return ARBTextureRg.GL_RG16I;
+ case RG16UI:
+ return ARBTextureRg.GL_RG16UI;
+ case RG32I:
+ return ARBTextureRg.GL_RG32I;
+ case RG32UI:
+ return ARBTextureRg.GL_RG32UI;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException("Incorrect format set: " + format);
+ }
+
+ public static int getGLPixelDataType(final PixelDataType type) {
+ switch (type) {
+ case Byte:
+ return GL11.GL_BYTE;
+ case Float:
+ return GL11.GL_FLOAT;
+ case HalfFloat:
+ return ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
+ case Short:
+ return GL11.GL_SHORT;
+ case UnsignedShort:
+ return GL11.GL_UNSIGNED_SHORT;
+ case Int:
+ return GL11.GL_INT;
+ case UnsignedInt:
+ return GL11.GL_UNSIGNED_INT;
+ case UnsignedByte:
+ return GL11.GL_UNSIGNED_BYTE;
+ case UnsignedByte_3_3_2:
+ return GL12.GL_UNSIGNED_BYTE_3_3_2;
+ case UnsignedByte_2_3_3_Rev:
+ return GL12.GL_UNSIGNED_BYTE_2_3_3_REV;
+ case UnsignedShort_5_6_5:
+ return GL12.GL_UNSIGNED_SHORT_5_6_5;
+ case UnsignedShort_5_6_5_Rev:
+ return GL12.GL_UNSIGNED_SHORT_5_6_5_REV;
+ case UnsignedShort_4_4_4_4:
+ return GL12.GL_UNSIGNED_SHORT_4_4_4_4;
+ case UnsignedShort_4_4_4_4_Rev:
+ return GL12.GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ case UnsignedShort_5_5_5_1:
+ return GL12.GL_UNSIGNED_SHORT_5_5_5_1;
+ case UnsignedShort_1_5_5_5_Rev:
+ return GL12.GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ case UnsignedInt_8_8_8_8:
+ return GL12.GL_UNSIGNED_INT_8_8_8_8;
+ case UnsignedInt_8_8_8_8_Rev:
+ return GL12.GL_UNSIGNED_INT_8_8_8_8_REV;
+ case UnsignedInt_10_10_10_2:
+ return GL12.GL_UNSIGNED_INT_10_10_10_2;
+ case UnsignedInt_2_10_10_10_Rev:
+ return GL12.GL_UNSIGNED_INT_2_10_10_10_REV;
+ default:
+ throw new Error("Unhandled type: " + type);
+ }
+ }
+
+ public static int getGLPixelFormat(final ImageDataFormat format) {
+ switch (format) {
+ case RGBA:
+ return GL11.GL_RGBA;
+ case RGB:
+ return GL11.GL_RGB;
+ case RG:
+ return ARBTextureRg.GL_RG;
+ case Alpha:
+ return GL11.GL_ALPHA;
+ case Luminance:
+ return GL11.GL_LUMINANCE;
+ case Intensity:
+ return GL11.GL_INTENSITY;
+ case LuminanceAlpha:
+ return GL11.GL_LUMINANCE_ALPHA;
+ case Depth:
+ return GL11.GL_DEPTH_COMPONENT;
+ case BGR:
+ return GL12.GL_BGR;
+ case BGRA:
+ return GL12.GL_BGRA;
+ case Red:
+ return GL11.GL_RED;
+ case Blue:
+ return GL11.GL_BLUE;
+ case Green:
+ return GL11.GL_GREEN;
+ case ColorIndex:
+ return GL11.GL_COLOR_INDEX;
+ case StencilIndex:
+ return GL11.GL_STENCIL_INDEX;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException("Incorrect format set: " + format);
+ }
+
+ public static int getGLPixelFormatFromStoreFormat(final TextureStoreFormat format) {
+ switch (format) {
+ case RGBA2:
+ case RGBA4:
+ case RGBA8:
+ case RGB5A1:
+ case RGB10A2:
+ case RGBA12:
+ case RGBA16:
+ case CompressedRGBA:
+ case NativeDXT1A:
+ case NativeDXT3:
+ case NativeDXT5:
+ case RGBA16F:
+ case RGBA32F:
+ return GL11.GL_RGBA;
+ case R3G3B2:
+ case RGB4:
+ case RGB5:
+ case RGB8:
+ case RGB10:
+ case RGB12:
+ case RGB16:
+ case CompressedRGB:
+ case NativeDXT1:
+ case RGB16F:
+ case RGB32F:
+ return GL11.GL_RGB;
+ case Alpha4:
+ case Alpha8:
+ case Alpha12:
+ case Alpha16:
+ case Alpha16F:
+ case Alpha32F:
+ return GL11.GL_ALPHA;
+ case Luminance4:
+ case Luminance8:
+ case Luminance12:
+ case Luminance16:
+ case Luminance16F:
+ case Luminance32F:
+ case CompressedLuminance:
+ case NativeLATC_L:
+ return GL11.GL_LUMINANCE;
+ case Intensity4:
+ case Intensity8:
+ case Intensity12:
+ case Intensity16:
+ case Intensity16F:
+ case Intensity32F:
+ return GL11.GL_INTENSITY;
+ case Luminance4Alpha4:
+ case Luminance6Alpha2:
+ case Luminance8Alpha8:
+ case Luminance12Alpha4:
+ case Luminance12Alpha12:
+ case Luminance16Alpha16:
+ case LuminanceAlpha16F:
+ case LuminanceAlpha32F:
+ case CompressedLuminanceAlpha:
+ case NativeLATC_LA:
+ return GL11.GL_LUMINANCE_ALPHA;
+ case Depth:
+ case Depth16:
+ case Depth24:
+ case Depth32:
+ case Depth32F:
+ return GL11.GL_DEPTH_COMPONENT;
+ case R8:
+ case R16:
+ case R16F:
+ case R32F:
+ case R8I:
+ case R8UI:
+ case R16I:
+ case R16UI:
+ case R32I:
+ case R32UI:
+ case CompressedRed:
+ return ARBTextureRg.GL_RED;
+ case RG8:
+ case RG16:
+ case RG16F:
+ case RG32F:
+ case RG8I:
+ case RG8UI:
+ case RG16I:
+ case RG16UI:
+ case RG32I:
+ case RG32UI:
+ case CompressedRG:
+ return ARBTextureRg.GL_RG;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException("Incorrect format set: " + format);
+ }
+
+ public static int getGLDepthTextureMode(final DepthTextureMode mode) {
+ switch (mode) {
+ case Alpha:
+ return GL11.GL_ALPHA;
+ case Luminance:
+ return GL11.GL_LUMINANCE;
+ case Intensity:
+ default:
+ return GL11.GL_INTENSITY;
+ }
+ }
+
+ public static int getGLDepthTextureCompareMode(final DepthTextureCompareMode mode) {
+ switch (mode) {
+ case RtoTexture:
+ return ARBShadow.GL_COMPARE_R_TO_TEXTURE_ARB;
+ case None:
+ default:
+ return GL11.GL_NONE;
+ }
+ }
+
+ public static int getGLDepthTextureCompareFunc(final DepthTextureCompareFunc func) {
+ switch (func) {
+ case GreaterThanEqual:
+ return GL11.GL_GEQUAL;
+ case LessThanEqual:
+ default:
+ return GL11.GL_LEQUAL;
+ }
+ }
+
+ public static int getGLMagFilter(final MagnificationFilter magFilter) {
+ switch (magFilter) {
+ case Bilinear:
+ return GL11.GL_LINEAR;
+ case NearestNeighbor:
+ default:
+ return GL11.GL_NEAREST;
+
+ }
+ }
+
+ public static int getGLMinFilter(final MinificationFilter filter) {
+ switch (filter) {
+ case BilinearNoMipMaps:
+ return GL11.GL_LINEAR;
+ case Trilinear:
+ return GL11.GL_LINEAR_MIPMAP_LINEAR;
+ case BilinearNearestMipMap:
+ return GL11.GL_LINEAR_MIPMAP_NEAREST;
+ case NearestNeighborNoMipMaps:
+ return GL11.GL_NEAREST;
+ case NearestNeighborNearestMipMap:
+ return GL11.GL_NEAREST_MIPMAP_NEAREST;
+ case NearestNeighborLinearMipMap:
+ return GL11.GL_NEAREST_MIPMAP_LINEAR;
+ }
+ throw new IllegalArgumentException("invalid MinificationFilter type: " + filter);
+ }
+
+ public static int getGLEnvMode(final ApplyMode apply) {
+ switch (apply) {
+ case Replace:
+ return GL11.GL_REPLACE;
+ case Blend:
+ return GL11.GL_BLEND;
+ case Combine:
+ return ARBTextureEnvCombine.GL_COMBINE_ARB;
+ case Decal:
+ return GL11.GL_DECAL;
+ case Add:
+ return GL11.GL_ADD;
+ case Modulate:
+ return GL11.GL_MODULATE;
+ }
+ throw new IllegalArgumentException("invalid ApplyMode type: " + apply);
+ }
+
+ public static int getPerspHint(final CorrectionType type) {
+ switch (type) {
+ case Perspective:
+ return GL11.GL_NICEST;
+ case Affine:
+ return GL11.GL_FASTEST;
+ }
+ throw new IllegalArgumentException("unknown correction type: " + type);
+ }
+
+ public static int getGLCombineOpRGB(final CombinerOperandRGB operand) {
+ switch (operand) {
+ case SourceColor:
+ return GL11.GL_SRC_COLOR;
+ case OneMinusSourceColor:
+ return GL11.GL_ONE_MINUS_SRC_COLOR;
+ case SourceAlpha:
+ return GL11.GL_SRC_ALPHA;
+ case OneMinusSourceAlpha:
+ return GL11.GL_ONE_MINUS_SRC_ALPHA;
+ }
+ throw new IllegalArgumentException("invalid CombinerOperandRGB type: " + operand);
+ }
+
+ public static int getGLCombineOpAlpha(final CombinerOperandAlpha operand) {
+ switch (operand) {
+ case SourceAlpha:
+ return GL11.GL_SRC_ALPHA;
+ case OneMinusSourceAlpha:
+ return GL11.GL_ONE_MINUS_SRC_ALPHA;
+ }
+ throw new IllegalArgumentException("invalid CombinerOperandAlpha type: " + operand);
+ }
+
+ public static int getGLCombineSrc(final CombinerSource combineSrc) {
+ switch (combineSrc) {
+ case CurrentTexture:
+ return GL11.GL_TEXTURE;
+ case PrimaryColor:
+ return ARBTextureEnvCombine.GL_PRIMARY_COLOR_ARB;
+ case Constant:
+ return ARBTextureEnvCombine.GL_CONSTANT_ARB;
+ case Previous:
+ return ARBTextureEnvCombine.GL_PREVIOUS_ARB;
+ case TextureUnit0:
+ return ARBMultitexture.GL_TEXTURE0_ARB;
+ case TextureUnit1:
+ return ARBMultitexture.GL_TEXTURE1_ARB;
+ case TextureUnit2:
+ return ARBMultitexture.GL_TEXTURE2_ARB;
+ case TextureUnit3:
+ return ARBMultitexture.GL_TEXTURE3_ARB;
+ case TextureUnit4:
+ return ARBMultitexture.GL_TEXTURE4_ARB;
+ case TextureUnit5:
+ return ARBMultitexture.GL_TEXTURE5_ARB;
+ case TextureUnit6:
+ return ARBMultitexture.GL_TEXTURE6_ARB;
+ case TextureUnit7:
+ return ARBMultitexture.GL_TEXTURE7_ARB;
+ case TextureUnit8:
+ return ARBMultitexture.GL_TEXTURE8_ARB;
+ case TextureUnit9:
+ return ARBMultitexture.GL_TEXTURE9_ARB;
+ case TextureUnit10:
+ return ARBMultitexture.GL_TEXTURE10_ARB;
+ case TextureUnit11:
+ return ARBMultitexture.GL_TEXTURE11_ARB;
+ case TextureUnit12:
+ return ARBMultitexture.GL_TEXTURE12_ARB;
+ case TextureUnit13:
+ return ARBMultitexture.GL_TEXTURE13_ARB;
+ case TextureUnit14:
+ return ARBMultitexture.GL_TEXTURE14_ARB;
+ case TextureUnit15:
+ return ARBMultitexture.GL_TEXTURE15_ARB;
+ case TextureUnit16:
+ return ARBMultitexture.GL_TEXTURE16_ARB;
+ case TextureUnit17:
+ return ARBMultitexture.GL_TEXTURE17_ARB;
+ case TextureUnit18:
+ return ARBMultitexture.GL_TEXTURE18_ARB;
+ case TextureUnit19:
+ return ARBMultitexture.GL_TEXTURE19_ARB;
+ case TextureUnit20:
+ return ARBMultitexture.GL_TEXTURE20_ARB;
+ case TextureUnit21:
+ return ARBMultitexture.GL_TEXTURE21_ARB;
+ case TextureUnit22:
+ return ARBMultitexture.GL_TEXTURE22_ARB;
+ case TextureUnit23:
+ return ARBMultitexture.GL_TEXTURE23_ARB;
+ case TextureUnit24:
+ return ARBMultitexture.GL_TEXTURE24_ARB;
+ case TextureUnit25:
+ return ARBMultitexture.GL_TEXTURE25_ARB;
+ case TextureUnit26:
+ return ARBMultitexture.GL_TEXTURE26_ARB;
+ case TextureUnit27:
+ return ARBMultitexture.GL_TEXTURE27_ARB;
+ case TextureUnit28:
+ return ARBMultitexture.GL_TEXTURE28_ARB;
+ case TextureUnit29:
+ return ARBMultitexture.GL_TEXTURE29_ARB;
+ case TextureUnit30:
+ return ARBMultitexture.GL_TEXTURE30_ARB;
+ case TextureUnit31:
+ return ARBMultitexture.GL_TEXTURE31_ARB;
+ }
+ throw new IllegalArgumentException("invalid CombinerSource type: " + combineSrc);
+ }
+
+ public static int getGLCombineFuncAlpha(final CombinerFunctionAlpha combineFunc) {
+ switch (combineFunc) {
+ case Modulate:
+ return GL11.GL_MODULATE;
+ case Replace:
+ return GL11.GL_REPLACE;
+ case Add:
+ return GL11.GL_ADD;
+ case AddSigned:
+ return ARBTextureEnvCombine.GL_ADD_SIGNED_ARB;
+ case Subtract:
+ return ARBTextureEnvCombine.GL_SUBTRACT_ARB;
+ case Interpolate:
+ return ARBTextureEnvCombine.GL_INTERPOLATE_ARB;
+ }
+ throw new IllegalArgumentException("invalid CombinerFunctionAlpha type: " + combineFunc);
+ }
+
+ public static int getGLCombineFuncRGB(final CombinerFunctionRGB combineFunc) {
+ switch (combineFunc) {
+ case Modulate:
+ return GL11.GL_MODULATE;
+ case Replace:
+ return GL11.GL_REPLACE;
+ case Add:
+ return GL11.GL_ADD;
+ case AddSigned:
+ return ARBTextureEnvCombine.GL_ADD_SIGNED_ARB;
+ case Subtract:
+ return ARBTextureEnvCombine.GL_SUBTRACT_ARB;
+ case Interpolate:
+ return ARBTextureEnvCombine.GL_INTERPOLATE_ARB;
+ case Dot3RGB:
+ return ARBTextureEnvDot3.GL_DOT3_RGB_ARB;
+ case Dot3RGBA:
+ return ARBTextureEnvDot3.GL_DOT3_RGBA_ARB;
+ }
+ throw new IllegalArgumentException("invalid CombinerFunctionRGB type: " + combineFunc);
+ }
+}
diff --git a/ardor3d-lwjgl/src/main/native/linux/libjinput-linux.so b/ardor3d-lwjgl/src/main/native/linux/libjinput-linux.so
new file mode 100644
index 0000000..b6f1090
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/linux/libjinput-linux.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/linux/libjinput-linux64.so b/ardor3d-lwjgl/src/main/native/linux/libjinput-linux64.so
new file mode 100644
index 0000000..5fb7265
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/linux/libjinput-linux64.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/linux/liblwjgl.so b/ardor3d-lwjgl/src/main/native/linux/liblwjgl.so
new file mode 100644
index 0000000..b5271dd
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/linux/liblwjgl.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/linux/liblwjgl64.so b/ardor3d-lwjgl/src/main/native/linux/liblwjgl64.so
new file mode 100644
index 0000000..2ba3daa
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/linux/liblwjgl64.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/linux/libopenal.so b/ardor3d-lwjgl/src/main/native/linux/libopenal.so
new file mode 100644
index 0000000..2b5a8d5
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/linux/libopenal.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/linux/libopenal64.so b/ardor3d-lwjgl/src/main/native/linux/libopenal64.so
new file mode 100644
index 0000000..ce1c38f
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/linux/libopenal64.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/macosx/libjinput-osx.jnilib b/ardor3d-lwjgl/src/main/native/macosx/libjinput-osx.jnilib
new file mode 100644
index 0000000..51c089c
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/macosx/libjinput-osx.jnilib
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/macosx/liblwjgl.jnilib b/ardor3d-lwjgl/src/main/native/macosx/liblwjgl.jnilib
new file mode 100644
index 0000000..8d8c446
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/macosx/liblwjgl.jnilib
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/solaris/liblwjgl.so b/ardor3d-lwjgl/src/main/native/solaris/liblwjgl.so
new file mode 100644
index 0000000..d8155d1
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/solaris/liblwjgl.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/solaris/libopenal.so b/ardor3d-lwjgl/src/main/native/solaris/libopenal.so
new file mode 100644
index 0000000..50edb3e
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/solaris/libopenal.so
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/win32/OpenAL32.dll b/ardor3d-lwjgl/src/main/native/win32/OpenAL32.dll
new file mode 100644
index 0000000..8dc9fa5
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/win32/OpenAL32.dll
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/win32/jinput-dx8.dll b/ardor3d-lwjgl/src/main/native/win32/jinput-dx8.dll
new file mode 100644
index 0000000..0ad824b
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/win32/jinput-dx8.dll
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/win32/jinput-raw.dll b/ardor3d-lwjgl/src/main/native/win32/jinput-raw.dll
new file mode 100644
index 0000000..2a014f6
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/win32/jinput-raw.dll
Binary files differ
diff --git a/ardor3d-lwjgl/src/main/native/win32/lwjgl.dll b/ardor3d-lwjgl/src/main/native/win32/lwjgl.dll
new file mode 100644
index 0000000..387c60d
--- /dev/null
+++ b/ardor3d-lwjgl/src/main/native/win32/lwjgl.dll
Binary files differ