9

I am working on an OpenGL 2D game with sprite graphics. I was recently advised that I should use OpenGL ES calls as it is a subset of OpenGL and would allow me to port it more easily to mobile platforms. The majority of the code is just calls to a draw_image function, which is defined so:

void draw_img(float x, float y, float w, float h, GLuint tex,float r=1,float g=1, float b=1) {
    glColor3f(r,g,b);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, tex);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f( x, y);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2f(w+x, y);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2f( w+x, h+y);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2f( x, h+y);
    glEnd();
}

What do I need to change to make this OpenGL ES compatible? Also, the reason I am using fixed-function rather than shaders is that I am developing on a machine which doesn't support GLSL.

Skyler
  • 909
  • 1
  • 10
  • 24

1 Answers1

14

In OpenGL ES 1.1 use the glVertexPointer(), glColorPointer(), glTexCoordPointer() and glDrawArrays() functions to draw a quad. In contrast to your OpenGL implementation, you will have to describe the structures (vectors, colors, texture coordinates) that your quad consists of instead of just using the built-in glTexCoord2f, glVertex2f and glColor3f methods.

Here is some example code that should do what you want. (I have used the argument names you used in your function definition, so it should be simple to port your code from the example.)

First, you need to define a structure for one vertex of your quad. This will hold the quad vertex positions, colors and texture coordinates.

// Define a simple 2D vector
typedef struct Vec2 {
    float x,y;
} Vec2;

// Define a simple 4-byte color
typedef struct Color4B {
    GLbyte r,g,b,a;
};

// Define a suitable quad vertex with a color and tex coords.
typedef struct QuadVertex {
    Vec2 vect;              // 8 bytes
    Color4B color;          // 4 bytes
    Vec2 texCoords;         // 8 bytes
} QuadVertex;

Then, you should define a structure describing the whole quad consisting of four vertices:

// Define a quad structure
typedef struct Quad {
    QuadVertex tl;
    QuadVertex bl;
    QuadVertex tr;
    QuadVertex br;
} Quad; 

Now, instantiate your quad and assign quad vertex information (positions, colors, texture coordinates):

Quad quad;
quad.bl.vect = (Vec2){x,y};
quad.br.vect = (Vec2){w+x,y};
quad.tr.vect = (Vec2){w+x,h+y};
quad.tl.vect = (Vec2){x,h+y};
quad.tl.color = quad.tr.color = quad.bl.color = quad.br.color
              = (Color4B){r,g,b,255};
quad.tl.texCoords = (Vec2){0,0};
quad.tr.texCoords = (Vec2){1,0};
quad.br.texCoords = (Vec2){1,1};
quad.bl.texCoords = (Vec2){0,1};

Now tell OpenGL how to draw the quad. The calls to gl...Pointer provide OpenGL with the right offsets and sizes to your vertex structure's values, so it can later use that information for drawing the quad.

// "Explain" the quad structure to OpenGL ES

#define kQuadSize sizeof(quad.bl)    
long offset = (long)&quad;

// vertex
int diff = offsetof(QuadVertex, vect);
glVertexPointer(2, GL_FLOAT, kQuadSize, (void*)(offset + diff));

// color
diff = offsetof(QuadVertex, color);
glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (void*)(offset + diff));

// texCoods
diff = offsetof(QuadVertex, texCoords);
glTexCoordPointer(2, GL_FLOAT, kQuadSize, (void*)(offset + diff));

Finally, assign the texture and draw the quad. glDrawArrays tells OpenGL to use the previously defined offsets together with the values contained in your Quad object to draw the shape defined by 4 vertices.

glBindTexture(GL_TEXTURE_2D, tex);

// Draw the quad
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glBindTexture(GL_TEXTURE_2D, 0);

Please also note that it is perfectly OK to use OpenGL ES 1 if you don't need shaders. The main difference between ES1 and ES2 is that, in ES2, there is no fixed pipeline, so you would need to implement a matrix stack plus shaders for the basic rendering on your own. If you are fine with the functionality offered by the fixed pipeline, just use OpenGL ES 1.

starbugs
  • 992
  • 1
  • 9
  • 14
  • Ok, but I don't fully understand how I can translate this into a function. Where do things like Vec2 come from - I get 'Vec2 does not name a type' when trying to compile it. – Skyler Apr 24 '12 at 14:42
  • From his example: "(consider Vec2 to be a struct of two floats (x,y) and color a struct with 4 bytes (r,g,b,a))" – Nathan Monteleone Apr 24 '12 at 14:44
  • I have just edited my answer, hope it is more useful for you now. It should be relatively simple to use this as a template for your port now. – starbugs Apr 24 '12 at 15:16
  • Thank you. Should this work in regular OpenGL as well? If I try it, I just get black for any image. – Skyler Apr 24 '12 at 15:22
  • It should work in both OpenGL and OpenGL ES. I suppose you are seeing a black image because of the vertex order. I have corrected it in the example. If you still see nothing, deactivate culling by calling glDisable(GL_CULL_FACE) and check if it works then. – starbugs Apr 24 '12 at 15:53
  • 1
    Nice thorough answer, but note that you put a value of 3 for glVertexPointer dimensions while you're sending 2-dimension quad vertices, that looks like a typo. – Tim Apr 24 '12 at 16:01
  • starbugs: I tried that and still got black. I noticed that it was complaining about the lack of "Color4B" after its struct declaration, but that didn't fix it either. I also tried `glEnable(GL_TEXTURE_2D)` in case that was needed, but still nothing. I put everything from `Quad quad;` to the end in the draw_img function; is this the right way to call this or should I re-define the structs each time? – Skyler Apr 24 '12 at 16:38
  • edit: I tried without all the structs and stuff and just hardcoding the vertex array, and it worked fine, so I suppose this code is just drawing the vertices in the wrong place. Can't figure out why though. – Skyler Apr 24 '12 at 17:10
  • 1
    I corrected the number of vertex floats in the code sample. Hope it is 100% correct now. – starbugs Apr 25 '12 at 08:10