Alpha and per pixel alpha

All,
Is there any way to have per surface alpha combined with per pixel alpha together ?
In a sense it means that I want to use TTF with antialiasing and then blit it to the surface with additional transparency.
Can I do that ?

Dmitry/

I had to write my own function to combine per pixel alpha and per surface alpha.
For my needs I also had a per program alpha that is a master alpha value so that I can reliably fade in or out the entire display (since gamma doesn’t seem to be reliable enough for all configurations.

This code is for my TextSurface class that uses SDL_ttf, but I don’t see any reason it wouldn’t work on any other kinds of 32 bit surfaces. This code will have to be modified for surfaces of other bit depths and is not very mature code yet.

In order for this to work, you must keep an original copy of the surface around so that the alpha can be recalculated from the original each time it is changed. Then simply display the copy which has the alpha values set the way you want.

I’d really like to see functionality like this built into SDL. Hope this helps.
–Warren Schwader

void TextSurface::SetAlpha(int alpha, int masterAlpha)
{
// calculate the alpha based on the master alpha for the entire game with this objects surface alpha setting
// The netAlpha value will be used to determine each pixel’s alpha setting
int surfaceAlpha = (alpha * masterAlpha) / 255;

// the pixels that make up the dats - not necessarily a simple 2d array
Uint32* pixels = (Uint32*)_textSurface->pixels;

// the surface width and height
int width = _textSurface->w;
int height = _textSurface->h;

// the pitch of the surface. Used to determine where the next vertical line in pixels starts
int pitch = _textSurface->pitch;

// this is the RGBA of a single pixel in the pixels array
Uint32 pixel = 0;

// the number of pixels for pitch instead of the numer of bytes
Uint32 pitchPixels = pitch / 4;

// this will refer to the alpha value of an individual pixel in the surface
int pixelAlpha = 0;

// for faster access
SDL_PixelFormat* format = _textSurface->format;

// this mask covers all the bits in the RGB section of the pixel, but not the Alpha portion
Uint32 RGBMask = format->Rmask | format->Gmask | format->Bmask;

// some other shortcuts to make the inner loop as fast as possible
Uint32 alphaShift = format->Ashift;
Uint32 alphaMask = format->Amask;

int ndx = 0;
for (int h = 0; h < height; h++)
{
// for each vertical line, calculate the starting index. Each pixel in that line will then be contiguous
ndx = (h * pitchPixels);

for (int w = 0; w < width; w++)
{
pixel = pixels[ndx];
pixelAlpha = (pixel & alphaMask) >> alphaShift;

if (pixelAlpha > 0)
{
// calculate the new pixel alpha value and shift it into the location of the alpha bits
pixelAlpha = ((pixelAlpha * surfaceAlpha) / 255) << alphaShift;

// first AND out the alpha portion so that they are 0 and then OR in the new alpha value
pixels[ndx] = (pixel & RGBMask) | pixelAlpha;  

}
ndx++;
}
}
}----- Original Message -----
From: Dmitry Borisov
To: sdl at libsdl.org
Sent: Thursday, November 06, 2003 10:40 PM
Subject: [SDL] Alpha and per pixel alpha

All,
Is there any way to have per surface alpha combined with per pixel alpha together ?
In a sense it means that I want to use TTF with antialiasing and then blit it to the surface with additional transparency.
Can I do that ?

Dmitry/

Actually the code I listed had a bug so I am posting the correct version:

void TextSurface::SetAlpha(int alpha, int masterAlpha)
{
// calculate the alpha based on the master alpha for the entire game with this objects surface alpha setting
// The netAlpha value will be used to determine each pixel’s alpha setting
int surfaceAlpha = (alpha * masterAlpha) / 255;

// the pixels that make up the dats - not necessarily a simple 2d array
Uint32* origPixels = (Uint32*)_textSurfaceOrig->pixels;
Uint32* destPixels = (Uint32*)_textSurface->pixels;

// for faster access
SDL_PixelFormat* format = _textSurfaceOrig->format;

// the surface width and height
int width = _textSurfaceOrig->w;
int height = _textSurfaceOrig->h;

// the pitch of the surface. Used to determine where the next vertical line in pixels starts
int pitch = _textSurfaceOrig->pitch;

// this is the RGBA of a single pixel in the pixels array
Uint32 pixel = 0;

// the number of pixels for pitch instead of the numer of bytes
Uint32 pitchPixels = pitch / format->BytesPerPixel;

// this will refer to the alpha value of an individual pixel in the surface
int pixelAlpha = 0;

// this mask covers all the bits in the RGB section of the pixel, but not the Alpha portion
Uint32 RGBMask = format->Rmask | format->Gmask | format->Bmask;

// other time savers because these are used in the inner loop
Uint32 alphaShift = format->Ashift;
Uint32 alphaMask = format->Amask;

// NOTE: Since we are only modifying the alpha bytes we could simply read only that byte and then add 4 to get
// to the next alpha byte. That approach depends on the endianess of the alpha byte and also the 32 bit pixel depth
// so if those things change then this code will need changing too. but we already rely on 32 bpp
int ndx = 0;
for (int h = 0; h < height; h++)
{
// for each vertical line, calculate the starting index. Each pixel in that line will then be contiguous
ndx = (h * pitchPixels);

for (int w = 0; w < width; w++)
{
pixel = origPixels[ndx];
pixelAlpha = (pixel & alphaMask) >> alphaShift;

if (pixelAlpha > 0)
{
// calculate the new pixel alpha value and shift it into the location of the alpha bits
pixelAlpha = ((pixelAlpha * surfaceAlpha) / 255) << alphaShift;

// first AND out the alpha portion so that they are 0 and then OR in the new alpha value
destPixels[ndx] = (pixel & RGBMask) | pixelAlpha;  

}
ndx++;
}
}
}----- Original Message -----
From: Warren Schwader
To: sdl at libsdl.org
Sent: Saturday, November 29, 2003 6:35 PM
Subject: Re: [SDL] Alpha and per pixel alpha

I had to write my own function to combine per pixel alpha and per surface alpha.
For my needs I also had a per program alpha that is a master alpha value so that I can reliably fade in or out the entire display (since gamma doesn’t seem to be reliable enough for all configurations.

This code is for my TextSurface class that uses SDL_ttf, but I don’t see any reason it wouldn’t work on any other kinds of 32 bit surfaces. This code will have to be modified for surfaces of other bit depths and is not very mature code yet.

In order for this to work, you must keep an original copy of the surface around so that the alpha can be recalculated from the original each time it is changed. Then simply display the copy which has the alpha values set the way you want.

I’d really like to see functionality like this built into SDL. Hope this helps.
–Warren Schwader

Thank you Warren,
It was my approach too. I’ve made almost identical piece of code. Unfortunatelly has a side effect. But it works just great for my purposes…
Thanks again.
Dmitry/----- Original Message -----
From: Warren Schwader
To: sdl at libsdl.org
Sent: Saturday, November 29, 2003 8:37 PM
Subject: Re: [SDL] Alpha and per pixel alpha

Actually the code I listed had a bug so I am posting the correct version:

void TextSurface::SetAlpha(int alpha, int masterAlpha)
{
// calculate the alpha based on the master alpha for the entire game with this objects surface alpha setting
// The netAlpha value will be used to determine each pixel’s alpha setting
int surfaceAlpha = (alpha * masterAlpha) / 255;

// the pixels that make up the dats - not necessarily a simple 2d array
Uint32* origPixels = (Uint32*)_textSurfaceOrig->pixels;
Uint32* destPixels = (Uint32*)_textSurface->pixels;

// for faster access
SDL_PixelFormat* format = _textSurfaceOrig->format;

// the surface width and height
int width = _textSurfaceOrig->w;
int height = _textSurfaceOrig->h;

// the pitch of the surface. Used to determine where the next vertical line in pixels starts
int pitch = _textSurfaceOrig->pitch;

// this is the RGBA of a single pixel in the pixels array
Uint32 pixel = 0;

// the number of pixels for pitch instead of the numer of bytes
Uint32 pitchPixels = pitch / format->BytesPerPixel;

// this will refer to the alpha value of an individual pixel in the surface
int pixelAlpha = 0;

// this mask covers all the bits in the RGB section of the pixel, but not the Alpha portion
Uint32 RGBMask = format->Rmask | format->Gmask | format->Bmask;

// other time savers because these are used in the inner loop
Uint32 alphaShift = format->Ashift;
Uint32 alphaMask = format->Amask;

// NOTE: Since we are only modifying the alpha bytes we could simply read only that byte and then add 4 to get
// to the next alpha byte. That approach depends on the endianess of the alpha byte and also the 32 bit pixel depth
// so if those things change then this code will need changing too. but we already rely on 32 bpp
int ndx = 0;
for (int h = 0; h < height; h++)
{
// for each vertical line, calculate the starting index. Each pixel in that line will then be contiguous
ndx = (h * pitchPixels);

for (int w = 0; w < width; w++)
{   
 pixel = origPixels[ndx];
 pixelAlpha = (pixel & alphaMask) >> alphaShift;

 if (pixelAlpha > 0)
 {
  // calculate the new pixel alpha value and shift it into the location of the alpha bits
  pixelAlpha = ((pixelAlpha * surfaceAlpha) / 255) << alphaShift;

  // first AND out the alpha portion so that they are 0 and then OR in the new alpha value
  destPixels[ndx] = (pixel & RGBMask) | pixelAlpha;  
 }
 ndx++;
}

}
}

----- Original Message ----- 
From: Warren Schwader 
To: sdl at libsdl.org 
Sent: Saturday, November 29, 2003 6:35 PM
Subject: Re: [SDL] Alpha and per pixel alpha


I had to write my own function to combine per pixel alpha and per surface alpha.
For my needs I also had a per program alpha that is a master alpha value so that I can reliably fade in or out the entire display (since gamma doesn't seem to be reliable enough for all configurations.

This code is for my TextSurface class that uses SDL_ttf, but I don't see any reason it wouldn't work on any other kinds of 32 bit surfaces.  This code will have to be modified for surfaces of other bit depths and is not very mature code yet.

In order for this to work, you must keep an original copy of the surface around so that the alpha can be recalculated from the original each time it is changed.  Then simply display the copy which has the alpha values set the way you want.

I'd really like to see functionality like this built into SDL.  Hope this helps.
--Warren Schwader