Sfoglia il codice sorgente

* Added new image format: Depth24Stencil8, for framebuffers and textures that need stencil data
* Renderer now uses getArray() to access mesh's buffers
* GL image format data now stored in a special data structure for easier management (instead of huge switch/case statement)
* Android texture loading: If the format is not supported by GLES spec, the texture upload will fail

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9298 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Sha..rd 13 anni fa
parent
commit
f68475319a

+ 30 - 106
engine/src/android/com/jme3/renderer/android/TextureUtil.java

@@ -6,50 +6,11 @@ import android.opengl.GLUtils;
 import com.jme3.asset.AndroidImageInfo;
 import com.jme3.math.FastMath;
 import com.jme3.texture.Image;
-import com.jme3.texture.Image.Format;
 import java.nio.ByteBuffer;
 import javax.microedition.khronos.opengles.GL10;
 
 public class TextureUtil {
 
-    public static int convertTextureFormat(Format fmt){
-        switch (fmt){
-            case Alpha16:
-            case Alpha8:
-                return GL10.GL_ALPHA;
-            case Luminance8Alpha8:
-            case Luminance16Alpha16:
-                return GL10.GL_LUMINANCE_ALPHA;
-            case Luminance8:
-            case Luminance16:
-                return GL10.GL_LUMINANCE;
-            case RGB10:
-            case RGB16:
-            case BGR8:
-            case RGB8:
-            case RGB565:
-                return GL10.GL_RGB;
-            case RGB5A1:
-            case RGBA16:
-            case RGBA8:
-                return GL10.GL_RGBA;
-                
-            case Depth:
-                return GLES20.GL_DEPTH_COMPONENT;
-            case Depth16:
-                return GLES20.GL_DEPTH_COMPONENT16;
-            case Depth24:
-            case Depth32:
-            case Depth32F:
-                throw new UnsupportedOperationException("Unsupported depth format: " + fmt);   
-                
-            case DXT1A:
-                throw new UnsupportedOperationException("Unsupported format: " + fmt);
-            default:
-                throw new UnsupportedOperationException("Unrecognized format: " + fmt);
-        }
-    }
-
     private static void buildMipmap(Bitmap bitmap) {
         int level = 0;
         int height = bitmap.getHeight();
@@ -77,21 +38,17 @@ public class TextureUtil {
 
     /**
      * <code>uploadTextureBitmap</code> uploads a native android bitmap
-     * @param target
-     * @param bitmap
-     * @param generateMips
-     * @param powerOf2
      */
-    public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2)
-    {
-        if (!powerOf2)
-        {
+    public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2) {
+        if (!powerOf2) {
+            // Power of 2 images are not supported by this GPU. 
             int width = bitmap.getWidth();
             int height = bitmap.getHeight();
-            if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height))
-            {
-                // scale to power of two
-                width = FastMath.nearestPowerOfTwo(width);
+            
+            // If the image is not power of 2, rescale it
+            if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)) {
+                // scale to power of two, then recycle the old image.
+                width  = FastMath.nearestPowerOfTwo(width);
                 height = FastMath.nearestPowerOfTwo(height);
                 Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
                 bitmap.recycle();
@@ -99,19 +56,15 @@ public class TextureUtil {
             }
         }
 
-        if (generateMips)
-        {
+        if (generateMips) {
             buildMipmap(bitmap);
-        }
-        else
-        {
+        } else {
             GLUtils.texImage2D(target, 0, bitmap, 0);
             //bitmap.recycle();
         }
     }
 
-    public static void uploadTexture(
-                                     Image img,
+    public static void uploadTexture(Image img,
                                      int target,
                                      int index,
                                      int border,
@@ -128,7 +81,6 @@ public class TextureUtil {
 
         // Otherwise upload image directly. 
         // Prefer to only use power of 2 textures here to avoid errors.
-        
         Image.Format fmt = img.getFormat();
         ByteBuffer data;
         if (index >= 0 || img.getData() != null && img.getData().size() > 0){
@@ -142,12 +94,20 @@ public class TextureUtil {
         int depth = img.getDepth();
 
         boolean compress = false;
-        int internalFormat = -1;
         int format = -1;
         int dataType = -1;
 
         switch (fmt){
+            case RGBA16:
+            case RGB16:
+            case RGB10:
+            case Luminance16:
+            case Luminance16Alpha16:
             case Alpha16:
+            case Depth32:
+            case Depth32F:
+                throw new UnsupportedOperationException("The image format '" 
+                        + fmt + "' is not supported by OpenGL ES 2.0 specification.");
             case Alpha8:
                 format = GLES20.GL_ALPHA;
                 dataType = GLES20.GL_UNSIGNED_BYTE;                
@@ -160,34 +120,16 @@ public class TextureUtil {
                 format = GLES20.GL_LUMINANCE_ALPHA;
                 dataType = GLES20.GL_UNSIGNED_BYTE;
                 break;
-            case Luminance16Alpha16:
-                format = GLES20.GL_LUMINANCE_ALPHA;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
-                break;
-            case Luminance16:
-                format = GLES20.GL_LUMINANCE;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
-                break;
             case RGB565:
                 format = GLES20.GL_RGB;
-                internalFormat = GLES20.GL_RGB565;
                 dataType = GLES20.GL_UNSIGNED_SHORT_5_6_5;
                 break;
             case ARGB4444:
-                format = GLES20.GL_RGBA;
+                format = GLES20.GL_RGBA4;
                 dataType = GLES20.GL_UNSIGNED_SHORT_4_4_4_4;
                 break;
-            case RGB10:
-                format = GLES20.GL_RGB;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
-                break;
-            case RGB16:
-                format = GLES20.GL_RGB;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
-                break;
             case RGB5A1:
                 format = GLES20.GL_RGBA;
-                internalFormat = GLES20.GL_RGB5_A1;
                 dataType = GLES20.GL_UNSIGNED_SHORT_5_5_5_1;
                 break;
             case RGB8:
@@ -198,42 +140,23 @@ public class TextureUtil {
                 format = GLES20.GL_RGB;
                 dataType = GLES20.GL_UNSIGNED_BYTE;
                 break;
-            case RGBA16:
-                format = GLES20.GL_RGBA;
-                internalFormat = GLES20.GL_RGBA4;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
-                break;
             case RGBA8:
                 format = GLES20.GL_RGBA;                
                 dataType = GLES20.GL_UNSIGNED_BYTE;
                 break;
-            case DXT1A:
-                format = GLES20.GL_COMPRESSED_TEXTURE_FORMATS;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
             case Depth:
-                format = GLES20.GL_DEPTH_COMPONENT;
-                dataType = GLES20.GL_UNSIGNED_BYTE;
-                break;
             case Depth16:
+            case Depth24:
                 format = GLES20.GL_DEPTH_COMPONENT;
-                internalFormat = GLES20.GL_DEPTH_COMPONENT16;
                 dataType = GLES20.GL_UNSIGNED_BYTE;
                 break;
-            case Depth24:
-            case Depth32:
-            case Depth32F:
-                throw new UnsupportedOperationException("Unsupported depth format: " + fmt);                
             default:
                 throw new UnsupportedOperationException("Unrecognized format: " + fmt);
         }
-        
-        if (internalFormat == -1)
-        {
-            internalFormat = format;
-        }
 
-        if (data != null)
+        if (data != null) {
             GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
+        }
 
         int[] mipSizes = img.getMipMapSizes();
         int pos = 0;
@@ -246,9 +169,10 @@ public class TextureUtil {
 
         // XXX: might want to change that when support
         // of more than paletted compressions is added..
+        /// NOTE: Doesn't support mipmaps
         if (compress){
             data.clear();
-            GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
+            GLES20.glCompressedTexImage2D(target,
                                       1 - mipSizes.length,
                                       format,
                                       width,
@@ -262,7 +186,7 @@ public class TextureUtil {
         for (int i = 0; i < mipSizes.length; i++){
             int mipWidth =  Math.max(1, width  >> i);
             int mipHeight = Math.max(1, height >> i);
-            int mipDepth =  Math.max(1, depth  >> i);
+//            int mipDepth =  Math.max(1, depth  >> i);
 
             if (data != null){
                 data.position(pos);
@@ -270,7 +194,7 @@ public class TextureUtil {
             }
 
             if (compress && data != null){
-                GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
+                GLES20.glCompressedTexImage2D(target,
                                           i,
                                           format,
                                           mipWidth,
@@ -279,9 +203,9 @@ public class TextureUtil {
                                           data.remaining(),
                                           data);
             }else{
-                GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
+                GLES20.glTexImage2D(target,
                                 i,
-                                internalFormat,
+                                format,
                                 mipWidth,
                                 mipHeight,
                                 0,

+ 5 - 10
engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java

@@ -738,7 +738,6 @@ public class LwjglGL1Renderer implements GL1Renderer {
 
                     // Resize texture to Power-of-2 size
                     MipMapGenerator.resizeToPowerOf2(img);
-
                 }
             }
         }
@@ -777,7 +776,7 @@ public class LwjglGL1Renderer implements GL1Renderer {
         TextureUtil.uploadTexture(img, target, i, 0, tdc);
         }
         } else {*/
-        TextureUtil.uploadTexture(img, target, 0, 0, false);
+        TextureUtil.uploadTexture(img, target, 0, 0);
         //}
 
         img.clearUpdateNeeded();
@@ -1052,15 +1051,12 @@ public class LwjglGL1Renderer implements GL1Renderer {
             updateBufferData(interleavedData);
         }
 
-        IntMap<VertexBuffer> buffers = mesh.getBuffers();
         if (mesh.getNumLodLevels() > 0) {
             indices = mesh.getLodLevel(lod);
         } else {
-            indices = buffers.get(Type.Index.ordinal());
+            indices = mesh.getBuffer(Type.Index);
         }
-        for (Entry<VertexBuffer> entry : buffers) {
-            VertexBuffer vb = entry.getValue();
-
+        for (VertexBuffer vb : mesh.getBufferList().getArray()) {
             if (vb.getBufferType() == Type.InterleavedData
                     || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
                     || vb.getBufferType() == Type.Index) {
@@ -1108,9 +1104,8 @@ public class LwjglGL1Renderer implements GL1Renderer {
         }
 
         if (mesh.getNumLodLevels() == 0) {
-            IntMap<VertexBuffer> bufs = mesh.getBuffers();
-            for (Entry<VertexBuffer> entry : bufs) {
-                if (entry.getValue().getUsage() != VertexBuffer.Usage.Static) {
+            for (VertexBuffer vb : mesh.getBufferList().getArray()) {
+                if (vb.getUsage() != VertexBuffer.Usage.Static) {
                     dynamic = true;
                     break;
                 }

+ 25 - 31
engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -53,12 +53,8 @@ import com.jme3.texture.FrameBuffer.RenderBuffer;
 import com.jme3.texture.Image;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapAxis;
-import com.jme3.util.BufferUtils;
-import com.jme3.util.IntMap;
 import com.jme3.util.IntMap.Entry;
-import com.jme3.util.ListMap;
-import com.jme3.util.NativeObjectManager;
-import com.jme3.util.SafeArrayList;
+import com.jme3.util.*;
 import java.nio.*;
 import java.util.EnumSet;
 import java.util.List;
@@ -109,7 +105,6 @@ public class LwjglRenderer implements Renderer {
     private int maxTriCount;
     private int maxColorTexSamples;
     private int maxDepthTexSamples;
-    private boolean tdc;
     private FrameBuffer lastFb = null;
     private FrameBuffer mainFbOverride = null;
     private final Statistics statistics = new Statistics();
@@ -272,6 +267,10 @@ public class LwjglRenderer implements Renderer {
         if (ctxCaps.GL_ARB_depth_buffer_float) {
             caps.add(Caps.FloatDepthBuffer);
         }
+        
+        if (ctxCaps.OpenGL30){
+            caps.add(Caps.PackedDepthStencilBuffer);
+        }
 
         if (ctxCaps.GL_ARB_draw_instanced) {
             caps.add(Caps.MeshInstancing);
@@ -304,12 +303,8 @@ public class LwjglRenderer implements Renderer {
         }
 
         boolean latc = ctxCaps.GL_EXT_texture_compression_latc;
-        boolean atdc = ctxCaps.GL_ATI_texture_compression_3dc;
-        if (latc || atdc) {
+        if (latc) {
             caps.add(Caps.TextureCompressionLATC);
-            if (atdc && !latc) {
-                tdc = true;
-            }
         }
 
         if (ctxCaps.GL_EXT_packed_float) {
@@ -454,10 +449,12 @@ public class LwjglRenderer implements Renderer {
     }
 
     public void setAlphaToCoverage(boolean value) {
-        if (value) {
-            glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
-        } else {
-            glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+        if (caps.contains(Caps.Multisample)){
+            if (value) {
+                glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+            } else {
+                glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
+            }
         }
     }
 
@@ -1270,7 +1267,7 @@ public class LwjglRenderer implements Renderer {
         switch (type) {
             case GL_NONE:
                 System.out.println("Type: None");
-                return; // note: return from method as other queries will be invalid
+                break;
             case GL_TEXTURE:
                 System.out.println("Type: Texture");
                 break;
@@ -1364,8 +1361,8 @@ public class LwjglRenderer implements Renderer {
                     + ":" + fb.getHeight() + " is not supported.");
         }
 
-        TextureUtil.checkFormatSupported(rb.getFormat());
-
+        TextureUtil.GLImageFormat glFmt = TextureUtil.getImageFormatWithError(rb.getFormat());
+        
         if (fb.getSamples() > 1 && GLContext.getCapabilities().GL_EXT_framebuffer_multisample) {
             int samples = fb.getSamples();
             if (maxFBOSamples < samples) {
@@ -1373,12 +1370,12 @@ public class LwjglRenderer implements Renderer {
             }
             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
                     samples,
-                    TextureUtil.convertTextureFormat(rb.getFormat()),
+                    glFmt.internalFormat,
                     fb.getWidth(),
                     fb.getHeight());
         } else {
             glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
-                    TextureUtil.convertTextureFormat(rb.getFormat()),
+                    glFmt.internalFormat,
                     fb.getWidth(),
                     fb.getHeight());
         }
@@ -1854,19 +1851,19 @@ public class LwjglRenderer implements Renderer {
                 return;
             }
             for (int i = 0; i < 6; i++) {
-                TextureUtil.uploadTexture(img, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc);
+                TextureUtil.uploadTexture(img, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0);
             }
         } else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT) {
             List<ByteBuffer> data = img.getData();
             // -1 index specifies prepare data for 2D Array
-            TextureUtil.uploadTexture(img, target, -1, 0, tdc);
+            TextureUtil.uploadTexture(img, target, -1, 0);
             for (int i = 0; i < data.size(); i++) {
                 // upload each slice of 2D array in turn
                 // this time with the appropriate index
-                TextureUtil.uploadTexture(img, target, i, 0, tdc);
+                TextureUtil.uploadTexture(img, target, i, 0);
             }
         } else {
-            TextureUtil.uploadTexture(img, target, 0, 0, tdc);
+            TextureUtil.uploadTexture(img, target, 0, 0);
         }
 
         if (img.getMultiSamples() != imageSamples) {
@@ -1978,8 +1975,8 @@ public class LwjglRenderer implements Renderer {
                 return GL_INT;
             case UnsignedInt:
                 return GL_UNSIGNED_INT;
-            case Half:
-                return NVHalfFloat.GL_HALF_FLOAT_NV;
+//            case Half:
+//                return NVHalfFloat.GL_HALF_FLOAT_NV;
 //                return ARBHalfFloatVertex.GL_HALF_FLOAT;
             case Float:
                 return GL_FLOAT;
@@ -2343,10 +2340,7 @@ public class LwjglRenderer implements Renderer {
             updateBufferData(interleavedData);
         }
 
-        IntMap<VertexBuffer> buffers = mesh.getBuffers();
-        for (Entry<VertexBuffer> entry : buffers) {
-            VertexBuffer vb = entry.getValue();
-
+        for (VertexBuffer vb : mesh.getBufferList().getArray()) {
             if (vb.getBufferType() == Type.InterleavedData
                     || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
                     || vb.getBufferType() == Type.Index) {
@@ -2376,7 +2370,7 @@ public class LwjglRenderer implements Renderer {
         }
 
 //        IntMap<VertexBuffer> buffers = mesh.getBuffers();
-        VertexBuffer indices = null;
+        VertexBuffer indices;
         if (mesh.getNumLodLevels() > 0) {
             indices = mesh.getLodLevel(lod);
         } else {

+ 215 - 391
engine/src/lwjgl/com/jme3/renderer/lwjgl/TextureUtil.java

@@ -36,369 +36,192 @@ import com.jme3.renderer.RendererException;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image.Format;
 import java.nio.ByteBuffer;
-import static org.lwjgl.opengl.ATITextureCompression3DC.GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
-import static org.lwjgl.opengl.EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
-import static org.lwjgl.opengl.EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_LATC1_EXT;
-import static org.lwjgl.opengl.EXTTextureCompressionS3TC.*;
-import static org.lwjgl.opengl.GL11.*;
-import static org.lwjgl.opengl.GL12.*;
-import static org.lwjgl.opengl.GL13.glCompressedTexImage2D;
-import static org.lwjgl.opengl.GL13.glCompressedTexImage3D;
-import static org.lwjgl.opengl.GL14.*;
 import org.lwjgl.opengl.*;
 
-public class TextureUtil {
+class TextureUtil {
 
-    private static boolean isFormatSupported(Format fmt, ContextCapabilities caps){
+    static class GLImageFormat {
+        
+        int internalFormat;
+        int format;
+        int dataType;
+        boolean compressed;
+
+        public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) {
+            this.internalFormat = internalFormat;
+            this.format = format;
+            this.dataType = dataType;
+            this.compressed = compressed;
+        }
+    }
+    
+    private static final GLImageFormat[] formatToGL = new GLImageFormat[Format.values().length];
+    
+    private static void setFormat(Format format, int glInternalFormat, int glFormat, int glDataType, boolean glCompressed){
+        formatToGL[format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, glCompressed);
+    }
+    
+    static {
+        // Alpha formats
+        setFormat(Format.Alpha8,  GL11.GL_ALPHA8,  GL11.GL_ALPHA, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Alpha16, GL11.GL_ALPHA16, GL11.GL_ALPHA, GL11.GL_UNSIGNED_BYTE, false);
+        
+        // Luminance formats
+        setFormat(Format.Luminance8,   GL11.GL_LUMINANCE8,  GL11.GL_LUMINANCE, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Luminance16,  GL11.GL_LUMINANCE16, GL11.GL_LUMINANCE, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Luminance16F, ARBTextureFloat.GL_LUMINANCE16F_ARB, GL11.GL_LUMINANCE, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Luminance32F, ARBTextureFloat.GL_LUMINANCE32F_ARB, GL11.GL_LUMINANCE, GL11.GL_UNSIGNED_BYTE, false);
+        
+        // Luminance alpha formats
+        setFormat(Format.Luminance8Alpha8, GL11.GL_LUMINANCE8_ALPHA8,  GL11.GL_LUMINANCE_ALPHA, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Luminance16Alpha16, GL11.GL_LUMINANCE16_ALPHA16, GL11.GL_LUMINANCE_ALPHA, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Luminance16FAlpha16F, ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB, GL11.GL_LUMINANCE_ALPHA, GL11.GL_UNSIGNED_BYTE, false);
+        
+        // Depth formats
+        setFormat(Format.Depth,    GL11.GL_DEPTH_COMPONENT,    GL11.GL_DEPTH_COMPONENT, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Depth16,  GL14.GL_DEPTH_COMPONENT16,  GL11.GL_DEPTH_COMPONENT, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Depth24,  GL14.GL_DEPTH_COMPONENT24,  GL11.GL_DEPTH_COMPONENT, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Depth32,  GL14.GL_DEPTH_COMPONENT32,  GL11.GL_DEPTH_COMPONENT, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.Depth32F, GL30.GL_DEPTH_COMPONENT32F, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT,         false);
+        
+        // Depth stencil formats
+        setFormat(Format.Depth24Stencil8, GL30.GL_DEPTH24_STENCIL8, GL11.GL_DEPTH_COMPONENT, GL30.GL_UNSIGNED_INT_24_8, false);
+        
+        // RGB formats
+        setFormat(Format.BGR8,       GL11.GL_RGB8,  EXTBgra.GL_BGR_EXT, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.RGB8,       GL11.GL_RGB8,  GL11.GL_RGB,        GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.RGB10,      GL11.GL_RGB10, GL11.GL_RGB,        GL12.GL_UNSIGNED_INT_10_10_10_2, false); 
+        setFormat(Format.RGB16,      GL11.GL_RGB16, GL11.GL_RGB,        GL11.GL_UNSIGNED_BYTE, false); // might be incorrect
+        setFormat(Format.RGB16F,     ARBTextureFloat.GL_RGB16F_ARB, GL11.GL_RGB, ARBHalfFloatPixel.GL_HALF_FLOAT_ARB, false);
+        setFormat(Format.RGB32F,     ARBTextureFloat.GL_RGB32F_ARB, GL11.GL_RGB, GL11.GL_FLOAT, false);
+        
+        // Special RGB formats
+        setFormat(Format.RGB111110F, EXTPackedFloat.GL_R11F_G11F_B10F_EXT,    GL11.GL_RGB, EXTPackedFloat.GL_UNSIGNED_INT_10F_11F_11F_REV_EXT, false);
+        setFormat(Format.RGB9E5,     EXTTextureSharedExponent.GL_RGB9_E5_EXT, GL11.GL_RGB, EXTTextureSharedExponent.GL_UNSIGNED_INT_5_9_9_9_REV_EXT, false);
+        setFormat(Format.RGB16F_to_RGB111110F, EXTPackedFloat.GL_R11F_G11F_B10F_EXT,    GL11.GL_RGB, ARBHalfFloatPixel.GL_HALF_FLOAT_ARB, false);
+        setFormat(Format.RGB16F_to_RGB111110F, EXTTextureSharedExponent.GL_RGB9_E5_EXT, GL11.GL_RGB, ARBHalfFloatPixel.GL_HALF_FLOAT_ARB, false);
+        
+        // RGBA formats
+        setFormat(Format.ABGR8,   GL11.GL_RGBA8,       EXTAbgr.GL_ABGR_EXT, GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.RGB5A1,  GL11.GL_RGB5_A1,     GL11.GL_RGBA,        GL12.GL_UNSIGNED_SHORT_5_5_5_1, false);
+        setFormat(Format.RGBA8,   GL11.GL_RGBA8,       GL11.GL_RGBA,        GL11.GL_UNSIGNED_BYTE, false);
+        setFormat(Format.RGBA16,  GL11.GL_RGBA16,      GL11.GL_RGBA,        GL11.GL_UNSIGNED_BYTE, false); // might be incorrect
+        setFormat(Format.RGBA16F, ARBTextureFloat.GL_RGBA16F_ARB, GL11.GL_RGBA, ARBHalfFloatPixel.GL_HALF_FLOAT_ARB, false);
+        setFormat(Format.RGBA32F, ARBTextureFloat.GL_RGBA32F_ARB, GL11.GL_RGBA, GL11.GL_FLOAT, false);
+        
+        // DXT formats
+        setFormat(Format.DXT1,  EXTTextureCompressionS3TC.GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL11.GL_RGB,   GL11.GL_UNSIGNED_BYTE, true);
+        setFormat(Format.DXT1A, EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, true);
+        setFormat(Format.DXT3,  EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, true);
+        setFormat(Format.DXT5,  EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, true);
+    
+        // LTC/LATC/3Dc formats
+        setFormat(Format.LTC,  EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL11.GL_LUMINANCE,       GL11.GL_UNSIGNED_BYTE, true);
+        setFormat(Format.LATC, EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL11.GL_LUMINANCE_ALPHA, GL11.GL_UNSIGNED_BYTE, true);
+    }
+    
+    public static GLImageFormat getImageFormat(ContextCapabilities caps, Format fmt){
         switch (fmt){
-            case ARGB4444:
-                return false;
+            case ABGR8:
+                if (!caps.GL_EXT_abgr){
+                    return null;
+                }
+                break;
             case BGR8:
-                return caps.OpenGL12 || caps.GL_EXT_bgra;
+                if (!caps.OpenGL12 && !caps.GL_EXT_bgra){
+                    return null;
+                }
+                break;
             case DXT1:
             case DXT1A:
             case DXT3:
             case DXT5:
-                return caps.GL_EXT_texture_compression_s3tc;
+                if (!caps.GL_EXT_texture_compression_s3tc) {
+                    return null;
+                }
+                break;
             case Depth:
             case Depth16:
             case Depth24:
             case Depth32:
-                return caps.OpenGL14 || caps.GL_ARB_depth_texture;
-            case Depth32F:
+                if (!caps.OpenGL14 && !caps.GL_ARB_depth_texture){
+                    return null;
+                }
+                break;
             case Luminance16F:
             case Luminance16FAlpha16F:
             case Luminance32F:
+                if (!caps.GL_ARB_texture_float){
+                    return null;
+                }
+                break;
+            case RGB16F:
+            case RGB32F:
             case RGBA16F:
             case RGBA32F:
-                return caps.OpenGL30 || caps.GL_ARB_texture_float;
+                if (!caps.OpenGL30 && !caps.GL_ARB_texture_float){
+                    return null;
+                }
+                break;
+            case Depth32F:
+                if (!caps.OpenGL30 && !caps.GL_NV_depth_buffer_float){
+                    return null;
+                }
+                break;
             case LATC:
             case LTC:
-                return caps.GL_EXT_texture_compression_latc;
+                if (!caps.GL_EXT_texture_compression_latc){
+                    return null;
+                }
+                break;
             case RGB9E5:
             case RGB16F_to_RGB9E5:
-                return caps.OpenGL30 || caps.GL_EXT_texture_shared_exponent;
+                if (!caps.OpenGL30 && !caps.GL_EXT_texture_shared_exponent){
+                    return null;
+                }
+                break;
             case RGB111110F:
             case RGB16F_to_RGB111110F:
-                return caps.OpenGL30 || caps.GL_EXT_packed_float;
-            default:
-                return true;
+                if (!caps.OpenGL30 && !caps.GL_EXT_packed_float){
+                    return null;
+                }
+                break;
         }
+        return formatToGL[fmt.ordinal()];
     }
-
-    public static void checkFormatSupported(Format fmt) {
-        if (!isFormatSupported(fmt, GLContext.getCapabilities())) {
+    
+    public static GLImageFormat getImageFormatWithError(Format fmt) {
+        GLImageFormat glFmt = getImageFormat(GLContext.getCapabilities(), fmt);
+        if (glFmt == null) {
             throw new RendererException("Image format '" + fmt + "' is unsupported by the video hardware.");
         }
+        return glFmt;
     }
-
-    public static int convertTextureFormat(Format fmt){
-        switch (fmt){
-            case Alpha16:
-                return GL_ALPHA16;
-            case Alpha8:
-                return GL_ALPHA8;
-            case DXT1:
-                return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-            case DXT1A:
-                return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-            case DXT3:
-                return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-            case DXT5:
-                return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-            case LATC:
-                return GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
-            case Depth:
-                return GL_DEPTH_COMPONENT;
-            case Depth16:
-                return GL_DEPTH_COMPONENT16;
-            case Depth24:
-                return GL_DEPTH_COMPONENT24;
-            case Depth32:
-                return GL_DEPTH_COMPONENT32;
-            case Depth32F:
-                return ARBDepthBufferFloat.GL_DEPTH_COMPONENT32F;
-            case Luminance8Alpha8:
-                return GL_LUMINANCE8_ALPHA8;
-            case Luminance16Alpha16:
-                return GL_LUMINANCE16_ALPHA16;
-            case Luminance16FAlpha16F:
-                return ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB;
-            case Intensity8:
-                return GL_INTENSITY8;
-            case Intensity16:
-                return GL_INTENSITY16;
-            case Luminance8:
-                return GL_LUMINANCE8;
-            case Luminance16:
-                return GL_LUMINANCE16;
-            case Luminance16F:
-                return ARBTextureFloat.GL_LUMINANCE16F_ARB;
-             case Luminance32F:
-                return ARBTextureFloat.GL_LUMINANCE32F_ARB;
-            case RGB10:
-                return GL_RGB10;
-            case RGB16:
-                return GL_RGB16;
-            case RGB111110F:
-                return EXTPackedFloat.GL_R11F_G11F_B10F_EXT;
-            case RGB9E5:
-                return EXTTextureSharedExponent.GL_RGB9_E5_EXT;
-            case RGB16F:
-                return ARBTextureFloat.GL_RGB16F_ARB;
-            case RGBA16F:
-                return ARBTextureFloat.GL_RGBA16F_ARB;
-            case RGB32F:
-                return ARBTextureFloat.GL_RGB32F_ARB;
-            case RGB5A1:
-                return GL_RGB5_A1;
-            case BGR8:
-                return GL_RGB8;
-            case RGB8:
-                return GL_RGB8;
-            case RGBA16:
-                return GL_RGBA16;
-            case RGBA8:
-                return GL_RGBA8;
-            default:
-                throw new UnsupportedOperationException("Unrecognized format: "+fmt);
-        }
-    }
-
-    public static void uploadTexture(Image img,
+    
+    public static void uploadTexture(Image image,
                                      int target,
                                      int index,
-                                     int border,
-                                     boolean tdc){
-        Image.Format fmt = img.getFormat();
-
-        checkFormatSupported(fmt);
+                                     int border){
+        
+        Image.Format fmt = image.getFormat();
+        GLImageFormat glFmt = getImageFormatWithError(fmt);
 
         ByteBuffer data;
-        if (index >= 0 && img.getData() != null && img.getData().size() > 0){
-            data = img.getData(index);
+        if (index >= 0 && image.getData() != null && image.getData().size() > 0){
+            data = image.getData(index);
         }else{
             data = null;
         }
 
-        int width = img.getWidth();
-        int height = img.getHeight();
-        int depth = img.getDepth();
+        int width = image.getWidth();
+        int height = image.getHeight();
+        int depth = image.getDepth();
 
-        boolean compress = false;
-        int internalFormat = -1;
-        int format = -1;
-        int dataType = -1;
-
-        switch (fmt){
-            case Alpha16:
-                internalFormat = GL_ALPHA16;
-                format = GL_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Alpha8:
-                internalFormat = GL_ALPHA8;
-                format = GL_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case DXT1:
-                compress = true;
-                internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-                format = GL_RGB;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case DXT1A:
-                compress = true;
-                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-                format = GL_RGBA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case DXT3:
-                compress = true;
-                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-                format = GL_RGBA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case DXT5:
-                compress = true;
-                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-                format = GL_RGBA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case LATC:
-                compress = true;
-                if (tdc){
-                    internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
-                }else{
-                    internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
-                }
-                format = GL_LUMINANCE_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case LTC:
-                compress = true;
-                internalFormat = GL_COMPRESSED_LUMINANCE_LATC1_EXT;
-                format = GL_LUMINANCE_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Depth:
-                internalFormat = GL_DEPTH_COMPONENT;
-                format = GL_DEPTH_COMPONENT;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Depth16:
-                internalFormat = GL_DEPTH_COMPONENT16;
-                format = GL_DEPTH_COMPONENT;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Depth24:
-                internalFormat = GL_DEPTH_COMPONENT24;
-                format = GL_DEPTH_COMPONENT;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Depth32:
-                internalFormat = GL_DEPTH_COMPONENT32;
-                format = GL_DEPTH_COMPONENT;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Depth32F:
-                internalFormat = NVDepthBufferFloat.GL_DEPTH_COMPONENT32F_NV;
-                format = GL_DEPTH_COMPONENT;
-                dataType = GL_FLOAT;
-                break;
-            case Luminance16FAlpha16F:
-                internalFormat = ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB;
-                format = GL_LUMINANCE_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Intensity8:
-                internalFormat = GL_INTENSITY8;
-                format = GL_INTENSITY;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Intensity16:
-                internalFormat = GL_INTENSITY16;
-                format = GL_INTENSITY;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Luminance8:
-                internalFormat = GL_LUMINANCE8;
-                format = GL_LUMINANCE;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Luminance8Alpha8:
-                internalFormat = GL_LUMINANCE8_ALPHA8;
-                format = GL_LUMINANCE_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Luminance16Alpha16:
-                internalFormat = GL_LUMINANCE16_ALPHA16;
-                format = GL_LUMINANCE_ALPHA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Luminance16:
-                internalFormat = GL_LUMINANCE16;
-                format = GL_LUMINANCE;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case Luminance16F:
-                internalFormat = ARBTextureFloat.GL_LUMINANCE16F_ARB;
-                format = GL_LUMINANCE;
-                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
-                break;
-            case Luminance32F:
-                internalFormat = ARBTextureFloat.GL_LUMINANCE32F_ARB;
-                format = GL_LUMINANCE;
-                dataType = GL_FLOAT;
-                break;
-            case RGB10:
-                internalFormat = GL_RGB10;
-                format = GL_RGB;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case RGB16:
-                internalFormat = GL_RGB16;
-                format = GL_RGB;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case RGB111110F:
-                internalFormat = EXTPackedFloat.GL_R11F_G11F_B10F_EXT;
-                format = GL_RGB;
-                dataType = EXTPackedFloat.GL_UNSIGNED_INT_10F_11F_11F_REV_EXT;
-                break;
-            case RGB16F_to_RGB111110F:
-                internalFormat = EXTPackedFloat.GL_R11F_G11F_B10F_EXT;
-                format = GL_RGB;
-                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
-                break;
-            case RGB16F_to_RGB9E5:
-                internalFormat = EXTTextureSharedExponent.GL_RGB9_E5_EXT;
-                format = GL_RGB;
-                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
-                break;
-            case RGB9E5:
-                internalFormat = EXTTextureSharedExponent.GL_RGB9_E5_EXT;
-                format = GL_RGB;
-                dataType = EXTTextureSharedExponent.GL_UNSIGNED_INT_5_9_9_9_REV_EXT;
-                break;
-            case RGB16F:
-                internalFormat = ARBTextureFloat.GL_RGB16F_ARB;
-                format = GL_RGB;
-                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
-                break;
-            case RGBA16F:
-                internalFormat = ARBTextureFloat.GL_RGBA16F_ARB;
-                format = GL_RGBA;
-                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
-                break;
-            case RGB32F:
-                internalFormat = ARBTextureFloat.GL_RGB32F_ARB;
-                format = GL_RGB;
-                dataType = GL_FLOAT;
-                break;
-            case RGBA32F:
-                internalFormat = ARBTextureFloat.GL_RGBA32F_ARB;
-                format = GL_RGBA;
-                dataType = GL_FLOAT;
-                break;
-            case RGB5A1:
-                internalFormat = GL_RGB5_A1;
-                format = GL_RGBA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case RGB8:
-                internalFormat = GL_RGB8;
-                format = GL_RGB;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case BGR8:
-                internalFormat = GL_RGB8;
-                format = GL_BGR;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case RGBA16:
-                internalFormat = GL_RGBA16;
-                format = GL_RGBA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case RGBA8:
-                internalFormat = GL_RGBA8;
-                format = GL_RGBA;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            case ABGR8:
-                internalFormat = GL_RGBA8;
-                format = EXTAbgr.GL_ABGR_EXT;
-                dataType = GL_UNSIGNED_BYTE;
-                break;
-            default:
-                throw new UnsupportedOperationException("Unrecognized format: "+fmt);
+        if (data != null) {
+            GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
         }
 
-        if (data != null)
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-        int[] mipSizes = img.getMipMapSizes();
+        int[] mipSizes = image.getMipMapSizes();
         int pos = 0;
         // TODO: Remove unneccessary allocation
         if (mipSizes == null){
@@ -409,7 +232,7 @@ public class TextureUtil {
         }
 
         boolean subtex = false;
-        int samples = img.getMultiSamples();
+        int samples = image.getMultiSamples();
 
         for (int i = 0; i < mipSizes.length; i++){
             int mipWidth =  Math.max(1, width  >> i);
@@ -421,95 +244,96 @@ public class TextureUtil {
                 data.limit(pos + mipSizes[i]);
             }
             
-            if (compress && data != null){
-                if (target == GL_TEXTURE_3D){
-                    glCompressedTexImage3D(target,
-                                           i,
-                                           internalFormat,
-                                           mipWidth,
-                                           mipHeight,
-                                           mipDepth,
-                                           border,
-                                           data);
+            if (glFmt.compressed && data != null){
+                if (target == GL12.GL_TEXTURE_3D){
+                    GL13.glCompressedTexImage3D(target,
+                                                i,
+                                                glFmt.internalFormat,
+                                                mipWidth,
+                                                mipHeight,
+                                                mipDepth,
+                                                border,
+                                                data);
                 }else{
                     //all other targets use 2D: array, cubemap, 2d
-                    glCompressedTexImage2D(target,
-                                           i,
-                                           internalFormat,
-                                           mipWidth,
-                                           mipHeight,
-                                           border,
-                                           data);
+                    GL13.glCompressedTexImage2D(target,
+                                                i,
+                                                glFmt.internalFormat,
+                                                mipWidth,
+                                                mipHeight,
+                                                border,
+                                                data);
                 }
             }else{
-                if (target == GL_TEXTURE_3D){
-                    glTexImage3D(target,
-                                 i,
-                                 internalFormat,
-                                 mipWidth,
-                                 mipHeight,
-                                 mipDepth,
-                                 border,
-                                 format,
-                                 dataType,
-                                 data);
+                if (target == GL12.GL_TEXTURE_3D){
+                    GL12.glTexImage3D(target,
+                                      i,
+                                      glFmt.internalFormat,
+                                      mipWidth,
+                                      mipHeight,
+                                      mipDepth,
+                                      border,
+                                      glFmt.format,
+                                      glFmt.dataType,
+                                      data);
                 }else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){
                     // prepare data for 2D array
                     // or upload slice
                     if (index == -1){
-                        glTexImage3D(target,
-                                     0,
-                                     internalFormat,
-                                     mipWidth,
-                                     mipHeight,
-                                     img.getData().size(), //# of slices
-                                     border,
-                                     format,
-                                     dataType,
-                                     data);
+                        GL12.glTexImage3D(target,
+                                          0,
+                                          glFmt.internalFormat,
+                                          mipWidth,
+                                          mipHeight,
+                                          image.getData().size(), //# of slices
+                                          border,
+                                          glFmt.format,
+                                          glFmt.dataType,
+                                          data);
                     }else{
-                        glTexSubImage3D(target,
-                                        i, // level
-                                        0, // xoffset
-                                        0, // yoffset
-                                        index, // zoffset
-                                        width, // width
-                                        height, // height
-                                        1, // depth
-                                        format,
-                                        dataType,
-                                        data);
+                        GL12.glTexSubImage3D(target,
+                                             i, // level
+                                             0, // xoffset
+                                             0, // yoffset
+                                             index, // zoffset
+                                             width, // width
+                                             height, // height
+                                             1, // depth
+                                             glFmt.format,
+                                             glFmt.dataType,
+                                             data);
                     }
                 }else{
                     if (subtex){
-                        if (samples > 1)
+                        if (samples > 1){
                             throw new IllegalStateException("Cannot update multisample textures");
+                        }
 
-                        glTexSubImage2D(target,
-                                        i,
-                                        0, 0,
-                                        mipWidth, mipHeight,
-                                        format,
-                                        dataType,
-                                        data);
+                        GL11.glTexSubImage2D(target,
+                                             i,
+                                             0, 0,
+                                             mipWidth, mipHeight,
+                                             glFmt.format,
+                                             glFmt.dataType,
+                                             data);
                     }else{
                         if (samples > 1){
                             ARBTextureMultisample.glTexImage2DMultisample(target,
                                                                           samples,
-                                                                          internalFormat,
+                                                                          glFmt.internalFormat,
                                                                           mipWidth,
                                                                           mipHeight,
                                                                           true);
                         }else{
-                            glTexImage2D(target,
-                                         i,
-                                         internalFormat,
-                                         mipWidth,
-                                         mipHeight,
-                                         border,
-                                         format,
-                                         dataType,
-                                         data);
+                            GL11.glTexImage2D(target,
+                                              i,
+                                              glFmt.internalFormat,
+                                              mipWidth,
+                                              mipHeight,
+                                              border,
+                                              glFmt.format,
+                                              glFmt.dataType,
+                                              data);
                         }
                     }
                 }