PDA

View Full Version : glBlendFunc() problem



woofbluddywoof
01-31-2011, 08:55 AM
Hi all,
I'm making a simple 2d game in SDL and openGL (converting SDL surfaces to GL textures for the sprites). All was going fine until I started trying to add in some color keying.

The problem is when calling glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) the screen gets blanked to whatever the clear screen color is. When I call blending with GL_ZERO I just get a black rectangular square where the sprite should be. I found a thread elsewhere with a similar problem to mine
(http://www.gamedev.net/topic/556601-simple-problemblank-screen-solved/)
and in this calling SDL_SetAlpha to make sure the SDL surface is opaque worked - but unfortunately not the same for me. Still nothing.

Has anyone got any ideas?

Much appreciated.

_arts_
01-31-2011, 11:51 AM
Do you initialize an RGBA OpenGL context (and not RGB only) ? Do you enable blending ? Do you render in the good order ? Do you clear the buffer with all rgba good values ?

If yes, post more details, for example code snippets.

woofbluddywoof
01-31-2011, 04:17 PM
Hi, thanks for your response -
In answer to your queries.

I'm pretty sure I initialize an RGBA context - it's possible I'm wrong though - have thus far about three days experience with this. Will chuck all the pertient code down at the end of this...

Yes I do enable blending.


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

- It's actually turning this on that seems to be the source of my problems. With it diabled my sprites render fine (albeit without transparency)

- Think I render in a good order. Clear the screen then render sprites right?

- Not sure what you mean be 'clear the buffer with all rgba good values' - if you mean are all my textures RGBA when rendered then yes - otherwise not sure what you mean?

Anyway code is as follow (btw am using SDL_Opengl - don't know if this is a problem?)

All the initialization stuff:




cGraphics::cGraphics(int WindowWidth, int WindowHeight, int WindowBPP, string WindowCaption)
{
//initialize all SDL subsystems
SDL_Init(SDL_INIT_VIDEO);

//Initialize SDL_ttf
TTF_Init();

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );


//Set up the screen
screen = SDL_SetVideoMode(WindowWidth, WindowHeight, WindowBPP, SDL_OPENGL );//SDL_FULLSCREEN);

//Set the window caption
SDL_WM_SetCaption(WindowCaption.c_str(), NULL);

glEnable(GL_TEXTURE_2D);

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

//Clear the screen to red
glClearColor( 255.0f, 0.0f, 0.0f, 0.0f );

//Set the viewport to the size of the window
glViewport( 0, 0, WindowWidth, WindowHeight);
//glViewport( 0, 0, 640, 480);

glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode( GL_PROJECTION );
glLoadIdentity();

glOrtho(0.0f, WindowWidth, WindowHeight, 0.0f, -1.0f, 1.0f);
//glOrtho(0.0f, 640, 480, 0.0f, -1.0f, 1.0f);

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}



reading in the sdl surfaces + converting into textures




SDL_Surface* cGraphics::load_image_SDL(string filename)
{
//The image that's loaded
SDL_Surface* loadedImage = NULL;

//The optimized image that will be used
SDL_Surface* optimizedImage = NULL;

//Load the image
loadedImage = IMG_Load(filename.c_str());

//If the image loaded
if (loadedImage != NULL)
{
//Create an optimized image
optimizedImage = SDL_DisplayFormat(loadedImage);

//Free the old image
SDL_FreeSurface(loadedImage);
//If the image was optimized just fine
if (optimizedImage != NULL)
{
//Map the color key
//Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF);

//Set all pixels of color [0,0xFF,0xFF] to be transparent
//SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
}
}

//Return the optimzed image
return optimizedImage;
}

spriteStruct cGraphics::load_texture(std::string filename)
{
GLuint texture; // This is a handle to our texture object
SDL_Surface *testSurface; // This surface will tell us the details of the image
SDL_Surface *surface; //The final surface to be converted to gl texture
GLenum texture_format;
GLint nOfColors;

testSurface = load_image_SDL(filename);


unsigned width;
unsigned height;

if (SDL_MUSTLOCK(testSurface))
SDL_LockSurface(testSurface);

for(int i = 0; i < testSurface->w; i++ )
{
for (int j = 0; j < testSurface->h; j++)
{

Uint8 r;
Uint8 g;
Uint8 b;
Uint8 a;
Uint32 onePixel = get_pixel32(testSurface, i, j);
SDL_GetRGBA(onePixel, testSurface->format, &amp;r, &amp;g, &amp;b, &amp;a);
if (r ==0 &amp;&amp; g == 255 &amp;&amp; b == 255)
{
// if so, then set alpha to transparent
a = 0;
}
else a = 255;
Uint32 newPixel = SDL_MapRGBA(testSurface->format, r, g, b, a);
put_pixel32(testSurface, i, j, newPixel);

onePixel = get_pixel32(testSurface, i, j);
SDL_GetRGBA(onePixel, testSurface->format, &amp;r, &amp;g, &amp;b, &amp;a);
SDL_GetRGBA(onePixel, testSurface->format, &amp;r, &amp;g, &amp;b, &amp;a);
}
}

if (SDL_MUSTLOCK(testSurface))
SDL_UnlockSurface(testSurface);

if ( ( (testSurface->w != 0) &amp;&amp; ( (testSurface->w & (testSurface->w - 1) )!=0 ) ) ||
( (testSurface->h != 0) &amp;&amp; ( (testSurface->h & (testSurface->h - 1) )!=0 ) ) )
{
printf("Warning: texture width/depth is not a power of two");

width = pow( 2, ceil( log10(static_cast<double>(testSurface->w) ) / log10(static_cast<double>(2) ) ) );
height = pow( 2, ceil( log10(static_cast<double>(testSurface->h) ) / log10(static_cast<double>(2) ) ) );

surface = SDL_CreateRGBSurface(testSurface->flags,
width,
height,
testSurface->format->BitsPerPixel,
testSurface->format->Rmask,
testSurface->format->Gmask,
testSurface->format->Bmask,
testSurface->format->Amask);

SDL_BlitSurface(testSurface, NULL, surface, NULL);
SDL_Flip(surface);

}
else
{
surface = testSurface;
printf("Texture is ok!");
width = surface->w;
height = surface->h;
}

SDL_SetAlpha(surface, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);

// get the number of channels in the SDL surface
nOfColors = surface->format->BytesPerPixel;
if (nOfColors == 4) // contains an alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
}
else if (nOfColors == 3) // no alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
}
else
{
printf("warning: the image is not truecolor.. this will probably break\n");
// this error should not go unhandled
}

