diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshBuilder.java b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshBuilder.java index 51f093fcf..65025c7ab 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshBuilder.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshBuilder.java @@ -259,6 +259,13 @@ import com.jme3.util.BufferUtils; return uvCoordinates.size() > 0; } + /** + * @return true if the mesh has no vertices and false otherwise + */ + public boolean isEmpty() { + return vertexMap.size() == 0; + } + /** * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth. * diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java index 152d80445..1b4ca6fbc 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java @@ -112,59 +112,18 @@ public class MeshHelper extends AbstractBlenderHelper { MeshBuilder meshBuilder = new MeshBuilder(vertices, verticesColors, this.areGeneratedTexturesPresent(materials)); Pointer pMFace = (Pointer) structure.getFieldValue("mface"); - List mFaces = null; - if (pMFace.isNotNull()) { - mFaces = pMFace.fetchData(blenderContext.getInputStream()); - if (mFaces == null || mFaces.size() == 0) { - return new ArrayList(0); - } - } else{ - mFaces = new ArrayList(0); - } - - Pointer pMTFace = (Pointer) structure.getFieldValue("mtface"); - List mtFaces = null; - - if (pMTFace.isNotNull()) { - mtFaces = pMTFace.fetchData(blenderContext.getInputStream()); - int facesAmount = ((Number) structure.getFieldValue("totface")).intValue(); - if (mtFaces.size() != facesAmount) { - throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!"); - } + if(pMFace.isNotNull()) { + this.readTraditionalFaces(meshBuilder, structure, blenderContext); + } else { + this.readBMesh(meshBuilder, structure, blenderContext); } - - // indicates if the material with the specified number should have a texture attached - Vector2f[] uvCoordinatesForFace = new Vector2f[3]; - 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 uvs = null; - - if (mtFaces != null) { - Structure mtFace = mtFaces.get(i); - // uvs always must be added wheater we have texture or not - uvs = (DynamicArray) 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()); - } - - int v1 = ((Number) mFace.getFieldValue("v1")).intValue(); - int v2 = ((Number) mFace.getFieldValue("v2")).intValue(); - int v3 = ((Number) mFace.getFieldValue("v3")).intValue(); - int v4 = ((Number) mFace.getFieldValue("v4")).intValue(); - - meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i); - 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()); - } - meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i); - } + if(meshBuilder.isEmpty()) { + geometries = new ArrayList(0); + blenderContext.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries); + blenderContext.setMeshContext(structure.getOldMemoryAddress(), meshContext); + return geometries; } + meshContext.setVertexReferenceMap(meshBuilder.getVertexReferenceMap()); // reading vertices groups (from the parent) @@ -275,6 +234,136 @@ public class MeshHelper extends AbstractBlenderHelper { return geometries; } + + /** + * This method reads the mesh from the new BMesh system. + * + * @param meshBuilder + * the mesh builder + * @param meshStructure + * the mesh structure + * @param blenderContext + * the blender context + * @throws BlenderFileException + * 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]; + + if (pMPoly.isNotNull() && pMLoop.isNotNull() && pMEdge.isNotNull()) { + int faceIndex = 0; + List polys = pMPoly.fetchData(blenderContext.getInputStream()); + List loops = pMLoop.fetchData(blenderContext.getInputStream()); + List 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 loopUVS = (DynamicArray) loopuvs.get(i).getFieldValue("uv"); + uvs[i - loopStart] = new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue()); + } + } + + int i = 0; + while (i < totLoop - 2) { + int v1 = vertexIndexes[0]; + 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]; + } + + meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, faceIndex); + + ++i; + } + ++faceIndex; + } + } + } + + /** + * This method reads the mesh from traditional triangle/quad storing + * structures. + * + * @param meshBuilder + * the mesh builder + * @param meshStructure + * the mesh structure + * @param blenderContext + * the blender context + * @throws BlenderFileException + * 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 mFaces = pMFace.fetchData(blenderContext.getInputStream()); + if (mFaces != null && mFaces.size() > 0) { + Pointer pMTFace = (Pointer) meshStructure.getFieldValue("mtface"); + List 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]; + 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 uvs = null; + + if (mtFaces != null) { + Structure mtFace = mtFaces.get(i); + // uvs always must be added wheater we have texture or not + uvs = (DynamicArray) 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()); + } + + int v1 = ((Number) mFace.getFieldValue("v1")).intValue(); + int v2 = ((Number) mFace.getFieldValue("v2")).intValue(); + int v3 = ((Number) mFace.getFieldValue("v3")).intValue(); + int v4 = ((Number) mFace.getFieldValue("v4")).intValue(); + + meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i); + 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()); + } + meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i); + } + } + } + } /** * @return true if the material has at least one generated component and false otherwise