diff --git a/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java b/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java new file mode 100644 index 000000000..c19dc59bf --- /dev/null +++ b/engine/src/core/com/jme3/texture/image/BitMaskImageCodec.java @@ -0,0 +1,73 @@ +package com.jme3.texture.image; + +import java.nio.ByteBuffer; + +class BitMaskImageCodec extends ImageCodec { + + // Shifts + final int as, rs, gs, bs; + boolean be = false; + + public BitMaskImageCodec(int bpp, int flags, int ac, int rc, int gc, int bc, int as, int rs, int gs, int bs) { + super(bpp, flags, + (int) (((long) 1 << ac) - 1), + (int) (((long) 1 << rc) - 1), + (int) (((long) 1 << gc) - 1), + (int) (((long) 1 << bc) - 1)); + + if (bpp > 4) { + throw new UnsupportedOperationException("Use ByteAlignedImageCodec for codecs with pixel sizes larger than 4 bytes"); + } + + this.as = as; + this.rs = rs; + this.gs = gs; + this.bs = bs; + } + + 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); + } + return original; + } + + 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); + } +// } else { +// for (int i = bpp - 1; i >= 0; i--) { +// byte bt = (byte) ((pixel >> (i * 8)) & 0xff); +// buf.put(idx + i, bt); +// } +// } + } + + @Override + public void readComponents(ByteBuffer buf, int x, int y, int width, int[] components, byte[] tmp) { + int inputPixel = readPixelRaw(buf, (x + y * width) * bpp, bpp); + components[0] = (inputPixel >> as) & maxAlpha; + components[1] = (inputPixel >> rs) & maxRed; + components[2] = (inputPixel >> gs) & maxGreen; + components[3] = (inputPixel >> bs) & maxBlue; + } + + public void writeComponents(ByteBuffer buf, int x, int y, int width, int[] components, byte[] tmp) { + // Shift components then mask them + // Map all components into a single bitspace + int outputPixel = ((components[0] & maxAlpha) << as) + | ((components[1] & maxRed) << rs) + | ((components[2] & maxGreen) << gs) + | ((components[3] & maxBlue) << bs); + + // Find index in image where to write pixel. + // Write the resultant bitspace into the pixel. + writePixelRaw(buf, (x + y * width) * bpp, outputPixel, bpp); + } +} diff --git a/engine/src/core/com/jme3/texture/image/ByteAlignedImageCodec.java b/engine/src/core/com/jme3/texture/image/ByteAlignedImageCodec.java new file mode 100644 index 000000000..eff57a657 --- /dev/null +++ b/engine/src/core/com/jme3/texture/image/ByteAlignedImageCodec.java @@ -0,0 +1,96 @@ +package com.jme3.texture.image; + +import java.nio.ByteBuffer; + +class ByteAlignedImageCodec extends ImageCodec { + + private final int ap, az, rp, rz, gp, gz, bp, bz; + boolean be; + + public ByteAlignedImageCodec(int bpp, int flags, int az, int rz, int gz, int bz, int ap, int rp, int gp, int bp) { + // Cast to long to compute max vals, since some components could be as high as 32 bits. + super(bpp, flags, + (int)(((long)1 << (az << 3)) - 1), + (int)(((long)1 << (rz << 3)) - 1), + (int)(((long)1 << (gz << 3)) - 1), + (int)(((long)1 << (bz << 3)) - 1)); + + this.ap = ap; + this.az = az; + this.rp = rp; + this.rz = rz; + + this.gp = gp; + this.gz = gz; + this.bp = bp; + this.bz = bz; + } + + private static void readPixelRaw(ByteBuffer buf, int idx, int bpp, byte[] result) { + buf.position(idx); + buf.get(result, 0, bpp); + } + + private static void writePixelRaw(ByteBuffer buf, int idx, byte[] pixel, int bpp) { +// try { + buf.position(idx); + buf.put(pixel, 0, bpp); +// } catch (IndexOutOfBoundsException ex) { +// System.out.println("!"); +// } + } + + private static int readComponent(byte[] encoded, int position, int size) { +// int component = encoded[position] & 0xff; +// while ((--size) > 0){ +// component = (component << 8) | (encoded[++position] & 0xff); +// } +// return component; + try { + int component = 0; + for (int i = size - 1; i >= 0; i--) { + component = (component << 8) | (encoded[position + i] & 0xff); + } + return component; +// position += size - 1; +// +// while ((--size) >= 0) { +// component = (component << 8) | (encoded[position--] & 0xff); +// } +// return component; + } catch (ArrayIndexOutOfBoundsException ex){ + ex.printStackTrace(); + return 0; + } + } + + private void writeComponent(int component, int position, int size, byte[] result) { +// if (!be) { +// while ((--size) >= 0){ +// byte bt = (byte) ((component >> (size * 8)) & 0xff); +// result[position++] = bt; +// } +// } else { + for (int i = 0; i < size; i++) { + byte bt = (byte) ((component >> (i * 8)) & 0xff); + result[position++] = bt; + } +// } + } + + public void readComponents(ByteBuffer buf, int x, int y, int width, int[] components, byte[] tmp) { + readPixelRaw(buf, (x + y * width) * bpp, bpp, tmp); + components[0] = readComponent(tmp, ap, az); + components[1] = readComponent(tmp, rp, rz); + components[2] = readComponent(tmp, gp, gz); + components[3] = readComponent(tmp, bp, bz); + } + + public void writeComponents(ByteBuffer buf, int x, int y, int width, int[] components, byte[] tmp) { + writeComponent(components[0], ap, az, tmp); + writeComponent(components[1], rp, rz, tmp); + writeComponent(components[2], gp, gz, tmp); + writeComponent(components[3], bp, bz, tmp); + writePixelRaw(buf, (x + y * width) * bpp, tmp, bpp); + } +} diff --git a/engine/src/core/com/jme3/texture/image/ImageCodec.java b/engine/src/core/com/jme3/texture/image/ImageCodec.java new file mode 100644 index 000000000..5a3d3ca31 --- /dev/null +++ b/engine/src/core/com/jme3/texture/image/ImageCodec.java @@ -0,0 +1,140 @@ +package com.jme3.texture.image; + +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import java.nio.ByteBuffer; +import java.util.EnumMap; + +abstract class ImageCodec { + + public static final int FLAG_F16 = 1, FLAG_F32 = 2, FLAG_GRAY = 4, FLAG_ALPHAONLY = 8, FLAG_SHAREDEXP = 16; + private static final EnumMap params = new EnumMap(Image.Format.class); + + protected final int bpp, flags, maxAlpha, maxRed, maxGreen, maxBlue; + + public ImageCodec(int bpp, int flags, int maxAlpha, int maxRed, int maxGreen, int maxBlue) { + this.bpp = bpp; + this.flags = flags; + this.maxAlpha = maxAlpha; + this.maxRed = maxRed; + this.maxGreen = maxGreen; + this.maxBlue = maxBlue; + } + + static { + // == ALPHA == + params.put(Format.Alpha8, new BitMaskImageCodec(1, 0, 8, 0, 0, 0, + 0, 0, 0, 0)); + + params.put(Format.Alpha16, new BitMaskImageCodec(2, 0, 16, 0, 0, 0, + 0, 0, 0, 0)); + + // == LUMINANCE == + params.put(Format.Luminance8, new BitMaskImageCodec(1, FLAG_GRAY, 0, 8, 0, 0, + 0, 0, 0, 0)); + params.put(Format.Luminance16, new BitMaskImageCodec(2, FLAG_GRAY, 0, 16, 0, 0, + 0, 0, 0, 0)); + params.put(Format.Luminance16F, new BitMaskImageCodec(2, FLAG_GRAY | FLAG_F16, 0, 16, 0, 0, + 0, 0, 0, 0)); + params.put(Format.Luminance32F, new BitMaskImageCodec(4, FLAG_GRAY | FLAG_F32, 0, 32, 0, 0, + 0, 0, 0, 0)); + + // == INTENSITY == + // ?? + + // == LUMINANCA ALPHA == + params.put(Format.Luminance8Alpha8, new BitMaskImageCodec(2, FLAG_GRAY, + 8, 8, 0, 0, + 8, 0, 0, 0)); + + params.put(Format.Luminance16Alpha16, new BitMaskImageCodec(4, FLAG_GRAY, + 16, 16, 0, 0, + 16, 0, 0, 0)); + + params.put(Format.Luminance16FAlpha16F, new BitMaskImageCodec(4, FLAG_GRAY | FLAG_F16, + 16, 16, 0, 0, + 16, 0, 0, 0)); + + // == RGB == + params.put(Format.BGR8, new BitMaskImageCodec(3, 0, + 0, 8, 8, 8, + 0, 16, 8, 0)); + + params.put(Format.RGB565, new BitMaskImageCodec(2, 0, + 0, 5, 6, 5, + 0, 11, 5, 0)); + + params.put(Format.RGB8, new BitMaskImageCodec(3, 0, + 0, 8, 8, 8, + 0, 0, 8, 16)); + + params.put(Format.RGB16, new ByteAlignedImageCodec(6, 0, + 0, 2, 2, 2, + 0, 0, 2, 4)); + + params.put(Format.RGB32F, new ByteAlignedImageCodec(12, FLAG_F32, + 0, 4, 4, 4, + 0, 0, 4, 8)); + + ByteAlignedImageCodec rgb16f = new ByteAlignedImageCodec(6, FLAG_F16, + 0, 2, 2, 2, + 0, 0, 2, 4); + params.put(Format.RGB16F, rgb16f); + params.put(Format.RGB16F_to_RGB111110F, rgb16f); + params.put(Format.RGB16F_to_RGB9E5, rgb16f); + + + // == RGBA == + params.put(Format.ABGR8, new BitMaskImageCodec(4, 0, + 0, 8, 8, 8, + 0, 24, 16, 8)); + + params.put(Format.ARGB4444, new BitMaskImageCodec(2, 0, + 4, 4, 4, 4, + 12, 0, 4, 8)); + + params.put(Format.RGB5A1, new BitMaskImageCodec(2, 0, + 1, 5, 5, 5, + 0, 11, 6, 1)); + ((BitMaskImageCodec)params.get(Format.RGB5A1)).be = true; + + params.put(Format.RGBA8, new ByteAlignedImageCodec(4, 0, + 0, 1, 1, 1, + 0, 0, 1, 2)); + + //new BitMaskImageCodec(4, 0, + // 8, 8, 8, 8, + // 24, 0, 8, 16)); + + params.put(Format.RGBA16, new ByteAlignedImageCodec(8, 0, + 2, 2, 2, 2, + 6, 0, 2, 4)); + + params.put(Format.RGBA16F, new ByteAlignedImageCodec(8, FLAG_F16, + 2, 2, 2, 2, + 6, 0, 2, 4)); + + params.put(Format.RGBA32F, new ByteAlignedImageCodec(16, FLAG_F32, + 4, 4, 4, 4, + 12, 0, 4, 8)); + } + + public abstract void readComponents(ByteBuffer buf, int x, int y, int width, int[] components, byte[] tmp); + + public abstract void writeComponents(ByteBuffer buf, int x, int y, int width, int[] components, byte[] tmp); + + /** + * Looks up the format in the codec registry. + * The codec will be able to decode the given format. + * + * @param format The format to lookup. + * @return The codec capable of decoding it, or null if not found. + */ + public static ImageCodec lookup(Format format) { + ImageCodec codec = params.get(format); + if (codec == null) { + throw new UnsupportedOperationException("The format " + format + " is not supported"); + } + return codec; + } +} diff --git a/engine/src/core/com/jme3/texture/image/ImageRaster.java b/engine/src/core/com/jme3/texture/image/ImageRaster.java new file mode 100644 index 000000000..7b59dbbbc --- /dev/null +++ b/engine/src/core/com/jme3/texture/image/ImageRaster.java @@ -0,0 +1,231 @@ +package com.jme3.texture.image; + +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.texture.Image; +import java.nio.ByteBuffer; + +/** + * Utility class for reading and writing from jME3 {@link Image images}. + *
+ * Allows directly manipulating pixels of the image by writing and + * reading {@link ColorRGBA colors} at any coordinate, without + * regard to the underlying {@link Image.Format format} of the image. + * NOTE: compressed and depth formats are not supported. + * Special RGB formats like RGB111110F and RGB9E5 are not supported + * at the moment, but may be added later on. For now + * use RGB16F_to_RGB111110F and RGB16F_to_RGB9E5 to handle + * the conversion on the GPU. + *

+ * If direct manipulations are done to the image, such as replacing + * the image data, or changing the width, height, or format, then + * all current instances of ImageReadWrite become invalid, and + * new instances must be created in order to properly access + * the image data. + * + * Usage example:
+ * + * Image myImage = ... + * ImageReadWrite imageRW = new ImageReadWrite(myImage); + * imageRW.setPixel(1, 5, ColorRGBA.Green); + * System.out.println( imageRW.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; + + /** + * 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. + */ + 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; + } + } + + /** + * Create new image reader / writer for 2D images. + * + * @param image The image to read / write to. + */ + public ImageRaster(Image image) { + this(image, 0); + if (image.getData().size() > 1) { + throw new IllegalStateException("Use constructor that takes slices argument to read from multislice image"); + } + } + + 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"); + } + } + + /** + * Sets the pixel at the given coordinate to the given color. + *

