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
experimental
Kirill Vainer 10 years ago
parent 09a104a7b1
commit 0a0fdca0b4
  1. 9
      jme3-core/src/main/java/com/jme3/system/JmeSystem.java
  2. 5
      jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
  3. 51
      jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java
  4. 25
      jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java

@ -172,15 +172,6 @@ public class JmeSystem {
return systemDelegate.getPlatformAssetConfigURL(); 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 * Displays an error message to the user in whichever way the context
* feels is appropriate. If this is a headless or an offscreen surface * feels is appropriate. If this is a headless or an offscreen surface

@ -132,11 +132,6 @@ public abstract class JmeSystemDelegate {
return new DesktopAssetManager(null); 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 writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
public abstract void showErrorDialog(String message); public abstract void showErrorDialog(String message);

@ -44,7 +44,9 @@ public class DefaultImageRaster extends ImageRaster {
private final ImageCodec codec; private final ImageCodec codec;
private final int width; private final int width;
private final int height; private final int height;
private final int offset;
private final byte[] temp; private final byte[] temp;
private final boolean convertToLinear;
private int slice; private int slice;
private void rangeCheck(int x, int y) { 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.image = image;
this.slice = slice; 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.buffer = image.getData(slice);
this.codec = ImageCodec.lookup(image.getFormat()); this.codec = ImageCodec.lookup(image.getFormat());
this.width = image.getWidth();
this.height = image.getHeight();
if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) { if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) {
this.temp = new byte[codec.bpp]; this.temp = new byte[codec.bpp];
} else { } else {
@ -86,6 +115,12 @@ public class DefaultImageRaster extends ImageRaster {
public void setPixel(int x, int y, ColorRGBA color) { public void setPixel(int x, int y, ColorRGBA color) {
rangeCheck(x, y); 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 // Check flags for grayscale
if (codec.isGray) { if (codec.isGray) {
float gray = color.r * 0.27f + color.g * 0.67f + color.b * 0.06f; 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); components[3] = Math.min( (int) (color.b * codec.maxBlue + 0.5f), codec.maxBlue);
break; break;
} }
codec.writeComponents(getBuffer(), x, y, width, 0, components, temp); codec.writeComponents(getBuffer(), x, y, width, offset, components, temp);
image.setUpdateNeeded(); image.setUpdateNeeded();
} }
@ -128,7 +163,7 @@ public class DefaultImageRaster extends ImageRaster {
public ColorRGBA getPixel(int x, int y, ColorRGBA store) { public ColorRGBA getPixel(int x, int y, ColorRGBA store) {
rangeCheck(x, y); rangeCheck(x, y);
codec.readComponents(getBuffer(), x, y, width, 0, components, temp); codec.readComponents(getBuffer(), x, y, width, offset, components, temp);
if (store == null) { if (store == null) {
store = new ColorRGBA(); store = new ColorRGBA();
} }
@ -169,6 +204,12 @@ public class DefaultImageRaster extends ImageRaster {
store.a = 1; 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; return store;
} }
} }

@ -71,21 +71,42 @@ public abstract class ImageRaster {
* @param image The image to read / write to. * @param image The image to read / write to.
* @param slice Which slice to use. Only applies to 3D images, 2D image * @param slice Which slice to use. Only applies to 3D images, 2D image
* arrays or cubemaps. * 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) { 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. * Create new image reader / writer for 2D images.
* *
* @param image The image to read / write to. * @param image The image to read / write to.
* @return An ImageRaster to read / write to the image.
*/ */
public static ImageRaster create(Image image) { public static ImageRaster create(Image image) {
if (image.getData().size() > 1) { if (image.getData().size() > 1) {
throw new IllegalStateException("Use constructor that takes slices argument to read from multislice image"); 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() { public ImageRaster() {

Loading…
Cancel
Save