// lag effect of loading a scene larger than the video RAM. Indeed, when using JVM
// memory, the sanction is immediate : the scene becomes quite impossible to manipulate.
// With NIO buffers, there is a progressive degradation of performances when the scene
// doesn't fit entirely in the 3D card RAM.
DoubleBuffer nioCoords = ByteBuffer.allocateDirect(triangles.length*3 * 8).order(ByteOrder.nativeOrder()).asDoubleBuffer();
FloatBuffer nioColors = ByteBuffer.allocateDirect(triangles.length*3 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
FloatBuffer nioNormals = ByteBuffer.allocateDirect(triangles.length * 3 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
// Set up the coordinates loaded by the parent method into the
// NIO buffers.
// This also expand the geometry. The file is described in indexed mode : triangles
// are defined by indexing points.
// Java3D also has an indexed mode, and using it would be immediate.
// Unfortunately, when using an indexed mode, the triangle vertices are shared by definition.
// It is thus not possible to change the values for the vertices for only one triangle
// For example, when highlighting a triangle, it is necessary to modify the colors of
// this triangle only, not its neighbors.
// On the other hand, if picking/highlighting was done on vertices only, then modifying
// all triangles using this vertex could be a good idea.
// In this example, a triangle is picked, and the closest vertex is also shown, but
// highlighted only in this triangle. This is not that complicated, but shows potential
// problems. One should thus be able to easily adapt this example to simpler cases.
for (int i=0; i<triangles.length; i+=3) {
int pt = triangles[i];
nioCoords.put(data[0][pt]);
nioCoords.put(data[1][pt]);
nioCoords.put(data[2][pt]);
pt = triangles[i+1];
nioCoords.put(data[0][pt]);
nioCoords.put(data[1][pt]);
nioCoords.put(data[2][pt]);
pt = triangles[i+2];
nioCoords.put(data[0][pt]);
nioCoords.put(data[1][pt]);
nioCoords.put(data[2][pt]);
}
// Create a triangle array using NIO.
// Unfortunately, Sun picking utilities don't handle NIO very well, thus
// we need to overload a method
TriangleArray ta = new TriangleArray(triangles.length, GeometryArray.BY_REFERENCE|GeometryArray.USE_NIO_BUFFER|GeometryArray.COORDINATES|GeometryArray.NORMALS|GeometryArray.COLOR_3) {
public double[] getCoordRefDouble() {
// When picking, tests have shown that NIO buffer copy has no noticeable impact
// on performance. So, it is actually better to copy the array each time the picking is
// done than to hog memory with a permanent copy.
// It is also still better to copy the buffer only when picking rather than at each rendering
double[] array = new double[getVertexCount()*3];
DoubleBuffer db = (DoubleBuffer)super.getCoordRefBuffer().getBuffer();
db.rewind();
db.get(array); // optimized get
return array;
}
};
ta.setCoordRefBuffer(new J3DBuffer(nioCoords));
// Use Java3D utilities to compute normals
GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
double[] coords = new double[data[0].length*3];
nioCoords.position(0);
nioCoords.get(coords);
gi.setCoordinates(coords);
// generate normals
NormalGenerator ng = new NormalGenerator();
ng.generateNormals(gi);
Vector3f[] n3f = gi.getNormals();
int[] ni = gi.getNormalIndices();
float[] tmp = new float[3];
for (int i=0; i<ni.length; ++i) {
n3f[ni[i]].get(tmp);
nioNormals.put(tmp);
}
ta.setNormalRefBuffer(new J3DBuffer(nioNormals));
// Setup color buffer
ta.setColorRefBuffer(new J3DBuffer(nioColors));