glEnabling and glDisabling many MANY times?

Member
Posts: 75
Joined: 2009.01
Post: #1
In drawView which is being called 30 times a second, I use a for loop to draw 400 tiles (20*20) with a texture mapped to each. The tiles are from a different class which contains ALL my objects to draw. The class has all the vertices and texCoords and textures to map and a method for each object to be rendered.

Here are two methods from my object class:
Code:
- (void)updateSmallBush:(float)camX :(float)camY :(float)camZ :(float)x :(float)y :(float)z {
    
    glLoadIdentity();
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    /*
    glEnable(GL_LIGHT0);
    const GLfloat light0Ambient[] = {0.1, 0.1, 0.1, 1.0};
    glLightfv(GL_LIGHT0, GL_AMBIENT, light0Ambient);
    
    const GLfloat light0Diffuse[] = {0.7, 0.7, 0.7, 1.0};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse);
    
    const GLfloat light0Specular[] = {0.7, 0.7, 0.7, 1.0};
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0Specular);
    
    const GLfloat light0Position[] = {-10.0, 0.0, 0.0, 0.0};
    glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
    
    const GLfloat light0Direction[] = {-1.0, 0.0, 0.0};
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0Direction);
    */
    glRotatef(-90.0f, 0, 0, 1);
    gluLookAt(camX, camY + 35.0, camZ + 20.0,            // Eye location, look “from”
              camX, camY, camZ,         // Target location, look “to”
              0.0, 1.0, 0.0);
    
    glTranslatef(x, y, z);
    glVertexPointer(3, GL_FLOAT, 0, smallBushVertices);
    glTexCoordPointer(2, GL_FLOAT, 0, smallBushTexCoord);
    [[GETextures share] bindTexture:potTexture];
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    [[GETextures share] bindTexture:smallBushTexture];
    glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
    [[GETextures share] bindTexture:potTexture];
    glDrawArrays(GL_TRIANGLE_FAN, 16, 4);
    glDrawArrays(GL_TRIANGLE_FAN, 20, 4);
    
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_TEXTURE_2D);
}


- (void)updateGrassPatch:(float)camX :(float)camY :(float)camZ :(float)x :(float)y :(float)z {
    
    glLoadIdentity();
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    glRotatef(-90.0f, 0, 0, 1);
    gluLookAt(camX, camY + 35.0, camZ + 20.0,            // Eye location, look “from”
              camX, camY, camZ,         // Target location, look “to”
              0.0, 1.0, 0.0);
    
    glTranslatef(x, y, z);
    glVertexPointer(3, GL_FLOAT, 0, grassPatchVertices);
    glTexCoordPointer(2, GL_FLOAT, 0, grassPatchTexCoord);
    [[GETextures share] bindTexture:grassPatchTexture];
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_TEXTURE_2D);
}

Is there anything wrong with what Im doing?
Because I get such low framerates.
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #2
State changes can definitely be expensive. Use OpenGL Profiler to find your hotspots and try to optimize them out. Easy example: There's no reason to ever disable GL_VERTEX_ARRAY, so just enable it once at startup and don't touch it again. It seems unlikely that you'd need to set up lighting on every call to -updateSmallBush::::::, so do it once ahead of time. Batch draws of objects that use the same texture so that you don't switch textures all the time.
Quote this message in a reply
Member
Posts: 75
Joined: 2009.01
Post: #3
Yea, I did a bit of reading and found out that switching textures are expensive.

The above code is my only solution to making this work and i'm still working on one right now. Is it possible to draw the map ONCE somewhere else and then use something like gluLookAt to move the "camera" around instead of having to redraw the map every 60 frames?
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #4
Nope, there's no way around drawing every frame. Drawing can be done with many fewer state changes than in the above code, though, in the ways I mentioned in my previous post and many more.
Quote this message in a reply
Member
Posts: 75
Joined: 2009.01
Post: #5
After some more reading I found out my problem but am clueless to how to solve it.
This is the solution from another forum:
Right now you are issuing N*N draw calls (4096 !)... obviously this is going to be slow as hell.

You need to create a vertex buffer and run your loop updating vertices within the buffer.
Then submit the whole thing with a single glDrawArrays.

How do I go about doing what he says?

EDIT:
I did find this bit of code and got it to work but nothings showing up =X.
Code:
// ---- Setup code ----
typedef float Vertex[3];
typedef float TexCoord[2];

Vertex vertices[24576]; // 64 * 64 * 6
TexCoord texCoords[24576];

int currentVertex = 0;

for (y=0;y<64;y++)
{
for (x=0;x<64;x++)
{
SetVertex(vertices[currentVertex], (x*8), (y*8), 0);
SetVertex(vertices[currentVertex+1], (x*8), (y*8)+8, 0);
SetVertex(vertices[currentVertex+2], (x*8)+8, (y*8), 0);

SetVertex(vertices[currentVertex+3], (x*8)+8, (y*8), 0);
SetVertex(vertices[currentVertex+4], (x*8), (y*8)+8, 0);
SetVertex(vertices[currentVertex+5], (x*8)+8, (y*8)+8, 0);

// Same deal with texCoords using your mapData

currentVertex += 6;
}
}

// ---- Then in your draw loop ----
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glBindTexture(GL_TEXTURE_2D, yourTileMapTexture);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLES, 0, 24576); // Plow through and draw our vertex array in one call
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  some times this new error. imaumac 0 1,494 Oct 30, 2008 04:58 PM
Last Post: imaumac