OpenGL Textures from SDL_Surfaces (A Question in "Color Keying")

Hello,

First off I’d like to say that I do know and understand that using
SDL_SetColorKey does not effect OpenGL Textures. That is not my
question/problem. I also know and understand that OpenGL does not have any
sort of function that resembles in functionality that of SDL_SetColorKey.

With that being said, here is my problem.

I’m working on a simple 2d game. I’m using it to teach me mixing SDL with
OpenGL. I have a 24bit bitmap of a ship with black as the background. With
SDL drawing functions I can simply set black as the colorkey and not worry
about it. However, I’ve spent the last few months googling for code to get
something similar to work with OpenGL. All the code I have found ends up
leaving a black box around my ship. I’ve just recently attempted to use the
getpixel/putpixel method to parse the pixels and set alpha to the colorkey I
wish. But it still failed. I’ve used pngs with the backgrounds with the alpha
set to 0. But I’m guessing the surfaces are somehow dropping the alpha data
when I do the poweroftwo conversion for the OpenGL Textures and then blitting
to a new surface (shouldn’t happen but I cannot think of what else is causing
it)

From all I’ve read it must be common knowledge on how to do it since there are
no tutorials. That, or else it is impossible (which I very well doubt).

So my request:
Please, anyone who knows how to accomplish what I’m attempting, please post
code to initialize OpenGL, convert an SDL_Surface to an OpenGL Texture, or even
the drawing functions used. Or what ever might be involved in getting rid of
the boxes around the textures. I’m assuming I’m just forgetting to enable some
option, or set some value. But I cannot find anywhere on the Internet that
just comes out and tells it all plain and simple. I guess I need something
from start to finish so that I’m not missing something so brain numbingly
obvious.

Or, if what I am attempting is in truth not possible, please let me know so I
can stop pulling out my hair.

Thanks in advance of any assistance,
Micah

Hello,

I’m working on a simple 2d game. I’m using it to teach me mixing SDL with
OpenGL. I have a 24bit bitmap of a ship with black as the background. With
SDL drawing functions I can simply set black as the colorkey and not worry
about it. However, I’ve spent the last few months googling for code to get
something similar to work with OpenGL. All the code I have found ends up
leaving a black box around my ship. I’ve just recently attempted to use the
getpixel/putpixel method to parse the pixels and set alpha to the colorkey I
wish. But it still failed. I’ve used pngs with the backgrounds with the alpha
set to 0. But I’m guessing the surfaces are somehow dropping the alpha data
when I do the poweroftwo conversion for the OpenGL Textures and then blitting
to a new surface (shouldn’t happen but I cannot think of what else is causing
it)

Thanks in advance of any assistance,
Micah

Hmmm, the most obvious reason why you are seeing black borders, is
because black, which you are setting to be transparent, is (0,0,0), and
there is border of black pixels around your picture that are ie. (1,0,0)

  • which makes them black for you, but not for your
    "transparency-setting-algorithm". Maybe you didn’t created them, but
    your gfx program did. Or they were created by you by mistake. However,
    if that’s not the case, then there’s probably sth wrong with code, so it
    would help if you could post here source of the smallest possible
    program example which reproduces the problem.

And btw, yes, having such functionality is certainly possible and should
be quite easy to implement. Unfortunately I don’t use color keys in this
way (rather than straight alpha information encoded in RGBA) so I don’t
have any piece of code to show.

Koshmaar

Koshmaar <koshmaar poczta.onet.pl> writes:

Hmmm, the most obvious reason why you are seeing black borders, is
because black, which you are setting to be transparent, is (0,0,0), and
there is border of black pixels around your picture that are ie. (1,0,0)

  • which makes them black for you, but not for your
    "transparency-setting-algorithm". Maybe you didn’t created them, but
    your gfx program did. Or they were created by you by mistake. However,
    if that’s not the case, then there’s probably sth wrong with code, so it
    would help if you could post here source of the smallest possible
    program example which reproduces the problem.

