SDL & OpenGL Texture Transparency

Started by
11 comments, last by MatrixCubed 18 years, 4 months ago
I am using SDL and OpenGL (of course by the topic) and am attempting to make a function that loads a file and returns it as an OpenGL texture with transparency. Currently, I already have a function that returns an OpenGL texture, but I need it to also make certain parts of it transparent (for example, the color magenta - FF00FF (255,0,255)). I would like to modify my current function to make the returned textures transparent. Below is my current code for texture loading:

static int  powerOfTwo(int input)
{
    int value = 1;
    while(value < input)
        value <<= 1;
    return value;
}

GLuint  LoadGLTexture(const char* filename)
{
    SDL_Surface *pImage = NULL, *image = NULL;
    GLuint      texture = 0;
    int         w = 0, h = 0, ybegin, yend;
    SDL_Rect    area;
    Uint32      saved_flags;
    Uint16      pitch;
    Uint8       saved_alpha, *pixels, *line;
    
    pImage = IMG_Load(filename);
    if(!pImage)
    {
        printf("Unable to load texture '%s'\n", filename);
        return 0;
    }
    
    w = powerOfTwo(pImage->w);
    h = powerOfTwo(pImage->h);
    /*
    texcoord[0] = 0.0f;
    texcoord[1] = 0.0f;
    texcoord[2] = (GLfloat)pImage->w / w;
    texcoord[3] = (GLfloat)pImage->h / h;
    */
  
    if(!(image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
    0x000000FF,
    0x0000FF00,
    0x00FF0000,
    0xFF000000
#else
    0xFF000000,
    0x00FF0000,
    0x0000FF00,
    0x000000FF
#endif
    )))
    {
        printf("SDL_CreateRGBSurface: Unable to create RGB Surface for texture '%s'\n", filename);
        return 0;
    }
    
    saved_flags = pImage->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
    saved_alpha = pImage->format->alpha;
    if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
        SDL_SetAlpha(pImage, 0, 0);
        
    area.x = area.y = 0;
    area.w = pImage->w;
    area.h = pImage->h;
    SDL_BlitSurface(pImage, &area, image, &area);
    
    if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
        SDL_SetAlpha(pImage, saved_flags, saved_alpha);

	line = new Uint8[image->pitch];
	pixels = static_cast<Uint8*>(image->pixels);
	pitch = image->pitch;
	ybegin = 0;
	yend = image->h - 1;

	if(SDL_MUSTLOCK(image))
        SDL_LockSurface(image);
	while(ybegin < yend)
    {
		memcpy(line, pixels + pitch * ybegin, pitch);
		memcpy(pixels + pitch * ybegin, pixels + pitch * yend, pitch);
		memcpy(pixels + pitch * yend, line, pitch);
		ybegin++;
		yend--;
	}
	if(SDL_MUSTLOCK(image))
        SDL_UnlockSurface(image);
    
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
    
    if(pImage)
        SDL_FreeSurface(pImage); 
    if(image)
        SDL_FreeSurface(image);
    if(line)
        delete[] line;
    
    return texture;
}

Thanks for any help!
"Everything begins with Nu and everything ends with Nu. This is the truth! This is my belief... at least for now." - Mysteries of Life Volume 184 Chapter 26
Advertisement
You get a pointer to the pixels (before they are given to OpenGL), and you examine each pixel. If (pixel&0xffffff) is 0xff00ff, then set it to 0x00000000, else set it to ((pixel&0xffffff)|0xff000000). Then upload the data as an actual texture.

When you draw using this transparency, use GL_ONE,GL_ONE_MINUS_SRC_ALPHA blend function, because the color pixels will blend towards black as they blend towards translucency. If you use GL_SRC_ALPHA, then you'll get black fringes.
enum Bool { True, False, FileNotFound };
What would be the best way to cycle through each pixel, then?
Also, where in the function? (I am presuming right before the glTexImage2D)

Wouldn't cycling through each pixel, though, be quite slow? Is there any better alternative or something? If not, that's okay, but I am just concerned about speed a little bit.
"Everything begins with Nu and everything ends with Nu. This is the truth! This is my belief... at least for now." - Mysteries of Life Volume 184 Chapter 26
I think I did this a few years ago. It should be possible to setup a color key. Then (I think) you can use SDL_DisplayFormatAlpha() which will take a surface with a color key set and give you a new surface with transparency using an alpha channel. Then you can just use that to build your OpenGL texture.

