aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/texture
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core/com/jme3/texture')
-rw-r--r--engine/src/core/com/jme3/texture/FrameBuffer.java460
-rw-r--r--engine/src/core/com/jme3/texture/Image.java790
-rw-r--r--engine/src/core/com/jme3/texture/Texture.java613
-rw-r--r--engine/src/core/com/jme3/texture/Texture2D.java221
-rw-r--r--engine/src/core/com/jme3/texture/Texture3D.java224
-rw-r--r--engine/src/core/com/jme3/texture/TextureArray.java113
-rw-r--r--engine/src/core/com/jme3/texture/TextureCubeMap.java206
7 files changed, 2627 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/texture/FrameBuffer.java b/engine/src/core/com/jme3/texture/FrameBuffer.java
new file mode 100644
index 0000000..b52927f
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/FrameBuffer.java
@@ -0,0 +1,460 @@
+/*
+ * 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.renderer.Caps;
+import com.jme3.renderer.Renderer;
+import com.jme3.texture.Image.Format;
+import com.jme3.util.NativeObject;
+import java.util.ArrayList;
+
+/**
+ * <p>
+ * <code>FrameBuffer</code>s are rendering surfaces allowing
+ * off-screen rendering and render-to-texture functionality.
+ * Instead of the scene rendering to the screen, it is rendered into the
+ * FrameBuffer, the result can be either a texture or a buffer.
+ * <p>
+ * A <code>FrameBuffer</code> supports two methods of rendering,
+ * using a {@link Texture} or using a buffer.
+ * When using a texture, the result of the rendering will be rendered
+ * onto the texture, after which the texture can be placed on an object
+ * and rendered as if the texture was uploaded from disk.
+ * When using a buffer, the result is rendered onto
+ * a buffer located on the GPU, the data of this buffer is not accessible
+ * to the user. buffers are useful if one
+ * wishes to retrieve only the color content of the scene, but still desires
+ * depth testing (which requires a depth buffer).
+ * Buffers can be copied to other framebuffers
+ * including the main screen, by using
+ * {@link Renderer#copyFrameBuffer(com.jme3.texture.FrameBuffer, com.jme3.texture.FrameBuffer) }.
+ * The content of a {@link RenderBuffer} can be retrieved by using
+ * {@link Renderer#readFrameBuffer(com.jme3.texture.FrameBuffer, java.nio.ByteBuffer) }.
+ * <p>
+ * <code>FrameBuffer</code>s have several attachment points, there are
+ * several <em>color</em> attachment points and a single <em>depth</em>
+ * attachment point.
+ * The color attachment points support image formats such as
+ * {@link Format#RGBA8}, allowing rendering the color content of the scene.
+ * The depth attachment point requires a depth image format.
+ *
+ * @see Renderer#setFrameBuffer(com.jme3.texture.FrameBuffer)
+ *
+ * @author Kirill Vainer
+ */
+public class FrameBuffer extends NativeObject {
+
+ private int width = 0;
+ private int height = 0;
+ private int samples = 1;
+ private ArrayList<RenderBuffer> colorBufs = new ArrayList<RenderBuffer>();
+ private RenderBuffer depthBuf = null;
+ private int colorBufIndex = 0;
+
+ /**
+ * <code>RenderBuffer</code> represents either a texture or a
+ * buffer that will be rendered to. <code>RenderBuffer</code>s
+ * are attached to an attachment slot on a <code>FrameBuffer</code>.
+ */
+ public class RenderBuffer {
+
+ Texture tex;
+ Image.Format format;
+ int id = -1;
+ int slot = -1;
+
+ /**
+ * @return The image format of the render buffer.
+ */
+ public Format getFormat() {
+ return format;
+ }
+
+ /**
+ * @return The texture to render to for this <code>RenderBuffer</code>
+ * or null if content should be rendered into a buffer.
+ */
+ public Texture getTexture(){
+ return tex;
+ }
+
+ /**
+ * Do not use.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Do not use.
+ */
+ public void setId(int id){
+ this.id = id;
+ }
+
+ /**
+ * Do not use.
+ */
+ public int getSlot() {
+ return slot;
+ }
+
+ public void resetObject(){
+ id = -1;
+ }
+
+ public RenderBuffer createDestructableClone(){
+ if (tex != null){
+ return null;
+ }else{
+ RenderBuffer destructClone = new RenderBuffer();
+ destructClone.id = id;
+ return destructClone;
+ }
+ }
+
+ @Override
+ public String toString(){
+ if (tex != null){
+ return "TextureTarget[format=" + format + "]";
+ }else{
+ return "BufferTarget[format=" + format + "]";
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Creates a new FrameBuffer with the given width, height, and number
+ * of samples. If any textures are attached to this FrameBuffer, then
+ * they must have the same number of samples as given in this constructor.
+ * <p>
+ * Note that if the {@link Renderer} does not expose the
+ * {@link Caps#NonPowerOfTwoTextures}, then an exception will be thrown
+ * if the width and height arguments are not power of two.
+ *
+ * @param width The width to use
+ * @param height The height to use
+ * @param samples The number of samples to use for a multisampled
+ * framebuffer, or 1 if the framebuffer should be singlesampled.
+ *
+ * @throws IllegalArgumentException If width or height are not positive.
+ */
+ public FrameBuffer(int width, int height, int samples){
+ super(FrameBuffer.class);
+ if (width <= 0 || height <= 0)
+ throw new IllegalArgumentException("FrameBuffer must have valid size.");
+
+ this.width = width;
+ this.height = height;
+ this.samples = samples == 0 ? 1 : samples;
+ }
+
+ protected FrameBuffer(FrameBuffer src){
+ super(FrameBuffer.class, src.id);
+ /*
+ for (RenderBuffer renderBuf : src.colorBufs){
+ RenderBuffer clone = renderBuf.createDestructableClone();
+ if (clone != null)
+ this.colorBufs.add(clone);
+ }
+
+ this.depthBuf = src.depthBuf.createDestructableClone();
+ */
+ }
+
+ /**
+ * Enables the use of a depth buffer for this <code>FrameBuffer</code>.
+ *
+ * @param format The format to use for the depth buffer.
+ * @throws IllegalArgumentException If <code>format</code> is not a depth format.
+ */
+ public void setDepthBuffer(Image.Format format){
+ if (id != -1)
+ throw new UnsupportedOperationException("FrameBuffer already initialized.");
+
+ if (!format.isDepthFormat())
+ throw new IllegalArgumentException("Depth buffer format must be depth.");
+
+ depthBuf = new RenderBuffer();
+ depthBuf.slot = -100; // -100 == special slot for DEPTH_BUFFER
+ depthBuf.format = format;
+ }
+
+ /**
+ * Enables the use of a color buffer for this <code>FrameBuffer</code>.
+ *
+ * @param format The format to use for the color buffer.
+ * @throws IllegalArgumentException If <code>format</code> is not a color format.
+ */
+ public void setColorBuffer(Image.Format format){
+ if (id != -1)
+ throw new UnsupportedOperationException("FrameBuffer already initialized.");
+
+ if (format.isDepthFormat())
+ throw new IllegalArgumentException("Color buffer format must be color/luminance.");
+
+ RenderBuffer colorBuf = new RenderBuffer();
+ colorBuf.slot = 0;
+ colorBuf.format = format;
+
+ colorBufs.clear();
+ colorBufs.add(colorBuf);
+ }
+
+ private void checkSetTexture(Texture tex, boolean depth){
+ Image img = tex.getImage();
+ if (img == null)
+ throw new IllegalArgumentException("Texture not initialized with RTT.");
+
+ if (depth && !img.getFormat().isDepthFormat())
+ throw new IllegalArgumentException("Texture image format must be depth.");
+ else if (!depth && img.getFormat().isDepthFormat())
+ throw new IllegalArgumentException("Texture image format must be color/luminance.");
+
+ // check that resolution matches texture resolution
+ if (width != img.getWidth() || height != img.getHeight())
+ throw new IllegalArgumentException("Texture image resolution " +
+ "must match FB resolution");
+
+ if (samples != tex.getImage().getMultiSamples())
+ throw new IllegalStateException("Texture samples must match framebuffer samples");
+ }
+
+ /**
+ * If enabled, any shaders rendering into this <code>FrameBuffer</code>
+ * will be able to write several results into the renderbuffers
+ * by using the <code>gl_FragData</code> array. Every slot in that
+ * array maps into a color buffer attached to this framebuffer.
+ *
+ * @param enabled True to enable MRT (multiple rendering targets).
+ */
+ public void setMultiTarget(boolean enabled){
+ if (enabled) colorBufIndex = -1;
+ else colorBufIndex = 0;
+ }
+
+ /**
+ * @return True if MRT (multiple rendering targets) is enabled.
+ * @see FrameBuffer#setMultiTarget(boolean)
+ */
+ public boolean isMultiTarget(){
+ return colorBufIndex == -1;
+ }
+
+ /**
+ * If MRT is not enabled ({@link FrameBuffer#setMultiTarget(boolean) } is false)
+ * then this specifies the color target to which the scene should be rendered.
+ * <p>
+ * By default the value is 0.
+ *
+ * @param index The color attachment index.
+ * @throws IllegalArgumentException If index is negative or doesn't map
+ * to any attachment on this framebuffer.
+ */
+ public void setTargetIndex(int index){
+ if (index < 0 || index >= 16)
+ throw new IllegalArgumentException("Target index must be between 0 and 16");
+
+ if (colorBufs.size() < index)
+ throw new IllegalArgumentException("The target at " + index + " is not set!");
+
+ colorBufIndex = index;
+ setUpdateNeeded();
+ }
+
+ /**
+ * @return The color target to which the scene should be rendered.
+ *
+ * @see FrameBuffer#setTargetIndex(int)
+ */
+ public int getTargetIndex(){
+ return colorBufIndex;
+ }
+
+ /**
+ * Set the color texture to use for this framebuffer.
+ * This automatically clears all existing textures added previously
+ * with {@link FrameBuffer#addColorTexture(com.jme3.texture.Texture2D) }
+ * and adds this texture as the only target.
+ *
+ * @param tex The color texture to set.
+ */
+ public void setColorTexture(Texture2D tex){
+ clearColorTargets();
+ addColorTexture(tex);
+ }
+
+ /**
+ * Clears all color targets that were set or added previously.
+ */
+ public void clearColorTargets(){
+ colorBufs.clear();
+ }
+
+ /**
+ * Add a color texture to use for this framebuffer.
+ * If MRT is enabled, then each subsequently added texture can be
+ * rendered to through a shader that writes to the array <code>gl_FragData</code>.
+ * If MRT is not enabled, then the index set with {@link FrameBuffer#setTargetIndex(int) }
+ * is rendered to by the shader.
+ *
+ * @param tex The texture to add.
+ */
+ public void addColorTexture(Texture2D tex) {
+ if (id != -1)
+ throw new UnsupportedOperationException("FrameBuffer already initialized.");
+
+ Image img = tex.getImage();
+ checkSetTexture(tex, false);
+
+ RenderBuffer colorBuf = new RenderBuffer();
+ colorBuf.slot = colorBufs.size();
+ colorBuf.tex = tex;
+ colorBuf.format = img.getFormat();
+
+ colorBufs.add(colorBuf);
+ }
+
+ /**
+ * Set the depth texture to use for this framebuffer.
+ *
+ * @param tex The color texture to set.
+ */
+ public void setDepthTexture(Texture2D tex){
+ if (id != -1)
+ throw new UnsupportedOperationException("FrameBuffer already initialized.");
+
+ Image img = tex.getImage();
+ checkSetTexture(tex, true);
+
+ depthBuf = new RenderBuffer();
+ depthBuf.slot = -100; // indicates GL_DEPTH_ATTACHMENT
+ depthBuf.tex = tex;
+ depthBuf.format = img.getFormat();
+ }
+
+ /**
+ * @return The number of color buffers attached to this texture.
+ */
+ public int getNumColorBuffers(){
+ return colorBufs.size();
+ }
+
+ /**
+ * @param index
+ * @return The color buffer at the given index.
+ */
+ public RenderBuffer getColorBuffer(int index){
+ return colorBufs.get(index);
+ }
+
+ /**
+ * @return The first color buffer attached to this FrameBuffer, or null
+ * if no color buffers are attached.
+ */
+ public RenderBuffer getColorBuffer() {
+ if (colorBufs.isEmpty())
+ return null;
+
+ return colorBufs.get(0);
+ }
+
+ /**
+ * @return The depth buffer attached to this FrameBuffer, or null
+ * if no depth buffer is attached
+ */
+ public RenderBuffer getDepthBuffer() {
+ return depthBuf;
+ }
+
+ /**
+ * @return The height in pixels of this framebuffer.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * @return The width in pixels of this framebuffer.
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * @return The number of samples when using a multisample framebuffer, or
+ * 1 if this is a singlesampled framebuffer.
+ */
+ public int getSamples() {
+ return samples;
+ }
+
+ @Override
+ public String toString(){
+ StringBuilder sb = new StringBuilder();
+ String mrtStr = colorBufIndex >= 0 ? "" + colorBufIndex : "mrt";
+ sb.append("FrameBuffer[format=").append(width).append("x").append(height)
+ .append("x").append(samples).append(", drawBuf=").append(mrtStr).append("]\n");
+ if (depthBuf != null)
+ sb.append("Depth => ").append(depthBuf).append("\n");
+ for (RenderBuffer colorBuf : colorBufs){
+ sb.append("Color(").append(colorBuf.slot)
+ .append(") => ").append(colorBuf).append("\n");
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void resetObject() {
+ this.id = -1;
+
+ for (int i = 0; i < colorBufs.size(); i++) {
+ colorBufs.get(i).resetObject();
+ }
+
+ if (depthBuf != null)
+ depthBuf.resetObject();
+
+ setUpdateNeeded();
+ }
+
+ @Override
+ public void deleteObject(Object rendererObject) {
+ ((Renderer)rendererObject).deleteFrameBuffer(this);
+ }
+
+ public NativeObject createDestructableClone(){
+ return new FrameBuffer(this);
+ }
+}
diff --git a/engine/src/core/com/jme3/texture/Image.java b/engine/src/core/com/jme3/texture/Image.java
new file mode 100644
index 0000000..5d23522
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/Image.java
@@ -0,0 +1,790 @@
+/*
+ * 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.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;
+
+/**
+ * <code>Image</code> 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),
+
+ Intensity8(8),
+ 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),
+
+ /**
+ * 10-bit red, green, and blue.
+ */
+ 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);
+
+ 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<ByteBuffer> data;
+ protected transient Object efficientData;
+ protected int multiSamples = 1;
+// protected int mipOffset = 0;
+
+ @Override
+ public void resetObject() {
+ this.id = -1;
+ 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<ByteBuffer>(data) : null;
+ clone.setUpdateNeeded();
+ return clone;
+ }
+
+ /**
+ * Constructor instantiates a new <code>Image</code> object. All values
+ * are undefined.
+ */
+ public Image() {
+ super(Image.class);
+ data = new ArrayList<ByteBuffer>(1);
+ }
+
+ protected Image(int id){
+ super(Image.class, id);
+ }
+
+ /**
+ * Constructor instantiates a new <code>Image</code> 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<ByteBuffer> 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 <code>Image</code> 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<ByteBuffer>(1);
+ this.data.add(data);
+ }
+ this.mipMapSizes = mipMapSizes;
+ }
+
+ /**
+ * Constructor instantiates a new <code>Image</code> 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<ByteBuffer> data) {
+ this(format, width, height, depth, data, null);
+ }
+
+ /**
+ * Constructor instantiates a new <code>Image</code> 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;
+ }
+
+ /**
+ * <code>setData</code> sets the data that makes up the image. This data
+ * is packed into an array of <code>ByteBuffer</code> objects.
+ *
+ * @param data
+ * the data that contains the image information.
+ */
+ public void setData(ArrayList<ByteBuffer> data) {
+ this.data = data;
+ setUpdateNeeded();
+ }
+
+ /**
+ * <code>setData</code> sets the data that makes up the image. This data
+ * is packed into a single <code>ByteBuffer</code>.
+ *
+ * @param data
+ * the data that contains the image information.
+ */
+ public void setData(ByteBuffer data) {
+ this.data = new ArrayList<ByteBuffer>(1);
+ this.data.add(data);
+ setUpdateNeeded();
+ }
+
+ public void addData(ByteBuffer data) {
+ if (this.data == null)
+ this.data = new ArrayList<ByteBuffer>(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.
+ * <p>
+ * 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();
+ }
+
+ /**
+ * <code>setHeight</code> 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();
+ }
+
+ /**
+ * <code>setDepth</code> 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();
+ }
+
+ /**
+ * <code>setWidth</code> 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();
+ }
+
+ /**
+ * <code>setFormat</code> 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();
+ }
+
+ /**
+ * <code>getFormat</code> returns the image format for this image.
+ *
+ * @return the image format.
+ * @see Format
+ */
+ public Format getFormat() {
+ return format;
+ }
+
+ /**
+ * <code>getWidth</code> returns the width of this image.
+ *
+ * @return the width of this image.
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * <code>getHeight</code> returns the height of this image.
+ *
+ * @return the height of this image.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * <code>getDepth</code> returns the depth of this image (for 3d images).
+ *
+ * @return the depth of this image.
+ */
+ public int getDepth() {
+ return depth;
+ }
+
+ /**
+ * <code>getData</code> returns the data for this image. If the data is
+ * undefined, null will be returned.
+ *
+ * @return the data for this image.
+ */
+ public List<ByteBuffer> getData() {
+ return data;
+ }
+
+ /**
+ * <code>getData</code> 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<ByteBuffer>) capsule.readByteBufferArrayList("data", null);
+ }
+
+}
diff --git a/engine/src/core/com/jme3/texture/Texture.java b/engine/src/core/com/jme3/texture/Texture.java
new file mode 100644
index 0000000..1efedec
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/Texture.java
@@ -0,0 +1,613 @@
+/*
+ * 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.asset.Asset;
+import com.jme3.asset.AssetKey;
+import com.jme3.asset.AssetNotFoundException;
+import com.jme3.asset.TextureKey;
+import com.jme3.export.*;
+import com.jme3.util.PlaceholderAssets;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <code>Texture</code> defines a texture object to be used to display an
+ * image on a piece of geometry. The image to be displayed is defined by the
+ * <code>Image</code> class. All attributes required for texture mapping are
+ * contained within this class. This includes mipmapping if desired,
+ * magnificationFilter options, apply options and correction options. Default
+ * values are as follows: minificationFilter - NearestNeighborNoMipMaps,
+ * magnificationFilter - NearestNeighbor, wrap - EdgeClamp on S,T and R, apply -
+ * Modulate, environment - None.
+ *
+ * @see com.jme3.texture.Image
+ * @author Mark Powell
+ * @author Joshua Slack
+ * @version $Id: Texture.java 4131 2009-03-19 20:15:28Z blaine.dev $
+ */
+public abstract class Texture implements Asset, Savable, Cloneable {
+
+ public enum Type {
+
+ /**
+ * Two dimensional texture (default). A rectangle.
+ */
+ TwoDimensional,
+
+ /**
+ * An array of two dimensional textures.
+ */
+ TwoDimensionalArray,
+
+ /**
+ * Three dimensional texture. (A cube)
+ */
+ ThreeDimensional,
+
+ /**
+ * A set of 6 TwoDimensional textures arranged as faces of a cube facing
+ * inwards.
+ */
+ CubeMap;
+ }
+
+ public enum MinFilter {
+
+ /**
+ * Nearest neighbor interpolation is the fastest and crudest filtering
+ * method - it simply uses the color of the texel closest to the pixel
+ * center for the pixel color. While fast, this results in aliasing and
+ * shimmering during minification. (GL equivalent: GL_NEAREST)
+ */
+ NearestNoMipMaps(false),
+
+ /**
+ * In this method the four nearest texels to the pixel center are
+ * sampled (at texture level 0), and their colors are combined by
+ * weighted averages. Though smoother, without mipmaps it suffers the
+ * same aliasing and shimmering problems as nearest
+ * NearestNeighborNoMipMaps. (GL equivalent: GL_LINEAR)
+ */
+ BilinearNoMipMaps(false),
+
+ /**
+ * Same as NearestNeighborNoMipMaps except that instead of using samples
+ * from texture level 0, the closest mipmap level is chosen based on
+ * distance. This reduces the aliasing and shimmering significantly, but
+ * does not help with blockiness. (GL equivalent:
+ * GL_NEAREST_MIPMAP_NEAREST)
+ */
+ NearestNearestMipMap(true),
+
+ /**
+ * Same as BilinearNoMipMaps except that instead of using samples from
+ * texture level 0, the closest mipmap level is chosen based on
+ * distance. By using mipmapping we avoid the aliasing and shimmering
+ * problems of BilinearNoMipMaps. (GL equivalent:
+ * GL_LINEAR_MIPMAP_NEAREST)
+ */
+ BilinearNearestMipMap(true),
+
+ /**
+ * Similar to NearestNeighborNoMipMaps except that instead of using
+ * samples from texture level 0, a sample is chosen from each of the
+ * closest (by distance) two mipmap levels. A weighted average of these
+ * two samples is returned. (GL equivalent: GL_NEAREST_MIPMAP_LINEAR)
+ */
+ NearestLinearMipMap(true),
+
+ /**
+ * Trilinear filtering is a remedy to a common artifact seen in
+ * mipmapped bilinearly filtered images: an abrupt and very noticeable
+ * change in quality at boundaries where the renderer switches from one
+ * mipmap level to the next. Trilinear filtering solves this by doing a
+ * texture lookup and bilinear filtering on the two closest mipmap
+ * levels (one higher and one lower quality), and then linearly
+ * interpolating the results. This results in a smooth degradation of
+ * texture quality as distance from the viewer increases, rather than a
+ * series of sudden drops. Of course, closer than Level 0 there is only
+ * one mipmap level available, and the algorithm reverts to bilinear
+ * filtering (GL equivalent: GL_LINEAR_MIPMAP_LINEAR)
+ */
+ Trilinear(true);
+
+ private boolean usesMipMapLevels;
+
+ private MinFilter(boolean usesMipMapLevels) {
+ this.usesMipMapLevels = usesMipMapLevels;
+ }
+
+ public boolean usesMipMapLevels() {
+ return usesMipMapLevels;
+ }
+ }
+
+ public enum MagFilter {
+
+ /**
+ * Nearest neighbor interpolation is the fastest and crudest filtering
+ * mode - it simply uses the color of the texel closest to the pixel
+ * center for the pixel color. While fast, this results in texture
+ * 'blockiness' during magnification. (GL equivalent: GL_NEAREST)
+ */
+ Nearest,
+
+ /**
+ * In this mode the four nearest texels to the pixel center are sampled
+ * (at the closest mipmap level), and their colors are combined by
+ * weighted average according to distance. This removes the 'blockiness'
+ * seen during magnification, as there is now a smooth gradient of color
+ * change from one texel to the next, instead of an abrupt jump as the
+ * pixel center crosses the texel boundary. (GL equivalent: GL_LINEAR)
+ */
+ Bilinear;
+
+ }
+
+ public enum WrapMode {
+ /**
+ * Only the fractional portion of the coordinate is considered.
+ */
+ Repeat,
+ /**
+ * Only the fractional portion of the coordinate is considered, but if
+ * the integer portion is odd, we'll use 1 - the fractional portion.
+ * (Introduced around OpenGL1.4) Falls back on Repeat if not supported.
+ */
+ MirroredRepeat,
+ /**
+ * coordinate will be clamped to [0,1]
+ */
+ Clamp,
+ /**
+ * mirrors and clamps the texture coordinate, where mirroring and
+ * clamping a value f computes:
+ * <code>mirrorClamp(f) = min(1, max(1/(2*N),
+ * abs(f)))</code> where N
+ * is the size of the one-, two-, or three-dimensional texture image in
+ * the direction of wrapping. (Introduced after OpenGL1.4) Falls back on
+ * Clamp if not supported.
+ */
+ MirrorClamp,
+ /**
+ * coordinate will be clamped to the range [-1/(2N), 1 + 1/(2N)] where N
+ * is the size of the texture in the direction of clamping. Falls back
+ * on Clamp if not supported.
+ */
+ BorderClamp,
+ /**
+ * Wrap mode MIRROR_CLAMP_TO_BORDER_EXT mirrors and clamps to border the
+ * texture coordinate, where mirroring and clamping to border a value f
+ * computes:
+ * <code>mirrorClampToBorder(f) = min(1+1/(2*N), max(1/(2*N), abs(f)))</code>
+ * where N is the size of the one-, two-, or three-dimensional texture
+ * image in the direction of wrapping." (Introduced after OpenGL1.4)
+ * Falls back on BorderClamp if not supported.
+ */
+ MirrorBorderClamp,
+ /**
+ * coordinate will be clamped to the range [1/(2N), 1 - 1/(2N)] where N
+ * is the size of the texture in the direction of clamping. Falls back
+ * on Clamp if not supported.
+ */
+ EdgeClamp,
+ /**
+ * mirrors and clamps to edge the texture coordinate, where mirroring
+ * and clamping to edge a value f computes:
+ * <code>mirrorClampToEdge(f) = min(1-1/(2*N), max(1/(2*N), abs(f)))</code>
+ * where N is the size of the one-, two-, or three-dimensional texture
+ * image in the direction of wrapping. (Introduced after OpenGL1.4)
+ * Falls back on EdgeClamp if not supported.
+ */
+ MirrorEdgeClamp;
+ }
+
+ public enum WrapAxis {
+ /**
+ * S wrapping (u or "horizontal" wrap)
+ */
+ S,
+ /**
+ * T wrapping (v or "vertical" wrap)
+ */
+ T,
+ /**
+ * R wrapping (w or "depth" wrap)
+ */
+ R;
+ }
+
+ /**
+ * If this texture is a depth texture (the format is Depth*) then
+ * this value may be used to compare the texture depth to the R texture
+ * coordinate.
+ */
+ public enum ShadowCompareMode {
+ /**
+ * Shadow comparison mode is disabled.
+ * Texturing is done normally.
+ */
+ Off,
+
+ /**
+ * Compares the 3rd texture coordinate R to the value
+ * in this depth texture. If R <= texture value then result is 1.0,
+ * otherwise, result is 0.0. If filtering is set to bilinear or trilinear
+ * the implementation may sample the texture multiple times to provide
+ * smoother results in the range [0, 1].
+ */
+ LessOrEqual,
+
+ /**
+ * Compares the 3rd texture coordinate R to the value
+ * in this depth texture. If R >= texture value then result is 1.0,
+ * otherwise, result is 0.0. If filtering is set to bilinear or trilinear
+ * the implementation may sample the texture multiple times to provide
+ * smoother results in the range [0, 1].
+ */
+ GreaterOrEqual
+ }
+
+ /**
+ * The name of the texture (if loaded as a resource).
+ */
+ private String name = null;
+
+ /**
+ * The image stored in the texture
+ */
+ private Image image = null;
+
+ /**
+ * The texture key allows to reload a texture from a file
+ * if needed.
+ */
+ private TextureKey key = null;
+
+ private MinFilter minificationFilter = MinFilter.BilinearNoMipMaps;
+ private MagFilter magnificationFilter = MagFilter.Bilinear;
+ private ShadowCompareMode shadowCompareMode = ShadowCompareMode.Off;
+ private int anisotropicFilter;
+
+ /**
+ * @return
+ */
+ @Override
+ public Texture clone(){
+ try {
+ return (Texture) super.clone();
+ } catch (CloneNotSupportedException ex) {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Constructor instantiates a new <code>Texture</code> object with default
+ * attributes.
+ */
+ public Texture() {
+ }
+
+ /**
+ * @return the MinificationFilterMode of this texture.
+ */
+ public MinFilter getMinFilter() {
+ return minificationFilter;
+ }
+
+ /**
+ * @param minificationFilter
+ * the new MinificationFilterMode for this texture.
+ * @throws IllegalArgumentException
+ * if minificationFilter is null
+ */
+ public void setMinFilter(MinFilter minificationFilter) {
+ if (minificationFilter == null) {
+ throw new IllegalArgumentException(
+ "minificationFilter can not be null.");
+ }
+ this.minificationFilter = minificationFilter;
+ }
+
+ /**
+ * @return the MagnificationFilterMode of this texture.
+ */
+ public MagFilter getMagFilter() {
+ return magnificationFilter;
+ }
+
+ /**
+ * @param magnificationFilter
+ * the new MagnificationFilter for this texture.
+ * @throws IllegalArgumentException
+ * if magnificationFilter is null
+ */
+ public void setMagFilter(MagFilter magnificationFilter) {
+ if (magnificationFilter == null) {
+ throw new IllegalArgumentException(
+ "magnificationFilter can not be null.");
+ }
+ this.magnificationFilter = magnificationFilter;
+ }
+
+ /**
+ * @return The ShadowCompareMode of this texture.
+ * @see ShadowCompareMode
+ */
+ public ShadowCompareMode getShadowCompareMode(){
+ return shadowCompareMode;
+ }
+
+ /**
+ * @param compareMode
+ * the new ShadowCompareMode for this texture.
+ * @throws IllegalArgumentException
+ * if compareMode is null
+ * @see ShadowCompareMode
+ */
+ public void setShadowCompareMode(ShadowCompareMode compareMode){
+ if (compareMode == null){
+ throw new IllegalArgumentException(
+ "compareMode can not be null.");
+ }
+ this.shadowCompareMode = compareMode;
+ }
+
+ /**
+ * <code>setImage</code> sets the image object that defines the texture.
+ *
+ * @param image
+ * the image that defines the texture.
+ */
+ public void setImage(Image image) {
+ this.image = image;
+ }
+
+ /**
+ * @param key The texture key that was used to load this texture
+ */
+ public void setKey(AssetKey key){
+ this.key = (TextureKey) key;
+ }
+
+ public AssetKey getKey(){
+ return this.key;
+ }
+
+ /**
+ * <code>getImage</code> returns the image data that makes up this
+ * texture. If no image data has been set, this will return null.
+ *
+ * @return the image data that makes up the texture.
+ */
+ public Image getImage() {
+ return image;
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for a
+ * particular axis.
+ *
+ * @param axis
+ * the texture axis to define a wrapmode on.
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if axis or mode are null or invalid for this type of texture
+ */
+ public abstract void setWrap(WrapAxis axis, WrapMode mode);
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for all axis.
+ *
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if mode is null or invalid for this type of texture
+ */
+ public abstract void setWrap(WrapMode mode);
+
+ /**
+ * <code>getWrap</code> returns the wrap mode for a given coordinate axis
+ * on this texture.
+ *
+ * @param axis
+ * the axis to return for
+ * @return the wrap mode of the texture.
+ * @throws IllegalArgumentException
+ * if axis is null or invalid for this type of texture
+ */
+ public abstract WrapMode getWrap(WrapAxis axis);
+
+ public abstract Type getType();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the anisotropic filtering level for this texture. Default value
+ * is 1 (no anisotrophy), 2 means x2, 4 is x4, etc.
+ */
+ public int getAnisotropicFilter() {
+ return anisotropicFilter;
+ }
+
+ /**
+ * @param level
+ * the anisotropic filtering level for this texture.
+ */
+ public void setAnisotropicFilter(int level) {
+ if (level < 1)
+ anisotropicFilter = 1;
+ else
+ anisotropicFilter = level;
+ }
+
+ @Override
+ public String toString(){
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append("[name=").append(name);
+ if (image != null)
+ sb.append(", image=").append(image.toString());
+
+ sb.append("]");
+
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Texture other = (Texture) obj;
+ if (this.image != other.image && (this.image == null || !this.image.equals(other.image))) {
+ return false;
+ }
+ if (this.minificationFilter != other.minificationFilter) {
+ return false;
+ }
+ if (this.magnificationFilter != other.magnificationFilter) {
+ return false;
+ }
+ if (this.shadowCompareMode != other.shadowCompareMode) {
+ return false;
+ }
+ if (this.anisotropicFilter != other.anisotropicFilter) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 67 * hash + (this.image != null ? this.image.hashCode() : 0);
+ hash = 67 * hash + (this.minificationFilter != null ? this.minificationFilter.hashCode() : 0);
+ hash = 67 * hash + (this.magnificationFilter != null ? this.magnificationFilter.hashCode() : 0);
+ hash = 67 * hash + (this.shadowCompareMode != null ? this.shadowCompareMode.hashCode() : 0);
+ hash = 67 * hash + this.anisotropicFilter;
+ return hash;
+ }
+
+
+
+// public abstract Texture createSimpleClone();
+
+
+ /** Retrieve a basic clone of this Texture (ie, clone everything but the
+ * image data, which is shared)
+ *
+ * @return Texture
+ */
+ public Texture createSimpleClone(Texture rVal) {
+ rVal.setMinFilter(minificationFilter);
+ rVal.setMagFilter(magnificationFilter);
+ rVal.setShadowCompareMode(shadowCompareMode);
+// rVal.setHasBorder(hasBorder);
+ rVal.setAnisotropicFilter(anisotropicFilter);
+ rVal.setImage(image); // NOT CLONED.
+// rVal.memReq = memReq;
+ rVal.setKey(key);
+ rVal.setName(name);
+// rVal.setBlendColor(blendColor != null ? blendColor.clone() : null);
+// if (getTextureKey() != null) {
+// rVal.setTextureKey(getTextureKey());
+// }
+ return rVal;
+ }
+
+ public abstract Texture createSimpleClone();
+
+ public void write(JmeExporter e) throws IOException {
+ OutputCapsule capsule = e.getCapsule(this);
+ capsule.write(name, "name", null);
+
+ if (key == null){
+ // no texture key is set, try to save image instead then
+ capsule.write(image, "image", null);
+ }else{
+ capsule.write(key, "key", null);
+ }
+
+ capsule.write(anisotropicFilter, "anisotropicFilter", 1);
+ capsule.write(minificationFilter, "minificationFilter",
+ MinFilter.BilinearNoMipMaps);
+ capsule.write(magnificationFilter, "magnificationFilter",
+ MagFilter.Bilinear);
+ }
+
+ public void read(JmeImporter e) throws IOException {
+ InputCapsule capsule = e.getCapsule(this);
+ name = capsule.readString("name", null);
+ key = (TextureKey) capsule.readSavable("key", null);
+
+ // load texture from key, if available
+ if (key != null) {
+ // key is available, so try the texture from there.
+ try {
+ Texture loadedTex = e.getAssetManager().loadTexture(key);
+ image = loadedTex.getImage();
+ } catch (AssetNotFoundException ex){
+ Logger.getLogger(Texture.class.getName()).log(Level.SEVERE, "Cannot locate texture {0}", key);
+ image = PlaceholderAssets.getPlaceholderImage();
+ }
+ }else{
+ // no key is set on the texture. Attempt to load an embedded image
+ image = (Image) capsule.readSavable("image", null);
+ if (image == null){
+ // TODO: what to print out here? the texture has no key or data, there's no useful information ..
+ // assume texture.name is set even though the key is null
+ Logger.getLogger(Texture.class.getName()).log(Level.SEVERE, "Cannot load embedded image {0}", toString() );
+ }
+ }
+
+ anisotropicFilter = capsule.readInt("anisotropicFilter", 1);
+ minificationFilter = capsule.readEnum("minificationFilter",
+ MinFilter.class,
+ MinFilter.BilinearNoMipMaps);
+ magnificationFilter = capsule.readEnum("magnificationFilter",
+ MagFilter.class, MagFilter.Bilinear);
+ }
+} \ No newline at end of file
diff --git a/engine/src/core/com/jme3/texture/Texture2D.java b/engine/src/core/com/jme3/texture/Texture2D.java
new file mode 100644
index 0000000..9598413
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/Texture2D.java
@@ -0,0 +1,221 @@
+/*
+ * 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.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import java.io.IOException;
+
+/**
+ * @author Joshua Slack
+ */
+public class Texture2D extends Texture {
+
+ private WrapMode wrapS = WrapMode.EdgeClamp;
+ private WrapMode wrapT = WrapMode.EdgeClamp;
+
+ /**
+ * Creates a new two-dimensional texture with default attributes.
+ */
+ public Texture2D(){
+ super();
+ }
+
+ /**
+ * Creates a new two-dimensional texture using the given image.
+ * @param img The image to use.
+ */
+ public Texture2D(Image img){
+ super();
+ setImage(img);
+ if (img.getFormat().isDepthFormat()){
+ setMagFilter(MagFilter.Nearest);
+ setMinFilter(MinFilter.NearestNoMipMaps);
+ }
+ }
+
+ /**
+ * Creates a new two-dimensional texture for the purpose of offscreen
+ * rendering.
+ *
+ * @see com.jme3.texture.FrameBuffer
+ *
+ * @param width
+ * @param height
+ * @param format
+ */
+ public Texture2D(int width, int height, Image.Format format){
+ this(new Image(format, width, height, null));
+ }
+
+ /**
+ * Creates a new two-dimensional texture for the purpose of offscreen
+ * rendering.
+ *
+ * @see com.jme3.texture.FrameBuffer
+ *
+ * @param width
+ * @param height
+ * @param format
+ * @param numSamples
+ */
+ public Texture2D(int width, int height, int numSamples, Image.Format format){
+ this(new Image(format, width, height, null));
+ getImage().setMultiSamples(numSamples);
+ }
+
+ @Override
+ public Texture createSimpleClone() {
+ Texture2D clone = new Texture2D();
+ createSimpleClone(clone);
+ return clone;
+ }
+
+ @Override
+ public Texture createSimpleClone(Texture rVal) {
+ rVal.setWrap(WrapAxis.S, wrapS);
+ rVal.setWrap(WrapAxis.T, wrapT);
+ return super.createSimpleClone(rVal);
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for a
+ * particular axis.
+ *
+ * @param axis
+ * the texture axis to define a wrapmode on.
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if axis or mode are null
+ */
+ public void setWrap(WrapAxis axis, WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ } else if (axis == null) {
+ throw new IllegalArgumentException("axis can not be null.");
+ }
+ switch (axis) {
+ case S:
+ this.wrapS = mode;
+ break;
+ case T:
+ this.wrapT = mode;
+ break;
+ default:
+ throw new IllegalArgumentException("Not applicable for 2D textures");
+ }
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for all axis.
+ *
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if mode is null
+ */
+ public void setWrap(WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ }
+ this.wrapS = mode;
+ this.wrapT = mode;
+ }
+
+ /**
+ * <code>getWrap</code> returns the wrap mode for a given coordinate axis
+ * on this texture.
+ *
+ * @param axis
+ * the axis to return for
+ * @return the wrap mode of the texture.
+ * @throws IllegalArgumentException
+ * if axis is null
+ */
+ public WrapMode getWrap(WrapAxis axis) {
+ switch (axis) {
+ case S:
+ return wrapS;
+ case T:
+ return wrapT;
+ default:
+ throw new IllegalArgumentException("invalid WrapAxis: " + axis);
+ }
+ }
+
+ @Override
+ public Type getType() {
+ return Type.TwoDimensional;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Texture2D)) {
+ return false;
+ }
+ Texture2D that = (Texture2D) other;
+ if (this.getWrap(WrapAxis.S) != that.getWrap(WrapAxis.S))
+ return false;
+ if (this.getWrap(WrapAxis.T) != that.getWrap(WrapAxis.T))
+ return false;
+ return super.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ hash = 79 * hash + (this.wrapS != null ? this.wrapS.hashCode() : 0);
+ hash = 79 * hash + (this.wrapT != null ? this.wrapT.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public void write(JmeExporter e) throws IOException {
+ super.write(e);
+ OutputCapsule capsule = e.getCapsule(this);
+ capsule.write(wrapS, "wrapS", WrapMode.EdgeClamp);
+ capsule.write(wrapT, "wrapT", WrapMode.EdgeClamp);
+ }
+
+ @Override
+ public void read(JmeImporter e) throws IOException {
+ super.read(e);
+ InputCapsule capsule = e.getCapsule(this);
+ wrapS = capsule.readEnum("wrapS", WrapMode.class, WrapMode.EdgeClamp);
+ wrapT = capsule.readEnum("wrapT", WrapMode.class, WrapMode.EdgeClamp);
+ }
+
+}
diff --git a/engine/src/core/com/jme3/texture/Texture3D.java b/engine/src/core/com/jme3/texture/Texture3D.java
new file mode 100644
index 0000000..bded644
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/Texture3D.java
@@ -0,0 +1,224 @@
+/*
+ * 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.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import java.io.IOException;
+
+/**
+ * @author Maarten Steur
+ */
+public class Texture3D extends Texture {
+
+ private WrapMode wrapS = WrapMode.EdgeClamp;
+ private WrapMode wrapT = WrapMode.EdgeClamp;
+ private WrapMode wrapR = WrapMode.EdgeClamp;
+
+ /**
+ * Creates a new two-dimensional texture with default attributes.
+ */
+ public Texture3D() {
+ super();
+ }
+
+ /**
+ * Creates a new three-dimensional texture using the given image.
+ * @param img The image to use.
+ */
+ public Texture3D(Image img) {
+ super();
+ setImage(img);
+ if (img.getFormat().isDepthFormat()) {
+ setMagFilter(MagFilter.Nearest);
+ setMinFilter(MinFilter.NearestNoMipMaps);
+ }
+ }
+
+ /**
+ * Creates a new three-dimensional texture for the purpose of offscreen
+ * rendering.
+ *
+ * @see com.jme3.texture.FrameBuffer
+ *
+ * @param width
+ * @param height
+ * @param depth
+ * @param format
+ */
+ public Texture3D(int width, int height, int depth, Image.Format format) {
+ this(new Image(format, width, height, depth, null));
+ }
+
+ /**
+ * Creates a new three-dimensional texture for the purpose of offscreen
+ * rendering.
+ *
+ * @see com.jme3.texture.FrameBuffer
+ *
+ * @param width
+ * @param height
+ * @param format
+ * @param numSamples
+ */
+ public Texture3D(int width, int height, int depth, int numSamples, Image.Format format) {
+ this(new Image(format, width, height, depth, null));
+ getImage().setMultiSamples(numSamples);
+ }
+
+ @Override
+ public Texture createSimpleClone() {
+ Texture3D clone = new Texture3D();
+ createSimpleClone(clone);
+ return clone;
+ }
+
+ @Override
+ public Texture createSimpleClone(Texture rVal) {
+ rVal.setWrap(WrapAxis.S, wrapS);
+ rVal.setWrap(WrapAxis.T, wrapT);
+ rVal.setWrap(WrapAxis.R, wrapR);
+ return super.createSimpleClone(rVal);
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for a
+ * particular axis.
+ *
+ * @param axis
+ * the texture axis to define a wrapmode on.
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if axis or mode are null
+ */
+ public void setWrap(WrapAxis axis, WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ } else if (axis == null) {
+ throw new IllegalArgumentException("axis can not be null.");
+ }
+ switch (axis) {
+ case S:
+ this.wrapS = mode;
+ break;
+ case T:
+ this.wrapT = mode;
+ break;
+ case R:
+ this.wrapR = mode;
+ break;
+ }
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for all axis.
+ *
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if mode is null
+ */
+ public void setWrap(WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ }
+ this.wrapS = mode;
+ this.wrapT = mode;
+ this.wrapR = mode;
+ }
+
+ /**
+ * <code>getWrap</code> returns the wrap mode for a given coordinate axis
+ * on this texture.
+ *
+ * @param axis
+ * the axis to return for
+ * @return the wrap mode of the texture.
+ * @throws IllegalArgumentException
+ * if axis is null
+ */
+ public WrapMode getWrap(WrapAxis axis) {
+ switch (axis) {
+ case S:
+ return wrapS;
+ case T:
+ return wrapT;
+ case R:
+ return wrapR;
+ }
+ throw new IllegalArgumentException("invalid WrapAxis: " + axis);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.ThreeDimensional;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Texture3D)) {
+ return false;
+ }
+ Texture3D that = (Texture3D) other;
+ if (this.getWrap(WrapAxis.S) != that.getWrap(WrapAxis.S)) {
+ return false;
+ }
+ if (this.getWrap(WrapAxis.T) != that.getWrap(WrapAxis.T)) {
+ return false;
+ }
+ if (this.getWrap(WrapAxis.R) != that.getWrap(WrapAxis.R)) {
+ return false;
+ }
+ return super.equals(other);
+ }
+
+ @Override
+ public void write(JmeExporter e) throws IOException {
+ super.write(e);
+ OutputCapsule capsule = e.getCapsule(this);
+ capsule.write(wrapS, "wrapS", WrapMode.EdgeClamp);
+ capsule.write(wrapT, "wrapT", WrapMode.EdgeClamp);
+ capsule.write(wrapR, "wrapR", WrapMode.EdgeClamp);
+ }
+
+ @Override
+ public void read(JmeImporter e) throws IOException {
+ super.read(e);
+ InputCapsule capsule = e.getCapsule(this);
+ wrapS = capsule.readEnum("wrapS", WrapMode.class, WrapMode.EdgeClamp);
+ wrapT = capsule.readEnum("wrapT", WrapMode.class, WrapMode.EdgeClamp);
+ wrapR = capsule.readEnum("wrapR", WrapMode.class, WrapMode.EdgeClamp);
+ }
+} \ No newline at end of file
diff --git a/engine/src/core/com/jme3/texture/TextureArray.java b/engine/src/core/com/jme3/texture/TextureArray.java
new file mode 100644
index 0000000..e39d95f
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/TextureArray.java
@@ -0,0 +1,113 @@
+package com.jme3.texture;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class implements a Texture array
+ * warning, this feature is only supported on opengl 3.0 version.
+ * To check if a hardware supports TextureArray check :
+ * renderManager.getRenderer().getCaps().contains(Caps.TextureArray)
+ * @author phate666
+ */
+public class TextureArray extends Texture {
+
+ private WrapMode wrapS = WrapMode.EdgeClamp;
+ private WrapMode wrapT = WrapMode.EdgeClamp;
+
+ /**
+ * Construct a TextureArray
+ * warning, this feature is only supported on opengl 3.0 version.
+ * To check if a hardware supports TextureArray check :
+ * renderManager.getRenderer().getCaps().contains(Caps.TextureArray)
+ */
+ public TextureArray() {
+ super();
+ }
+
+ /**
+ * Construct a TextureArray from the given list of images
+ * warning, this feature is only supported on opengl 3.0 version.
+ * To check if a hardware supports TextureArray check :
+ * renderManager.getRenderer().getCaps().contains(Caps.TextureArray)
+ * @param images
+ */
+ public TextureArray(List<Image> images) {
+ super();
+ int width = images.get(0).getWidth();
+ int height = images.get(0).getHeight();
+ Image arrayImage = new Image(images.get(0).getFormat(), width, height,
+ null);
+
+ for (Image img : images) {
+ if (img.getHeight() != height || img.getWidth() != width) {
+ Logger.getLogger(TextureArray.class.getName()).log(
+ Level.WARNING,
+ "all images must have the same width/height");
+ continue;
+ }
+ arrayImage.addData(img.getData(0));
+ }
+ setImage(arrayImage);
+ }
+
+ @Override
+ public Texture createSimpleClone() {
+ TextureArray clone = new TextureArray();
+ createSimpleClone(clone);
+ return clone;
+ }
+
+ @Override
+ public Texture createSimpleClone(Texture rVal) {
+ rVal.setWrap(WrapAxis.S, wrapS);
+ rVal.setWrap(WrapAxis.T, wrapT);
+ return super.createSimpleClone(rVal);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.TwoDimensionalArray;
+ }
+
+ @Override
+ public WrapMode getWrap(WrapAxis axis) {
+ switch (axis) {
+ case S:
+ return wrapS;
+ case T:
+ return wrapT;
+ default:
+ throw new IllegalArgumentException("invalid WrapAxis: " + axis);
+ }
+ }
+
+ @Override
+ public void setWrap(WrapAxis axis, WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ } else if (axis == null) {
+ throw new IllegalArgumentException("axis can not be null.");
+ }
+ switch (axis) {
+ case S:
+ this.wrapS = mode;
+ break;
+ case T:
+ this.wrapT = mode;
+ break;
+ default:
+ throw new IllegalArgumentException("Not applicable for 2D textures");
+ }
+ }
+
+ @Override
+ public void setWrap(WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ }
+ this.wrapS = mode;
+ this.wrapT = mode;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core/com/jme3/texture/TextureCubeMap.java b/engine/src/core/com/jme3/texture/TextureCubeMap.java
new file mode 100644
index 0000000..9290d8a
--- /dev/null
+++ b/engine/src/core/com/jme3/texture/TextureCubeMap.java
@@ -0,0 +1,206 @@
+/*
+ * 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.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import java.io.IOException;
+
+/**
+ * Describes a cubemap texture.
+ * The image specified by setImage must contain 6 data units,
+ * each data contains a 2D image representing a cube's face.
+ * The slices are specified in this order:<br/>
+ * <br/>
+ * 0 => Positive X (+x)<br/>
+ * 1 => Negative X (-x)<br/>
+ * 2 => Positive Y (+y)<br/>
+ * 3 => Negative Y (-y)<br/>
+ * 4 => Positive Z (+z)<br/>
+ * 5 => Negative Z (-z)<br/>
+ *
+ * @author Joshua Slack
+ */
+public class TextureCubeMap extends Texture {
+
+ private WrapMode wrapS = WrapMode.EdgeClamp;
+ private WrapMode wrapT = WrapMode.EdgeClamp;
+ private WrapMode wrapR = WrapMode.EdgeClamp;
+
+ /**
+ * Face of the Cubemap as described by its directional offset from the
+ * origin.
+ */
+// public enum Face {
+// PositiveX, NegativeX, PositiveY, NegativeY, PositiveZ, NegativeZ;
+// }
+
+ public TextureCubeMap(){
+ super();
+ }
+
+ public TextureCubeMap(Image img){
+ super();
+ setImage(img);
+ }
+
+ public Texture createSimpleClone() {
+ return createSimpleClone(new TextureCubeMap());
+ }
+
+ @Override
+ public Texture createSimpleClone(Texture rVal) {
+ rVal.setWrap(WrapAxis.S, wrapS);
+ rVal.setWrap(WrapAxis.T, wrapT);
+ rVal.setWrap(WrapAxis.R, wrapR);
+ return super.createSimpleClone(rVal);
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for a
+ * particular axis.
+ *
+ * @param axis
+ * the texture axis to define a wrapmode on.
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if axis or mode are null
+ */
+ public void setWrap(WrapAxis axis, WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ } else if (axis == null) {
+ throw new IllegalArgumentException("axis can not be null.");
+ }
+ switch (axis) {
+ case S:
+ this.wrapS = mode;
+ break;
+ case T:
+ this.wrapT = mode;
+ break;
+ case R:
+ this.wrapR = mode;
+ break;
+ }
+ }
+
+ /**
+ * <code>setWrap</code> sets the wrap mode of this texture for all axis.
+ *
+ * @param mode
+ * the wrap mode for the given axis of the texture.
+ * @throws IllegalArgumentException
+ * if mode is null
+ */
+ public void setWrap(WrapMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode can not be null.");
+ }
+ this.wrapS = mode;
+ this.wrapT = mode;
+ this.wrapR = mode;
+ }
+
+ /**
+ * <code>getWrap</code> returns the wrap mode for a given coordinate axis
+ * on this texture.
+ *
+ * @param axis
+ * the axis to return for
+ * @return the wrap mode of the texture.
+ * @throws IllegalArgumentException
+ * if axis is null
+ */
+ public WrapMode getWrap(WrapAxis axis) {
+ switch (axis) {
+ case S:
+ return wrapS;
+ case T:
+ return wrapT;
+ case R:
+ return wrapR;
+ }
+ throw new IllegalArgumentException("invalid WrapAxis: " + axis);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.CubeMap;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof TextureCubeMap)) {
+ return false;
+ }
+ TextureCubeMap that = (TextureCubeMap) other;
+ if (this.getWrap(WrapAxis.S) != that.getWrap(WrapAxis.S))
+ return false;
+ if (this.getWrap(WrapAxis.T) != that.getWrap(WrapAxis.T))
+ return false;
+ if (this.getWrap(WrapAxis.R) != that.getWrap(WrapAxis.R))
+ return false;
+ return super.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ hash = 53 * hash + (this.wrapS != null ? this.wrapS.hashCode() : 0);
+ hash = 53 * hash + (this.wrapT != null ? this.wrapT.hashCode() : 0);
+ hash = 53 * hash + (this.wrapR != null ? this.wrapR.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public void write(JmeExporter e) throws IOException {
+ super.write(e);
+ OutputCapsule capsule = e.getCapsule(this);
+ capsule.write(wrapS, "wrapS", WrapMode.EdgeClamp);
+ capsule.write(wrapT, "wrapT", WrapMode.EdgeClamp);
+ capsule.write(wrapR, "wrapR", WrapMode.EdgeClamp);
+ }
+
+ @Override
+ public void read(JmeImporter e) throws IOException {
+ super.read(e);
+ InputCapsule capsule = e.getCapsule(this);
+ wrapS = capsule.readEnum("wrapS", WrapMode.class, WrapMode.EdgeClamp);
+ wrapT = capsule.readEnum("wrapT", WrapMode.class, WrapMode.EdgeClamp);
+ wrapR = capsule.readEnum("wrapR", WrapMode.class, WrapMode.EdgeClamp);
+ }
+}