|
|
@@ -31,8 +31,15 @@
|
|
|
*/
|
|
|
package com.jme3.scene.plugins.blender.meshes;
|
|
|
|
|
|
+import java.nio.ByteBuffer;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.LinkedList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Map.Entry;
|
|
|
+
|
|
|
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
|
|
-import com.jme3.math.FastMath;
|
|
|
import com.jme3.math.Vector2f;
|
|
|
import com.jme3.math.Vector3f;
|
|
|
import com.jme3.scene.Geometry;
|
|
|
@@ -54,13 +61,6 @@ import com.jme3.scene.plugins.blender.objects.Properties;
|
|
|
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
|
|
import com.jme3.texture.Texture;
|
|
|
import com.jme3.util.BufferUtils;
|
|
|
-import java.nio.ByteBuffer;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.LinkedList;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Map.Entry;
|
|
|
|
|
|
/**
|
|
|
* A class that is used in mesh calculations.
|
|
|
@@ -109,16 +109,20 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
String name = structure.getName();
|
|
|
MeshContext meshContext = new MeshContext();
|
|
|
|
|
|
+ // reading materials
|
|
|
+ MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
|
|
+ MaterialContext[] materials = null;
|
|
|
+ if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
|
|
|
+ materials = materialHelper.getMaterials(structure, blenderContext);
|
|
|
+ }
|
|
|
+
|
|
|
// reading vertices
|
|
|
Vector3f[] vertices = this.getVertices(structure, blenderContext);
|
|
|
- int verticesAmount = vertices.length;
|
|
|
-
|
|
|
+ MeshBuilder meshBuilder = new MeshBuilder(vertices, this.areGeneratedTexturesPresent(materials));
|
|
|
+
|
|
|
// vertices Colors
|
|
|
List<byte[]> verticesColors = this.getVerticesColors(structure, blenderContext);
|
|
|
|
|
|
- // reading faces
|
|
|
- // the following map sorts faces by material number (because in jme Mesh can have only one material)
|
|
|
- Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();
|
|
|
Pointer pMFace = (Pointer) structure.getFieldValue("mface");
|
|
|
List<Structure> mFaces = null;
|
|
|
if (pMFace.isNotNull()) {
|
|
|
@@ -131,7 +135,6 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
}
|
|
|
|
|
|
Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");
|
|
|
- Map<Integer, List<Vector2f>> uvCoordinates = new HashMap<Integer, List<Vector2f>>();//<material_number; list of uv coordinates for mesh's vertices>
|
|
|
List<Structure> mtFaces = null;
|
|
|
|
|
|
if (pMTFace.isNotNull()) {
|
|
|
@@ -142,17 +145,10 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // normalMap merges normals of faces that will be rendered smooth
|
|
|
- Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);
|
|
|
-
|
|
|
- List<Vector3f> normalList = new ArrayList<Vector3f>();
|
|
|
- List<Vector3f> vertexList = new ArrayList<Vector3f>();
|
|
|
// indicates if the material with the specified number should have a texture attached
|
|
|
Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();
|
|
|
- // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
|
|
|
- // positions (it simply tells which vertex is referenced where in the result list)
|
|
|
- Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);
|
|
|
int vertexColorIndex = 0;
|
|
|
+ Vector2f[] uvCoordinatesForFace = new Vector2f[3];
|
|
|
for (int i = 0; i < mFaces.size(); ++i) {
|
|
|
Structure mFace = mFaces.get(i);
|
|
|
int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();
|
|
|
@@ -161,28 +157,17 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
boolean materialWithoutTextures = false;
|
|
|
Pointer pImage = null;
|
|
|
|
|
|
- List<Vector2f> uvCoordinatesList = uvCoordinates.get(Integer.valueOf(matNr));
|
|
|
- if(uvCoordinatesList == null) {
|
|
|
- uvCoordinatesList = new ArrayList<Vector2f>();
|
|
|
- uvCoordinates.put(Integer.valueOf(matNr), uvCoordinatesList);
|
|
|
- }
|
|
|
-
|
|
|
if (mtFaces != null) {
|
|
|
Structure mtFace = mtFaces.get(i);
|
|
|
pImage = (Pointer) mtFace.getFieldValue("tpage");
|
|
|
materialWithoutTextures = pImage.isNull();
|
|
|
// uvs always must be added wheater we have texture or not
|
|
|
uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
|
|
|
- uvCoordinatesList.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
|
|
|
- uvCoordinatesList.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));
|
|
|
- uvCoordinatesList.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
|
|
|
+ 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());
|
|
|
}
|
|
|
Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);
|
|
|
- List<Integer> indexList = meshesMap.get(materialNumber);
|
|
|
- if (indexList == null) {
|
|
|
- indexList = new ArrayList<Integer>();
|
|
|
- meshesMap.put(materialNumber, indexList);
|
|
|
- }
|
|
|
|
|
|
// attaching image to texture (face can have UV's and image whlie its material may have no texture attached)
|
|
|
if (pImage != null && pImage.isNotNull() && !materialNumberToTexture.containsKey(materialNumber)) {
|
|
|
@@ -198,46 +183,14 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
|
|
|
int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
|
|
|
|
|
|
- Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);
|
|
|
- this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);
|
|
|
- normalList.add(normalMap.get(vertices[v1]));
|
|
|
- normalList.add(normalMap.get(vertices[v2]));
|
|
|
- normalList.add(normalMap.get(vertices[v3]));
|
|
|
-
|
|
|
- this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
|
|
|
- indexList.add(vertexList.size());
|
|
|
- vertexList.add(vertices[v1]);
|
|
|
-
|
|
|
- this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);
|
|
|
- indexList.add(vertexList.size());
|
|
|
- vertexList.add(vertices[v2]);
|
|
|
-
|
|
|
- this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
|
|
|
- indexList.add(vertexList.size());
|
|
|
- vertexList.add(vertices[v3]);
|
|
|
-
|
|
|
+ meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace);
|
|
|
if (v4 > 0) {
|
|
|
if (uvs != null) {
|
|
|
- uvCoordinatesList.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
|
|
|
- uvCoordinatesList.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
|
|
|
- uvCoordinatesList.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));
|
|
|
+ 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());
|
|
|
}
|
|
|
- this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
|
|
|
- indexList.add(vertexList.size());
|
|
|
- vertexList.add(vertices[v1]);
|
|
|
-
|
|
|
- this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
|
|
|
- indexList.add(vertexList.size());
|
|
|
- vertexList.add(vertices[v3]);
|
|
|
-
|
|
|
- this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);
|
|
|
- indexList.add(vertexList.size());
|
|
|
- vertexList.add(vertices[v4]);
|
|
|
-
|
|
|
- this.addNormal(n, normalMap, smooth, vertices[v4]);
|
|
|
- normalList.add(normalMap.get(vertices[v1]));
|
|
|
- normalList.add(normalMap.get(vertices[v3]));
|
|
|
- normalList.add(normalMap.get(vertices[v4]));
|
|
|
+ meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace);
|
|
|
|
|
|
if (verticesColors != null) {
|
|
|
verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));
|
|
|
@@ -251,10 +204,7 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- meshContext.setVertexList(vertexList);
|
|
|
- meshContext.setVertexReferenceMap(vertexReferenceMap);
|
|
|
-
|
|
|
- Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);
|
|
|
+ meshContext.setVertexReferenceMap(meshBuilder.getVertexReferenceMap());
|
|
|
|
|
|
// reading vertices groups (from the parent)
|
|
|
Structure parent = blenderContext.peekParent();
|
|
|
@@ -266,48 +216,23 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
verticesGroups[defIndex++] = def.getFieldValue("name").toString();
|
|
|
}
|
|
|
|
|
|
- // reading materials
|
|
|
- MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
|
|
- MaterialContext[] materials = null;
|
|
|
- if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
|
|
|
- materials = materialHelper.getMaterials(structure, blenderContext);
|
|
|
- }
|
|
|
-
|
|
|
// creating the result meshes
|
|
|
- geometries = new ArrayList<Geometry>(meshesMap.size());
|
|
|
-
|
|
|
- VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);
|
|
|
- verticesBuffer.setupData(Usage.Static, 3, Format.Float,
|
|
|
- BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));
|
|
|
-
|
|
|
- // initial vertex position (used with animation)
|
|
|
- VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);
|
|
|
- verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));
|
|
|
-
|
|
|
- VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);
|
|
|
- normalsBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(normals));
|
|
|
-
|
|
|
- // initial normals position (used with animation)
|
|
|
- VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);
|
|
|
- normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));
|
|
|
+ geometries = new ArrayList<Geometry>(meshBuilder.getMeshesPartAmount());
|
|
|
|
|
|
//reading custom properties
|
|
|
Properties properties = this.loadProperties(structure, blenderContext);
|
|
|
|
|
|
// generating meshes
|
|
|
- //FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);
|
|
|
ByteBuffer verticesColorsBuffer = this.createByteBuffer(verticesColors);
|
|
|
- verticesAmount = vertexList.size();
|
|
|
- Map<Mesh, Integer> meshToMAterialMap = new HashMap<Mesh, Integer>(meshesMap.size());
|
|
|
- for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {
|
|
|
+ for (Entry<Integer, List<Integer>> meshEntry : meshBuilder.getMeshesMap().entrySet()) {
|
|
|
+ int materialIndex = meshEntry.getKey();
|
|
|
//key is the material index (or -1 if the material has no texture)
|
|
|
//value is a list of vertex indices
|
|
|
Mesh mesh = new Mesh();
|
|
|
- meshToMAterialMap.put(mesh, meshEntry.getKey());
|
|
|
|
|
|
// creating vertices indices for this mesh
|
|
|
List<Integer> indexList = meshEntry.getValue();
|
|
|
- if(verticesAmount <= Short.MAX_VALUE) {
|
|
|
+ if(meshBuilder.getVerticesAmount(materialIndex) <= Short.MAX_VALUE) {
|
|
|
short[] indices = new short[indexList.size()];
|
|
|
for (int i = 0; i < indexList.size(); ++i) {
|
|
|
indices[i] = indexList.get(i).shortValue();
|
|
|
@@ -321,6 +246,20 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
mesh.setBuffer(Type.Index, 1, indices);
|
|
|
}
|
|
|
|
|
|
+ VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);
|
|
|
+ verticesBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(meshBuilder.getVertices(materialIndex)));
|
|
|
+
|
|
|
+ // initial vertex position (used with animation)
|
|
|
+ VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);
|
|
|
+ verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));
|
|
|
+
|
|
|
+ VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);
|
|
|
+ normalsBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(meshBuilder.getNormals(materialIndex)));
|
|
|
+
|
|
|
+ // initial normals position (used with animation)
|
|
|
+ VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);
|
|
|
+ normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));
|
|
|
+
|
|
|
mesh.setBuffer(verticesBuffer);
|
|
|
meshContext.setBindPoseBuffer(verticesBind);//this is stored in the context and applied when needed (when animation is applied to the mesh)
|
|
|
|
|
|
@@ -340,6 +279,7 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
geometry.setUserData("properties", properties);
|
|
|
}
|
|
|
geometries.add(geometry);
|
|
|
+ meshContext.putGeometry(materialIndex, geometry);
|
|
|
}
|
|
|
|
|
|
//store the data in blender context before applying the material
|
|
|
@@ -349,20 +289,30 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
//apply materials only when all geometries are in place
|
|
|
if(materials != null) {
|
|
|
for(Geometry geometry : geometries) {
|
|
|
- int materialNumber = meshToMAterialMap.get(geometry.getMesh()).intValue();
|
|
|
+ int materialNumber = meshContext.getMaterialIndex(geometry);
|
|
|
+ List<Vector2f> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
|
|
|
boolean noTextures = false;
|
|
|
if(materialNumber < 0) {
|
|
|
materialNumber = -1 * (materialNumber + 1);
|
|
|
noTextures = true;
|
|
|
}
|
|
|
- MaterialContext materialContext = materials[materialNumber];
|
|
|
- materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), noTextures, uvCoordinates.get(Integer.valueOf(materialNumber)), blenderContext);
|
|
|
+ if(materials[materialNumber] != null) {
|
|
|
+ MaterialContext materialContext = materials[materialNumber];
|
|
|
+ materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), noTextures, uvCoordinates, blenderContext);
|
|
|
+ } else {
|
|
|
+ geometry.setMaterial(blenderContext.getDefaultMaterial());
|
|
|
+ if(uvCoordinates != null) {
|
|
|
+ VertexBuffer uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
|
|
|
+ uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));
|
|
|
+ geometry.getMesh().setBuffer(uvCoordsBuffer);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
//add UV coordinates if they are defined even if the material is not applied to the model
|
|
|
VertexBuffer uvCoordsBuffer = null;
|
|
|
- if(uvCoordinates.size() > 0) {
|
|
|
- List<Vector2f> uvs = uvCoordinates.get(0);
|
|
|
+ if(meshBuilder.hasUVCoordinates()) {
|
|
|
+ List<Vector2f> uvs = meshBuilder.getUVCoordinates(-1);
|
|
|
uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
|
|
|
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
|
|
|
}
|
|
|
@@ -375,62 +325,23 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // if there are multiple materials used, extract the shared
|
|
|
- // vertex data
|
|
|
- if (geometries.size() > 1){
|
|
|
- // extract from itself
|
|
|
- for (Geometry geom : geometries){
|
|
|
- geom.getMesh().extractVertexData(geom.getMesh());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
return geometries;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.
|
|
|
- *
|
|
|
- * @param normalToAdd
|
|
|
- * a normal to be added
|
|
|
- * @param normalMap
|
|
|
- * merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector
|
|
|
- * @param smooth
|
|
|
- * the variable that indicates wheather to merge normals (creating the smooth mesh) or not
|
|
|
- * @param vertices
|
|
|
- * a list of vertices read from the blender file
|
|
|
- */
|
|
|
- public void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {
|
|
|
- for (Vector3f v : vertices) {
|
|
|
- Vector3f n = normalMap.get(v);
|
|
|
- if (!smooth || n == null) {
|
|
|
- normalMap.put(v, normalToAdd.clone());
|
|
|
- } else {
|
|
|
- n.addLocal(normalToAdd).normalizeLocal();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created
|
|
|
- * 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
|
|
|
- * - the reference indices list.
|
|
|
- *
|
|
|
- * @param basicVertexIndex
|
|
|
- * the index of the vertex from its basic table
|
|
|
- * @param resultIndex
|
|
|
- * the index of the vertex in its result vertex list
|
|
|
- * @param vertexReferenceMap
|
|
|
- * the reference map
|
|
|
- */
|
|
|
- protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {
|
|
|
- List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));
|
|
|
- if (referenceList == null) {
|
|
|
- referenceList = new ArrayList<Integer>();
|
|
|
- vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);
|
|
|
- }
|
|
|
- referenceList.add(Integer.valueOf(resultIndex));
|
|
|
+ * @return <b>true</b> if the material has at least one generated component and <b>false</b> otherwise
|
|
|
+ */
|
|
|
+ private boolean areGeneratedTexturesPresent(MaterialContext[] materials) {
|
|
|
+ if(materials != null) {
|
|
|
+ for(MaterialContext material : materials) {
|
|
|
+ if(material != null && material.hasGeneratedTextures()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* This method returns the vertices colors. Each vertex is stored in byte[4] array.
|
|
|
*
|