2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 package com.jme.scene.state;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
40 import com.jme.image.Image;
41 import com.jme.image.Texture;
42 import com.jme.scene.state.RenderState.StateType;
43 import com.jme.util.TextureManager;
44 import com.jme.util.export.InputCapsule;
45 import com.jme.util.export.JMEExporter;
46 import com.jme.util.export.JMEImporter;
47 import com.jme.util.export.OutputCapsule;
50 * <code>TextureState</code> maintains a texture state for a given node and
51 * it's children. The number of states that a TextureState can maintain at one
52 * time is equal to the number of texture units available on the GPU. It is not
53 * within the scope of this class to generate the texture, and is recommended
54 * that <code>TextureManager</code> be used to create the Texture objects.
56 * @see com.jme.util.TextureManager
58 * @author Joshua Slack
59 * @author Tijl Houtbeckers - TextureID cache / Shader texture units
60 * @author Vekas Arpad - Shader Texture units
61 * @version $Id: TextureState.java,v 1.43 2007/10/05 22:39:48 nca Exp $
63 public abstract class TextureState extends RenderState {
64 private static final Logger logger = Logger.getLogger(TextureState.class
67 protected static Texture defaultTexture = null;
69 public enum CorrectionType {
71 * Correction modifier makes no color corrections, and is the fastest.
76 * Correction modifier makes color corrections based on perspective and
77 * is slower than CM_AFFINE. (Default)
82 /** The texture(s). */
83 protected transient ArrayList<Texture> texture;
85 /** The total number of supported texture units. */
86 protected static int numTotalTexUnits = -1;
88 /** The number of texture units availible for fixed functionality */
89 protected static int numFixedTexUnits = -1;
91 /** The number of texture units availible to vertex shader */
92 protected static int numVertexTexUnits = -1;
94 /** The number of texture units availible to fragment shader */
95 protected static int numFragmentTexUnits = -1;
97 /** The number of texture coordinate sets available */
98 protected static int numFragmentTexCoordUnits = -1;
100 protected static float maxAnisotropic = -1.0f;
102 /** True if multitexturing is supported. */
103 protected static boolean supportsMultiTexture = false;
104 protected static boolean supportsMultiTextureDetected = false;
106 /** True if combine dot3 is supported. */
107 protected static boolean supportsEnvDot3 = false;
108 protected static boolean supportsEnvDot3Detected = false;
110 /** True if combine dot3 is supported. */
111 protected static boolean supportsEnvCombine = false;
112 protected static boolean supportsEnvCombineDetected = false;
114 /** True if anisofiltering is supported. */
115 protected static boolean supportsAniso = false;
116 protected static boolean supportsAnisoDetected = false;
118 /** True if non pow 2 texture sizes are supported. */
119 protected static boolean supportsNonPowerTwo = false;
120 protected static boolean supportsNonPowerTwoDetected = false;
122 /** True if rectangular textures are supported (vs. only square textures) */
123 protected static boolean supportsRectangular = false;
124 protected static boolean supportsRectangularDetected = false;
126 /** True if S3TC compression is supported. */
127 protected static boolean supportsS3TCCompression = false;
128 protected static boolean supportsS3TCCompressionDetected = false;
130 /** True if Texture3D is supported. */
131 protected static boolean supportsTexture3D = false;
132 protected static boolean supportsTexture3DDetected = false;
134 /** True if TextureCubeMap is supported. */
135 protected static boolean supportsTextureCubeMap = false;
136 protected static boolean supportsTextureCubeMapDetected = false;
138 /** True if non-GLU mipmap generation (part of FBO) is supported. */
139 protected static boolean automaticMipMaps = false;
140 protected static boolean automaticMipMapsDetected = false;
142 /** True if depth textures are supported */
143 protected static boolean supportsDepthTexture = false;
144 /** True if shadow mapping supported */
145 protected static boolean supportsShadow = false;
147 protected transient int firstTexture = 0;
148 protected transient int lastTexture = 0;
151 * Perspective correction to use for the object rendered with this texture
152 * state. Default is CorrectionType.Perspective.
154 private CorrectionType correctionType = CorrectionType.Perspective;
157 * offset is used to denote where to begin access of texture coordinates. 0
160 protected int offset = 0;
162 protected transient int[] idCache = new int[0];
165 * Constructor instantiates a new <code>TextureState</code> object.
167 public TextureState() {
168 if (defaultTexture == null)
170 defaultTexture = TextureManager.loadTexture(TextureState.class
171 .getResource("notloaded.png"), Texture.MinificationFilter.Trilinear,
172 Texture.MagnificationFilter.Bilinear, 0.0f, true);
173 } catch (Exception e) {
174 logger.log(Level.WARNING, "Failed to load default texture: notloaded.png", e);
179 * <code>getType</code> returns this type of render state. (RS_TEXTURE).
181 * @see com.jme.scene.state.RenderState#getType()
182 * @deprecated As of 2.0, use {@link RenderState#getStateType()} instead.
184 public int getType() {
189 * <code>getStateType</code> returns the type {@link RenderState.StateType#Texture}
191 * @return {@link RenderState.StateType#Texture}
192 * @see com.jme.scene.state.RenderState#getStateType()
194 public StateType getStateType() {
196 return StateType.Texture;
200 * <code>setTexture</code> sets a single texture to the first texture
204 * the texture to set.
206 public void setTexture(Texture texture) {
207 if (this.texture.size() == 0) {
208 this.texture.add(texture);
210 this.texture.set(0, texture);
212 setNeedsRefresh(true);
218 * <code>getTexture</code> gets the texture that is assigned to the first
221 * @return the texture in the first texture unit.
223 public Texture getTexture() {
224 if (texture.size() > 0)
225 return texture.get(0);
230 * <code>setTexture</code> sets the texture object to be used by the
231 * state. The texture unit that this texture uses is set, if the unit is not
232 * valid, i.e. less than zero or greater than the number of texture units
233 * supported by the graphics card, it is ignored.
236 * the texture to be used by the state.
238 * the texture unit this texture will fill.
240 public void setTexture(Texture texture, int textureUnit) {
241 if (textureUnit >= 0 && textureUnit < numTotalTexUnits) {
242 while (textureUnit >= this.texture.size()) {
243 this.texture.add(null);
245 this.texture.set(textureUnit, texture);
248 setNeedsRefresh(true);
252 * <code>getTexture</code> retrieves the texture being used by the state
253 * in a particular texture unit.
256 * the texture unit to retrieve the texture from.
257 * @return the texture being used by the state. If the texture unit is
258 * invalid, null is returned.
260 public Texture getTexture(int textureUnit) {
261 if (textureUnit < texture.size() && textureUnit >= 0) {
262 return texture.get(textureUnit);
268 public boolean removeTexture(Texture tex) {
270 int index = texture.indexOf(tex);
274 texture.set(index, null);
279 public boolean removeTexture(int textureUnit) {
280 if (textureUnit < 0 || textureUnit >= numTotalTexUnits
281 || textureUnit >= texture.size())
284 Texture t = texture.get(textureUnit);
288 texture.set(textureUnit, null);
289 idCache[textureUnit] = 0;
295 * Removes all textures in this texture state. Does not delete them from the
298 public void clearTextures() {
299 for (int i = texture.size(); --i >= 0;) {
305 * <code>setCorrectionType</code> sets the image correction type for this
309 * the correction type for this texture.
310 * @throws IllegalArgumentException
313 public void setCorrectionType(CorrectionType type) {
315 throw new IllegalArgumentException("type can not be null.");
317 this.correctionType = type;
318 setNeedsRefresh(true);
322 * <code>getCorrectionType</code> returns the correction mode for the texture state.
324 * @return the correction type for the texture state.
326 public CorrectionType getCorrectionType() {
327 return correctionType;
331 * <code>getTotalNumberOfUnits</code> returns the total number of texture
332 * units the computer's graphics card supports.
334 * @return the total number of texture units supported by the graphics card.
336 public static int getTotalNumberOfUnits() {
337 return numTotalTexUnits;
341 * <code>getNumberOfFixedUnits</code> returns the number of texture units
342 * the computer's graphics card supports, for use in the fixed pipeline.
344 * @return the number units.
346 public static int getNumberOfFixedUnits() {
347 return numFixedTexUnits;
351 * <code>getNumberOfVertexUnits</code> returns the number of texture units
352 * available to a vertex shader that this graphics card supports.
354 * @return the number of units.
356 public static int getNumberOfVertexUnits() {
357 return numVertexTexUnits;
361 * <code>getNumberOfFragmentUnits</code> returns the number of texture units
362 * available to a fragment shader that this graphics card supports.
364 * @return the number of units.
366 public static int getNumberOfFragmentUnits() {
367 return numFragmentTexUnits;
371 * <code>getNumberOfFragmentTexCoordUnits</code> returns the number of
372 * texture coordinate sets available that this graphics card supports.
374 * @return the number of units.
376 public static int getNumberOfFragmentTexCoordUnits() {
377 return numFragmentTexCoordUnits;
381 * <code>getNumberOfTotalUnits</code> returns the number texture units the
382 * computer's graphics card supports.
384 * @return the number of units.
386 public static int getNumberOfTotalUnits() {
387 return numTotalTexUnits;
391 * Returns the number of textures this texture manager is maintaining.
393 * @return the number of textures.
395 public int getNumberOfSetTextures() {
396 return texture.size();
400 * Fast access for retrieving a Texture ID. A return is guaranteed when
401 * <code>textureUnit</code> is any number under or equal to the highest
402 * textureunit currently in use. This value can be retrieved with
403 * <code>getNumberOfSetTextures</code>. A higher value might result in
404 * unexpected behaviour such as an exception being thrown.
407 * The texture unit from which to retrieve the ID.
408 * @return the textureID, or 0 if there is none.
410 public final int getTextureID(int textureUnit) {
411 if (textureUnit < idCache.length && textureUnit >= 0) {
412 return idCache[textureUnit];
419 * <code>setTextureCoordinateOffset</code> sets the offset value used to
420 * determine which coordinates to use for texturing Geometry.
423 * the offset (default 0).
425 public void setTextureCoordinateOffset(int offset) {
426 this.offset = offset;
427 setNeedsRefresh(true);
431 * <code>setTextureCoordinateOffset</code> gets the offset value used to
432 * determine which coordinates to use for texturing Geometry.
434 * @return the offset (default 0).
436 public int getTextureCoordinateOffset() {
441 * Loads our textures into the underlying rendering system, generating mip
442 * maps if appropriate.
445 for (int unit = 0; unit < numTotalTexUnits; unit++) {
446 if (getTexture(unit) != null) {
453 * Loads the texture for the given unit into the underlying rendering
454 * system, generating mip maps if appropriate.
456 public abstract void load(int unit);
459 * Removes the texture of the given unit.
462 * The unit of the Texture to remove.
464 public abstract void delete(int unit);
467 * Removes all Texture set in this TextureState. Does not also remove from
468 * TextureManager's cache.
470 public abstract void deleteAll();
473 * Removes all Texture set in this TextureState. Also removes the textures
474 * from the TextureManager cache if passed boolean is true.
476 public abstract void deleteAll(boolean removeFromCache);
479 * Returns the maximum anisotropic filter.
481 * @return The maximum anisotropic filter.
483 public float getMaxAnisotropic() {
484 return maxAnisotropic;
488 * Updates firstTexture to be the first non-null Texture, and lastTexture to
489 * be the last non-null texture.
491 protected void resetFirstLast() {
492 boolean foundFirst = false;
493 for (int x = 0; x < texture.size(); x++) {
494 if (texture.get(x) != null) {
502 if (idCache == null || idCache.length <= lastTexture) {
503 if (idCache == null || idCache.length == 0) {
504 idCache = new int[lastTexture + 2];
506 int[] tempCache = new int[lastTexture + 2];
507 System.arraycopy(idCache, 0, tempCache, 0, idCache.length);
514 * @return true if multi-texturing is supported in fixed function
516 public static boolean isMultiTextureSupported() {
517 return supportsMultiTexture;
521 * Overide setting of fixed function multi-texturing support.
525 public static void overrideMultiTextureSupport(boolean use) {
526 supportsMultiTexture = use;
530 * Reset fixed function multi-texturing support to driver-detected setting.
532 public static void resetMultiTextureSupport() {
533 supportsMultiTexture = supportsMultiTextureDetected;
538 * @return true we support dot3 environment texture settings
540 public static boolean isEnvDot3Supported() {
541 return supportsEnvDot3;
545 * Overide support for dot3 environment texture settings
549 public static void overrideEnvDot3Support(boolean use) {
550 supportsEnvDot3 = use;
554 * Reset dot3 environment texture support to driver-detected setting.
556 public static void resetEnvDot3Support() {
557 supportsEnvDot3 = supportsEnvDot3Detected;
562 * @return true we support combine environment texture settings
564 public static boolean isEnvCombineSupported() {
565 return supportsEnvCombine;
569 * Overide support for combine environment texture settings
573 public static void overrideEnvCombineSupport(boolean use) {
574 supportsEnvCombine = use;
578 * Reset combine environment texture support to driver-detected setting.
580 public static void resetEnvCombineSupport() {
581 supportsEnvCombine = supportsEnvCombineDetected;
586 * Returns if S3TC compression is available for textures.
588 * @return true if S3TC is available.
590 public boolean isS3TCSupported() {
591 return supportsS3TCCompression;
595 * Overide setting of S3TC compression support.
599 public static void overrideS3TCSupport(boolean use) {
600 supportsS3TCCompression = use;
604 * Reset dot3 environment texture support to driver-detected setting.
606 public static void resetS3TCSupport() {
607 supportsS3TCCompression = supportsS3TCCompressionDetected;
611 * Returns if Texture3D is available for textures.
613 * @return true if Texture3D is available.
615 public boolean isTexture3DSupported() {
616 return supportsTexture3D;
620 * Overide setting of Texture3D support.
624 public static void overrideTexture3DSupport(boolean use) {
625 supportsTexture3D = use;
629 * Reset Texture3D support to driver-detected setting.
631 public static void resetTexture3DSupport() {
632 supportsTexture3D = supportsTexture3DDetected;
636 * Returns if TextureCubeMap is available for textures.
638 * @return true if TextureCubeMap is available.
640 public boolean isTextureCubeMapSupported() {
641 return supportsTextureCubeMap;
645 * Overide setting of TextureCubeMap support.
649 public static void overrideTextureCubeMapSupport(boolean use) {
650 supportsTextureCubeMap = use;
654 * Reset TextureCubeMap support to driver-detected setting.
656 public static void resetTextureCubeMapSupport() {
657 supportsTextureCubeMap = supportsTextureCubeMapDetected;
661 * Returns if AutomaticMipmap generation is available for textures.
663 * @return true if AutomaticMipmap generation is available.
665 public boolean isAutomaticMipmapsSupported() {
666 return automaticMipMaps;
670 * Overide setting of AutomaticMipmap generation support.
674 public static void overrideAutomaticMipmapsSupport(boolean use) {
675 automaticMipMaps = use;
679 * Reset AutomaticMipmap generation support to driver-detected setting.
681 public static void resetAutomaticMipmapsSupport() {
682 automaticMipMaps = automaticMipMapsDetected;
687 * @return if Anisotropic texture filtering is supported
689 public static boolean isAnisoSupported() {
690 return supportsAniso;
694 * Overide setting of support for Anisotropic texture filtering.
698 public static void overrideAnisoSupport(boolean use) {
703 * Reset dot3 environment texture support to driver-detected setting.
705 public static void resetAnisoSupport() {
706 supportsAniso = supportsAnisoDetected;
711 * @return true if non pow 2 texture sizes are supported
713 public static boolean isNonPowerOfTwoTextureSupported() {
714 return supportsNonPowerTwo;
718 * Overide setting of support for non-pow2 texture sizes.
722 public static void overrideNonPowerOfTwoTextureSupport(boolean use) {
723 supportsNonPowerTwo = use;
727 * Reset support for non-pow2 texture sizes to driver-detected setting.
729 public static void resetNonPowerOfTwoTextureSupport() {
730 supportsNonPowerTwo = supportsNonPowerTwoDetected;
735 * @return if rectangular texture sizes are supported (width != height)
737 public static boolean isRectangularTextureSupported() {
738 return supportsRectangular;
742 * Overide auto-detected setting of support for rectangular texture sizes (width != height).
746 public static void overrideRectangularTextureSupport(boolean use) {
747 supportsRectangular = use;
751 * Reset support for rectangular texture sizes to driver-detected setting.
753 public static void resetRectangularTextureSupport() {
754 supportsRectangular = supportsRectangularDetected;
758 public void write(JMEExporter e) throws IOException {
760 OutputCapsule capsule = e.getCapsule(this);
761 capsule.writeSavableArrayList(texture, "texture",
762 new ArrayList<Texture>(1));
763 capsule.write(offset, "offset", 0);
764 capsule.write(correctionType, "correctionType", CorrectionType.Perspective);
768 @SuppressWarnings("unchecked")
769 public void read(JMEImporter e) throws IOException {
771 InputCapsule capsule = e.getCapsule(this);
772 texture = capsule.readSavableArrayList("texture",
773 new ArrayList<Texture>(1));
774 offset = capsule.readInt("offset", 0);
775 correctionType = capsule.readEnum("correctionType", CorrectionType.class, CorrectionType.Perspective);
779 public Class<? extends TextureState> getClassTag() {
780 return TextureState.class;
783 public void deleteTextureId(int textureId) {
786 public static Image getDefaultTextureImage() {
787 return defaultTexture != null ? defaultTexture.getImage() : null;
790 public static Texture getDefaultTexture() {
791 return defaultTexture;