Original Post
Hello, Altough it doesn't seems to, this question could be summarized to "What can i do to render a textured plane?". Sorry if it seems to be a newbie question, but the problem is more complicated. I'm trying to program a little accelerated 2D library using, surprinsgly, OpenGL and SDL as GL context. In this library, there are a number of sprites in the screen that are textured planes. I'm using vertex and texture coord arrays to store sprite data so, as you can guess, rendering is made using glEnableClientState and gl*Pointer. A sprite can contain a number of frames, which are textures of the plane (SDL surfaces). When loading one, it is resized to be a power of two sized and converted to the screen format. It is done sucesfully, i've debugged it. The problem? Textures are not rendered. Since surface handling is done well, i thought that could be a problem of texture identifiers. After calling glIsTexture, this theory was rejected. This is the relevant piece of code:
//Init the engine
void SDL_GL_Renderer::init()
{
int cd;
switch (color_depth)
{
case CD_16:
cd = 16;
break;
case CD_24:
cd = 24;
break;
case CD_32:
cd = 32;
break;
}
SDL_Init(SDL_INIT_VIDEO);
sdl_surface = SDL_SetVideoMode(scr_x, scr_y, cd, SDL_OPENGL | SDL_GL_DOUBLEBUFFER);
if(fullscreen)
SDL_WM_ToggleFullScreen(sdl_surface.getRaw());
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, cd/3);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, cd/3);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, cd/3);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16 );
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1 );
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT, GL_FILL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 100, 0, 100);
}
//Rendering
void SDL_GL_Renderer::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
typedef std::deque<cPointer<Sprite> >::iterator It;
for(It i = sprites.begin(); i != sprites.end(); i++)
(*i)->render();
//AÑADIR OPCIONALIDAD EN DOBLE BUFFER
SDL_GL_SwapBuffers();
}
//Sprite's rendering
void SDL_GL_Sprite::render()
{
updateUVCoords();
glBindTexture(GL_TEXTURE_2D, textures.at(current_frame));
glTranslatef(x, y, 0.0);
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, textures.at(current_frame));
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*3, vertices);
glTexCoordPointer(2, GL_INT, sizeof(GLint)*2, uv_coords);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_QUADS, 0, 12);
glPopMatrix();
}
//Update the UV coords
void SDL_GL_Sprite::updateUVCoords()
{
uv_coords[0] = (GLint) 0;
uv_coords[1] = (GLint) 0;
uv_coords[2] = (GLint) 0;
uv_coords[3] = (GLint) frames.at(current_frame)->h;
uv_coords[4] = (GLint) frames.at(current_frame)->w;
uv_coords[5] = (GLint) frames.at(current_frame)->h;
uv_coords[6] = (GLint) frames.at(current_frame)->w;
uv_coords[7] = (GLint) 0;
}
//Load a frame
void SDL_GL_Sprite::loadFrame(const char* file)
{
frames.push_back(NULL);
textures.push_back(GLuint());
loadFrameInPos(file, frames.size() - 1);
}
//Load a frame from a file in a position
void SDL_GL_Sprite::loadFrameInPos(const char* file, size_t pos)
{
SDL_Surface* srf = IMG_Load(file);
SDL_Surface* srf_converted = SDL_DisplayFormat(srf);
SDL_FreeSurface(srf);
frames.at(pos) = srf_converted;
resizeSurfacePowTwo(&(frames.at(pos)));
SDL_Surface* srf2 = frames.at(pos).getRaw();
genGlTex(srf2, textures.at(pos));
}
//Resize an image to the nearest power of two
static void resizeSurfacePowTwo(cPointer<SDL_Surface>* srf)
{
//Nearest power of two
int p2w = (int) pow(2.0, ceil((float)log((*srf)->w)/log(2.0)));
int p2h = (int) pow(2.0, ceil((float)log((*srf)->h)/log(2.0)));
if(p2w == (*srf)->w && p2h == (*srf)->h)
return;
cPointer<SDL_Surface> new_srf = SDL_CreateRGBSurface(
(*srf)->flags,
max(p2w, p2h),
max(p2w, p2h),
(int) Core::getSingleton()->getRenderer()->getColorDepth(),
(*srf)->format->Rmask,
(*srf)->format->Gmask,
(*srf)->format->Bmask,
(*srf)->format->Amask);
SDL_BlitSurface(srf->getRaw(), &((*srf)->clip_rect),
new_srf.getRaw(), &(new_srf->clip_rect));
SDL_FreeSurface(srf->getRaw());
*srf = new_srf;
}
//Handy function for creating GL textures
static void genGlTex(SDL_Surface* srf, GLuint& tex)
{
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NICEST);
switch(srf->format->BitsPerPixel)
{
case (Uint8) 24:
glTexImage2D(GL_TEXTURE_2D, 0, 3, srf->w, srf->h,
0, GL_RGBA, GL_UNSIGNED_BYTE, srf->pixels);
break;
case (Uint8) 32:
glTexImage2D(GL_TEXTURE_2D, 0, 4, srf->w, srf->h,
0, GL_RGBA, GL_UNSIGNED_BYTE, srf->pixels);
break;
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}/*
The purpose of this piece of code is to be a part of a 2d graphic library where
different rendering enviroments could be selected (OGL and SDL+OGL)
*/
//Init the engine
void SDL_GL_Renderer::init()
{
int cd;
switch (color_depth)
{
case CD_16:
cd = 16;
break;
case CD_24:
cd = 24;
break;
case CD_32:
cd = 32;
break;
}
SDL_Init(SDL_INIT_VIDEO);
sdl_surface = SDL_SetVideoMode(scr_x, scr_y, cd, SDL_OPENGL | SDL_GL_DOUBLEBUFFER);
if(fullscreen)
SDL_WM_ToggleFullScreen(sdl_surface.getRaw());
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, cd/3);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, cd/3);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, cd/3);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16 );
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1 );
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT, GL_FILL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 100, 0, 100);
}
//Rendering
void SDL_GL_Renderer::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
typedef std::deque<cPointer<Sprite> >::iterator It;
for(It i = sprites.begin(); i != sprites.end(); i++)
(*i)->render();
//AÑADIR OPCIONALIDAD EN DOBLE BUFFER
SDL_GL_SwapBuffers();
}
//Sprite's rendering
void SDL_GL_Sprite::render()
{
updateUVCoords();
glBindTexture(GL_TEXTURE_2D, textures.at(current_frame));
glTranslatef(x, y, 0.0);
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, textures.at(current_frame));
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*3, vertices);
glTexCoordPointer(2, GL_INT, sizeof(GLint)*2, uv_coords);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_QUADS, 0, 12);
glPopMatrix();
}
//Update the UV coords
void SDL_GL_Sprite::updateUVCoords()
{
uv_coords[0] = (GLint) 0;
uv_coords[1] = (GLint) 0;
uv_coords[2] = (GLint) 0;
uv_coords[3] = (GLint) frames.at(current_frame)->h;
uv_coords[4] = (GLint) frames.at(current_frame)->w;
uv_coords[5] = (GLint) frames.at(current_frame)->h;
uv_coords[6] = (GLint) frames.at(current_frame)->w;
uv_coords[7] = (GLint) 0;
}
//Load a frame
void SDL_GL_Sprite::loadFrame(const char* file)
{
frames.push_back(NULL);
textures.push_back(GLuint());
loadFrameInPos(file, frames.size() - 1);
}
//Load a frame from a file in a position
void SDL_GL_Sprite::loadFrameInPos(const char* file, size_t pos)
{
SDL_Surface* srf = IMG_Load(file);
SDL_Surface* srf_converted = SDL_DisplayFormat(srf);
SDL_FreeSurface(srf);
frames.at(pos) = srf_converted;
resizeSurfacePowTwo(&(frames.at(pos)));
SDL_Surface* srf2 = frames.at(pos).getRaw();
genGlTex(srf2, textures.at(pos));
}
//Resize an image to the nearest power of two
static void resizeSurfacePowTwo(cPointer<SDL_Surface>* srf)
{
//Nearest power of two
int p2w = (int) pow(2.0, ceil((float)log((*srf)->w)/log(2.0)));
int p2h = (int) pow(2.0, ceil((float)log((*srf)->h)/log(2.0)));
if(p2w == (*srf)->w && p2h == (*srf)->h)
return;
cPointer<SDL_Surface> new_srf = SDL_CreateRGBSurface(
(*srf)->flags,
max(p2w, p2h),
max(p2w, p2h),
(int) Core::getSingleton()->getRenderer()->getColorDepth(),
(*srf)->format->Rmask,
(*srf)->format->Gmask,
(*srf)->format->Bmask,
(*srf)->format->Amask);
SDL_BlitSurface(srf->getRaw(), &((*srf)->clip_rect),
new_srf.getRaw(), &(new_srf->clip_rect));
SDL_FreeSurface(srf->getRaw());
*srf = new_srf;
}
//Handy function for creating GL textures
static void genGlTex(SDL_Surface* srf, GLuint& tex)
{
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NICEST);
switch(srf->format->BitsPerPixel)
{
case (Uint8) 24:
glTexImage2D(GL_TEXTURE_2D, 0, 3, srf->w, srf->h,
0, GL_RGB, GL_UNSIGNED_BYTE, srf->pixels);
break;
case (Uint8) 32:
glTexImage2D(GL_TEXTURE_2D, 0, 4, srf->w, srf->h,
0, GL_RGBA, GL_UNSIGNED_BYTE, srf->pixels);
break;
}
}
Maybe you have notice the presence of odd classes with odd member calls (::getRaw()): The class is a smart pointer implementation which it hasn't implemented the automatic conversion to * (i found getRaw() call more clear) ). Of course, there are a lot of things that can be optimized, but i'll do that in the future, when things going well. I'm trying the sample using 32 bpp. Where am i wrong? Thank you very much in advance.