diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java index 8c4980411..665c36a99 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java @@ -37,10 +37,6 @@ import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.objects.Properties; -import com.jme3.util.BufferUtils; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.util.List; /** * A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can @@ -95,50 +91,6 @@ public abstract class AbstractBlenderHelper { return true; } - /** - * Generate a new ByteBuffer using the given array of byte[4] objects. The ByteBuffer will be 4 * data.length - * long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc. - * @param data - * list of byte[4] objects to place into a new ByteBuffer - */ - protected ByteBuffer createByteBuffer(List data) { - if (data == null) { - return null; - } - ByteBuffer buff = BufferUtils.createByteBuffer(4 * data.size()); - for (byte[] v : data) { - if (v != null) { - buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]); - } else { - buff.put((byte)0).put((byte)0).put((byte)0).put((byte)0); - } - } - buff.flip(); - return buff; - } - - /** - * Generate a new FloatBuffer using the given array of float[4] objects. The FloatBuffer will be 4 * data.length - * long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc. - * @param data - * list of float[4] objects to place into a new FloatBuffer - */ - protected FloatBuffer createFloatBuffer(List data) { - if (data == null) { - return null; - } - FloatBuffer buff = BufferUtils.createFloatBuffer(4 * data.size()); - for (float[] v : data) { - if (v != null) { - buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]); - } else { - buff.put(0).put(0).put(0).put(0); - } - } - buff.flip(); - return buff; - } - /** * This method loads the properties if they are available and defined for the structure. * @param structure 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 d5afc8b19..51f093fcf 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 @@ -1,5 +1,6 @@ package com.jme3.scene.plugins.blender.meshes; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -8,10 +9,13 @@ import java.util.Map; import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; +import com.jme3.util.BufferUtils; /*package*/ class MeshBuilder { /** An array of reference vertices. */ private Vector3f[] vertices; + /** An list of vertices colors. */ + private List verticesColors; /** A variable that indicates if the model uses generated textures. */ private boolean usesGeneratedTextures; @@ -27,6 +31,8 @@ import com.jme3.math.Vector3f; private Map> normalMap = new HashMap>(); /** The following map sorts vertices by material number (because in jme Mesh can have only one material). */ private Map> vertexMap = new HashMap>(); + /** The following map sorts vertices colors by material number (because in jme Mesh can have only one material). */ + private Map> vertexColorsMap = new HashMap>(); /** The following map sorts indexes by material number (because in jme Mesh can have only one material). */ private Map> indexMap = new HashMap>(); /** A map between material number and UV coordinates of mesh that has this material applied. */ @@ -39,11 +45,12 @@ import com.jme3.math.Vector3f; * @param vertices the reference vertices array * @param usesGeneratedTextures a variable that indicates if the model uses generated textures or not */ - public MeshBuilder(Vector3f[] vertices, boolean usesGeneratedTextures) { + public MeshBuilder(Vector3f[] vertices, List verticesColors, boolean usesGeneratedTextures) { if(vertices == null || vertices.length == 0) { throw new IllegalArgumentException("No vertices loaded to build mesh."); } this.vertices = vertices; + this.verticesColors = verticesColors; this.usesGeneratedTextures = usesGeneratedTextures; globalVertexReferenceMap = new HashMap>>(vertices.length); } @@ -56,11 +63,15 @@ import com.jme3.math.Vector3f; * @param smooth 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 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) { + 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!"); } + + //getting the required lists List indexList = indexMap.get(materialNumber); if (indexList == null) { indexList = new ArrayList(); @@ -71,6 +82,12 @@ import com.jme3.math.Vector3f; vertexList = new ArrayList(); vertexMap.put(materialNumber, vertexList); } + List vertexColorsList = vertexColorsMap != null ? vertexColorsMap.get(materialNumber) : null; + int[] vertexColorIndex = new int[] { 0, 1, 2 }; + if(vertexColorsList == null && vertexColorsMap != null) { + vertexColorsList = new ArrayList(); + vertexColorsMap.put(materialNumber, vertexColorsList); + } List normalList = normalMap.get(materialNumber); if (normalList == null) { normalList = new ArrayList(); @@ -81,7 +98,6 @@ import com.jme3.math.Vector3f; vertexReferenceMap = new HashMap>(); globalVertexReferenceMap.put(materialNumber, vertexReferenceMap); } - List uvCoordinatesList = null; if(uvs != null) { uvCoordinatesList = uvCoordinates.get(Integer.valueOf(materialNumber)); @@ -91,6 +107,13 @@ import com.jme3.math.Vector3f; } } + faceIndex *= 4; + if(quad) { + vertexColorIndex[1] = 2; + vertexColorIndex[2] = 3; + } + + //creating faces Integer[] index = new Integer[] {v1, v2, v3}; Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]); this.addNormal(n, globalNormalMap, smooth, vertices[v1], vertices[v2], vertices[v3]); @@ -99,6 +122,9 @@ import com.jme3.math.Vector3f; if(!vertexReferenceMap.containsKey(index[i])) { this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap); vertexList.add(vertices[index[i]]); + if(verticesColors != null) { + vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i])); + } normalList.add(globalNormalMap.get(vertices[index[i]])); if(uvCoordinatesList != null) { uvsMap.put(vertexList.size(), uvs[i]); @@ -118,6 +144,9 @@ import com.jme3.math.Vector3f; this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap); uvsMap.put(vertexList.size(), uvs[i]); vertexList.add(vertices[index[i]]); + if(verticesColors != null) { + vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i])); + } normalList.add(globalNormalMap.get(vertices[index[i]])); uvCoordinatesList.add(uvs[i]); index[i] = vertexList.size() - 1; @@ -136,6 +165,9 @@ import com.jme3.math.Vector3f; uvsMap.put(vertexList.size(), uvs[i]); } vertexList.add(vertices[index[i]]); + if(verticesColors != null) { + vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i])); + } normalList.add(globalNormalMap.get(vertices[index[i]])); } } @@ -149,6 +181,8 @@ import com.jme3.math.Vector3f; } /** + * @param materialNumber + * the material index * @return result vertices array */ public Vector3f[] getVertices(int materialNumber) { @@ -156,6 +190,8 @@ import com.jme3.math.Vector3f; } /** + * @param materialNumber + * the material index * @return the amount of result vertices */ public int getVerticesAmount(int materialNumber) { @@ -163,12 +199,36 @@ import com.jme3.math.Vector3f; } /** + * @param materialNumber + * the material index * @return normals result array */ public Vector3f[] getNormals(int materialNumber) { return normalMap.get(materialNumber).toArray(new Vector3f[normalMap.get(materialNumber).size()]); } + /** + * @param materialNumber + * the material index + * @return the vertices colors buffer or null if no vertex colors is set + */ + public ByteBuffer getVertexColorsBuffer(int materialNumber) { + ByteBuffer result = null; + if (verticesColors != null && vertexColorsMap.get(materialNumber) != null) { + List data = vertexColorsMap.get(materialNumber); + result = BufferUtils.createByteBuffer(4 * data.size()); + for (byte[] v : data) { + if (v != null) { + result.put(v[0]).put(v[1]).put(v[2]).put(v[3]); + } else { + result.put((byte)0).put((byte)0).put((byte)0).put((byte)0); + } + } + result.flip(); + } + return result; + } + /** * @return a map between material number and the mesh part vertices indices */ @@ -184,7 +244,8 @@ import com.jme3.math.Vector3f; } /** - * @param materialNumber the material number that is appied to the mesh + * @param materialNumber + * the material number that is appied to the mesh * @return UV coordinates of vertices that belong to the required mesh part */ public List getUVCoordinates(int materialNumber) { 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 6ffcdf5d1..152d80445 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 @@ -31,9 +31,7 @@ */ package com.jme3.scene.plugins.blender.meshes; -import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; @@ -87,8 +85,7 @@ public class MeshHelper extends AbstractBlenderHelper { */ @SuppressWarnings("unchecked") public List toMesh(Structure structure, BlenderContext blenderContext) throws BlenderFileException { - List geometries = (List) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), - LoadedFeatureDataType.LOADED_FEATURE); + List geometries = (List) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE); if (geometries != null) { List copiedGeometries = new ArrayList(geometries.size()); for (Geometry geometry : geometries) { @@ -108,12 +105,11 @@ public class MeshHelper extends AbstractBlenderHelper { materials = materialHelper.getMaterials(structure, blenderContext); } - // reading vertices + // reading vertices and their colors Vector3f[] vertices = this.getVertices(structure, blenderContext); - MeshBuilder meshBuilder = new MeshBuilder(vertices, this.areGeneratedTexturesPresent(materials)); - - // vertices Colors List verticesColors = this.getVerticesColors(structure, blenderContext); + + MeshBuilder meshBuilder = new MeshBuilder(vertices, verticesColors, this.areGeneratedTexturesPresent(materials)); Pointer pMFace = (Pointer) structure.getFieldValue("mface"); List mFaces = null; @@ -138,7 +134,6 @@ public class MeshHelper extends AbstractBlenderHelper { } // indicates if the material with the specified number should have a texture attached - int vertexColorIndex = 0; Vector2f[] uvCoordinatesForFace = new Vector2f[3]; for (int i = 0; i < mFaces.size(); ++i) { Structure mFace = mFaces.get(i); @@ -160,25 +155,14 @@ public class MeshHelper extends AbstractBlenderHelper { 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); + 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); - - if (verticesColors != null) { - verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex)); - verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2)); - } - vertexColorIndex += 6; - } else { - if (verticesColors != null) { - verticesColors.remove(vertexColorIndex + 3); - vertexColorIndex += 3; - } + meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i); } } meshContext.setVertexReferenceMap(meshBuilder.getVertexReferenceMap()); @@ -200,7 +184,6 @@ public class MeshHelper extends AbstractBlenderHelper { Properties properties = this.loadProperties(structure, blenderContext); // generating meshes - ByteBuffer verticesColorsBuffer = this.createByteBuffer(verticesColors); for (Entry> meshEntry : meshBuilder.getMeshesMap().entrySet()) { int materialIndex = meshEntry.getKey(); //key is the material index (or -1 if the material has no texture) @@ -241,8 +224,8 @@ public class MeshHelper extends AbstractBlenderHelper { meshContext.setBindPoseBuffer(verticesBind);//this is stored in the context and applied when needed (when animation is applied to the mesh) // setting vertices colors - if (verticesColorsBuffer != null) { - mesh.setBuffer(Type.Color, 4, verticesColorsBuffer); + if (verticesColors != null) { + mesh.setBuffer(Type.Color, 4, meshBuilder.getVertexColorsBuffer(materialIndex)); mesh.getBuffer(Type.Color).setNormalized(true); } @@ -323,7 +306,7 @@ public class MeshHelper extends AbstractBlenderHelper { List verticesColors = null; List mCol = null; if (pMCol.isNotNull()) { - verticesColors = new LinkedList(); + verticesColors = new ArrayList(); mCol = pMCol.fetchData(blenderContext.getInputStream()); for (Structure color : mCol) { byte r = ((Number)color.getFieldValue("r")).byteValue();