And btw, yes, having such functionality is certainly possible and should
be quite easy to implement. Unfortunately I don’t use color keys in this
way (rather than straight alpha information encoded in RGBA) so I don’t
have any piece of code to show.

Koshmaar

Well, I added a part to the code to alert me every time it finds the (0,0,0)
pixel, in case it was something such as the pixel being just slightly off.
According to that, it is finding black easy enough. I just have a nagging
feeling that I do not have opengl set up properly to deal with the alpha (even
though I enable GL_ALPHA_TEST (if that means anything))

I did have it working at on point in time by creating a mask. While I could in
theory set up a structure that holds both the actual texture and the mask. It
just seems stupid to have to do it that way. But if I have to, I have to. But
surely there is another way, right?

Also, I can post some code, but I’ll have to do it later. I’m on my work
computer without access to my code.

Anyway, thank you for your reply. If you by any chance whip up, or come across
some code, please let me know. Thanks!

Micah

First off I’d like to say that I do know and understand that using
SDL_SetColorKey does not effect OpenGL Textures. That is not my
question/problem. I also know and understand that OpenGL does not have
any
sort of function that resembles in functionality that of SDL_SetColorKey.

It has, in fact. It’s called alpha test.

With that being said, here is my problem.

I’m working on a simple 2d game. I’m using it to teach me mixing SDL
with
OpenGL. I have a 24bit bitmap of a ship with black as the background.
With
SDL drawing functions I can simply set black as the colorkey and not
worry
about it. However, I’ve spent the last few months googling for code to
get
something similar to work with OpenGL. All the code I have found ends up
leaving a black box around my ship. I’ve just recently attempted to use
the
getpixel/putpixel method to parse the pixels and set alpha to the
colorkey I
wish. But it still failed. I’ve used pngs with the backgrounds with
the alpha
set to 0. But I’m guessing the surfaces are somehow dropping the alpha
data
when I do the poweroftwo conversion for the OpenGL Textures and then
blitting
to a new surface (shouldn’t happen but I cannot think of what else is
causing
it)

From all I’ve read it must be common knowledge on how to do it since
there are
no tutorials. That, or else it is impossible (which I very well doubt).

So my request:
Please, anyone who knows how to accomplish what I’m attempting, please
post
code to initialize OpenGL, convert an SDL_Surface to an OpenGL Texture,
or even
the drawing functions used. Or what ever might be involved in getting
rid of
the boxes around the textures. I’m assuming I’m just forgetting to
enable some
option, or set some value. But I cannot find anywhere on the Internet
that
just comes out and tells it all plain and simple. I guess I need
something
from start to finish so that I’m not missing something so brain numbingly
obvious.

Here it is:

#include “SDL.h”
#include “SDL_endian.h”
#include “SDL_opengl.h”

int main(int, char**)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetVideoMode(400, 400, 0, SDL_OPENGL);

 // some.bmp is a red ship with a black backround
 SDL_Surface* original = SDL_LoadBMP("some.bmp");

 // We set a black colorkey for the ship
 SDL_SetColorKey(original, SDL_SRCCOLORKEY, 0);

 // We create a surface with known format to pass to opengl
 SDL_Surface* withalpha = SDL_CreateRGBSurface(
     SDL_SWSURFACE,
     original->w,
     original->h,
     32,
     SDL_SwapBE32(0xff000000),
     SDL_SwapBE32(0x00ff0000),
     SDL_SwapBE32(0x0000ff00),
     SDL_SwapBE32(0x000000ff));

 // We blit one on top of the other, but withalpha keeps
 // a transparent black in the backround
 // We should flip the texture so it has the origin in the bottom,
 // as opengl expects, but we flip coordinates instead
 SDL_BlitSurface(original, NULL, withalpha, NULL);
 SDL_FreeSurface(original);

 // The sky is blue
 glClearColor(0, 0, 1, 0);
 glClear(GL_COLOR_BUFFER_BIT);
 glEnable(GL_TEXTURE_2D);
 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

 // We enable skipping transparent texels
 glAlphaFunc(GL_GREATER, 0);
 glEnable(GL_ALPHA_TEST);

 GLuint texName = 0;
 glGenTextures(1, &texName);
 glBindTexture(GL_TEXTURE_2D, texName);
 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,
     withalpha->w,
     withalpha->h,
     0,
     GL_RGBA,
     GL_UNSIGNED_BYTE,
     withalpha->pixels);
 SDL_FreeSurface(withalpha);

 glBegin(GL_QUADS); {
     glTexCoord2d(0, 0);
     glVertex2d(-0.8, +0.8);
     glTexCoord2d(0, 1);
     glVertex2d(-0.8, -0.8);
     glTexCoord2d(1, 1);
     glVertex2d(+0.8, -0.8);
     glTexCoord2d(1, 0);
     glVertex2d(+0.8, +0.8);
 }glEnd();
 SDL_GL_SwapBuffers();

 // You should see a red ship over a blue backround
 SDL_Delay(1000);
 SDL_Quit();
 return 0;

}

