iDevGames Forums
SDL_Surface to OpenGL Texture Corruption - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Graphics & Audio Programming (/forum-9.html)
+--- Thread: SDL_Surface to OpenGL Texture Corruption (/thread-3213.html)



SDL_Surface to OpenGL Texture Corruption - RyanA - Jun 23, 2007 03:45 PM

Recently I made a function that loaded a bitmap, and converted it to a texture in OpenGL, where everything that was "magic pink" (255, 0, 255) was transparent. From there, I wanted to use this to make a simple monospace font function.

For some reason, I have used the same/similar code yet I get different results when I use arrays. I am not sure if this is due to SDL or OpenGL. I have been getting help from Joseph Duchesne, and we can't seem to figure it out. So he told me this was the place to go. Wow

This is the struct for the monospace font:
Code:
struct MonoFont
{
    int glyph_width;
    int glyph_height;
    int glyph_tex_width;
    int glyph_tex_height;
    GLuint glyphs[128];
};

This function loads the bitmap (used this code for the bmp loader function..works fine on that. The only real difference is that this function uses arrays)
Code:
MonoFont LoadBmpFont(char *filename)
{
    MonoFont Temp;
    
    SDL_Surface *FullFont;
    FullFont = SDL_LoadBMP(filename);

    Temp.glyph_width = FullFont->w / 16;
    Temp.glyph_height = FullFont->h / 6;
    Temp.glyph_tex_width = NextPowerOfTwo(Temp.glyph_width);
    Temp.glyph_tex_height = NextPowerOfTwo(Temp.glyph_height);

    SDL_Surface *GlyphSurfaces[128];

    #if SDL_BYTEORDER == SDL_LIL_ENDIAN
        for(int i=0; i<128; i++)
        {
            GlyphSurfaces[i] = SDL_CreateRGBSurface(SDL_SWSURFACE, Temp.glyph_tex_width,
                Temp.glyph_tex_height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
        }
    #else
        for(int i=0; i<128; i++)
        {
            GlyphSurfaces[i] = SDL_CreateRGBSurface(SDL_SWSURFACE, Temp.glyph_tex_width,
                Temp.glyph_tex_height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
        }
    #endif

    Uint32 ColorKey;
    
    for(int i=0; i<128; i++)
    {
        ColorKey = SDL_MapRGBA(GlyphSurfaces[i]->format, 255, 0, 255, 0);
        SDL_FillRect(GlyphSurfaces[i], 0, ColorKey);
    }

    ColorKey = SDL_MapRGBA(FullFont->format, 255, 0, 255, 0);
    SDL_SetColorKey(FullFont, SDL_SRCCOLORKEY, ColorKey);

    SDL_Rect source;
    source.x = 0;
    source.y = 0;
    source.w = Temp.glyph_width;
    source.h = Temp.glyph_height;

    SDL_Rect dest;
    dest.x = 0;
    dest.y = 0;
    dest.w = Temp.glyph_width;
    dest.h = Temp.glyph_height;

    for(int i=32; i<128; i++)
    {
        SDL_BlitSurface(FullFont, &source, GlyphSurfaces[i], &dest);
    
        source.x += 8;
        if(source.x == 128)
        {
            source.x = 0;
            source.y += 12;
        }
    }

    for(int i=32; i<128; i++)
    {
        glGenTextures(1, &Temp.glyphs[i]);
        glBindTexture(GL_TEXTURE_2D, Temp.glyphs[i]);

        // Todo: Figure out what parameters I need here:
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Temp.glyph_tex_width, Temp.glyph_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, GlyphSurfaces[i]->pixels);
    }

        // Test output of one glyph..is this the problem? -Nope.
    SDL_SaveBMP(GlyphSurfaces[82], "char.bmp");
    return Temp;
}

Finally, I output the text with this function:
Code:
void DrawText(MonoFont font, int x, int y, char *text, ...)
{
    char FullText[1024];
    va_list ParseVars;
    va_start(ParseVars, text);
    vsprintf(FullText, text, ParseVars);
    va_end(ParseVars);

    int ascii;
    int glyph_x = x;

    for(int i=0; i<(int)strlen(text); i++)
    {
        ascii = (int)FullText[i];

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, font.glyphs[ascii]);
        glBegin(GL_QUADS);
            glTexCoord2f(0.0, 0.0);        glVertex2i(glyph_x, y);
            glTexCoord2f(1.0, 0.0);        glVertex2i(glyph_x + font.glyph_tex_width, y);
            glTexCoord2f(1.0, 1.0);        glVertex2i(glyph_x + font.glyph_tex_width, y+font.glyph_tex_height);
            glTexCoord2f(0.0, 0.0);        glVertex2i(glyph_x, y+font.glyph_tex_height);
        glEnd();
        glDisable(GL_TEXTURE_2D);

        glyph_x += font.glyph_width;
    }
}

