1
\$\begingroup\$

been messing with OpenGL and SDL for a pair of weeks.

The thing is quite weird. I have been loading a texture from a BMP and using a really easy shader to make it work, and so far it has worked very well.

Now, i've refractored my code and made a heightmap loader, with is pretty cool and works nice. I have a ResourceManager class which successfully loads shaders but fails at loading textures.

The structure of that class is simple:

  • Constructor (empty)
  • Destructor (empty)
  • AddTexture (const char* FileName, const char* indexName)
  • GetTexture (const char* indexName)
  • typedef map TextureMap
  • typedef TextureMap::iterator TextureIt
  • TextureMap Textures

I tried using SDL Load BMP function and SDL_img Load IMG function. The first one makes this weird result:

Close-Up

When the real image is a simple BMP in 32bit format, as always:

Real Texture

And the second method, using SDL_image, simply doesn't show the image.

The 'AddTexture' function:

bool TEXTURE::TextureManager::AddTexture(const char* fileName, const char* indexName)
{
    SDL_Surface* img = SDL_LoadBMP(fileName);
unsigned int id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->w, img->h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, img->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
SDL_FreeSurface(img);
Textures[indexName] = id;
return true;
}

And the 'AddTexture' SDL_image version:

GLuint id = 0;

SDL_Surface* Surface = IMG_Load(fileName);

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

int Mode = NULL;
if(Surface->format->BytesPerPixel == 4)
    Mode = GL_RGBA;
else
    Mode = GL_RGB;

glTexImage2D(GL_TEXTURE_2D, 0, Mode, Surface->w, Surface->h, 0, Mode, GL_UNSIGNED_BYTE, Surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glBindTexture(GL_TEXTURE_2D, 0);

std::cout << "The ID of the tex is " << id << std::endl;

Textures[indexName] = id;

return true;

I create the texture here:

Res->TexManager->AddTextureAlt("res/sum.bmp", "Brick");

And the following code is used to bind the texture:

GLuint TEX = Res->TexManager->GetTexture("Brick");
glBindTexture(GL_TEXTURE_2D, TEX);

The normals and tex coords are alright, i've been using it all the time and it was displaying the tex and light perfectly well before.

I can't find the problem. I just can't. Is someone able to help a poor noob?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Your problem is that there are almost an infinite number of different image formats which can be represented inside an SDL_Surface, and you're telling OpenGL that this particular SDL_Surface is an RGB image made of 5-6-5 bits each of red, green, and blue, when it probably isn't!

What you need to do is after loading the image, but before giving it to OpenGL, you need to copy the SDL_Surface into another SDL_Surface which you've created with a known image format, which matches the format you tell OpenGL.

Personally, I like converting to 8888 RGBA, because that supports everything and is simple and easy (565 has no bits for an alpha channel, for example). If you're strongly concerned about memory usage, you might want to modify this a bit to use some other format. But as a first stab at a solution and to illustrate the issue you're running into, this code works. :)

Here's my code to do this conversion, which is mostly adapted from a very old SDL wiki page which I can't find any more. It assumes that the file you've loaded is in a SDL_Surface* named 'source'. (My full code is available here, if you want more context than I've pasted into this answer).

SDL_Surface *image = SDL_CreateRGBSurface(
        SDL_SWSURFACE,
        w, h,
        32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
        0x000000FF,
        0x0000FF00,
        0x00FF0000,
        0xFF000000
#else
        0xFF000000,
        0x00FF0000,
        0x0000FF00,
        0x000000FF
#endif
        );

saved_flags = source->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
saved_alpha = source->format->alpha;
if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
    SDL_SetAlpha(source, 0, SDL_ALPHA_OPAQUE);
}

/* Copy the surface into the GL texture image */
area.x = 0;
area.y = 0;
area.w = source->w;
area.h = source->h;
SDL_BlitSurface(source, &area, image, &area);

/* Restore the alpha blending attributes */
if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
    SDL_SetAlpha(source, saved_flags, saved_alpha);
}
(... normal OpenGL texture creation code goes here)
glTexImage2D(GL_TEXTURE_2D,
    0,
    GL_RGBA,
    w, h,
    0,
    GL_RGBA,
    GL_UNSIGNED_INT_8_8_8_8_REV,
    image->pixels);
\$\endgroup\$
1
  • \$\begingroup\$ Oh wow, that pretty much solved my problems, thank you! The thing is that i now use SOIL to load graphic resources, and i don't have to worry anymore about that. Thank you anyways! \$\endgroup\$ Mar 1, 2013 at 20:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .