Commits

Michael Ludwig committed 5c1b9e2

Test texturing, and fix some bugs involving the TGA loader, as well as some event handling bugs in JoglOnscreenSurface.

  • Participants
  • Parent commits a344f12

Comments (0)

Files changed (24)

data/textures/squiggles.tga

Binary file added.

src/com/ferox/renderer/DisplayOptions.java

 	public AntiAliasMode getAntiAliasing() {
 		return this.aaMode;
 	}
+	
+	@Override
+	public String toString() {
+		return this.pixelFormat + " " + this.depthFormat + " " + this.stencilFormat + " " + this.aaMode;
+	}
 }

src/com/ferox/renderer/impl/jogl/JoglOnscreenSurface.java

 	private DisplayOptions options;
 	private boolean finalizeOptions;
 	
+	private boolean iconified;
+	
 	private boolean enableVsync;
 	private boolean updateVsync;
 	
 		
 		this.enableVsync = false;
 		this.updateVsync = true;
+		
+		this.iconified = false;
 	}
 	
 	/** Return the frame object that contains this surface's GLCanvas. */
 	
 	@Override
 	public boolean isVisible() {
-		return !this.isDestroyed() && this.getFrame().isVisible();
+		return !this.isDestroyed() && !this.iconified;
 	}
 	
 	/** Do a half-cleanup and notify the factory that we've been destroyed. */
 	@Override
-	public void windowClosed(WindowEvent e) {
-		 // the factory will make sure everything is destroyed properly on the correct thread
-		this.getFactory().notifyOnscreenSurfaceZombie(this);
-	}
+	public void windowClosed(WindowEvent e) { }
 
 	/* Unfortunate consequences of being a window listener. */
 	
 	public void windowActivated(WindowEvent e) { }
 	
 	@Override
-	public void windowClosing(WindowEvent e) { }
+	public void windowClosing(WindowEvent e) {
+		 // the factory will make sure everything is destroyed properly on the correct thread
+		this.getFactory().notifyOnscreenSurfaceZombie(this);
+	}
 
 	@Override
 	public void windowDeactivated(WindowEvent e) { }
 
 	@Override
-	public void windowDeiconified(WindowEvent e) { }
+	public void windowDeiconified(WindowEvent e) { 
+		this.iconified = false;
+	}
 
 	@Override
-	public void windowIconified(WindowEvent e) { }
+	public void windowIconified(WindowEvent e) { 
+		this.iconified = true;
+	}
 
 	@Override
 	public void windowOpened(WindowEvent e) { }

src/com/ferox/renderer/impl/jogl/JoglSurfaceFactory.java

 import javax.media.opengl.GLDrawableFactory;
 import javax.media.opengl.GLPbuffer;
 import javax.media.opengl.Threading;
+import javax.media.opengl.TraceGL;
 import javax.swing.SwingUtilities;
 
 import com.ferox.math.Color;
 			GL gl = this.currentGL;
 
 			Color clearColor = this.currentSurface.getClearColor();
-			if (record.clearColor.equals(clearColor)) {
+			if (!clearColor.equals(record.clearColor)) {
 				gl.glClearColor(clearColor.getRed(), clearColor.getGreen(), clearColor.getBlue(), clearColor.getAlpha());
 				clearColor.get(record.clearColor);
 			}
 				res = c.makeCurrent();
 			}
 			this.currentContext = context;
-			this.currentGL = (this.debugGL ? new DebugGL(c.getGL()) : c.getGL());
+			this.currentGL = (this.debugGL ? new TraceGL(new DebugGL(c.getGL()), System.out) : c.getGL());
 		}
 	}
 	

src/com/ferox/renderer/impl/jogl/JoglWindowSurface.java

 					Frame f = new Frame();
 					f.setResizable(resizable);
 					f.setUndecorated(undecorated);
-					
+
 					f.add(JoglWindowSurface.this.getGLCanvas());
 					f.setBounds(x, y, Math.max(width, 1), Math.max(height, 1));
 					f.setVisible(true);

src/com/ferox/renderer/impl/jogl/drivers/JoglLightingStateDriver.java

 	private static final int MAX_LIGHTS = 8;
 	
 	private final Transform cache;
+	private final Light[] appliedLights;
 	private Vector3f p;
 	
 	public JoglLightingStateDriver(JoglSurfaceFactory factory) {
 		super(null, Light.class, Math.min(MAX_LIGHTS, factory.getRenderer().getCapabilities().getMaxActiveLights()), factory);
 		this.cache = new Transform();
+		this.appliedLights = new Light[Math.min(MAX_LIGHTS, factory.getRenderer().getCapabilities().getMaxActiveLights())];
 	}
 
 	@Override
+	public void reset() {
+		super.reset();
+		
+		// reset the applied lights, since it's likely that the
+		// view transform has changed.
+		for (int i = 0; i < this.appliedLights.length; i++) {
+			this.appliedLights[i] = null;
+		}
+	}
+	
+	@Override
 	protected void apply(GL gl, JoglContext context, int unit, Light next) {
 		LightRecord lr = context.getStateRecord().lightRecord.lightUnits[unit];
 		int glUnit = GL.GL_LIGHT0 + unit;
 				gl.glEnable(glUnit);
 			}
 			
-			// set lighting colors
-			// ambient
-			Color c = next.getAmbient();
-			if (!c.equals(lr.ambient)) {
-				c.get(lr.ambient);
-				gl.glLightfv(glUnit, GL.GL_AMBIENT, lr.ambient, 0);
+			// only make the other changes if the light is different
+			if (this.appliedLights[unit] != next) {
+				this.appliedLights[unit] = next;
+				
+				// set lighting colors
+				// ambient
+				Color c = next.getAmbient();
+				if (!c.equals(lr.ambient)) {
+					c.get(lr.ambient);
+					gl.glLightfv(glUnit, GL.GL_AMBIENT, lr.ambient, 0);
+				}
+				// diffuse
+				c = next.getDiffuse();
+				if (!c.equals(lr.diffuse)) {
+					c.get(lr.diffuse);
+					gl.glLightfv(glUnit, GL.GL_DIFFUSE, lr.diffuse, 0);
+				}
+				// specular
+				c = next.getSpecular();
+				if (!c.equals(lr.specular)) {
+					c.get(lr.specular);
+					gl.glLightfv(glUnit, GL.GL_SPECULAR, lr.specular, 0);
+				}
+
+				// setup other properties
+				if (next instanceof SpotLight)
+					this.setupSpotLight(gl, lr, glUnit, (SpotLight) next);
+				else if (next instanceof DirectionLight)
+					this.setupDirectionLight(gl, lr, glUnit, (DirectionLight) next);
 			}
-			// diffuse
-			c = next.getDiffuse();
-			if (!c.equals(lr.diffuse)) {
-				c.get(lr.diffuse);
-				gl.glLightfv(glUnit, GL.GL_DIFFUSE, lr.diffuse, 0);
-			}
-			// specular
-			c = next.getSpecular();
-			if (!c.equals(lr.specular)) {
-				c.get(lr.specular);
-				gl.glLightfv(glUnit, GL.GL_SPECULAR, lr.specular, 0);
-			}
-			
-			// setup other properties
-			if (next instanceof SpotLight)
-				this.setupSpotLight(gl, lr, glUnit, (SpotLight) next);
-			else if (next instanceof DirectionLight)
-				this.setupDirectionLight(gl, lr, glUnit, (DirectionLight) next);
 			// else nothing we can do
 		}
 	}
 		lr.position[3] = 0f;
 		
 		// setup of the direction
-		this.cache.setTranslation(0f, 0f, 0f);
-		this.cache.setRotation(light.getWorldTransform().getRotation());
-		this.cache.mul(this.factory.getCurrentView(), this.cache);
-		
-		// load computed modelview matrix onto stack
+		this.cache.mul(this.factory.getCurrentView(), light.getWorldTransform());		
 		this.factory.getTransformDriver().loadMatrix(gl, this.cache);
 		
 		gl.glLightfv(glUnit, GL.GL_POSITION, lr.position, 0);		

src/com/ferox/renderer/impl/jogl/drivers/JoglTexture1DResourceDriver.java

 import com.ferox.renderer.RenderCapabilities;
 import com.ferox.renderer.impl.ResourceData;
 import com.ferox.renderer.impl.ResourceDriver;
-import com.ferox.renderer.impl.jogl.JoglContext;
 import com.ferox.renderer.impl.jogl.JoglSurfaceFactory;
