git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10914 75d07b2b-3a1a-0410-a2c5-0572b91ccdcaexperimental
parent
69e4392ba9
commit
dd8b8fbd5f
@ -1,5 +1,163 @@ |
|||||||
package com.jme3.scene.plugins.blender.meshes.builders; |
package com.jme3.scene.plugins.blender.meshes.builders; |
||||||
|
|
||||||
/*package*/ class LineMeshBuilder { |
import java.util.ArrayList; |
||||||
//TODO: this will be implemented soon
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.scene.Mesh; |
||||||
|
import com.jme3.scene.Mesh.Mode; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.scene.VertexBuffer.Format; |
||||||
|
import com.jme3.scene.VertexBuffer.Type; |
||||||
|
import com.jme3.scene.VertexBuffer.Usage; |
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext; |
||||||
|
import com.jme3.scene.plugins.blender.file.BlenderFileException; |
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer; |
||||||
|
import com.jme3.scene.plugins.blender.file.Structure; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* A builder that creates a lines mesh. The result is made of lines that do not belong to any face. |
||||||
|
* |
||||||
|
* @author Marcin Roguski (Kaelthas) |
||||||
|
*/ |
||||||
|
/* package */class LineMeshBuilder { |
||||||
|
private static final Logger LOGGER = Logger.getLogger(LineMeshBuilder.class.getName()); |
||||||
|
|
||||||
|
private static final int EDGE_NOT_IN_FACE_FLAG = 0x80; |
||||||
|
|
||||||
|
/** An array of reference vertices. */ |
||||||
|
private Vector3f[][] verticesAndNormals; |
||||||
|
/** The vertices of the mesh. */ |
||||||
|
private List<Vector3f> vertices = new ArrayList<Vector3f>(); |
||||||
|
/** The normals of the mesh. */ |
||||||
|
private List<Vector3f> normals = new ArrayList<Vector3f>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 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). |
||||||
|
*/ |
||||||
|
private Map<Integer, List<Integer>> globalVertexReferenceMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Stores the given array (not copying it). |
||||||
|
* The second argument describes if the model uses generated textures. If yes then no vertex amount optimisation is applied. |
||||||
|
* The amount of vertices is always faceCount * 3. |
||||||
|
* @param verticesAndNormals |
||||||
|
* the reference vertices and normals array |
||||||
|
*/ |
||||||
|
public LineMeshBuilder(Vector3f[][] verticesAndNormals) { |
||||||
|
this.verticesAndNormals = verticesAndNormals; |
||||||
|
globalVertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAndNormals.length); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The method reads the mesh. It loads only edges that are marked as not belonging to any face in their flag field. |
||||||
|
* @param meshStructure |
||||||
|
* the mesh structure |
||||||
|
* @param blenderContext |
||||||
|
* the blender context |
||||||
|
* @throws BlenderFileException |
||||||
|
* an exception thrown when reading from the blend file fails |
||||||
|
*/ |
||||||
|
public void readMesh(Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException { |
||||||
|
LOGGER.fine("Reading line mesh."); |
||||||
|
Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge"); |
||||||
|
|
||||||
|
if (pMEdge.isNotNull()) { |
||||||
|
List<Structure> edges = pMEdge.fetchData(blenderContext.getInputStream()); |
||||||
|
int vertexIndex = 0;//vertex index in the result mesh
|
||||||
|
for (Structure edge : edges) { |
||||||
|
int flag = ((Number) edge.getFieldValue("flag")).intValue(); |
||||||
|
if ((flag & EDGE_NOT_IN_FACE_FLAG) != 0) { |
||||||
|
int v1 = ((Number) edge.getFieldValue("v1")).intValue(); |
||||||
|
int v2 = ((Number) edge.getFieldValue("v2")).intValue(); |
||||||
|
|
||||||
|
vertices.add(verticesAndNormals[v1][0]); |
||||||
|
normals.add(verticesAndNormals[v1][1]); |
||||||
|
this.appendVertexReference(v1, vertexIndex++, globalVertexReferenceMap); |
||||||
|
|
||||||
|
vertices.add(verticesAndNormals[v2][0]); |
||||||
|
normals.add(verticesAndNormals[v2][1]); |
||||||
|
this.appendVertexReference(v2, vertexIndex++, globalVertexReferenceMap); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds the meshes. |
||||||
|
* @return a map between material index and the mesh |
||||||
|
*/ |
||||||
|
public Map<Integer, Mesh> buildMeshes() { |
||||||
|
LOGGER.fine("Building line mesh."); |
||||||
|
Map<Integer, Mesh> result = new HashMap<Integer, Mesh>(1); |
||||||
|
if (vertices.size() > 0) { |
||||||
|
Mesh mesh = new Mesh(); |
||||||
|
mesh.setMode(Mode.Lines); |
||||||
|
|
||||||
|
LOGGER.fine("Creating indices buffer."); |
||||||
|
if (vertices.size() <= Short.MAX_VALUE) { |
||||||
|
short[] indices = new short[vertices.size()]; |
||||||
|
for (int i = 0; i < vertices.size(); ++i) { |
||||||
|
indices[i] = (short) i; |
||||||
|
} |
||||||
|
mesh.setBuffer(Type.Index, 1, indices); |
||||||
|
} else { |
||||||
|
int[] indices = new int[vertices.size()]; |
||||||
|
for (int i = 0; i < vertices.size(); ++i) { |
||||||
|
indices[i] = i; |
||||||
|
} |
||||||
|
mesh.setBuffer(Type.Index, 1, indices); |
||||||
|
} |
||||||
|
|
||||||
|
LOGGER.fine("Creating vertices buffer."); |
||||||
|
VertexBuffer verticesBuffer = new VertexBuffer(Type.Position); |
||||||
|
verticesBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(vertices.toArray(new Vector3f[vertices.size()]))); |
||||||
|
mesh.setBuffer(verticesBuffer); |
||||||
|
|
||||||
|
LOGGER.fine("Creating normals buffer (in case of lines it is required if skeleton is applied)."); |
||||||
|
VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal); |
||||||
|
normalsBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(normals.toArray(new Vector3f[normals.size()]))); |
||||||
|
mesh.setBuffer(normalsBuffer); |
||||||
|
|
||||||
|
result.put(-1, mesh); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return <b>true</b> if the mesh has no vertices and <b>false</b> otherwise |
||||||
|
*/ |
||||||
|
public boolean isEmpty() { |
||||||
|
return vertices == null; |
||||||
|
} |
||||||
|
|
||||||
|
public Map<Integer, List<Integer>> getGlobalVertexReferenceMap() { |
||||||
|
return globalVertexReferenceMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 |
||||||
|
*/ |
||||||
|
private 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)); |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -1,5 +1,174 @@ |
|||||||
package com.jme3.scene.plugins.blender.meshes.builders; |
package com.jme3.scene.plugins.blender.meshes.builders; |
||||||
|
|
||||||
/*package*/ class PointMeshBuilder { |
import java.util.ArrayList; |
||||||
//TODO: this will be implemented soon
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.scene.Mesh; |
||||||
|
import com.jme3.scene.Mesh.Mode; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.scene.VertexBuffer.Format; |
||||||
|
import com.jme3.scene.VertexBuffer.Type; |
||||||
|
import com.jme3.scene.VertexBuffer.Usage; |
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext; |
||||||
|
import com.jme3.scene.plugins.blender.file.BlenderFileException; |
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer; |
||||||
|
import com.jme3.scene.plugins.blender.file.Structure; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* A builder that creates a points mesh. The result is made of points that do not belong to any edge and face. |
||||||
|
* |
||||||
|
* @author Marcin Roguski (Kaelthas) |
||||||
|
*/ |
||||||
|
/* package */class PointMeshBuilder { |
||||||
|
private static final Logger LOGGER = Logger.getLogger(PointMeshBuilder.class.getName()); |
||||||
|
|
||||||
|
/** An array of reference vertices. */ |
||||||
|
private Vector3f[][] verticesAndNormals; |
||||||
|
/** The vertices of the mesh. */ |
||||||
|
private List<Vector3f> vertices = new ArrayList<Vector3f>(); |
||||||
|
/** The normals of the mesh. */ |
||||||
|
private List<Vector3f> normals = new ArrayList<Vector3f>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 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). |
||||||
|
*/ |
||||||
|
private Map<Integer, List<Integer>> globalVertexReferenceMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Stores the given array (not copying it). |
||||||
|
* The second argument describes if the model uses generated textures. If yes then no vertex amount optimisation is applied. |
||||||
|
* The amount of vertices is always faceCount * 3. |
||||||
|
* @param verticesAndNormals |
||||||
|
* the reference vertices and normals array |
||||||
|
*/ |
||||||
|
public PointMeshBuilder(Vector3f[][] verticesAndNormals) { |
||||||
|
this.verticesAndNormals = verticesAndNormals; |
||||||
|
globalVertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAndNormals.length); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The method reads the mesh. Since blender does not store the information in the vertex itself whether it belongs |
||||||
|
* anywhere or not, we need to check all vertices and use here only those that are not used. |
||||||
|
* @param meshStructure |
||||||
|
* the mesh structure |
||||||
|
* @param blenderContext |
||||||
|
* the blender context |
||||||
|
* @throws BlenderFileException |
||||||
|
* an exception thrown when reading from the blend file fails |
||||||
|
*/ |
||||||
|
public void readMesh(Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException { |
||||||
|
LOGGER.fine("Reading points mesh."); |
||||||
|
Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge"); |
||||||
|
|
||||||
|
if (pMEdge.isNotNull()) { |
||||||
|
int count = ((Number) meshStructure.getFieldValue("totvert")).intValue(); |
||||||
|
Set<Vector3f> usedVertices = new HashSet<Vector3f>(count); |
||||||
|
List<Structure> edges = pMEdge.fetchData(blenderContext.getInputStream()); |
||||||
|
|
||||||
|
for (Structure edge : edges) { |
||||||
|
int v1 = ((Number) edge.getFieldValue("v1")).intValue(); |
||||||
|
int v2 = ((Number) edge.getFieldValue("v2")).intValue(); |
||||||
|
usedVertices.add(verticesAndNormals[v1][0]); |
||||||
|
usedVertices.add(verticesAndNormals[v2][0]); |
||||||
|
} |
||||||
|
|
||||||
|
if (usedVertices.size() < count) { |
||||||
|
vertices = new ArrayList<Vector3f>(count - usedVertices.size()); |
||||||
|
int vertexIndex = 0, blenderVertexIndex = 0; |
||||||
|
for (Vector3f[] vertAndNormal : verticesAndNormals) { |
||||||
|
if (!usedVertices.contains(vertAndNormal[0])) { |
||||||
|
vertices.add(vertAndNormal[0]); |
||||||
|
normals.add(vertAndNormal[1]); |
||||||
|
this.appendVertexReference(blenderVertexIndex, vertexIndex++, globalVertexReferenceMap); |
||||||
|
} |
||||||
|
++blenderVertexIndex; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds the meshes. |
||||||
|
* @return a map between material index and the mesh |
||||||
|
*/ |
||||||
|
public Map<Integer, Mesh> buildMeshes() { |
||||||
|
LOGGER.fine("Building point mesh."); |
||||||
|
Map<Integer, Mesh> result = new HashMap<Integer, Mesh>(1); |
||||||
|
|
||||||
|
if (vertices.size() > 0) { |
||||||
|
Mesh mesh = new Mesh(); |
||||||
|
mesh.setMode(Mode.Points); |
||||||
|
mesh.setPointSize(3); |
||||||
|
|
||||||
|
// the point mesh does not need index buffer, but some modifiers applied by importer need it
|
||||||
|
// the 'alone point' situation should be quite rare so not too many resources are wasted here
|
||||||
|
LOGGER.fine("Creating indices buffer."); |
||||||
|
if (vertices.size() <= Short.MAX_VALUE) { |
||||||
|
short[] indices = new short[vertices.size()]; |
||||||
|
for (int i = 0; i < vertices.size(); ++i) { |
||||||
|
indices[i] = (short) i; |
||||||
|
} |
||||||
|
mesh.setBuffer(Type.Index, 1, indices); |
||||||
|
} else { |
||||||
|
int[] indices = new int[vertices.size()]; |
||||||
|
for (int i = 0; i < vertices.size(); ++i) { |
||||||
|
indices[i] = i; |
||||||
|
} |
||||||
|
mesh.setBuffer(Type.Index, 1, indices); |
||||||
|
} |
||||||
|
|
||||||
|
LOGGER.fine("Creating vertices buffer."); |
||||||
|
VertexBuffer verticesBuffer = new VertexBuffer(Type.Position); |
||||||
|
verticesBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(vertices.toArray(new Vector3f[vertices.size()]))); |
||||||
|
mesh.setBuffer(verticesBuffer); |
||||||
|
|
||||||
|
LOGGER.fine("Creating normals buffer (in case of points it is required if skeleton is applied)."); |
||||||
|
VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal); |
||||||
|
normalsBuffer.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(normals.toArray(new Vector3f[normals.size()]))); |
||||||
|
mesh.setBuffer(normalsBuffer); |
||||||
|
|
||||||
|
result.put(-1, mesh); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return <b>true</b> if the mesh has no vertices and <b>false</b> otherwise |
||||||
|
*/ |
||||||
|
public boolean isEmpty() { |
||||||
|
return vertices == null; |
||||||
|
} |
||||||
|
|
||||||
|
public Map<Integer, List<Integer>> getGlobalVertexReferenceMap() { |
||||||
|
return globalVertexReferenceMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 |
||||||
|
*/ |
||||||
|
private 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)); |
||||||
|
} |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue