1
votes

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?

5

5 Answers

2
votes

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

1
votes

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.

0
votes

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.

0
votes

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

0
votes

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 );