Преглед на файлове

Image: support for RGTC format

Kirill Vainer преди 9 години
родител
ревизия
6db1d15045

+ 6 - 1
jme3-core/src/main/java/com/jme3/renderer/Caps.java

@@ -349,7 +349,12 @@ public enum Caps {
     /**
      * GPU can provide and accept binary shaders.
      */
-    BinaryShader;
+    BinaryShader, 
+    
+    /**
+     * Supports {@link Format#RGTC} and {@link Format#RTC} texture compression.
+     */
+    TextureCompressionRGTC;
 
     /**
      * Returns true if given the renderer capabilities, the texture

+ 2 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java

@@ -44,6 +44,8 @@ import java.nio.IntBuffer;
 public interface GLExt {
 
         public static final int GL_ALREADY_SIGNALED = 0x911A;
+        public static final int GL_COMPRESSED_RED_RGTC1 = 0x8DBB;
+        public static final int GL_COMPRESSED_RG_RGTC2 = 0x8DBD;
 	public static final int GL_COMPRESSED_RGB8_ETC2 = 0x9274;
 	public static final int GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
 	public static final int GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;

+ 5 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java

@@ -233,6 +233,11 @@ public final class GLImageFormats {
             formatComp(formatToGL, Format.ETC1, GLExt.GL_ETC1_RGB8_OES,        GL.GL_RGB, GL.GL_UNSIGNED_BYTE);
         }
         
+        if (caps.contains(Caps.TextureCompressionRGTC)) {
+            formatComp(formatToGL, Format.RGTC, GLExt.GL_COMPRESSED_RG_RGTC2,  GL.GL_RGB, GL.GL_UNSIGNED_BYTE);
+            formatComp(formatToGL, Format.RTC, GLExt.GL_COMPRESSED_RED_RGTC1,  GL.GL_RED, GL.GL_UNSIGNED_BYTE);
+        }
+        
         return formatToGL;
     }
 }

+ 4 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java

@@ -348,6 +348,10 @@ public final class GLRenderer implements Renderer {
         } else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
             caps.add(Caps.TextureCompressionETC1);
         }
+        
+        if (hasExtension("GL_ARB_texture_compression_rgtc")) {
+            caps.add(Caps.TextureCompressionRGTC);
+        }
 
         // == end texture format extensions ==
 

+ 15 - 1
jme3-core/src/main/java/com/jme3/texture/Image.java

@@ -299,7 +299,21 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
          * 
          * Requires {@link Caps#TextureCompressionETC1}.
          */
-        ETC1(4, false, true, false);
+        ETC1(4, false, true, false),
+        
+        /**
+         * RGTC with red channel only.
+         * 
+         * Requires {@link Caps#TextureCompressionRGTC}.
+         */
+        RTC(4, false, true, false),
+        
+        /**
+         * RGTC with red and green channels.
+         * 
+         * Requires {@link Caps#TextureCompressionRGTC}.
+         */
+        RGTC(8, false, true, false);
 
         private int bpp;
         private boolean isDepth;

+ 67 - 13
jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java

@@ -85,6 +85,8 @@ public class DDSLoader implements AssetLoader {
     private static final int PF_DXT1 = 0x31545844;
     private static final int PF_DXT3 = 0x33545844;
     private static final int PF_DXT5 = 0x35545844;
+    private static final int PF_ETC1 = 0x31435445;
+    private static final int PF_ETC_ = 0x20435445; // the underscore represents a space
     private static final int PF_ATI1 = 0x31495441;
     private static final int PF_ATI2 = 0x32495441; // 0x41544932;
     private static final int PF_DX10 = 0x30315844; // a DX10 format
@@ -94,6 +96,9 @@ public class DDSLoader implements AssetLoader {
             DX10DIM_TEXTURE3D = 0x4;
     private static final int DX10MISC_GENERATE_MIPS = 0x1,
             DX10MISC_TEXTURECUBE = 0x4;
+    private static final int DXGI_FORMAT_BC4_TYPELESS = 79;
+    private static final int DXGI_FORMAT_BC4_UNORM = 80;
+    private static final int DXGI_FORMAT_BC4_SNORM = 81;
     private static final double LOG2 = Math.log(2);
     private int width;
     private int height;
@@ -105,9 +110,11 @@ public class DDSLoader implements AssetLoader {
     private int caps2;
     private boolean directx10;
     private boolean compressed;
+    private boolean dxtOrRgtc;
     private boolean texture3D;
     private boolean grayscaleOrAlpha;
     private boolean normal;
+    private ColorSpace colorSpace;
     private Format pixelFormat;
     private int bpp;
     private int[] sizes;
@@ -133,7 +140,8 @@ public class DDSLoader implements AssetLoader {
                 ((TextureKey) info.getKey()).setTextureTypeHint(Texture.Type.CubeMap);
             }
             ArrayList<ByteBuffer> data = readData(((TextureKey) info.getKey()).isFlipY());
-            return new Image(pixelFormat, width, height, depth, data, sizes, ColorSpace.sRGB);
+            
+            return new Image(pixelFormat, width, height, depth, data, sizes, colorSpace);
         } finally {
             if (stream != null){
                 stream.close();
@@ -145,18 +153,24 @@ public class DDSLoader implements AssetLoader {
         in = new LittleEndien(stream);
         loadHeader();
         ArrayList<ByteBuffer> data = readData(false);
-        return new Image(pixelFormat, width, height, depth, data, sizes, ColorSpace.sRGB);
+        return new Image(pixelFormat, width, height, depth, data, sizes, colorSpace);
     }
 
     private void loadDX10Header() throws IOException {
         int dxgiFormat = in.readInt();
+        
         if (dxgiFormat == 0) {
-                pixelFormat = Format.ETC1;
-                bpp = 4;
+            pixelFormat = Format.ETC1;
+            compressed = true;
+            bpp = 4;
         } else {
+            pixelFormat = DXGIFormat.getJmeFormat(dxgiFormat);
+            if (pixelFormat == null) {
                 throw new IOException("Unsupported DX10 format: " + dxgiFormat);
+            }
+            bpp = pixelFormat.getBitsPerPixel();
+            compressed = pixelFormat.isCompressed();
         }
-        compressed = true;
         
         int resDim = in.readInt();
         if (resDim == DX10DIM_TEXTURE3D) {
@@ -201,6 +215,7 @@ public class DDSLoader implements AssetLoader {
         caps2 = in.readInt();
         in.skipBytes(12);
         texture3D = false;
+        colorSpace = ColorSpace.sRGB;
 
         if (!directx10) {
             if (!is(caps1, DDSCAPS_TEXTURE)) {
@@ -268,10 +283,12 @@ public class DDSLoader implements AssetLoader {
                     } else {
                         pixelFormat = Image.Format.DXT1;
                     }
+                    dxtOrRgtc = true;
                     break;
                 case PF_DXT3:
                     bpp = 8;
                     pixelFormat = Image.Format.DXT3;
+                    dxtOrRgtc = true;
                     break;
                 case PF_DXT5:
                     bpp = 8;
@@ -279,17 +296,24 @@ public class DDSLoader implements AssetLoader {
                     if (swizzle == SWIZZLE_xGxR) {
                         normal = true;
                     }
+                    dxtOrRgtc = true;
                     break;
-                /*
                 case PF_ATI1:
                     bpp = 4;
-                    pixelFormat = Image.Format.LTC;
+                    pixelFormat = Image.Format.RTC;
+                    dxtOrRgtc = true;
                     break;
                 case PF_ATI2:
                     bpp = 8;
-                    pixelFormat = Image.Format.LATC;
+                    pixelFormat = Image.Format.RGTC;
+                    dxtOrRgtc = true;
+                    break;
+                case PF_ETC1:
+                case PF_ETC_:
+                    bpp = 4;
+                    pixelFormat = Image.Format.ETC1;
+                    dxtOrRgtc = false;
                     break;
-                */
                 case PF_DX10:
                     compressed = false;
                     directx10 = true;
@@ -530,6 +554,30 @@ public class DDSLoader implements AssetLoader {
         return dataBuffer;
     }
 
+    public ByteBuffer readCompressed2Dor3D(boolean flip, int totalSize) throws IOException {
+        logger.log(Level.FINEST, "Source image format: {0}", pixelFormat);
+        
+        ByteBuffer buffer = BufferUtils.createByteBuffer(totalSize * depth);
+
+        // TODO: add support for flipping ETC1
+        
+        for (int i = 0; i < depth; i++) {
+            int mipWidth = width;
+            int mipHeight = height;
+            for (int mip = 0; mip < mipMapCount; mip++) {
+                byte[] data = new byte[sizes[mip]];
+                in.readFully(data);
+                buffer.put(data);
+
+                mipWidth = Math.max(mipWidth / 2, 1);
+                mipHeight = Math.max(mipHeight / 2, 1);
+            }
+        }
+        buffer.rewind();
+        
+        return buffer;
+    }
+    
     /**
      * Reads a DXT compressed image from the InputStream
      *
@@ -738,8 +786,10 @@ public class DDSLoader implements AssetLoader {
         ArrayList<ByteBuffer> allMaps = new ArrayList<ByteBuffer>();
         if (depth > 1 && !texture3D) {
             for (int i = 0; i < depth; i++) {
-                if (compressed) {
+                if (compressed && dxtOrRgtc) {
                     allMaps.add(readDXT2D(flip, totalSize));
+                } else if (compressed) {
+                    allMaps.add(readCompressed2Dor3D(flip, totalSize));
                 } else if (grayscaleOrAlpha) {
                     allMaps.add(readGrayscale2D(flip, totalSize));
                 } else {
@@ -747,8 +797,10 @@ public class DDSLoader implements AssetLoader {
                 }
             }
         } else if (texture3D) {
-            if (compressed) {
+            if (compressed && dxtOrRgtc) {
                 allMaps.add(readDXT3D(flip, totalSize));
+            } else if (compressed) {
+                allMaps.add(readCompressed2Dor3D(flip, totalSize));
             } else if (grayscaleOrAlpha) {
                 allMaps.add(readGrayscale3D(flip, totalSize));
             } else {
@@ -756,8 +808,10 @@ public class DDSLoader implements AssetLoader {
             }
 
         } else {
-            if (compressed) {
+            if (compressed && dxtOrRgtc) {
                 allMaps.add(readDXT2D(flip, totalSize));
+            } else if (compressed) {
+                allMaps.add(readCompressed2Dor3D(flip, totalSize));
             } else if (grayscaleOrAlpha) {
                 allMaps.add(readGrayscale2D(flip, totalSize));
             } else {
@@ -822,7 +876,7 @@ public class DDSLoader implements AssetLoader {
         buf.append((char) (value & 0xFF));
         buf.append((char) ((value & 0xFF00) >> 8));
         buf.append((char) ((value & 0xFF0000) >> 16));
-        buf.append((char) ((value & 0xFF00000) >> 24));
+        buf.append((char) ((value & 0xFF000000) >> 24));
 
         return buf.toString();
     }

+ 3 - 5
jme3-core/src/plugins/java/com/jme3/texture/plugins/DXTFlipper.java

@@ -213,20 +213,18 @@ public class DXTFlipper {
             case DXT5:
                 type = 3;
                 break;
-            /*
-            case LATC:
+            case RGTC:
                 type = 4;
                 break;
-            case LTC:
+            case RTC:
                 type = 5;
                 break;
-            */
             default:
                 throw new IllegalArgumentException();
         }
 
         // DXT1 uses 8 bytes per block,
-        // DXT3, DXT5, LATC use 16 bytes per block
+        // DXT3, DXT5, RGTC use 16 bytes per block
         int bpb = type == 1 || type == 5 ? 8 : 16;
 
         ByteBuffer retImg = BufferUtils.createByteBuffer(blocksX * blocksY * bpb);