Poser Mesh with openGL 1.0, 50 % of Triangles seem to miss - java

I generated a 3D model with Poser to use it with openGL 1.0 in a Android Application. When I render the mesh I can see the 3D Model as generated in Poser 8, but unfortunately only half of the triangles are rendered - it look like I have to draw some kind of squares instead. Is there any method to mirror the existing triangles so I can draw the missing ones?
My mesh is generated from a wavefront object. Therefor I use a class called Mesh
public final class Mesh {
public enum PrimitiveType {
Points,
Lines,
Triangles,
LineStrip,
TriangleStrip,
TriangleFan
}
// gl instance
private GL10 gl;
// vertex position buffer, array
private float vertices[];
private int vertexHandle;
private FloatBuffer vertexBuffer;
// color buffer, array
private float colors[];
private int colorHandle;
private FloatBuffer colorBuffer;
// texture coordinate buffer, array
private float texCoords[];
private int texHandle;
private FloatBuffer texBuffer;
// normal (for illumination) buffer, array
private float normals[];
private int normalHandle;
private FloatBuffer normalBuffer;
// index where next vertices will be inserted
private int index = 0;
// number vertices for mesh
private int numVertices = 0;
// renderer support vbos
private boolean globalVBO = true;
// is mesh dirty
private boolean dirty = true;
// last mesh
private static Mesh lastMesh;
// mesh count
public static int numMeshes = 0;
/**
* after calling constructor first set attribute (color, texture, normal), then fix the vertex by calling vertex(...)
*
* #param gl GL10
* #param numVertices number vertices of mesh
* #param hasColors using colors?
* #param hasTextureCoordinates using textures coordinates
* #param hasNormals using normals?
*/
public Mesh(GL10 gl, int numVertices, boolean hasColors, boolean hasTextureCoordinates, boolean hasNormals) {
this.gl = gl;
vertices = new float[numVertices * 3];
int[] buffer = new int[1];
if (!globalVBO) {
vertexBuffer = allocateBuffer(numVertices * 3);
} else {
((GL11) gl).glGenBuffers(1, buffer, 0);
vertexHandle = buffer[0];
vertexBuffer = FloatBuffer.wrap(vertices);
}
if (hasColors) {
colors = new float[numVertices * 4];
if (!globalVBO) {
colorBuffer = allocateBuffer(numVertices * 3);
} else {
((GL11) gl).glGenBuffers(1, buffer, 0);
colorHandle = buffer[0];
colorBuffer = FloatBuffer.wrap(colors);
}
}
if (hasTextureCoordinates) {
texCoords = new float[numVertices * 2];
if (!globalVBO) {
texBuffer = allocateBuffer(numVertices * 3);
} else {
((GL11) gl).glGenBuffers(1, buffer, 0);
texHandle = buffer[0];
texBuffer = FloatBuffer.wrap(texCoords);
}
}
if (hasNormals) {
normals = new float[numVertices * 3];
if (!globalVBO) {
normalBuffer = allocateBuffer(numVertices * 3);
} else {
((GL11) gl).glGenBuffers(1, buffer, 0);
normalHandle = buffer[0];
normalBuffer = FloatBuffer.wrap(normals);
}
}
}
/**
* allocates FloatBuffer of size
*
* #param size size number of floats
* #return FloatBuffer
*/
private FloatBuffer allocateBuffer(int size) {
ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4);
buffer.order(ByteOrder.nativeOrder());
return buffer.asFloatBuffer();
}
/**
* renders mesh given type, starts at offset wirh numVertices vertices
*
* #param type PrimitiveType (see above)
* #param offset offset in number of vertices
* #param numVertices number of vertices to use
*/
public void render(PrimitiveType type, int offset, int numVertices) {
boolean wasDirty = dirty;
if (dirty) {
update();
}
if (this == lastMesh && !wasDirty) {
gl.glDrawArrays(getPrimitiveType(type), offset, numVertices);
return;
} else {
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
if (globalVBO) {
((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexHandle);
((GL11) gl).glVertexPointer(3, GL10.GL_FLOAT, 0, 0);
} else {
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
}
if (colors != null) {
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
if (globalVBO) {
((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, colorHandle);
((GL11) gl).glColorPointer(4, GL10.GL_FLOAT, 0, 0);
} else
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
}
if (texCoords != null) {
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
if (globalVBO) {
((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, texHandle);
((GL11) gl).glTexCoordPointer(2, GL10.GL_FLOAT, 0, 0);
} else
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer);
}
if (normals != null) {
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
if (globalVBO) {
((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, normalHandle);
((GL11) gl).glNormalPointer(GL10.GL_FLOAT, 0, 0);
} else
gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer);
}
gl.glDrawArrays(getPrimitiveType(type), offset, numVertices);
lastMesh = this;
}
/**
* renders mesh as given type with numVertices from calling vertex()
*
* #param type PrimitveType
*/
public void render(PrimitiveType type) {
render(type, 0, numVertices);
}
/**
* returns openGL constant of PrimitiveType
*
* #param type PrimitiveType (enum above)
* #return openGL constant
*/
private int getPrimitiveType(PrimitiveType type) {
if (type == PrimitiveType.Lines) {
return GL10.GL_LINES;
} else if (type == PrimitiveType.Triangles) {
return GL10.GL_TRIANGLES;
} else if (type == PrimitiveType.LineStrip) {
return GL10.GL_LINE_STRIP;
} else if (type == PrimitiveType.TriangleStrip) {
return GL10.GL_TRIANGLE_STRIP;
} else if (type == PrimitiveType.Points) {
return GL10.GL_POINTS;
} else {
return GL10.GL_TRIANGLE_FAN;
}
}
/**
* updates the direct buffers in case the user
*/
private void update() {
if (!globalVBO) {
vertexBuffer.put(vertices);
vertexBuffer.position(0);
if (colors != null) {
colorBuffer.put(colors);
colorBuffer.position(0);
}
if (texCoords != null) {
texBuffer.put(texCoords);
texBuffer.position(0);
}
if (normals != null) {
normalBuffer.put(normals);
normalBuffer.position(0);
}
} else {
GL11 gl = (GL11) this.gl;
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexHandle);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertices.length * 4, vertexBuffer, GL11.GL_DYNAMIC_DRAW);
if (colors != null) {
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorHandle);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colors.length * 4, colorBuffer, GL11.GL_DYNAMIC_DRAW);
}
if (normals != null) {
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, normalHandle);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, normals.length * 4, normalBuffer, GL11.GL_DYNAMIC_DRAW);
}
if (texCoords != null) {
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, texHandle);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, texCoords.length * 4, texBuffer, GL11.GL_DYNAMIC_DRAW);
}
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
}
numVertices = index;
index = 0;
dirty = false;
}
/**
* defines position of current vertex, before calling call method like color, normal or texCoord
*
* #param x x coordinate
* #param y y coordinate
* #param z z coordinate
*/
public void vertex(float x, float y, float z) {
dirty = true;
int offset = index * 3;
vertices[offset] = x;
vertices[offset + 1] = y;
vertices[offset + 2] = z;
index++;
}
/**
* sets color of current vertex
*
* #param r red
* #param g green
* #param b blue
* #param a alpha
*/
public void color(float r, float g, float b, float a) {
dirty = true;
int offset = index * 4;
colors[offset] = r;
colors[offset + 1] = g;
colors[offset + 2] = b;
colors[offset + 3] = a;
}
/**
* sets the normal of current vertex
*
* #param x x components
* #param y y components
* #param z z components
*/
public void normal(float x, float y, float z) {
dirty = true;
int offset = index * 3;
normals[offset] = x;
normals[offset + 1] = y;
normals[offset + 2] = z;
}
/**
* sets texture coordinates of current vertex
*
* #param s s coordinate (correlates x)
* #param t t coordinate (correlates y)
*/
public void texCoord(float s, float t) {
dirty = true;
int offset = index * 2;
texCoords[offset] = s;
texCoords[offset + 1] = t;
}
/**
* deletes all buffers, sets all attributes to null
*/
public void dispose() {
if (globalVBO) {
GL11 gl = (GL11) this.gl;
if (vertexHandle != -1)
gl.glDeleteBuffers(1, new int[]{vertexHandle}, 0);
if (colorHandle != -1)
gl.glDeleteBuffers(1, new int[]{colorHandle}, 0);
if (normalHandle != -1)
gl.glDeleteBuffers(1, new int[]{normalHandle}, 0);
if (texHandle != -1)
gl.glDeleteBuffers(1, new int[]{texHandle}, 0);
}
vertices = null;
vertexBuffer = null;
colors = null;
colorBuffer = null;
normals = null;
normalBuffer = null;
texCoords = null;
texBuffer = null;
numMeshes--;
}
/**
* #return number of vertices
*/
public int getMaximumVertices() {
return vertices.length / 3;
}
/**
* resets index
*/
public void reset() {
dirty = true;
index = 0;
}
}
and a class called MeshLoader
public class MeshLoader {
/**
*
* Loads a mesh from the given InputStream
* #param gl GL10 instance
* #return The mesh
*/
public static Mesh loadObj( GL10 gl, InputStream in )
{
String line = "";
try
{
BufferedReader reader = new BufferedReader( new InputStreamReader(in) );
StringBuffer b = new StringBuffer();
String l = reader.readLine();
while( l != null )
{
b.append( l );
b.append( "\n" );
l = reader.readLine();
}
line = b.toString();
reader.close();
}
catch( Exception ex )
{
throw new RuntimeException(ex.getMessage() + " " +
"couldn't load file mesh from input stream" );
}
return loadObjFromString( gl, line );
}
/**
* Loads a mesh from the given string in obj format
*
* #param obj The string
* #return The Mesh
*/
public static Mesh loadObjFromString( GL10 gl, String obj )
{
String[] lines = obj.split( "\n" );
float[] vertices = new float[lines.length * 3];
float[] normals = new float[lines.length * 3];
float[] uv = new float[lines.length * 3];
int numVertices = 0;
int numNormals = 0;
int numUV = 0;
int numFaces = 0;
int[] facesVerts = new int[lines.length * 3];
int[] facesNormals = new int[lines.length * 3];
int[] facesUV = new int[lines.length * 3];
int vertexIndex = 0;
int normalIndex = 0;
int uvIndex = 0;
int faceIndex = 0;
for( int i = 0; i < lines.length; i++ )
{
String line = lines[i];
if( line.startsWith( "v " ) )
{
String[] tokens = line.split( " " );
vertices[vertexIndex] = Float.parseFloat(tokens[1]);
vertices[vertexIndex+1] = Float.parseFloat(tokens[2]);
vertices[vertexIndex+2] = Float.parseFloat(tokens[3]);
vertexIndex += 3;
numVertices++;
continue;
}
if( line.startsWith( "vn " ) )
{
String[] tokens = line.split( " " );
normals[normalIndex] = Float.parseFloat(tokens[1]);
normals[normalIndex+1] = Float.parseFloat(tokens[2]);
normals[normalIndex+2] = Float.parseFloat(tokens[3]);
normalIndex += 3;
numNormals++;
continue;
}
// coords of each texture point
if( line.startsWith( "vt" ) )
{
String[] tokens = line.split( " " );
uv[uvIndex] = Float.parseFloat(tokens[1]);
uv[uvIndex+1] = Float.parseFloat(tokens[2]);
uvIndex += 2;
numUV++;
continue;
}
if( line.startsWith( "f " ) )
{
String[] tokens = line.split( " " );
String[] parts = tokens[1].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
facesNormals[faceIndex] = getIndex(parts[2], numNormals);
facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
parts = tokens[2].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
facesNormals[faceIndex] = getIndex(parts[2], numNormals);
facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
parts = tokens[3].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
facesNormals[faceIndex] = getIndex(parts[2], numNormals);
facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
numFaces++;
continue;
}
}
Mesh mesh = new Mesh(gl, numFaces * 3, false ,numUV > 0, numNormals > 0 );
for( int i = 0; i < numFaces*3; i++ )
{
if( numNormals > 0 )
{
int normalIdx = facesNormals[i] * 3;
mesh.normal( normals[normalIdx], normals[normalIdx+1], normals[normalIdx+2] );
}
if( numUV > 0 )
{
int uvIdx = facesUV[i] * 2;
mesh.texCoord( uv[uvIdx], uv[uvIdx+1]);
}
int vertexIdx = facesVerts[i] *3;
mesh.vertex( vertices[vertexIdx], vertices[vertexIdx+1], vertices[vertexIdx+2] );
}
return mesh;
}
private static int getIndex( String index, int size )
{
if( index == null || index.length() == 0 )
return 0;
int idx = Integer.parseInt( index );
if( idx < 0 )
return size + idx;
else
return idx - 1;
}
}
every 3D Object is a Mesh and will be generated by the MeshLoader.loadObject Method.
This works perfectly with simple Objects. But not with 3D Models generated by Poser 8.
Does anyone have an idea, how to solve this problem?

