diff --git a/engine/src/core/com/jme3/texture/Image.java b/engine/src/core/com/jme3/texture/Image.java index 467df292b..42612391f 100644 --- a/engine/src/core/com/jme3/texture/Image.java +++ b/engine/src/core/com/jme3/texture/Image.java @@ -1,842 +1,862 @@ -/* - * Copyright (c) 2009-2010 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.jme3.texture; - -import com.jme3.export.*; -import com.jme3.renderer.Caps; -import com.jme3.renderer.Renderer; -import com.jme3.util.NativeObject; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Image defines a data format for a graphical image. The image - * is defined by a format, a height and width, and the image data. The width and - * height must be greater than 0. The data is contained in a byte buffer, and - * should be packed before creation of the image object. - * - * @author Mark Powell - * @author Joshua Slack - * @version $Id: Image.java 4131 2009-03-19 20:15:28Z blaine.dev $ - */ -public class Image extends NativeObject implements Savable /*, Cloneable*/ { - - public enum Format { - /** - * 8-bit alpha - */ - Alpha8(8), - - /** - * 16-bit alpha - */ - Alpha16(16), - - /** - * 8-bit grayscale/luminance. - */ - Luminance8(8), - - /** - * 16-bit grayscale/luminance. - */ - Luminance16(16), - - /** - * half-precision floating-point grayscale/luminance. - */ - Luminance16F(16,true), - - /** - * single-precision floating-point grayscale/luminance. - */ - Luminance32F(32,true), - - /** - * 8-bit luminance/grayscale and 8-bit alpha. - */ - Luminance8Alpha8(16), - - /** - * 16-bit luminance/grayscale and 16-bit alpha. - */ - Luminance16Alpha16(32), - - /** - * half-precision floating-point grayscale/luminance and alpha. - */ - Luminance16FAlpha16F(32,true), - - @Deprecated - Intensity8(8), - - @Deprecated - Intensity16(16), - - /** - * 8-bit blue, green, and red. - */ - BGR8(24), // BGR and ABGR formats are often used on windows systems - - /** - * 8-bit red, green, and blue. - */ - RGB8(24), - - @Deprecated - RGB10(30), - - /** - * 16-bit red, green, and blue. - */ - RGB16(48), - - /** - * 5-bit red, 6-bit green, and 5-bit blue. - */ - RGB565(16), - - /** - * 4-bit alpha, red, green, and blue. Used on Android only. - */ - ARGB4444(16), - - /** - * 5-bit red, green, and blue with 1-bit alpha. - */ - RGB5A1(16), - - /** - * 8-bit red, green, blue, and alpha. - */ - RGBA8(32), - - /** - * 8-bit alpha, blue, green, and red. - */ - ABGR8(32), - - /** - * 16-bit red, green, blue and alpha - */ - RGBA16(64), - - /** - * S3TC compression DXT1. - * Called BC1 in DirectX10. - */ - DXT1(4,false,true, false), - - /** - * S3TC compression DXT1 with 1-bit alpha. - */ - DXT1A(4,false,true, false), - - /** - * S3TC compression DXT3 with 4-bit alpha. - * Called BC2 in DirectX10. - */ - DXT3(8,false,true, false), - - /** - * S3TC compression DXT5 with interpolated 8-bit alpha. - * Called BC3 in DirectX10. - */ - DXT5(8,false,true, false), - - /** - * Luminance-Alpha Texture Compression. - * Called BC5 in DirectX10. - */ - LATC(8, false, true, false), - - /** - * Arbitrary depth format. The precision is chosen by the video - * hardware. - */ - Depth(0,true,false,false), - - /** - * 16-bit depth. - */ - Depth16(16,true,false,false), - - /** - * 24-bit depth. - */ - Depth24(24,true,false,false), - - /** - * 32-bit depth. - */ - Depth32(32,true,false,false), - - /** - * single-precision floating point depth. - */ - Depth32F(32,true,false,true), - - /** - * Texture data is stored as {@link Format#RGB16F} in system memory, - * but will be converted to {@link Format#RGB111110F} when sent - * to the video hardware. - */ - RGB16F_to_RGB111110F(48,true), - - /** - * unsigned floating-point red, green and blue that uses 32 bits. - */ - RGB111110F(32,true), - - /** - * Texture data is stored as {@link Format#RGB16F} in system memory, - * but will be converted to {@link Format#RGB9E5} when sent - * to the video hardware. - */ - RGB16F_to_RGB9E5(48,true), - - /** - * 9-bit red, green and blue with 5-bit exponent. - */ - RGB9E5(32,true), - - /** - * half-precision floating point red, green, and blue. - */ - RGB16F(48,true), - - /** - * half-precision floating point red, green, blue, and alpha. - */ - RGBA16F(64,true), - - /** - * single-precision floating point red, green, and blue. - */ - RGB32F(96,true), - - /** - * single-precision floating point red, green, blue and alpha. - */ - RGBA32F(128,true), - - /** - * Luminance/grayscale texture compression. - * Called BC4 in DirectX10. - */ - LTC(4, false, true, false), - - /** - * 24-bit depth with 8-bit stencil. - * Check the cap {@link Caps#PackedDepthStencilBuffer}. - */ - Depth24Stencil8(32, true, false, false); - - private int bpp; - private boolean isDepth; - private boolean isCompressed; - private boolean isFloatingPoint; - - private Format(int bpp){ - this.bpp = bpp; - } - - private Format(int bpp, boolean isFP){ - this(bpp); - this.isFloatingPoint = isFP; - } - - private Format(int bpp, boolean isDepth, boolean isCompressed, boolean isFP){ - this(bpp, isFP); - this.isDepth = isDepth; - this.isCompressed = isCompressed; - } - - /** - * @return bits per pixel. - */ - public int getBitsPerPixel(){ - return bpp; - } - - /** - * @return True if this format is a depth format, false otherwise. - */ - public boolean isDepthFormat(){ - return isDepth; - } - - /** - * @return True if this is a compressed image format, false if - * uncompressed. - */ - public boolean isCompressed() { - return isCompressed; - } - - /** - * @return True if this image format is in floating point, - * false if it is an integer format. - */ - public boolean isFloatingPont(){ - return isFloatingPoint; - } - - } - - // image attributes - protected Format format; - protected int width, height, depth; - protected int[] mipMapSizes; - protected ArrayList data; - protected transient Object efficientData; - protected int multiSamples = 1; -// protected int mipOffset = 0; - - // attributes relating to GL object - protected boolean mipsWereGenerated = false; - protected boolean needGeneratedMips = false; - - /** - * Internal use only. - * The renderer marks which images have generated mipmaps in VRAM - * and which do not, so it can generate them as needed. - * - * @param generated If mipmaps were generated or not. - */ - public void setMipmapsGenerated(boolean generated) { - this.mipsWereGenerated = generated; - } - - /** - * Internal use only. - * Check if the renderer has generated mipmaps for this image in VRAM - * or not. - * - * @return If mipmaps were generated already. - */ - public boolean isMipmapsGenerated() { - return mipsWereGenerated; - } - - /** - * (Package private) Called by {@link Texture} when - * {@link #isMipmapsGenerated() } is false in order to generate - * mipmaps for this image. - */ - void setNeedGeneratedMipmaps() { - needGeneratedMips = true; - } - - /** - * @return True if the image needs to have mipmaps generated - * for it (as requested by the texture). - */ - public boolean isGeneratedMipmapsRequired() { - return needGeneratedMips; - } - - @Override - public void resetObject() { - this.id = -1; - this.mipsWereGenerated = false; - setUpdateNeeded(); - } - - @Override - public void deleteObject(Object rendererObject) { - ((Renderer)rendererObject).deleteImage(this); - } - - @Override - public NativeObject createDestructableClone() { - return new Image(id); - } - - /** - * @return A shallow clone of this image. The data is not cloned. - */ - @Override - public Image clone(){ - Image clone = (Image) super.clone(); - clone.mipMapSizes = mipMapSizes != null ? mipMapSizes.clone() : null; - clone.data = data != null ? new ArrayList(data) : null; - clone.setUpdateNeeded(); - return clone; - } - - /** - * Constructor instantiates a new Image object. All values - * are undefined. - */ - public Image() { - super(Image.class); - data = new ArrayList(1); - } - - protected Image(int id){ - super(Image.class, id); - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param data - * the image data. - * @param mipMapSizes - * the array of mipmap sizes, or null for no mipmaps. - */ - public Image(Format format, int width, int height, int depth, ArrayList data, - int[] mipMapSizes) { - - this(); - - if (mipMapSizes != null && mipMapSizes.length <= 1) { - mipMapSizes = null; - } - - setFormat(format); - this.width = width; - this.height = height; - this.data = data; - this.depth = depth; - this.mipMapSizes = mipMapSizes; - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param data - * the image data. - * @param mipMapSizes - * the array of mipmap sizes, or null for no mipmaps. - */ - public Image(Format format, int width, int height, ByteBuffer data, - int[] mipMapSizes) { - - this(); - - if (mipMapSizes != null && mipMapSizes.length <= 1) { - mipMapSizes = null; - } - - setFormat(format); - this.width = width; - this.height = height; - if (data != null){ - this.data = new ArrayList(1); - this.data.add(data); - } - this.mipMapSizes = mipMapSizes; - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param data - * the image data. - */ - public Image(Format format, int width, int height, int depth, ArrayList data) { - this(format, width, height, depth, data, null); - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param data - * the image data. - */ - public Image(Format format, int width, int height, ByteBuffer data) { - this(format, width, height, data, null); - } - - /** - * @return The number of samples (for multisampled textures). - * @see Image#setMultiSamples(int) - */ - public int getMultiSamples() { - return multiSamples; - } - - /** - * @param multiSamples Set the number of samples to use for this image, - * setting this to a value higher than 1 turns this image/texture - * into a multisample texture (on OpenGL3.1 and higher). - */ - public void setMultiSamples(int multiSamples) { - if (multiSamples <= 0) - throw new IllegalArgumentException("multiSamples must be > 0"); - - if (getData(0) != null) - throw new IllegalArgumentException("Cannot upload data as multisample texture"); - - if (hasMipmaps()) - throw new IllegalArgumentException("Multisample textures do not support mipmaps"); - - this.multiSamples = multiSamples; - } - - /** - * setData sets the data that makes up the image. This data - * is packed into an array of ByteBuffer objects. - * - * @param data - * the data that contains the image information. - */ - public void setData(ArrayList data) { - this.data = data; - setUpdateNeeded(); - } - - /** - * setData sets the data that makes up the image. This data - * is packed into a single ByteBuffer. - * - * @param data - * the data that contains the image information. - */ - public void setData(ByteBuffer data) { - this.data = new ArrayList(1); - this.data.add(data); - setUpdateNeeded(); - } - - public void addData(ByteBuffer data) { - if (this.data == null) - this.data = new ArrayList(1); - this.data.add(data); - setUpdateNeeded(); - } - - public void setData(int index, ByteBuffer data) { - if (index >= 0) { - while (this.data.size() <= index) { - this.data.add(null); - } - this.data.set(index, data); - setUpdateNeeded(); - } else { - throw new IllegalArgumentException("index must be greater than or equal to 0."); - } - } - - /** - * Set the efficient data representation of this image. - *

- * Some system implementations are more efficient at operating - * on data other than ByteBuffers, in that case, this method can be used. - * - * @param efficientData - */ - public void setEfficentData(Object efficientData){ - this.efficientData = efficientData; - setUpdateNeeded(); - } - - /** - * @return The efficient data representation of this image. - * @see Image#setEfficentData(java.lang.Object) - */ - public Object getEfficentData(){ - return efficientData; - } - - /** - * Sets the mipmap sizes stored in this image's data buffer. Mipmaps are - * stored sequentially, and the first mipmap is the main image data. To - * specify no mipmaps, pass null and this will automatically be expanded - * into a single mipmap of the full - * - * @param mipMapSizes - * the mipmap sizes array, or null for a single image map. - */ - public void setMipMapSizes(int[] mipMapSizes) { - if (mipMapSizes != null && mipMapSizes.length <= 1) - mipMapSizes = null; - - this.mipMapSizes = mipMapSizes; - setUpdateNeeded(); - } - - /** - * setHeight sets the height value of the image. It is - * typically a good idea to try to keep this as a multiple of 2. - * - * @param height - * the height of the image. - */ - public void setHeight(int height) { - this.height = height; - setUpdateNeeded(); - } - - /** - * setDepth sets the depth value of the image. It is - * typically a good idea to try to keep this as a multiple of 2. This is - * used for 3d images. - * - * @param depth - * the depth of the image. - */ - public void setDepth(int depth) { - this.depth = depth; - setUpdateNeeded(); - } - - /** - * setWidth sets the width value of the image. It is - * typically a good idea to try to keep this as a multiple of 2. - * - * @param width - * the width of the image. - */ - public void setWidth(int width) { - this.width = width; - setUpdateNeeded(); - } - - /** - * setFormat sets the image format for this image. - * - * @param format - * the image format. - * @throws NullPointerException - * if format is null - * @see Format - */ - public void setFormat(Format format) { - if (format == null) { - throw new NullPointerException("format may not be null."); - } - - this.format = format; - setUpdateNeeded(); - } - - /** - * getFormat returns the image format for this image. - * - * @return the image format. - * @see Format - */ - public Format getFormat() { - return format; - } - - /** - * getWidth returns the width of this image. - * - * @return the width of this image. - */ - public int getWidth() { - return width; - } - - /** - * getHeight returns the height of this image. - * - * @return the height of this image. - */ - public int getHeight() { - return height; - } - - /** - * getDepth returns the depth of this image (for 3d images). - * - * @return the depth of this image. - */ - public int getDepth() { - return depth; - } - - /** - * getData returns the data for this image. If the data is - * undefined, null will be returned. - * - * @return the data for this image. - */ - public List getData() { - return data; - } - - /** - * getData returns the data for this image. If the data is - * undefined, null will be returned. - * - * @return the data for this image. - */ - public ByteBuffer getData(int index) { - if (data.size() > index) - return data.get(index); - else - return null; - } - - /** - * Returns whether the image data contains mipmaps. - * - * @return true if the image data contains mipmaps, false if not. - */ - public boolean hasMipmaps() { - return mipMapSizes != null; - } - - /** - * Returns the mipmap sizes for this image. - * - * @return the mipmap sizes for this image. - */ - public int[] getMipMapSizes() { - return mipMapSizes; - } - - @Override - public String toString(){ - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName()); - sb.append("[size=").append(width).append("x").append(height); - - if (depth > 1) - sb.append("x").append(depth); - - sb.append(", format=").append(format.name()); - - if (hasMipmaps()) - sb.append(", mips"); - - if (getId() >= 0) - sb.append(", id=").append(id); - - sb.append("]"); - - return sb.toString(); - } - - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - if (!(other instanceof Image)) { - return false; - } - Image that = (Image) other; - if (this.getFormat() != that.getFormat()) - return false; - if (this.getWidth() != that.getWidth()) - return false; - if (this.getHeight() != that.getHeight()) - return false; - if (this.getData() != null && !this.getData().equals(that.getData())) - return false; - if (this.getData() == null && that.getData() != null) - return false; - if (this.getMipMapSizes() != null - && !Arrays.equals(this.getMipMapSizes(), that.getMipMapSizes())) - return false; - if (this.getMipMapSizes() == null && that.getMipMapSizes() != null) - return false; - if (this.getMultiSamples() != that.getMultiSamples()) - return false; - - return true; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 97 * hash + (this.format != null ? this.format.hashCode() : 0); - hash = 97 * hash + this.width; - hash = 97 * hash + this.height; - hash = 97 * hash + this.depth; - hash = 97 * hash + Arrays.hashCode(this.mipMapSizes); - hash = 97 * hash + (this.data != null ? this.data.hashCode() : 0); - hash = 97 * hash + this.multiSamples; - return hash; - } - - public void write(JmeExporter e) throws IOException { - OutputCapsule capsule = e.getCapsule(this); - capsule.write(format, "format", Format.RGBA8); - capsule.write(width, "width", 0); - capsule.write(height, "height", 0); - capsule.write(depth, "depth", 0); - capsule.write(mipMapSizes, "mipMapSizes", null); - capsule.write(multiSamples, "multiSamples", 1); - capsule.writeByteBufferArrayList(data, "data", null); - } - - public void read(JmeImporter e) throws IOException { - InputCapsule capsule = e.getCapsule(this); - format = capsule.readEnum("format", Format.class, Format.RGBA8); - width = capsule.readInt("width", 0); - height = capsule.readInt("height", 0); - depth = capsule.readInt("depth", 0); - mipMapSizes = capsule.readIntArray("mipMapSizes", null); - multiSamples = capsule.readInt("multiSamples", 1); - data = (ArrayList) capsule.readByteBufferArrayList("data", null); - } - -} +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.texture; + +import com.jme3.export.*; +import com.jme3.renderer.Caps; +import com.jme3.renderer.Renderer; +import com.jme3.util.NativeObject; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Image defines a data format for a graphical image. The image + * is defined by a format, a height and width, and the image data. The width and + * height must be greater than 0. The data is contained in a byte buffer, and + * should be packed before creation of the image object. + * + * @author Mark Powell + * @author Joshua Slack + * @version $Id: Image.java 4131 2009-03-19 20:15:28Z blaine.dev $ + */ +public class Image extends NativeObject implements Savable /*, Cloneable*/ { + + public enum Format { + /** + * 8-bit alpha + */ + Alpha8(8), + + /** + * 16-bit alpha + */ + Alpha16(16), + + /** + * 8-bit grayscale/luminance. + */ + Luminance8(8), + + /** + * 16-bit grayscale/luminance. + */ + Luminance16(16), + + /** + * half-precision floating-point grayscale/luminance. + */ + Luminance16F(16,true), + + /** + * single-precision floating-point grayscale/luminance. + */ + Luminance32F(32,true), + + /** + * 8-bit luminance/grayscale and 8-bit alpha. + */ + Luminance8Alpha8(16), + + /** + * 16-bit luminance/grayscale and 16-bit alpha. + */ + Luminance16Alpha16(32), + + /** + * half-precision floating-point grayscale/luminance and alpha. + */ + Luminance16FAlpha16F(32,true), + + @Deprecated + Intensity8(8), + + @Deprecated + Intensity16(16), + + /** + * 8-bit blue, green, and red. + */ + BGR8(24), // BGR and ABGR formats are often used on windows systems + + /** + * 8-bit red, green, and blue. + */ + RGB8(24), + + @Deprecated + RGB10(30), + + /** + * 16-bit red, green, and blue. + */ + RGB16(48), + + /** + * 5-bit red, 6-bit green, and 5-bit blue. + */ + RGB565(16), + + /** + * 4-bit alpha, red, green, and blue. Used on Android only. + */ + ARGB4444(16), + + /** + * 5-bit red, green, and blue with 1-bit alpha. + */ + RGB5A1(16), + + /** + * 8-bit red, green, blue, and alpha. + */ + RGBA8(32), + + /** + * 8-bit alpha, blue, green, and red. + */ + ABGR8(32), + + /** + * 16-bit red, green, blue and alpha + */ + RGBA16(64), + + /** + * S3TC compression DXT1. + * Called BC1 in DirectX10. + */ + DXT1(4,false,true, false), + + /** + * S3TC compression DXT1 with 1-bit alpha. + */ + DXT1A(4,false,true, false), + + /** + * S3TC compression DXT3 with 4-bit alpha. + * Called BC2 in DirectX10. + */ + DXT3(8,false,true, false), + + /** + * S3TC compression DXT5 with interpolated 8-bit alpha. + * Called BC3 in DirectX10. + */ + DXT5(8,false,true, false), + + /** + * Luminance-Alpha Texture Compression. + * Called BC5 in DirectX10. + */ + LATC(8, false, true, false), + + /** + * Arbitrary depth format. The precision is chosen by the video + * hardware. + */ + Depth(0,true,false,false), + + /** + * 16-bit depth. + */ + Depth16(16,true,false,false), + + /** + * 24-bit depth. + */ + Depth24(24,true,false,false), + + /** + * 32-bit depth. + */ + Depth32(32,true,false,false), + + /** + * single-precision floating point depth. + */ + Depth32F(32,true,false,true), + + /** + * Texture data is stored as {@link Format#RGB16F} in system memory, + * but will be converted to {@link Format#RGB111110F} when sent + * to the video hardware. + */ + RGB16F_to_RGB111110F(48,true), + + /** + * unsigned floating-point red, green and blue that uses 32 bits. + */ + RGB111110F(32,true), + + /** + * Texture data is stored as {@link Format#RGB16F} in system memory, + * but will be converted to {@link Format#RGB9E5} when sent + * to the video hardware. + */ + RGB16F_to_RGB9E5(48,true), + + /** + * 9-bit red, green and blue with 5-bit exponent. + */ + RGB9E5(32,true), + + /** + * half-precision floating point red, green, and blue. + */ + RGB16F(48,true), + + /** + * half-precision floating point red, green, blue, and alpha. + */ + RGBA16F(64,true), + + /** + * single-precision floating point red, green, and blue. + */ + RGB32F(96,true), + + /** + * single-precision floating point red, green, blue and alpha. + */ + RGBA32F(128,true), + + /** + * Luminance/grayscale texture compression. + * Called BC4 in DirectX10. + */ + LTC(4, false, true, false), + + /** + * 24-bit depth with 8-bit stencil. + * Check the cap {@link Caps#PackedDepthStencilBuffer}. + */ + Depth24Stencil8(32, true, false, false); + + private int bpp; + private boolean isDepth; + private boolean isCompressed; + private boolean isFloatingPoint; + + private Format(int bpp){ + this.bpp = bpp; + } + + private Format(int bpp, boolean isFP){ + this(bpp); + this.isFloatingPoint = isFP; + } + + private Format(int bpp, boolean isDepth, boolean isCompressed, boolean isFP){ + this(bpp, isFP); + this.isDepth = isDepth; + this.isCompressed = isCompressed; + } + + /** + * @return bits per pixel. + */ + public int getBitsPerPixel(){ + return bpp; + } + + /** + * @return True if this format is a depth format, false otherwise. + */ + public boolean isDepthFormat(){ + return isDepth; + } + + /** + * @return True if this is a compressed image format, false if + * uncompressed. + */ + public boolean isCompressed() { + return isCompressed; + } + + /** + * @return True if this image format is in floating point, + * false if it is an integer format. + */ + public boolean isFloatingPont(){ + return isFloatingPoint; + } + + } + + // image attributes + protected Format format; + protected int width, height, depth; + protected int[] mipMapSizes; + protected ArrayList data; + protected transient Object efficientData; + protected int multiSamples = 1; +// protected int mipOffset = 0; + + // attributes relating to GL object + protected boolean mipsWereGenerated = false; + protected boolean needGeneratedMips = false; + + /** + * Internal use only. + * The renderer marks which images have generated mipmaps in VRAM + * and which do not, so it can generate them as needed. + * + * @param generated If mipmaps were generated or not. + */ + public void setMipmapsGenerated(boolean generated) { + this.mipsWereGenerated = generated; + } + + /** + * Internal use only. + * Check if the renderer has generated mipmaps for this image in VRAM + * or not. + * + * @return If mipmaps were generated already. + */ + public boolean isMipmapsGenerated() { + return mipsWereGenerated; + } + + /** + * (Package private) Called by {@link Texture} when + * {@link #isMipmapsGenerated() } is false in order to generate + * mipmaps for this image. + */ + void setNeedGeneratedMipmaps() { + needGeneratedMips = true; + } + + /** + * @return True if the image needs to have mipmaps generated + * for it (as requested by the texture). + */ + public boolean isGeneratedMipmapsRequired() { + return needGeneratedMips; + } + + @Override + public void resetObject() { + this.id = -1; + this.mipsWereGenerated = false; + setUpdateNeeded(); + } + + @Override + public void deleteObject(Object rendererObject) { + ((Renderer)rendererObject).deleteImage(this); + } + + @Override + public NativeObject createDestructableClone() { + return new Image(id); + } + + /** + * @return A shallow clone of this image. The data is not cloned. + */ + @Override + public Image clone(){ + Image clone = (Image) super.clone(); + clone.mipMapSizes = mipMapSizes != null ? mipMapSizes.clone() : null; + clone.data = data != null ? new ArrayList(data) : null; + clone.setUpdateNeeded(); + return clone; + } + + /** + * Constructor instantiates a new Image object. All values + * are undefined. + */ + public Image() { + super(Image.class); + data = new ArrayList(1); + } + + protected Image(int id){ + super(Image.class, id); + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param data + * the image data. + * @param mipMapSizes + * the array of mipmap sizes, or null for no mipmaps. + */ + public Image(Format format, int width, int height, int depth, ArrayList data, + int[] mipMapSizes) { + + this(); + + if (mipMapSizes != null && mipMapSizes.length <= 1) { + mipMapSizes = null; + } else { + needGeneratedMips = false; + mipsWereGenerated = true; + } + + setFormat(format); + this.width = width; + this.height = height; + this.data = data; + this.depth = depth; + this.mipMapSizes = mipMapSizes; + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param data + * the image data. + * @param mipMapSizes + * the array of mipmap sizes, or null for no mipmaps. + */ + public Image(Format format, int width, int height, ByteBuffer data, + int[] mipMapSizes) { + + this(); + + if (mipMapSizes != null && mipMapSizes.length <= 1) { + mipMapSizes = null; + } else { + needGeneratedMips = false; + mipsWereGenerated = true; + } + + setFormat(format); + this.width = width; + this.height = height; + if (data != null){ + this.data = new ArrayList(1); + this.data.add(data); + } + this.mipMapSizes = mipMapSizes; + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param data + * the image data. + */ + public Image(Format format, int width, int height, int depth, ArrayList data) { + this(format, width, height, depth, data, null); + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param data + * the image data. + */ + public Image(Format format, int width, int height, ByteBuffer data) { + this(format, width, height, data, null); + } + + /** + * @return The number of samples (for multisampled textures). + * @see Image#setMultiSamples(int) + */ + public int getMultiSamples() { + return multiSamples; + } + + /** + * @param multiSamples Set the number of samples to use for this image, + * setting this to a value higher than 1 turns this image/texture + * into a multisample texture (on OpenGL3.1 and higher). + */ + public void setMultiSamples(int multiSamples) { + if (multiSamples <= 0) + throw new IllegalArgumentException("multiSamples must be > 0"); + + if (getData(0) != null) + throw new IllegalArgumentException("Cannot upload data as multisample texture"); + + if (hasMipmaps()) + throw new IllegalArgumentException("Multisample textures do not support mipmaps"); + + this.multiSamples = multiSamples; + } + + /** + * setData sets the data that makes up the image. This data + * is packed into an array of ByteBuffer objects. + * + * @param data + * the data that contains the image information. + */ + public void setData(ArrayList data) { + this.data = data; + setUpdateNeeded(); + } + + /** + * setData sets the data that makes up the image. This data + * is packed into a single ByteBuffer. + * + * @param data + * the data that contains the image information. + */ + public void setData(ByteBuffer data) { + this.data = new ArrayList(1); + this.data.add(data); + setUpdateNeeded(); + } + + public void addData(ByteBuffer data) { + if (this.data == null) + this.data = new ArrayList(1); + this.data.add(data); + setUpdateNeeded(); + } + + public void setData(int index, ByteBuffer data) { + if (index >= 0) { + while (this.data.size() <= index) { + this.data.add(null); + } + this.data.set(index, data); + setUpdateNeeded(); + } else { + throw new IllegalArgumentException("index must be greater than or equal to 0."); + } + } + + /** + * Set the efficient data representation of this image. + *

+ * Some system implementations are more efficient at operating + * on data other than ByteBuffers, in that case, this method can be used. + * + * @param efficientData + */ + public void setEfficentData(Object efficientData){ + this.efficientData = efficientData; + setUpdateNeeded(); + } + + /** + * @return The efficient data representation of this image. + * @see Image#setEfficentData(java.lang.Object) + */ + public Object getEfficentData(){ + return efficientData; + } + + /** + * Sets the mipmap sizes stored in this image's data buffer. Mipmaps are + * stored sequentially, and the first mipmap is the main image data. To + * specify no mipmaps, pass null and this will automatically be expanded + * into a single mipmap of the full + * + * @param mipMapSizes + * the mipmap sizes array, or null for a single image map. + */ + public void setMipMapSizes(int[] mipMapSizes) { + if (mipMapSizes != null && mipMapSizes.length <= 1) + mipMapSizes = null; + + this.mipMapSizes = mipMapSizes; + + if (mipMapSizes != null) { + needGeneratedMips = false; + mipsWereGenerated = false; + } else { + needGeneratedMips = false; + mipsWereGenerated = true; + } + + setUpdateNeeded(); + } + + /** + * setHeight sets the height value of the image. It is + * typically a good idea to try to keep this as a multiple of 2. + * + * @param height + * the height of the image. + */ + public void setHeight(int height) { + this.height = height; + setUpdateNeeded(); + } + + /** + * setDepth sets the depth value of the image. It is + * typically a good idea to try to keep this as a multiple of 2. This is + * used for 3d images. + * + * @param depth + * the depth of the image. + */ + public void setDepth(int depth) { + this.depth = depth; + setUpdateNeeded(); + } + + /** + * setWidth sets the width value of the image. It is + * typically a good idea to try to keep this as a multiple of 2. + * + * @param width + * the width of the image. + */ + public void setWidth(int width) { + this.width = width; + setUpdateNeeded(); + } + + /** + * setFormat sets the image format for this image. + * + * @param format + * the image format. + * @throws NullPointerException + * if format is null + * @see Format + */ + public void setFormat(Format format) { + if (format == null) { + throw new NullPointerException("format may not be null."); + } + + this.format = format; + setUpdateNeeded(); + } + + /** + * getFormat returns the image format for this image. + * + * @return the image format. + * @see Format + */ + public Format getFormat() { + return format; + } + + /** + * getWidth returns the width of this image. + * + * @return the width of this image. + */ + public int getWidth() { + return width; + } + + /** + * getHeight returns the height of this image. + * + * @return the height of this image. + */ + public int getHeight() { + return height; + } + + /** + * getDepth returns the depth of this image (for 3d images). + * + * @return the depth of this image. + */ + public int getDepth() { + return depth; + } + + /** + * getData returns the data for this image. If the data is + * undefined, null will be returned. + * + * @return the data for this image. + */ + public List getData() { + return data; + } + + /** + * getData returns the data for this image. If the data is + * undefined, null will be returned. + * + * @return the data for this image. + */ + public ByteBuffer getData(int index) { + if (data.size() > index) + return data.get(index); + else + return null; + } + + /** + * Returns whether the image data contains mipmaps. + * + * @return true if the image data contains mipmaps, false if not. + */ + public boolean hasMipmaps() { + return mipMapSizes != null; + } + + /** + * Returns the mipmap sizes for this image. + * + * @return the mipmap sizes for this image. + */ + public int[] getMipMapSizes() { + return mipMapSizes; + } + + @Override + public String toString(){ + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append("[size=").append(width).append("x").append(height); + + if (depth > 1) + sb.append("x").append(depth); + + sb.append(", format=").append(format.name()); + + if (hasMipmaps()) + sb.append(", mips"); + + if (getId() >= 0) + sb.append(", id=").append(id); + + sb.append("]"); + + return sb.toString(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof Image)) { + return false; + } + Image that = (Image) other; + if (this.getFormat() != that.getFormat()) + return false; + if (this.getWidth() != that.getWidth()) + return false; + if (this.getHeight() != that.getHeight()) + return false; + if (this.getData() != null && !this.getData().equals(that.getData())) + return false; + if (this.getData() == null && that.getData() != null) + return false; + if (this.getMipMapSizes() != null + && !Arrays.equals(this.getMipMapSizes(), that.getMipMapSizes())) + return false; + if (this.getMipMapSizes() == null && that.getMipMapSizes() != null) + return false; + if (this.getMultiSamples() != that.getMultiSamples()) + return false; + + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.format != null ? this.format.hashCode() : 0); + hash = 97 * hash + this.width; + hash = 97 * hash + this.height; + hash = 97 * hash + this.depth; + hash = 97 * hash + Arrays.hashCode(this.mipMapSizes); + hash = 97 * hash + (this.data != null ? this.data.hashCode() : 0); + hash = 97 * hash + this.multiSamples; + return hash; + } + + public void write(JmeExporter e) throws IOException { + OutputCapsule capsule = e.getCapsule(this); + capsule.write(format, "format", Format.RGBA8); + capsule.write(width, "width", 0); + capsule.write(height, "height", 0); + capsule.write(depth, "depth", 0); + capsule.write(mipMapSizes, "mipMapSizes", null); + capsule.write(multiSamples, "multiSamples", 1); + capsule.writeByteBufferArrayList(data, "data", null); + } + + public void read(JmeImporter e) throws IOException { + InputCapsule capsule = e.getCapsule(this); + format = capsule.readEnum("format", Format.class, Format.RGBA8); + width = capsule.readInt("width", 0); + height = capsule.readInt("height", 0); + depth = capsule.readInt("depth", 0); + mipMapSizes = capsule.readIntArray("mipMapSizes", null); + multiSamples = capsule.readInt("multiSamples", 1); + data = (ArrayList) capsule.readByteBufferArrayList("data", null); + + if (mipMapSizes != null) { + needGeneratedMips = false; + mipsWereGenerated = true; + } + } + +}