Home | History | Annotate | Download | only in meshes
      1 /*
      2  * Copyright (c) 2009-2010 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 package com.jme3.scene.plugins.blender.meshes;
     33 
     34 import java.nio.ByteBuffer;
     35 import java.util.ArrayList;
     36 import java.util.HashMap;
     37 import java.util.LinkedList;
     38 import java.util.List;
     39 import java.util.Map;
     40 import java.util.Map.Entry;
     41 
     42 import com.jme3.asset.BlenderKey.FeaturesToLoad;
     43 import com.jme3.material.Material;
     44 import com.jme3.math.FastMath;
     45 import com.jme3.math.Vector2f;
     46 import com.jme3.math.Vector3f;
     47 import com.jme3.renderer.queue.RenderQueue.Bucket;
     48 import com.jme3.scene.Geometry;
     49 import com.jme3.scene.Mesh;
     50 import com.jme3.scene.VertexBuffer;
     51 import com.jme3.scene.VertexBuffer.Format;
     52 import com.jme3.scene.VertexBuffer.Type;
     53 import com.jme3.scene.VertexBuffer.Usage;
     54 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
     55 import com.jme3.scene.plugins.blender.BlenderContext;
     56 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
     57 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
     58 import com.jme3.scene.plugins.blender.file.DynamicArray;
     59 import com.jme3.scene.plugins.blender.file.Pointer;
     60 import com.jme3.scene.plugins.blender.file.Structure;
     61 import com.jme3.scene.plugins.blender.materials.MaterialContext;
     62 import com.jme3.scene.plugins.blender.materials.MaterialHelper;
     63 import com.jme3.scene.plugins.blender.objects.Properties;
     64 import com.jme3.scene.plugins.blender.textures.TextureHelper;
     65 import com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator;
     66 import com.jme3.texture.Texture;
     67 import com.jme3.util.BufferUtils;
     68 
     69 /**
     70  * A class that is used in mesh calculations.
     71  *
     72  * @author Marcin Roguski (Kaelthas)
     73  */
     74 public class MeshHelper extends AbstractBlenderHelper {
     75 
     76     /**
     77      * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
     78      * versions.
     79      *
     80      * @param blenderVersion
     81      *            the version read from the blend file
     82      * @param fixUpAxis
     83      *        a variable that indicates if the Y asxis is the UP axis or not
     84      */
     85     public MeshHelper(String blenderVersion, boolean fixUpAxis) {
     86         super(blenderVersion,fixUpAxis);
     87     }
     88 
     89     /**
     90      * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.
     91      *
     92      * @param structure
     93      *            the structure we read the mesh from
     94      * @return the mesh feature
     95      * @throws BlenderFileException
     96      */
     97     @SuppressWarnings("unchecked")
     98     public List<Geometry> toMesh(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
     99         List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(),
    100                 LoadedFeatureDataType.LOADED_FEATURE);
    101         if (geometries != null) {
    102             List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());
    103             for (Geometry geometry : geometries) {
    104                 copiedGeometries.add(geometry.clone());
    105             }
    106             return copiedGeometries;
    107         }
    108 
    109         // helpers
    110         TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
    111 
    112         // reading mesh data
    113         String name = structure.getName();
    114         MeshContext meshContext = new MeshContext();
    115 
    116         // reading vertices
    117         Vector3f[] vertices = this.getVertices(structure, blenderContext);
    118         int verticesAmount = vertices.length;
    119 
    120         // vertices Colors
    121         List<byte[]> verticesColors = this.getVerticesColors(structure, blenderContext);
    122 
    123         // reading faces
    124         // the following map sorts faces by material number (because in jme Mesh can have only one material)
    125         Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();
    126         Pointer pMFace = (Pointer) structure.getFieldValue("mface");
    127         List<Structure> mFaces = null;
    128         if (pMFace.isNotNull()) {
    129             mFaces = pMFace.fetchData(blenderContext.getInputStream());
    130             if (mFaces == null || mFaces.size() == 0) {
    131                 return new ArrayList<Geometry>(0);
    132             }
    133         } else{
    134         	mFaces = new ArrayList<Structure>(0);
    135         }
    136 
    137         Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");
    138         List<Vector2f> uvCoordinates = null;
    139         List<Structure> mtFaces = null;
    140 
    141         if (pMTFace.isNotNull()) {
    142             mtFaces = pMTFace.fetchData(blenderContext.getInputStream());
    143             int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();
    144             if (mtFaces.size() != facesAmount) {
    145                 throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");
    146             }
    147             uvCoordinates = new ArrayList<Vector2f>();
    148         }
    149 
    150         // normalMap merges normals of faces that will be rendered smooth
    151         Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);
    152 
    153         List<Vector3f> normalList = new ArrayList<Vector3f>();
    154         List<Vector3f> vertexList = new ArrayList<Vector3f>();
    155         // indicates if the material with the specified number should have a texture attached
    156         Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();
    157         // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
    158         // positions (it simply tells which vertex is referenced where in the result list)
    159         Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);
    160         int vertexColorIndex = 0;
    161         for (int i = 0; i < mFaces.size(); ++i) {
    162             Structure mFace = mFaces.get(i);
    163             boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
    164             DynamicArray<Number> uvs = null;
    165             boolean materialWithoutTextures = false;
    166             Pointer pImage = null;
    167             if (mtFaces != null) {
    168                 Structure mtFace = mtFaces.get(i);
    169                 pImage = (Pointer) mtFace.getFieldValue("tpage");
    170                 materialWithoutTextures = pImage.isNull();
    171                 // uvs always must be added wheater we have texture or not
    172                 uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
    173                 uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
    174                 uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));
    175                 uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
    176             }
    177             int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();
    178             Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);
    179             List<Integer> indexList = meshesMap.get(materialNumber);
    180             if (indexList == null) {
    181                 indexList = new ArrayList<Integer>();
    182                 meshesMap.put(materialNumber, indexList);
    183             }
    184 
    185             // attaching image to texture (face can have UV's and image whlie its material may have no texture attached)
    186             if (pImage != null && pImage.isNotNull() && !materialNumberToTexture.containsKey(materialNumber)) {
    187                 Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(blenderContext.getInputStream()).get(0),
    188                         blenderContext);
    189                 if (texture != null) {
    190                     materialNumberToTexture.put(materialNumber, texture);
    191                 }
    192             }
    193 
    194             int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
    195             int v2 = ((Number) mFace.getFieldValue("v2")).intValue();
    196             int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
    197             int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
    198 
    199             Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);
    200             this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);
    201             normalList.add(normalMap.get(vertices[v1]));
    202             normalList.add(normalMap.get(vertices[v2]));
    203             normalList.add(normalMap.get(vertices[v3]));
    204 
    205             this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
    206             indexList.add(vertexList.size());
    207             vertexList.add(vertices[v1]);
    208 
    209             this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);
    210             indexList.add(vertexList.size());
    211             vertexList.add(vertices[v2]);
    212 
    213             this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
    214             indexList.add(vertexList.size());
    215             vertexList.add(vertices[v3]);
    216 
    217             if (v4 > 0) {
    218                 if (uvs != null) {
    219                     uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
    220                     uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
    221                     uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));
    222                 }
    223                 this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
    224                 indexList.add(vertexList.size());
    225                 vertexList.add(vertices[v1]);
    226 
    227                 this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
    228                 indexList.add(vertexList.size());
    229                 vertexList.add(vertices[v3]);
    230 
    231                 this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);
    232                 indexList.add(vertexList.size());
    233                 vertexList.add(vertices[v4]);
    234 
    235                 this.addNormal(n, normalMap, smooth, vertices[v4]);
    236                 normalList.add(normalMap.get(vertices[v1]));
    237                 normalList.add(normalMap.get(vertices[v3]));
    238                 normalList.add(normalMap.get(vertices[v4]));
    239 
    240                 if (verticesColors != null) {
    241                     verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));
    242                     verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));
    243                 }
    244                 vertexColorIndex += 6;
    245             } else {
    246                 if (verticesColors != null) {
    247                     verticesColors.remove(vertexColorIndex + 3);
    248                     vertexColorIndex += 3;
    249                 }
    250             }
    251         }
    252         meshContext.setVertexList(vertexList);
    253         meshContext.setVertexReferenceMap(vertexReferenceMap);
    254 
    255         Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);
    256 
    257         // reading vertices groups (from the parent)
    258         Structure parent = blenderContext.peekParent();
    259         Structure defbase = (Structure) parent.getFieldValue("defbase");
    260         List<Structure> defs = defbase.evaluateListBase(blenderContext);
    261         String[] verticesGroups = new String[defs.size()];
    262         int defIndex = 0;
    263         for (Structure def : defs) {
    264             verticesGroups[defIndex++] = def.getFieldValue("name").toString();
    265         }
    266 
    267         // reading materials
    268         MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
    269         Material[] materials = null;
    270         Material[] nonTexturedMaterials = null;
    271         if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
    272             materials = materialHelper.getMaterials(structure, blenderContext);
    273             nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed
    274         }
    275 
    276         // creating the result meshes
    277         geometries = new ArrayList<Geometry>(meshesMap.size());
    278 
    279         VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);
    280         verticesBuffer.setupData(Usage.Stream, 3, Format.Float,
    281                 BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));
    282 
    283         // initial vertex position (used with animation)
    284         VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);
    285         verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));
    286 
    287         VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);
    288         normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));
    289 
    290         // initial normals position (used with animation)
    291         VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);
    292         normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));
    293 
    294         VertexBuffer uvCoordsBuffer = null;
    295         if (uvCoordinates != null) {
    296             uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
    297             uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,
    298                     BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));
    299         }
    300 
    301         //reading custom properties
    302         Properties properties = this.loadProperties(structure, blenderContext);
    303 
    304         // generating meshes
    305         //FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);
    306         ByteBuffer verticesColorsBuffer = createByteBuffer(verticesColors);
    307         verticesAmount = vertexList.size();
    308         for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {
    309             Mesh mesh = new Mesh();
    310 
    311             // creating vertices indices for this mesh
    312             List<Integer> indexList = meshEntry.getValue();
    313             if(verticesAmount <= Short.MAX_VALUE) {
    314             	short[] indices = new short[indexList.size()];
    315                 for (int i = 0; i < indexList.size(); ++i) {
    316                     indices[i] = indexList.get(i).shortValue();
    317                 }
    318                 mesh.setBuffer(Type.Index, 1, indices);
    319             } else {
    320             	int[] indices = new int[indexList.size()];
    321                 for (int i = 0; i < indexList.size(); ++i) {
    322                     indices[i] = indexList.get(i).intValue();
    323                 }
    324                 mesh.setBuffer(Type.Index, 1, indices);
    325             }
    326 
    327             mesh.setBuffer(verticesBuffer);
    328             mesh.setBuffer(verticesBind);
    329 
    330             // setting vertices colors
    331             if (verticesColorsBuffer != null) {
    332                 mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);
    333                 mesh.getBuffer(Type.Color).setNormalized(true);
    334             }
    335 
    336             // setting faces' normals
    337             mesh.setBuffer(normalsBuffer);
    338             mesh.setBuffer(normalsBind);
    339 
    340             // creating the result
    341             Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);
    342             if (materials != null) {
    343                 int materialNumber = meshEntry.getKey().intValue();
    344                 Material material;
    345                 if (materialNumber >= 0) {
    346                     material = materials[materialNumber];
    347                     if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {
    348                         if (material.getMaterialDef().getAssetName().contains("Lighting")) {
    349                             if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {
    350                                 material = material.clone();
    351                                 material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,
    352                                         materialNumberToTexture.get(Integer.valueOf(materialNumber)));
    353                             }
    354                         } else {
    355                             if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {
    356                                 material = material.clone();
    357                                 material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,
    358                                         materialNumberToTexture.get(Integer.valueOf(materialNumber)));
    359                             }
    360                         }
    361                     }
    362                 } else {
    363                     materialNumber = -1 * (materialNumber + 1);
    364                     if (nonTexturedMaterials[materialNumber] == null) {
    365                         nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],
    366                                 TextureHelper.TEX_IMAGE);
    367                     }
    368                     material = nonTexturedMaterials[materialNumber];
    369                 }
    370                 geometry.setMaterial(material);
    371                 if (material.isTransparent()) {
    372                     geometry.setQueueBucket(Bucket.Transparent);
    373                 }
    374             } else {
    375                 geometry.setMaterial(blenderContext.getDefaultMaterial());
    376             }
    377             if (properties != null && properties.getValue() != null) {
    378                 geometry.setUserData("properties", properties);
    379             }
    380             geometries.add(geometry);
    381         }
    382 
    383         //applying uvCoordinates for all the meshes
    384         if (uvCoordsBuffer != null) {
    385             for (Geometry geom : geometries) {
    386                 geom.getMesh().setBuffer(uvCoordsBuffer);
    387             }
    388         } else {
    389             Map<Material, List<Geometry>> materialMap = new HashMap<Material, List<Geometry>>();
    390             for (Geometry geom : geometries) {
    391                 Material material = geom.getMaterial();
    392                 List<Geometry> geomsWithCommonMaterial = materialMap.get(material);
    393                 if (geomsWithCommonMaterial == null) {
    394                     geomsWithCommonMaterial = new ArrayList<Geometry>();
    395                     materialMap.put(material, geomsWithCommonMaterial);
    396                 }
    397                 geomsWithCommonMaterial.add(geom);
    398 
    399             }
    400             for (Entry<Material, List<Geometry>> entry : materialMap.entrySet()) {
    401                 MaterialContext materialContext = blenderContext.getMaterialContext(entry.getKey());
    402                 if (materialContext != null && materialContext.getTexturesCount() > 0) {
    403                     VertexBuffer coords = UVCoordinatesGenerator.generateUVCoordinates(materialContext.getUvCoordinatesType(),
    404                             materialContext.getProjectionType(), materialContext.getTextureDimension(),
    405                             materialContext.getProjection(0), entry.getValue());
    406                     //setting the coordinates inside the mesh context
    407                     for (Geometry geometry : entry.getValue()) {
    408                         meshContext.addUVCoordinates(geometry, coords);
    409                     }
    410                 }
    411             }
    412         }
    413 
    414         // if there are multiple materials used, extract the shared
    415         // vertex data
    416         if (geometries.size() > 1){
    417             // extract from itself
    418             for (Geometry geom : geometries){
    419                 geom.getMesh().extractVertexData(geom.getMesh());
    420             }
    421         }
    422 
    423         blenderContext.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);
    424         blenderContext.setMeshContext(structure.getOldMemoryAddress(), meshContext);
    425         return geometries;
    426     }
    427 
    428     /**
    429      * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.
    430      *
    431      * @param normalToAdd
    432      *            a normal to be added
    433      * @param normalMap
    434      *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector
    435      * @param smooth
    436      *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not
    437      * @param vertices
    438      *            a list of vertices read from the blender file
    439      */
    440     public void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {
    441         for (Vector3f v : vertices) {
    442             Vector3f n = normalMap.get(v);
    443             if (!smooth || n == null) {
    444                 normalMap.put(v, normalToAdd.clone());
    445             } else {
    446                 n.addLocal(normalToAdd).normalizeLocal();
    447             }
    448         }
    449     }
    450 
    451     /**
    452      * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created
    453      * to tell where the basic vertices are referenced in the result vertex lists. The key of the map is the basic vertex index, and its key
    454      * - the reference indices list.
    455      *
    456      * @param basicVertexIndex
    457      *            the index of the vertex from its basic table
    458      * @param resultIndex
    459      *            the index of the vertex in its result vertex list
    460      * @param vertexReferenceMap
    461      *            the reference map
    462      */
    463     protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {
    464         List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));
    465         if (referenceList == null) {
    466             referenceList = new ArrayList<Integer>();
    467             vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);
    468         }
    469         referenceList.add(Integer.valueOf(resultIndex));
    470     }
    471 
    472     /**
    473      * This method returns the vertices colors. Each vertex is stored in byte[4] array.
    474      *
    475      * @param meshStructure
    476      *            the structure containing the mesh data
    477      * @param blenderContext
    478      *            the blender context
    479      * @return a list of vertices colors, each color belongs to a single vertex
    480      * @throws BlenderFileException
    481      *             this exception is thrown when the blend file structure is somehow invalid or corrupted
    482      */
    483     public List<byte[]> getVerticesColors(Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
    484         Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");
    485         List<byte[]> verticesColors = null;
    486         List<Structure> mCol = null;
    487         if (pMCol.isNotNull()) {
    488             verticesColors = new LinkedList<byte[]>();
    489             mCol = pMCol.fetchData(blenderContext.getInputStream());
    490             for (Structure color : mCol) {
    491                 byte r = ((Number)color.getFieldValue("r")).byteValue();
    492                 byte g = ((Number)color.getFieldValue("g")).byteValue();
    493                 byte b = ((Number)color.getFieldValue("b")).byteValue();
    494                 byte a = ((Number)color.getFieldValue("a")).byteValue();
    495                 verticesColors.add(new byte[]{b, g, r, a});
    496             }
    497         }
    498         return verticesColors;
    499     }
    500 
    501     /**
    502      * This method returns the vertices.
    503      *
    504      * @param meshStructure
    505      *            the structure containing the mesh data
    506      * @param blenderContext
    507      *            the blender context
    508      * @return a list of vertices colors, each color belongs to a single vertex
    509      * @throws BlenderFileException
    510      *             this exception is thrown when the blend file structure is somehow invalid or corrupted
    511      */
    512     @SuppressWarnings("unchecked")
    513     private Vector3f[] getVertices(Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
    514         int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();
    515         Vector3f[] vertices = new Vector3f[verticesAmount];
    516         if (verticesAmount == 0) {
    517             return vertices;
    518         }
    519 
    520         Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");
    521         List<Structure> mVerts = pMVert.fetchData(blenderContext.getInputStream());
    522         if(this.fixUpAxis) {
    523         	for (int i = 0; i < verticesAmount; ++i) {
    524                 DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");
    525                 vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(2).floatValue(), -coordinates.get(1).floatValue());
    526             }
    527         } else {
    528         	for (int i = 0; i < verticesAmount; ++i) {
    529                 DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");
    530                 vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());
    531             }
    532         }
    533         return vertices;
    534     }
    535 
    536     @Override
    537     public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
    538         return true;
    539     }
    540 }
    541