# Optimisation help

This topic is 3626 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello all. I have a mighty favour to ask. Could someone have a look over my code and point out how and where I can optimise my code. It forms part of a project at uni so I'm working to a deadline so I didn't bother making efficient code at first as I needed something working initially, but now I have the majority of the code done I want to start improving performance. The program is basically a heightmap with the map data loaded from a text file, and then a few other things are drawn as well, such as place names and an aircraft for example. The code structure is basically as follows: 1- Load file 2- Import data into vertex array 3- Build colour array 4- Build index array 5- Enter display loop 6- Draw map 7- Draw other objects (plane, flightpath etc) 8- Check if we've gone out of bounds, if so, go back to step 1 9- Else, go back to step 5, continue until quit And here is the code:

void drawPlane(){

glTranslatef(xPosPlane,yPosPlane,zPosPlane);
glRotatef(xRotPlane, 0.0, 0.0, 1.0);
glRotatef(yRotPlane, 1.0, 0.0, 0.0);

//Draw Plane!
glColor4f(1.0, 1.0, 1.0, 1.0);

//Main part
glPushMatrix();
glRotatef(90.0,0.0,1.0,0.0); //Rotate it to be parallel with ground
glRotatef(90.0,1.0,0.0,0.0);
glPopMatrix();

//Back of plane
glPushMatrix();
glTranslatef(0.0, 3000.0, 0);
glRotatef(90.0,0.0,1.0,0.0);
glRotatef(90.0,1.0,0.0,0.0);
glPopMatrix();

//Front of plane
glPushMatrix();
glTranslatef(0.0, -5000.0, 0);
glRotatef(90.0,0.0,1.0,0.0);
glRotatef(90.0,1.0,0.0,0.0);
glPopMatrix();

//Nose of plane
glPushMatrix();
glTranslatef(0.0,-6210.0,0.0);
glPopMatrix();

//Right Wing
glPushMatrix();
glTexCoord2f(0.0, 0.0); glVertex3f(7000.0, -1000.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(7000.0, -1600.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(700.0, -4000.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(700.0, -1000.0, 0.0);
glEnd();
glPopMatrix();

//Left Wing
glPushMatrix();
glTexCoord2f(0.0, 0.0); glVertex3f(-700.0, -1000.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-700.0, -4000.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(-7000.0, -1600.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(-7000.0, -1000.0, 0.0);
glEnd();
glPopMatrix();

//Right Engine
glPushMatrix();
glTranslatef(3500.0, -2000.0, 580);
glRotatef(90.0,0.0,1.0,0.0); //Rotate it to be parallel with ground
glRotatef(90.0,1.0,0.0,0.0);
glPopMatrix();

//Left Engine
glPushMatrix();
glTranslatef(-3500.0, -2000.0, 580);
glRotatef(90.0,0.0,1.0,0.0); //Rotate it to be parallel with ground
glRotatef(90.0,1.0,0.0,0.0);
glPopMatrix();

}

void drawFlightPath(){

//Loads of variables would be here

y = getHeight(h, d, x);
angle = atan((destLon-startLon)/(destLat-startLat));

glColor4f(1.0, 1.0, 1.0, 0.6);
for(int i=0; i<accuracy; i++){

height = getHeight(h, d, (splitDistance*(i+1)));

glPushMatrix();
glTexCoord2f(0.0, 0.0); glVertex3f(startLon, startLat, currentHeight);
glTexCoord2f(0.0, 1.0); glVertex3f(startLon-2000, startLat, currentHeight);
glTexCoord2f(1.0, 1.0); glVertex3f(startLon-2000-(splitDistance*(tan(angle))), startLat-splitDistance, height);
glTexCoord2f(1.0, 0.0); glVertex3f(startLon-(splitDistance*(tan(angle))), startLat-splitDistance, height);

glEnd();
glPopMatrix();

startLon += -splitDistance*(tan(angle));
startLat += -splitDistance;
currentHeight = height;
}

}

void fillArray(){

FILE *filein;
char oneline[255];
char* c;
float x, y, z;
int j=0;
int widthCount = 0;
int heightCount = 0;

filein = fopen(InFileTest, "rt");

while (heightCount < origMapHeight){
if (heightCount%accuracyLevel==0){

while (widthCount < origMapWidth){
if (widthCount%accuracyLevel==0){

c= fgets(oneline, 255, filein);
sscanf(oneline, "%f, " "%f, " "%f, ", &x, &y, &z);

vertices[j] = x;
vertices[j+1] = y;
vertices[j+2] = z;
j +=3;
}
else
c= fgets(oneline, 255, filein);

widthCount++;
}
widthCount=0;
}
else{
for (int i=0; i<origMapWidth; i++)
c= fgets(oneline, 255, filein);
}
heightCount++;
}
fclose(filein);
}

void setColors() {
int j = 0;
double ave = 0.0;
int elev;

for (int j = 0; j<HEIGHT; j++){
for (int i = 0; i < WIDTH; i++){

elev = vertices[((j*WIDTH+i)*3)+2];
if (elev == 0){ //Blue
colors[(j*WIDTH+i)*3] = 0.000; //blue (sea)
colors[((j*WIDTH+i)*3)+1] = 0.000;
colors[((j*WIDTH+i)*3)+2] = 1.000;
}
if (0 < elev && elev <=50){
colors[(j*WIDTH+i)*3] = 0.082; //v.dark green
colors[((j*WIDTH+i)*3)+1] = 0.416;
colors[((j*WIDTH+i)*3)+2] = 0.082;
}
if (50 < elev && elev <=100){
colors[(j*WIDTH+i)*3] = 0.192; //dark green
colors[((j*WIDTH+i)*3)+1] = 0.537;
colors[((j*WIDTH+i)*3)+2] = 0.192;
}
.......etc
}

void makeIndex() {

int j = 0;
int i = 0;

for (int x =0; x < HEIGHT-1; x++){
for (int y=0; y < WIDTH-1; y++){ //Work left to right, move down a row, repeat
index = j; //First triangle in square
index[i+1] = j+1;
index[i+2] = j+(WIDTH)+1;

index[i+3] = j;//Second triangle in square
index[i+4] = j+(WIDTH);
index[i+5] = j+(WIDTH)+1;

i+=6;
j++;
}
j++;
}
}

void drawTicker(){

int width = glutGet(GLUT_WINDOW_WIDTH);
int height = glutGet(GLUT_WINDOW_HEIGHT);

double xTick = width/10;
double yTickBase = height/8.3; //Used to keep it in proportion
double yTickTop = height/10;

glColor4f(0.20, 0.20, 0.20, 1.0);

glTexCoord2f(0.0, 0.0); glVertex3f(-(width/xTick), -(height/yTickTop), -10.001);
glTexCoord2f(0.0, 1.0); glVertex3f(-(width/xTick), -(height/yTickBase), -10.001);
glTexCoord2f(1.0, 1.0); glVertex3f((width/xTick), -(height/yTickBase), -10.001);
glTexCoord2f(1.0, 0.0); glVertex3f((width/xTick), -(height/yTickTop), -10.001);

glEnd();

glColor4f(1.0, 1.0, 1.0, 1.0);
glRasterPos3f(move, -9.2, -10);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , speedString);
glRasterPos3f(move+8, -9.2, -10);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , altString);
glRasterPos3f(move+17, -9.2, -10);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , distString);
glRasterPos3f(move+31, -9.2, -10);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , tempString);
glRasterPos3f(move+43, -9.2, -10);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , ETAString);
glRasterPos3f(move+50, -9.2, -10);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , timeString);

move = move -  0.05;
if (move<=-59)
move = 8;

}

void display (void){

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();

if (loadCheck == 1){
}

camera();

glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(3, GL_FLOAT, 0, colors);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLES, indexSize, GL_UNSIGNED_INT, index);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

drawLocations();
drawFlightPath();

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
drawPlane();
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);

