use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class TerrainPatch method generateLodEntropies.
/**
* This calculation is slow, so don't use it often.
*/
public void generateLodEntropies() {
float[] entropies = new float[getMaxLod() + 1];
for (int i = 0; i <= getMaxLod(); i++) {
int curLod = (int) Math.pow(2, i);
IndexBuffer idxB = geomap.writeIndexArrayLodDiff(curLod, false, false, false, false, totalSize);
Buffer ib;
if (idxB.getBuffer() instanceof IntBuffer)
ib = (IntBuffer) idxB.getBuffer();
else
ib = (ShortBuffer) idxB.getBuffer();
entropies[i] = EntropyComputeUtil.computeLodEntropy(mesh, ib);
}
lodEntropy = entropies;
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class LODGeomap method writeIndexArrayLodVariable.
public IndexBuffer writeIndexArrayLodVariable(int lod, int rightLod, int topLod, int leftLod, int bottomLod, int totalSize) {
int numIndexes = calculateNumIndexesLodDiff(lod);
IndexBuffer ib = IndexBuffer.createIndexBuffer(numIndexes, numIndexes);
VerboseBuffer buffer = new VerboseBuffer(ib);
//System.out.println(" for (z="+lod+"; z<"+(getWidth()-(1*lod))+"; z+="+lod+")");
for (int r = lod; r < getWidth() - (2 * lod); r += lod) {
// row
int rowIdx = r * getWidth();
int nextRowIdx = (r + 1 * lod) * getWidth();
for (int c = lod; c < getWidth() - (1 * lod); c += lod) {
// column
int idx = rowIdx + c;
buffer.put(idx);
idx = nextRowIdx + c;
buffer.put(idx);
}
// add degenerate triangles
if (r < getWidth() - (3 * lod)) {
int idx = nextRowIdx + getWidth() - (1 * lod) - 1;
buffer.put(idx);
// inset by 1
idx = nextRowIdx + (1 * lod);
buffer.put(idx);
//System.out.println("");
}
}
//System.out.println("\nright:");
//int runningBufferCount = buffer.getCount();
//System.out.println("buffer start: "+runningBufferCount);
// right
int br = getWidth() * (getWidth() - lod) - 1 - lod;
// bottom right -1
buffer.put(br);
int corner = getWidth() * getWidth() - 1;
// bottom right corner
buffer.put(corner);
if (rightLod > lod) {
// if lower LOD
int idx = corner;
// iterations
int it = (getWidth() - 1) / rightLod;
int lodDiff = rightLod / lod;
for (int i = it; i > 0; i--) {
// for each lod level of the neighbour
idx = getWidth() * (i * rightLod + 1) - 1;
for (int j = 1; j <= lodDiff; j++) {
// for each section in that lod level
int idxB = idx - (getWidth() * (j * lod)) - lod;
if (j == lodDiff && i == 1) {
// the last one
buffer.put(getWidth() - 1);
} else if (j == lodDiff) {
buffer.put(idxB);
buffer.put(idxB + lod);
} else {
buffer.put(idxB);
buffer.put(idx);
}
}
}
// reset winding order
// top-right +1row
buffer.put(getWidth() * (lod + 1) - lod - 1);
// top-right
buffer.put(getWidth() - 1);
} else {
//br+1);//degenerate to flip winding order
buffer.put(corner);
for (int row = getWidth() - lod; row > lod; row -= lod) {
// mult to get row
int idx = row * getWidth() - 1;
buffer.put(idx);
buffer.put(idx - lod);
}
buffer.put(getWidth() - 1);
}
// top (the order gets reversed here so the diagonals line up)
if (topLod > lod) {
// if lower LOD
if (rightLod > lod) {
// need to flip winding order
buffer.put(getWidth() - 1);
buffer.put(getWidth() * lod - 1);
buffer.put(getWidth() - 1);
}
int idx = getWidth() - 1;
// iterations
int it = (getWidth() - 1) / topLod;
int lodDiff = topLod / lod;
for (int i = it; i > 0; i--) {
// for each lod level of the neighbour
idx = (i * topLod);
for (int j = 1; j <= lodDiff; j++) {
// for each section in that lod level
int idxB = lod * getWidth() + (i * topLod) - (j * lod);
if (j == lodDiff && i == 1) {
// the last one
buffer.put(0);
} else if (j == lodDiff) {
buffer.put(idxB);
buffer.put(idx - topLod);
} else {
buffer.put(idxB);
buffer.put(idx);
}
}
}
} else {
if (rightLod > lod) {
buffer.put(getWidth() - 1);
}
for (int col = getWidth() - 1 - lod; col > 0; col -= lod) {
int idx = col + (lod * getWidth());
buffer.put(idx);
idx = col;
buffer.put(idx);
}
buffer.put(0);
}
buffer.put(0);
// left
if (leftLod > lod) {
// if lower LOD
int idx = 0;
// iterations
int it = (getWidth() - 1) / leftLod;
int lodDiff = leftLod / lod;
for (int i = 0; i < it; i++) {
// for each lod level of the neighbour
idx = getWidth() * (i * leftLod);
for (int j = 1; j <= lodDiff; j++) {
// for each section in that lod level
int idxB = idx + (getWidth() * (j * lod)) + lod;
if (j == lodDiff && i == it - 1) {
// the last one
buffer.put(getWidth() * getWidth() - getWidth());
} else if (j == lodDiff) {
buffer.put(idxB);
buffer.put(idxB - lod);
} else {
buffer.put(idxB);
buffer.put(idx);
}
}
}
} else {
buffer.put(0);
buffer.put(getWidth() * lod + lod);
buffer.put(0);
for (int row = lod; row < getWidth() - lod; row += lod) {
int idx = row * getWidth();
buffer.put(idx);
idx = row * getWidth() + lod;
buffer.put(idx);
}
buffer.put(getWidth() * (getWidth() - 1));
}
// bottom
if (bottomLod > lod) {
// if lower LOD
if (leftLod > lod) {
buffer.put(getWidth() * (getWidth() - 1));
buffer.put(getWidth() * (getWidth() - lod));
buffer.put(getWidth() * (getWidth() - 1));
}
int idx = getWidth() * getWidth() - getWidth();
// iterations
int it = (getWidth() - 1) / bottomLod;
int lodDiff = bottomLod / lod;
for (int i = 0; i < it; i++) {
// for each lod level of the neighbour
idx = getWidth() * getWidth() - getWidth() + (i * bottomLod);
for (int j = 1; j <= lodDiff; j++) {
// for each section in that lod level
int idxB = idx - (getWidth() * lod) + j * lod;
if (j == lodDiff && i == it - 1) {
// the last one
buffer.put(getWidth() * getWidth() - 1);
} else if (j == lodDiff) {
buffer.put(idxB);
buffer.put(idx + bottomLod);
} else {
buffer.put(idxB);
buffer.put(idx);
}
}
}
} else {
if (leftLod > lod) {
buffer.put(getWidth() * (getWidth() - 1));
buffer.put(getWidth() * getWidth() - (getWidth() * lod) + lod);
buffer.put(getWidth() * (getWidth() - 1));
}
for (int col = lod; col < getWidth() - lod; col += lod) {
// up
int idx = getWidth() * (getWidth() - 1 - lod) + col;
buffer.put(idx);
// down
idx = getWidth() * (getWidth() - 1) + col;
buffer.put(idx);
}
//buffer.put(getWidth()*getWidth()-1-lod); // <-- THIS caused holes at the end!
}
buffer.put(getWidth() * getWidth() - 1);
// fill in the rest of the buffer with degenerates, there should only be a couple
for (int i = buffer.getCount(); i < numIndexes; i++) {
buffer.put(getWidth() * getWidth() - 1);
}
return buffer.delegate;
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class LODGeomap method createMesh.
public Mesh createMesh(Vector3f scale, Vector2f tcScale, Vector2f tcOffset, float offsetAmount, int totalSize, boolean center, int lod, boolean rightLod, boolean topLod, boolean leftLod, boolean bottomLod) {
FloatBuffer pb = writeVertexArray(null, scale, center);
FloatBuffer texb = writeTexCoordArray(null, tcOffset, tcScale, offsetAmount, totalSize);
FloatBuffer nb = writeNormalArray(null, scale);
Buffer ib;
IndexBuffer idxB = writeIndexArrayLodDiff(lod, rightLod, topLod, leftLod, bottomLod, totalSize);
if (idxB.getBuffer() instanceof IntBuffer)
ib = (IntBuffer) idxB.getBuffer();
else
ib = (ShortBuffer) idxB.getBuffer();
FloatBuffer bb = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
FloatBuffer tanb = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
writeTangentArray(nb, tanb, bb, texb, scale);
Mesh m = new Mesh();
m.setMode(Mode.TriangleStrip);
m.setBuffer(Type.Position, 3, pb);
m.setBuffer(Type.Normal, 3, nb);
m.setBuffer(Type.Tangent, 3, tanb);
m.setBuffer(Type.Binormal, 3, bb);
m.setBuffer(Type.TexCoord, 2, texb);
if (ib instanceof IntBuffer)
m.setBuffer(Type.Index, 3, (IntBuffer) ib);
else if (ib instanceof ShortBuffer)
m.setBuffer(Type.Index, 3, (ShortBuffer) ib);
m.setStatic();
m.updateBound();
return m;
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class BatchNode method mergeGeometries.
/**
* Merges all geometries in the collection into
* the output mesh. Does not take into account materials.
*
* @param geometries
* @param outMesh
*/
private void mergeGeometries(Mesh outMesh, List<Geometry> geometries) {
int[] compsForBuf = new int[VertexBuffer.Type.values().length];
VertexBuffer.Format[] formatForBuf = new VertexBuffer.Format[compsForBuf.length];
boolean[] normForBuf = new boolean[VertexBuffer.Type.values().length];
int totalVerts = 0;
int totalTris = 0;
int totalLodLevels = 0;
int maxWeights = -1;
Mesh.Mode mode = null;
float lineWidth = 1f;
for (Geometry geom : geometries) {
totalVerts += geom.getVertexCount();
totalTris += geom.getTriangleCount();
totalLodLevels = Math.min(totalLodLevels, geom.getMesh().getNumLodLevels());
if (maxVertCount < geom.getVertexCount()) {
maxVertCount = geom.getVertexCount();
}
Mesh.Mode listMode;
//float listLineWidth = 1f;
int components;
switch(geom.getMesh().getMode()) {
case Points:
listMode = Mesh.Mode.Points;
components = 1;
break;
case LineLoop:
case LineStrip:
case Lines:
listMode = Mesh.Mode.Lines;
//listLineWidth = geom.getMesh().getLineWidth();
components = 2;
break;
case TriangleFan:
case TriangleStrip:
case Triangles:
listMode = Mesh.Mode.Triangles;
components = 3;
break;
default:
throw new UnsupportedOperationException();
}
for (VertexBuffer vb : geom.getMesh().getBufferList().getArray()) {
int currentCompsForBuf = compsForBuf[vb.getBufferType().ordinal()];
if (vb.getBufferType() != VertexBuffer.Type.Index && currentCompsForBuf != 0 && currentCompsForBuf != vb.getNumComponents()) {
throw new UnsupportedOperationException("The geometry " + geom + " buffer " + vb.getBufferType() + " has different number of components than the rest of the meshes " + "(this: " + vb.getNumComponents() + ", expected: " + currentCompsForBuf + ")");
}
compsForBuf[vb.getBufferType().ordinal()] = vb.getNumComponents();
formatForBuf[vb.getBufferType().ordinal()] = vb.getFormat();
normForBuf[vb.getBufferType().ordinal()] = vb.isNormalized();
}
maxWeights = Math.max(maxWeights, geom.getMesh().getMaxNumWeights());
if (mode != null && mode != listMode) {
throw new UnsupportedOperationException("Cannot combine different" + " primitive types: " + mode + " != " + listMode);
}
mode = listMode;
//Not needed anymore as lineWidth is now in RenderState and will be taken into account when merging according to the material
// if (mode == Mesh.Mode.Lines) {
// if (lineWidth != 1f && listLineWidth != lineWidth) {
// throw new UnsupportedOperationException("When using Mesh Line mode, cannot combine meshes with different line width "
// + lineWidth + " != " + listLineWidth);
// }
// lineWidth = listLineWidth;
// }
compsForBuf[VertexBuffer.Type.Index.ordinal()] = components;
}
outMesh.setMaxNumWeights(maxWeights);
outMesh.setMode(mode);
//outMesh.setLineWidth(lineWidth);
if (totalVerts >= 65536) {
// make sure we create an UnsignedInt buffer so we can fit all of the meshes
formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedInt;
} else {
formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedShort;
}
// generate output buffers based on retrieved info
for (int i = 0; i < compsForBuf.length; i++) {
if (compsForBuf[i] == 0) {
continue;
}
Buffer data;
if (i == VertexBuffer.Type.Index.ordinal()) {
data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalTris);
} else {
data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalVerts);
}
VertexBuffer vb = new VertexBuffer(VertexBuffer.Type.values()[i]);
vb.setupData(VertexBuffer.Usage.Dynamic, compsForBuf[i], formatForBuf[i], data);
vb.setNormalized(normForBuf[i]);
outMesh.setBuffer(vb);
}
int globalVertIndex = 0;
int globalTriIndex = 0;
for (Geometry geom : geometries) {
Mesh inMesh = geom.getMesh();
if (!isBatch(geom)) {
geom.associateWithGroupNode(this, globalVertIndex);
}
int geomVertCount = inMesh.getVertexCount();
int geomTriCount = inMesh.getTriangleCount();
for (int bufType = 0; bufType < compsForBuf.length; bufType++) {
VertexBuffer inBuf = inMesh.getBuffer(VertexBuffer.Type.values()[bufType]);
VertexBuffer outBuf = outMesh.getBuffer(VertexBuffer.Type.values()[bufType]);
if (outBuf == null) {
continue;
}
if (VertexBuffer.Type.Index.ordinal() == bufType) {
int components = compsForBuf[bufType];
IndexBuffer inIdx = inMesh.getIndicesAsList();
IndexBuffer outIdx = outMesh.getIndexBuffer();
for (int tri = 0; tri < geomTriCount; tri++) {
for (int comp = 0; comp < components; comp++) {
int idx = inIdx.get(tri * components + comp) + globalVertIndex;
outIdx.put((globalTriIndex + tri) * components + comp, idx);
}
}
} else if (VertexBuffer.Type.Position.ordinal() == bufType) {
FloatBuffer inPos = (FloatBuffer) inBuf.getData();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
doCopyBuffer(inPos, globalVertIndex, outPos, 3);
} else if (VertexBuffer.Type.Normal.ordinal() == bufType || VertexBuffer.Type.Tangent.ordinal() == bufType) {
FloatBuffer inPos = (FloatBuffer) inBuf.getData();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
doCopyBuffer(inPos, globalVertIndex, outPos, compsForBuf[bufType]);
if (VertexBuffer.Type.Tangent.ordinal() == bufType) {
useTangents = true;
}
} else {
if (inBuf == null) {
throw new IllegalArgumentException("Geometry " + geom.getName() + " has no " + outBuf.getBufferType() + " buffer whereas other geoms have. all geometries should have the same types of buffers.\n Try to use GeometryBatchFactory.alignBuffer() on the BatchNode before batching");
} else if (outBuf == null) {
throw new IllegalArgumentException("Geometry " + geom.getName() + " has a " + outBuf.getBufferType() + " buffer whereas other geoms don't. all geometries should have the same types of buffers.\n Try to use GeometryBatchFactory.alignBuffer() on the BatchNode before batching");
} else {
inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount);
}
}
}
globalVertIndex += geomVertCount;
globalTriIndex += geomTriCount;
}
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class IrUtils method convertIrMeshToJmeMesh.
/**
* Convert IrMesh to jME3 mesh.
*/
public static Mesh convertIrMeshToJmeMesh(IrMesh mesh) {
Map<IrVertex, Integer> vertexToVertexIndex = new HashMap<IrVertex, Integer>();
List<IrVertex> vertices = new ArrayList<IrVertex>();
List<Integer> indexes = new ArrayList<Integer>();
int vertexIndex = 0;
for (IrPolygon polygon : mesh.polygons) {
if (polygon.vertices.length != 3) {
throw new UnsupportedOperationException("IrMesh must be triangulated first");
}
for (IrVertex vertex : polygon.vertices) {
// Is this vertex already indexed?
Integer existingIndex = vertexToVertexIndex.get(vertex);
if (existingIndex == null) {
// Not indexed yet, allocate index.
indexes.add(vertexIndex);
vertexToVertexIndex.put(vertex, vertexIndex);
vertices.add(vertex);
vertexIndex++;
} else {
// Index already allocated for this vertex, reuse it.
indexes.add(existingIndex);
}
}
}
Mesh jmeMesh = new Mesh();
jmeMesh.setMode(Mesh.Mode.Triangles);
FloatBuffer posBuf = null;
FloatBuffer normBuf = null;
FloatBuffer tangBuf = null;
FloatBuffer uv0Buf = null;
FloatBuffer uv1Buf = null;
ByteBuffer colorBuf = null;
ByteBuffer boneIndices = null;
FloatBuffer boneWeights = null;
IndexBuffer indexBuf = null;
IrVertex inspectionVertex = vertices.get(0);
if (inspectionVertex.pos != null) {
posBuf = BufferUtils.createVector3Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.Position, 3, posBuf);
}
if (inspectionVertex.norm != null) {
normBuf = BufferUtils.createVector3Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
}
if (inspectionVertex.tang4d != null) {
tangBuf = BufferUtils.createFloatBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.Tangent, 4, tangBuf);
}
if (inspectionVertex.tang != null || inspectionVertex.bitang != null) {
throw new IllegalStateException("Mesh is using 3D tangents, must be converted to 4D tangents first.");
}
if (inspectionVertex.uv0 != null) {
uv0Buf = BufferUtils.createVector2Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.TexCoord, 2, uv0Buf);
}
if (inspectionVertex.uv1 != null) {
uv1Buf = BufferUtils.createVector2Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.TexCoord2, 2, uv1Buf);
}
if (inspectionVertex.color != null) {
colorBuf = BufferUtils.createByteBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.Color, 4, colorBuf);
jmeMesh.getBuffer(VertexBuffer.Type.Color).setNormalized(true);
}
if (inspectionVertex.boneWeightsIndices != null) {
boneIndices = BufferUtils.createByteBuffer(vertices.size() * 4);
boneWeights = BufferUtils.createFloatBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, boneIndices);
jmeMesh.setBuffer(VertexBuffer.Type.BoneWeight, 4, boneWeights);
//creating empty buffers for HW skinning
//the buffers will be setup if ever used.
VertexBuffer weightsHW = new VertexBuffer(VertexBuffer.Type.HWBoneWeight);
VertexBuffer indicesHW = new VertexBuffer(VertexBuffer.Type.HWBoneIndex);
//setting usage to cpuOnly so that the buffer is not send empty to the GPU
indicesHW.setUsage(VertexBuffer.Usage.CpuOnly);
weightsHW.setUsage(VertexBuffer.Usage.CpuOnly);
jmeMesh.setBuffer(weightsHW);
jmeMesh.setBuffer(indicesHW);
}
if (vertices.size() >= 65536) {
// too many verticies: use intbuffer instead of shortbuffer
IntBuffer ib = BufferUtils.createIntBuffer(indexes.size());
jmeMesh.setBuffer(VertexBuffer.Type.Index, 3, ib);
indexBuf = new IndexIntBuffer(ib);
} else {
ShortBuffer sb = BufferUtils.createShortBuffer(indexes.size());
jmeMesh.setBuffer(VertexBuffer.Type.Index, 3, sb);
indexBuf = new IndexShortBuffer(sb);
}
jmeMesh.setStatic();
int maxBonesPerVertex = -1;
for (IrVertex vertex : vertices) {
if (posBuf != null) {
posBuf.put(vertex.pos.x).put(vertex.pos.y).put(vertex.pos.z);
}
if (normBuf != null) {
normBuf.put(vertex.norm.x).put(vertex.norm.y).put(vertex.norm.z);
}
if (tangBuf != null) {
tangBuf.put(vertex.tang4d.x).put(vertex.tang4d.y).put(vertex.tang4d.z).put(vertex.tang4d.w);
}
if (uv0Buf != null) {
uv0Buf.put(vertex.uv0.x).put(vertex.uv0.y);
}
if (uv1Buf != null) {
uv1Buf.put(vertex.uv1.x).put(vertex.uv1.y);
}
if (colorBuf != null) {
colorBuf.putInt(vertex.color.asIntABGR());
}
if (boneIndices != null) {
if (vertex.boneWeightsIndices != null) {
if (vertex.boneWeightsIndices.length > 4) {
throw new UnsupportedOperationException("Mesh uses more than 4 weights per bone. " + "Call trimBoneWeights() to allieviate this");
}
for (int i = 0; i < vertex.boneWeightsIndices.length; i++) {
boneIndices.put((byte) (vertex.boneWeightsIndices[i].boneIndex & 0xFF));
boneWeights.put(vertex.boneWeightsIndices[i].boneWeight);
}
for (int i = 0; i < 4 - vertex.boneWeightsIndices.length; i++) {
boneIndices.put((byte) 0);
boneWeights.put(0f);
}
} else {
boneIndices.putInt(0);
boneWeights.put(0f).put(0f).put(0f).put(0f);
}
maxBonesPerVertex = Math.max(maxBonesPerVertex, vertex.boneWeightsIndices.length);
}
}
for (int i = 0; i < indexes.size(); i++) {
indexBuf.put(i, indexes.get(i));
}
jmeMesh.updateCounts();
jmeMesh.updateBound();
if (boneIndices != null) {
jmeMesh.setMaxNumWeights(maxBonesPerVertex);
jmeMesh.prepareForAnim(true);
jmeMesh.generateBindPose(true);
}
return jmeMesh;
}
Aggregations