Explorar el Código

Feature: loading separate UV sets defined by user and loading LightMap.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10737 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl hace 12 años
padre
commit
bf4447bc46

+ 31 - 28
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialContext.java

@@ -2,9 +2,11 @@ package com.jme3.scene.plugins.blender.materials;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+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;
 
 import com.jme3.material.Material;
@@ -44,6 +46,7 @@ public final class MaterialContext {
     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;
@@ -109,7 +112,11 @@ public final class MaterialContext {
                 textureData.mtex = p.fetchData(blenderContext.getInputStream()).get(0);
                 textureData.uvCoordinatesType = ((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) {
+                    textureData.uvCoordinatesName = null;
+                }
+                
                 Pointer pTex = (Pointer) textureData.mtex.getFieldValue("tex");
                 if (pTex.isNotNull()) {
                     Structure tex = pTex.fetchData(blenderContext.getInputStream()).get(0);
@@ -136,7 +143,8 @@ public final class MaterialContext {
                         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, blenderContext);
+                        combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType,
+                        					textureData.textureStructure, textureData.uvCoordinatesName, blenderContext);
                     }
                 }
                 if (combinedTexture.getTexturesCount() > 0) {
@@ -176,7 +184,7 @@ public final class MaterialContext {
      * @param blenderContext
      *            the blender context
      */
-    public void applyMaterial(Geometry geometry, Long geometriesOMA, List<Vector2f> userDefinedUVCoordinates, BlenderContext blenderContext) {
+    public void applyMaterial(Geometry geometry, Long geometriesOMA, LinkedHashMap<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
         Material material = null;
         if (shadeless) {
             material = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
@@ -206,30 +214,24 @@ public final class MaterialContext {
 
         // applying textures
         if (loadedTextures != null && loadedTextures.size() > 0) {
-            Entry<Number, CombinedTexture> basicUVSOwner = null;
+            int textureIndex = 0;
+            if(loadedTextures.size() > 8) {
+                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()) {
-                CombinedTexture combinedTexture = entry.getValue();
-                combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
+                if(textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
+                    CombinedTexture combinedTexture = entry.getValue();
+                    combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
 
-                if (basicUVSOwner == null) {
-                    basicUVSOwner = entry;
-                } else {
-                    combinedTexture.castToUVS(basicUVSOwner.getValue(), blenderContext);
                     this.setTexture(material, entry.getKey().intValue(), combinedTexture.getResultTexture());
+                    List<Vector2f> uvs = entry.getValue().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);
+                } else {
+                    LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length);
                 }
             }
-
-            if (basicUVSOwner != null) {
-                this.setTexture(material, basicUVSOwner.getKey().intValue(), basicUVSOwner.getValue().getResultTexture());
-                List<Vector2f> basicUVS = basicUVSOwner.getValue().getResultUVS();
-                VertexBuffer uvCoordsBuffer = new VertexBuffer(VertexBuffer.Type.TexCoord);
-                uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(basicUVS.toArray(new Vector2f[basicUVS.size()])));
-                geometry.getMesh().setBuffer(uvCoordsBuffer);
-            }
-        } else if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
-            VertexBuffer uvCoordsBuffer = new VertexBuffer(VertexBuffer.Type.TexCoord);
-            uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(userDefinedUVCoordinates.toArray(new Vector2f[userDefinedUVCoordinates.size()])));
-            geometry.getMesh().setBuffer(uvCoordsBuffer);
         }
 
         // applying additional data
@@ -237,11 +239,7 @@ public final class MaterialContext {
         if (vertexColor) {
             material.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", true);
         }
-        if (this.faceCullMode != null) {
-            material.getAdditionalRenderState().setFaceCullMode(faceCullMode);
-        } else {
-            material.getAdditionalRenderState().setFaceCullMode(blenderContext.getBlenderKey().getFaceCullMode());
-        }
+        material.getAdditionalRenderState().setFaceCullMode(faceCullMode != null ? faceCullMode : blenderContext.getBlenderKey().getFaceCullMode());
         if (transparent) {
             material.setTransparent(true);
             material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
@@ -282,6 +280,9 @@ public final class MaterialContext {
                     LOGGER.warning("JME does not support alpha map on unshaded material. Material name is " + name);
                 }
                 break;
+            case MTEX_AMB:
+                material.setTexture(MaterialHelper.TEXTURE_TYPE_LIGHTMAP, texture);
+                break;
             default:
                 LOGGER.severe("Unknown mapping type: " + mapTo);
         }
@@ -311,7 +312,7 @@ public final class MaterialContext {
      * @return a map with sorted and filtered textures
      */
     private Map<Number, List<TextureData>> sortAndFilterTextures(List<TextureData> textures) {
-        int[] mappings = new int[] { MTEX_COL, MTEX_NOR, MTEX_EMIT, MTEX_SPEC, MTEX_ALPHA };
+        int[] mappings = new int[] { MTEX_COL, MTEX_NOR, MTEX_EMIT, MTEX_SPEC, MTEX_ALPHA, MTEX_AMB };
         Map<Number, List<TextureData>> result = new HashMap<Number, List<TextureData>>();
         for (TextureData data : textures) {
             Number mapto = (Number) data.mtex.getFieldValue("mapto");
@@ -413,5 +414,7 @@ public final class MaterialContext {
         Structure textureStructure;
         int       uvCoordinatesType;
         int       projectionType;
+        /** The name of the user's UV coordinates that are used for this texture. */
+        String	  uvCoordinatesName;
     }
 }

+ 1 - 0
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java

@@ -65,6 +65,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
     public static final String               TEXTURE_TYPE_SPECULAR = "SpecularMap";
     public static final String               TEXTURE_TYPE_GLOW     = "GlowMap";
     public static final String               TEXTURE_TYPE_ALPHA    = "AlphaMap";
+    public static final String               TEXTURE_TYPE_LIGHTMAP = "LightMap";
 
     public static final Integer              ALPHA_MASK_NONE       = Integer.valueOf(0);
     public static final Integer              ALPHA_MASK_CIRCLE     = Integer.valueOf(1);

+ 52 - 39
engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshBuilder.java

@@ -3,13 +3,16 @@ package com.jme3.scene.plugins.blender.meshes;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.logging.Logger;
 
 import com.jme3.math.FastMath;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.plugins.blender.textures.UserUVCollection;
 import com.jme3.util.BufferUtils;
 
 /**
@@ -17,8 +20,8 @@ import com.jme3.util.BufferUtils;
  * 
  * @author Marcin Roguski (Kaelthas)
  */
-/*package*/class MeshBuilder {
-    private static final Logger                       LOGGER          = Logger.getLogger(MeshBuilder.class.getName());
+/* package */class MeshBuilder {
+    private static final Logger                       LOGGER           = Logger.getLogger(MeshBuilder.class.getName());
 
     /** An array of reference vertices. */
     private Vector3f[][]                              verticesAndNormals;
@@ -26,25 +29,21 @@ import com.jme3.util.BufferUtils;
     private List<byte[]>                              verticesColors;
     /** A variable that indicates if the model uses generated textures. */
     private boolean                                   usesGeneratedTextures;
-
     /**
      * This map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
      * positions (it simply tells which vertex is referenced where in the result list).
      */
     private Map<Integer, Map<Integer, List<Integer>>> globalVertexReferenceMap;
-
-    /** A map between vertex index and its UV coordinates. */
-    private Map<Integer, Vector2f>                    uvsMap          = new HashMap<Integer, Vector2f>();
     /** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
-    private Map<Integer, List<Vector3f>>              normalMap       = new HashMap<Integer, List<Vector3f>>();
+    private Map<Integer, List<Vector3f>>              normalMap        = new HashMap<Integer, List<Vector3f>>();
     /** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
-    private Map<Integer, List<Vector3f>>              vertexMap       = new HashMap<Integer, List<Vector3f>>();
+    private Map<Integer, List<Vector3f>>              vertexMap        = new HashMap<Integer, List<Vector3f>>();
     /** The following map sorts vertices colors by material number (because in jme Mesh can have only one material). */
-    private Map<Integer, List<byte[]>>                vertexColorsMap = new HashMap<Integer, List<byte[]>>();
+    private Map<Integer, List<byte[]>>                vertexColorsMap  = new HashMap<Integer, List<byte[]>>();
     /** The following map sorts indexes by material number (because in jme Mesh can have only one material). */
-    private Map<Integer, List<Integer>>               indexMap        = new HashMap<Integer, List<Integer>>();
-    /** A map between material number and UV coordinates of mesh that has this material applied. */
-    private Map<Integer, List<Vector2f>>              uvCoordinates   = new HashMap<Integer, List<Vector2f>>();        // <material_number; list of uv coordinates for mesh's vertices>
+    private Map<Integer, List<Integer>>               indexMap         = new HashMap<Integer, List<Integer>>();
+    /** A collection of user defined UV coordinates (one mesh can have more than one such mappings). */
+    private UserUVCollection                          userUVCollection = new UserUVCollection();
 
     /**
      * Constructor. Stores the given array (not copying it).
@@ -100,16 +99,20 @@ import com.jme3.util.BufferUtils;
      *            indicates if this face should have smooth shading or flat shading
      * @param materialNumber
      *            the material number for this face
-     * @param uvs
-     *            a 3-element array of vertices UV coordinates
+     * @param uvsForFace
+     *            a 3-element array of vertices UV coordinates mapped to the UV's set name
      * @param quad
      *            indicates if the appended face is a part of a quad face (used for creating vertex colors buffer)
      * @param faceIndex
      *            the face index (used for creating vertex colors buffer)
      */
-    public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Vector2f[] uvs, boolean quad, int faceIndex) {
-        if (uvs != null && uvs.length != 3) {
-            throw new IllegalArgumentException("UV coordinates must be a 3-element array!");
+    public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Map<String, Vector2f[]> uvsForFace, boolean quad, int faceIndex) {
+        if (uvsForFace != null && uvsForFace.size() > 0) {
+            for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
+                if (entry.getValue().length != 3) {
+                    throw new IllegalArgumentException("UV coordinates must be a 3-element array!" + (entry.getKey() != null ? " (UV set name: " + entry.getKey() + ')' : ""));
+                }
+            }
         }
 
         // getting the required lists
@@ -139,14 +142,6 @@ import com.jme3.util.BufferUtils;
             vertexReferenceMap = new HashMap<Integer, List<Integer>>();
             globalVertexReferenceMap.put(materialNumber, vertexReferenceMap);
         }
-        List<Vector2f> uvCoordinatesList = null;
-        if (uvs != null) {
-            uvCoordinatesList = uvCoordinates.get(Integer.valueOf(materialNumber));
-            if (uvCoordinatesList == null) {
-                uvCoordinatesList = new ArrayList<Vector2f>();
-                uvCoordinates.put(Integer.valueOf(materialNumber), uvCoordinatesList);
-            }
-        }
 
         faceIndex *= 4;
         if (quad) {
@@ -159,38 +154,55 @@ import com.jme3.util.BufferUtils;
         if (smooth && !usesGeneratedTextures) {
             for (int i = 0; i < 3; ++i) {
                 if (!vertexReferenceMap.containsKey(index[i])) {
+                    //if this index is not yet used then create another face
                     this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
+                    if (uvsForFace != null) {
+                        for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
+                            userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
+                        }
+                    }
+
                     vertexList.add(verticesAndNormals[index[i]][0]);
                     if (verticesColors != null) {
                         vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
                     }
                     normalList.add(verticesAndNormals[index[i]][1]);
-                    if (uvCoordinatesList != null) {
-                        uvsMap.put(vertexList.size(), uvs[i]);
-                        uvCoordinatesList.add(uvs[i]);
-                    }
+
                     index[i] = vertexList.size() - 1;
-                } else if (uvCoordinatesList != null) {
+                } else if (uvsForFace != null) {
+                    //if the index is used then check if the vertexe's UV coordinates match, if yes then the vertex doesn't have separate UV's
+                    //in different faces so we can use it here as well, if UV's are different in separate faces the we need to add this vert
+                    //because in jme one vertex can have only on UV coordinate
                     boolean vertexAlreadyUsed = false;
                     for (Integer vertexIndex : vertexReferenceMap.get(index[i])) {
-                        if (uvs[i].equals(uvsMap.get(vertexIndex))) {
+                        int vertexUseCounter = 0;
+                        for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
+                            if (entry.getValue()[i].equals(userUVCollection.getUVForVertex(entry.getKey(), vertexIndex))) {
+                                ++vertexUseCounter;
+                            }
+                        }
+                        if (vertexUseCounter == uvsForFace.size()) {
                             vertexAlreadyUsed = true;
                             index[i] = vertexIndex;
                             break;
                         }
                     }
+
                     if (!vertexAlreadyUsed) {
+                        // treat this face as a new one because its vertices have separate UV's
                         this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
-                        uvsMap.put(vertexList.size(), uvs[i]);
+                        for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
+                            userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
+                        }
                         vertexList.add(verticesAndNormals[index[i]][0]);
                         if (verticesColors != null) {
                             vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
                         }
                         normalList.add(verticesAndNormals[index[i]][1]);
-                        uvCoordinatesList.add(uvs[i]);
                         index[i] = vertexList.size() - 1;
                     }
                 } else {
+                    //use this index again
                     index[i] = vertexList.indexOf(verticesAndNormals[index[i]][0]);
                 }
                 indexList.add(index[i]);
@@ -200,9 +212,10 @@ import com.jme3.util.BufferUtils;
             for (int i = 0; i < 3; ++i) {
                 indexList.add(vertexList.size());
                 this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
-                if (uvCoordinatesList != null) {
-                    uvCoordinatesList.add(uvs[i]);
-                    uvsMap.put(vertexList.size(), uvs[i]);
+                if (uvsForFace != null) {
+                    for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
+                        userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
+                    }
                 }
                 vertexList.add(verticesAndNormals[index[i]][0]);
                 if (verticesColors != null) {
@@ -288,15 +301,15 @@ import com.jme3.util.BufferUtils;
      *            the material number that is appied to the mesh
      * @return UV coordinates of vertices that belong to the required mesh part
      */
-    public List<Vector2f> getUVCoordinates(int materialNumber) {
-        return uvCoordinates.get(materialNumber);
+    public LinkedHashMap<String, List<Vector2f>> getUVCoordinates(int materialNumber) {
+        return userUVCollection.getUVCoordinates(materialNumber);
     }
 
     /**
      * @return indicates if the mesh has UV coordinates
      */
     public boolean hasUVCoordinates() {
-        return uvCoordinates.size() > 0;
+        return userUVCollection.hasUVCoordinates();
     }
 
     /**

+ 119 - 48
engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java

@@ -32,7 +32,10 @@
 package com.jme3.scene.plugins.blender.meshes;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.logging.Logger;
 
@@ -55,6 +58,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.materials.MaterialContext;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper;
 import com.jme3.scene.plugins.blender.objects.Properties;
+import com.jme3.scene.plugins.blender.textures.TextureHelper;
 import com.jme3.util.BufferUtils;
 
 /**
@@ -63,7 +67,12 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski (Kaelthas)
  */
 public class MeshHelper extends AbstractBlenderHelper {
-    private static final Logger LOGGER = Logger.getLogger(MeshHelper.class.getName());
+    private static final Logger LOGGER                   = Logger.getLogger(MeshHelper.class.getName());
+
+    /** A type of UV data layer in traditional faced mesh (triangles or quads). */
+    private static final int    UV_DATA_LAYER_TYPE_FMESH = 5;
+    /** A type of UV data layer in bmesh type. */
+    private static final int    UV_DATA_LAYER_TYPE_BMESH = 16;
 
     /**
      * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
@@ -213,7 +222,7 @@ public class MeshHelper extends AbstractBlenderHelper {
             for (Geometry geometry : geometries) {
                 int materialNumber = meshContext.getMaterialIndex(geometry);
                 if (materials[materialNumber] != null) {
-                    List<Vector2f> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
+                    LinkedHashMap<String, List<Vector2f>> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
                     MaterialContext materialContext = materials[materialNumber];
                     materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), uvCoordinates, blenderContext);
                 } else {
@@ -223,17 +232,26 @@ public class MeshHelper extends AbstractBlenderHelper {
             }
         } else {
             // add UV coordinates if they are defined even if the material is not applied to the model
-            VertexBuffer uvCoordsBuffer = null;
+            List<VertexBuffer> uvCoordsBuffer = null;
             if (meshBuilder.hasUVCoordinates()) {
-                List<Vector2f> uvs = meshBuilder.getUVCoordinates(0);
-                uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
-                uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
+                Map<String, List<Vector2f>> uvs = meshBuilder.getUVCoordinates(0);
+                if (uvs != null && uvs.size() > 0) {
+                    uvCoordsBuffer = new ArrayList<VertexBuffer>(uvs.size());
+                    int uvIndex = 0;
+                    for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
+                        VertexBuffer buffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[uvIndex++]);
+                        buffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(entry.getValue().toArray(new Vector2f[uvs.size()])));
+                        uvCoordsBuffer.add(buffer);
+                    }
+                }
             }
 
             for (Geometry geometry : geometries) {
                 geometry.setMaterial(blenderContext.getDefaultMaterial());
                 if (uvCoordsBuffer != null) {
-                    geometry.getMesh().setBuffer(uvCoordsBuffer);
+                    for (VertexBuffer buffer : uvCoordsBuffer) {
+                        geometry.getMesh().setBuffer(buffer);
+                    }
                 }
             }
         }
@@ -254,6 +272,67 @@ public class MeshHelper extends AbstractBlenderHelper {
         return pMLoop != null && pMPoly != null && pMLoop.isNotNull() && pMPoly.isNotNull();
     }
 
+    /**
+     * The method loads the UV coordinates. The result is a map where the key is the user's UV set name and the values are UV coordinates.
+     * But depending on the mesh type (triangle/quads or bmesh) the lists in the map have different meaning.
+     * For bmesh they are enlisted just like they are stored in the blend file (in loops).
+     * For traditional faces every 4 UV's should be assigned for a single face.
+     * @param meshStructure
+     *            the mesh structure
+     * @param useBMesh
+     *            tells if we should load the coordinates from loops of from faces
+     * @param blenderContext
+     *            the blender context
+     * @return a map that sorts UV coordinates between different UV sets
+     * @throws BlenderFileException
+     *             an exception is thrown when problems with blend file occur
+     */
+    @SuppressWarnings("unchecked")
+    private Map<String, List<Vector2f>> loadUVCoordinates(Structure meshStructure, boolean useBMesh, BlenderContext blenderContext) throws BlenderFileException {
+        Map<String, List<Vector2f>> result = new HashMap<String, List<Vector2f>>();
+        if (useBMesh) {
+            // in this case the UV's are assigned to vertices (an array is the same length as the vertex array)
+            Structure loopData = (Structure) meshStructure.getFieldValue("ldata");
+            Pointer pLoopDataLayers = (Pointer) loopData.getFieldValue("layers");
+            List<Structure> loopDataLayers = pLoopDataLayers.fetchData(blenderContext.getInputStream());
+            for (Structure structure : loopDataLayers) {
+                Pointer p = (Pointer) structure.getFieldValue("data");
+                if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == UV_DATA_LAYER_TYPE_BMESH) {
+                    String uvSetName = structure.getFieldValue("name").toString();
+                    List<Structure> uvsStructures = p.fetchData(blenderContext.getInputStream());
+                    List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
+                    for (Structure uvStructure : uvsStructures) {
+                        DynamicArray<Number> loopUVS = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
+                        uvs.add(new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue()));
+                    }
+                    result.put(uvSetName, uvs);
+                }
+            }
+        } else {
+            // in this case UV's are assigned to faces (the array has the same legnth as the faces count)
+            Structure facesData = (Structure) meshStructure.getFieldValue("fdata");
+            Pointer pFacesDataLayers = (Pointer) facesData.getFieldValue("layers");
+            List<Structure> facesDataLayers = pFacesDataLayers.fetchData(blenderContext.getInputStream());
+            for (Structure structure : facesDataLayers) {
+                Pointer p = (Pointer) structure.getFieldValue("data");
+                if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == UV_DATA_LAYER_TYPE_FMESH) {
+                    String uvSetName = structure.getFieldValue("name").toString();
+                    List<Structure> uvsStructures = p.fetchData(blenderContext.getInputStream());
+                    List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
+                    for (Structure uvStructure : uvsStructures) {
+                        DynamicArray<Number> mFaceUVs = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
+                        uvs.add(new Vector2f(mFaceUVs.get(0).floatValue(), mFaceUVs.get(1).floatValue()));
+                        uvs.add(new Vector2f(mFaceUVs.get(2).floatValue(), mFaceUVs.get(3).floatValue()));
+                        uvs.add(new Vector2f(mFaceUVs.get(4).floatValue(), mFaceUVs.get(5).floatValue()));
+                        uvs.add(new Vector2f(mFaceUVs.get(6).floatValue(), mFaceUVs.get(7).floatValue()));
+                    }
+                    result.put(uvSetName, uvs);
+                }
+            }
+        }
+        return result;
+    }
+
     /**
      * This method reads the mesh from the new BMesh system.
      * 
@@ -267,33 +346,26 @@ public class MeshHelper extends AbstractBlenderHelper {
      *             an exception is thrown when there are problems with the
      *             blender file
      */
-    @SuppressWarnings("unchecked")
     private void readBMesh(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
         Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
         Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
         Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge");
-        Pointer pMLoopUV = (Pointer) meshStructure.getFieldValue("mloopuv");
-        Vector2f[] uvCoordinatesForFace = new Vector2f[3];
+        Map<String, Vector2f[]> uvCoordinatesForFace = new HashMap<String, Vector2f[]>();
 
         if (pMPoly.isNotNull() && pMLoop.isNotNull() && pMEdge.isNotNull()) {
+            Map<String, List<Vector2f>> uvs = this.loadUVCoordinates(meshStructure, true, blenderContext);
             int faceIndex = 0;
             List<Structure> polys = pMPoly.fetchData(blenderContext.getInputStream());
             List<Structure> loops = pMLoop.fetchData(blenderContext.getInputStream());
-            List<Structure> loopuvs = pMLoopUV.isNotNull() ? pMLoopUV.fetchData(blenderContext.getInputStream()) : null;
             for (Structure poly : polys) {
                 int materialNumber = ((Number) poly.getFieldValue("mat_nr")).intValue();
                 int loopStart = ((Number) poly.getFieldValue("loopstart")).intValue();
                 int totLoop = ((Number) poly.getFieldValue("totloop")).intValue();
                 boolean smooth = (((Number) poly.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
                 int[] vertexIndexes = new int[totLoop];
-                Vector2f[] uvs = loopuvs != null ? new Vector2f[totLoop] : null;
 
                 for (int i = loopStart; i < loopStart + totLoop; ++i) {
                     vertexIndexes[i - loopStart] = ((Number) loops.get(i).getFieldValue("v")).intValue();
-                    if (uvs != null) {
-                        DynamicArray<Number> loopUVS = (DynamicArray<Number>) loopuvs.get(i).getFieldValue("uv");
-                        uvs[i - loopStart] = new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue());
-                    }
                 }
 
                 int i = 0;
@@ -302,15 +374,19 @@ public class MeshHelper extends AbstractBlenderHelper {
                     int v2 = vertexIndexes[i + 1];
                     int v3 = vertexIndexes[i + 2];
 
-                    if (uvs != null) {// uvs always must be added wheater we
-                                      // have texture or not
-                        uvCoordinatesForFace[0] = uvs[0];
-                        uvCoordinatesForFace[1] = uvs[i + 1];
-                        uvCoordinatesForFace[2] = uvs[i + 2];
+                    if (uvs != null) {
+                        // uvs always must be added wheater we have texture or not
+                        for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
+                            Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
+                            uvCoordsForASingleFace[0] = entry.getValue().get(loopStart);
+                            uvCoordsForASingleFace[1] = entry.getValue().get(loopStart + i + 1);
+                            uvCoordsForASingleFace[2] = entry.getValue().get(loopStart + i + 2);
+                            uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
+                        }
                     }
 
                     meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, faceIndex);
-
+                    uvCoordinatesForFace.clear();
                     ++i;
                 }
                 ++faceIndex;
@@ -332,38 +408,26 @@ public class MeshHelper extends AbstractBlenderHelper {
      *             an exception is thrown when there are problems with the
      *             blender file
      */
-    @SuppressWarnings("unchecked")
     private void readTraditionalFaces(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
         Pointer pMFace = (Pointer) meshStructure.getFieldValue("mface");
         List<Structure> mFaces = pMFace.isNotNull() ? pMFace.fetchData(blenderContext.getInputStream()) : null;
         if (mFaces != null && mFaces.size() > 0) {
-            Pointer pMTFace = (Pointer) meshStructure.getFieldValue("mtface");
-            List<Structure> mtFaces = null;
-
-            if (pMTFace.isNotNull()) {
-                mtFaces = pMTFace.fetchData(blenderContext.getInputStream());
-                int facesAmount = ((Number) meshStructure.getFieldValue("totface")).intValue();
-                if (mtFaces.size() != facesAmount) {
-                    throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");
-                }
-            }
-
-            // indicates if the material with the specified number should have a
-            // texture attached
-            Vector2f[] uvCoordinatesForFace = new Vector2f[3];
+            // indicates if the material with the specified number should have a texture attached
+            Map<String, List<Vector2f>> uvs = this.loadUVCoordinates(meshStructure, false, blenderContext);
+            Map<String, Vector2f[]> uvCoordinatesForFace = new HashMap<String, Vector2f[]>();
             for (int i = 0; i < mFaces.size(); ++i) {
                 Structure mFace = mFaces.get(i);
                 int materialNumber = ((Number) mFace.getFieldValue("mat_nr")).intValue();
                 boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
-                DynamicArray<Number> uvs = null;
-
-                if (mtFaces != null) {
-                    Structure mtFace = mtFaces.get(i);
+                if (uvs != null) {
                     // uvs always must be added wheater we have texture or not
-                    uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
-                    uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue());
-                    uvCoordinatesForFace[1] = new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue());
-                    uvCoordinatesForFace[2] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue());
+                    for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
+                        Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
+                        uvCoordsForASingleFace[0] = entry.getValue().get(i * 4);
+                        uvCoordsForASingleFace[1] = entry.getValue().get(i * 4 + 1);
+                        uvCoordsForASingleFace[2] = entry.getValue().get(i * 4 + 2);
+                        uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
+                    }
                 }
 
                 int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
@@ -372,13 +436,20 @@ public class MeshHelper extends AbstractBlenderHelper {
                 int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
 
                 meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i);
+                uvCoordinatesForFace.clear();
                 if (v4 > 0) {
                     if (uvs != null) {
-                        uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue());
-                        uvCoordinatesForFace[1] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue());
-                        uvCoordinatesForFace[2] = new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue());
+                        // uvs always must be added wheater we have texture or not
+                        for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
+                            Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
+                            uvCoordsForASingleFace[0] = entry.getValue().get(i * 4);
+                            uvCoordsForASingleFace[1] = entry.getValue().get(i * 4 + 2);
+                            uvCoordsForASingleFace[2] = entry.getValue().get(i * 4 + 3);
+                            uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
+                        }
                     }
                     meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i);
+                    uvCoordinatesForFace.clear();
                 }
             }
         } else {

+ 48 - 133
engine/src/blender/com/jme3/scene/plugins/blender/textures/CombinedTexture.java

@@ -2,10 +2,9 @@ package com.jme3.scene.plugins.blender.textures;
 
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
-import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.logging.Logger;
 
@@ -46,8 +45,6 @@ public class CombinedTexture {
     private final int           mappingType;
     /** The data for each of the textures. */
     private List<TextureData>   textureDatas = new ArrayList<TextureData>();
-    /** The variable indicates if the texture was already triangulated or not. */
-    private boolean             wasTriangulated;
     /** The result texture. */
     private Texture             resultTexture;
     /** The UV values for the result texture. */
@@ -77,10 +74,12 @@ public class CombinedTexture {
      *            the type of UV coordinates projection (for flat textures)
      * @param textureStructure
      *            the texture sructure
+     * @param uvCoordinatesName
+     * 			  the name of the used user's UV coordinates for this texture
      * @param blenderContext
      *            the blender context
      */
-    public void add(Texture texture, TextureBlender textureBlender, int uvCoordinatesType, int projectionType, Structure textureStructure, BlenderContext blenderContext) {
+    public void add(Texture texture, TextureBlender textureBlender, int uvCoordinatesType, int projectionType, Structure textureStructure, String uvCoordinatesName, BlenderContext blenderContext) {
         if (!(texture instanceof GeneratedTexture) && !(texture instanceof Texture2D)) {
             throw new IllegalArgumentException("Unsupported texture type: " + (texture == null ? "null" : texture.getClass()));
         }
@@ -92,6 +91,7 @@ public class CombinedTexture {
                 textureData.uvCoordinatesType = UVCoordinatesType.valueOf(uvCoordinatesType);
                 textureData.projectionType = UVProjectionType.valueOf(projectionType);
                 textureData.textureStructure = textureStructure;
+                textureData.uvCoordinatesName = uvCoordinatesName;
 
                 if (textureDatas.size() > 0 && this.isWithoutAlpha(textureData, blenderContext)) {
                     textureDatas.clear();// clear previous textures, they will be covered anyway
@@ -119,11 +119,12 @@ public class CombinedTexture {
      *            the blender context
      */
     @SuppressWarnings("unchecked")
-    public void flatten(Geometry geometry, Long geometriesOMA, List<Vector2f> userDefinedUVCoordinates, BlenderContext blenderContext) {
+    public void flatten(Geometry geometry, Long geometriesOMA, LinkedHashMap<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
         TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
         Mesh mesh = geometry.getMesh();
         Texture previousTexture = null;
         UVCoordinatesType masterUVCoordinatesType = null;
+        String masterUserUVSetName = null;
         for (TextureData textureData : textureDatas) {
             // decompress compressed textures (all will be merged into one texture anyway)
             if (textureDatas.size() > 1 && textureData.texture.getImage().getFormat().isCompressed()) {
@@ -138,7 +139,12 @@ public class CombinedTexture {
                     resultTexture = textureData.texture;
 
                     if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
-                        resultUVS = userDefinedUVCoordinates;
+                        if(textureData.uvCoordinatesName == null) {
+                            resultUVS = userDefinedUVCoordinates.values().iterator().next();//get the first UV available
+                        } else {
+                            resultUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
+                        }
+                        masterUserUVSetName = textureData.uvCoordinatesName;
                     } else {
                         List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
                         resultUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
@@ -161,7 +167,9 @@ public class CombinedTexture {
                     triangulatedTexture.blend(textureData.textureBlender, (TriangulatedTexture) resultTexture, blenderContext);
                     resultTexture = previousTexture = triangulatedTexture;
                 } else if (textureData.texture instanceof Texture2D) {
-                    if (masterUVCoordinatesType == textureData.uvCoordinatesType && resultTexture instanceof Texture2D) {
+                    if (this.isUVTypesMatch(masterUVCoordinatesType, masterUserUVSetName,
+                                             textureData.uvCoordinatesType, textureData.uvCoordinatesName) &&
+                        resultTexture instanceof Texture2D) {
                         this.scale((Texture2D) textureData.texture, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight());
                         this.merge((Texture2D) resultTexture, (Texture2D) textureData.texture);
                         previousTexture = resultTexture;
@@ -173,7 +181,11 @@ public class CombinedTexture {
                         // first triangulate the current texture
                         List<Vector2f> textureUVS = null;
                         if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
-                            textureUVS = userDefinedUVCoordinates;
+                            if(textureData.uvCoordinatesName == null) {
+                                textureUVS = userDefinedUVCoordinates.values().iterator().next();//get the first UV available
+                            } else {
+                                textureUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
+                            }
                         } else {
                             List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
                             textureUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
@@ -196,7 +208,6 @@ public class CombinedTexture {
             }
             resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
             resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
-            wasTriangulated = true;
         }
 
         // setting additional data
@@ -207,6 +218,31 @@ public class CombinedTexture {
         resultTexture.setMinFilter(MinFilter.NearestNoMipMaps);
     }
 
+    /**
+     * The method checks if the texture UV coordinates match.
+     * It the types are equal and different then UVCoordinatesType.TEXCO_UV then we consider them a match.
+     * If they are both UVCoordinatesType.TEXCO_UV then they match only when their UV sets names are equal.
+     * In other cases they are considered NOT a match.
+     * @param type1 the UV coord type
+     * @param uvSetName1 the user's UV coords set name (considered only for UVCoordinatesType.TEXCO_UV)
+     * @param type2 the UV coord type
+     * @param uvSetName2 the user's UV coords set name (considered only for UVCoordinatesType.TEXCO_UV)
+     * @return <b>true</b> if the types match and <b>false</b> otherwise
+     */
+    private boolean isUVTypesMatch(UVCoordinatesType type1, String uvSetName1,
+                                     UVCoordinatesType type2, String uvSetName2) {
+        if(type1 == type2) {
+            if(type1 == UVCoordinatesType.TEXCO_UV) {
+                if(uvSetName1 != null && uvSetName2 != null && uvSetName1.equals(uvSetName2)) {
+                    return true;
+                }
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+    
     /**
      * This method blends the texture.
      * 
@@ -228,129 +264,6 @@ public class CombinedTexture {
         }
     }
 
-    /**
-     * This method casts the current image to the basic UV's owner UV's
-     * coordinates.
-     * 
-     * @param basicUVSOwner
-     *            the owner of the UV's we cast to
-     * @param blenderContext
-     *            the blender context
-     */
-    public void castToUVS(CombinedTexture basicUVSOwner, BlenderContext blenderContext) {
-        if (resultUVS.size() != basicUVSOwner.resultUVS.size()) {
-            throw new IllegalStateException("The amount of UV coordinates must be equal in order to cast one UV's onto another!");
-        }
-        if (!resultUVS.equals(basicUVSOwner.resultUVS)) {
-            if (!basicUVSOwner.wasTriangulated) {
-                throw new IllegalStateException("The given texture must be triangulated!");
-            }
-            if (!this.wasTriangulated) {
-                resultTexture = new TriangulatedTexture((Texture2D) resultTexture, resultUVS, blenderContext);
-                resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
-                resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
-            }
-            // casting algorithm
-            TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
-            ImageLoader imageLoader = new ImageLoader();
-            List<TriangleTextureElement> faceTextures = new ArrayList<TriangleTextureElement>();
-            List<Vector2f> basicUVS = basicUVSOwner.getResultUVS();
-            int[] imageRectangle = new int[4];// minX, minY, maxX, maxY
-            int[] sourceSize = new int[2], targetSize = new int[2];// width,
-                                                                   // height
-            Vector2f[] destinationUVS = new Vector2f[3];
-            Vector2f[] sourceUVS = new Vector2f[3];
-            List<Vector2f> partImageUVS = Arrays.asList(new Vector2f(), new Vector2f(), new Vector2f());
-            int faceIndex = 0;
-
-            for (int i = 0; i < basicUVS.size(); i += 3) {
-                // destination size nad UVS
-                destinationUVS[0] = basicUVS.get(i);
-                destinationUVS[1] = basicUVS.get(i + 1);
-                destinationUVS[2] = basicUVS.get(i + 2);
-                this.computeImageRectangle(destinationUVS, imageRectangle, basicUVSOwner.resultTexture.getImage().getWidth(), basicUVSOwner.resultTexture.getImage().getHeight(), blenderContext);
-                targetSize[0] = imageRectangle[2] - imageRectangle[0];
-                targetSize[1] = imageRectangle[3] - imageRectangle[1];
-                for (int j = 0; j < 3; ++j) {
-                    partImageUVS.get(j).set((basicUVSOwner.resultTexture.getImage().getWidth() * destinationUVS[j].x - imageRectangle[0]) / targetSize[0], (basicUVSOwner.resultTexture.getImage().getHeight() * destinationUVS[j].y - imageRectangle[1]) / targetSize[1]);
-                }
-
-                // source size and UVS (translate UVS to (0,0) and stretch it to
-                // the borders of the image)
-                sourceUVS[0] = resultUVS.get(i);
-                sourceUVS[1] = resultUVS.get(i + 1);
-                sourceUVS[2] = resultUVS.get(i + 2);
-                this.computeImageRectangle(sourceUVS, imageRectangle, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight(), blenderContext);
-                sourceSize[0] = imageRectangle[2] - imageRectangle[0];
-                sourceSize[1] = imageRectangle[3] - imageRectangle[1];
-                float xTranslateFactor = imageRectangle[0] / (float) resultTexture.getImage().getWidth();
-                float xStreachFactor = resultTexture.getImage().getWidth() / (float) sourceSize[0];
-                float yTranslateFactor = imageRectangle[1] / (float) resultTexture.getImage().getHeight();
-                float yStreachFactor = resultTexture.getImage().getHeight() / (float) sourceSize[1];
-                for (int j = 0; j < 3; ++j) {
-                    sourceUVS[j].x = (sourceUVS[j].x - xTranslateFactor) * xStreachFactor;
-                    sourceUVS[j].y = (sourceUVS[j].y - yTranslateFactor) * yStreachFactor;
-                }
-
-                AffineTransform affineTransform = textureHelper.createAffineTransform(sourceUVS, partImageUVS.toArray(new Vector2f[3]), sourceSize, targetSize);
-
-                Image image = textureHelper.getSubimage(resultTexture.getImage(), imageRectangle[0], imageRectangle[1], imageRectangle[2], imageRectangle[3]);
-
-                // compute the result texture
-                BufferedImage sourceImage = ImageToAwt.convert(image, false, true, 0);
-
-                BufferedImage targetImage = new BufferedImage(targetSize[0], targetSize[1], sourceImage.getType());
-                Graphics2D g = targetImage.createGraphics();
-                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-                g.drawImage(sourceImage, affineTransform, null);
-                g.dispose();
-
-                Image output = imageLoader.load(targetImage, false);
-                faceTextures.add(new TriangleTextureElement(faceIndex++, output, partImageUVS, false, blenderContext));
-            }
-            TriangulatedTexture triangulatedTexture = new TriangulatedTexture(faceTextures, blenderContext);
-            triangulatedTexture.setKeepIdenticalTextures(false);
-            resultTexture = triangulatedTexture.getResultTexture();
-            resultUVS = basicUVS;
-        }
-    }
-
-    /**
-     * This method computes the rectangle of an image constrained by the
-     * triangle UV coordinates.
-     * 
-     * @param triangleVertices
-     *            the triangle UV coordinates
-     * @param result
-     *            the array where the result is stored
-     * @param totalImageWidth
-     *            the total image width
-     * @param totalImageHeight
-     *            the total image height
-     * @param blenderContext
-     *            the blender context
-     */
-    private void computeImageRectangle(Vector2f[] triangleVertices, int[] result, int totalImageWidth, int totalImageHeight, BlenderContext blenderContext) {
-        TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
-
-        float minX = Math.min(triangleVertices[0].x, triangleVertices[1].x);
-        minX = Math.min(minX, triangleVertices[2].x);
-
-        float maxX = Math.max(triangleVertices[0].x, triangleVertices[1].x);
-        maxX = Math.max(maxX, triangleVertices[2].x);
-
-        float minY = Math.min(triangleVertices[0].y, triangleVertices[1].y);
-        minY = Math.min(minY, triangleVertices[2].y);
-
-        float maxY = Math.max(triangleVertices[0].y, triangleVertices[1].y);
-        maxY = Math.max(maxY, triangleVertices[2].y);
-
-        result[0] = textureHelper.getPixelPosition(minX, totalImageWidth);
-        result[1] = textureHelper.getPixelPosition(minY, totalImageHeight);
-        result[2] = textureHelper.getPixelPosition(maxX, totalImageWidth);
-        result[3] = textureHelper.getPixelPosition(maxY, totalImageHeight);
-    }
-
     /**
      * @return the result texture
      */
@@ -546,5 +459,7 @@ public class CombinedTexture {
         public UVProjectionType  projectionType;
         /** The texture sructure. */
         public Structure         textureStructure;
+        /** The name of the user's UV coordinates that are used for this texture. */
+        public String	  		 uvCoordinatesName;
     }
 }

+ 5 - 4
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

@@ -53,6 +53,7 @@ import com.jme3.asset.GeneratedTextureKey;
 import com.jme3.asset.TextureKey;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
@@ -94,11 +95,11 @@ public class TextureHelper extends AbstractBlenderHelper {
     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_POINTDENSITY = 14; // v. 25+
+    public static final int         TEX_VOXELDATA    = 15; // v. 25+
 
+    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();
 
     /**

+ 86 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/UserUVCollection.java

@@ -0,0 +1,86 @@
+package com.jme3.scene.plugins.blender.textures;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.jme3.math.Vector2f;
+
+/**
+ * A collection of UV coordinates. The coords are stored in groups defined by the material index and their UV set name.
+ * 
+ * @author Kaelthas (Marcin Roguski)
+ */
+public class UserUVCollection {
+    /** A map between material number and UV coordinates of mesh that has this material applied. */
+    private Map<Integer, LinkedHashMap<String, List<Vector2f>>> uvCoordinates = new HashMap<Integer, LinkedHashMap<String, List<Vector2f>>>();
+    /** A map between vertex index and its UV coordinates. */
+    private Map<String, Map<Integer, Vector2f>>                 uvsMap        = new HashMap<String, Map<Integer, Vector2f>>();
+
+    /**
+     * Adds a single UV coordinates for a specified vertex index.
+     * @param materialIndex
+     *            the material index
+     * @param uvSetName
+     *            the UV set name
+     * @param uv
+     *            the added UV coordinates
+     * @param jmeVertexIndex
+     *            the index of the vertex in result jme mesh
+     */
+    public void addUV(int materialIndex, String uvSetName, Vector2f uv, int jmeVertexIndex) {
+        // first get all UV sets for the specified material ...
+        LinkedHashMap<String, List<Vector2f>> uvsForMaterial = uvCoordinates.get(materialIndex);
+        if (uvsForMaterial == null) {
+            uvsForMaterial = new LinkedHashMap<String, List<Vector2f>>();
+            uvCoordinates.put(materialIndex, uvsForMaterial);
+        }
+
+        // ... then fetch the UVS for the specified UV set name ...
+        List<Vector2f> uvsForName = uvsForMaterial.get(uvSetName);
+        if (uvsForName == null) {
+            uvsForName = new ArrayList<Vector2f>();
+            uvsForMaterial.put(uvSetName, uvsForName);
+        }
+
+        // ... add the UV coordinates to the proper list ...
+        uvsForName.add(uv);
+
+        // ... and add the mapping of the UV coordinates to a vertex index for the specified UV set
+        Map<Integer, Vector2f> uvToVertexIndexMapping = uvsMap.get(uvSetName);
+        if (uvToVertexIndexMapping == null) {
+            uvToVertexIndexMapping = new HashMap<Integer, Vector2f>();
+            uvsMap.put(uvSetName, uvToVertexIndexMapping);
+        }
+        uvToVertexIndexMapping.put(jmeVertexIndex, uv);
+    }
+
+    /**
+     * @param uvSetName
+     *            the name of the UV set
+     * @param vertexIndex
+     *            the vertex index corresponds to the index in jme mesh and not the original one in blender
+     * @return
+     */
+    public Vector2f getUVForVertex(String uvSetName, int vertexIndex) {
+        return uvsMap.get(uvSetName).get(vertexIndex);
+    }
+
+    /**
+     * @param materialNumber
+     *            the material number that is appied to the mesh
+     * @return UV coordinates of vertices that belong to the required mesh part
+     */
+    public LinkedHashMap<String, List<Vector2f>> getUVCoordinates(int materialNumber) {
+        return uvCoordinates.get(materialNumber);
+    }
+
+    /**
+     * @return indicates if the mesh has UV coordinates
+     */
+    public boolean hasUVCoordinates() {
+        return uvCoordinates.size() > 0;
+    }
+}