Hope it helps,
BrunoOn Wed, 14 Dec 2005 13:56:52 -0200, Micah Brening <micah.brening at gmail.com> wrote:

Bruno Mart?nez <br1 internet.com.uy> writes:

Here it is:

#include “SDL.h”
#include “SDL_endian.h”
#include “SDL_opengl.h”

int main(int, char**)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetVideoMode(400, 400, 0, SDL_OPENGL);

 // some.bmp is a red ship with a black backround
 SDL_Surface* original = SDL_LoadBMP("some.bmp");

 // We set a black colorkey for the ship
 SDL_SetColorKey(original, SDL_SRCCOLORKEY, 0);

 // We create a surface with known format to pass to opengl
 SDL_Surface* withalpha = SDL_CreateRGBSurface(
     SDL_SWSURFACE,
     original->w,
     original->h,
     32,
     SDL_SwapBE32(0xff000000),
     SDL_SwapBE32(0x00ff0000),
     SDL_SwapBE32(0x0000ff00),
     SDL_SwapBE32(0x000000ff));

 // We blit one on top of the other, but withalpha keeps
 // a transparent black in the backround
 // We should flip the texture so it has the origin in the bottom,
 // as opengl expects, but we flip coordinates instead
 SDL_BlitSurface(original, NULL, withalpha, NULL);
 SDL_FreeSurface(original);

 // The sky is blue
 glClearColor(0, 0, 1, 0);
 glClear(GL_COLOR_BUFFER_BIT);
 glEnable(GL_TEXTURE_2D);
 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

 // We enable skipping transparent texels
 glAlphaFunc(GL_GREATER, 0);
 glEnable(GL_ALPHA_TEST);

 GLuint texName = 0;
 glGenTextures(1, &texName);
 glBindTexture(GL_TEXTURE_2D, texName);
 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,
     withalpha->w,
     withalpha->h,
     0,
     GL_RGBA,
     GL_UNSIGNED_BYTE,
     withalpha->pixels);
 SDL_FreeSurface(withalpha);

 glBegin(GL_QUADS); {
     glTexCoord2d(0, 0);
     glVertex2d(-0.8, +0.8);
     glTexCoord2d(0, 1);
     glVertex2d(-0.8, -0.8);
     glTexCoord2d(1, 1);
     glVertex2d(+0.8, -0.8);
     glTexCoord2d(1, 0);
     glVertex2d(+0.8, +0.8);
 }glEnd();
 SDL_GL_SwapBuffers();

 // You should see a red ship over a blue backround
 SDL_Delay(1000);
 SDL_Quit();
 return 0;

}

Hope it helps,
Bruno

Now I’m wondering if there is something wrong with my opengl library, or
something along those lines. I took your code, changed only the filename,
compiled it, linked it, ran it, and I had a window, with a blue back ground,
and a big white box in the middle of it. No picture…