+ * For all integer based formats (those not ending in "F"), the + * color is first clamped to 0.0 - 1.0 before converting it to + * an integer to avoid overflow. For floating point based formats, + * components larger than 1.0 can be represented, but components + * lower than 0.0 are still not allowed (as all formats are unsigned). + *

+ * If the underlying format is grayscale (e.g. one of the luminance formats, + * such as {@link Image.Format#Luminance8}) then a color to grayscale + * conversion is done first, before writing the result into the image. + *

+ * If the image does not have some of the components in the color (such + * as alpha, or any of the color components), then these components + * will be ignored. The only exception to this is luminance formats + * for which the color is converted to luminance first (see above). + *

+ * After writing the color, the image shall be marked as requiring an + * update. The next time it is used for rendering, all pixel changes + * will be reflected when the image is rendered. + * + * @param x The x coordinate, from 0 to width - 1. + * @param y The y coordinate, from 0 to height - 1. + * @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(); + } + + /** + * Retrieve the color at the given coordinate. + *

+ * Any components that are not defined in the image format + * will be set to 1.0 in the returned color. For example, + * reading from an {@link Image.Format#Alpha8} format will + * return a ColorRGBA with the R, G, and B components set to 1.0, and + * the A component set to the alpha in the image. + *

+ * For grayscale or luminance formats, the luminance value is replicated + * in the R, G, and B components. + *

+ * Integer formats are converted to the range 0.0 - 1.0, based + * on the maximum possible integer value that can be represented + * by the number of bits the component has. + * For example, the {@link Image.Format#RGB5A1} format can + * contain the integer values 0 - 31, a conversion to floating point + * is done by diving the integer value by 31 (done with floating point + * precision). + * + * @param x The x coordinate, from 0 to width - 1. + * @param y The y coordinate, from 0 to height - 1. + * @param store Storage location for the read color, if null, + * then a new ColorRGBA is created and returned with the read color. + * @return The store parameter, if it is null, then a new ColorRGBA + * 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; + } + + /** + * Retrieve the color at the given coordinate. + *

+ * Convenience method that does not take a store argument. Equivalent + * to calling getPixel(x, y, null). + * See {@link #getPixel(int, int, com.jme3.math.ColorRGBA) } for + * more information. + * + * @param x The x coordinate, from 0 to width - 1. + * @param y The y coordinate, from 0 to height - 1. + * @return A new ColorRGBA with the read color. + * @throws IllegalArgumentException If x or y are outside the image dimensions + */ + public ColorRGBA getPixel(int x, int y) { + return getPixel(x, y, null); + } +} diff --git a/engine/src/test/jme3test/texture/TestImageRaster.java b/engine/src/test/jme3test/texture/TestImageRaster.java new file mode 100644 index 000000000..5ed707c9c --- /dev/null +++ b/engine/src/test/jme3test/texture/TestImageRaster.java @@ -0,0 +1,169 @@ +package jme3test.texture; + + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +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; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.MagFilter; +import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ImageRaster; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; + +public class TestImageRaster extends SimpleApplication { + + private Image convertImage(Image image, Format newFormat) { + int width = image.getWidth(); + int height = image.getHeight(); + 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); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + ColorRGBA color = sourceReader.getPixel(x, y); + targetWriter.setPixel(x, y, color); + } + } + + return convertedImage; + } + + private void convertAndPutImage(Image image, float posX, float posY) { + Texture tex = new Texture2D(image); + tex.setMagFilter(MagFilter.Nearest); + tex.setMinFilter(MinFilter.NearestNoMipMaps); + tex.setAnisotropicFilter(16); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", tex); + + Quad q = new Quad(5, 5); + Geometry g = new Geometry("quad", q); + g.setLocalTranslation(posX, posY - 5, -0.0001f); + g.setMaterial(mat); + rootNode.attachChild(g); + + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText txt = new BitmapText(fnt); + txt.setBox(new Rectangle(0, 0, 5, 5)); + txt.setQueueBucket(RenderQueue.Bucket.Transparent); + txt.setSize(0.5f); + txt.setText(image.getFormat().name()); + txt.setLocalTranslation(posX, posY, 0); + rootNode.attachChild(txt); + } + + private Image createTestImage() { + Image testImage = new Image(Format.BGR8, 4, 3, BufferUtils.createByteBuffer(4 * 4 * 3)); + + ImageRaster io = new ImageRaster(testImage); + io.setPixel(0, 0, ColorRGBA.Black); + io.setPixel(1, 0, ColorRGBA.Gray); + io.setPixel(2, 0, ColorRGBA.White); + io.setPixel(3, 0, ColorRGBA.White.mult(4)); // HDR color + + io.setPixel(0, 1, ColorRGBA.Red); + io.setPixel(1, 1, ColorRGBA.Green); + io.setPixel(2, 1, ColorRGBA.Blue); + io.setPixel(3, 1, new ColorRGBA(0, 0, 0, 0)); + + io.setPixel(0, 2, ColorRGBA.Yellow); + io.setPixel(1, 2, ColorRGBA.Magenta); + io.setPixel(2, 2, ColorRGBA.Cyan); + io.setPixel(3, 2, new ColorRGBA(1, 1, 1, 0)); + + return testImage; + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(16, 6, 36)); + flyCam.setMoveSpeed(10); + + Texture tex = assetManager.loadTexture("com/jme3/app/Monkey.png"); +// Texture tex = assetManager.loadTexture("Textures/HdrTest/Memorial.hdr"); + Image originalImage = tex.getImage(); + + Image image = convertImage(originalImage, Format.RGBA32F); + convertAndPutImage(image, 0, 0); + + image = convertImage(originalImage, Format.RGB32F); + convertAndPutImage(image, 5, 0); + + image = convertImage(originalImage, Format.RGBA16F); + convertAndPutImage(image, 10, 0); + + image = convertImage(originalImage, Format.RGB16F); + convertAndPutImage(image, 15, 0); + + image = convertImage(originalImage, Format.RGB16F_to_RGB9E5); + convertAndPutImage(image, 20, 0); + + image = convertImage(originalImage, Format.RGB16F_to_RGB111110F); + convertAndPutImage(image, 25, 0); + + image = convertImage(originalImage, Format.RGBA16); + convertAndPutImage(image, 0, 5); + + image = convertImage(originalImage, Format.RGB16); + convertAndPutImage(image, 5, 5); + + image = convertImage(originalImage, Format.RGBA8); + convertAndPutImage(image, 10, 5); + + image = convertImage(originalImage, Format.RGB8); + convertAndPutImage(image, 15, 5); + + image = convertImage(originalImage, Format.ABGR8); + convertAndPutImage(image, 20, 5); + + image = convertImage(originalImage, Format.BGR8); + convertAndPutImage(image, 25, 5); + + image = convertImage(originalImage, Format.RGB5A1); + convertAndPutImage(image, 0, 10); + + image = convertImage(originalImage, Format.ARGB4444); + convertAndPutImage(image, 5, 10); + + image = convertImage(originalImage, Format.Luminance32F); + convertAndPutImage(image, 0, 15); + + image = convertImage(originalImage, Format.Luminance16FAlpha16F); + convertAndPutImage(image, 5, 15); + + image = convertImage(originalImage, Format.Luminance16F); + convertAndPutImage(image, 10, 15); + + image = convertImage(originalImage, Format.Luminance16Alpha16); + convertAndPutImage(image, 15, 15); + + image = convertImage(originalImage, Format.Luminance16); + convertAndPutImage(image, 20, 15); + + image = convertImage(originalImage, Format.Luminance8Alpha8); + convertAndPutImage(image, 25, 15); + + image = convertImage(originalImage, Format.Luminance8); + convertAndPutImage(image, 30, 15); + } + + public static void main(String[] args) { + TestImageRaster app = new TestImageRaster(); + app.start(); + } +}