drawTicker();

glPopMatrix();
glutSwapBuffers();
}

int main (int argc, char **argv)
{

fillArray();
setColors();
scaleVertices();
makeIndex();

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(550, 550);
glutInitWindowPosition(100, 100);
glutCreateWindow("Testing");
init();
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc (keyboard);
glutMainLoop();

return 0;
}


There are quite a few functions that I've missed out so there may be a couple of things in there that may not make sense (variables not declared, unknown functions etc), but I think thats the main bulk of the code. I've put a couple of functions in like drawPlane() so you can see how I'm drawing things. I'm only really after anything that will give quite a large peroformance increase because I'm still working to a deadline so dont have that much time. I think I need to use VBO's or display lists but I really havent had chance to look at them in any depth. One final thing. The array sizes can be fairly large. I can have over 20 million points to draw so the vertex array is 60 million elements (the 3 dimensions of each point) so the colour array is also 60 million and the index array is 120 million, this is quite extreme though, normally I will be working with 1-5 million points. Thank you very much for any advice.

##### Share on other sites
if u need 2 use vbos here is a good link:
http://www.songho.ca/opengl/gl_vbo.html

##### Share on other sites
You're rendering 1-5 million vertices each frame? That's quite a lot - and it seems like you really don't need that many - for any object. You might look into reducing this number if possible, for a couple of reasons:

