package gl.scenegraph;
import gl.GLUtilityClass;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import javax.microedition.khronos.opengles.GL10;
import util.Vec;
public class RenderData {
private static final String LOG_TAG = "RenderData";
protected FloatBuffer vertexBuffer;
protected int verticesCount;
protected FloatBuffer normalsBuffer;
public int drawMode = GL10.GL_TRIANGLES;
/**
* call whenever a {@link Shape} changes
*
* @param shape
*/
public void updateShape(ArrayList<Vec> shape) {
setVertexArray(turnShapeToFloatArray(shape));
normalsBuffer = getNormalsBuffer(shape);
}
private FloatBuffer getNormalsBuffer(ArrayList<Vec> shape) {
// don't use normals if the shape does not consist of triangles:
if (shape.size() % 3 != 0)
return null;
/*
* This will take always 3 vecs and calculate the normal of the triangle
* defined by these 3 vecs. So the size of the float array has to be
* shapesize *3 ! to store the x y and z value of the normal vector
*/
float[] normalsArray = new float[shape.size() * 3];
int currentNormalsIndex = 0;
// Log.d(LOG_TAG, "shape.size()=" + shape.size());
for (int i = 0; i < shape.size(); i += 3) {
Vec v1 = Vec.sub(shape.get(i), shape.get(i + 1));
Vec v2 = Vec.sub(shape.get(i), shape.get(i + 2));
Vec normalVec = Vec.calcNormalVec(v1, v2).normalize();
/*
* TODO implement Newell's Method to have a more general approach:
* http://www.opengl.org/wiki/Calculating_a_Surface_Normal
*/
// Log.d(LOG_TAG, " >" + i + " u=" + v1);
// Log.d(LOG_TAG, " >" + i + " v=" + v2);
// Log.d(LOG_TAG, " >" + i + " normal=" + normalVec);
/*
* each vertex neads an own normal vector!
*/
currentNormalsIndex = addNormalVectorForVertex(normalsArray,
currentNormalsIndex, normalVec);
currentNormalsIndex = addNormalVectorForVertex(normalsArray,
currentNormalsIndex, normalVec);
currentNormalsIndex = addNormalVectorForVertex(normalsArray,
currentNormalsIndex, normalVec);
}
return GLUtilityClass.createAndInitFloatBuffer(normalsArray);
}
private int addNormalVectorForVertex(float[] normalsArray, int j,
Vec normalVec) {
normalsArray[j] = normalVec.x;
j++;
normalsArray[j] = normalVec.y;
j++;
normalsArray[j] = normalVec.z;
j++;
return j;
}
public void setVertexArray(float[] floatArray) {
vertexBuffer = GLUtilityClass.createAndInitFloatBuffer(floatArray);
}
public void setNormalsBuffer(FloatBuffer normalsBuffer) {
this.normalsBuffer = normalsBuffer;
}
public void setDrawModeToTriangles() {
drawMode = GL10.GL_TRIANGLES;
}
public void setDrawModeToLines() {
drawMode = GL10.GL_LINES;
}
protected RenderData() {
}
protected float[] turnShapeToFloatArray(ArrayList<Vec> shape) {
float[] vertices = new float[shape.size() * 3];
verticesCount = shape.size();
int i = 0;
for (Vec v : shape) {
i = addNormalVectorForVertex(vertices, i, v);
}
return vertices;
}
/*
* (non-Javadoc)
*
* @see gl.Renderable#draw(javax.microedition.khronos.opengles.GL10)
*/
public void draw(GL10 gl) {
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
if (normalsBuffer != null) {
// Enable normals array (for lightning):
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glNormalPointer(GL10.GL_FLOAT, 0, normalsBuffer);
}
gl.glDrawArrays(drawMode, 0, verticesCount);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
// Disable normals array (for lightning):
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
}