// Have OpenGL generate a texture object handle for us
glGenTextures( 1, &amp;texture );

// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );

// Set the texture's stretching properties
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

// Edit the texture object's image data using the information SDL_Surface gives us
glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels );

spriteStruct sprite;

sprite.spriteClip.h = testSurface->h;
sprite.spriteClip.w = testSurface->w;
sprite.spriteClip.x = 0;
sprite.spriteClip.y = 0;

sprite.spriteTexture = texture;

// Free the SDL_Surface only if it was successfully created
if (surface)
SDL_FreeSurface(surface);
if (testSurface)
SDL_FreeSurface(testSurface);

return sprite;
}



- Should point out I am using a custom structure which hold both the texture and the sprite rectangle (just for collision stuff) - could this be the problem? - Again though, without blending all works fine.

Finally textures are rendered as follows




int cGraphics::apply_texture(int x, int y, spriteStruct *sprite, SDL_Rect* clip)
{

glBindTexture( GL_TEXTURE_2D, sprite->spriteTexture );

GLfloat textureWidth; GLfloat textureHeight;

float spriteWidth = sprite->spriteClip.w;
float spriteHeight = sprite->spriteClip.h;

glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &amp;textureWidth);
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &amp;textureHeight);

float fractionalWidth = spriteWidth/textureWidth;
float fractionalHeight = spriteHeight/textureHeight;

x = float(x);
y = float(y);

glBegin( GL_QUADS );
//Bottom-left vertex (corner)
glTexCoord2f( 0.f, 0.f );
glVertex3f( x, y, 0.f );

//Bottom-right vertex (corner)
glTexCoord2f( fractionalWidth, 0.f );
glVertex3f( x+spriteWidth, y, 0.f );

//Top-right vertex (corner)
glTexCoord2f( fractionalWidth, fractionalHeight );
glVertex3f( x+spriteWidth, y+spriteHeight, 0.f );

//Top-left vertex (corner)
glTexCoord2f( 0.f, fractionalHeight );
glVertex3f( x, y+spriteHeight, 0.f );
glEnd();

return 0;
}



and the buffers swapped:



int cGraphics::show()
{
SDL_GL_SwapBuffers();
return 0;
}


Apologies for so much messy code - hard to keep it tidy with so much mucking about going on...

Thanks a lot.

_arts_
02-01-2011, 03:40 AM
This line is wrong:

glClearColor( 255.0f, 0.0f, 0.0f, 0.0f );

Values must be between 0 (no intensity) and 1 (full intensity). Even if I think this is not the source of your problem, you might have some things similar to this in some other places in your program that could cause this.

Other parts look ok.

woofbluddywoof
02-01-2011, 10:53 AM
Hi, thanks for your help, hadn't noticed that.

Turns out the problem was the way I was returning an SDL surface from a seperate function - this was denying me access to alter the pixel info for some reason, so things weren't doing what I thought they were...

Cheers!