An interesting thing I found is that the corruption looks different on different machines..so I am not too sure what the problem could be. Any ideas? I'd really appreciate it!

p.s: Here is what the corruption looks like, (on my machine). As you can sorta tell it is supposed to read "Hello World!".
[Image: blahaj9.png]

Thanks for your time!

Edit: Oops, I forgot to mention. I fooled around with outputting some of the SDL_Surfaces to see if that was the problem, but it turns out they all look how they should (when I save them to a bmp during runtime).


SDL_Surface to OpenGL Texture Corruption - Skorche - Jun 24, 2007 11:01 AM

I remember having all sorts of annoying problems getting SDL surfaces to load into OpenGL textures. One possibility is that SDL could be padding the end of each image row. (the 'pitch' field) Don't have the Red Book handy, but there is a function you can call to tell OpenGL about it.

My recommendation though is that loading textures from SDL surfaces just isn't worth the effort. Code for loading PNGs or JPEGs from their respective libraries are not difficult, it just takes a little manual reading. They are also ultimately much faster and more flexible.


SDL_Surface to OpenGL Texture Corruption - RyanA - Jun 24, 2007 11:40 AM

Thanks for the suggestion, Skorche. As for the pitch field, someone on Gamedev.net suggested the same thing. I placed that in the code though, with the same corrupted effect.

I used this:
Code:
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
glPixelStorei(GL_UNPACK_ROW_LENGTH, GlyphSurfaces[i]->pitch / GlyphSurfaces[i]->format->BytesPerPixel);

...

glPopClientAttrib();

As for your other suggestion, I would drop using SDL_Surfaces, if not for the fact if I have it implemented perfectly in another place in my code. I use this code to load a bitmap and make any pixel that is RGB (255, 0, 255) have an alpha value of 0, thus making it transparent.

Code:
Texture LoadBmp(char *filename)
{
    Texture Temp;

    SDL_Surface *bitmap;
    bitmap = SDL_LoadBMP(filename);

    Temp.width = bitmap->w;
    Temp.height = bitmap->h;
    Temp.tex_width = NextPowerOfTwo(bitmap->w);
    Temp.tex_height = NextPowerOfTwo(bitmap->h);

    SDL_Surface *image;
    image = SDL_CreateRGBSurface(SDL_SWSURFACE, Temp.tex_width, Temp.tex_height, 32,
        #if SDL_BYTEORDER == SDL_LIL_ENDIAN
            0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
        #else
            0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
        #endif
        );

    if(image == NULL)
    {
        WriteToLog("Error: Could not create image.");
        return Temp;
    }

    Uint32 ColorKey;
    ColorKey = SDL_MapRGBA(image->format, 255, 0, 255, 0);
    SDL_FillRect(image, 0, ColorKey);

    ColorKey = SDL_MapRGBA(bitmap->format, 255, 0, 255, 0);
    SDL_SetColorKey(bitmap, SDL_SRCCOLORKEY, ColorKey);

    SDL_Rect area;
    area.x = 0;
    area.y = 0;
    area.w = bitmap->w;
    area.h = bitmap->h;

    SDL_BlitSurface(bitmap, &area, image, &area);

    glGenTextures(1, &Temp.id);
    glBindTexture(GL_TEXTURE_2D, Temp.id);

    // Todo: Figure out what parameters I need here:
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Temp.tex_width, Temp.tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

    SDL_FreeSurface(bitmap);
    SDL_FreeSurface(image);

    return Temp;
}

If you compare the two, you can see how the font code and the bitmap code are pretty much the same thing. I am really happy with the bitmap code, I just am frustrated that I cannot make it work with the font code. I am just hoping there is a stupid mistake that I am not catching. Annoyed


SDL_Surface to OpenGL Texture Corruption - RyanA - Jun 24, 2007 03:22 PM

I am a dolt.

Code:
glBegin(GL_QUADS);
            glTexCoord2f(0.0, 0.0);        glVertex2i(glyph_x, y);
            glTexCoord2f(1.0, 0.0);        glVertex2i(glyph_x + font.glyph_tex_width, y);
            glTexCoord2f(1.0, 1.0);        glVertex2i(glyph_x + font.glyph_tex_width, y+font.glyph_tex_height);
            glTexCoord2f(0.0, 0.0);        glVertex2i(glyph_x, y+font.glyph_tex_height);
        glEnd();

The last tex coord is supposed to be: glTexCoord2f(0.0, 1.0); Thanks for all your help...I cannot believe this bug took 5 days to find Rasp. Thanks to Joseph Duchesne!