I solved it.
I triangulated the Mesh and reduced the number of vertices under 32.000. Therefor I exported the Mesh from Poser as Collada-File and imported it to Blender (because there are more tutorials :D).

Related

How to change specific part of vbo?

I have recently created 2D height map grid which generates 3D terrain mesh for my world With the ability to add hills/bumps with mouse click events during runtime. My Problem is that every time i add to the height of the vertices i update the whole terrain's normal and position vbos(very not efficient). what is the way to
change specific part of vbo?
I have heared that glBufferSubData is the way, but How can i change only the Y value? (the vbo is x,y,z,x,y,z...)
and get the changed verticies in order for glBufferSubData?
Terrain class:
public class Terrain {
public static final int SIZE = 500;
//VAO, vertexCount, VBOS
private RawModel model;
//textures for the terrain
private terrainTexturePack texturePack;
Loader loader;
private static int VERTEX_COUNT =128;
float[] Vertices;
float[] Normals;
float[] TextureCoords;
int[] Indices;
private float[][] heights;
public Terrain(Loader loader, terrainTexturePack texturePack) {
this.texturePack = texturePack;
this.loader = loader;
this.model = generateTerrain(loader);
}
public RawModel getModel() {
return model;
}
public terrainTexturePack getTexturePack() {
return texturePack;
}
//player collision detection witn the terrain
public Vector3f getXYZOfTerrain(float worldX, float worldZ) {
float gridSquareSize = SIZE / ((float) heights.length - 1);
int gridX = (int) Math.floor(worldX / gridSquareSize);
int gridZ = (int) Math.floor(worldZ / gridSquareSize);
if(gridX >= heights.length - 1 || gridZ >= heights.length - 1 || gridX < 0 || gridZ < 0) {
return null;
}
float xCoord = (worldX % gridSquareSize)/gridSquareSize;
float zCoord = (worldZ % gridSquareSize)/gridSquareSize;
float yCoord;
if (xCoord <= (1-zCoord)) {
yCoord = Maths.barryCentric(new Vector3f(0, heights[gridX][gridZ], 0), new Vector3f(1,
heights[gridX + 1][gridZ], 0), new Vector3f(0,
heights[gridX][gridZ + 1], 1), new Vector2f(xCoord, zCoord));
} else {
yCoord = Maths.barryCentric(new Vector3f(1, heights[gridX + 1][gridZ], 0), new Vector3f(1,
heights[gridX + 1][gridZ + 1], 1), new Vector3f(0,
heights[gridX][gridZ + 1], 1), new Vector2f(xCoord, zCoord));
}
return new Vector3f(gridX, yCoord, gridZ);
}
//GENERATE THE TERRAIN
private RawModel generateTerrain(Loader loader) {
int pointer = 0;
int count = VERTEX_COUNT * VERTEX_COUNT;
heights = new float[VERTEX_COUNT][VERTEX_COUNT];
float[] vertices = new float[count * 3];
float[] normals = new float[count * 3];
float[] textureCoords = new float[count * 2];
int[] indices = new int[6 * (VERTEX_COUNT - 1) * (VERTEX_COUNT * 1)];
int vertexPointer = 0;
for (int i = 0; i < VERTEX_COUNT; i++) {
for (int j = 0; j < VERTEX_COUNT; j++) {
vertices[vertexPointer * 3] = (float) j / ((float) VERTEX_COUNT - 1) * SIZE;
float height = 0f;
vertices[vertexPointer * 3 + 1] = height;
heights[j][i] = height;
vertices[vertexPointer * 3 + 2] = (float) i / ((float) VERTEX_COUNT - 1) * SIZE;
Vector3f normal =new Vector3f(0, 1, 0);// calculateNormal(j, i, noise);
normals[vertexPointer * 3] = normal.x;
normals[vertexPointer * 3 + 1] = normal.y;
normals[vertexPointer * 3 + 2] = normal.z;
textureCoords[vertexPointer * 2] = (float) j / ((float) VERTEX_COUNT - 1);
textureCoords[vertexPointer * 2 + 1] = (float) i / ((float) VERTEX_COUNT - 1);
vertexPointer++;
if(i < VERTEX_COUNT - 1 && j < VERTEX_COUNT - 1){
int topLeft = (i * VERTEX_COUNT) + j;
int topRight = topLeft + 1;
int bottomLeft = ((i + 1) * VERTEX_COUNT) + j;
int bottomRight = bottomLeft + 1;
indices[pointer++] = topLeft;
indices[pointer++] = bottomLeft;
indices[pointer++] = topRight;
indices[pointer++] = topRight;
indices[pointer++] = bottomLeft;
indices[pointer++] = bottomRight;
}
}
}
Vertices = vertices;
TextureCoords = textureCoords;
Normals = normals;
Indices = indices;
return loader.loadToVAO(vertices, textureCoords, normals, indices);
}
//Calculate normal
private Vector3f calculateNormal(int x, int z) {
float heightL = Vertices[((( (z) *VERTEX_COUNT)+ (x-1) )*3)+1];
float heightR = Vertices[((( (z) *VERTEX_COUNT)+ (x+1) )*3)+1];
float heightD = Vertices[((( (z-1) *VERTEX_COUNT)+ (x) )*3)+1];
float heightU = Vertices[((( (z+1) *VERTEX_COUNT)+ (x) )*3)+1];
Vector3f normal = new Vector3f(heightL - heightR, 2f, heightD - heightU);
normal.normalise();
return normal;
}
//create mountain where the mouse clicked
//Vertices[(((y*VERTEX_COUNT)+x)*3)+1] = one Vertex in 2d grid
public void createHill(int x0, int y0){
float h = 0.06f;
int xs=VERTEX_COUNT;
int ys=VERTEX_COUNT;
float maxHeight =Vertices[(((y0*xs)+x0)*3)+1]+h;
float r = (9*maxHeight)/30;
//Loop the vertices
for(int y=(int) (y0-r);y<=y0+r;y++)
for(int x=(int) (x0-r);x<=x0+r;x++){
double circule = Math.sqrt((x-x0)*(x-x0)+(y0-y)*(y0-y));
if (circule <= r)
if ((x>=1)&&(x<xs-1))
if ((y>=1)&&(y<ys-1)){
Vertices[(((y*xs)+x)*3)+1] = Maths.hillsHeight(x0, x, y0, y,(maxHeight), r);
Vector3f normal = calculateNormal(x,y);
Normals[((((y*xs)+x))) * 3] = normal.x;
Normals[((((y*xs)+x))) * 3 + 1] = normal.y;
Normals[((((y*xs)+x))) * 3 + 2] = normal.z;
}
}
//change the whole VBO's not effective
//Note: i know that i dont need to update textures and indices
this.model=loader.loadToVAO(Vertices, TextureCoords, Normals, Indices);
}
}
Raw model class(vbo and vao holder):
//Store the VAOS and VBOS
public class RawModel {
private int vaoID;
private int vertexCount;
private int positionVbo;
private int normalVbo;
private int textureVbo;
public RawModel(int vaoID, int vertexCount, int positionVbo, int normalVbo, int textureVbo) {
this.vaoID = vaoID;
this.vertexCount = vertexCount;
this.positionVbo = positionVbo;
this.normalVbo = normalVbo;
this.textureVbo = textureVbo;
}
public RawModel(int vaoID, int vertexCount) {
this.vaoID = vaoID;
this.vertexCount = vertexCount;
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return vertexCount;
}
public int getPositionVbo() {
return positionVbo;
}
public int getTextureVbo() {
return textureVbo;
}
public int getNormalVbo() {
return normalVbo;
}
}
loader class:
public class Loader {
//For clean up
private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();
private List<Integer> textures = new ArrayList<Integer>();
//Load mesh into VAO
public RawModel loadToVAO(float[] positions,float[] textureCoords,float[] normals,int[] indices){
int vaoID = createVAO();
bindIndicesBuffer(indices);
int positionvbo = storeDataInAttributeList(0,3,positions);
int textureVbo = storeDataInAttributeList(1,2,textureCoords);
int normalsnvbo = storeDataInAttributeList(2,3,normals);
unbindVAO();
return new RawModel(vaoID,indices.length, positionvbo, textureVbo, normalsnvbo);
}
//Load texture
public int loadTexture(String fileName) {
Texture texture = null;
try {
texture = TextureLoader.getTexture("PNG",
new FileInputStream("res/textures/" + fileName + ".png"));
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
GL11.GL_LINEAR_MIPMAP_LINEAR);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, -2);
if(GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){
float amount = Math.min(4f,
GL11.glGetFloat(EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT));
GL11.glTexParameterf(GL11.GL_TEXTURE_2D,
EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, amount);
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("Tried to load texture " + fileName + ".png , didn't work");
System.exit(-1);
}
textures.add(texture.getTextureID());
return texture.getTextureID();
}
//Clean up
public void cleanUp(){
for(int vao:vaos){
GL30.glDeleteVertexArrays(vao);
}
for(int vbo:vbos){
GL15.glDeleteBuffers(vbo);
}
for(int texture:textures){
GL11.glDeleteTextures(texture);
}
}
//Creates vao
private int createVAO(){
int vaoID = GL30.glGenVertexArrays();
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
//Store data in vbo
private int storeDataInAttributeList(int attributeNumber, int coordinateSize,float[] data){
int vboID = GL15.glGenBuffers();
vbos.add(vboID);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = storeDataInFloatBuffer(data);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(attributeNumber,coordinateSize,GL11.GL_FLOAT,false,0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
return vboID;
}
private void unbindVAO(){
GL30.glBindVertexArray(0);
}
//Bind indices buffer
private void bindIndicesBuffer(int[] indices){
int vboID = GL15.glGenBuffers();
vbos.add(vboID);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboID);
IntBuffer buffer = storeDataInIntBuffer(indices);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
}
//Store in int buffer
private IntBuffer storeDataInIntBuffer(int[] data){
IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
//Store in float buffer
private FloatBuffer storeDataInFloatBuffer(float[] data){
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
//Load skyBox textures
public int loadCubeMap(String[] textureFiles){
int texID = GL11.glGenTextures();
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texID);
for(int i = 0; i < textureFiles.length; i++){
TextureData data = decodeTextureFile("res/textures/"+ textureFiles[i] + ".png");
GL11.glTexImage2D(GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, 0, GL11.GL_RGBA, data.getWidth(), data.getHeight(), 0,
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, data.getBuffer());
}
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
textures.add(texID);
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
return texID;
}
private TextureData decodeTextureFile(String fileName) {
int width = 0;
int height = 0;
ByteBuffer buffer = null;
try {
FileInputStream in = new FileInputStream(fileName);
PNGDecoder decoder = new PNGDecoder(in);
width = decoder.getWidth();
height = decoder.getHeight();
buffer = ByteBuffer.allocateDirect(4 * width * height);
decoder.decode(buffer, width * 4, Format.RGBA);
buffer.flip();
in.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("Tried to load texture " + fileName + ", didn't work");
System.exit(-1);
}
return new TextureData(buffer, width, height);
}
//Load textures for GUI
public RawModel loadToVAO(float[] positions, int dimensions) {
int vaoID = createVAO();
this.storeDataInAttributeList(0, dimensions, positions);
unbindVAO();
return new RawModel(vaoID, positions.length / dimensions);
}
}
Solved Thank to Reto Koradi
public void changeVbo(int position, float[] data, int VboId){
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, VboId);
FloatBuffer ArrayData = storeDataInFloatBuffer(data);
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER,position * 4, ArrayData);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
The easiest and likely most efficient way is to store the heights (y-values) in a separate VBO, and specify them as a separate vertex attribute.
Then, in your vertex shader code, you can simply reassemble the position from the separate attributes. You might have something like this in your shader code now:
in vec3 pos;
This changes to:
in vec3 posXZ;
in float posY;
...
vec3 pos = vec3(posXZ.x, posY, posXZ.y);
Using a separate VBO for data that changes frequently also allows you to specify the allocation flags accordingly. You can use GL_DYNAMIC_DRAW for the data that changes frequently, GL_STATIC_DRAW for the rest.
Another option would be to use glMapBuffer(). This gives you a CPU pointer to the buffer content, allowing you to modify only the data that you actually want to change. However, you'll have to be careful that you don't introduce undesirable synchronization between CPU and GPU. The glMapBuffer() call might block until the GPU finished all rendering calls using the previous content of the buffer. One common technique is to use multiple copies of the data in a set of buffers, and cycle through them, to minimize synchronization. But if the amount of data is large, that will obviously cause memory usage to increase dramatically.
In your use case, I suspect that you'll have to update the normals as well, since they depend on the height values.