There's a few details I can't really remember, but that's the basics.
I like the DARK layout!
Yes, I've read that all over (and via the documentation), but whenever I try to use it, for some reason, it seems not to work at all.
"Everything begins with Nu and everything ends with Nu. This is the truth! This is my belief... at least for now." - Mysteries of Life Volume 184 Chapter 26
I found some really old code of mine (IIRC it worked, but I can't be sure) that does what you want:

SDL_Surface * surface = IMG_Load("something.tga");// the color key is a disgusting shade of bright purpleSDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, 255,0,255));SDL_Surface * alphasurface = SDL_DisplayFormatAlpha(surface);// standard OpenGL stuff hereunsigned int gltex;glGenTextures(1, &gltex);glBindTexture(GL_TEXTURE_2D);glTexImage2D(GL_TEXTURE_2D, 0, 4, alphasurface->w, alphasurface->h, 0, GL_BGRA_EXT,     GL_UNSIGNED_BYTE, alphasurface->pixels);glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );SDL_FreeSurface(alphasurface);SDL_FreeSurface(surface);

You'll also need to make sure the proper OpenGL alpha testing stuff is turned on.

Edit: Oh, by the way, if you are using something like .tga or .png or anything else that supports alpha for your textures, you can just include the alpha information in those files and not worry about setting color keys and junk like that.
I like the DARK layout!
As hplus mentioned the best way is to cycle through the SDL_Surface using something like the SDL_GetPixel and SDL_PutPixel functions you can find in the SDL documentation and setting the pixels yourself. This will allow you to set multiple color keys and even change certain colors to different alpha values on load. Since you should only be doing this once when you load the texture the speed shouldn't be an issue unless you plan on loading lots of textures on the fly.

Evillive2
BradDaBug's code didn't seem to work at all for me.
I have blending enabled as below:

glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

and I literally copied and pasted his code into my current function (with mild modifying, such as replacing the "something.tga" with filename, correcting his Binding and returning the gltex variable).

evillive2's comment on SDL_GetPixel and SDL_PutPixel sounds like a good idea, but whenever I go to use the two functions, it says that they both are undeclared (I have both SDL.h and SDL_image.h included in the file and I have even checked SDL's documentation for the functions; they don't seem to be actual functions in SDL or something).

Thanks again for all your help; I'll keep trying to crack this darn thing open.

I think, looking at my function, that part of my problem is that it loads the texture into one surface, Blits the surface onto another one after resizing it into a proper texture size (8, 16, 32, 64, 128, ...) and then converts that second surface into the OpenGL texture. I think that somewhere between the conversion between surface to surface or during the conversion from surface to OpenGL texture we have to set the color key and change the surface or the such into a surface with alpha transparency. Just a big brainstorm but so far I don't seem to have any luck with it.
"Everything begins with Nu and everything ends with Nu. This is the truth! This is my belief... at least for now." - Mysteries of Life Volume 184 Chapter 26
Quote:Original post by codemastermm
evillive2's comment on SDL_GetPixel and SDL_PutPixel sounds like a good idea, but whenever I go to use the two functions, it says that they both are undeclared (I have both SDL.h and SDL_image.h included in the file and I have even checked SDL's documentation for the functions; they don't seem to be actual functions in SDL or something).

They aren't actually part of SDL. See here. You've got to add the functions to your project somewhere.

Edit: Are you blitting the image, then setting the color key and getting the alpha surface, or are you blitting after you do that? IIRC unless you specifically tell SDL to include alpha information when blitting (via SDL_SetAlpha()) it'll ignore it, and the new blitted surface won't have any alpha info.
I like the DARK layout!
I might switch my textures into PNG or TGA since colorkeying is a bit of a hassale.

How about would I load a TGA or PNG in, given that they already have alpha values and won't need much more of a conversion to enable alpha transparency with those.
"Everything begins with Nu and everything ends with Nu. This is the truth! This is my belief... at least for now." - Mysteries of Life Volume 184 Chapter 26

This topic is closed to new replies.

Advertisement