glBlendFunc() problem

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.

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.

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, &r, &g, &b, &a);  
			if (r ==0 && g == 255 && 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, &r, &g, &b, &a);
			 SDL_GetRGBA(onePixel, testSurface->format, &r, &g, &b, &a);
		}
	}

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

	if ( ( (testSurface->w != 0) && ( (testSurface->w & (testSurface->w - 1) )!=0 ) ) || 
		 ( (testSurface->h != 0) && ( (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
");
        // this error should not go unhandled
    }
 
	// Have OpenGL generate a texture object handle for us
	glGenTextures( 1, &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, &textureWidth);
	glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &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.

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.

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!