views:

1540

answers:

5

I have a large texture atlas and I'm drawing lots of textures on the screen from this. At the moment each texture from the atlas is drawn separately with code like this:

GLfloat coordinates[] = {
        bla, bla,
        bla, bla,
        bla, bla,
        bla, bla
};

GLfloat vertices[] = {
        bla, bla, bla,
        bla, bla, bla
        bla, bla, bla
        bla, bla bla
};


glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

So we're doing this with a triangle strip.

Now, I just tried to cache these kinds of calls by saving the coordinates/vertices, and drawing them all out in a single call. But OpenGL ES does not have quads so trying to use triangle strips means the operation will merge them all together and you get textures warping across the screen from the previous point.

I tried with both glDrawArrays and glDrawElements but I didn't get any success. Is this even possible?

+1  A: 

Can you draw each quad as two triangles (GL_TRIANGLES)? Of course, you will have duplicated vertices and coordinates in your arrays.

Marco Mustapic
Yeah this is what I ended up doing. Instead of defining a triangle strip with 4 points in my arrays, I defined two triangles (6 points) and used glDrawArrays(GL_TRIANGLES, 0, totalSize * 6). So this stops everything being warped into a giant triangle strip.
Mike Weller
There are performance advantages to making the GL_TRIANGLE_STRIP version work.
Rhythmic Fistman
A: 

Change

glVertexPointer(3, GL_FLOAT, 0, vertices);

to

glVertexPointer(2, GL_FLOAT, 0, vertices);

and it should work, assuming that the triangle strip coords you elided are correct.

Rhythmic Fistman
This shouldn't make a difference. It's 3 now just because I had some z values in there but they are all 0.0.
Mike Weller
A: 

You might be interested in the TextureAtlas class of Cocos 2D engine for iPhone.

zoul
Thanks, they seem to be doing just what I was attempting. Maybe I Just made a silly mistake somewhere.
Mike Weller
A: 

Use glDrawElements with GL_TRIANGLES with 4 verts and 6 indexes. Modern hardware will cache the memory fetches for the repeated verts so performance will be nearly equal to GL_TRIANGLE_STRIP, and the fact that you can batch GL_TRIANGLES much more efficiently than strips for things like individual quads is a huge win. Make sure you get the triangle winding correct, or turn off backface culling.

// triangle vertex order
// 1--2
// | /|
// |/ |
// 0--3

vertex foo[4] = {
    {<vtx0>},
    {<vtx1>},
    {<vtx2>},
    {<vtx3>}
};

// same clockwise winding for both triangles
GLushort idx[2][3] = {
    { 0, 1, 2 },
    { 0, 2, 3 }
};

<setup vertex array>
// use a VBO for both the vertex and index array if possible...

glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, idx );
dude
A: 

You could using a degenerate strip.

In this case it makes (almost) no sense, since you only save two vertices per strip, but if you get longer strips and less stops it's good to have this weapon in your arsenal.

The degenerate strip is based on the fact that the hardware skips triangles with zero area, which is true for triangles with two identical vertices.

(Horrible coder ascii art to the rescue.)

A--D
| /|
|/ |
B--C

   E--H
   | /|
   |/ |
   F--G

Triangles

ABD DBC EFH HFG  -> 12

Va = f(Q) = 6xQ

Trianglestrips

ABD     C     C     E     E     F     H     G -> 10
ABD (BD)C (DC)C (CC)E (CE)E (EE)F (EF)H (FH)G
CCW CW    CCW   CW    CCW   CW    CCW   CW
NOR NOR   DEG   DEG   DEG   DEG   NOR   NOR

Vb = f(Q) = 4+ (4+2)(Q-1)

Q   | Va | Vb
 1  |  6 |  4
 2  | 12 | 10
 3  | 18 | 16
10  | 60 | 58

From OpenGL 3.1 you could simply use "Primitive Restart" which would make your life much easier.

Andreas