OSDN Git Service

Set optimal mime types and executable settings.
[mikumikustudio/MikuMikuStudio.git] / src / com / jme / scene / state / TextureState.java
1 /*
2  * Copyright (c) 2003-2009 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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.
31  */
32
33 package com.jme.scene.state;
34
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
39
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;
48
49 /**
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.
55  * 
56  * @see com.jme.util.TextureManager
57  * @author Mark Powell
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 $
62  */
63 public abstract class TextureState extends RenderState {
64     private static final Logger logger = Logger.getLogger(TextureState.class
65             .getName());
66
67     protected static Texture defaultTexture = null;
68
69     public enum CorrectionType {
70         /**
71          * Correction modifier makes no color corrections, and is the fastest.
72          */
73         Affine,
74
75         /**
76          * Correction modifier makes color corrections based on perspective and
77          * is slower than CM_AFFINE. (Default)
78          */
79         Perspective;
80     }
81     
82     /** The texture(s). */
83     protected transient ArrayList<Texture> texture;
84
85     /** The total number of supported texture units. */
86     protected static int numTotalTexUnits = -1;
87
88     /** The number of texture units availible for fixed functionality */
89     protected static int numFixedTexUnits = -1;
90
91     /** The number of texture units availible to vertex shader */
92     protected static int numVertexTexUnits = -1;
93
94     /** The number of texture units availible to fragment shader */
95     protected static int numFragmentTexUnits = -1;
96
97     /** The number of texture coordinate sets available */
98     protected static int numFragmentTexCoordUnits = -1;
99
100     protected static float maxAnisotropic = -1.0f;
101
102     /** True if multitexturing is supported. */
103     protected static boolean supportsMultiTexture = false;
104     protected static boolean supportsMultiTextureDetected = false;
105
106     /** True if combine dot3 is supported. */
107     protected static boolean supportsEnvDot3 = false;
108     protected static boolean supportsEnvDot3Detected = false;
109
110     /** True if combine dot3 is supported. */
111     protected static boolean supportsEnvCombine = false;
112     protected static boolean supportsEnvCombineDetected = false;
113
114     /** True if anisofiltering is supported. */
115     protected static boolean supportsAniso = false;
116     protected static boolean supportsAnisoDetected = false;
117
118     /** True if non pow 2 texture sizes are supported. */
119     protected static boolean supportsNonPowerTwo = false;
120     protected static boolean supportsNonPowerTwoDetected = false;
121
122     /** True if rectangular textures are supported (vs. only square textures) */
123     protected static boolean supportsRectangular = false;
124     protected static boolean supportsRectangularDetected = false;
125
126     /** True if S3TC compression is supported. */
127     protected static boolean supportsS3TCCompression = false;
128     protected static boolean supportsS3TCCompressionDetected = false;
129
130     /** True if Texture3D is supported. */
131     protected static boolean supportsTexture3D = false;
132     protected static boolean supportsTexture3DDetected = false;
133
134     /** True if TextureCubeMap is supported. */
135     protected static boolean supportsTextureCubeMap = false;
136     protected static boolean supportsTextureCubeMapDetected = false;
137
138     /** True if non-GLU mipmap generation (part of FBO) is supported. */
139     protected static boolean automaticMipMaps = false;
140     protected static boolean automaticMipMapsDetected = false;
141
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;
146     
147     protected transient int firstTexture = 0;
148     protected transient int lastTexture = 0;
149
150     /**
151      * Perspective correction to use for the object rendered with this texture
152      * state. Default is CorrectionType.Perspective.
153      */
154     private CorrectionType correctionType = CorrectionType.Perspective;
155
156     /**
157      * offset is used to denote where to begin access of texture coordinates. 0
158      * default
159      */
160     protected int offset = 0;
161
162     protected transient int[] idCache = new int[0];
163
164     /**
165      * Constructor instantiates a new <code>TextureState</code> object.
166      */
167     public TextureState() {
168         if (defaultTexture == null)
169             try {
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);
175             }
176     }
177
178     /**
179      * <code>getType</code> returns this type of render state. (RS_TEXTURE).
180      * 
181      * @see com.jme.scene.state.RenderState#getType()
182      * @deprecated As of 2.0, use {@link RenderState#getStateType()} instead.
183      */
184     public int getType() {
185         return RS_TEXTURE;
186     }
187
188     /**
189      * <code>getStateType</code> returns the type {@link RenderState.StateType#Texture}
190      * 
191      * @return {@link RenderState.StateType#Texture}
192      * @see com.jme.scene.state.RenderState#getStateType()
193      */
194     public StateType getStateType() {
195         
196         return StateType.Texture;
197     }
198
199     /**
200      * <code>setTexture</code> sets a single texture to the first texture
201      * unit.
202      * 
203      * @param texture
204      *            the texture to set.
205      */
206     public void setTexture(Texture texture) {
207         if (this.texture.size() == 0) {
208             this.texture.add(texture);
209         } else {
210             this.texture.set(0, texture);
211         }
212         setNeedsRefresh(true);
213
214         resetFirstLast();
215     }
216
217     /**
218      * <code>getTexture</code> gets the texture that is assigned to the first
219      * texture unit.
220      * 
221      * @return the texture in the first texture unit.
222      */
223     public Texture getTexture() {
224         if (texture.size() > 0)
225             return texture.get(0);
226         else return null;
227     }
228
229     /**
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.
234      * 
235      * @param texture
236      *            the texture to be used by the state.
237      * @param textureUnit
238      *            the texture unit this texture will fill.
239      */
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);
244             }
245             this.texture.set(textureUnit, texture);
246             resetFirstLast();
247         }
248         setNeedsRefresh(true);
249     }
250
251     /**
252      * <code>getTexture</code> retrieves the texture being used by the state
253      * in a particular texture unit.
254      * 
255      * @param textureUnit
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.
259      */
260     public Texture getTexture(int textureUnit) {
261         if (textureUnit < texture.size() && textureUnit >= 0) {
262             return texture.get(textureUnit);
263         }
264
265         return null;
266     }
267
268     public boolean removeTexture(Texture tex) {
269
270         int index = texture.indexOf(tex);
271         if (index == -1)
272             return false;
273
274         texture.set(index, null);
275         idCache[index] = 0;
276         return true;
277     }
278
279     public boolean removeTexture(int textureUnit) {
280         if (textureUnit < 0 || textureUnit >= numTotalTexUnits
281                 || textureUnit >= texture.size())
282             return false;
283
284         Texture t = texture.get(textureUnit);
285         if (t == null)
286             return false;
287
288         texture.set(textureUnit, null);
289         idCache[textureUnit] = 0;
290         return true;
291
292     }
293
294     /**
295      * Removes all textures in this texture state. Does not delete them from the
296      * graphics card.
297      */
298     public void clearTextures() {
299         for (int i = texture.size(); --i >= 0;) {
300             removeTexture(i);
301         }
302     }
303
304     /**
305      * <code>setCorrectionType</code> sets the image correction type for this
306      * texture state.
307      * 
308      * @param type
309      *            the correction type for this texture.
310      * @throws IllegalArgumentException
311      *             if type is null
312      */
313     public void setCorrectionType(CorrectionType type) {
314         if (type == null) {
315             throw new IllegalArgumentException("type can not be null.");
316         }
317         this.correctionType = type;
318         setNeedsRefresh(true);
319     }
320
321     /**
322      * <code>getCorrectionType</code> returns the correction mode for the texture state.
323      * 
324      * @return the correction type for the texture state.
325      */
326     public CorrectionType getCorrectionType() {
327         return correctionType;
328     }
329
330     /**
331      * <code>getTotalNumberOfUnits</code> returns the total number of texture
332      * units the computer's graphics card supports.
333      * 
334      * @return the total number of texture units supported by the graphics card.
335      */
336     public static int getTotalNumberOfUnits() {
337         return numTotalTexUnits;
338     }
339
340     /**
341      * <code>getNumberOfFixedUnits</code> returns the number of texture units
342      * the computer's graphics card supports, for use in the fixed pipeline.
343      * 
344      * @return the number units.
345      */
346     public static int getNumberOfFixedUnits() {
347         return numFixedTexUnits;
348     }
349
350     /**
351      * <code>getNumberOfVertexUnits</code> returns the number of texture units
352      * available to a vertex shader that this graphics card supports.
353      * 
354      * @return the number of units.
355      */
356     public static int getNumberOfVertexUnits() {
357         return numVertexTexUnits;
358     }
359
360     /**
361      * <code>getNumberOfFragmentUnits</code> returns the number of texture units
362      * available to a fragment shader that this graphics card supports.
363      * 
364      * @return the number of units.
365      */
366     public static int getNumberOfFragmentUnits() {
367         return numFragmentTexUnits;
368     }
369
370     /**
371      * <code>getNumberOfFragmentTexCoordUnits</code> returns the number of
372      * texture coordinate sets available that this graphics card supports.
373      * 
374      * @return the number of units.
375      */
376     public static int getNumberOfFragmentTexCoordUnits() {
377         return numFragmentTexCoordUnits;
378     }
379
380     /**
381      * <code>getNumberOfTotalUnits</code> returns the number texture units the
382      * computer's graphics card supports.
383      * 
384      * @return the number of units.
385      */
386     public static int getNumberOfTotalUnits() {
387         return numTotalTexUnits;
388     }
389
390     /**
391      * Returns the number of textures this texture manager is maintaining.
392      * 
393      * @return the number of textures.
394      */
395     public int getNumberOfSetTextures() {
396         return texture.size();
397     }
398
399     /**
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.
405      * 
406      * @param textureUnit
407      *            The texture unit from which to retrieve the ID.
408      * @return the textureID, or 0 if there is none.
409      */
410     public final int getTextureID(int textureUnit) {
411         if (textureUnit < idCache.length && textureUnit >= 0) {
412             return idCache[textureUnit];
413         }
414
415         return 0;
416     }
417
418     /**
419      * <code>setTextureCoordinateOffset</code> sets the offset value used to
420      * determine which coordinates to use for texturing Geometry.
421      * 
422      * @param offset
423      *            the offset (default 0).
424      */
425     public void setTextureCoordinateOffset(int offset) {
426         this.offset = offset;
427         setNeedsRefresh(true);
428     }
429
430     /**
431      * <code>setTextureCoordinateOffset</code> gets the offset value used to
432      * determine which coordinates to use for texturing Geometry.
433      * 
434      * @return the offset (default 0).
435      */
436     public int getTextureCoordinateOffset() {
437         return this.offset;
438     }
439
440     /**
441      * Loads our textures into the underlying rendering system, generating mip
442      * maps if appropriate.
443      */
444     public void load() {
445         for (int unit = 0; unit < numTotalTexUnits; unit++) {
446             if (getTexture(unit) != null) {
447                 load(unit);
448             }
449         }
450     }
451
452     /**
453      * Loads the texture for the given unit into the underlying rendering
454      * system, generating mip maps if appropriate.
455      */
456     public abstract void load(int unit);
457
458     /**
459      * Removes the texture of the given unit.
460      * 
461      * @param unit
462      *            The unit of the Texture to remove.
463      */
464     public abstract void delete(int unit);
465
466     /**
467      * Removes all Texture set in this TextureState. Does not also remove from
468      * TextureManager's cache.
469      */
470     public abstract void deleteAll();
471
472     /**
473      * Removes all Texture set in this TextureState. Also removes the textures
474      * from the TextureManager cache if passed boolean is true.
475      */
476     public abstract void deleteAll(boolean removeFromCache);
477
478     /**
479      * Returns the maximum anisotropic filter.
480      * 
481      * @return The maximum anisotropic filter.
482      */
483     public float getMaxAnisotropic() {
484         return maxAnisotropic;
485     }
486
487     /**
488      * Updates firstTexture to be the first non-null Texture, and lastTexture to
489      * be the last non-null texture.
490      */
491     protected void resetFirstLast() {
492         boolean foundFirst = false;
493         for (int x = 0; x < texture.size(); x++) {
494             if (texture.get(x) != null) {
495                 if (!foundFirst) {
496                     firstTexture = x;
497                     foundFirst = true;
498                 }
499                 lastTexture = x;
500             }
501         }
502         if (idCache == null || idCache.length <= lastTexture) {
503             if (idCache == null || idCache.length == 0) {
504                 idCache = new int[lastTexture + 2];
505             } else {
506                 int[] tempCache = new int[lastTexture + 2];
507                 System.arraycopy(idCache, 0, tempCache, 0, idCache.length);
508                 idCache = tempCache;
509             }
510         }
511     }
512
513     /**
514      * @return true if multi-texturing is supported in fixed function
515      */
516     public static boolean isMultiTextureSupported() {
517         return supportsMultiTexture;
518     }
519
520     /**
521      * Overide setting of fixed function multi-texturing support.
522      * 
523      * @param use
524      */
525     public static void overrideMultiTextureSupport(boolean use) {
526         supportsMultiTexture = use;
527     }
528
529     /**
530      * Reset fixed function multi-texturing support to driver-detected setting.
531      */
532     public static void resetMultiTextureSupport() {
533         supportsMultiTexture = supportsMultiTextureDetected;
534     }
535
536     
537     /**
538      * @return true we support dot3 environment texture settings
539      */
540     public static boolean isEnvDot3Supported() {
541         return supportsEnvDot3;
542     }
543
544     /**
545      * Overide support for dot3 environment texture settings
546      * 
547      * @param use
548      */
549     public static void overrideEnvDot3Support(boolean use) {
550         supportsEnvDot3 = use;
551     }
552
553     /**
554      * Reset dot3 environment texture support to driver-detected setting.
555      */
556     public static void resetEnvDot3Support() {
557         supportsEnvDot3 = supportsEnvDot3Detected;
558     }
559
560     
561     /**
562      * @return true we support combine environment texture settings
563      */
564     public static boolean isEnvCombineSupported() {
565         return supportsEnvCombine;
566     }
567
568     /**
569      * Overide support for combine environment texture settings
570      * 
571      * @param use
572      */
573     public static void overrideEnvCombineSupport(boolean use) {
574         supportsEnvCombine = use;
575     }
576
577     /**
578      * Reset combine environment texture support to driver-detected setting.
579      */
580     public static void resetEnvCombineSupport() {
581         supportsEnvCombine = supportsEnvCombineDetected;
582     }
583     
584     
585     /**
586      * Returns if S3TC compression is available for textures.
587      * 
588      * @return true if S3TC is available.
589      */
590     public boolean isS3TCSupported() {
591         return supportsS3TCCompression;
592     }
593
594     /**
595      * Overide setting of S3TC compression support.
596      * 
597      * @param use
598      */
599     public static void overrideS3TCSupport(boolean use) {
600         supportsS3TCCompression = use;
601     }
602
603     /**
604      * Reset dot3 environment texture support to driver-detected setting.
605      */
606     public static void resetS3TCSupport() {
607         supportsS3TCCompression = supportsS3TCCompressionDetected;
608     }
609     
610     /**
611      * Returns if Texture3D is available for textures.
612      * 
613      * @return true if Texture3D is available.
614      */
615     public boolean isTexture3DSupported() {
616         return supportsTexture3D;
617     }
618
619     /**
620      * Overide setting of Texture3D support.
621      * 
622      * @param use
623      */
624     public static void overrideTexture3DSupport(boolean use) {
625         supportsTexture3D = use;
626     }
627
628     /**
629      * Reset Texture3D support to driver-detected setting.
630      */
631     public static void resetTexture3DSupport() {
632         supportsTexture3D = supportsTexture3DDetected;
633     }
634
635     /**
636      * Returns if TextureCubeMap is available for textures.
637      * 
638      * @return true if TextureCubeMap is available.
639      */
640     public boolean isTextureCubeMapSupported() {
641         return supportsTextureCubeMap;
642     }
643
644     /**
645      * Overide setting of TextureCubeMap support.
646      * 
647      * @param use
648      */
649     public static void overrideTextureCubeMapSupport(boolean use) {
650         supportsTextureCubeMap = use;
651     }
652
653     /**
654      * Reset TextureCubeMap support to driver-detected setting.
655      */
656     public static void resetTextureCubeMapSupport() {
657         supportsTextureCubeMap = supportsTextureCubeMapDetected;
658     }
659
660     /**
661      * Returns if AutomaticMipmap generation is available for textures.
662      * 
663      * @return true if AutomaticMipmap generation is available.
664      */
665     public boolean isAutomaticMipmapsSupported() {
666         return automaticMipMaps;
667     }
668
669     /**
670      * Overide setting of AutomaticMipmap generation support.
671      * 
672      * @param use
673      */
674     public static void overrideAutomaticMipmapsSupport(boolean use) {
675         automaticMipMaps = use;
676     }
677
678     /**
679      * Reset AutomaticMipmap generation support to driver-detected setting.
680      */
681     public static void resetAutomaticMipmapsSupport() {
682         automaticMipMaps = automaticMipMapsDetected;
683     }
684     
685
686     /**
687      * @return if Anisotropic texture filtering is supported
688      */
689     public static boolean isAnisoSupported() {
690         return supportsAniso;
691     }
692
693     /**
694      * Overide setting of support for Anisotropic texture filtering.
695      * 
696      * @param use
697      */
698     public static void overrideAnisoSupport(boolean use) {
699         supportsAniso = use;
700     }
701
702     /**
703      * Reset dot3 environment texture support to driver-detected setting.
704      */
705     public static void resetAnisoSupport() {
706         supportsAniso = supportsAnisoDetected;
707     }
708
709     
710     /**
711      * @return true if non pow 2 texture sizes are supported
712      */
713     public static boolean isNonPowerOfTwoTextureSupported() {
714         return supportsNonPowerTwo;
715     }
716
717     /**
718      * Overide setting of support for non-pow2 texture sizes.
719      * 
720      * @param use
721      */
722     public static void overrideNonPowerOfTwoTextureSupport(boolean use) {
723         supportsNonPowerTwo = use;
724     }
725
726     /**
727      * Reset support for non-pow2 texture sizes to driver-detected setting.
728      */
729     public static void resetNonPowerOfTwoTextureSupport() {
730         supportsNonPowerTwo = supportsNonPowerTwoDetected;
731     }
732
733     
734     /**
735      * @return if rectangular texture sizes are supported (width != height)
736      */
737     public static boolean isRectangularTextureSupported() {
738         return supportsRectangular;
739     }
740
741     /**
742      * Overide auto-detected setting of support for rectangular texture sizes (width != height).
743      * 
744      * @param use
745      */
746     public static void overrideRectangularTextureSupport(boolean use) {
747         supportsRectangular = use;
748     }
749
750     /**
751      * Reset support for rectangular texture sizes to driver-detected setting.
752      */
753     public static void resetRectangularTextureSupport() {
754         supportsRectangular = supportsRectangularDetected;
755     }
756
757     
758     public void write(JMEExporter e) throws IOException {
759         super.write(e);
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);
765
766     }
767
768     @SuppressWarnings("unchecked")
769     public void read(JMEImporter e) throws IOException {
770         super.read(e);
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);
776         resetFirstLast();
777     }
778
779     public Class<? extends TextureState> getClassTag() {
780         return TextureState.class;
781     }
782
783     public void deleteTextureId(int textureId) {
784     }
785
786     public static Image getDefaultTextureImage() {
787         return defaultTexture != null ? defaultTexture.getImage() : null;
788     }
789
790     public static Texture getDefaultTexture() {
791         return defaultTexture;
792     }
793 }