OpenGL/Java slicing dataset and plotting it

My task is to create an OpenGL Java program which will load a dataset, and then display an orthogonal slice of said data on the X, Y and Z axis. I'm new to OpenGL and I've been having trouble with plotting the data. The class to load the dataset has been provided for me:
public class VolumetricDataSet {
private final int[] dimensions;
private int maxValue;
private int minValue;
private final int[][][] volumeData;
/**
* Construct a new dataset from a File.
*
* #param in
* the file to read the data from.
* #param xSize
* the maximal x dimension to use.
* #param ySize
* the maximal y dimension to use.
* #param zSize
* the maximal z dimension to use.
* #throws IOException
* if the underlying reader encounters an error.
* #throws FileNotFoundException
* if the file cannot be found.
*/
public VolumetricDataSet(final File in, final int xSize, final int ySize,
final int zSize) throws IOException, FileNotFoundException {
this(new FileInputStream(in), xSize, ySize, zSize);
}
/**
* Construct a new dataset.
*
* #param in
* the stream to read the data from.
* #param xSize
* the maximal x dimension to use.
* #param ySize
* the maximal y dimension to use.
* #param zSize
* the maximal z dimension to use.
* #throws IOException
* if the underlying reader encounters an error.
*/
public VolumetricDataSet(final InputStream in, final int xSize,
final int ySize, final int zSize) throws IOException {
int value = 0, xCur = 0, yCur = 0, zCur = 0;
volumeData = new int[xSize][ySize][zSize];
while ((value = in.read()) != -1) {
volumeData[xCur][yCur][zCur] = value;
if (value > maxValue)
maxValue = value;
if (value < minValue)
minValue = value;
if (++xCur == xSize) {
xCur = 0;
if (++yCur == ySize) {
yCur = 0;
zCur++;
}
}
}
dimensions = new int[] { xSize, ySize, zSize };
}
/**
* Retrieve the length of the x y z dimensions of the data set. 3 element array
*
* #return the dimensions.
*/
public int[] getDimensions()
{
return dimensions;
}
/**
* #return the maximal value
*/
public int getMaxValue()
{
return maxValue;
}
/**
* #return the minimal value.
*/
public int getMinValue()
{
return minValue;
}
/**
* #return the entire data set as a 3-D array. x is the 1st dimension, y the
* 2nd and z the 3rd.
*/
public int[][][] getVolumeData()
{
return volumeData;
}
}
My code to display the data:
VolumetricDataSet ds = new VolumetricDataSet(new File("C:\\Users\\Me\\Desktop\\Work\\Comp Graphics\\marschnerlobb.raw.gz"), 41, 41, 41);
int[][][] volumeData = ds.getVolumeData();
int[] dimensions = ds.getDimensions();
for(int i = 0; i < dimensions[0]; i++)
{
for(int j = 0; j < dimensions[1]; j++)
{
if(volumeData[i][j][0] < 1)
{
gl.glColor3f(0.0f,0.0f,0.0f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 40)
{
gl.glColor3f(0.0f,0.0f,0.1f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 80)
{
gl.glColor3f(0.0f,0.0f,0.2f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 120)
{
gl.glColor3f(0.0f,0.0f,0.3f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 160)
{
gl.glColor3f(0.0f,0.0f,0.4f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 200)
{
gl.glColor3f(0.0f,0.0f,0.5f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 240)
{
gl.glColor3f(0.0f,0.0f,0.6f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
else if(volumeData[i][j][0] < 280)
{
gl.glColor3f(0.0f,0.0f,0.7f);
gl.glPointSize(10);
gl.glBegin(GL.GL_POINTS);
gl.glVertex2i(i, j);
}
}
}
marschnerlobb.raw.gz is the dataset that I am currently using to test my program which can be found at http://www.volvis.org/
When I run the program at first I thought it was correct as it looked like it may be a a slice from the dataset I used (which resembles a square). But when I tried it with a different dataset (a skull) the result being displayed was still a square image.

How to apply color to an irregular polygon with unknown indices?

I'm having a set of vertices (X,Y) of an irregular polygon, some having 4 vertices and some more than 4. I'm creating an array of vertices for drawing from the set of vertices I have using the getTransformedVertices() method. The indices and UV for the texture are unknown so I had to calculate tem using Triangulate() method below. I've setup the color and texture in the setColor() and setImage() methods.
However, the polygons having more than 4 vertices are not rendered properly. I've been trying for weeks now and almost the searched half of the internet. This is what I could come up with. The polygons with 4 vertices and the outlines are working properly. But I couldn't get the textures displayed properly on the polygon. Please help
public class BoothRectangle
{
float angle;
float scale;
RectF base;
PointF translation;
int textureId;
int positionBufferId;
int textureBufferId;
PointF[] corners;
float[] verts;
// Geometric variables
public float vertices[];
public float colors[];
public short indices[];
public float uvs[];
public FloatBuffer vertexBuffer;
public ShortBuffer drawListBuffer;
public FloatBuffer colorBuffer;
public FloatBuffer uvBuffer;
TextPaint textPaint = new TextPaint();
String title;
public BoothRectangle(PointF[] corners, int textureId, float[] colors, String title)
{
// Initialise our intital size around the 0,0 point
base = new RectF(corners[1].x, corners[3].y, corners[0].x, corners[1].y);
this.corners = corners;
this.title = title;
// Offset translation
translation = new PointF(0f,0f);
// Initial Size
scale = 1f;
// We start in our inital angle
angle = 0f;
this.textureId = textureId;
this.colors = colors;
}
public void setColor(float[] topColor){
List<Float> colorsList = new ArrayList<Float>();
for(PointF point : corners){
colorsList.add(topColor[0] / 255);
colorsList.add(topColor[1] / 255);
colorsList.add(topColor[2] / 255);
colorsList.add(1f);
}
int i = 0;
float[] colors = new float[colorsList.size()];
for (Float f : colorsList) {
colors[i++] = (f != null ? f : Float.NaN);
}
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
int[] buffers = new int[1];
GLES11.glGenBuffers(1, buffers, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, buffers[0]);
GLES11.glBufferData(GLES11.GL_ARRAY_BUFFER, 4 * colors.length, colorBuffer, GLES11.GL_STATIC_DRAW);
textureBufferId = buffers[0];
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
}
public float[] getTransformedVertices()
{
float z;
List<Float> finalVertices = new ArrayList<Float>();
if(textureId == 0)
z = 0.5f;
else
z = 2.0f;
finalVertices.clear();
for(PointF point : corners){
finalVertices.add(point.x);
finalVertices.add(point.y);
finalVertices.add(0.0f);
}
int i = 0;
float[] verticesArray = new float[finalVertices.size()];
for (Float f : finalVertices) {
verticesArray[i++] = (f != null ? f : Float.NaN);
}
return verticesArray;
}
public void setImage()
{
uvs = new float[] {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
// The texture buffer
ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer = bb.asFloatBuffer();
uvBuffer.put(uvs);
uvBuffer.position(0);
int[] buffers = new int[1];
GLES11.glGenBuffers(1, buffers, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, buffers[0]);
GLES11.glBufferData(GLES11.GL_ARRAY_BUFFER, 4 * uvs.length, uvBuffer, GLES11.GL_STATIC_DRAW);
textureBufferId = buffers[0];
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
}
public void initBooth()
{
vertices = this.getTransformedVertices();
indices = PolygonTriangulation.Process(vertices);
if(indices==null){
Log.d("PolygonTriangulation",title + " - failed");
if(this.corners.length == 4){
indices = new short[] {2, 1, 0, 2, 0, 3};
}else{
indices = new short[corners.length];
for(int i=0;i<corners.length;i++){
indices[i] = (short) i;
}
}
}
// The vertex buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(indices);
drawListBuffer.position(0);
int[] buffers = new int[1];
GLES11.glGenBuffers(1, buffers, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, buffers[0]);
GLES11.glBufferData(GLES11.GL_ARRAY_BUFFER, 4 * vertices.length, vertexBuffer, GLES11.GL_STATIC_DRAW);
positionBufferId = buffers[0];
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
if(this.textureId !=0){
setImage();
} else {
setColor(colors);
}
}
public void Render(GL10 gl){
if(textureId == 0){
GLES11.glPushMatrix();
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, positionBufferId);
GLES11.glEnableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glVertexPointer(3, GL10.GL_FLOAT, 0, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
GLES11.glFrontFace(GL10.GL_CW);
GLES11.glColor4f(0.8f, 0.8f, 0.8f, 0.8f);
GLES11.glLineWidth(3.0f);
GLES11.glDrawArrays(GL10.GL_LINE_LOOP, 0, corners.length);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, textureBufferId);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
GLES11.glColorPointer(4, GL10.GL_FLOAT, 0, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
GLES11.glDrawElements(GL10.GL_TRIANGLES, indices.length,
GL10.GL_UNSIGNED_SHORT, drawListBuffer);
GLES11.glDisableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glDisableClientState(GL10.GL_COLOR_ARRAY);
GLES11.glPopMatrix();
} else {
GLES11.glPushMatrix();
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, positionBufferId);
GLES11.glEnableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glVertexPointer(3, GL10.GL_FLOAT, 0, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, textureBufferId);
GLES11.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
GLES11.glTexCoordPointer(2, GL10.GL_FLOAT, 0, 0);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
GLES11.glEnable(GL10.GL_TEXTURE_2D);
GLES11.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
GLES11.glEnable(GL10.GL_BLEND);
GLES11.glFrontFace(GL10.GL_CW);
GLES11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
GLES11.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
int error = gl.glGetError();
if (error != GL10.GL_NO_ERROR)
{
Log.e("OPENGL", "GL Texture Load Error: " + GLU.gluErrorString(error));
}
GLES11.glDrawElements(GL10.GL_TRIANGLES, indices.length,
GL10.GL_UNSIGNED_SHORT, drawListBuffer);
GLES11.glDisable(GL10.GL_BLEND);
GLES11.glDisableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
GLES11.glDisable(GL10.GL_TEXTURE_2D);
GLES11.glPopMatrix();
}
}
}
PolygonTriangulation.java - got from AssetFX - http://www.experts-exchange.com/Programming/Languages/Java/Q_27882746.html
public class PolygonTriangulation {
static final float EPSILON=0.0000000001f;
static public float Area(float[] contour) {
int n = contour.length;
float A = 0.0f;
for(int p = n - 3, q = 0; q < n; p=q, q+=3)
{
A += contour[p] * contour[q+1] - contour[q] * contour[p+1];
}
return A * 0.5f;
}
static public boolean InsideTriangle(float Ax,float Ay,float Bx,float By,float Cx,float Cy,float Px,float Py){
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
float cCROSSap, bCROSScp, aCROSSbp;
ax = Cx - Bx; ay = Cy - By;
bx = Ax - Cx; by = Ay - Cy;
cx = Bx - Ax; cy = By - Ay;
apx= Px - Ax; apy= Py - Ay;
bpx= Px - Bx; bpy= Py - By;
cpx= Px - Cx; cpy= Py - Cy;
aCROSSbp = ax * bpy - ay * bpx;
cCROSSap = cx * apy - cy * apx;
bCROSScp = bx * cpy - by * cpx;
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
}
static public boolean Snip(float[] contour, int u, int v, int w, int n, int[] V) {
int p;
float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
Ax = contour[V[u]];
Ay = contour[V[u+1]];
Bx = contour[V[v]];
By = contour[V[v+1]];
Cx = contour[V[w]];
Cy = contour[V[w+1]];
if ( EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ){
return false;
}
for (p = 0; p < n; p++)
{
if( (p == u/2) || (p == v/2) || (p == w/2) ){
continue;
}
Px = contour[V[p*2]];
Py = contour[V[(p*2)+1]];
if (InsideTriangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py)){
return false;
}
}
return true;
}
//Brings in 3D vertex float array but processes it as 2D only.
static public short[] Process(float[] contour) {
//Pre-return list
ArrayList<Integer> vertexArray = new ArrayList<Integer>();
/* allocate and initialize list of Vertices in polygon */
int n = contour.length;
if ( n/3 < 3 )
return null;
//The (n/3)*2 occurs as we are removing the z coordinate from the mix
int[] V = new int[(n/3)*2];
/* we want a counter-clockwise polygon in V */
if (0.0f < Area(contour)){
for (int s = 0, v = 0; v < n-1; s+=2, v += 3){
V[s] = v;
V[s + 1] = v + 1;
}
}
else{
for(int s = 0, v = 0; v < n-1; s += 2, v += 3){
V[s] = (n - 1) - (v + 2);
V[s + 1] = (n - 1) - (v + 1);
}
}
int nv = n/3;
/* remove nv-2 Vertices, creating 1 triangle every time */
int count = 2 * nv; /* error detection */
for(int v = nv - 1; nv > 2;)
{
/* if we loop, it is probably a non-simple polygon */
if (0 >= (count--))
{
//** Triangulate: ERROR - probable bad polygon!
Log.e("PolygonTriangulation","Invalid Polygon");
return null;
}
/* three consecutive vertices in current polygon, <u,v,w> */
int u = v;
if (nv <= u)
u = 0; /* previous */
v = u + 1;
if (nv <= v)
v = 0; /* new v */
int w = v + 1;
if (nv <= w)
w = 0; /* next */
if (Snip(contour, u*2, v*2, w*2, nv, V))
{
vertexArray.add(V[u*2]/3);
vertexArray.add(V[v*2]/3);
vertexArray.add(V[w*2]/3);
// remove v from remaining polygon
for(int s = v * 2, t = (v * 2) + 2; t < (nv * 2); s += 2, t += 2){
V[s] = V[t];
V[s+1] = V[t+1];
}
nv--;
// reset error detection counter
count = 2 * nv;
}
}
//Convert ArrayList into short array
short[] index = new short[vertexArray.size()];
for(int i = 0; i < vertexArray.size(); i++){
index[i] = vertexArray.get(i).shortValue();
}
return index;
}
}

OpenGL 2.0 Matrices not working

I am using Java and OpenGL (LWJGL) to setup some matrices, I didn't want to use the inbuilt methods as I also want this to work on Android and so using LWJGL's Matrix classes wouldn't be appropriate. Currently I am setting up a perspective view, using an fov of 70, znear 0.1, zfar 1000. Rotating using the current setup only results in strange results, not rotating in the correct way, and objects being scaled strangely and often disappearing.
Here is the Matrix4D class:
public class Matrix4D {
/* The values within this matrix */
public float[] values;
/* The default constructor */
public Matrix4D() {
//Create the values
this.values = new float[16];
}
/* The constructor with the values given */
public Matrix4D(float[] values) {
//Create the values
this.values = values;
}
/* The constructor with the values given */
public Matrix4D(float[][] values) {
//Load the values
load(values);
}
/* The method used to set the values given a 2 dimensional array */
public void load(float[][] values) {
this.values = new float[] {
values[0][0], values[0][1], values[0][2], values[0][3],
values[1][0], values[1][1], values[1][2], values[1][3],
values[2][0], values[2][1], values[2][2], values[2][3],
values[3][0], values[3][1], values[3][2], values[3][3]
};
}
/* The method used to get a value using the coordinate within this matrix */
public float get(int x, int y) {
//Get the position
int position = x + (y * 4);
//Return the value
return this.values[position];
}
/* The method used to return a string representation of this matrix */
public String toString() {
//Return the string
return "[ " + this.values[0] + " " + this.values[1] + " " + + this.values[2] + " " + + this.values[3] + " ]" + "\n" +
"[ " + this.values[4] + " " + this.values[5] + " " + + this.values[6] + " " + + this.values[7] + " ]" + "\n" +
"[ " + this.values[8] + " " + this.values[9] + " " + + this.values[10] + " " + + this.values[11] + " ]" + "\n" +
"[ " + this.values[12] + " " + this.values[13] + " " + + this.values[14] + " " + + this.values[15] + " ]";
}
/* The method used to get the values */
public float[] getValues() { return this.values; }
/* The method used to get the values in a 2D array */
public float[][] getValues2DArray() {
//The array
float[][] array = new float[4][4];
//Go through each value
int column = 0;
int row = 0;
while (column * row < array.length) {
row ++;
if (row >= 4) {
column++;
row = 0;
}
array[column][row] = this.values[column * row];
}
//Return the array
return array;
}
}
Here is the Matrix class (Used to setup and perform calculations on a matrix):
public class Matrix {
/* The different matrices */
public static Matrix4D modelMatrix = new Matrix4D();
public static Matrix4D viewMatrix = new Matrix4D();
public static Matrix4D projectionMatrix = new Matrix4D();
public static Matrix4D modelViewProjectionMatrix = new Matrix4D();
/* The static method used to load an identity matrix */
public static void loadIdentity(Matrix4D matrix) {
//Load the identity matrix
matrix.load(new float[][] {
new float[] { 1, 0, 0, 0 },
new float[] { 0, 1, 0, 0 },
new float[] { 0, 0, 1, 0 },
new float[] { 0, 0, 0, 1 },
});
}
/* The static method used to add two matrices together */
public static Matrix4D add(Matrix4D matrixA, Matrix4D matrixB) {
//Create a new matrix
Matrix4D matrix = new Matrix4D();
//Go through each value
for (int a = 0; a < matrix.values.length; a++)
//Assign the current value
matrix.values[a] = matrixA.values[a] + matrixB.values[a];
//Return the matrix
return matrix;
}
/* The static method used to subtract a matrix (B) from another (A) */
public static Matrix4D subtract(Matrix4D matrixA, Matrix4D matrixB) {
//Create a new matrix
Matrix4D matrix = new Matrix4D();
//Go through each value
for (int a = 0; a < matrix.values.length; a++)
//Assign the current value
matrix.values[a] = matrixB.values[a] - matrixA.values[a];
//Return the matrix
return matrix;
}
/* The static method used to multiply two matrices together */
public static Matrix4D multiply(Matrix4D matrixA, Matrix4D matrixB) {
//Create a new matrix
Matrix4D matrix = new Matrix4D(new float[][] {
new float[] {
(matrixA.values[0] * matrixB.values[0]) + (matrixA.values[1] * matrixB.values[4]) + (matrixA.values[2] * matrixB.values[8]) + (matrixA.values[3] * matrixB.values[12]),
(matrixA.values[0] * matrixB.values[1]) + (matrixA.values[1] * matrixB.values[5]) + (matrixA.values[2] * matrixB.values[9]) + (matrixA.values[3] * matrixB.values[13]),
(matrixA.values[0] * matrixB.values[2]) + (matrixA.values[1] * matrixB.values[6]) + (matrixA.values[2] * matrixB.values[10]) + (matrixA.values[3] * matrixB.values[14]),
(matrixA.values[0] * matrixB.values[3]) + (matrixA.values[1] * matrixB.values[7]) + (matrixA.values[2] * matrixB.values[11]) + (matrixA.values[3] * matrixB.values[15])
},
new float[] {
(matrixA.values[4] * matrixB.values[0]) + (matrixA.values[5] * matrixB.values[4]) + (matrixA.values[6] * matrixB.values[8]) + (matrixA.values[7] * matrixB.values[12]),
(matrixA.values[4] * matrixB.values[1]) + (matrixA.values[5] * matrixB.values[5]) + (matrixA.values[6] * matrixB.values[9]) + (matrixA.values[7] * matrixB.values[13]),
(matrixA.values[4] * matrixB.values[2]) + (matrixA.values[5] * matrixB.values[6]) + (matrixA.values[6] * matrixB.values[10]) + (matrixA.values[7] * matrixB.values[14]),
(matrixA.values[4] * matrixB.values[3]) + (matrixA.values[5] * matrixB.values[7]) + (matrixA.values[6] * matrixB.values[11]) + (matrixA.values[7] * matrixB.values[15])
},
new float[] {
(matrixA.values[8] * matrixB.values[0]) + (matrixA.values[9] * matrixB.values[4]) + (matrixA.values[10] * matrixB.values[8]) + (matrixA.values[11] * matrixB.values[12]),
(matrixA.values[8] * matrixB.values[1]) + (matrixA.values[9] * matrixB.values[5]) + (matrixA.values[10] * matrixB.values[9]) + (matrixA.values[11] * matrixB.values[13]),
(matrixA.values[8] * matrixB.values[2]) + (matrixA.values[9] * matrixB.values[6]) + (matrixA.values[10] * matrixB.values[10]) + (matrixA.values[11] * matrixB.values[14]),
(matrixA.values[8] * matrixB.values[3]) + (matrixA.values[9] * matrixB.values[7]) + (matrixA.values[10] * matrixB.values[11]) + (matrixA.values[11] * matrixB.values[15])
},
new float[] {
(matrixA.values[12] * matrixB.values[0]) + (matrixA.values[13] * matrixB.values[4]) + (matrixA.values[14] * matrixB.values[8]) + (matrixA.values[15] * matrixB.values[12]),
(matrixA.values[12] * matrixB.values[1]) + (matrixA.values[13] * matrixB.values[5]) + (matrixA.values[14] * matrixB.values[9]) + (matrixA.values[15] * matrixB.values[13]),
(matrixA.values[12] * matrixB.values[2]) + (matrixA.values[13] * matrixB.values[6]) + (matrixA.values[14] * matrixB.values[10]) + (matrixA.values[15] * matrixB.values[14]),
(matrixA.values[12] * matrixB.values[3]) + (matrixA.values[13] * matrixB.values[7]) + (matrixA.values[14] * matrixB.values[11]) + (matrixA.values[15] * matrixB.values[15])
}
});
//Return the matrix
return matrix;
}
/* The static method used to transpose a matrix */
public static Matrix4D transpose(Matrix4D matrix) {
//Get the values from the matrix
float[][] values = matrix.getValues2DArray();
//The new values
float[][] newValues = new float[4][4];
//Go through the array
for (int y = 0; y < values.length; y++) {
for (int x = 0; x < values[y].length; x++) {
//Assign the new value
newValues[x][y] = values[y][x];
}
}
//Return the matrix
return new Matrix4D(newValues);
}
/* The static method used to translate a matrix */
public static Matrix4D translate(Matrix4D matrix, Vector3D vector) {
//The transform matrix
Matrix4D transform = new Matrix4D(new float[][] {
new float[] { 0, 0, 0, vector.x },
new float[] { 0, 0, 0, vector.y },
new float[] { 0, 0, 0, vector.z },
new float[] { 0, 0, 0, 0 },
});
//Add onto the matrix and return the result
return add(matrix, transform);
}
/* The static method used to rotate a matrix */
public static Matrix4D rotate(Matrix4D matrix, float angle, int x, int y, int z) {
//The transform matrix
Matrix4D transform = new Matrix4D();
//Calculate the values needed
float cos = (float) Math.cos(angle);
float sin = (float) Math.sin(angle);
//Check the x y and z values
if (x == 1) {
transform.load(new float[][] {
new float[] { 0, 0, 0, 0 },
new float[] { 0, cos, -sin, 0 },
new float[] { 0, sin, cos, 0 },
new float[] { 0, 0, 0, 0 },
});
} else if (y == 1) {
transform.load(new float[][] {
new float[] { cos, 0, sin, 0 },
new float[] { 0, 0, 0, 0 },
new float[] { -sin, 0, cos, 0 },
new float[] { 0, 0, 0, 0 },
});
} else if (z == 1) {
transform.load(new float[][] {
new float[] { cos, -sin, 0, 0 },
new float[] { sin, cos, 0, 0 },
new float[] { 0, 0, 0, 0 },
new float[] { 0, 0, 0, 0 },
});
}
//Add onto the matrix and return the result
return add(matrix, transform);
}
/* The static method used to scale a matrix */
public static Matrix4D scale(Matrix4D matrix, Vector3D vector) {
//The transform matrix
Matrix4D transform = new Matrix4D(new float[][] {
new float[] { vector.x, 0, 0, 0 },
new float[] { 0, vector.y, 0, 0 },
new float[] { 0, 0, vector.z, 0 },
new float[] { 0, 0, 0, 0 },
});
//Add onto the matrix and return the result
return add(matrix, transform);
}
/* The static method used to return an orthographic projection matrix */
public static Matrix4D ortho(float left, float right, float top, float bottom, float zfar, float znear) {
return new Matrix4D(new float[][] {
new float[] { 2 / (right - left), 0, 0, -((right + left) / (right - left)) },
new float[] { 0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom)) },
new float[] { 0, 0, -2 / (zfar - znear), -((zfar + znear) / (zfar - znear)) },
new float[] { 0, 0, 0, 1 },
});
}
/* The static method used to return a perspective projection matrix */
public static Matrix4D perspective(float fov, float aspect, float zNear, float zFar) {
float f = (float) (1f / Math.tan(fov / 2f));
return new Matrix4D(new float[][] {
new float[] { f / aspect, 0, 0, 0 },
new float[] { 0, f, 0, 0 },
new float[] { 0, 0, (zFar + zNear) / (zFar - zNear), (2 * zFar * zNear) / (zNear - zFar) },
new float[] { 0, 0, -1, 0 },
});
}
}
Finally the method used to setup the perspective/orthographic projection is:
/* The static method to setup an orthographic view given the width, height
* znear and zfar values */
public static void setupOrtho(float width, float height, float znear , float zfar) {
Matrix.loadIdentity(Matrix.modelMatrix);
Matrix.loadIdentity(Matrix.viewMatrix);
Matrix.projectionMatrix = Matrix.ortho(0, width, 0, height, znear, zfar);
}
/* The static method used to setup a perspective view given the
* fov, z near and z far value */
public static void setupPerspective(float fov, float zNear, float zFar) {
setupPerspective(fov, (float) (Settings.Window.Width / Settings.Window.Height), zNear, zFar);
}
/* The static method used to setup a perspective view given the
* fov, aspect ratio, z near and z far values */
public static void setupPerspective(float fov, float aspect, float zNear, float zFar) {
Matrix.loadIdentity(Matrix.modelMatrix);
Matrix.loadIdentity(Matrix.viewMatrix);
Matrix.projectionMatrix = Matrix.perspective(fov, aspect, zNear, zFar);
}
To render all of this and pass the matrices to the shader I am using
//Multiply the matrices together
Matrix4D modelViewMatrix = Matrix.multiply(Matrix.modelMatrix, Matrix.viewMatrix);
Matrix.modelViewProjectionMatrix = (Matrix.multiply(modelViewMatrix, Matrix.projectionMatrix));
System.out.println(Matrix.modelViewProjectionMatrix.toString() + "\n");
And in the shader I multiply the current vertices position by the model view projection marix.
Here is a picture of what it currently looks like.
You seem to be multiplying your matrices in the wrong order. When combining matrix transformations, the one on the right of the equation will be the first transformation performed.
You calculate your matrix as Model × View × Projection. When multiplying this by a vector, the projection would be performed first, followed by the view transformation, and lastly the model transformation. Obviously this is not what you want.
Your final matrix should be calculated like Projection × View × Model to do the transformations in the right order.

zoom in/out graph using AWT on Applet

I am newbie to the java....working on a piece of applet code...............as I am still going through the OOPs concepts and java understanding and need to develop below mentioned functionality.
The piece of code I have works like this :
First it reads all parameters from HTML tags and stores in global variables. Then it sends query to CGI to read graph data. Then it converts data for plotting and draws graph. There is a option for user to select 1-24 hours. Based on the selection graph will be plotted by plotting only selected data. Every 30 sec it sends query to CGI for collecting data.
The code uses following library and uses java 1.5 environment and i cannot change it due to embeded requirements :
I need to enchance it by implementing zoom in zoom out feature with x-y axis granuality changing with zoom in .
My worry is how to do that?I know its Frustrating question ...but i am here to get suggestion from the java experts so that I can quickly learn and implement this stuff.
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.text.*;
/******************************************************************************
*
* Class - Graph
*
* This is the entry point.
* This class extends Applet class and implements Runnable.
*
*****************************************************************************/
public class GraphPerf extends Applet implements Runnable,ItemListener,MouseMotionListener
{
//Global variables
int MAX_DATA_X ;
int SIZE_X= 480;
int SIZE_Y= 250;
int SIZE_Y1= 240;
int MIN_ERROR = -1;
int MAX_LOG10_ERROR_COUNT = 1001;
int MAX_ERROR_COUNT = 101;
int SIZE_Y_EXTENDED_BOTTOM = 20;
int MAX_DISP_PARMS = 16;
int MAX_NUM_INTERVELL_PER_DAY = 96;
int MAX_DISP_PARMS_STD = 7;
int refreshTime;
String serverAddress,hostAddr;
Color plotColor1,plotColor8;
float graphData[][];
float graph_data_rf_east,graph_data_rf_west;
int xOffset = 50;
int yOffset = 40;
int Y1_MAX_VALUE = 100;
int Y2_MAX_VALUE = 3;
float RANGE2;
Thread graphThread;
Image Buffer;
Graphics plot;
Choice timeChoice, modeChoice, seloptChoice;
int duration=1, viewMode=1, line_type = 0,viewOpt = 1;
Label valueLabel1, valueLabel2,valueLabel3,valueLabel4,valueLabel5;
boolean GraphBottomExtendFlag=true;
/******************************************************************************
*
* method - init
*
* This is the method called first after applet loaded in to browser.
* This function reads configurable parameters from HTML tag and updates
* global variables.
*****************************************************************************/
public void init()
{
MAX_DATA_X = 672;//Integer.parseInt(getParameter("max_data_x"));
//refreshTime = 30;//Integer.parseInt(getParameter("refresh_sec"));
/*URL url = getDocumentBase();
String host = url.getHost();
try
{
InetAddress addr = InetAddress.getByName(host);
hostAddr=addr.getHostAddress();
}catch (UnknownHostException ex) {
ex.printStackTrace();
}
*/
//serverAddress = new String ( getParameter("access_str")+ hostAddr + getParameter("data_server"));
graphData = new float[MAX_DISP_PARMS][MAX_DATA_X+1];
/*initialize the array with -1 not with 0(0 also valid for graph data) */
int i =0,j = 0;
for( j=0; j<MAX_DISP_PARMS; j++)
{
for( i=0; i<MAX_DATA_X+1; i++)
{
graphData[j][i] = -1;
}
}
graph_data_rf_east = -1;
graph_data_rf_west = -1;
plotColor1 = Color.orange;
plotColor2 = Color.black;
plotColor8 = Color.red;
plotColor9 = Color.green;
setBackground(Color.white);
setLayout(null);
timeChoice = new Choice();
timeChoice.add("1");
timeChoice.add("2");
timeChoice.add("3");
timeChoice.add("4");
timeChoice.add("5");
timeChoice.add("6");
timeChoice.add("7");
add(timeChoice);
timeChoice.setBounds(190,340,40,23);
timeChoice.addItemListener(this);
Label timeLabel1 = new Label("View graph for last");
Label timeLabel2 = new Label("day(s)");
add(timeLabel1);
timeLabel1.setBounds(xOffset+30,340,160,23);
add(timeLabel2);
timeLabel2.setBounds(240,340,50,23);
valueLabel1 = new Label();
add(valueLabel1);
valueLabel1.setBounds(300,340,50,23);
valueLabel2 = new Label();
add(valueLabel2);
valueLabel2.setBounds(370,340,70,23);
valueLabel3 = new Label();
add(valueLabel3);
valueLabel3.setBounds(440,340,70,23);
valueLabel4 = new Label();
add(valueLabel4);
valueLabel4.setBounds(500,340,70,23);
valueLabel5 = new Label();
add(valueLabel5);
valueLabel5.setBounds(370,370,80,25);
modeChoice = new Choice();
modeChoice.add("East");
modeChoice.add("West");
/* Display this only for Protected and East-West Mode */
if(2/*Integer.parseInt(getParameter("mode"))*/ == 2)
{
add(modeChoice);
}
else
{
viewOpt = 1;
}
modeChoice.setBounds(xOffset+SIZE_X-55, 0, 60, 25);
modeChoice.addItemListener(this);
addMouseMotionListener(this);
}
public void start()
{
graphThread = new Thread(this);
graphThread.start();
}
public void stop()
{
graphThread = null;
}
/******************************************************************************
*
* This method will be called after starting the thread. This is a
* infinite loop which will call query method for every 30 sec to read data
* from CGI. Then it plots graph by calling plotGraph method
* the thread.
*****************************************************************************/
public void run()
{
/*while (false)
{
try
{//getData(serverAddress);
int sizeY = SIZE_Y;
if(GraphBottomExtendFlag)
{
sizeY += SIZE_Y_EXTENDED_BOTTOM;
}
repaint(xOffset+1,yOffset+1,SIZE_X-1,sizeY-1);
//graphThread.sleep(refreshTime*1000);
}catch (Exception e) { System.out.println(e); }
}*/
}
/******************************************************************************
*
* method - paint
*
* This method displays the graph plotted by plotGraph method
* in the screen. Then it draws axis for the graph
*
*****************************************************************************/
public void paint(Graphics g1)
{
int sizeY = SIZE_Y;
/*If Graph Bottom is to be Etended
*soo that zero is displayed properly
*/
if(GraphBottomExtendFlag)
{
sizeY += SIZE_Y_EXTENDED_BOTTOM;
}
if( duration <= 5 )
{
Buffer = createImage(SIZE_X, sizeY);
plot = Buffer.getGraphics();
plotGraph(plot);
g1.drawImage (Buffer,xOffset,yOffset,this);
}
else
{
Buffer = createImage(MAX_DATA_X*duration/7,sizeY);
plot = Buffer.getGraphics();
plotGraph(plot);
g1.drawImage (Buffer,xOffset,yOffset,SIZE_X,sizeY,this);
}
g1.setColor(Color.black);
g1.drawRect(70,150,270,80);
/*Dram Graph boarder */
g1.drawRect(xOffset,yOffset,SIZE_X,sizeY);
g1.drawRect(xOffset-1,yOffset-1,SIZE_X+2,sizeY+2);
/*Plot X axis*/
int max_x_marks = 8;
int temp = 1,cnt_graph = 0;
int float_temp,float_temp2;
/*max 8 plots on x axis*/
for(int x=max_x_marks; x>0; x--)
{
float_temp = (int)((MAX_NUM_INTERVELL_PER_DAY*duration)/max_x_marks)*((max_x_marks+1)-x);
float_temp2 = SIZE_X-(60*cnt_graph);
g1.drawString(String.valueOf(float_temp),(float_temp2-20) ,SIZE_Y+yOffset+35);
cnt_graph++;
}
/*Plot Y1 AXIS*/
temp = Y1_MAX_VALUE;
for(int x = 0; x <= SIZE_Y; x+= 25)
{
g1.drawString(String.valueOf(temp), 25, x + yOffset+10);
temp -= (Y1_MAX_VALUE - 0)/10;
}
temp = 1000;
/*Plot Y2 AXIS*/
int index_log = 1;
for(int x = 0; x <= SIZE_Y1; x+= 80)
{
if(x== 240)
index_log--;
if(temp>=1)
{
g1.drawString(String.valueOf(temp), 550, x+yOffset+8-index_log);
g1.drawLine(530,x+yOffset+5-index_log, 540, x+yOffset+5-index_log);
}
temp = temp/10;
}
Font thisFont = new Font("Times New Roman", Font.BOLD, 14);
g1.setFont(thisFont);
g1.drawString("Y2", 550, 160);
g1.drawString("Y1",5, 160);
}
/******************************************************************************
*
* method - plotGraph
*
* Depending on the mode, "East", "West" or "Combined", it plots
* single or two graphs in the same applet.
*
* Inputs :
* g - Graphics object
*****************************************************************************/
public void plotGraph(Graphics g)
{
g.setColor(new Color(255,255,220));
/*If Error-Sec-Count Graph
*Then extend the lower portion
*soo that zero is displayed properly
*/
if(GraphBottomExtendFlag)
{
g.fillRect(0,0,MAX_DATA_X,SIZE_Y + SIZE_Y_EXTENDED_BOTTOM);
}
else
{
g.fillRect(0,0,MAX_DATA_X,SIZE_Y);
}
switch(viewMode)
{
case 1 :
plot1(g);
plot_timeelapsed_east(g);
break;
case 2 :
plot8(g);
plot_timeelapsed_west(g);
break;
}
}
/******************************************************************************
*
* method - plot1
*
* This method uses graphData[0][] global variable and plots series of lines
* in the applet
*
* Inputs :
* g - Graphics object
*****************************************************************************/
void plot1(Graphics g)
{
int end = MAX_DATA_X;
int localPlotBuffer[];
localPlotBuffer = new int[2];
g.setColor(plotColor1);
if(duration > 5)
{
for(int x=(duration*MAX_NUM_INTERVELL_PER_DAY); x > 0 ; x--)
{
/*if data is valid data then plot else ignore*/
if((graphData[0][end]>MIN_ERROR)&&(graphData[0][end-1]<MAX_LOG10_ERROR_COUNT)&&(graphData[0][end-1]>MIN_ERROR)&&(graphData[0][end]<MAX_LOG10_ERROR_COUNT))
{
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[0][end] == 0)
{
localPlotBuffer[0] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[0][end]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[0] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[0][end])/(float)Y2_MAX_VALUE));
}
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[0][end-1] == 0)
{
localPlotBuffer[1] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[0][end-1]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[1] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[0][end-1])/(float)Y2_MAX_VALUE));
}
g.drawLine(x-1,(localPlotBuffer[0]+5), x-2,(localPlotBuffer[1]+5));
g.drawLine(x,(localPlotBuffer[0]+5), x-1,(localPlotBuffer[1]+5));
}
end--;
}
}
else
{
float temp = SIZE_X;
for(int x=(duration*MAX_NUM_INTERVELL_PER_DAY) ; x > 0 ; x--)
{
float LocalTemp1 = temp;
float LocalTemp2 = (int)(temp-(double)5/(double)duration);
/*Normalise the pixcel positions */
/*Normalise the pixcel positions */
if(duration == 1)
{
if(LocalTemp1>(SIZE_X-3))
LocalTemp1 = SIZE_X;
if(LocalTemp2>(SIZE_X-3))
LocalTemp2 = SIZE_X;
}
/*Normalise the pixcel positions */
else if(duration == 2)
{
if(LocalTemp1>(SIZE_X-2))
LocalTemp1 = SIZE_X;
if(LocalTemp2>(SIZE_X-2))
LocalTemp2 = SIZE_X;
}
/*Normalise the pixcel positions */
else if(duration == 3)
{
if(LocalTemp1>(SIZE_X-1))
LocalTemp1 = SIZE_X;
if(LocalTemp2>(SIZE_X-1))
LocalTemp2 = SIZE_X;
}
/*if data is valid data then plot else ignore*/
if((graphData[0][end]>MIN_ERROR)&&(graphData[0][end-1]<MAX_LOG10_ERROR_COUNT)&&(graphData[0][end-1]>MIN_ERROR)&&(graphData[0][end]<MAX_LOG10_ERROR_COUNT))
{
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[0][end] == 0)
{
localPlotBuffer[0] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[0][end]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[0] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[0][end])/(float)Y2_MAX_VALUE));
}
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[0][end-1] == 0)
{
localPlotBuffer[1] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[0][end-1]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[1] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[0][end-1])/(float)Y2_MAX_VALUE));
}
g.drawLine((int)LocalTemp1,(localPlotBuffer[0]+5), (int)LocalTemp2,(localPlotBuffer[1]+5));
}
temp-=(double)5/(double)duration;
end--;
}
}
}
/******************************************************************************
*
* method - plot8
*
* This method uses graphData[7][] global variable and plots series of lines
* in the applet
*
* Inputs :
* g - Graphics object
*****************************************************************************/
void plot8(Graphics g)
{
int end = MAX_DATA_X;
int localPlotBuffer[];
localPlotBuffer = new int[2];
g.setColor(plotColor1);
if(duration > 5)
{
for(int x=(duration*MAX_NUM_INTERVELL_PER_DAY); x > 0 ;x-- )
{
/*if data is valid data then plot else ignore*/
if((graphData[8][end]>MIN_ERROR)&&(graphData[8][end-1]<MAX_LOG10_ERROR_COUNT)&&(graphData[8][end-1]>MIN_ERROR)&&(graphData[8][end]<MAX_LOG10_ERROR_COUNT))
{
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[8][end] == 0)
{
localPlotBuffer[0] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[8][end]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[0] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[8][end])/(float)Y2_MAX_VALUE));
}
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[8][end-1]== 0)
{
localPlotBuffer[1] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[8][end-1]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[1] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[8][end-1])/(float)Y2_MAX_VALUE));
}
g.drawLine(x-1,(localPlotBuffer[0]+5), x-2,(localPlotBuffer[1]+5));
g.drawLine(x,(localPlotBuffer[0]+5), x-1,(localPlotBuffer[1]+5));
}
end--;
}
}
else
{
float temp = SIZE_X;
for(int x=(duration*MAX_NUM_INTERVELL_PER_DAY) ; x > 0 ; x--)
{
float LocalTemp1 = temp;
float LocalTemp2 = (int)(temp-(double)5/(double)duration);
/*Normalise the pixcel positions */
if(duration == 1)
{
if(LocalTemp1>(SIZE_X-3))
LocalTemp1 = SIZE_X;
if(LocalTemp2>(SIZE_X-3))
LocalTemp2 = SIZE_X;
}
/*Normalise the pixcel positions */
else if(duration == 2)
{
if(LocalTemp1>(SIZE_X-2))
LocalTemp1 = SIZE_X;
if(LocalTemp2>(SIZE_X-2))
LocalTemp2 = SIZE_X;
}
/*Normalise the pixcel positions */
else if(duration == 3)
{
if(LocalTemp1>(SIZE_X-1))
LocalTemp1 = SIZE_X;
if(LocalTemp2>(SIZE_X-1))
LocalTemp2 = SIZE_X;
}
/*if data is valid data then plot else ignore*/
if((graphData[8][end]>MIN_ERROR)&&(graphData[8][end-1]<MAX_LOG10_ERROR_COUNT)&&(graphData[8][end-1]>MIN_ERROR)&&(graphData[8][end]<MAX_LOG10_ERROR_COUNT))
{
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[8][end] == 0)
{
localPlotBuffer[0] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[8][end]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[0] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[8][end])/(float)Y2_MAX_VALUE));
}
/*if data present is 0, log10(0) is not define so then plot this graph in normal scale */
if(graphData[8][end-1]== 0)
{
localPlotBuffer[1] = (int)((float)(SIZE_Y )*(float)(1 - (float)graphData[8][end-1]/(float)Y1_MAX_VALUE)) ;
}
else
{
localPlotBuffer[1] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graphData[8][end-1])/(float)Y2_MAX_VALUE));
}
g.drawLine((int)LocalTemp1,(localPlotBuffer[0]+5), (int)LocalTemp2,(localPlotBuffer[1]+5));
}
temp-=(double)5/(double)duration;
end--;
}
}
}
/******************************************************************************
*
* method - plot_timeelapsed_east
*
* This method uses graph_data_rf_east global variable and plots series of lines
* in the applet
*****************************************************************************/
void plot_timeelapsed_east(Graphics g)
{
int end = MAX_DATA_X;
int localPlotBuffer[];
int x= 0;
localPlotBuffer = new int[2];
x= (duration*MAX_NUM_INTERVELL_PER_DAY);
g.setColor(plotColor9);
/*if data is valid data then plot else ignore*/
if((graph_data_rf_east>0)&&(graph_data_rf_east<MAX_LOG10_ERROR_COUNT))
{
localPlotBuffer[0] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graph_data_rf_east)/(float)Y2_MAX_VALUE));
if(duration>5)
g.drawLine(x-1,SIZE_Y+5, x-2,(localPlotBuffer[0]+5));
else
g.drawLine(SIZE_X,SIZE_Y+5, 474+duration,(localPlotBuffer[0]+5));
}
}/*End for plot_timeelapsed_east() */
/******************************************************************************
*
* method - plot_timeelapsed_west
*
* This method uses graph_data_rf_east global variable and plots series of lines
* in the applet
*****************************************************************************/
void plot_timeelapsed_west(Graphics g)
{
int end = MAX_DATA_X;
int localPlotBuffer[];
int x= 0;
localPlotBuffer = new int[2];
x= (duration*MAX_NUM_INTERVELL_PER_DAY);
g.setColor(plotColor9);
/*if data is valid data then plot else ignore*/
if((graph_data_rf_east>MIN_ERROR)&&(graph_data_rf_east<MAX_LOG10_ERROR_COUNT))
{
localPlotBuffer[0] = (int)((float)(SIZE_Y1 )*(float)(1 - (float)Math.log10(graph_data_rf_west)/(float)Y2_MAX_VALUE));
if(duration>5)
g.drawLine(x-1,SIZE_Y+5, x-2,(localPlotBuffer[0]+5));
else
g.drawLine(SIZE_X,SIZE_Y+5, 474+duration,(localPlotBuffer[0]+5));
}
}
/******************************************************************************
*
* method - getData
*
* This method sends query to CGI to collect data. Then it converts the
* data for applet area then updates global variable.
*
* Inputs :
* serverAddress - server CGI path
*****************************************************************************/
public void getData(String serverAddress)
{
URL addr;
BufferedReader in;
String inputLine;
int count = 0;
int i=0,j = 0;
try
{
addr = new URL(serverAddress);
URLConnection connection = addr.openConnection();
in = new BufferedReader(new InputStreamReader(addr.openStream()));
/*Read data for first link */
for( j=0; j<MAX_DISP_PARMS_STD; j++)
{
for( i=0; i<MAX_DATA_X+1; i++)
{
inputLine = in.readLine();
graphData[j][i] = Integer.parseInt(inputLine);
}
}
for( i=0; i<MAX_DATA_X; i++)
{
inputLine = in.readLine();
graphData[7][i] = Integer.parseInt(inputLine);
if(graphData[7][i] == 1)
graphData[7][i] = 10;
}
inputLine = in.readLine();
graph_data_rf_east = Integer.parseInt(inputLine);
/*Reading data for second link */
if(Integer.parseInt(getParameter("mode")) == 2)
{
for( j=8; j<15; j++)
{
for( i=0; i<MAX_DATA_X+1; i++)
{
inputLine = in.readLine();
graphData[j][i] = Integer.parseInt(inputLine);
}
}
for( i=0; i<MAX_DATA_X; i++)
{
inputLine = in.readLine();
graphData[15][i] = Integer.parseInt(inputLine);
if(graphData[15][i] == 1)
graphData[15][i] = 10;
}
inputLine = in.readLine();
graph_data_rf_west = Integer.parseInt(inputLine);
}
in.close();
}catch (Exception e) { System.out.println("Server Data Read Error:"+e); }
}
/******************************************************************************
*
* method - itemStateChanged
*
* This method will be called whenever event occured on this choice.
* it read the current status and changes scale accordingly.
* *****************************************************************************/
public void itemStateChanged(ItemEvent evt)
{
if( evt.getSource() == timeChoice )
duration = Integer.parseInt(timeChoice.getSelectedItem());
else
viewMode = modeChoice.getSelectedIndex()+1;
repaint();
}
/******************************************************************************
*
* method - mouseMoved
*
* This method will be called whenever mouse cursor is moved over the
* applet. Depending on the cursor position, it will display Actual
* X and Y values of the graph.
*****************************************************************************/
public void mouseMoved(MouseEvent evt)
{
int x = evt.getX()-xOffset;
int y = evt.getY()-yOffset-5;
int a = evt.getX();
int b = evt.getY();
int duration = Integer.parseInt(timeChoice.getSelectedItem());
if( (x>=0) && (x<=SIZE_X) && (y>=0) && (y<=SIZE_Y) )
{
valueLabel1.setText("X ");
valueLabel2.setText("Y1 ");
valueLabel3.setText("Y2 ");
try
{
int x_max_value = ((SIZE_X*duration)/5);
int x1 = (int)((float)((float)((float)(SIZE_X*duration))/5) * ((float)((float)(SIZE_X - x))/((float)SIZE_X)));
/*For Durations less than 16 scale starts with 1*/
int y1 = (int)((float)Y1_MAX_VALUE * (((float)SIZE_Y - (float)y)/((float)SIZE_Y)));
int y2 = (int) Math.pow(10,((float)(3 * ((float)(1 - (float)y/((float)SIZE_Y1))))));
valueLabel1.setText("X="+x1);
valueLabel2.setText("X pix="+a);
valueLabel3.setText("Y="+y1);
valueLabel4.setText("Y pix="+b);
valueLabel5.setText("Y2="+y2);
}
catch(Exception e) {System.out.println("Mouse Moved Error" + e);}
}
else
{
valueLabel1.setText(" ");
valueLabel2.setText(" ");
valueLabel3.setText(" ");
}
}
public void mouseDragged(MouseEvent evt) { }
}
There are many ways to do this. Here are two:
You can simply scale the values: Multiply every coordinate with the zoom factor.
Use Java2D and AffineTransform:
AffineTransform transformer = new AffineTransform();
transformer.scale(zoom, zoom);
Graphics2D g2d = (Graphics2D)g;
g2d.setTransform(transformer);
// draw to g2d.
[EDIT] If you want to do everything yourself, see this page for a refresh of basic linear algebra: 2D Transformations
Don't mind the 3D example at the top; the rest of the page is about 2D.
I used JCC kit for my target platform and it's less than 100kb library. You need to understand the library and after that you can play without worrying about size. :)
Good library to use in embedded systems whether size is always the issue. it has inbuilt function o transform coordinates into screen coordinates and vice-verse.

Categories