blob: 7f9e8acf49b6852207c419acde05523dfe05636e [file] [log] [blame]
Scott Barta59b2e682012-03-01 12:35:35 -08001/*
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 */
32package com.jme3.scene.plugins.blender.meshes;
33
Scott Bartaa6b44652012-03-09 13:52:20 -080034import java.nio.ByteBuffer;
35import java.util.ArrayList;
36import java.util.HashMap;
37import java.util.LinkedList;
38import java.util.List;
39import java.util.Map;
40import java.util.Map.Entry;
41
Scott Barta59b2e682012-03-01 12:35:35 -080042import com.jme3.asset.BlenderKey.FeaturesToLoad;
43import com.jme3.material.Material;
44import com.jme3.math.FastMath;
45import com.jme3.math.Vector2f;
46import com.jme3.math.Vector3f;
47import com.jme3.renderer.queue.RenderQueue.Bucket;
48import com.jme3.scene.Geometry;
49import com.jme3.scene.Mesh;
50import com.jme3.scene.VertexBuffer;
51import com.jme3.scene.VertexBuffer.Format;
52import com.jme3.scene.VertexBuffer.Type;
53import com.jme3.scene.VertexBuffer.Usage;
54import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
55import com.jme3.scene.plugins.blender.BlenderContext;
56import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
57import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
58import com.jme3.scene.plugins.blender.file.DynamicArray;
59import com.jme3.scene.plugins.blender.file.Pointer;
60import com.jme3.scene.plugins.blender.file.Structure;
61import com.jme3.scene.plugins.blender.materials.MaterialContext;
62import com.jme3.scene.plugins.blender.materials.MaterialHelper;
63import com.jme3.scene.plugins.blender.objects.Properties;
64import com.jme3.scene.plugins.blender.textures.TextureHelper;
65import com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator;
66import com.jme3.texture.Texture;
67import com.jme3.util.BufferUtils;
Scott Barta59b2e682012-03-01 12:35:35 -080068
69/**
70 * A class that is used in mesh calculations.
71 *
72 * @author Marcin Roguski (Kaelthas)
73 */
74public 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);
Scott Bartaa6b44652012-03-09 13:52:20 -0800307 verticesAmount = vertexList.size();
Scott Barta59b2e682012-03-01 12:35:35 -0800308 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();
Scott Bartaa6b44652012-03-09 13:52:20 -0800313 if(verticesAmount <= Short.MAX_VALUE) {
Scott Barta59b2e682012-03-01 12:35:35 -0800314 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}