There were two differences in your code with what I had:
glAlphaFunc(GL_GREATER, 0); /* Yes, I actually forgot to set the alpha
function*/
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /I am unfamiliar
with this function…
/

But, even when I made those changes to my own code, nothing changed (there are
times when I get rid of the black box, and in it’s place is a white box… lol)

I’ll upload some of my code when I get the chance, perhaps that would help.

Also, another question. The way my code is organized, I have a seperate shared
object loading at runtime with the opengl code, is it in any way possible it
just isn’t accessing the memory correctly? (shouldn’t be, but then I have no
clue)

Thanks for code, maybe I just have something incorrect somewhere else… Any
thoughts? …Oh here is a stupid idea… My xserver is currently running at
16bpp I’ll have to go change it to see if that is the problem (I’ll have
pleanty of choice words for the computer if that is the case)

Micah

Now I’m wondering if there is something wrong with my opengl library, or
something along those lines. I took your code, changed only the
filename,
compiled it, linked it, ran it, and I had a window, with a blue back
ground,
and a big white box in the middle of it. No picture…

Seems familiar. When writing the code, whenever I did something wrong,
that was what happened.

Maybe you could use GLIntercept to debug it. I used gDEBugger.

There were two differences in your code with what I had:
glAlphaFunc(GL_GREATER, 0); /* Yes, I actually forgot to set the alpha
function*/

:smiley:

Also, another question. The way my code is organized, I have a seperate
shared
object loading at runtime with the opengl code, is it in any way
possible it
just isn’t accessing the memory correctly? (shouldn’t be, but then I
have no
clue)

I don’t know. I use Windows.

Thanks for code, maybe I just have something incorrect somewhere
else… Any
thoughts? …Oh here is a stupid idea… My xserver is currently
running at
16bpp I’ll have to go change it to see if that is the problem (I’ll have
pleanty of choice words for the computer if that is the case)

I tried 16bpp here without problems. It’s a different OS, though.

BrunoOn Wed, 14 Dec 2005 20:59:18 -0200, Micah Brening <micah.brening at gmail.com> wrote:

Micah Brening <micah.brening gmail.com> writes:

So my request:
Please, anyone who knows how to accomplish what I’m attempting, please post
code to initialize OpenGL, convert an SDL_Surface to an OpenGL Texture, or
even
the drawing functions used. Or what ever might be involved in getting rid of
the boxes around the textures. I’m assuming I’m just forgetting to enable
some
option, or set some value. But I cannot find anywhere on the Internet that
just comes out and tells it all plain and simple. I guess I need something
from start to finish so that I’m not missing something so brain numbingly
obvious.

I added the code that Mr. Mart?nez had shown me. This is what I have now (the
current result is just a blue screen. So in other words, no I have no textures
showing at all.)

Also, I’d like to note, I structured this code to be a part of a SO/DLL But
this is all of the OpenGL commands I run. the GFX_* commands are the ones the
rest of my code runs directly.

Any ideas? Suggestions? Theories?

The Code:

#include “main.h”
#include “SDL_opengl.h”
#include “SDL_image.h”

typedef struct sprite{
GLuint img;
GLfloat texcoord[4];
} sprite;

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

GLuint SDL_GL_LoadTexture(SDL_Surface *surface,GLfloat *texcoord)
{
GLuint texture;
int w, h;
SDL_Surface *image;
SDL_Rect area;
Uint32 saved_flags,colorkey;
Uint8 saved_alpha;

w = power_of_two(surface->w);
h = power_of_two(surface->h);
texcoord[0] = 0.0f;
texcoord[1] = 0.0f;
texcoord[2] = (GLfloat)surface->w / w;
texcoord[3] = (GLfloat)surface->h / h;

image = SDL_CreateRGBSurface(
		SDL_SWSURFACE,
		w, h,
		32,

#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x000000FF,
0x0000FF00,
0x00FF0000,
0xFF000000
#else
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF
#endif
);
if ( image == NULL ) {
return 0;
}
saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
saved_alpha = surface->format->alpha;
if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
SDL_SetAlpha(surface, 0, 0);
}