+import com.ferox.renderer.impl.jogl.record.JoglStateRecord;
 import com.ferox.renderer.impl.jogl.record.PackUnpackRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord.TextureUnit;
 	
 	@Override
 	public void cleanUp(Resource resource, ResourceData data) {
-		GL gl = this.factory.getCurrentContext().getContext().getGL();
+		GL gl = this.factory.getGL();
 		TextureHandle handle = (TextureHandle) data.getHandle();
 		
 		// a T_1D should always have a valid handle
 
 	@Override
 	public void update(Resource resource, ResourceData data, boolean fullUpdate) {
-		JoglContext current = this.factory.getCurrentContext();
-
-		GL gl = current.getContext().getGL();
-		PackUnpackRecord pr = current.getStateRecord().packRecord;
-		TextureRecord tr = current.getStateRecord().textureRecord;
+		JoglStateRecord sr = this.factory.getCurrentContext().getStateRecord();
+		
+		GL gl = this.factory.getGL();
+		PackUnpackRecord pr = sr.packRecord;
+		TextureRecord tr = sr.textureRecord;
 
 		TextureHandle handle = (TextureHandle) data.getHandle();
 		Texture1D t1d = (Texture1D) resource;

src/com/ferox/renderer/impl/jogl/drivers/JoglTexture2DResourceDriver.java

 import com.ferox.renderer.RenderCapabilities;
 import com.ferox.renderer.impl.ResourceData;
 import com.ferox.renderer.impl.ResourceDriver;
-import com.ferox.renderer.impl.jogl.JoglContext;
 import com.ferox.renderer.impl.jogl.JoglSurfaceFactory;
+import com.ferox.renderer.impl.jogl.record.JoglStateRecord;
 import com.ferox.renderer.impl.jogl.record.PackUnpackRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord.TextureUnit;
 	
 	@Override
 	public void cleanUp(Resource resource, ResourceData data) {
-		GL gl = this.factory.getCurrentContext().getContext().getGL();
+		GL gl = this.factory.getGL();
 		TextureHandle handle = (TextureHandle) data.getHandle();
 		
 		if (handle != null) {
 
 	@Override
 	public void update(Resource resource, ResourceData data, boolean fullUpdate) {
-		JoglContext current = this.factory.getCurrentContext();
+		JoglStateRecord sr = this.factory.getCurrentContext().getStateRecord();
 		
-		GL gl = current.getContext().getGL();
-		PackUnpackRecord pr = current.getStateRecord().packRecord;
-		TextureRecord tr = current.getStateRecord().textureRecord;
+		GL gl = this.factory.getGL();
+		PackUnpackRecord pr = sr.packRecord;
+		TextureRecord tr = sr.textureRecord;
 		
 		if (data.getStatus() != Status.ERROR) {
 			// only do an update if we haven't got an error

src/com/ferox/renderer/impl/jogl/drivers/JoglTexture3DResourceDriver.java

 import com.ferox.renderer.RenderCapabilities;
 import com.ferox.renderer.impl.ResourceData;
 import com.ferox.renderer.impl.ResourceDriver;
-import com.ferox.renderer.impl.jogl.JoglContext;
 import com.ferox.renderer.impl.jogl.JoglSurfaceFactory;
+import com.ferox.renderer.impl.jogl.record.JoglStateRecord;
 import com.ferox.renderer.impl.jogl.record.PackUnpackRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord.TextureUnit;
 	
 	@Override
 	public void cleanUp(Resource resource, ResourceData data) {
-		GL gl = this.factory.getCurrentContext().getContext().getGL();
+		GL gl = this.factory.getGL();
 		TextureHandle handle = (TextureHandle) data.getHandle();
 		
 		this.imageDriver.destroyTexture(gl, handle);
 
 	@Override
 	public void update(Resource resource, ResourceData data, boolean fullUpdate) {
-		JoglContext current = this.factory.getCurrentContext();
-		
-		GL gl = current.getContext().getGL();
-		PackUnpackRecord pr = current.getStateRecord().packRecord;
-		TextureRecord tr = current.getStateRecord().textureRecord;
+		JoglStateRecord sr = this.factory.getCurrentContext().getStateRecord();
+
+		GL gl = this.factory.getGL();
+		PackUnpackRecord pr = sr.packRecord;
+		TextureRecord tr = sr.textureRecord;
 
 		TextureHandle handle = (TextureHandle) data.getHandle();
 		Texture3D t3d = (Texture3D) resource;

src/com/ferox/renderer/impl/jogl/drivers/JoglTextureCubeMapResourceDriver.java

 import com.ferox.renderer.impl.ResourceData;
 import com.ferox.renderer.impl.ResourceDriver;
 import com.ferox.renderer.impl.jogl.EnumUtil;
-import com.ferox.renderer.impl.jogl.JoglContext;
 import com.ferox.renderer.impl.jogl.JoglSurfaceFactory;
+import com.ferox.renderer.impl.jogl.record.JoglStateRecord;
 import com.ferox.renderer.impl.jogl.record.PackUnpackRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord;
 import com.ferox.renderer.impl.jogl.record.TextureRecord.TextureUnit;
 	
 	@Override
 	public void cleanUp(Resource resource, ResourceData data) {
-		GL gl = this.factory.getCurrentContext().getContext().getGL();
+		GL gl = this.factory.getGL();
 		TextureHandle handle = (TextureHandle) data.getHandle();
 		
 		if (handle != null) {
 
 	@Override
 	public void update(Resource resource, ResourceData data, boolean fullUpdate) {
-		JoglContext current = this.factory.getCurrentContext();
+		JoglStateRecord sr = this.factory.getCurrentContext().getStateRecord();
 		
-		GL gl = current.getContext().getGL();
-		PackUnpackRecord pr = current.getStateRecord().packRecord;
-		TextureRecord tr = current.getStateRecord().textureRecord;
+		GL gl = this.factory.getGL();
+		PackUnpackRecord pr = sr.packRecord;
+		TextureRecord tr = sr.textureRecord;
 		
 		if (data.getStatus() != Status.ERROR) {
 			// only do an update if we haven't got an error
 			// proceed with glTexImage
 			this.imageDriver.setUnpackRegion(gl, pr, 0, 0, 0, s, s);
 			if (handle.glSrcFormat > 0)
-				gl.glTexImage2D(handle.glTarget, level, handle.glDstFormat, s, s, 0, handle.glSrcFormat, handle.glType, this.imageDriver.wrap(bd));
+				gl.glTexImage2D(EnumUtil.getGLCubeFace(face), level, handle.glDstFormat, s, s, 0, handle.glSrcFormat, handle.glType, this.imageDriver.wrap(bd));
 			else
-				gl.glCompressedTexImage2D(handle.glTarget, level, handle.glDstFormat, s, s, 0, bd.getCapacity(), this.imageDriver.wrap(bd));
+				gl.glCompressedTexImage2D(EnumUtil.getGLCubeFace(face), level, handle.glDstFormat, s, s, 0, bd.getCapacity(), this.imageDriver.wrap(bd));
 		} else if (newTex) {
 			// we'll just allocate an empty image
 			if (handle.glSrcFormat > 0)
-				gl.glTexImage2D(handle.glTarget, level, handle.glDstFormat, s, s, 0, handle.glSrcFormat, handle.glType, null);
+				gl.glTexImage2D(EnumUtil.getGLCubeFace(face), level, handle.glDstFormat, s, s, 0, handle.glSrcFormat, handle.glType, null);
 			else
-				gl.glCompressedTexImage2D(handle.glTarget, level, handle.glDstFormat, s, s, 0, tex.getFormat().getBufferSize(s, s, 0), null);
+				gl.glCompressedTexImage2D(EnumUtil.getGLCubeFace(face), level, handle.glDstFormat, s, s, 0, tex.getFormat().getBufferSize(s, s, 0), null);
 		} // else .. ignore this layer
 	}
 	

src/com/ferox/renderer/impl/jogl/drivers/JoglTextureStateDriver.java

 	
 	private MultiTexture singleUnit; // used to store a Texture that's in lastApplied or queuedTexture
 	private boolean lastAppliedDirty; // will be true if lastApplied == singleUnit && queuedTexture == singleUnit && singleUnit.0th is changed
-	
+		
 	private JoglSurfaceFactory factory;
 	
 	public JoglTextureStateDriver(JoglSurfaceFactory factory) {
 		if (this.lastApplied == this.singleUnit && this.queuedTexture != this.singleUnit)
 			this.singleUnit.setTexture(0, null); // clear reference here, since we don't need it anymore
 		this.lastApplied = this.queuedTexture;
+		
+		this.reset();
 	}
 
 	@Override
 				unit = tex.getUnit();
 				// must make sure it's a valid unit, and that it's a different Texture instance
 				if (unit < tr.textureUnits.length &&
-					(this.lastApplied == null || this.lastApplied.getTexture(unit) != tex.getData())) {
+					(this.lastApplied == null || this.lastAppliedDirty || this.lastApplied.getTexture(unit) != tex.getData())) {
 					// bind the texture
-					activeTex = applyTexture(gl, renderer, activeTex, unit, tr.textureUnits[unit], tex.getData());
+					activeTex = this.applyTexture(gl, renderer, activeTex, unit, tr.textureUnits[unit], tex.getData());
 				}
 			}
 		}
 				if (unit < tr.textureUnits.length
 				    && (toApply == null || next.getTexture(unit) == null)) {
 					// unbind the texture by passing in null
-					activeTex = applyTexture(gl, renderer, activeTex, unit, tr.textureUnits[unit], null);
+					activeTex = this.applyTexture(gl, renderer, activeTex, unit, tr.textureUnits[unit], null);
 				}
 			}
 		}
 			unit.isTextureMatrixIdentity = false;
 		}
 		// tc_s
-		setTexGen(gl, GL.GL_S, GL.GL_TEXTURE_GEN_S, unit.texGenS, tex.getTexCoordGenS(), tex.getTexCoordGenPlaneS());
+		this.setTexGen(gl, GL.GL_S, GL.GL_TEXTURE_GEN_S, unit.texGenS, tex.getTexCoordGenS(), tex.getTexCoordGenPlaneS());
 		// tc_t
-		setTexGen(gl, GL.GL_T, GL.GL_TEXTURE_GEN_T, unit.texGenT, tex.getTexCoordGenT(), tex.getTexCoordGenPlaneT());
+		this.setTexGen(gl, GL.GL_T, GL.GL_TEXTURE_GEN_T, unit.texGenT, tex.getTexCoordGenT(), tex.getTexCoordGenPlaneT());
 		// tc_r
-		setTexGen(gl, GL.GL_R, GL.GL_TEXTURE_GEN_R, unit.texGenR, tex.getTexCoordGenR(), tex.getTexCoordGenPlaneR());
+		this.setTexGen(gl, GL.GL_R, GL.GL_TEXTURE_GEN_R, unit.texGenR, tex.getTexCoordGenR(), tex.getTexCoordGenPlaneR());
 		
 		// env color
 		Color blend = tex.getTextureEnvColor();
 			unit.enableTarget = false;
 		}
 		
-		if (id != 0) {
+		if (glTarget > 0 && id > 0) {
 			if (!unit.enableTarget) {
 				gl.glEnable(glTarget);
 				unit.enabledTarget = glTarget;
 	 * GL_S/T/R, and boolMode would then be GL_TEXTURE_GEN_x, and tgr is the
 	 * matching record.  If genMode is NONE, generation is disabled, otherwise
 	 * its enabled and set, possibly resetting the texture plane. */
-	private static void setTexGen(GL gl, int coord, int boolMode, TextureGenRecord tgr, TexCoordGen genMode, Plane eyeOrObject) {
+	private void setTexGen(GL gl, int coord, int boolMode, TextureGenRecord tgr, TexCoordGen genMode, Plane eyeOrObject) {
 		if (genMode == TexCoordGen.NONE) {
 			// disable coordinate generation for this coord
 			if (tgr.enableTexGen) {
 				gl.glDisable(boolMode);
 			}
 		} else {
+			// possibly set the planes
+			if (genMode == TexCoordGen.EYE) {
+				// always push the eye-plane through
+				this.factory.getTransformDriver().loadMatrix(gl, this.factory.getCurrentView());
+				//gl.glLoadIdentity();
+				eyeOrObject.get(tgr.eyePlane);
+				gl.glTexGenfv(coord, GL.GL_EYE_PLANE, tgr.eyePlane, 0);
+			} else if (genMode == TexCoordGen.OBJECT) {
+				if (!eyeOrObject.equals(tgr.objectPlane)) {
+					eyeOrObject.get(tgr.objectPlane);
+					gl.glTexGenfv(coord, GL.GL_OBJECT_PLANE, tgr.objectPlane, 0);
+				}
+			}
 			// set the mode
 			int mode = EnumUtil.getGLTexGen(genMode);
 			if (mode != tgr.textureGenMode) {
-				gl.glTexEnvi(coord, GL.GL_TEXTURE_GEN_MODE, mode);
+				gl.glTexGeni(coord, GL.GL_TEXTURE_GEN_MODE, mode);
 				tgr.textureGenMode = mode;
 			}
 			// enable it
 				gl.glEnable(boolMode);
 				tgr.enableTexGen = true;
 			}
-			// possibly set the planes
-			if (genMode == TexCoordGen.EYE) {
-				if (!eyeOrObject.equals(tgr.eyePlane)) {
-					eyeOrObject.get(tgr.eyePlane);
-					gl.glTexEnvfv(coord, GL.GL_EYE_PLANE, tgr.eyePlane, 0);
-				}
-			} else if (genMode == TexCoordGen.OBJECT) {
-				if (!eyeOrObject.equals(tgr.objectPlane)) {
-					eyeOrObject.get(tgr.objectPlane);
-					gl.glTexEnvfv(coord, GL.GL_OBJECT_PLANE, tgr.objectPlane, 0);
-				}
-			}
 		}
 	}
 	

src/com/ferox/renderer/impl/jogl/drivers/SingleStateDriver.java

 		} else if (this.lastAppliedState != null)
 			this.apply(this.factory.getGL(), this.factory.getCurrentContext(), this.defaultState);
 		this.lastAppliedState = this.queuedState;
+		
+		this.reset();
 	}
 
 	@Override

src/com/ferox/renderer/impl/jogl/drivers/TextureImageDriver.java

 
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
 import java.nio.ShortBuffer;
 			pr.unpackAlignment = 1;
 			gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
 		}
-		
-		// set the byte ordering
-		boolean enableSwap = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
-		if (pr.unpackSwapBytes != enableSwap) {
-			pr.unpackSwapBytes = enableSwap;
-			gl.glPixelStorei(GL.GL_UNPACK_SWAP_BYTES, (enableSwap ? GL.GL_TRUE : GL.GL_FALSE));
-		}
 	}
 
 	/** Convenience method to set all of the texture parameters on the given handle, based on 
 		
 		handle.setWrapS(gl, ti.getWrapS(), tdd.isTextureWrapDirty() || forceAll);
 		handle.setWrapT(gl, ti.getWrapT(), tdd.isTextureWrapDirty() || forceAll);
-		handle.setWrapT(gl, ti.getWrapT(), tdd.isTextureWrapDirty() || forceAll);
+		handle.setWrapR(gl, ti.getWrapR(), tdd.isTextureWrapDirty() || forceAll);
 		
 		handle.setDepthTest(gl, ti.getDepthCompareTest(), tdd.isDepthCompareDirty() || forceAll);
 		handle.setDepthMode(gl, ti.getDepthMode(), tdd.isDepthCompareDirty() || forceAll);

src/com/ferox/renderer/impl/jogl/record/LightingRecord.java

  *
  */
 public class LightingRecord {
-	/** State record for an individual light. */
+	/** State record for an individual light.
+	 * Certain lighting properties here, such as position
+	 * and direction are actually modified by the current
+	 * modelview matrix when set.  Because of this, the
+	 * values should not be taken as actual state, but are
+	 * an easy way of storing the data before passing into opengl. */
 	public static class LightRecord {
-		public final float[] ambient = {0f, 0f, 0f, 1f};
-		public final float[] diffuse = {.8f, .8f, .8f, 1f};
-		public final float[] specular = {0f, 0f, 0f, 1f};
+		/* Initial values for these are bogus, just to force a color change. */
+		public final float[] ambient = {-1f, -1f, -1f, -1f};
+		public final float[] diffuse = {-1f, -1f, -1f, 1f};
+		public final float[] specular = {0f, 0f, 0f, -1f};
 		public final float[] position = {0f, 0f, 1f, 0f};
 		
 		public float constantAttenuation = 1f;

src/com/ferox/renderer/impl/jogl/record/TextureRecord.java

 		public final float[] textureEnvColor = {0f, 0f, 0f, 0f};
 		public float textureLodBias = 0f;
 		
-		public final TextureGenRecord texGenR = new TextureGenRecord();
-		public final TextureGenRecord texGenS = new TextureGenRecord();
-		public final TextureGenRecord texGenT = new TextureGenRecord();
-		public final TextureGenRecord texGenQ = new TextureGenRecord();
+		public final TextureGenRecord texGenR = new TextureGenRecord(new float[] {0f, 0f, 0f, 0f});
+		public final TextureGenRecord texGenS = new TextureGenRecord(new float[] {1f, 0f, 0f, 0f});
+		public final TextureGenRecord texGenT = new TextureGenRecord(new float[] {0f, 1f, 0f, 0f});
+		public final TextureGenRecord texGenQ = new TextureGenRecord(new float[] {0f, 0f, 0f, 0f});
 
 		public int combineRgb = GL.GL_MODULATE;
 		public int combineAlpha = GL.GL_MODULATE;
 		public int texBinding = 0;
 	}
 	
+	/** The eyeplane is actually transformed by the current 
+	 * modelview matrix, so values stored in here cannot be
+	 * assumed to reflect the true eye plane.  It it instead
+	 * functions as a vessel to transport the plane to opengl. */
 	public static class TextureGenRecord {
 		public boolean enableTexGen;
-		public final float[] eyePlane = {};
-		public final float[] objectPlane = {};
+		public final float[] eyePlane = new float[4];
+		public final float[] objectPlane = new float[4];
 		public int textureGenMode = GL.GL_EYE_LINEAR;
+		
+		public TextureGenRecord(float[] plane) {
+			for (int i = 0; i < 4; i++) {
+				this.eyePlane[i] = plane[i];
+				this.objectPlane[i] = plane[i];
+			}
+		}
 	}
 	
 	/** For simplicity, activeTexture is valued 0 to maxUnits so it

src/com/ferox/resource/BufferData.java

 		SHORT(short[].class, BYTESIZE_SHORT, false), 
 		BYTE(byte[].class, BYTESIZE_BYTE, false),
 		
-		UNSIGNED_INT(int[].class, BYTESIZE_INT, false), 
-		UNSIGNED_SHORT(short[].class, BYTESIZE_SHORT, false),
-		UNSIGNED_BYTE(byte[].class, BYTESIZE_BYTE, false);
+		UNSIGNED_INT(int[].class, BYTESIZE_INT, true), 
+		UNSIGNED_SHORT(short[].class, BYTESIZE_SHORT, true),
+		UNSIGNED_BYTE(byte[].class, BYTESIZE_BYTE, true);
 		
 		private Class<?> classType; private int byteSize; private boolean unsigned;
 		private DataType(Class<?> type, int byteSize, boolean unsigned) {

src/com/ferox/resource/TextureFormat.java

 	}
 	
 	private TextureFormat(DataType type, int pPerC, boolean alpha, boolean packed) {
-		this.type = type; this.pPerC = pPerC; this.hasAlpha = alpha;
+		this.type = type; this.pPerC = pPerC; this.hasAlpha = alpha; this.isPacked = packed;
 	}
 	
 	/** Return true if this format has its color components packed into

src/com/ferox/resource/util/DDSTexture.java

 		
 		public String toString() {
 			String first = "RGB (" + isFlagSet(this.flags, DDPF_RGB) + "), LUM (" + isFlagSet(this.flags, DDPF_LUMINANCE) + 
-							"), ALPHA (" + isFlagSet(this.flags, DDPF_ALPHA) + "), FourCC (" + isFlagSet(this.flags, DDPF_FOURCC) + ")";
+							"), ALPHA (" + isFlagSet(this.flags, DDPF_ALPHAPIXELS) + "), FourCC (" + isFlagSet(this.flags, DDPF_FOURCC) + ")";
 			String second;
 			if (isFlagSet(this.flags, DDPF_FOURCC))
 				second = "FourCC = " + unmakeFourCC(this.fourCC);
 	 * where the next byte read is the first byte in the texture data (header already read from stream). */
 	private void readData(InputStream in) throws IOException {
 		int width, height, depth, size;
-		System.out.println(this.target);
+		System.out.println(this.target + " " + this.format + " " + this.type);
 		System.out.println(this.header.pixelFormat);
 		System.out.println(this.mipmapCount + " " + this.width + " " + this.height);
 		
     }
     
     // as bytesToInt, but for shorts (converts 2 bytes instead of 4)
+    // assuming little endian
     private static short bytesToShort(byte[] in, int offset) {
 		return (short)(
-					    (in[offset + 1] & 0xff) |
-					   ((in[offset + 0] & 0xff) << 8)
+					    (in[offset + 0] & 0xff) |
+					   ((in[offset + 1] & 0xff) << 8)
 					  );
 	}
     
     // the bytes are ordered little endian.
     private static int bytesToInt(byte[] in, int offset) {
 		return (
-				 (in[offset + 3] & 0xff) |
-				((in[offset + 1] & 0xff) << 8) |
-				((in[offset + 1] & 0xff) << 16) |
-				((in[offset + 0] & 0xff) << 24)
-			   );
-	}
-    
-    // convert 4 bytes starting at offset into an integer, assuming
-    // the bytes are ordered little endian.
-    private static int littleEndianBytesToInt(byte[] in, int offset) {
-		return (
-				(in[offset] & 0xff) |
+				 (in[offset + 0] & 0xff) |
 				((in[offset + 1] & 0xff) << 8) |
 				((in[offset + 2] & 0xff) << 16) |
 				((in[offset + 3] & 0xff) << 24)
     private static int readLEInt(InputStream in) throws IOException {
 		byte[] b = new byte[4];
 		readAll(in, b);
-		return littleEndianBytesToInt(b, 0);
+		return bytesToInt(b, 0);
 	}    
 }

src/com/ferox/resource/util/TGATexture.java

 	private static String validateHeader(Header h) {
 		if (h.idLength < 0 || h.idLength > 255)
 			return "Bad idLength value: " + h.idLength;
-		if (h.colorMapType != 0 || h.colorMapType != 1)
+		if (h.colorMapType != 0 && h.colorMapType != 1)
 			return "Bad color map type: " + h.colorMapType;
 		
 		switch(h.imageType) {
 			if (h.colorMapLength < 0)
 				return "Bad number of color map entries: " + h.colorMapLength;
 			if (!h.isBlackAndWhite()) {
-				if (h.colorMapEntrySize != 16 || h.colorMapEntrySize != 24 || h.colorMapEntrySize != 32)
+				if (h.colorMapEntrySize != 16 && h.colorMapEntrySize != 24 && h.colorMapEntrySize != 32)
 					return "Unsupported color map entry size: " + h.colorMapEntrySize;
 			}
-			if (h.pixelDepth != 8 || h.pixelDepth != 16)
+			if (h.pixelDepth != 8 && h.pixelDepth != 16)
 				return "Pixel depth doesn't have a valid value: " + h.pixelDepth;
 			if (h.hasColorMap() && h.colorMapType == 0)
 				return "Image type expects a color map, but one is not specified";
 			readAll(dIn, rawBuf);
 			for (c = 0; c < this.header.width; c++)
 				swapRow[c] = (short) bytesToLittleEndianShort(rawBuf, c << 1);
-			
+
 			y = (this.header.isTopToBottom() ? this.header.height - i - 1 : i);
-			System.arraycopy(rawBuf, 0, tmpData, y * this.header.width, swapRow.length);
+			System.arraycopy(swapRow, 0, tmpData, y * this.header.width, swapRow.length);
 		}
 
 		this.data = new BufferData(tmpData, true);
 	}
 	
 	/* This assumes that the body is for a 24 bit or 32 bit for a
-	 * BGR and BGRA image respectively. */
+	 * BGR and BGRA image respectively. (really a ARGB image, but its
+	 * in LE order, but just using BGRA is faster) */
 	private void decodeTrueColor24_32(InputStream dIn) throws IOException {
 		int i;    // input row index
 		int y;    // output row index
 		}
 	}
     
-    private static int bytesToLittleEndianShort(byte[] data, int offset) {
-    	return (data[offset] | (data[offset + 1] << 8));
+    private static int bytesToLittleEndianShort(byte[] b, int offset) {
+    	//return (data[offset] | (data[offset + 1] << 8));
+    	return (
+				 (b[offset + 0] & 0xff) |
+				((b[offset + 1] & 0xff) << 8)
+			   );
     }
     
     // read an short represented in little endian from the given input stream

src/com/ferox/resource/util/TextureIO.java

 														  true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
 				this.data = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 4, null);
 				
-				this.type = DataType.BYTE;
+				this.type = DataType.UNSIGNED_BYTE;
 				this.format = TextureFormat.RGBA;
 				break;
 			}

src/com/ferox/scene/Node.java

 	
 	/** Adjusts this Node's local transform so that it looks at position (in world coordinates), and
 	 * its y-axis is aligned as closely as possible to up (not always exactly up because it has to
-	 * maintain orthogonality). */
-	public void lookAt(Vector3f position, Vector3f up) throws NullPointerException {
+	 * maintain orthogonality). 
+	 * 
+	 * Specify negateDirection = true if the node "faces" backwards.  This is especially useful
+	 * for view nodes, since a view looks down the negative z-axis. */
+	public void lookAt(Vector3f position, Vector3f up, boolean negateDirection) throws NullPointerException {
 		if (position == null || up == null)
 			throw new SceneException("Can't call lookAt() with null input vectors: " + position + " " + up);
 		
 		Vector3f upVec = Node.upVec.get();
 		
 		dirVec.sub(position, this.worldTransform.getTranslation()); dirVec.normalize();
+		if (negateDirection)
+			dirVec.scale(-1f);
+		
 		leftVec.cross(up, dirVec); leftVec.normalize();
 		upVec.cross(dirVec, leftVec); upVec.normalize();
 				

src/com/ferox/state/Texture.java

 
 	/** Set the texture coordinate generation policy for the r tex coord (third).
 	 * If null uses the default.  A value of NONE causes texture coordinates to come
-	 * from the rendered geometry. */
+	 * from the rendered geometry. 
+	 * 
+	 * SPHERE mapping isn't supported on the 3rd coordinate, so if SPHERE is given,
+	 * NONE is used instead. */
 	public void setTexCoordGenR(TexCoordGen coordGen) {
-		if (coordGen == null)
+		if (coordGen == null || coordGen == TexCoordGen.SPHERE)
 			coordGen = DEFAULT_COORD_GEN;
 		this.rCoordGen = coordGen;
 	}

test/com/ferox/BasicApplication.java

 import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
 
+import org.openmali.vecmath.Vector3f;
+
+import com.ferox.math.Color;
 import com.ferox.math.Transform;
 import com.ferox.renderer.DisplayOptions;
+import com.ferox.renderer.OnscreenSurface;
 import com.ferox.renderer.RenderPass;
 import com.ferox.renderer.RenderQueue;
 import com.ferox.renderer.Renderer;
 import com.ferox.renderer.View;
-import com.ferox.renderer.WindowSurface;
 import com.ferox.renderer.util.BasicRenderPass;
 import com.ferox.renderer.util.StateSortingRenderQueue;
 import com.ferox.resource.BufferData;
  *
  */
 public abstract class BasicApplication extends ApplicationBase {
-	private WindowSurface window;
+	private OnscreenSurface window;
 	private RenderPass pass;
 	
 	private ViewNode view;
 		this.scene = this.buildScene(renderer, this.view);
 		this.pass = new BasicRenderPass(this.scene, v, this.createQueue(), false);
 		
-		this.window = renderer.createWindowSurface(this.createOptions(), 10, 10, 640, 480, true, false);
+		this.window = renderer.createFullscreenSurface(new DisplayOptions(), 800, 600);
+		//this.window = renderer.createWindowSurface(this.createOptions(), 10, 10, 640, 480, true, false);
 		this.window.addRenderPass(this.pass);
 		this.window.setTitle(this.getClass().getSimpleName());
-				
+		this.window.setClearColor(new Color(.5f, .5f, .5f, 1f));
+		
+		System.out.println(this.window.getDisplayOptions());
+		System.out.println(this.window.getWidth() + " " + this.window.getHeight());
+		v.setPerspective(60f, (float) this.window.getWidth() / this.window.getHeight(), 1f, 1000f);
+		
 		// somewhat lame to get input working for now
 		Frame f = (Frame) this.window.getWindowImpl();
 		Component child = f.getComponent(0);
 	
 	@Override
 	protected boolean update() {
+		this.view.lookAt(new Vector3f(), new Vector3f(0f, 1f, 0f), true);
 		this.scene.update(true);
 		return false;
 	}
 		if (this.window.isDestroyed())
 			return true;
 		
-		renderer.queueRender(this.window);
-		return super.render(renderer);
+		if (this.window.isVisible()) {
+			renderer.queueRender(this.window);
+			return super.render(renderer);
+		} else {
+			try {
+				Thread.sleep(50);
+			} catch (InterruptedException e) {}
+			return false;
+		}
 	}
 	
 	@Override

test/com/ferox/scene/CubeTest.java

 package com.ferox.scene;
 
+import java.io.File;
+import java.io.IOException;
+
 import org.openmali.vecmath.Vector3f;
 
 import com.ferox.BasicApplication;
 import com.ferox.math.Color;
 import com.ferox.renderer.Renderer;
 import com.ferox.resource.Geometry;
+import com.ferox.resource.TextureImage;
+import com.ferox.resource.util.TextureIO;
 import com.ferox.state.Appearance;
 import com.ferox.state.LightReceiver;
 import com.ferox.state.Material;
+import com.ferox.state.Texture;
+import com.ferox.state.Texture.EnvMode;
+import com.ferox.state.Texture.TexCoordGen;
 
 public class CubeTest extends BasicApplication {
 	public static final boolean DEBUG = false;
 	public static final boolean USE_VBO = true;
+	public static final boolean RANDOM_PLACEMENT = false;
 	
 	public static final int NUM_CUBES = 10000;
 	public static final int BOUNDS = 100;
 	
 	protected Geometry geom;
-	protected Shape firstCube;
 	
 	public static void main(String[] args) {
 		new CubeTest(DEBUG).run();
 		Group root = new Group();
 		root.add(view);
 		
-		Light light = new SpotLight();
+		Light spotLight = new SpotLight();
 		
-		light.setAmbient(new Color(.2f, 2f, 2f, 1f));
-		light.setSpecular(new Color(0f, 0f, 0f, 1f));
-		light.setLocalBounds(new BoundSphere(BOUNDS));
-		light.getLocalTransform().getTranslation().set(0f, 0f, 0f);
+		spotLight.setLocalBounds(new BoundSphere(BOUNDS));
+		spotLight.getLocalTransform().getTranslation().set(0f, 0f, 0f);
 		
-		view.add(light);
+		view.add(spotLight);
 		
-		Appearance a = this.createAppearance();
+		Light directionLight = new DirectionLight(new Vector3f(-1f, -1f, -1f));
+		directionLight.setLocalBounds(new BoundSphere(BOUNDS));
+		root.add(directionLight);
+		
+		Appearance[] apps = this.createAppearances(renderer);
 		this.geom = buildCube(renderer, 2f, USE_VBO);
 		
+		// vars for regular gridding
+		int sideCubeCount = (int) (Math.ceil(Math.pow(NUM_CUBES, 1.0 / 3.0)));
+		float scale = BOUNDS / (float) sideCubeCount;
+		int x = 0;
+		int y = 0;
+		int z = 0;
+		
 		for (int i = 0; i < NUM_CUBES; i++) {
-			Shape shape = new Shape(geom, a);
+			Shape shape = new Shape(geom, apps[i % apps.length]);
 			shape.setLocalBounds(new BoundSphere());
 			Vector3f pos = shape.getLocalTransform().getTranslation();
 			
-			if (i != 0) {
-				// randomly place all but the 1st cube
-				pos.x = (float) (Math.random() * BOUNDS - BOUNDS / 2f);
-				pos.y = (float) (Math.random() * BOUNDS - BOUNDS / 2f);
-				pos.z = (float) (Math.random() * BOUNDS - BOUNDS / 2f);
-			} else
-				this.firstCube = shape;
+			if (RANDOM_PLACEMENT) {
+				if (i != 0) {
+					// randomly place all but the 1st cube
+					pos.x = (float) (Math.random() * BOUNDS - BOUNDS / 2f);
+					pos.y = (float) (Math.random() * BOUNDS - BOUNDS / 2f);
+					pos.z = (float) (Math.random() * BOUNDS - BOUNDS / 2f);
+				}
+			} else {
+				pos.x = scale * x - BOUNDS / 2f;
+				pos.y = scale * y - BOUNDS / 2f;
+				pos.z = scale * z - BOUNDS / 2f;
+				
+				x++;
+				if (x >= sideCubeCount) {
+					x = 0;
+					y++;
+					if (y >= sideCubeCount) {
+						y = 0;
+						z++;
+					}
+				}
+			}
 			
 			root.add(shape);
 		}
 		return root;
 	}
 	
-	private Appearance createAppearance() {
-		Material m = new Material(new Color(.8f, .5f, .5f));
-		LightReceiver lr = new LightReceiver();
-		m.setSmoothShaded(false);
-		return new Appearance(m, lr);
+	private Appearance[] createAppearances(Renderer renderer) {
+		Appearance[] apps = new Appearance[4];
+		for (int i = 0; i < apps.length; i++)
+			apps[i] = this.createAppearance(renderer, i, apps.length);
+		return apps;
+	}
+	
+	private Appearance createAppearance(Renderer renderer, int i, int max) {
+		float percent = (float) i / max;
+		Material m;
+		
+		if (percent < .3333f) {
+			m = new Material(new Color(1f, percent, percent));
+		} else if (percent < .666667f) {
+			m = new Material(new Color(percent / 2f, 1f, percent / 2f));
+		} else {
+			m = new Material(new Color(percent / 3f, percent / 3f, 1f));
+		}
+
+		LightReceiver lr = null;
+		if (i % 2 == 0) {
+			lr = new LightReceiver();
+			m.setSmoothShaded(true);
+		}
+		
+		Texture t = null;
+		
+		if (i < max / 2) {
+			try {
+				TextureImage image = TextureIO.readTexture(new File("data/textures/squiggles.tga"));
+				renderer.requestUpdate(image, false);
+				t = new Texture(image, EnvMode.MODULATE, new Color(), TexCoordGen.NONE);
+			} catch (IOException io) {
+				throw new RuntimeException(io);
+			}
+		} else {
+			try {
+				TextureImage image = TextureIO.readTexture(new File("data/textures/grace_cube.dds"));
+				renderer.requestUpdate(image, false);
+				t = new Texture(image, EnvMode.MODULATE, new Color(), TexCoordGen.OBJECT);
+			} catch (IOException io) {
+				throw new RuntimeException(io);
+			}
+		}
+		
+		return new Appearance(m, lr, t);
 	}
 }