Browse Source

ImageRaster: add mipmap access & gamma correction
* Remove deprecated image raster methods from JmeSystem
* Allow ImageRaster to read / write to arbitrary mipmaps
* Allow ImageRaster to perform conversion to / from linear color space as required

Kirill Vainer 10 năm trước cách đây
mục cha
commit
0a0fdca0b4

+ 0 - 9
jme3-core/src/main/java/com/jme3/system/JmeSystem.java

@@ -172,15 +172,6 @@ public class JmeSystem {
         return systemDelegate.getPlatformAssetConfigURL();
     }
     
-    /**
-     * @deprecated Directly create an image raster via {@link DefaultImageRaster}.
-     */
-    @Deprecated
-    public static ImageRaster createImageRaster(Image image, int slice) {
-        checkDelegate();
-        return systemDelegate.createImageRaster(image, slice);
-    }
-
     /**
      * Displays an error message to the user in whichever way the context
      * feels is appropriate. If this is a headless or an offscreen surface

+ 0 - 5
jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java

@@ -132,11 +132,6 @@ public abstract class JmeSystemDelegate {
         return new DesktopAssetManager(null);
     }
     
-    @Deprecated
-    public final ImageRaster createImageRaster(Image image, int slice) {
-        return new DefaultImageRaster(image, slice);
-    }
-    
     public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
 
     public abstract void showErrorDialog(String message);

+ 46 - 5
jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java

@@ -44,7 +44,9 @@ public class DefaultImageRaster extends ImageRaster {
     private final ImageCodec codec;
     private final int width;
     private final int height;
+    private final int offset;
     private final byte[] temp;
+    private final boolean convertToLinear;
     private int slice;
     
     private void rangeCheck(int x, int y) {
@@ -53,13 +55,40 @@ public class DefaultImageRaster extends ImageRaster {
         }
     }
     
-    public DefaultImageRaster(Image image, int slice) {
+    public DefaultImageRaster(Image image, int slice, int mipMapLevel, boolean convertToLinear) {
+        int[] mipMapSizes = image.getMipMapSizes();
+        int availableMips = mipMapSizes != null ? mipMapSizes.length : 1;
+        
+        if (mipMapLevel >= availableMips) {
+            throw new IllegalStateException("Cannot create image raster for mipmap level #" + mipMapLevel + ". "
+                                          + "Image only has " + availableMips + " mipmap levels.");
+        }
+        
+        if (image.hasMipmaps()) {
+            this.width  = Math.max(1, image.getWidth()  >> mipMapLevel);
+            this.height = Math.max(1, image.getHeight() >> mipMapLevel);
+            
+            int mipOffset = 0;
+            for (int i = 0; i < mipMapLevel; i++) {
+                mipOffset += mipMapSizes[i];
+            }
+            
+            this.offset = mipOffset;
+        } else {
+            this.width = image.getWidth();
+            this.height = image.getHeight();
+            this.offset = 0;
+        }
+        
         this.image = image;
         this.slice = slice;
+        
+        // Conversion to linear only needed if image's color space is sRGB.
+        this.convertToLinear = convertToLinear && image.getColorSpace() == ColorSpace.sRGB;
+        
         this.buffer = image.getData(slice);
         this.codec = ImageCodec.lookup(image.getFormat());
-        this.width = image.getWidth();
-        this.height = image.getHeight();
+        
         if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) {
             this.temp = new byte[codec.bpp];
         } else {
@@ -86,6 +115,12 @@ public class DefaultImageRaster extends ImageRaster {
     public void setPixel(int x, int y, ColorRGBA color) {
         rangeCheck(x, y);
         
+        if (convertToLinear) {
+            // Input is linear, needs to be converted to sRGB before writing
+            // into image.
+            color = color.getAsSrgb();
+        }
+        
         // Check flags for grayscale
         if (codec.isGray) {
             float gray = color.r * 0.27f + color.g * 0.67f + color.b * 0.06f;
@@ -113,7 +148,7 @@ public class DefaultImageRaster extends ImageRaster {
                 components[3] = Math.min( (int) (color.b * codec.maxBlue + 0.5f), codec.maxBlue);
                 break;
         }     
-        codec.writeComponents(getBuffer(), x, y, width, 0, components, temp);
+        codec.writeComponents(getBuffer(), x, y, width, offset, components, temp);
         image.setUpdateNeeded();
     }
     
@@ -128,7 +163,7 @@ public class DefaultImageRaster extends ImageRaster {
     public ColorRGBA getPixel(int x, int y, ColorRGBA store) {
         rangeCheck(x, y);
         
-        codec.readComponents(getBuffer(), x, y, width, 0, components, temp);
+        codec.readComponents(getBuffer(), x, y, width, offset, components, temp);
         if (store == null) {
             store = new ColorRGBA();
         }
@@ -169,6 +204,12 @@ public class DefaultImageRaster extends ImageRaster {
                 store.a = 1;
             }
         }
+        
+        if (convertToLinear) {
+            // Input image is sRGB, need to convert to linear.
+            store.setAsSrgb(store.r, store.g, store.b, store.a);
+        }
+        
         return store;
     }
 }

+ 23 - 2
jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java

@@ -71,21 +71,42 @@ public abstract class ImageRaster {
      * @param image The image to read / write to.
      * @param slice Which slice to use. Only applies to 3D images, 2D image
      * arrays or cubemaps.
+     * @param mipMapLevel The mipmap level to read / write to. To access levels 
+     * other than 0, the image must have 
+     * {@link Image#setMipMapSizes(int[]) mipmap sizes} set.
+     * @param convertToLinear If true, the application expects read or written
+     * colors to be in linear color space (<code>ImageRaster</code> will
+     * automatically perform a conversion as needed). If false, the application expects
+     * colors to be in the image's native {@link Image#getColorSpace() color space}.
+     * @return An ImageRaster to read / write to the image.
+     */
+    public static ImageRaster create(Image image, int slice, int mipMapLevel, boolean convertToLinear) {
+        return new DefaultImageRaster(image, slice, mipMapLevel, convertToLinear);
+    }
+    
+    /**
+     * Create new image reader / writer.
+     *
+     * @param image The image to read / write to.
+     * @param slice Which slice to use. Only applies to 3D images, 2D image
+     * arrays or cubemaps.
+     * @return An ImageRaster to read / write to the image.
      */
     public static ImageRaster create(Image image, int slice) {
-        return JmeSystem.createImageRaster(image, slice);
+        return create(image, slice, 0, false);
     }
     
     /**
      * Create new image reader / writer for 2D images.
      * 
      * @param image The image to read / write to.
+     * @return An ImageRaster to read / write to the image.
      */
     public static ImageRaster create(Image image) {
         if (image.getData().size() > 1) {
             throw new IllegalStateException("Use constructor that takes slices argument to read from multislice image");
         }
-        return JmeSystem.createImageRaster(image, 0);
+        return create(image, 0, 0, false);
     }
     
     public ImageRaster() {