area.x = 0;
area.y = 0;
area.w = surface->w;
area.h = surface->h;
SDL_BlitSurface(surface, &area, image, &area);
if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
	SDL_SetAlpha(surface, saved_flags, saved_alpha);
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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,
	     w, h,
	     0,
	     GL_RGBA,
	     GL_UNSIGNED_BYTE,
	     image->pixels);
SDL_FreeSurface(image); 

return texture;

}

int GFX_initgfx(kelset *rage)
{ rage->printd(rage,“Setting Video Mode”);
rage->screen = SDL_SetVideoMode(rage->width,rage->height,rage->bpp,rage-

flags);
if (!rage->screen)
{
rage->printd(rage,“Unable to initalize SDL”);
return -1;
}
else
{
rage->printd(rage,“Setting Window Title”);
SDL_WM_SetCaption(rage->wmtitle,NULL);

	glClearColor(0,0,1,0);
	glClear(GL_COLOR_BUFFER_BIT);
	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
	glAlphaFunc(GL_GREATER,0);
	glEnable(GL_ALPHA_TEST);

	rage->printd(rage,"Returning Successful");
	return 1;
}

}

void* GFX_loadsprite(char * filename,SDL_Rect *def)
{
SDL_Surface *img;
sprite *glimg = (sprite *)malloc(sizeof(sprite));
img = IMG_Load(filename);
def->w = img->w;
def->h = img->h;
SDL_SetColorKey(img,SDL_SRCCOLORKEY,SDL_MapRGB(img->format,0,0,0));
glimg->img = SDL_GL_LoadTexture(img,glimg->texcoord);
SDL_FreeSurface(img);
return glimg;
}

void GFX_drawsprite(void *vimg,int x,int y,int w,int h)
{
sprite *glimg = (sprite *)vimg;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,glimg->img);
glBegin(GL_QUADS);
glTexCoord2f(glimg->texcoord[0],glimg->texcoord[1]);
glVertex2i(x,y);
glTexCoord2f(glimg->texcoord[0],glimg->texcoord[3]);
glVertex2i(x+w,y);
glTexCoord2f(glimg->texcoord[2],glimg->texcoord[3]);
glVertex2i(x,y+h);
glTexCoord2f(glimg->texcoord[2],glimg->texcoord[1]);
glVertex2i(x+w,y+h);
glEnd();
}

void GFX_killsprite(void *vimg)
{
sprite *glimg = (sprite *)vimg;
glDeleteTextures(1,&glimg->img);
free(glimg);
}

void GFX_clearscreen(void)
{
glClear(GL_COLOR_BUFFER_BIT);
}

void GFX_flip(kelset *rage)
{
glFlush();
SDL_GL_SwapBuffers();
}

void GFX_killgfx(void)
{
SDL_Quit();
}

void GFX_drawline(int sx,int sy,int dx,int dy,SDL_Color color)
{
glDisable(GL_TEXTURE_2D);
glBegin(GL_LINE_STRIP);
glColor4ub(color.r, color.g, color.b,255);
glVertex2i(sx,sy);
glVertex2i(dx,dy);
glEnd();
glEnable(GL_TEXTURE_2D);
}

void GFX_drawgrline(int sx,int sy,SDL_Color scolor,int dx,int dy,SDL_Color
dcolor)
{
glDisable(GL_TEXTURE_2D);
glBegin(GL_LINE_STRIP);
glColor4ub(scolor.r, scolor.g, scolor.b,255);
glVertex2i(sx,sy);
glColor4ub(dcolor.r, dcolor.g, dcolor.b,255);
glVertex2i(dx,dy);
glEnd();
glEnable(GL_TEXTURE_2D);
}

void *GFX_totexture(SDL_Surface *img)
{
sprite *glimg = (sprite *)malloc(sizeof(sprite));
glimg->img = SDL_GL_LoadTexture(img,glimg->texcoord);
SDL_FreeSurface(img);
return glimg;
}