diff --git a/engine/src/android/com/jme3/asset/AndroidImageInfo.java b/engine/src/android/com/jme3/asset/AndroidImageInfo.java index f62d7b8b3..d762d07f1 100644 --- a/engine/src/android/com/jme3/asset/AndroidImageInfo.java +++ b/engine/src/android/com/jme3/asset/AndroidImageInfo.java @@ -3,8 +3,10 @@ package com.jme3.asset; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; +import com.jme3.math.ColorRGBA; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; +import com.jme3.texture.image.ImageRaster; import java.io.IOException; import java.io.InputStream; import java.util.logging.Level; @@ -18,7 +20,7 @@ import java.util.logging.Logger; * * @author Kirill Vainer */ -public class AndroidImageInfo { +public class AndroidImageInfo extends ImageRaster { private static final Logger logger = Logger.getLogger(AndroidImageInfo.class.getName()); @@ -57,6 +59,20 @@ public class AndroidImageInfo { return format; } + @Override + public void setPixel(int x, int y, ColorRGBA color) { + getBitmap().setPixel(x, y, color.asIntARGB()); + } + + @Override + public ColorRGBA getPixel(int x, int y, ColorRGBA store) { + if (store == null) { + store = new ColorRGBA(); + } + store.fromIntARGB(getBitmap().getPixel(x, y)); + return store; + } + /** * Loads the bitmap directly from the asset info, possibly updating * or creating the image object. diff --git a/engine/src/android/com/jme3/system/android/JmeAndroidSystem.java b/engine/src/android/com/jme3/system/android/JmeAndroidSystem.java index eecb02bd2..074f175e3 100644 --- a/engine/src/android/com/jme3/system/android/JmeAndroidSystem.java +++ b/engine/src/android/com/jme3/system/android/JmeAndroidSystem.java @@ -5,11 +5,15 @@ import android.app.AlertDialog; import android.graphics.Bitmap; import android.os.Environment; import com.jme3.asset.AndroidAssetManager; +import com.jme3.asset.AndroidImageInfo; import com.jme3.asset.AssetManager; import com.jme3.audio.AudioRenderer; import com.jme3.audio.android.AndroidAudioRenderer; import com.jme3.system.*; import com.jme3.system.JmeContext.Type; +import com.jme3.texture.Image; +import com.jme3.texture.image.DefaultImageRaster; +import com.jme3.texture.image.ImageRaster; import com.jme3.util.AndroidScreenshots; import com.jme3.util.JmeFormatter; import java.io.File; @@ -25,6 +29,13 @@ public class JmeAndroidSystem extends JmeSystemDelegate { private static Activity activity; + static { + try { + System.loadLibrary("bulletjme"); + } catch (UnsatisfiedLinkError e) { + } + } + @Override public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException { Bitmap bitmapImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); @@ -41,10 +52,12 @@ public class JmeAndroidSystem extends JmeSystemDelegate { bitmapImage.recycle(); } - static { - try { - System.loadLibrary("bulletjme"); - } catch (UnsatisfiedLinkError e) { + @Override + public ImageRaster createImageRaster(Image image, int slice) { + if (image.getEfficentData() != null) { + return (AndroidImageInfo) image.getEfficentData(); + } else { + return new DefaultImageRaster(image, slice); } } diff --git a/engine/src/core/com/jme3/system/JmeSystem.java b/engine/src/core/com/jme3/system/JmeSystem.java index 359dd86e9..e9dd8a222 100644 --- a/engine/src/core/com/jme3/system/JmeSystem.java +++ b/engine/src/core/com/jme3/system/JmeSystem.java @@ -34,6 +34,8 @@ package com.jme3.system; import com.jme3.asset.AssetManager; import com.jme3.audio.AudioRenderer; import com.jme3.input.SoftTextDialogInput; +import com.jme3.texture.Image; +import com.jme3.texture.image.ImageRaster; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -130,6 +132,11 @@ public class JmeSystem { checkDelegate(); return systemDelegate.newAudioRenderer(settings); } + + 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 diff --git a/engine/src/core/com/jme3/system/JmeSystemDelegate.java b/engine/src/core/com/jme3/system/JmeSystemDelegate.java index 8a481cfc7..9caf36f3c 100644 --- a/engine/src/core/com/jme3/system/JmeSystemDelegate.java +++ b/engine/src/core/com/jme3/system/JmeSystemDelegate.java @@ -34,6 +34,8 @@ package com.jme3.system; import com.jme3.asset.AssetManager; import com.jme3.audio.AudioRenderer; import com.jme3.input.SoftTextDialogInput; +import com.jme3.texture.Image; +import com.jme3.texture.image.ImageRaster; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -153,4 +155,6 @@ public abstract class JmeSystemDelegate { public abstract AudioRenderer newAudioRenderer(AppSettings settings); public abstract void initialize(AppSettings settings); + + public abstract ImageRaster createImageRaster(Image image, int slice); } diff --git a/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java b/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java index c19dc59bf..5e7148b83 100644 --- a/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java +++ b/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java @@ -26,27 +26,41 @@ class BitMaskImageCodec extends ImageCodec { } private static int readPixelRaw(ByteBuffer buf, int idx, int bpp) { - idx += bpp; - int original = buf.get(--idx) & 0xff; - while ((--bpp) > 0) { - original = (original << 8) | (buf.get(--idx) & 0xff); + //idx += bpp; + //int original = buf.get(--idx) & 0xff; + //while ((--bpp) > 0) { + // original = (original << 8) | (buf.get(--idx) & 0xff); + //} + //return original; + //return buf.getInt(idx) & (0xFFFFFFFF >>> (32 - bpp)); + int pixel = 0; + buf.position(idx); + for (int i = 0; i < bpp; i++) { + pixel = pixel | (buf.get() & 0xff) << (i * 8); } - return original; + return pixel; } private void writePixelRaw(ByteBuffer buf, int idx, int pixel, int bpp){ // buf.position(idx); // if (!be){ - while ((--bpp) >= 0){ - byte bt = (byte) ((pixel >> (bpp * 8)) & 0xff); - buf.put(idx + bpp, bt); - } + // This works: +// while ((--bpp) >= 0){ +// byte bt = (byte) ((pixel >> (bpp * 8)) & 0xff); +// buf.put(idx + bpp, bt); +// } + // == // } else { // for (int i = bpp - 1; i >= 0; i--) { // byte bt = (byte) ((pixel >> (i * 8)) & 0xff); // buf.put(idx + i, bt); // } // } + + buf.position(idx); + for (int i = 0; i < bpp; i++) { + buf.put( (byte)((pixel >> (8 * i)) & 0xff) ); + } } @Override diff --git a/engine/src/core/com/jme3/texture/image/DefaultImageRaster.java b/engine/src/core/com/jme3/texture/image/DefaultImageRaster.java new file mode 100644 index 000000000..1eafa0a63 --- /dev/null +++ b/engine/src/core/com/jme3/texture/image/DefaultImageRaster.java @@ -0,0 +1,114 @@ +package com.jme3.texture.image; + +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.texture.Image; +import java.nio.ByteBuffer; + +public class DefaultImageRaster extends ImageRaster { + + private final int[] components = new int[4]; + private final ByteBuffer buffer; + private final Image image; + private final ImageCodec codec; + private final int width; + private final int height; + private final byte[] temp; + + private void rangeCheck(int x, int y) { + if (x < 0 || y < 0 || x >= width || y >= height) { + throw new IllegalArgumentException("x and y must be inside the image dimensions"); + } + } + + public DefaultImageRaster(Image image, int slice) { + this.image = image; + this.buffer = image.getData(slice); + this.codec = ImageCodec.lookup(image.getFormat()); + this.width = image.getWidth(); + this.height = image.getHeight(); + if (codec instanceof ByteAlignedImageCodec) { + this.temp = new byte[codec.bpp]; + } else { + this.temp = null; + } + } + + @Override + public void setPixel(int x, int y, ColorRGBA color) { + rangeCheck(x, y); + + // Check flags for grayscale + if ((codec.flags & ImageCodec.FLAG_GRAY) != 0) { + float gray = color.r * 0.27f + color.g * 0.67f + color.b * 0.06f; + color = new ColorRGBA(gray, gray, gray, color.a); + } + + if ((codec.flags & ImageCodec.FLAG_F16) != 0) { + components[0] = (int) FastMath.convertFloatToHalf(color.a); + components[1] = (int) FastMath.convertFloatToHalf(color.r); + components[2] = (int) FastMath.convertFloatToHalf(color.g); + components[3] = (int) FastMath.convertFloatToHalf(color.b); + } else if ((codec.flags & ImageCodec.FLAG_F32) != 0) { + components[0] = (int) Float.floatToIntBits(color.a); + components[1] = (int) Float.floatToIntBits(color.r); + components[2] = (int) Float.floatToIntBits(color.g); + components[3] = (int) Float.floatToIntBits(color.b); + } else { + // Convert color to bits by multiplying by size + components[0] = Math.min( (int) (color.a * codec.maxAlpha + 0.5f), codec.maxAlpha); + components[1] = Math.min( (int) (color.r * codec.maxRed + 0.5f), codec.maxRed); + components[2] = Math.min( (int) (color.g * codec.maxGreen + 0.5f), codec.maxGreen); + components[3] = Math.min( (int) (color.b * codec.maxBlue + 0.5f), codec.maxBlue); + } + + codec.writeComponents(buffer, x, y, width, components, temp); + + image.setUpdateNeeded(); + } + + @Override + public ColorRGBA getPixel(int x, int y, ColorRGBA store) { + rangeCheck(x, y); + + codec.readComponents(buffer, x, y, width, components, temp); + + if (store == null) { + store = new ColorRGBA(); + } + if ((codec.flags & ImageCodec.FLAG_F16) != 0) { + store.set(FastMath.convertHalfToFloat((short)components[1]), + FastMath.convertHalfToFloat((short)components[2]), + FastMath.convertHalfToFloat((short)components[3]), + FastMath.convertHalfToFloat((short)components[0])); + } else if ((codec.flags & ImageCodec.FLAG_F32) != 0) { + store.set(Float.intBitsToFloat((int)components[1]), + Float.intBitsToFloat((int)components[2]), + Float.intBitsToFloat((int)components[3]), + Float.intBitsToFloat((int)components[0])); + } else { + // Convert to float and divide by bitsize to get into range 0.0 - 1.0. + store.set((float)components[1] / codec.maxRed, + (float)components[2] / codec.maxGreen, + (float)components[3] / codec.maxBlue, + (float)components[0] / codec.maxAlpha); + } + if ((codec.flags & ImageCodec.FLAG_GRAY) != 0) { + store.g = store.b = store.r; + } else { + if (codec.maxRed == 0) { + store.r = 1; + } + if (codec.maxGreen == 0) { + store.g = 1; + } + if (codec.maxBlue == 0) { + store.b = 1; + } + if (codec.maxAlpha == 0) { + store.a = 1; + } + } + return store; + } +} diff --git a/engine/src/core/com/jme3/texture/image/ImageRaster.java b/engine/src/core/com/jme3/texture/image/ImageRaster.java index d4c3bce1e..3040fa022 100644 --- a/engine/src/core/com/jme3/texture/image/ImageRaster.java +++ b/engine/src/core/com/jme3/texture/image/ImageRaster.java @@ -2,6 +2,7 @@ package com.jme3.texture.image; import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; +import com.jme3.system.JmeSystem; import com.jme3.texture.Image; import java.nio.ByteBuffer; @@ -26,22 +27,14 @@ import java.nio.ByteBuffer; * Usage example:
* * Image myImage = ... - * ImageRaster raster = new ImageRaster(myImage); + * ImageRaster raster = ImageRaster.create(myImage); * raster.setPixel(1, 5, ColorRGBA.Green); * System.out.println( raster.getPixel(1, 5) ); // Will print [0.0, 1.0, 0.0, 1.0]. * * * @author Kirill Vainer */ -public final class ImageRaster { - - private final int[] components = new int[4]; - private final ByteBuffer buffer; - private final Image image; - private final ImageCodec codec; - private final int width; - private final int height; - private final byte[] temp; +public abstract class ImageRaster { /** * Create new image reader / writer. @@ -50,17 +43,8 @@ public final class ImageRaster { * @param slice Which slice to use. Only applies to 3D images, 2D image * arrays or cubemaps. */ - public ImageRaster(Image image, int slice) { - this.image = image; - this.buffer = image.getData(slice); - this.codec = ImageCodec.lookup(image.getFormat()); - this.width = image.getWidth(); - this.height = image.getHeight(); - if (codec instanceof ByteAlignedImageCodec) { - this.temp = new byte[codec.bpp]; - } else { - this.temp = null; - } + public static ImageRaster create(Image image, int slices) { + return JmeSystem.createImageRaster(image, slices); } /** @@ -68,17 +52,14 @@ public final class ImageRaster { * * @param image The image to read / write to. */ - public ImageRaster(Image image) { - this(image, 0); + 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); } - private void rangeCheck(int x, int y) { - if (x < 0 || y < 0 || x >= width || y >= height) { - throw new IllegalArgumentException("x and y must be inside the image dimensions"); - } + public ImageRaster() { } /** @@ -108,37 +89,7 @@ public final class ImageRaster { * @param color The color to write. * @throws IllegalArgumentException If x or y are outside the image dimensions. */ - public void setPixel(int x, int y, ColorRGBA color) { - rangeCheck(x, y); - - // Check flags for grayscale - if ((codec.flags & ImageCodec.FLAG_GRAY) != 0) { - float gray = color.r * 0.27f + color.g * 0.67f + color.b * 0.06f; - color = new ColorRGBA(gray, gray, gray, color.a); - } - - if ((codec.flags & ImageCodec.FLAG_F16) != 0) { - components[0] = (int) FastMath.convertFloatToHalf(color.a); - components[1] = (int) FastMath.convertFloatToHalf(color.r); - components[2] = (int) FastMath.convertFloatToHalf(color.g); - components[3] = (int) FastMath.convertFloatToHalf(color.b); - } else if ((codec.flags & ImageCodec.FLAG_F32) != 0) { - components[0] = (int) Float.floatToIntBits(color.a); - components[1] = (int) Float.floatToIntBits(color.r); - components[2] = (int) Float.floatToIntBits(color.g); - components[3] = (int) Float.floatToIntBits(color.b); - } else { - // Convert color to bits by multiplying by size - components[0] = Math.min( (int) (color.a * codec.maxAlpha + 0.5f), codec.maxAlpha); - components[1] = Math.min( (int) (color.r * codec.maxRed + 0.5f), codec.maxRed); - components[2] = Math.min( (int) (color.g * codec.maxGreen + 0.5f), codec.maxGreen); - components[3] = Math.min( (int) (color.b * codec.maxBlue + 0.5f), codec.maxBlue); - } - - codec.writeComponents(buffer, x, y, width, components, temp); - - image.setUpdateNeeded(); - } + public abstract void setPixel(int x, int y, ColorRGBA color); /** * Retrieve the color at the given coordinate. @@ -168,49 +119,7 @@ public final class ImageRaster { * with the read color. * @throws IllegalArgumentException If x or y are outside the image dimensions. */ - public ColorRGBA getPixel(int x, int y, ColorRGBA store) { - rangeCheck(x, y); - - codec.readComponents(buffer, x, y, width, components, temp); - - if (store == null) { - store = new ColorRGBA(); - } - if ((codec.flags & ImageCodec.FLAG_F16) != 0) { - store.set(FastMath.convertHalfToFloat((short)components[1]), - FastMath.convertHalfToFloat((short)components[2]), - FastMath.convertHalfToFloat((short)components[3]), - FastMath.convertHalfToFloat((short)components[0])); - } else if ((codec.flags & ImageCodec.FLAG_F32) != 0) { - store.set(Float.intBitsToFloat((int)components[1]), - Float.intBitsToFloat((int)components[2]), - Float.intBitsToFloat((int)components[3]), - Float.intBitsToFloat((int)components[0])); - } else { - // Convert to float and divide by bitsize to get into range 0.0 - 1.0. - store.set((float)components[1] / codec.maxRed, - (float)components[2] / codec.maxGreen, - (float)components[3] / codec.maxBlue, - (float)components[0] / codec.maxAlpha); - } - if ((codec.flags & ImageCodec.FLAG_GRAY) != 0) { - store.g = store.b = store.r; - } else { - if (codec.maxRed == 0) { - store.r = 1; - } - if (codec.maxGreen == 0) { - store.g = 1; - } - if (codec.maxBlue == 0) { - store.b = 1; - } - if (codec.maxAlpha == 0) { - store.a = 1; - } - } - return store; - } + public abstract ColorRGBA getPixel(int x, int y, ColorRGBA store); /** * Retrieve the color at the given coordinate. diff --git a/engine/src/desktop/com/jme3/system/JmeDesktopSystem.java b/engine/src/desktop/com/jme3/system/JmeDesktopSystem.java index 1b2634f65..a0cb2d112 100644 --- a/engine/src/desktop/com/jme3/system/JmeDesktopSystem.java +++ b/engine/src/desktop/com/jme3/system/JmeDesktopSystem.java @@ -38,6 +38,9 @@ import com.jme3.asset.AssetNotFoundException; import com.jme3.asset.DesktopAssetManager; import com.jme3.audio.AudioRenderer; import com.jme3.system.JmeContext.Type; +import com.jme3.texture.Image; +import com.jme3.texture.image.DefaultImageRaster; +import com.jme3.texture.image.ImageRaster; import com.jme3.util.Screenshots; import java.awt.EventQueue; import java.awt.image.BufferedImage; @@ -70,6 +73,12 @@ public class JmeDesktopSystem extends JmeSystemDelegate { ImageIO.write(awtImage, format, outStream); } + @Override + public ImageRaster createImageRaster(Image image, int slice) { + assert image.getEfficentData() == null; + return new DefaultImageRaster(image, slice); + } + @Override public AssetManager newAssetManager() { return new DesktopAssetManager(null); diff --git a/engine/src/test/jme3test/texture/TestImageRaster.java b/engine/src/test/jme3test/texture/TestImageRaster.java index 5ed707c9c..da27ddf40 100644 --- a/engine/src/test/jme3test/texture/TestImageRaster.java +++ b/engine/src/test/jme3test/texture/TestImageRaster.java @@ -8,8 +8,6 @@ import com.jme3.font.Rectangle; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; -import com.jme3.post.FilterPostProcessor; -import com.jme3.post.filters.BloomFilter; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; @@ -31,8 +29,8 @@ public class TestImageRaster extends SimpleApplication { ByteBuffer data = BufferUtils.createByteBuffer( (int)Math.ceil(newFormat.getBitsPerPixel() / 8.0) * width * height); Image convertedImage = new Image(newFormat, width, height, data); - ImageRaster sourceReader = new ImageRaster(image); - ImageRaster targetWriter = new ImageRaster(convertedImage); + ImageRaster sourceReader = ImageRaster.create(image); + ImageRaster targetWriter = ImageRaster.create(convertedImage); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { ColorRGBA color = sourceReader.getPixel(x, y); @@ -70,7 +68,7 @@ public class TestImageRaster extends SimpleApplication { private Image createTestImage() { Image testImage = new Image(Format.BGR8, 4, 3, BufferUtils.createByteBuffer(4 * 4 * 3)); - ImageRaster io = new ImageRaster(testImage); + ImageRaster io = ImageRaster.create(testImage); io.setPixel(0, 0, ColorRGBA.Black); io.setPixel(1, 0, ColorRGBA.Gray); io.setPixel(2, 0, ColorRGBA.White); @@ -88,7 +86,7 @@ public class TestImageRaster extends SimpleApplication { return testImage; } - + @Override public void simpleInitApp() { cam.setLocation(new Vector3f(16, 6, 36)); @@ -101,64 +99,64 @@ public class TestImageRaster extends SimpleApplication { Image image = convertImage(originalImage, Format.RGBA32F); convertAndPutImage(image, 0, 0); - image = convertImage(originalImage, Format.RGB32F); + image = convertImage(image, Format.RGB32F); convertAndPutImage(image, 5, 0); - image = convertImage(originalImage, Format.RGBA16F); + image = convertImage(image, Format.RGBA16F); convertAndPutImage(image, 10, 0); - image = convertImage(originalImage, Format.RGB16F); + image = convertImage(image, Format.RGB16F); convertAndPutImage(image, 15, 0); - image = convertImage(originalImage, Format.RGB16F_to_RGB9E5); + image = convertImage(image, Format.RGB16F_to_RGB9E5); convertAndPutImage(image, 20, 0); - image = convertImage(originalImage, Format.RGB16F_to_RGB111110F); + image = convertImage(image, Format.RGB16F_to_RGB111110F); convertAndPutImage(image, 25, 0); - image = convertImage(originalImage, Format.RGBA16); + image = convertImage(image, Format.RGBA16); convertAndPutImage(image, 0, 5); - image = convertImage(originalImage, Format.RGB16); + image = convertImage(image, Format.RGB16); convertAndPutImage(image, 5, 5); - image = convertImage(originalImage, Format.RGBA8); + image = convertImage(image, Format.RGBA8); convertAndPutImage(image, 10, 5); - image = convertImage(originalImage, Format.RGB8); + image = convertImage(image, Format.RGB8); convertAndPutImage(image, 15, 5); - image = convertImage(originalImage, Format.ABGR8); + image = convertImage(image, Format.ABGR8); convertAndPutImage(image, 20, 5); - image = convertImage(originalImage, Format.BGR8); + image = convertImage(image, Format.BGR8); convertAndPutImage(image, 25, 5); - image = convertImage(originalImage, Format.RGB5A1); + image = convertImage(image, Format.RGB5A1); convertAndPutImage(image, 0, 10); - image = convertImage(originalImage, Format.ARGB4444); + image = convertImage(image, Format.ARGB4444); convertAndPutImage(image, 5, 10); - image = convertImage(originalImage, Format.Luminance32F); + image = convertImage(image, Format.Luminance32F); convertAndPutImage(image, 0, 15); - image = convertImage(originalImage, Format.Luminance16FAlpha16F); + image = convertImage(image, Format.Luminance16FAlpha16F); convertAndPutImage(image, 5, 15); - image = convertImage(originalImage, Format.Luminance16F); + image = convertImage(image, Format.Luminance16F); convertAndPutImage(image, 10, 15); - image = convertImage(originalImage, Format.Luminance16Alpha16); + image = convertImage(image, Format.Luminance16Alpha16); convertAndPutImage(image, 15, 15); - image = convertImage(originalImage, Format.Luminance16); + image = convertImage(image, Format.Luminance16); convertAndPutImage(image, 20, 15); - image = convertImage(originalImage, Format.Luminance8Alpha8); + image = convertImage(image, Format.Luminance8Alpha8); convertAndPutImage(image, 25, 15); - image = convertImage(originalImage, Format.Luminance8); + image = convertImage(image, Format.Luminance8); convertAndPutImage(image, 30, 15); }