Skip to main content
GameDev.net gamedev.net
🔒 Locked

Texturing issues using UV array

Started by LCO Aug 24, 2006 at 1:18 PM 2 replies 400+ views
Original Post
LCO
LCO
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.
Kalidor
Kalidor
Quote:
Original post by LCO
...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NICEST);
...
GL_NICEST isn't a valid minification filter. Use either GL_NEAREST or GL_LINEAR, since you aren't creating mipmaps. I didn't read the rest of your code but if it still doesn't work after that I'll try to continue following it.

It's also best to put that much source code in source tags instead of code tags.
LCO
LCO
Quote:

GL_NICEST isn't a valid minification filter.

Bingo. Now the texture is shown. I thought OpenGL would ignore that parameter if i didn't use mipmapping.

Thank you!

About the code, i've tried to post only the needed member functions, so sorry if it is a huge bunch. I could have ignore some pieces, but some people probably would reply me that i'm not calling glEnable(GL_TEXTURE_2D) or such init stuff.
Kalidor
Kalidor
Quote:
Original post by LCO
Bingo. Now the texture is shown. I thought OpenGL would ignore that parameter if i didn't use mipmapping.
OpenGL does ignore the function call (well, it sets the error flag to GL_INVALID_ENUM, then ignores it), but it still needs to know how you want to minify the texture. I suppose it could assume one of the non-mipmapping filters depending on which mipmapping filter is set (GL_NEAREST_MIPMAP_LINEAR is the default), but instead it assumes you want mipmapping and therefore acts as if texturing is disabled if the texture is not "complete."
Quote:
Original post by LCO
Thank you!
Any time. [smile]
Quote:
Original post by LCO
About the code, i've tried to post only the needed member functions, so sorry if it is a huge bunch. I could have ignore some pieces, but some people probably would reply me that i'm not calling glEnable(GL_TEXTURE_2D) or such init stuff.
The amount of code isn't a problem (although it looks like you pasted it twice [grin]), it's just easier to look at that much in the nice scrollable text box you get with source tags. If you didn't paste the init code and I overlooked the min filter, I probably would've posted about being sure to enable texturing. [grin]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.