Difference between revisions of "Porting to GLES from GL"
(→Known issues: cat) |
|||
(15 intermediate revisions by 5 users not shown) | |||
Line 2: | Line 2: | ||
This guide is based on my limited knowledge (I do have barely the requierement) on the subject. I'm open to get edits on it, in fact it is encouraged :) | This guide is based on my limited knowledge (I do have barely the requierement) on the subject. I'm open to get edits on it, in fact it is encouraged :) | ||
--[[User:Sebt3|Sebt3]] 17:05, 24 February 2011 (MET) | --[[User:Sebt3|Sebt3]] 17:05, 24 February 2011 (MET) | ||
+ | |||
+ | You might want to try [http://boards.openpandora.org/index.php/topic/11506-opengl-implementation-tldr-more-games/page-1 libGL] before following the instructions on this page. | ||
+ | |||
== Requirements == | == Requirements == | ||
* a working toolchain | * a working toolchain | ||
Line 26: | Line 29: | ||
<source lang=bash> | <source lang=bash> | ||
#!/bin/sh | #!/bin/sh | ||
− | + | ||
search() { | search() { | ||
− | find . -name "*.h" -o -name "*.c" -o -name "*.cpp" -exec grep -Hn "$*" {} \; | + | find . \( -name "*.h" -o -name "*.c" -o -name "*.cpp" -o -name "*.cxx" \) -exec grep -Hn "$*" {} \; |
} | } | ||
− | + | ||
listIssues() { | listIssues() { | ||
search SDL_WM_GrabInput | search SDL_WM_GrabInput | ||
Line 48: | Line 51: | ||
search glTexImage2D | search glTexImage2D | ||
search glBegin | search glBegin | ||
+ | search glX | ||
+ | search glRect | ||
+ | search glNewList | ||
} | } | ||
+ | |||
+ | listIssues|sort -u | ||
− | |||
</source> | </source> | ||
Run that from the source directory. The fewer lines displayed, the better. | Run that from the source directory. The fewer lines displayed, the better. | ||
Line 82: | Line 89: | ||
At the end of this process you'll end up with a broken pandora binary. Let's now fix it :D | At the end of this process you'll end up with a broken pandora binary. Let's now fix it :D | ||
== Adding the EGL context == | == Adding the EGL context == | ||
− | Grab the eglport package Pickle has built [http:// | + | Grab the eglport package Pickle has built [http://sourceforge.net/p/eglport/code-0/ here]. You will need to add a call to its 3 functions in the sources (make sure, also, that eglport.c is built and linked in the build process). Here is how your sources should look at the end : |
<source lang=c> | <source lang=c> | ||
#if !defined(HAVE_GLES) | #if !defined(HAVE_GLES) | ||
Line 90: | Line 97: | ||
#include "eglport.h" | #include "eglport.h" | ||
#endif | #endif | ||
+ | |||
+ | #include <SDL/SDL.h> | ||
int main( void ) | int main( void ) | ||
Line 96: | Line 105: | ||
SDL_Init( SDL_INIT_VIDEO ); | SDL_Init( SDL_INIT_VIDEO ); | ||
− | |||
− | |||
− | |||
− | |||
// some more initialisations | // some more initialisations | ||
+ | SDL_Surface* screen; | ||
#if !defined(HAVE_GLES) | #if !defined(HAVE_GLES) | ||
Line 107: | Line 113: | ||
#else | #else | ||
screen = SDL_SetVideoMode( 800, 480, 0, SDL_SWSURFACE | SDL_FULLSCREEN ); | screen = SDL_SetVideoMode( 800, 480, 0, SDL_SWSURFACE | SDL_FULLSCREEN ); | ||
− | + | if (EGL_Open( 800, 480 )) | |
+ | exit(1); | ||
#endif | #endif | ||
Line 125: | Line 132: | ||
#if defined(HAVE_GLES) | #if defined(HAVE_GLES) | ||
− | + | EGL_Close(); | |
#endif | #endif | ||
SDL_Quit(); | SDL_Quit(); | ||
Line 134: | Line 141: | ||
Please note that : | Please note that : | ||
− | |||
* SDL_SetVideoMode arguments have to be those given here (aka good resolution, and no SDL_OPENGL flag) | * SDL_SetVideoMode arguments have to be those given here (aka good resolution, and no SDL_OPENGL flag) | ||
− | * | + | * EGL_Open goes just after SDL_SetVideoMode, the parameters are the same resolution used in SDL_SetVideoMode |
* '''All''' SDL_GL_SwapBuffers calls have to be converted to EGL_SwapBuffers calls. | * '''All''' SDL_GL_SwapBuffers calls have to be converted to EGL_SwapBuffers calls. | ||
* EGL_Close is called before quitting SDL (or closing the video if that's separated in your original source). | * EGL_Close is called before quitting SDL (or closing the video if that's separated in your original source). | ||
When built, your source should run on the Pandora cleanly (ok, you'll have a black screen, but that's expected as we haven't converted the drawing yet). | When built, your source should run on the Pandora cleanly (ok, you'll have a black screen, but that's expected as we haven't converted the drawing yet). | ||
+ | |||
+ | ''In addition to these instructions, I had to add "#include <X11/Xlib.h>" and change all the comments from line to block in eglport.c --lunixbochs | ||
+ | * ''That was in old version (of eglport), you shouldn't need it it new version --M-HT | ||
== Converting the easy stuff == | == Converting the easy stuff == | ||
Line 153: | Line 162: | ||
#define glClearDepth glClearDepthf | #define glClearDepth glClearDepthf | ||
#define glOrtho glOrthof | #define glOrtho glOrthof | ||
+ | #define glFrustum glFrustumf | ||
=== Colors === | === Colors === | ||
GLES only knows glColor4f as the function to create a color; all the glColor3f, glColor3d, glColor4d or any other color conventions have to be converted to glColor4f. If you only have 3 arguments, the last have to be 1.0f (as no transparency). | GLES only knows glColor4f as the function to create a color; all the glColor3f, glColor3d, glColor4d or any other color conventions have to be converted to glColor4f. If you only have 3 arguments, the last have to be 1.0f (as no transparency). | ||
− | glColor3fv(a) | + | #define glColor4fv(a) glColor4f(a[0], a[1], a[2], a[3]) |
+ | #define glColor3fv(a) glColor4f(a[0], a[1], a[2], 1.0f) | ||
+ | #define glColor3f(a,b,c) glColor4f(a, b, c, 1.0f) | ||
== Converting the immediate mode == | == Converting the immediate mode == | ||
Line 262: | Line 274: | ||
#endif | #endif | ||
</source> | </source> | ||
+ | 4) GL_QUAD_STRIP : | ||
+ | <source lang=c> | ||
+ | #if !defined(HAVE_GLES) | ||
+ | glBegin(GL_QUAD_STRIP); | ||
+ | // Front | ||
+ | glVertex3f(-left, 0, front); // bottom left | ||
+ | glVertex3f(-left-wider, height, front+wider); // top left | ||
+ | glVertex3f( right, 0, front); // bottom right | ||
+ | glVertex3f( right+wider, height, front+wider); // top right | ||
+ | |||
+ | // Right | ||
+ | glVertex3f( right, 0,-back); // bottom r | ||
+ | glVertex3f( right+wider, height,-back-wider); // top r | ||
+ | |||
+ | // Back | ||
+ | glVertex3f(-left, 0, -back); // bottom right | ||
+ | glVertex3f(-left-wider, height, -back-wider); // top right | ||
+ | |||
+ | // Left | ||
+ | glVertex3f(-left, 0, front); // bottom r | ||
+ | glVertex3f(-left-wider, height, front+wider); // top r | ||
+ | glEnd(); | ||
+ | #else | ||
+ | { | ||
+ | GLfloat vtx1[] = {-left, 0, front, -left-wider, height, front+wider, right, 0, front, right+wider, height, front+wider}; | ||
+ | GLfloat vtx2[] = {right, 0, front, right+wider, height, front+wider, right, 0,-back, right+wider, height,-back-wider}; | ||
+ | GLfloat vtx3[] = {right, 0,-back, right+wider, height,-back-wider, -left, 0, -back, -left-wider, height, -back-wider}; | ||
+ | GLfloat vtx4[] = {-left, 0, -back, -left-wider, height, -back-wider, -left, 0, front, -left-wider, height, front+wider}; | ||
+ | glEnableClientState(GL_VERTEX_ARRAY); | ||
+ | glVertexPointer(3, GL_FLOAT, 0, vtx1); | ||
+ | glDrawArrays(GL_TRIANGLE_FAN,0,4); | ||
+ | glVertexPointer(3, GL_FLOAT, 0, vtx2); | ||
+ | glDrawArrays(GL_TRIANGLE_FAN,0,4); | ||
+ | glVertexPointer(3, GL_FLOAT, 0, vtx3); | ||
+ | glDrawArrays(GL_TRIANGLE_FAN,0,4); | ||
+ | glVertexPointer(3, GL_FLOAT, 0, vtx4); | ||
+ | glDrawArrays(GL_TRIANGLE_FAN,0,4); | ||
+ | glDisableClientState(GL_VERTEX_ARRAY); | ||
+ | } | ||
+ | #endif | ||
+ | </source> | ||
+ | 5) using int/short : | ||
+ | <source lang=c> | ||
+ | #if !defined(HAVE_GLES) | ||
+ | glBegin(GL_QUADS); | ||
+ | glTexCoord2i(0, 1); glVertex2i(-256, -256); | ||
+ | glTexCoord2i(0, 0); glVertex2i(-256, 256); | ||
+ | glTexCoord2i(1, 0); glVertex2i(256, 256); | ||
+ | glTexCoord2i(1, 1); glVertex2i(256, -256); | ||
+ | glEnd(); | ||
+ | #else | ||
+ | GLshort vtx1[] = { -256, -256, -256, 256, 256, 256, 256, -256 }; | ||
+ | GLshort tex1[] = { 0, 1, 0, 0, 1, 0, 1, 1 }; | ||
+ | glEnableClientState(GL_VERTEX_ARRAY); | ||
+ | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
+ | |||
+ | glVertexPointer(2, GL_SHORT, 0, vtx1); | ||
+ | glTexCoordPointer(2, GL_SHORT, 0, tex1); | ||
+ | glDrawArrays(GL_TRIANGLE_FAN,0,4); | ||
+ | |||
+ | glDisableClientState(GL_VERTEX_ARRAY); | ||
+ | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
+ | #endif | ||
+ | </source> | ||
+ | 5) glRect : | ||
+ | <source lang=c> | ||
+ | #ifndef HAVE_GLES | ||
+ | glRecti ( dx + min[0], dy + min[1], | ||
+ | dx + max[0], dy + max[1] ) ; | ||
+ | #else | ||
+ | GLshort vtx1[] = { dx + min[0], dy + min[1], dx + min[0], dy + max[1], dx + max[0], dy + max[1], dx + max[0], dy + min[1]}; | ||
+ | glEnableClientState(GL_VERTEX_ARRAY); | ||
+ | glVertexPointer(2, GL_SHORT, 0, vtx1); | ||
+ | glDrawArrays(GL_TRIANGLE_FAN,0,4); | ||
+ | glDisableClientState(GL_VERTEX_ARRAY); | ||
+ | #endif | ||
+ | </source> | ||
+ | |||
+ | |||
Note that the last argument of glDrawArrays is the number of points. In these examples, that's always 4 because these all have 4 points. You might want to change that if your object has more (or less) than these 4 points. | Note that the last argument of glDrawArrays is the number of points. In these examples, that's always 4 because these all have 4 points. You might want to change that if your object has more (or less) than these 4 points. | ||
Line 290: | Line 381: | ||
== Known issues == | == Known issues == | ||
− | * glPushAttrib, glPopAttrib and their client versions don't exist. You'll have to manage these states yourself. Another good way is to have all disabled at all times and only enable what is needed at the right time. | + | * glPushAttrib, glPopAttrib and their client versions don't exist. You'll have to manage these states yourself. Another good way is to have all disabled at all times and only enable what is needed at the right time. and see racer sources (http://sebt3.openpandora.org/src/?f=racer-pandora-src.tar.bz2) to get a partial implementation |
* SDL_WM_GrabInput and SDL_WarpMouse might cause soft freeze of your game. If it does, #ifndef PANDORA them :) | * SDL_WM_GrabInput and SDL_WarpMouse might cause soft freeze of your game. If it does, #ifndef PANDORA them :) | ||
Latest revision as of 10:53, 28 July 2013
Contents
Foreword
This guide is based on my limited knowledge (I do have barely the requierement) on the subject. I'm open to get edits on it, in fact it is encouraged :) --Sebt3 17:05, 24 February 2011 (MET)
You might want to try libGL before following the instructions on this page.
Requirements
- a working toolchain
- average C/C++ knowledge
- basic knowledge of how GL or GLES works
- read OpenGL_ES_1.1_Tutorial
You might also want to have a look at others' work in this matter :
- http://pickle.gp2x.de/source/kenlabes-src.zip
- http://pickle.gp2x.de/gish_src.zip
- http://sebt3.openpandora.org/src/briquolo-0.5.7-pandora.tar.gz
- http://sebt3.openpandora.org/src/zaz-1.0.0-pandora.tar.gz
- http://paeryn.myby.co.uk/pandora/sdl-ball.tar.bz2
- ...
For more references, have a look to :
Before starting
Choose a simple GL game for your first experience. Working with a large and complex codebase is not what you want to do at first.
To have a good view of what you'll need to do, here is a simple (and incomplete) bash script that will list you all the code lines you'll need to work with :
#!/bin/sh
search() {
find . \( -name "*.h" -o -name "*.c" -o -name "*.cpp" -o -name "*.cxx" \) -exec grep -Hn "$*" {} \;
}
listIssues() {
search SDL_WM_GrabInput
search SDL_WarpMouse
search SDL_GL
search GL_CLAMP
search glColor|grep -v glColor4f
search glPushAttrib
search glPolygonMode
search GL_QUADS |grep glDrawArrays
search SDL_Init
search SDL_OPENGL
search SDL_ShowCursor
search glClearDepth
search SDL_Quit
search gluBuild2DMipmaps
search glTexImage2D
search glBegin
search glX
search glRect
search glNewList
}
listIssues|sort -u
Run that from the source directory. The fewer lines displayed, the better.
If your project uses some GL libraries, get that to build first. Here are some libraries ported to GLES :
- GLU : http://code.google.com/p/glues/ (you might want to grab a binary version with headers in zaz or briquolo pnd)
- FTGL : http://code.google.com/p/ftgles/ (I do have a fixed version here; if you prefer a binary version, get that in the zaz PND)
Getting it to build
Your first goal is to have it built. You'll probably need to hack the build system.
- If it's just Makefiles, replace -lGL with -lGLES_CM -lEGL -lX11.
- If it's an autotools project, have a look at how it's done in briquolo for references. (take a look at configure.ac, and follow the enable_gles bits ;) Dont forget the Makefile.am too. Once your edits are in, autoreconf is your friend.)
Make sure your build system (or your toolchain) will also set defines some marker to know if it needs to build GL or GLES code. Having one too for pandora specific hack might show itself useful too. I'm using "-DPANDORA -DHAVE_GLES" myself.
Now try to build it. You'll have errors in the build process. To fix them, for now, just #ifdef out the offending lines. Here is what to do with the include instructions :
#if !defined(HAVE_GLES)
#include <GL/gl.h>
#else
#include <GLES/gl.h>
#endif
Other offending code, should be #ifdef out like this :
#if !defined(HAVE_GLES)
glClearDepth(1.0f);
#endif
At the end of this process you'll end up with a broken pandora binary. Let's now fix it :D
Adding the EGL context
Grab the eglport package Pickle has built here. You will need to add a call to its 3 functions in the sources (make sure, also, that eglport.c is built and linked in the build process). Here is how your sources should look at the end :
#if !defined(HAVE_GLES)
#include <GL/gl.h>
#else
#include <GLES/gl.h>
#include "eglport.h"
#endif
#include <SDL/SDL.h>
int main( void )
{
// other stuff here
SDL_Init( SDL_INIT_VIDEO );
// some more initialisations
SDL_Surface* screen;
#if !defined(HAVE_GLES)
screen = SDL_SetVideoMode( 800, 600, 0, SDL_HWSURFACE | SDL_OPENGL | SDL_FULLSCREEN);
#else
screen = SDL_SetVideoMode( 800, 480, 0, SDL_SWSURFACE | SDL_FULLSCREEN );
if (EGL_Open( 800, 480 ))
exit(1);
#endif
// the event loop
while( quit == 0 ) {
// management of the even and the game
#if !defined(HAVE_GLES)
SDL_GL_SwapBuffers();
#else
EGL_SwapBuffers();
#endif
}
// probably some more clean-ups here
#if defined(HAVE_GLES)
EGL_Close();
#endif
SDL_Quit();
return 0;
}
Please note that :
- SDL_SetVideoMode arguments have to be those given here (aka good resolution, and no SDL_OPENGL flag)
- EGL_Open goes just after SDL_SetVideoMode, the parameters are the same resolution used in SDL_SetVideoMode
- All SDL_GL_SwapBuffers calls have to be converted to EGL_SwapBuffers calls.
- EGL_Close is called before quitting SDL (or closing the video if that's separated in your original source).
When built, your source should run on the Pandora cleanly (ok, you'll have a black screen, but that's expected as we haven't converted the drawing yet).
In addition to these instructions, I had to add "#include <X11/Xlib.h>" and change all the comments from line to block in eglport.c --lunixbochs
- That was in old version (of eglport), you shouldn't need it it new version --M-HT
Converting the easy stuff
This part could have been done while getting the game built, but I preferred splitting the 2 processes for readability. Feel free to work as you please :D. Remember that all you have #ifdef out in the building part has to be converted; don't forget anything.
GLES only supports float; double (aka GLdouble) doesn't work. So :
- any GLdouble should be converted to GLfloat
- all GL function calls ending with a "d" should have the d replaced with f.
Here are other know conversions :
#define GLdouble GLfloat #define GL_CLAMP GL_CLAMP_TO_EDGE #define glClearDepth glClearDepthf #define glOrtho glOrthof #define glFrustum glFrustumf
Colors
GLES only knows glColor4f as the function to create a color; all the glColor3f, glColor3d, glColor4d or any other color conventions have to be converted to glColor4f. If you only have 3 arguments, the last have to be 1.0f (as no transparency).
#define glColor4fv(a) glColor4f(a[0], a[1], a[2], a[3]) #define glColor3fv(a) glColor4f(a[0], a[1], a[2], 1.0f) #define glColor3f(a,b,c) glColor4f(a, b, c, 1.0f)
Converting the immediate mode
If you have read OpenGL_ES_1.1_Tutorial, you already have a good idea of what needs to be changed here. Here are a few other examples to help you in your process :
1) a simple quad with no texture or color :
#if !defined(HAVE_GLES)
glBegin(GL_QUADS);
glVertex2f(-10,-10);
glVertex2f(10,-10);
glVertex2f(10,10);
glVertex2f(-10,10);
glEnd();
#else
GLfloat q3[] = {
-10,-10,
10,-10,
10,10,
-10,10
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, q3);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
#endif
2) a textured quad :
glBindTexture(GL_TEXTURE_2D, carac->TextureName);
#if !defined(HAVE_GLES)
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(pos[0]-tailleX/2, pos[1]-tailleY/2, 0);
glTexCoord2f(1,0);
glVertex3f(pos[0]+tailleX/2, pos[1]-tailleY/2, 0);
glTexCoord2f(1,1);
glVertex3f(pos[0]+tailleX/2, pos[1]+tailleY/2, 0);
glTexCoord2f(0,1);
glVertex3f(pos[0]-tailleX/2, pos[1]+tailleY/2, 0);
glEnd();
#else
GLfloat vtx1[] = {
pos[0]-tailleX/2, pos[1]-tailleY/2, 0,
pos[0]+tailleX/2, pos[1]-tailleY/2, 0,
pos[0]+tailleX/2, pos[1]+tailleY/2, 0,
pos[0]-tailleX/2, pos[1]+tailleY/2, 0
};
GLfloat tex1[] = {
0,0,
1,0,
1,1,
0,1
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vtx1);
glTexCoordPointer(2, GL_FLOAT, 0, tex1);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
#endif
3) a colored quad (note that, as GL is a state machine, the color is only showed once in the GL code, while it is copied for every point in gles) :
#if !defined(HAVE_GLES)
glBegin(GL_QUADS);
glColor3d( .1, .1, .7);
glVertex3d(0, 0, 0);
glVertex3d(0, -pbarheight, 0);
glColor3d( 0, 0, 0.5);
glVertex3d((startupProgress / startupProgressSteps) * pbarwidth, -pbarheight, 0);
glVertex3d((startupProgress / startupProgressSteps) * pbarwidth, 0, 0);
glEnd();
#else
GLfloat vtx1[] = {
0, 0, 0,
0, -pbarheight, 0,
(startupProgress / startupProgressSteps) * pbarwidth, -pbarheight, 0,
(startupProgress / startupProgressSteps) * pbarwidth, 0, 0
};
GLfloat col1[] = {
.1, .1, .7, 1.0f,
.1, .1, .7, 1.0f,
0, 0, 0.5, 1.0f,
0, 0, 0.5, 1.0f
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vtx1);
glColorPointer(4, GL_FLOAT, 0, col1);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
#endif
4) GL_QUAD_STRIP :
#if !defined(HAVE_GLES)
glBegin(GL_QUAD_STRIP);
// Front
glVertex3f(-left, 0, front); // bottom left
glVertex3f(-left-wider, height, front+wider); // top left
glVertex3f( right, 0, front); // bottom right
glVertex3f( right+wider, height, front+wider); // top right
// Right
glVertex3f( right, 0,-back); // bottom r
glVertex3f( right+wider, height,-back-wider); // top r
// Back
glVertex3f(-left, 0, -back); // bottom right
glVertex3f(-left-wider, height, -back-wider); // top right
// Left
glVertex3f(-left, 0, front); // bottom r
glVertex3f(-left-wider, height, front+wider); // top r
glEnd();
#else
{
GLfloat vtx1[] = {-left, 0, front, -left-wider, height, front+wider, right, 0, front, right+wider, height, front+wider};
GLfloat vtx2[] = {right, 0, front, right+wider, height, front+wider, right, 0,-back, right+wider, height,-back-wider};
GLfloat vtx3[] = {right, 0,-back, right+wider, height,-back-wider, -left, 0, -back, -left-wider, height, -back-wider};
GLfloat vtx4[] = {-left, 0, -back, -left-wider, height, -back-wider, -left, 0, front, -left-wider, height, front+wider};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vtx1);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glVertexPointer(3, GL_FLOAT, 0, vtx2);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glVertexPointer(3, GL_FLOAT, 0, vtx3);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glVertexPointer(3, GL_FLOAT, 0, vtx4);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
}
#endif
5) using int/short :
#if !defined(HAVE_GLES)
glBegin(GL_QUADS);
glTexCoord2i(0, 1); glVertex2i(-256, -256);
glTexCoord2i(0, 0); glVertex2i(-256, 256);
glTexCoord2i(1, 0); glVertex2i(256, 256);
glTexCoord2i(1, 1); glVertex2i(256, -256);
glEnd();
#else
GLshort vtx1[] = { -256, -256, -256, 256, 256, 256, 256, -256 };
GLshort tex1[] = { 0, 1, 0, 0, 1, 0, 1, 1 };
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_SHORT, 0, vtx1);
glTexCoordPointer(2, GL_SHORT, 0, tex1);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
#endif
5) glRect :
#ifndef HAVE_GLES
glRecti ( dx + min[0], dy + min[1],
dx + max[0], dy + max[1] ) ;
#else
GLshort vtx1[] = { dx + min[0], dy + min[1], dx + min[0], dy + max[1], dx + max[0], dy + max[1], dx + max[0], dy + min[1]};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_SHORT, 0, vtx1);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
#endif
Note that the last argument of glDrawArrays is the number of points. In these examples, that's always 4 because these all have 4 points. You might want to change that if your object has more (or less) than these 4 points.
Here is a list of conversions between GL to GLES draw modes :
- GL_POINTS -> GL_POINTS
- GL_TRIANGLES -> GL_TRIANGLES (or GL_LINE_LOOP if glPolygonMode is set to GL_LINE)
- GL_QUADS -> GL_TRIANGLE_FAN
- GL_LINE_STRIP -> GL_LINE_STRIP
- GL_LINE -> GL_LINE
- GL_POLYGON -> GL_TRIANGLE_FAN
Textures
All textures have to be loaded with dimensions in powers of 2. See GLES2D sources and GLES2D_p2 function for an easy method of working around that. Briquolo had a more advanced method of doing so thanks to Paeryn (it also actually scaled the texture to that given size).
When loading textures with glTexImage2D, the only supported formats are GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, or GL_LUMINANCE_ALPHA. Arguments for internal format and format(3 and 7) must be the same. Note: one common situation is where the original program uses 3 or 4 (which is valid for opengl) for internal format and GL_RGB or GL_RGBA for format. GLES requires the 3 to be GL_RGB or 4 to be GL_RGBA. GLES Example:
glTexImage2D( target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Display Lists
GL Functions: glGenLists, glCallList, glCallLists, glDeleteLists, glNewList
This is a feature provided by GL to allow the application to assign a group of GL commands to a display list. This list is remembered by the graphics card and the application only has to call the list once to get the gpu to rerun all of the assigned commands. GLES does not support this feature and must rerun the set of commands any time the list would have been called. Info on Display Lists
Known issues
- glPushAttrib, glPopAttrib and their client versions don't exist. You'll have to manage these states yourself. Another good way is to have all disabled at all times and only enable what is needed at the right time. and see racer sources (http://sebt3.openpandora.org/src/?f=racer-pandora-src.tar.bz2) to get a partial implementation
- SDL_WM_GrabInput and SDL_WarpMouse might cause soft freeze of your game. If it does, #ifndef PANDORA them :)