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