1) At 1280 x 1024, that's as many vertices as there are pixels on your screen. The odds of more than one vertex mapping to any single pixel is very high - in other words, you have gone beyond the limit of what can be seen on the screen anyway.

2) If each vertex has position (3 floats), u-v coordinates (2 floats), normal (3 floats), and color (3 floats) - that's 44 bytes per vertex. Which means that 1 million vertices takes about 42MB of RAM. More importantly, you're copying 42MB of data into the video card every frame. Ugh.

What exactly are these arrays filled with, anyway? If most of it is terrain data, you might consider using a heightmap and texture instead. There are a few good algorithms (such as ROAM) to reduce the triangle count and give you a major performance boost.

[Edited by - klaymore142 on March 17, 2008 8:03:03 PM]

##### Share on other sites
Well the data I'm using is NASA's SRTM3 data. It looks like this:
-49.00041,-25.00041,898
-48.99708,-25.00041,920
-48.99375,-25.00041,933
-48.99042,-25.00041,954
-48.98709,-25.00041,975
-48.98376,-25.00041,964
-48.98043,-25.00041,969
-48.97710,-25.00041,1007

The first column is longitude, the second is latitude, the third is elevation (above sea level). I convert the longitude and latitude into metres and this gives me my 3D coordinates which I store in my vertex array. And yes each point has correspondeing values in the colour array and index array but I don't use a normal array.

Here is an example of the map zoomed in, the one on the left is full detail, and the one on the right is half detail, i.e. I take every other point from the file. As you can see there is quite a difference in the appearance, the lower detailed map looks far more 'blocky'.

You say I don't need that many points klaymore, so how do I reduce the number of vertices I'm drawing without recucing the quality like above?

Thanks.

##### Share on other sites
You appear to have large reasonably uniform areas on your map (same color and slope), where you don't actually need all these additional polygons. You can eliminate triangles using the following rule: if the common point of four connected quads is coplanar with the four adjacent vertices, then you can remove it.

+---+---+     +---+---+|  /|\  |     |  / \  || / | \ |     | /   \ ||/  |  \|     |/     \|+---+---+ ==> +-------+|\  |  /|     |\     /|| \ | / |     | \   / ||  \|/  |     |  \ /  |+---+---+     +---+---+

Apply this method recursively to simplify your mesh. Also, google "GeoMipMapping".

##### Share on other sites
Thanks ToohrVyk, that makes sense, I do have lots of very similare terrain. This example is actually quite varied so other areas are almost entirley the same elevation (i.e. the sea) so I could represent the entire area with just 2 trangles.

The problem is I don't really know how I would actually implement this. I assume once you have loaded the points you iterate through the vertex array working out if a group of vertices are coplanar (not quite sure how you would do this), but the main thing is in the index array, because each row will have a different number of points in and therefore a sifferent number of triangles, e.g. one row might be able to be drawn using only 2 triangles but the next row may require 1000. How would you know where to draw the triangles??

Thanks.

##### Share on other sites
I found two articles which use different techniques to accomplish similar things. You can decide which makes more sense / is easier to implement.
Personally, I used this article and an algorithm by Peter Lindstrom to work very well.
I also found this article very useful: Clicky

##### Share on other sites
Thanks Klaymore, that's a very intersting read. Unfortunately I don't have anywhere enough time to start rewriting all my code. I would love to have a go at that when I have some spare time.

Is there anything else on a smaller, simpler scale that will improve my performance?

Thanks again.

##### Share on other sites
Here's an idea - use the color data to create an OpenGL texture, at full resolution. Then use only half or 1/4 of the vertices, but texture-mapped (instead of specifying a color for each vertex, specify texture coordinates). You can play with the resolution of the image and how many vertices you render, until you get a good balance.