Просмотр исходного кода

Feature: disabling texture optimisations by default.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10915 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl 11 лет назад
Родитель
Сommit
5e4af7a4fe

+ 37 - 7
engine/src/blender/com/jme3/asset/BlenderKey.java

@@ -114,7 +114,12 @@ public class BlenderKey extends ModelKey {
     /** The radius of a shape that will be used while creating the generated texture for the sky. The higher it is the larger part of the texture will be seen. */
     protected float                    skyGeneratedTextureRadius = 1;
     /** The shape against which the generated texture for the sky will be created. */
-    protected SkyGeneratedTextureShape skyGeneratedTextureShape     = SkyGeneratedTextureShape.SPHERE;
+    protected SkyGeneratedTextureShape skyGeneratedTextureShape  = SkyGeneratedTextureShape.SPHERE;
+    /**
+     * This field tells if the importer should optimise the use of textures or not. If set to true, then textures of the same mapping type will be merged together
+     * and textures that in the final result will never be visible - will be discarded.
+     */
+    protected boolean                  optimiseTextures;
 
     /**
      * Constructor used by serialization mechanisms.
@@ -273,7 +278,7 @@ public class BlenderKey extends ModelKey {
     public void excludeFromLoading(int featuresNotToLoad) {
         featuresToLoad &= ~featuresNotToLoad;
     }
-    
+
     public boolean shouldLoad(int featureToLoad) {
         return (featuresToLoad & featureToLoad) != 0;
     }
@@ -414,12 +419,29 @@ public class BlenderKey extends ModelKey {
      *            the shape against which the generated texture for the sky will be created
      */
     public void setSkyGeneratedTextureShape(SkyGeneratedTextureShape skyGeneratedTextureShape) {
-        if(skyGeneratedTextureShape == null) {
+        if (skyGeneratedTextureShape == null) {
             throw new IllegalArgumentException("The sky generated shape type cannot be null!");
         }
         this.skyGeneratedTextureShape = skyGeneratedTextureShape;
     }
 
+    /**
+     * If set to true, then textures of the same mapping type will be merged together
+     * and textures that in the final result will never be visible - will be discarded.
+     * @param optimiseTextures
+     *            the variable that tells if the textures should be optimised or not
+     */
+    public void setOptimiseTextures(boolean optimiseTextures) {
+        this.optimiseTextures = optimiseTextures;
+    }
+
+    /**
+     * @return the variable that tells if the textures should be optimised or not (by default the optimisation is disabled)
+     */
+    public boolean isOptimiseTextures() {
+        return optimiseTextures;
+    }
+
     /**
      * This mehtod sets the name of the WORLD data block taht should be used during file loading. By default the name is
      * not set. If no name is set or the given name does not occur in the file - the first WORLD data block will be used
@@ -474,6 +496,7 @@ public class BlenderKey extends ModelKey {
         oc.write(skyGeneratedTextureSize, "sky-generated-texture-size", 1000);
         oc.write(skyGeneratedTextureRadius, "sky-generated-texture-radius", 1f);
         oc.write(skyGeneratedTextureShape, "sky-generated-texture-shape", SkyGeneratedTextureShape.SPHERE);
+        oc.write(optimiseTextures, "optimise-textures", false);
     }
 
     @Override
@@ -494,6 +517,7 @@ public class BlenderKey extends ModelKey {
         skyGeneratedTextureSize = ic.readInt("sky-generated-texture-size", 1000);
         skyGeneratedTextureRadius = ic.readFloat("sky-generated-texture-radius", 1f);
         skyGeneratedTextureShape = ic.readEnum("sky-generated-texture-shape", SkyGeneratedTextureShape.class, SkyGeneratedTextureShape.SPHERE);
+        optimiseTextures = ic.readBoolean("optimise-textures", false);
     }
 
     @Override
@@ -507,14 +531,15 @@ public class BlenderKey extends ModelKey {
         result = prime * result + (fixUpAxis ? 1231 : 1237);
         result = prime * result + fps;
         result = prime * result + generatedTexturePPU;
-        result = prime * result + (skyGeneratedTextureShape == null ? 0 : skyGeneratedTextureShape.hashCode());
         result = prime * result + layersToLoad;
         result = prime * result + (loadGeneratedTextures ? 1231 : 1237);
         result = prime * result + (loadObjectProperties ? 1231 : 1237);
         result = prime * result + (loadUnlinkedAssets ? 1231 : 1237);
         result = prime * result + maxTextureSize;
         result = prime * result + (mipmapGenerationMethod == null ? 0 : mipmapGenerationMethod.hashCode());
+        result = prime * result + (optimiseTextures ? 1231 : 1237);
         result = prime * result + Float.floatToIntBits(skyGeneratedTextureRadius);
+        result = prime * result + (skyGeneratedTextureShape == null ? 0 : skyGeneratedTextureShape.hashCode());
         result = prime * result + skyGeneratedTextureSize;
         result = prime * result + (usedWorld == null ? 0 : usedWorld.hashCode());
         return result;
@@ -561,9 +586,6 @@ public class BlenderKey extends ModelKey {
         if (generatedTexturePPU != other.generatedTexturePPU) {
             return false;
         }
-        if (skyGeneratedTextureShape != other.skyGeneratedTextureShape) {
-            return false;
-        }
         if (layersToLoad != other.layersToLoad) {
             return false;
         }
@@ -582,9 +604,15 @@ public class BlenderKey extends ModelKey {
         if (mipmapGenerationMethod != other.mipmapGenerationMethod) {
             return false;
         }
+        if (optimiseTextures != other.optimiseTextures) {
+            return false;
+        }
         if (Float.floatToIntBits(skyGeneratedTextureRadius) != Float.floatToIntBits(other.skyGeneratedTextureRadius)) {
             return false;
         }
+        if (skyGeneratedTextureShape != other.skyGeneratedTextureShape) {
+            return false;
+        }
         if (skyGeneratedTextureSize != other.skyGeneratedTextureSize) {
             return false;
         }
@@ -598,6 +626,8 @@ public class BlenderKey extends ModelKey {
         return true;
     }
 
+
+
     /**
      * This enum tells the importer if the mipmaps for textures will be generated by jme. <li>NEVER_GENERATE and ALWAYS_GENERATE are quite understandable <li>GENERATE_WHEN_NEEDED is an option that checks if the texture had 'Generate mipmaps' option set in blender, mipmaps are generated only when the option is set
      * @author Marcin Roguski (Kaelthas)

+ 3 - 4
engine/src/blender/com/jme3/scene/plugins/blender/landscape/LandscapeHelper.java

@@ -2,7 +2,6 @@ package com.jme3.scene.plugins.blender.landscape;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -101,7 +100,7 @@ public class LandscapeHelper extends AbstractBlenderHelper {
         blenderContext.getBlenderKey().setLoadGeneratedTextures(true);
 
         TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
-        Map<Number, CombinedTexture> loadedTextures = null;
+        List<CombinedTexture> loadedTextures = null;
         try {
             loadedTextures = textureHelper.readTextureData(worldStructure, new float[] { horizontalColor.r, horizontalColor.g, horizontalColor.b, horizontalColor.a }, true);
         } finally {
@@ -113,7 +112,7 @@ public class LandscapeHelper extends AbstractBlenderHelper {
             if (loadedTextures.size() > 1) {
                 throw new IllegalStateException("There should be only one combined texture for sky!");
             }
-            CombinedTexture combinedTexture = loadedTextures.get(1);
+            CombinedTexture combinedTexture = loadedTextures.get(0);
             texture = combinedTexture.generateSkyTexture(horizontalColor, zenithColor, blenderContext);
         } else {
             LOGGER.fine("Preparing colors for colorband.");
@@ -169,7 +168,7 @@ public class LandscapeHelper extends AbstractBlenderHelper {
                     pixelIO.write(image, 3, pixel, x, y);
                 }
             }
-            
+
             LOGGER.fine("Creating bottom texture.");
             pixelIO.read(image, 0, pixel, 0, 0);
             for (int y = 0; y < size; ++y) {

+ 34 - 36
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialContext.java

@@ -2,7 +2,6 @@ package com.jme3.scene.plugins.blender.materials;
 
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -32,30 +31,30 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski (Kaelthas)
  */
 public final class MaterialContext {
-    private static final Logger                     LOGGER     = Logger.getLogger(MaterialContext.class.getName());
+    private static final Logger              LOGGER     = Logger.getLogger(MaterialContext.class.getName());
 
     // texture mapping types
-    public static final int                         MTEX_COL   = 0x01;
-    public static final int                         MTEX_NOR   = 0x02;
-    public static final int                         MTEX_SPEC  = 0x04;
-    public static final int                         MTEX_EMIT  = 0x40;
-    public static final int                         MTEX_ALPHA = 0x80;
-    public static final int                         MTEX_AMB   = 0x800;
+    public static final int                  MTEX_COL   = 0x01;
+    public static final int                  MTEX_NOR   = 0x02;
+    public static final int                  MTEX_SPEC  = 0x04;
+    public static final int                  MTEX_EMIT  = 0x40;
+    public static final int                  MTEX_ALPHA = 0x80;
+    public static final int                  MTEX_AMB   = 0x800;
 
-    /* package */final String                       name;
-    /* package */final Map<Number, CombinedTexture> loadedTextures;
+    /* package */final String                name;
+    /* package */final List<CombinedTexture> loadedTextures;
 
-    /* package */final ColorRGBA                    diffuseColor;
-    /* package */final DiffuseShader                diffuseShader;
-    /* package */final SpecularShader               specularShader;
-    /* package */final ColorRGBA                    specularColor;
-    /* package */final ColorRGBA                    ambientColor;
-    /* package */final float                        shininess;
-    /* package */final boolean                      shadeless;
-    /* package */final boolean                      vertexColor;
-    /* package */final boolean                      transparent;
-    /* package */final boolean                      vTangent;
-    /* package */FaceCullMode                       faceCullMode;
+    /* package */final ColorRGBA             diffuseColor;
+    /* package */final DiffuseShader         diffuseShader;
+    /* package */final SpecularShader        specularShader;
+    /* package */final ColorRGBA             specularColor;
+    /* package */final ColorRGBA             ambientColor;
+    /* package */final float                 shininess;
+    /* package */final boolean               shadeless;
+    /* package */final boolean               vertexColor;
+    /* package */final boolean               transparent;
+    /* package */final boolean               vTangent;
+    /* package */FaceCullMode                faceCullMode;
 
     /* package */MaterialContext(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
         name = structure.getName();
@@ -68,7 +67,7 @@ public final class MaterialContext {
         int diff_shader = ((Number) structure.getFieldValue("diff_shader")).intValue();
         diffuseShader = DiffuseShader.values()[diff_shader];
 
-        if (this.shadeless) {
+        if (shadeless) {
             float r = ((Number) structure.getFieldValue("r")).floatValue();
             float g = ((Number) structure.getFieldValue("g")).floatValue();
             float b = ((Number) structure.getFieldValue("b")).floatValue();
@@ -84,9 +83,9 @@ public final class MaterialContext {
             int spec_shader = ((Number) structure.getFieldValue("spec_shader")).intValue();
             specularShader = SpecularShader.values()[spec_shader];
             specularColor = this.readSpecularColor(structure);
-            float shininess = ((Number) structure.getFieldValue("har")).floatValue();//this is (probably) the specular hardness in blender
+            float shininess = ((Number) structure.getFieldValue("har")).floatValue();// this is (probably) the specular hardness in blender
             this.shininess = shininess > 0.0f ? shininess : MaterialHelper.DEFAULT_SHININESS;
-            
+
             float r = ((Number) structure.getFieldValue("ambr")).floatValue();
             float g = ((Number) structure.getFieldValue("ambg")).floatValue();
             float b = ((Number) structure.getFieldValue("ambb")).floatValue();
@@ -159,16 +158,15 @@ public final class MaterialContext {
         // applying textures
         if (loadedTextures != null && loadedTextures.size() > 0) {
             int textureIndex = 0;
-            if(loadedTextures.size() > TextureHelper.TEXCOORD_TYPES.length) {
+            if (loadedTextures.size() > TextureHelper.TEXCOORD_TYPES.length) {
                 LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different textures. JME supports only {0} UV mappings.", TextureHelper.TEXCOORD_TYPES.length);
             }
-            for (Entry<Number, CombinedTexture> entry : loadedTextures.entrySet()) {
-                if(textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
-                    CombinedTexture combinedTexture = entry.getValue();
+            for (CombinedTexture combinedTexture : loadedTextures) {
+                if (textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
                     combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
 
-                    this.setTexture(material, entry.getKey().intValue(), combinedTexture.getResultTexture());
-                    List<Vector2f> uvs = entry.getValue().getResultUVS();
+                    this.setTexture(material, combinedTexture.getMappingType(), combinedTexture.getResultTexture());
+                    List<Vector2f> uvs = combinedTexture.getResultUVS();
                     VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);
                     uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
                     geometry.getMesh().setBuffer(uvCoordsBuffer);
@@ -176,14 +174,14 @@ public final class MaterialContext {
                     LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length);
                 }
             }
-        } else if(userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
+        } else if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
             LOGGER.fine("No textures found for the mesh, but UV coordinates are applied.");
             int textureIndex = 0;
-            if(userDefinedUVCoordinates.size() > TextureHelper.TEXCOORD_TYPES.length) {
+            if (userDefinedUVCoordinates.size() > TextureHelper.TEXCOORD_TYPES.length) {
                 LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different UV coordinates for the mesh. JME supports only {0} UV coordinates buffers.", TextureHelper.TEXCOORD_TYPES.length);
             }
-            for(Entry<String, List<Vector2f>> entry : userDefinedUVCoordinates.entrySet()) {
-                if(textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
+            for (Entry<String, List<Vector2f>> entry : userDefinedUVCoordinates.entrySet()) {
+                if (textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
                     List<Vector2f> uvs = entry.getValue();
                     VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);
                     uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
@@ -253,8 +251,8 @@ public final class MaterialContext {
      */
     public boolean hasGeneratedTextures() {
         if (loadedTextures != null) {
-            for (Entry<Number, CombinedTexture> entry : loadedTextures.entrySet()) {
-                if (entry.getValue().hasGeneratedTextures()) {
+            for (CombinedTexture generatedTextures : loadedTextures) {
+                if (generatedTextures.hasGeneratedTextures()) {
                     return true;
                 }
             }

+ 8 - 1
engine/src/blender/com/jme3/scene/plugins/blender/textures/CombinedTexture.java

@@ -379,6 +379,13 @@ public class CombinedTexture {
         return textureDatas.size();
     }
 
+    /**
+     * @return the texture's mapping type
+     */
+    public int getMappingType() {
+        return mappingType;
+    }
+
     /**
      * @return <b>true</b> if the texture has at least one generated texture component and <b>false</b> otherwise
      */
@@ -392,7 +399,7 @@ public class CombinedTexture {
         }
         return false;
     }
-    
+
     /**
      * This method determines if the given texture has no alpha channel.
      * 

+ 74 - 45
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

@@ -77,29 +77,29 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski
  */
 public class TextureHelper extends AbstractBlenderHelper {
-    private static final Logger     LOGGER           = Logger.getLogger(TextureHelper.class.getName());
+    private static final Logger     LOGGER                  = Logger.getLogger(TextureHelper.class.getName());
 
     // texture types
-    public static final int         TEX_NONE         = 0;
-    public static final int         TEX_CLOUDS       = 1;
-    public static final int         TEX_WOOD         = 2;
-    public static final int         TEX_MARBLE       = 3;
-    public static final int         TEX_MAGIC        = 4;
-    public static final int         TEX_BLEND        = 5;
-    public static final int         TEX_STUCCI       = 6;
-    public static final int         TEX_NOISE        = 7;
-    public static final int         TEX_IMAGE        = 8;
-    public static final int         TEX_PLUGIN       = 9;
-    public static final int         TEX_ENVMAP       = 10;
-    public static final int         TEX_MUSGRAVE     = 11;
-    public static final int         TEX_VORONOI      = 12;
-    public static final int         TEX_DISTNOISE    = 13;
-    public static final int         TEX_POINTDENSITY = 14; // v. 25+
-    public static final int         TEX_VOXELDATA    = 15; // v. 25+
-    public static final int         TEX_OCEAN        = 16; // v. 26+
-
-    public static final Type[]      TEXCOORD_TYPES = new Type[] { Type.TexCoord, Type.TexCoord2, Type.TexCoord3, Type.TexCoord4, Type.TexCoord5, Type.TexCoord6, Type.TexCoord7, Type.TexCoord8 };
-    
+    public static final int         TEX_NONE                = 0;
+    public static final int         TEX_CLOUDS              = 1;
+    public static final int         TEX_WOOD                = 2;
+    public static final int         TEX_MARBLE              = 3;
+    public static final int         TEX_MAGIC               = 4;
+    public static final int         TEX_BLEND               = 5;
+    public static final int         TEX_STUCCI              = 6;
+    public static final int         TEX_NOISE               = 7;
+    public static final int         TEX_IMAGE               = 8;
+    public static final int         TEX_PLUGIN              = 9;
+    public static final int         TEX_ENVMAP              = 10;
+    public static final int         TEX_MUSGRAVE            = 11;
+    public static final int         TEX_VORONOI             = 12;
+    public static final int         TEX_DISTNOISE           = 13;
+    public static final int         TEX_POINTDENSITY        = 14;                                                                                                                                          // v. 25+
+    public static final int         TEX_VOXELDATA           = 15;                                                                                                                                          // v. 25+
+    public static final int         TEX_OCEAN               = 16;                                                                                                                                          // v. 26+
+
+    public static final Type[]      TEXCOORD_TYPES          = new Type[] { Type.TexCoord, Type.TexCoord2, Type.TexCoord3, Type.TexCoord4, Type.TexCoord5, Type.TexCoord6, Type.TexCoord7, Type.TexCoord8 };
+
     private TextureGeneratorFactory textureGeneratorFactory = new TextureGeneratorFactory();
 
     /**
@@ -523,9 +523,9 @@ public class TextureHelper extends AbstractBlenderHelper {
 
         return result;
     }
-    
+
     @SuppressWarnings("unchecked")
-    public Map<Number, CombinedTexture> readTextureData(Structure structure, float[] diffuseColorArray, boolean skyTexture) throws BlenderFileException {
+    public List<CombinedTexture> readTextureData(Structure structure, float[] diffuseColorArray, boolean skyTexture) throws BlenderFileException {
         DynamicArray<Pointer> mtexsArray = (DynamicArray<Pointer>) structure.getFieldValue("mtex");
         int separatedTextures = skyTexture ? 0 : ((Number) structure.getFieldValue("septex")).intValue();
         List<TextureData> texturesList = new ArrayList<TextureData>();
@@ -537,10 +537,10 @@ public class TextureHelper extends AbstractBlenderHelper {
                 textureData.uvCoordinatesType = skyTexture ? UVCoordinatesType.TEXCO_ORCO.blenderValue : ((Number) textureData.mtex.getFieldValue("texco")).intValue();
                 textureData.projectionType = ((Number) textureData.mtex.getFieldValue("mapping")).intValue();
                 textureData.uvCoordinatesName = textureData.mtex.getFieldValue("uvName").toString();
-                if(textureData.uvCoordinatesName != null && textureData.uvCoordinatesName.trim().length() == 0) {
+                if (textureData.uvCoordinatesName != null && textureData.uvCoordinatesName.trim().length() == 0) {
                     textureData.uvCoordinatesName = null;
                 }
-                
+
                 Pointer pTex = (Pointer) textureData.mtex.getFieldValue("tex");
                 if (pTex.isNotNull()) {
                     Structure tex = pTex.fetchData(blenderContext.getInputStream()).get(0);
@@ -550,33 +550,62 @@ public class TextureHelper extends AbstractBlenderHelper {
             }
         }
 
-        // loading the textures and merging them
-        Map<Number, List<TextureData>> textureDataMap = this.sortTextures(texturesList);
-        Map<Number, CombinedTexture> loadedTextures = new HashMap<Number, CombinedTexture>();
-        for (Entry<Number, List<TextureData>> entry : textureDataMap.entrySet()) {
-            if (entry.getValue().size() > 0) {
-                CombinedTexture combinedTexture = new CombinedTexture(entry.getKey().intValue(), !skyTexture);
-                for (TextureData textureData : entry.getValue()) {
+        LOGGER.info("Loading model's textures.");
+        List<CombinedTexture> loadedTextures = new ArrayList<CombinedTexture>();
+        if (blenderContext.getBlenderKey().isOptimiseTextures()) {
+            LOGGER.fine("Optimising the useage of model's textures.");
+            Map<Number, List<TextureData>> textureDataMap = this.sortTextures(texturesList);
+            for (Entry<Number, List<TextureData>> entry : textureDataMap.entrySet()) {
+                if (entry.getValue().size() > 0) {
+                    CombinedTexture combinedTexture = new CombinedTexture(entry.getKey().intValue(), !skyTexture);
+                    for (TextureData textureData : entry.getValue()) {
+                        int texflag = ((Number) textureData.mtex.getFieldValue("texflag")).intValue();
+                        boolean negateTexture = (texflag & 0x04) != 0;
+                        Texture texture = this.getTexture(textureData.textureStructure, textureData.mtex, blenderContext);
+                        if (texture != null) {
+                            int blendType = ((Number) textureData.mtex.getFieldValue("blendtype")).intValue();
+                            float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
+                            float colfac = ((Number) textureData.mtex.getFieldValue("colfac")).floatValue();
+                            TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat(), texflag, negateTexture, blendType, diffuseColorArray, color, colfac);
+                            combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType, textureData.textureStructure, textureData.uvCoordinatesName, blenderContext);
+                        }
+                    }
+                    if (combinedTexture.getTexturesCount() > 0) {
+                        loadedTextures.add(combinedTexture);
+                    }
+                }
+            }
+        } else {
+            LOGGER.fine("No textures optimisation applied.");
+            int[] mappings = new int[] { MaterialContext.MTEX_COL, MaterialContext.MTEX_NOR, MaterialContext.MTEX_EMIT, MaterialContext.MTEX_SPEC, MaterialContext.MTEX_ALPHA, MaterialContext.MTEX_AMB };
+            for (TextureData textureData : texturesList) {
+                Texture texture = this.getTexture(textureData.textureStructure, textureData.mtex, blenderContext);
+                if (texture != null) {
+                    Number mapto = (Number) textureData.mtex.getFieldValue("mapto");
                     int texflag = ((Number) textureData.mtex.getFieldValue("texflag")).intValue();
                     boolean negateTexture = (texflag & 0x04) != 0;
-                    Texture texture = this.getTexture(textureData.textureStructure, textureData.mtex, blenderContext);
-                    if (texture != null) {
-                        int blendType = ((Number) textureData.mtex.getFieldValue("blendtype")).intValue();
-                        float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
-                        float colfac = ((Number) textureData.mtex.getFieldValue("colfac")).floatValue();
-                        TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat(), texflag, negateTexture, blendType, diffuseColorArray, color, colfac);
-                        combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType,
-                                            textureData.textureStructure, textureData.uvCoordinatesName, blenderContext);
+
+                    for (int i = 0; i < mappings.length; ++i) {
+                        if ((mappings[i] & mapto.intValue()) != 0) {
+                            CombinedTexture combinedTexture = new CombinedTexture(mappings[i], !skyTexture);
+                            int blendType = ((Number) textureData.mtex.getFieldValue("blendtype")).intValue();
+                            float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
+                            float colfac = ((Number) textureData.mtex.getFieldValue("colfac")).floatValue();
+                            TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat(), texflag, negateTexture, blendType, diffuseColorArray, color, colfac);
+                            combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType, textureData.textureStructure, textureData.uvCoordinatesName, blenderContext);
+                            if (combinedTexture.getTexturesCount() > 0) {// the added texture might not have been accepted (if for example loading generated textures is disabled)
+                                loadedTextures.add(combinedTexture);
+                            }
+                        }
                     }
                 }
-                if (combinedTexture.getTexturesCount() > 0) {
-                    loadedTextures.put(entry.getKey(), combinedTexture);
-                }
+
             }
         }
+
         return loadedTextures;
     }
-    
+
     /**
      * This method sorts the textures by their mapping type. In each group only
      * textures of one type are put (either two- or three-dimensional).
@@ -601,7 +630,7 @@ public class TextureHelper extends AbstractBlenderHelper {
         }
         return result;
     }
-    
+
     private static class TextureData {
         public Structure mtex;
         public Structure textureStructure;