diff options
Diffstat (limited to 'engine/src/core/com/jme3/texture/Texture.java')
-rw-r--r-- | engine/src/core/com/jme3/texture/Texture.java | 613 |
1 files changed, 613 insertions, 0 deletions
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 |