use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class NativeMeshUtil method getTriangleIndexVertexArray.
public static long getTriangleIndexVertexArray(Mesh mesh) {
ByteBuffer triangleIndexBase = BufferUtils.createByteBuffer(mesh.getTriangleCount() * 3 * 4);
ByteBuffer vertexBase = BufferUtils.createByteBuffer(mesh.getVertexCount() * 3 * 4);
int numVertices = mesh.getVertexCount();
//3 verts * 4 bytes per.
int vertexStride = 12;
int numTriangles = mesh.getTriangleCount();
//3 index entries * 4 bytes each.
int triangleIndexStride = 12;
IndexBuffer indices = mesh.getIndicesAsList();
FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
vertices.rewind();
int verticesLength = mesh.getVertexCount() * 3;
for (int i = 0; i < verticesLength; i++) {
float tempFloat = vertices.get();
vertexBase.putFloat(tempFloat);
}
int indicesLength = mesh.getTriangleCount() * 3;
for (int i = 0; i < indicesLength; i++) {
triangleIndexBase.putInt(indices.get(i));
}
vertices.rewind();
vertices.clear();
return createTriangleIndexVertexArray(triangleIndexBase, vertexBase, numTriangles, numVertices, vertexStride, triangleIndexStride);
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class GeometryBatchFactory method mergeGeometries.
/**
* Merges all geometries in the collection into
* the output mesh. Creates a new material using the TextureAtlas.
*
* @param geometries
* @param outMesh
*/
public static void mergeGeometries(Collection<Geometry> geometries, Mesh outMesh) {
int[] compsForBuf = new int[VertexBuffer.Type.values().length];
Format[] formatForBuf = new Format[compsForBuf.length];
boolean[] normForBuf = new boolean[VertexBuffer.Type.values().length];
int totalVerts = 0;
int totalTris = 0;
int totalLodLevels = 0;
int maxWeights = -1;
Mode mode = null;
for (Geometry geom : geometries) {
totalVerts += geom.getVertexCount();
totalTris += geom.getTriangleCount();
totalLodLevels = Math.min(totalLodLevels, geom.getMesh().getNumLodLevels());
Mode listMode;
int components;
switch(geom.getMesh().getMode()) {
case Points:
listMode = Mode.Points;
components = 0;
break;
case LineLoop:
case LineStrip:
case Lines:
listMode = Mode.Lines;
components = 2;
break;
case TriangleFan:
case TriangleStrip:
case Triangles:
listMode = 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() != 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;
compsForBuf[Type.Index.ordinal()] = components;
}
outMesh.setMaxNumWeights(maxWeights);
outMesh.setMode(mode);
if (totalVerts >= 65536) {
// make sure we create an UnsignedInt buffer so
// we can fit all of the meshes
formatForBuf[Type.Index.ordinal()] = Format.UnsignedInt;
} else {
formatForBuf[Type.Index.ordinal()] = 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 == Type.Index.ordinal()) {
data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalTris);
} else {
data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalVerts);
}
VertexBuffer vb = new VertexBuffer(Type.values()[i]);
vb.setupData(Usage.Static, 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();
geom.computeWorldMatrix();
Matrix4f worldMatrix = geom.getWorldMatrix();
int geomVertCount = inMesh.getVertexCount();
int geomTriCount = inMesh.getTriangleCount();
for (int bufType = 0; bufType < compsForBuf.length; bufType++) {
VertexBuffer inBuf = inMesh.getBuffer(Type.values()[bufType]);
VertexBuffer outBuf = outMesh.getBuffer(Type.values()[bufType]);
if (inBuf == null || outBuf == null) {
continue;
}
if (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 (Type.Position.ordinal() == bufType) {
FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
doTransformVerts(inPos, globalVertIndex, outPos, worldMatrix);
} else if (Type.Normal.ordinal() == bufType) {
FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
doTransformNorms(inPos, globalVertIndex, outPos, worldMatrix);
} else if (Type.Tangent.ordinal() == bufType) {
FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
int components = inBuf.getNumComponents();
doTransformTangents(inPos, globalVertIndex, components, outPos, worldMatrix);
} 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 LodGenerator method makeLod.
private VertexBuffer makeLod(Mesh mesh) {
VertexBuffer indexBuffer = mesh.getBuffer(VertexBuffer.Type.Index);
boolean isShortBuffer = indexBuffer.getFormat() == VertexBuffer.Format.UnsignedShort;
// Create buffers.
VertexBuffer lodBuffer = new VertexBuffer(VertexBuffer.Type.Index);
int bufsize = indexCount == 0 ? 3 : indexCount;
if (isShortBuffer) {
lodBuffer.setupData(VertexBuffer.Usage.Static, 3, VertexBuffer.Format.UnsignedShort, BufferUtils.createShortBuffer(bufsize));
} else {
lodBuffer.setupData(VertexBuffer.Usage.Static, 3, VertexBuffer.Format.UnsignedInt, BufferUtils.createIntBuffer(bufsize));
}
lodBuffer.getData().rewind();
//Check if we should fill it with a "dummy" triangle.
if (indexCount == 0) {
if (isShortBuffer) {
for (int m = 0; m < 3; m++) {
((ShortBuffer) lodBuffer.getData()).put((short) 0);
}
} else {
for (int m = 0; m < 3; m++) {
((IntBuffer) lodBuffer.getData()).put(0);
}
}
}
// Fill buffers.
Buffer buf = lodBuffer.getData();
buf.rewind();
for (Triangle triangle : triangleList) {
if (!triangle.isRemoved) {
// assert (indexCount != 0);
if (isShortBuffer) {
for (int m = 0; m < 3; m++) {
((ShortBuffer) buf).put((short) triangle.vertexId[m]);
}
} else {
for (int m = 0; m < 3; m++) {
((IntBuffer) buf).put(triangle.vertexId[m]);
}
}
}
}
buf.clear();
lodBuffer.updateData(buf);
return lodBuffer;
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class ObjectHelper method flipMeshIfRequired.
/**
* The method flips the mesh if the scale is mirroring it. Mirroring scale has either 1 or all 3 factors negative.
* If two factors are negative then there is no mirroring because a rotation and translation can be found that will
* lead to the same transform when all scales are positive.
*
* @param geometry
* the geometry that is being flipped if necessary
* @param scale
* the scale vector of the given geometry
*/
private void flipMeshIfRequired(Geometry geometry, Vector3f scale) {
float s = scale.x * scale.y * scale.z;
if (s < 0 && geometry.getMesh() != null) {
// negative s means that the scale is mirroring the object
FloatBuffer normals = geometry.getMesh().getFloatBuffer(Type.Normal);
if (normals != null) {
for (int i = 0; i < normals.limit(); i += 3) {
if (scale.x < 0) {
normals.put(i, -normals.get(i));
}
if (scale.y < 0) {
normals.put(i + 1, -normals.get(i + 1));
}
if (scale.z < 0) {
normals.put(i + 2, -normals.get(i + 2));
}
}
}
if (geometry.getMesh().getMode() == Mode.Triangles) {
// there is no need to flip the indexes for lines and points
LOGGER.finer("Flipping index order in triangle mesh.");
Buffer indexBuffer = geometry.getMesh().getBuffer(Type.Index).getData();
for (int i = 0; i < indexBuffer.limit(); i += 3) {
if (indexBuffer instanceof ShortBuffer) {
short index = ((ShortBuffer) indexBuffer).get(i + 1);
((ShortBuffer) indexBuffer).put(i + 1, ((ShortBuffer) indexBuffer).get(i + 2));
((ShortBuffer) indexBuffer).put(i + 2, index);
} else {
int index = ((IntBuffer) indexBuffer).get(i + 1);
((IntBuffer) indexBuffer).put(i + 1, ((IntBuffer) indexBuffer).get(i + 2));
((IntBuffer) indexBuffer).put(i + 2, index);
}
}
}
}
}
use of com.jme3.scene.mesh.IndexBuffer in project jmonkeyengine by jMonkeyEngine.
the class Cylinder method updateGeometry.
/**
* Rebuilds the cylinder based on a new set of parameters.
*
* @param axisSamples the number of samples along the axis.
* @param radialSamples the number of samples around the radial.
* @param radius the radius of the bottom of the cylinder.
* @param radius2 the radius of the top of the cylinder.
* @param height the cylinder's height.
* @param closed should the cylinder have top and bottom surfaces.
* @param inverted is the cylinder is meant to be viewed from the inside.
*/
public void updateGeometry(int axisSamples, int radialSamples, float radius, float radius2, float height, boolean closed, boolean inverted) {
this.axisSamples = axisSamples;
this.radialSamples = radialSamples;
this.radius = radius;
this.radius2 = radius2;
this.height = height;
this.closed = closed;
this.inverted = inverted;
// VertexBuffer pvb = getBuffer(Type.Position);
// VertexBuffer nvb = getBuffer(Type.Normal);
// VertexBuffer tvb = getBuffer(Type.TexCoord);
axisSamples += (closed ? 2 : 0);
// Vertices
int vertCount = axisSamples * (radialSamples + 1) + (closed ? 2 : 0);
setBuffer(Type.Position, 3, createVector3Buffer(getFloatBuffer(Type.Position), vertCount));
// Normals
setBuffer(Type.Normal, 3, createVector3Buffer(getFloatBuffer(Type.Normal), vertCount));
// Texture co-ordinates
setBuffer(Type.TexCoord, 2, createVector2Buffer(vertCount));
int triCount = ((closed ? 2 : 0) + 2 * (axisSamples - 1)) * radialSamples;
setBuffer(Type.Index, 3, createShortBuffer(getShortBuffer(Type.Index), 3 * triCount));
// generate geometry
float inverseRadial = 1.0f / radialSamples;
float inverseAxisLess = 1.0f / (closed ? axisSamples - 3 : axisSamples - 1);
float inverseAxisLessTexture = 1.0f / (axisSamples - 1);
float halfHeight = 0.5f * height;
// Generate points on the unit circle to be used in computing the mesh
// points on a cylinder slice.
float[] sin = new float[radialSamples + 1];
float[] cos = new float[radialSamples + 1];
for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
float angle = FastMath.TWO_PI * inverseRadial * radialCount;
cos[radialCount] = FastMath.cos(angle);
sin[radialCount] = FastMath.sin(angle);
}
sin[radialSamples] = sin[0];
cos[radialSamples] = cos[0];
// calculate normals
Vector3f[] vNormals = null;
Vector3f vNormal = Vector3f.UNIT_Z;
if ((height != 0.0f) && (radius != radius2)) {
vNormals = new Vector3f[radialSamples];
Vector3f vHeight = Vector3f.UNIT_Z.mult(height);
Vector3f vRadial = new Vector3f();
for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
vRadial.set(cos[radialCount], sin[radialCount], 0.0f);
Vector3f vRadius = vRadial.mult(radius);
Vector3f vRadius2 = vRadial.mult(radius2);
Vector3f vMantle = vHeight.subtract(vRadius2.subtract(vRadius));
Vector3f vTangent = vRadial.cross(Vector3f.UNIT_Z);
vNormals[radialCount] = vMantle.cross(vTangent).normalize();
}
}
FloatBuffer nb = getFloatBuffer(Type.Normal);
FloatBuffer pb = getFloatBuffer(Type.Position);
FloatBuffer tb = getFloatBuffer(Type.TexCoord);
// generate the cylinder itself
Vector3f tempNormal = new Vector3f();
for (int axisCount = 0, i = 0; axisCount < axisSamples; axisCount++, i++) {
float axisFraction;
float axisFractionTexture;
int topBottom = 0;
if (!closed) {
// in [0,1]
axisFraction = axisCount * inverseAxisLess;
axisFractionTexture = axisFraction;
} else {
if (axisCount == 0) {
// bottom
topBottom = -1;
axisFraction = 0;
axisFractionTexture = inverseAxisLessTexture;
} else if (axisCount == axisSamples - 1) {
// top
topBottom = 1;
axisFraction = 1;
axisFractionTexture = 1 - inverseAxisLessTexture;
} else {
axisFraction = (axisCount - 1) * inverseAxisLess;
axisFractionTexture = axisCount * inverseAxisLessTexture;
}
}
// compute center of slice
float z = -halfHeight + height * axisFraction;
Vector3f sliceCenter = new Vector3f(0, 0, z);
// compute slice vertices with duplication at end point
int save = i;
for (int radialCount = 0; radialCount < radialSamples; radialCount++, i++) {
// in [0,1)
float radialFraction = radialCount * inverseRadial;
tempNormal.set(cos[radialCount], sin[radialCount], 0.0f);
if (vNormals != null) {
vNormal = vNormals[radialCount];
} else if (radius == radius2) {
vNormal = tempNormal;
}
if (topBottom == 0) {
if (!inverted)
nb.put(vNormal.x).put(vNormal.y).put(vNormal.z);
else
nb.put(-vNormal.x).put(-vNormal.y).put(-vNormal.z);
} else {
nb.put(0).put(0).put(topBottom * (inverted ? -1 : 1));
}
tempNormal.multLocal((radius - radius2) * axisFraction + radius2).addLocal(sliceCenter);
pb.put(tempNormal.x).put(tempNormal.y).put(tempNormal.z);
tb.put((inverted ? 1 - radialFraction : radialFraction)).put(axisFractionTexture);
}
BufferUtils.copyInternalVector3(pb, save, i);
BufferUtils.copyInternalVector3(nb, save, i);
tb.put((inverted ? 0.0f : 1.0f)).put(axisFractionTexture);
}
if (closed) {
// bottom center
pb.put(0).put(0).put(-halfHeight);
nb.put(0).put(0).put(-1 * (inverted ? -1 : 1));
tb.put(0.5f).put(0);
// top center
pb.put(0).put(0).put(halfHeight);
nb.put(0).put(0).put(1 * (inverted ? -1 : 1));
tb.put(0.5f).put(1);
}
IndexBuffer ib = getIndexBuffer();
int index = 0;
// Connectivity
for (int axisCount = 0, axisStart = 0; axisCount < axisSamples - 1; axisCount++) {
int i0 = axisStart;
int i1 = i0 + 1;
axisStart += radialSamples + 1;
int i2 = axisStart;
int i3 = i2 + 1;
for (int i = 0; i < radialSamples; i++) {
if (closed && axisCount == 0) {
if (!inverted) {
ib.put(index++, i0++);
ib.put(index++, vertCount - 2);
ib.put(index++, i1++);
} else {
ib.put(index++, i0++);
ib.put(index++, i1++);
ib.put(index++, vertCount - 2);
}
} else if (closed && axisCount == axisSamples - 2) {
ib.put(index++, i2++);
ib.put(index++, inverted ? vertCount - 1 : i3++);
ib.put(index++, inverted ? i3++ : vertCount - 1);
} else {
ib.put(index++, i0++);
ib.put(index++, inverted ? i2 : i1);
ib.put(index++, inverted ? i1 : i2);
ib.put(index++, i1++);
ib.put(index++, inverted ? i2++ : i3++);
ib.put(index++, inverted ? i3++ : i2++);
}
}
}
updateBound();
setStatic();
}
Aggregations